1/*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95
34 * $Id: udp_usrreq.c,v 1.37 1997/04/03 05:14:45 davidg Exp $
35 */
36
37#include <sys/param.h>
38#include <sys/queue.h>
39#include <sys/systm.h>
40#include <sys/errno.h>
41#include <sys/kernel.h>
42#include <sys/malloc.h>
43#include <sys/mbuf.h>
44#include <sys/protosw.h>
45#include <sys/socket.h>
46#include <sys/socketvar.h>
47#include <sys/stat.h>
48#include <sys/sysctl.h>
49#include <sys/syslog.h>
50
51#include <net/if.h>
52#include <net/route.h>
53
54#include <netinet/in.h>
55#include <netinet/in_systm.h>
56#include <netinet/ip.h>
57#include <netinet/in_pcb.h>
58#include <netinet/in_var.h>
59#include <netinet/ip_var.h>
60#include <netinet/ip_icmp.h>
61#include <netinet/udp.h>
62#include <netinet/udp_var.h>
63
64/*
65 * UDP protocol implementation.
66 * Per RFC 768, August, 1980.
67 */
68#ifndef COMPAT_42
69static int udpcksum = 1;
70#else
71static int udpcksum = 0; /* XXX */
72#endif
73SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW,
74 &udpcksum, 0, "");
75
76static int log_in_vain = 0;
77SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW,
78 &log_in_vain, 0, "");
79
80static struct inpcbhead udb; /* from udp_var.h */
81static struct inpcbinfo udbinfo;
82
83#ifndef UDBHASHSIZE
84#define UDBHASHSIZE 64
85#endif
86
87static struct udpstat udpstat; /* from udp_var.h */
88SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD,
89 &udpstat, udpstat, "");
90
91static struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
92
93static int udp_output __P((struct inpcb *, struct mbuf *, struct mbuf *,
94 struct mbuf *, struct proc *));
95static void udp_notify __P((struct inpcb *, int));
96
97void
98udp_init()
99{
100 LIST_INIT(&udb);
101 udbinfo.listhead = &udb;
102 udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask);
103}
104
105void
106udp_input(m, iphlen)
107 register struct mbuf *m;
108 int iphlen;
109{
110 register struct ip *ip;
111 register struct udphdr *uh;
112 register struct inpcb *inp;
113 struct mbuf *opts = 0;
114 int len;
115 struct ip save_ip;
116
117 udpstat.udps_ipackets++;
118
119 /*
120 * Strip IP options, if any; should skip this,
121 * make available to user, and use on returned packets,
122 * but we don't yet have a way to check the checksum
123 * with options still present.
124 */
125 if (iphlen > sizeof (struct ip)) {
126 ip_stripoptions(m, (struct mbuf *)0);
127 iphlen = sizeof(struct ip);
128 }
129
130 /*
131 * Get IP and UDP header together in first mbuf.
132 */
133 ip = mtod(m, struct ip *);
134 if (m->m_len < iphlen + sizeof(struct udphdr)) {
135 if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
136 udpstat.udps_hdrops++;
137 return;
138 }
139 ip = mtod(m, struct ip *);
140 }
141 uh = (struct udphdr *)((caddr_t)ip + iphlen);
142
143 /*
144 * Make mbuf data length reflect UDP length.
145 * If not enough data to reflect UDP length, drop.
146 */
147 len = ntohs((u_short)uh->uh_ulen);
148 if (ip->ip_len != len) {
149 if (len > ip->ip_len || len < sizeof(struct udphdr)) {
150 udpstat.udps_badlen++;
151 goto bad;
152 }
153 m_adj(m, len - ip->ip_len);
154 /* ip->ip_len = len; */
155 }
156 /*
157 * Save a copy of the IP header in case we want restore it
158 * for sending an ICMP error message in response.
159 */
160 save_ip = *ip;
161
162 /*
163 * Checksum extended UDP header and data.
164 */
165 if (uh->uh_sum) {
166 ((struct ipovly *)ip)->ih_next = 0;
167 ((struct ipovly *)ip)->ih_prev = 0;
168 ((struct ipovly *)ip)->ih_x1 = 0;
169 ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
170 uh->uh_sum = in_cksum(m, len + sizeof (struct ip));
171 if (uh->uh_sum) {
172 udpstat.udps_badsum++;
173 m_freem(m);
174 return;
175 }
176 }
177
178 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
179 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
180 struct inpcb *last;
181 /*
182 * Deliver a multicast or broadcast datagram to *all* sockets
183 * for which the local and remote addresses and ports match
184 * those of the incoming datagram. This allows more than
185 * one process to receive multi/broadcasts on the same port.
186 * (This really ought to be done for unicast datagrams as
187 * well, but that would cause problems with existing
188 * applications that open both address-specific sockets and
189 * a wildcard socket listening to the same port -- they would
190 * end up receiving duplicates of every unicast datagram.
191 * Those applications open the multiple sockets to overcome an
192 * inadequacy of the UDP socket interface, but for backwards
193 * compatibility we avoid the problem here rather than
194 * fixing the interface. Maybe 4.5BSD will remedy this?)
195 */
196
197 /*
198 * Construct sockaddr format source address.
199 */
200 udp_in.sin_port = uh->uh_sport;
201 udp_in.sin_addr = ip->ip_src;
202 m->m_len -= sizeof (struct udpiphdr);
203 m->m_data += sizeof (struct udpiphdr);
204 /*
205 * Locate pcb(s) for datagram.
206 * (Algorithm copied from raw_intr().)
207 */
208 last = NULL;
209 for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
210 if (inp->inp_lport != uh->uh_dport)
211 continue;
212 if (inp->inp_laddr.s_addr != INADDR_ANY) {
213 if (inp->inp_laddr.s_addr !=
214 ip->ip_dst.s_addr)
215 continue;
216 }
217 if (inp->inp_faddr.s_addr != INADDR_ANY) {
218 if (inp->inp_faddr.s_addr !=
219 ip->ip_src.s_addr ||
220 inp->inp_fport != uh->uh_sport)
221 continue;
222 }
223
224 if (last != NULL) {
225 struct mbuf *n;
226
227 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
228 if (last->inp_flags & INP_CONTROLOPTS
229 || last->inp_socket->so_options & SO_TIMESTAMP)
230 ip_savecontrol(last, &opts, ip, n);
231 if (sbappendaddr(&last->inp_socket->so_rcv,
232 (struct sockaddr *)&udp_in,
233 n, opts) == 0) {
234 m_freem(n);
235 if (opts)
236 m_freem(opts);
237 udpstat.udps_fullsock++;
238 } else
239 sorwakeup(last->inp_socket);
240 opts = 0;
241 }
242 }
243 last = inp;
244 /*
245 * Don't look for additional matches if this one does
246 * not have either the SO_REUSEPORT or SO_REUSEADDR
247 * socket options set. This heuristic avoids searching
248 * through all pcbs in the common case of a non-shared
249 * port. It * assumes that an application will never
250 * clear these options after setting them.
251 */
252 if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0))
253 break;
254 }
255
256 if (last == NULL) {
257 /*
258 * No matching pcb found; discard datagram.
259 * (No need to send an ICMP Port Unreachable
260 * for a broadcast or multicast datgram.)
261 */
262 udpstat.udps_noportbcast++;
263 goto bad;
264 }
265 if (last->inp_flags & INP_CONTROLOPTS
266 || last->inp_socket->so_options & SO_TIMESTAMP)
267 ip_savecontrol(last, &opts, ip, m);
268 if (sbappendaddr(&last->inp_socket->so_rcv,
269 (struct sockaddr *)&udp_in,
270 m, opts) == 0) {
271 udpstat.udps_fullsock++;
272 goto bad;
273 }
274 sorwakeup(last->inp_socket);
275 return;
276 }
277 /*
278 * Locate pcb for datagram.
279 */
280 inp = in_pcblookuphash(&udbinfo, ip->ip_src, uh->uh_sport,
281 ip->ip_dst, uh->uh_dport, 1);
282 if (inp == NULL) {
283 if (log_in_vain) {
284 char buf[4*sizeof "123"];
285
286 strcpy(buf, inet_ntoa(ip->ip_dst));
287 log(LOG_INFO, "Connection attempt to UDP %s:%d"
288 " from %s:%d\n",
289 buf, ntohs(uh->uh_dport),
290 inet_ntoa(ip->ip_src), ntohs(uh->uh_sport));
291 }
292 udpstat.udps_noport++;
293 if (m->m_flags & (M_BCAST | M_MCAST)) {
294 udpstat.udps_noportbcast++;
295 goto bad;
296 }
297 *ip = save_ip;
298 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
299 return;
300 }
301
302 /*
303 * Construct sockaddr format source address.
304 * Stuff source address and datagram in user buffer.
305 */
306 udp_in.sin_port = uh->uh_sport;
307 udp_in.sin_addr = ip->ip_src;
308 if (inp->inp_flags & INP_CONTROLOPTS
309 || inp->inp_socket->so_options & SO_TIMESTAMP)
310 ip_savecontrol(inp, &opts, ip, m);
311 iphlen += sizeof(struct udphdr);
312 m->m_len -= iphlen;
313 m->m_pkthdr.len -= iphlen;
314 m->m_data += iphlen;
315 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
316 m, opts) == 0) {
317 udpstat.udps_fullsock++;
318 goto bad;
319 }
320 sorwakeup(inp->inp_socket);
321 return;
322bad:
323 m_freem(m);
324 if (opts)
325 m_freem(opts);
326}
327
328/*
329 * Notify a udp user of an asynchronous error;
330 * just wake up so that he can collect error status.
331 */
332static void
333udp_notify(inp, errno)
334 register struct inpcb *inp;
335 int errno;
336{
337 inp->inp_socket->so_error = errno;
338 sorwakeup(inp->inp_socket);
339 sowwakeup(inp->inp_socket);
340}
341
342void
343udp_ctlinput(cmd, sa, vip)
344 int cmd;
345 struct sockaddr *sa;
346 void *vip;
347{
348 register struct ip *ip = vip;
349 register struct udphdr *uh;
350
351 if (!PRC_IS_REDIRECT(cmd) &&
352 ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
353 return;
354 if (ip) {
355 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
356 in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
357 cmd, udp_notify);
358 } else
359 in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
360}
361
362static int
363udp_output(inp, m, addr, control, p)
364 register struct inpcb *inp;
365 register struct mbuf *m;
366 struct mbuf *addr, *control;
367 struct proc *p;
368{
369 register struct udpiphdr *ui;
370 register int len = m->m_pkthdr.len;
371 struct in_addr laddr;
372 int s = 0, error = 0;
373
374 if (control)
375 m_freem(control); /* XXX */
376
377 if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
378 error = EMSGSIZE;
379 goto release;
380 }
381
382 if (addr) {
383 laddr = inp->inp_laddr;
384 if (inp->inp_faddr.s_addr != INADDR_ANY) {
385 error = EISCONN;
386 goto release;
387 }
388 /*
389 * Must block input while temporarily connected.
390 */
391 s = splnet();
392 error = in_pcbconnect(inp, addr, p);
393 if (error) {
394 splx(s);
395 goto release;
396 }
397 } else {
398 if (inp->inp_faddr.s_addr == INADDR_ANY) {
399 error = ENOTCONN;
400 goto release;
401 }
402 }
403 /*
404 * Calculate data length and get a mbuf
405 * for UDP and IP headers.
406 */
407 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
408 if (m == 0) {
409 error = ENOBUFS;
410 if (addr)
411 splx(s);
412 goto release;
413 }
414
415 /*
416 * Fill in mbuf with extended UDP header
417 * and addresses and length put into network format.
418 */
419 ui = mtod(m, struct udpiphdr *);
420 ui->ui_next = ui->ui_prev = 0;
421 ui->ui_x1 = 0;
422 ui->ui_pr = IPPROTO_UDP;
423 ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
424 ui->ui_src = inp->inp_laddr;
425 ui->ui_dst = inp->inp_faddr;
426 ui->ui_sport = inp->inp_lport;
427 ui->ui_dport = inp->inp_fport;
428 ui->ui_ulen = ui->ui_len;
429
430 /*
431 * Stuff checksum and output datagram.
432 */
433 ui->ui_sum = 0;
434 if (udpcksum) {
435 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
436 ui->ui_sum = 0xffff;
437 }
438 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
439 ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */
440 ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
441 udpstat.udps_opackets++;
442 error = ip_output(m, inp->inp_options, &inp->inp_route,
443 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
444 inp->inp_moptions);
445
446 if (addr) {
447 in_pcbdisconnect(inp);
448 inp->inp_laddr = laddr;
449 splx(s);
450 }
451 return (error);
452
453release:
454 m_freem(m);
455 return (error);
456}
457
458static u_long udp_sendspace = 9216; /* really max datagram size */
459 /* 40 1K datagrams */
460SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
461 &udp_sendspace, 0, "");
462
463static u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
464SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
465 &udp_recvspace, 0, "");
466
467static int
468udp_abort(struct socket *so)
469{
470 struct inpcb *inp;
471 int s;
472
473 inp = sotoinpcb(so);
474 if (inp == 0)
475 return EINVAL; /* ??? possible? panic instead? */
476 soisdisconnected(so);
477 s = splnet();
478 in_pcbdetach(inp);
479 splx(s);
480 return 0;
481}
482
483static int
484udp_attach(struct socket *so, int proto, struct proc *p)
485{
486 struct inpcb *inp;
487 int s, error;
488
489 inp = sotoinpcb(so);
490 if (inp != 0)
491 return EINVAL;
492
493 s = splnet();
494 error = in_pcballoc(so, &udbinfo, p);
495 splx(s);
496 if (error)
497 return error;
498 error = soreserve(so, udp_sendspace, udp_recvspace);
499 if (error)
500 return error;
501 ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl;
502 return 0;
503}
504
505static int
506udp_bind(struct socket *so, struct mbuf *nam, struct proc *p)
507{
508 struct inpcb *inp;
509 int s, error;
510
511 inp = sotoinpcb(so);
512 if (inp == 0)
513 return EINVAL;
514 s = splnet();
515 error = in_pcbbind(inp, nam, p);
516 splx(s);
517 return error;
518}
519
520static int
521udp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
522{
523 struct inpcb *inp;
524 int s, error;
525
526 inp = sotoinpcb(so);
527 if (inp == 0)
528 return EINVAL;
529 if (inp->inp_faddr.s_addr != INADDR_ANY)
530 return EISCONN;
531 s = splnet();
532 error = in_pcbconnect(inp, nam, p);
533 splx(s);
534 if (error == 0)
535 soisconnected(so);
536 return error;
537}
538
539static int
540udp_detach(struct socket *so)
541{
542 struct inpcb *inp;
543 int s;
544
545 inp = sotoinpcb(so);
546 if (inp == 0)
547 return EINVAL;
548 s = splnet();
549 in_pcbdetach(inp);
550 splx(s);
551 return 0;
552}
553
554static int
555udp_disconnect(struct socket *so)
556{
557 struct inpcb *inp;
558 int s;
559
560 inp = sotoinpcb(so);
561 if (inp == 0)
562 return EINVAL;
563 if (inp->inp_faddr.s_addr == INADDR_ANY)
564 return ENOTCONN;
565
566 s = splnet();
567 in_pcbdisconnect(inp);
568 inp->inp_laddr.s_addr = INADDR_ANY;
569 splx(s);
570 so->so_state &= ~SS_ISCONNECTED; /* XXX */
571 return 0;
572}
573
574static int
575udp_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *addr,
576 struct mbuf *control, struct proc *p)
577{
578 struct inpcb *inp;
579
580 inp = sotoinpcb(so);
581 if (inp == 0) {
582 m_freem(m);
583 return EINVAL;
584 }
585 return udp_output(inp, m, addr, control, p);
586}
587
588static int
589udp_shutdown(struct socket *so)
590{
591 struct inpcb *inp;
592
593 inp = sotoinpcb(so);
594 if (inp == 0)
595 return EINVAL;
596 socantsendmore(so);
597 return 0;
598}
599
600struct pr_usrreqs udp_usrreqs = {
601 udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect,
602 pru_connect2_notsupp, in_control, udp_detach, udp_disconnect,
603 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
604 pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown,
605 in_setsockaddr, sosend, soreceive, soselect
606};
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95
34 * $Id: udp_usrreq.c,v 1.37 1997/04/03 05:14:45 davidg Exp $
35 */
36
37#include <sys/param.h>
38#include <sys/queue.h>
39#include <sys/systm.h>
40#include <sys/errno.h>
41#include <sys/kernel.h>
42#include <sys/malloc.h>
43#include <sys/mbuf.h>
44#include <sys/protosw.h>
45#include <sys/socket.h>
46#include <sys/socketvar.h>
47#include <sys/stat.h>
48#include <sys/sysctl.h>
49#include <sys/syslog.h>
50
51#include <net/if.h>
52#include <net/route.h>
53
54#include <netinet/in.h>
55#include <netinet/in_systm.h>
56#include <netinet/ip.h>
57#include <netinet/in_pcb.h>
58#include <netinet/in_var.h>
59#include <netinet/ip_var.h>
60#include <netinet/ip_icmp.h>
61#include <netinet/udp.h>
62#include <netinet/udp_var.h>
63
64/*
65 * UDP protocol implementation.
66 * Per RFC 768, August, 1980.
67 */
68#ifndef COMPAT_42
69static int udpcksum = 1;
70#else
71static int udpcksum = 0; /* XXX */
72#endif
73SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW,
74 &udpcksum, 0, "");
75
76static int log_in_vain = 0;
77SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW,
78 &log_in_vain, 0, "");
79
80static struct inpcbhead udb; /* from udp_var.h */
81static struct inpcbinfo udbinfo;
82
83#ifndef UDBHASHSIZE
84#define UDBHASHSIZE 64
85#endif
86
87static struct udpstat udpstat; /* from udp_var.h */
88SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD,
89 &udpstat, udpstat, "");
90
91static struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
92
93static int udp_output __P((struct inpcb *, struct mbuf *, struct mbuf *,
94 struct mbuf *, struct proc *));
95static void udp_notify __P((struct inpcb *, int));
96
97void
98udp_init()
99{
100 LIST_INIT(&udb);
101 udbinfo.listhead = &udb;
102 udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask);
103}
104
105void
106udp_input(m, iphlen)
107 register struct mbuf *m;
108 int iphlen;
109{
110 register struct ip *ip;
111 register struct udphdr *uh;
112 register struct inpcb *inp;
113 struct mbuf *opts = 0;
114 int len;
115 struct ip save_ip;
116
117 udpstat.udps_ipackets++;
118
119 /*
120 * Strip IP options, if any; should skip this,
121 * make available to user, and use on returned packets,
122 * but we don't yet have a way to check the checksum
123 * with options still present.
124 */
125 if (iphlen > sizeof (struct ip)) {
126 ip_stripoptions(m, (struct mbuf *)0);
127 iphlen = sizeof(struct ip);
128 }
129
130 /*
131 * Get IP and UDP header together in first mbuf.
132 */
133 ip = mtod(m, struct ip *);
134 if (m->m_len < iphlen + sizeof(struct udphdr)) {
135 if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
136 udpstat.udps_hdrops++;
137 return;
138 }
139 ip = mtod(m, struct ip *);
140 }
141 uh = (struct udphdr *)((caddr_t)ip + iphlen);
142
143 /*
144 * Make mbuf data length reflect UDP length.
145 * If not enough data to reflect UDP length, drop.
146 */
147 len = ntohs((u_short)uh->uh_ulen);
148 if (ip->ip_len != len) {
149 if (len > ip->ip_len || len < sizeof(struct udphdr)) {
150 udpstat.udps_badlen++;
151 goto bad;
152 }
153 m_adj(m, len - ip->ip_len);
154 /* ip->ip_len = len; */
155 }
156 /*
157 * Save a copy of the IP header in case we want restore it
158 * for sending an ICMP error message in response.
159 */
160 save_ip = *ip;
161
162 /*
163 * Checksum extended UDP header and data.
164 */
165 if (uh->uh_sum) {
166 ((struct ipovly *)ip)->ih_next = 0;
167 ((struct ipovly *)ip)->ih_prev = 0;
168 ((struct ipovly *)ip)->ih_x1 = 0;
169 ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
170 uh->uh_sum = in_cksum(m, len + sizeof (struct ip));
171 if (uh->uh_sum) {
172 udpstat.udps_badsum++;
173 m_freem(m);
174 return;
175 }
176 }
177
178 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
179 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
180 struct inpcb *last;
181 /*
182 * Deliver a multicast or broadcast datagram to *all* sockets
183 * for which the local and remote addresses and ports match
184 * those of the incoming datagram. This allows more than
185 * one process to receive multi/broadcasts on the same port.
186 * (This really ought to be done for unicast datagrams as
187 * well, but that would cause problems with existing
188 * applications that open both address-specific sockets and
189 * a wildcard socket listening to the same port -- they would
190 * end up receiving duplicates of every unicast datagram.
191 * Those applications open the multiple sockets to overcome an
192 * inadequacy of the UDP socket interface, but for backwards
193 * compatibility we avoid the problem here rather than
194 * fixing the interface. Maybe 4.5BSD will remedy this?)
195 */
196
197 /*
198 * Construct sockaddr format source address.
199 */
200 udp_in.sin_port = uh->uh_sport;
201 udp_in.sin_addr = ip->ip_src;
202 m->m_len -= sizeof (struct udpiphdr);
203 m->m_data += sizeof (struct udpiphdr);
204 /*
205 * Locate pcb(s) for datagram.
206 * (Algorithm copied from raw_intr().)
207 */
208 last = NULL;
209 for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
210 if (inp->inp_lport != uh->uh_dport)
211 continue;
212 if (inp->inp_laddr.s_addr != INADDR_ANY) {
213 if (inp->inp_laddr.s_addr !=
214 ip->ip_dst.s_addr)
215 continue;
216 }
217 if (inp->inp_faddr.s_addr != INADDR_ANY) {
218 if (inp->inp_faddr.s_addr !=
219 ip->ip_src.s_addr ||
220 inp->inp_fport != uh->uh_sport)
221 continue;
222 }
223
224 if (last != NULL) {
225 struct mbuf *n;
226
227 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
228 if (last->inp_flags & INP_CONTROLOPTS
229 || last->inp_socket->so_options & SO_TIMESTAMP)
230 ip_savecontrol(last, &opts, ip, n);
231 if (sbappendaddr(&last->inp_socket->so_rcv,
232 (struct sockaddr *)&udp_in,
233 n, opts) == 0) {
234 m_freem(n);
235 if (opts)
236 m_freem(opts);
237 udpstat.udps_fullsock++;
238 } else
239 sorwakeup(last->inp_socket);
240 opts = 0;
241 }
242 }
243 last = inp;
244 /*
245 * Don't look for additional matches if this one does
246 * not have either the SO_REUSEPORT or SO_REUSEADDR
247 * socket options set. This heuristic avoids searching
248 * through all pcbs in the common case of a non-shared
249 * port. It * assumes that an application will never
250 * clear these options after setting them.
251 */
252 if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0))
253 break;
254 }
255
256 if (last == NULL) {
257 /*
258 * No matching pcb found; discard datagram.
259 * (No need to send an ICMP Port Unreachable
260 * for a broadcast or multicast datgram.)
261 */
262 udpstat.udps_noportbcast++;
263 goto bad;
264 }
265 if (last->inp_flags & INP_CONTROLOPTS
266 || last->inp_socket->so_options & SO_TIMESTAMP)
267 ip_savecontrol(last, &opts, ip, m);
268 if (sbappendaddr(&last->inp_socket->so_rcv,
269 (struct sockaddr *)&udp_in,
270 m, opts) == 0) {
271 udpstat.udps_fullsock++;
272 goto bad;
273 }
274 sorwakeup(last->inp_socket);
275 return;
276 }
277 /*
278 * Locate pcb for datagram.
279 */
280 inp = in_pcblookuphash(&udbinfo, ip->ip_src, uh->uh_sport,
281 ip->ip_dst, uh->uh_dport, 1);
282 if (inp == NULL) {
283 if (log_in_vain) {
284 char buf[4*sizeof "123"];
285
286 strcpy(buf, inet_ntoa(ip->ip_dst));
287 log(LOG_INFO, "Connection attempt to UDP %s:%d"
288 " from %s:%d\n",
289 buf, ntohs(uh->uh_dport),
290 inet_ntoa(ip->ip_src), ntohs(uh->uh_sport));
291 }
292 udpstat.udps_noport++;
293 if (m->m_flags & (M_BCAST | M_MCAST)) {
294 udpstat.udps_noportbcast++;
295 goto bad;
296 }
297 *ip = save_ip;
298 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
299 return;
300 }
301
302 /*
303 * Construct sockaddr format source address.
304 * Stuff source address and datagram in user buffer.
305 */
306 udp_in.sin_port = uh->uh_sport;
307 udp_in.sin_addr = ip->ip_src;
308 if (inp->inp_flags & INP_CONTROLOPTS
309 || inp->inp_socket->so_options & SO_TIMESTAMP)
310 ip_savecontrol(inp, &opts, ip, m);
311 iphlen += sizeof(struct udphdr);
312 m->m_len -= iphlen;
313 m->m_pkthdr.len -= iphlen;
314 m->m_data += iphlen;
315 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
316 m, opts) == 0) {
317 udpstat.udps_fullsock++;
318 goto bad;
319 }
320 sorwakeup(inp->inp_socket);
321 return;
322bad:
323 m_freem(m);
324 if (opts)
325 m_freem(opts);
326}
327
328/*
329 * Notify a udp user of an asynchronous error;
330 * just wake up so that he can collect error status.
331 */
332static void
333udp_notify(inp, errno)
334 register struct inpcb *inp;
335 int errno;
336{
337 inp->inp_socket->so_error = errno;
338 sorwakeup(inp->inp_socket);
339 sowwakeup(inp->inp_socket);
340}
341
342void
343udp_ctlinput(cmd, sa, vip)
344 int cmd;
345 struct sockaddr *sa;
346 void *vip;
347{
348 register struct ip *ip = vip;
349 register struct udphdr *uh;
350
351 if (!PRC_IS_REDIRECT(cmd) &&
352 ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
353 return;
354 if (ip) {
355 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
356 in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
357 cmd, udp_notify);
358 } else
359 in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
360}
361
362static int
363udp_output(inp, m, addr, control, p)
364 register struct inpcb *inp;
365 register struct mbuf *m;
366 struct mbuf *addr, *control;
367 struct proc *p;
368{
369 register struct udpiphdr *ui;
370 register int len = m->m_pkthdr.len;
371 struct in_addr laddr;
372 int s = 0, error = 0;
373
374 if (control)
375 m_freem(control); /* XXX */
376
377 if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
378 error = EMSGSIZE;
379 goto release;
380 }
381
382 if (addr) {
383 laddr = inp->inp_laddr;
384 if (inp->inp_faddr.s_addr != INADDR_ANY) {
385 error = EISCONN;
386 goto release;
387 }
388 /*
389 * Must block input while temporarily connected.
390 */
391 s = splnet();
392 error = in_pcbconnect(inp, addr, p);
393 if (error) {
394 splx(s);
395 goto release;
396 }
397 } else {
398 if (inp->inp_faddr.s_addr == INADDR_ANY) {
399 error = ENOTCONN;
400 goto release;
401 }
402 }
403 /*
404 * Calculate data length and get a mbuf
405 * for UDP and IP headers.
406 */
407 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
408 if (m == 0) {
409 error = ENOBUFS;
410 if (addr)
411 splx(s);
412 goto release;
413 }
414
415 /*
416 * Fill in mbuf with extended UDP header
417 * and addresses and length put into network format.
418 */
419 ui = mtod(m, struct udpiphdr *);
420 ui->ui_next = ui->ui_prev = 0;
421 ui->ui_x1 = 0;
422 ui->ui_pr = IPPROTO_UDP;
423 ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
424 ui->ui_src = inp->inp_laddr;
425 ui->ui_dst = inp->inp_faddr;
426 ui->ui_sport = inp->inp_lport;
427 ui->ui_dport = inp->inp_fport;
428 ui->ui_ulen = ui->ui_len;
429
430 /*
431 * Stuff checksum and output datagram.
432 */
433 ui->ui_sum = 0;
434 if (udpcksum) {
435 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
436 ui->ui_sum = 0xffff;
437 }
438 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
439 ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */
440 ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
441 udpstat.udps_opackets++;
442 error = ip_output(m, inp->inp_options, &inp->inp_route,
443 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
444 inp->inp_moptions);
445
446 if (addr) {
447 in_pcbdisconnect(inp);
448 inp->inp_laddr = laddr;
449 splx(s);
450 }
451 return (error);
452
453release:
454 m_freem(m);
455 return (error);
456}
457
458static u_long udp_sendspace = 9216; /* really max datagram size */
459 /* 40 1K datagrams */
460SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
461 &udp_sendspace, 0, "");
462
463static u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
464SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
465 &udp_recvspace, 0, "");
466
467static int
468udp_abort(struct socket *so)
469{
470 struct inpcb *inp;
471 int s;
472
473 inp = sotoinpcb(so);
474 if (inp == 0)
475 return EINVAL; /* ??? possible? panic instead? */
476 soisdisconnected(so);
477 s = splnet();
478 in_pcbdetach(inp);
479 splx(s);
480 return 0;
481}
482
483static int
484udp_attach(struct socket *so, int proto, struct proc *p)
485{
486 struct inpcb *inp;
487 int s, error;
488
489 inp = sotoinpcb(so);
490 if (inp != 0)
491 return EINVAL;
492
493 s = splnet();
494 error = in_pcballoc(so, &udbinfo, p);
495 splx(s);
496 if (error)
497 return error;
498 error = soreserve(so, udp_sendspace, udp_recvspace);
499 if (error)
500 return error;
501 ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl;
502 return 0;
503}
504
505static int
506udp_bind(struct socket *so, struct mbuf *nam, struct proc *p)
507{
508 struct inpcb *inp;
509 int s, error;
510
511 inp = sotoinpcb(so);
512 if (inp == 0)
513 return EINVAL;
514 s = splnet();
515 error = in_pcbbind(inp, nam, p);
516 splx(s);
517 return error;
518}
519
520static int
521udp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
522{
523 struct inpcb *inp;
524 int s, error;
525
526 inp = sotoinpcb(so);
527 if (inp == 0)
528 return EINVAL;
529 if (inp->inp_faddr.s_addr != INADDR_ANY)
530 return EISCONN;
531 s = splnet();
532 error = in_pcbconnect(inp, nam, p);
533 splx(s);
534 if (error == 0)
535 soisconnected(so);
536 return error;
537}
538
539static int
540udp_detach(struct socket *so)
541{
542 struct inpcb *inp;
543 int s;
544
545 inp = sotoinpcb(so);
546 if (inp == 0)
547 return EINVAL;
548 s = splnet();
549 in_pcbdetach(inp);
550 splx(s);
551 return 0;
552}
553
554static int
555udp_disconnect(struct socket *so)
556{
557 struct inpcb *inp;
558 int s;
559
560 inp = sotoinpcb(so);
561 if (inp == 0)
562 return EINVAL;
563 if (inp->inp_faddr.s_addr == INADDR_ANY)
564 return ENOTCONN;
565
566 s = splnet();
567 in_pcbdisconnect(inp);
568 inp->inp_laddr.s_addr = INADDR_ANY;
569 splx(s);
570 so->so_state &= ~SS_ISCONNECTED; /* XXX */
571 return 0;
572}
573
574static int
575udp_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *addr,
576 struct mbuf *control, struct proc *p)
577{
578 struct inpcb *inp;
579
580 inp = sotoinpcb(so);
581 if (inp == 0) {
582 m_freem(m);
583 return EINVAL;
584 }
585 return udp_output(inp, m, addr, control, p);
586}
587
588static int
589udp_shutdown(struct socket *so)
590{
591 struct inpcb *inp;
592
593 inp = sotoinpcb(so);
594 if (inp == 0)
595 return EINVAL;
596 socantsendmore(so);
597 return 0;
598}
599
600struct pr_usrreqs udp_usrreqs = {
601 udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect,
602 pru_connect2_notsupp, in_control, udp_detach, udp_disconnect,
603 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
604 pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown,
605 in_setsockaddr, sosend, soreceive, soselect
606};