Commit | Line | Data |
---|---|---|
39674d5f | 1 | /* udp_usrreq.c 4.28 82/04/25 */ |
1bd53abe BJ |
2 | |
3 | #include "../h/param.h" | |
53a5409e BJ |
4 | #include "../h/dir.h" |
5 | #include "../h/user.h" | |
1bd53abe | 6 | #include "../h/mbuf.h" |
d52566dd | 7 | #include "../h/protosw.h" |
53a5409e BJ |
8 | #include "../h/socket.h" |
9 | #include "../h/socketvar.h" | |
ce605ce8 | 10 | #include "../net/in.h" |
72e4f44e | 11 | #include "../net/if.h" |
c124e997 | 12 | #include "../net/route.h" |
ce605ce8 BJ |
13 | #include "../net/in_pcb.h" |
14 | #include "../net/in_systm.h" | |
eb44bfb2 BJ |
15 | #include "../net/ip.h" |
16 | #include "../net/ip_var.h" | |
72e4f44e | 17 | #include "../net/ip_icmp.h" |
53a5409e BJ |
18 | #include "../net/udp.h" |
19 | #include "../net/udp_var.h" | |
8a2f82db | 20 | #include <errno.h> |
d52566dd | 21 | |
2b4b57cd BJ |
22 | /* |
23 | * UDP protocol implementation. | |
24 | * Per RFC 768, August, 1980. | |
25 | */ | |
d52566dd BJ |
26 | udp_init() |
27 | { | |
28 | ||
ce605ce8 | 29 | COUNT(UDP_INIT); |
eb44bfb2 | 30 | udb.inp_next = udb.inp_prev = &udb; |
d52566dd | 31 | } |
1bd53abe | 32 | |
eb44bfb2 | 33 | int udpcksum; |
2b4b57cd | 34 | struct sockaddr_in udp_in = { AF_INET }; |
eb44bfb2 | 35 | |
2b4b57cd BJ |
36 | udp_input(m0) |
37 | struct mbuf *m0; | |
1bd53abe | 38 | { |
eb44bfb2 | 39 | register struct udpiphdr *ui; |
53a5409e | 40 | register struct inpcb *inp; |
2b4b57cd BJ |
41 | register struct mbuf *m; |
42 | int len, ulen; | |
eb44bfb2 | 43 | |
ce605ce8 | 44 | COUNT(UDP_INPUT); |
2b4b57cd | 45 | /* |
4aed14e3 | 46 | * Get IP and UDP header together in first mbuf. |
2b4b57cd BJ |
47 | */ |
48 | m = m0; | |
89925e89 BJ |
49 | if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && |
50 | (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { | |
2b4b57cd | 51 | udpstat.udps_hdrops++; |
89925e89 | 52 | return; |
2b4b57cd | 53 | } |
4e60622a | 54 | ui = mtod(m, struct udpiphdr *); |
4aed14e3 | 55 | if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) |
cca1853f | 56 | ip_stripoptions((struct ip *)ui, (struct mbuf *)0); |
2b4b57cd BJ |
57 | |
58 | /* | |
4aed14e3 BJ |
59 | * Make mbuf data length reflect UDP length. |
60 | * If not enough data to reflect UDP length, drop. | |
2b4b57cd | 61 | */ |
4ad99bae | 62 | ulen = ntohs((u_short)ui->ui_ulen); |
cca1853f | 63 | len = sizeof (struct udphdr) + ulen; |
2b4b57cd BJ |
64 | if (((struct ip *)ui)->ip_len != len) { |
65 | if (len > ((struct ip *)ui)->ip_len) { | |
66 | udpstat.udps_badlen++; | |
67 | goto bad; | |
68 | } | |
69 | m_adj(m, ((struct ip *)ui)->ip_len - len); | |
70 | /* (struct ip *)ui->ip_len = len; */ | |
71 | } | |
72 | ||
73 | /* | |
4aed14e3 | 74 | * Checksum extended UDP header and data. |
2b4b57cd | 75 | */ |
eb44bfb2 | 76 | if (udpcksum) { |
2b4b57cd BJ |
77 | ui->ui_next = ui->ui_prev = 0; |
78 | ui->ui_x1 = 0; | |
cca1853f BJ |
79 | ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen)); |
80 | if (ui->ui_sum = in_cksum(m, len)) { | |
2b4b57cd | 81 | udpstat.udps_badsum++; |
eb44bfb2 BJ |
82 | printf("udp cksum %x\n", ui->ui_sum); |
83 | m_freem(m); | |
84 | return; | |
85 | } | |
86 | } | |
2b4b57cd BJ |
87 | |
88 | /* | |
1aa87517 BJ |
89 | * Locate pcb for datagram. On wildcard match, update |
90 | * control block to anchor network and host address. | |
2b4b57cd | 91 | */ |
2b4b57cd | 92 | inp = in_pcblookup(&udb, |
ebcadd38 BJ |
93 | ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, |
94 | INPLOOKUP_WILDCARD); | |
72e4f44e SL |
95 | if (inp == 0) { |
96 | struct in_addr broadcastaddr; | |
97 | ||
98 | broadcastaddr = if_makeaddr(ui->ui_dst.s_net, INADDR_ANY); | |
39674d5f | 99 | if (ui->ui_dst.s_addr == broadcastaddr.s_addr) |
72e4f44e SL |
100 | goto bad; |
101 | icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT); | |
102 | return; | |
103 | } | |
2b4b57cd BJ |
104 | |
105 | /* | |
106 | * Construct sockaddr format source address. | |
107 | * Stuff source address and datagram in user buffer. | |
108 | */ | |
109 | udp_in.sin_port = ui->ui_sport; | |
110 | udp_in.sin_addr = ui->ui_src; | |
4e60622a BJ |
111 | m->m_len -= sizeof (struct udpiphdr); |
112 | m->m_off += sizeof (struct udpiphdr); | |
113 | if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) | |
2b4b57cd | 114 | goto bad; |
4e60622a | 115 | sorwakeup(inp->inp_socket); |
53a5409e | 116 | return; |
2b4b57cd | 117 | bad: |
53a5409e | 118 | m_freem(m); |
1bd53abe BJ |
119 | } |
120 | ||
72e4f44e SL |
121 | udp_abort(inp) |
122 | struct inpcb *inp; | |
123 | { | |
124 | struct socket *so = inp->inp_socket; | |
125 | ||
126 | in_pcbdisconnect(inp); | |
127 | soisdisconnected(so); | |
1bd53abe BJ |
128 | } |
129 | ||
39674d5f SL |
130 | udp_ctlinput(cmd, arg) |
131 | int cmd; | |
132 | caddr_t arg; | |
133 | { | |
134 | struct in_addr *sin; | |
135 | extern u_char inetctlerrmap[]; | |
136 | COUNT(UDP_CTLINPUT); | |
137 | ||
138 | if (cmd < 0 || cmd > PRC_NCMDS) | |
139 | return; | |
140 | switch (cmd) { | |
141 | ||
142 | case PRC_ROUTEDEAD: | |
143 | break; | |
144 | ||
145 | case PRC_QUENCH: | |
146 | break; | |
147 | ||
148 | /* these are handled by ip */ | |
149 | case PRC_IFDOWN: | |
150 | case PRC_HOSTDEAD: | |
151 | case PRC_HOSTUNREACH: | |
152 | break; | |
153 | ||
154 | default: | |
155 | sin = &((struct icmp *)arg)->icmp_ip.ip_dst; | |
156 | in_pcbnotify(&udb, sin, inetctlerrmap[cmd], udp_abort); | |
157 | } | |
158 | } | |
159 | ||
4ad99bae | 160 | udp_output(inp, m0) |
2b4b57cd | 161 | struct inpcb *inp; |
2b4b57cd | 162 | struct mbuf *m0; |
1bd53abe | 163 | { |
2b4b57cd BJ |
164 | register struct mbuf *m; |
165 | register struct udpiphdr *ui; | |
166 | register int len = 0; | |
167 | ||
ce605ce8 | 168 | COUNT(UDP_OUTPUT); |
2b4b57cd BJ |
169 | /* |
170 | * Calculate data length and get a mbuf | |
4aed14e3 | 171 | * for UDP and IP headers. |
2b4b57cd BJ |
172 | */ |
173 | for (m = m0; m; m = m->m_next) | |
174 | len += m->m_len; | |
ef9b4258 | 175 | m = m_get(M_DONTWAIT); |
8a2f82db SL |
176 | if (m == 0) { |
177 | m_freem(m0); | |
178 | return (ENOBUFS); | |
179 | } | |
2b4b57cd BJ |
180 | |
181 | /* | |
4aed14e3 | 182 | * Fill in mbuf with extended UDP header |
2b4b57cd BJ |
183 | * and addresses and length put into network format. |
184 | */ | |
185 | m->m_off = MMAXOFF - sizeof (struct udpiphdr); | |
186 | m->m_len = sizeof (struct udpiphdr); | |
187 | m->m_next = m0; | |
188 | ui = mtod(m, struct udpiphdr *); | |
189 | ui->ui_next = ui->ui_prev = 0; | |
190 | ui->ui_x1 = 0; | |
191 | ui->ui_pr = IPPROTO_UDP; | |
4e60622a BJ |
192 | ui->ui_len = sizeof (struct udpiphdr) + len; |
193 | ui->ui_src = inp->inp_laddr; | |
194 | ui->ui_dst = inp->inp_faddr; | |
195 | ui->ui_sport = inp->inp_lport; | |
196 | ui->ui_dport = inp->inp_fport; | |
4ad99bae | 197 | ui->ui_ulen = htons((u_short)len); |
2b4b57cd BJ |
198 | |
199 | /* | |
200 | * Stuff checksum and output datagram. | |
201 | */ | |
202 | ui->ui_sum = 0; | |
ce605ce8 | 203 | ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); |
4e60622a BJ |
204 | ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; |
205 | ((struct ip *)ui)->ip_ttl = MAXTTL; | |
8a2f82db SL |
206 | return (ip_output(m, (struct mbuf *)0, 0, |
207 | inp->inp_socket->so_state & SS_PRIV)); | |
1bd53abe BJ |
208 | } |
209 | ||
53a5409e BJ |
210 | udp_usrreq(so, req, m, addr) |
211 | struct socket *so; | |
1bd53abe BJ |
212 | int req; |
213 | struct mbuf *m; | |
cdad2eb1 | 214 | caddr_t addr; |
1bd53abe | 215 | { |
53a5409e | 216 | struct inpcb *inp = sotoinpcb(so); |
8a2f82db | 217 | int error = 0; |
1bd53abe | 218 | |
ce605ce8 | 219 | COUNT(UDP_USRREQ); |
bbb5f5dd | 220 | if (inp == 0 && req != PRU_ATTACH) |
4e60622a | 221 | return (EINVAL); |
1bd53abe BJ |
222 | switch (req) { |
223 | ||
224 | case PRU_ATTACH: | |
53a5409e BJ |
225 | if (inp != 0) |
226 | return (EINVAL); | |
8a2f82db SL |
227 | error = in_pcbattach(so, &udb, 2048, 2048, |
228 | (struct sockaddr_in *)addr); | |
53a5409e | 229 | break; |
1bd53abe BJ |
230 | |
231 | case PRU_DETACH: | |
53a5409e BJ |
232 | if (inp == 0) |
233 | return (ENOTCONN); | |
405c9168 | 234 | in_pcbdetach(inp); |
53a5409e | 235 | break; |
1bd53abe BJ |
236 | |
237 | case PRU_CONNECT: | |
4ad99bae | 238 | if (inp->inp_faddr.s_addr) |
53a5409e | 239 | return (EISCONN); |
405c9168 | 240 | error = in_pcbconnect(inp, (struct sockaddr_in *)addr); |
8a2f82db SL |
241 | if (error == 0) |
242 | soisconnected(so); | |
1bd53abe BJ |
243 | break; |
244 | ||
2b4b57cd BJ |
245 | case PRU_ACCEPT: |
246 | return (EOPNOTSUPP); | |
247 | ||
53a5409e | 248 | case PRU_DISCONNECT: |
4ad99bae | 249 | if (inp->inp_faddr.s_addr == 0) |
53a5409e | 250 | return (ENOTCONN); |
405c9168 | 251 | in_pcbdisconnect(inp); |
53a5409e | 252 | soisdisconnected(so); |
1bd53abe BJ |
253 | break; |
254 | ||
cdad2eb1 BJ |
255 | case PRU_SHUTDOWN: |
256 | socantsendmore(so); | |
257 | break; | |
258 | ||
1aa87517 BJ |
259 | case PRU_SEND: { |
260 | struct in_addr laddr; | |
261 | ||
53a5409e | 262 | if (addr) { |
1aa87517 | 263 | laddr = inp->inp_laddr; |
02bcdb4e | 264 | if (inp->inp_faddr.s_addr) |
53a5409e | 265 | return (EISCONN); |
405c9168 | 266 | error = in_pcbconnect(inp, (struct sockaddr_in *)addr); |
02bcdb4e | 267 | if (error) |
8a2f82db | 268 | break; |
4ad99bae BJ |
269 | } else { |
270 | if (inp->inp_faddr.s_addr == 0) | |
271 | return (ENOTCONN); | |
272 | } | |
8a2f82db | 273 | error = udp_output(inp, m); |
1aa87517 | 274 | if (addr) { |
405c9168 | 275 | in_pcbdisconnect(inp); |
1aa87517 BJ |
276 | inp->inp_laddr = laddr; |
277 | } | |
278 | } | |
1bd53abe BJ |
279 | break; |
280 | ||
281 | case PRU_ABORT: | |
405c9168 | 282 | in_pcbdetach(inp); |
53a5409e BJ |
283 | sofree(so); |
284 | soisdisconnected(so); | |
1bd53abe BJ |
285 | break; |
286 | ||
287 | case PRU_CONTROL: | |
53a5409e | 288 | return (EOPNOTSUPP); |
1bd53abe | 289 | |
126472ab SL |
290 | case PRU_SOCKADDR: |
291 | in_setsockaddr((struct sockaddr_in *)addr, inp); | |
292 | break; | |
293 | ||
1bd53abe BJ |
294 | default: |
295 | panic("udp_usrreq"); | |
d52566dd | 296 | } |
8a2f82db | 297 | return (error); |
d52566dd | 298 | } |