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.38 1997/04/27 20:01:16 wollman 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 sockaddr *,
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 sockaddr *addr;
367 struct mbuf *control;
368 struct proc *p;
369{
370 register struct udpiphdr *ui;
371 register int len = m->m_pkthdr.len;
372 struct in_addr laddr;
373 int s = 0, error = 0;
374
375 if (control)
376 m_freem(control); /* XXX */
377
378 if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
379 error = EMSGSIZE;
380 goto release;
381 }
382
383 if (addr) {
384 laddr = inp->inp_laddr;
385 if (inp->inp_faddr.s_addr != INADDR_ANY) {
386 error = EISCONN;
387 goto release;
388 }
389 /*
390 * Must block input while temporarily connected.
391 */
392 s = splnet();
393 error = in_pcbconnect(inp, addr, p);
394 if (error) {
395 splx(s);
396 goto release;
397 }
398 } else {
399 if (inp->inp_faddr.s_addr == INADDR_ANY) {
400 error = ENOTCONN;
401 goto release;
402 }
403 }
404 /*
405 * Calculate data length and get a mbuf
406 * for UDP and IP headers.
407 */
408 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
409 if (m == 0) {
410 error = ENOBUFS;
411 if (addr)
412 splx(s);
413 goto release;
414 }
415
416 /*
417 * Fill in mbuf with extended UDP header
418 * and addresses and length put into network format.
419 */
420 ui = mtod(m, struct udpiphdr *);
421 ui->ui_next = ui->ui_prev = 0;
422 ui->ui_x1 = 0;
423 ui->ui_pr = IPPROTO_UDP;
424 ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
425 ui->ui_src = inp->inp_laddr;
426 ui->ui_dst = inp->inp_faddr;
427 ui->ui_sport = inp->inp_lport;
428 ui->ui_dport = inp->inp_fport;
429 ui->ui_ulen = ui->ui_len;
430
431 /*
432 * Stuff checksum and output datagram.
433 */
434 ui->ui_sum = 0;
435 if (udpcksum) {
436 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
437 ui->ui_sum = 0xffff;
438 }
439 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
440 ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */
441 ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
442 udpstat.udps_opackets++;
443 error = ip_output(m, inp->inp_options, &inp->inp_route,
444 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
445 inp->inp_moptions);
446
447 if (addr) {
448 in_pcbdisconnect(inp);
449 inp->inp_laddr = laddr; /* XXX rehash? */
450 splx(s);
451 }
452 return (error);
453
454release:
455 m_freem(m);
456 return (error);
457}
458
459static u_long udp_sendspace = 9216; /* really max datagram size */
460 /* 40 1K datagrams */
461SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
462 &udp_sendspace, 0, "");
463
464static u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
465SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
466 &udp_recvspace, 0, "");
467
468static int
469udp_abort(struct socket *so)
470{
471 struct inpcb *inp;
472 int s;
473
474 inp = sotoinpcb(so);
475 if (inp == 0)
476 return EINVAL; /* ??? possible? panic instead? */
477 soisdisconnected(so);
478 s = splnet();
479 in_pcbdetach(inp);
480 splx(s);
481 return 0;
482}
483
484static int
485udp_attach(struct socket *so, int proto, struct proc *p)
486{
487 struct inpcb *inp;
488 int s, error;
489
490 inp = sotoinpcb(so);
491 if (inp != 0)
492 return EINVAL;
493
494 s = splnet();
495 error = in_pcballoc(so, &udbinfo, p);
496 splx(s);
497 if (error)
498 return error;
499 error = soreserve(so, udp_sendspace, udp_recvspace);
500 if (error)
501 return error;
502 ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl;
503 return 0;
504}
505
506static int
507udp_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
508{
509 struct inpcb *inp;
510 int s, error;
511
512 inp = sotoinpcb(so);
513 if (inp == 0)
514 return EINVAL;
515 s = splnet();
516 error = in_pcbbind(inp, nam, p);
517 splx(s);
518 return error;
519}
520
521static int
522udp_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
523{
524 struct inpcb *inp;
525 int s, error;
526
527 inp = sotoinpcb(so);
528 if (inp == 0)
529 return EINVAL;
530 if (inp->inp_faddr.s_addr != INADDR_ANY)
531 return EISCONN;
532 s = splnet();
533 error = in_pcbconnect(inp, nam, p);
534 splx(s);
535 if (error == 0)
536 soisconnected(so);
537 return error;
538}
539
540static int
541udp_detach(struct socket *so)
542{
543 struct inpcb *inp;
544 int s;
545
546 inp = sotoinpcb(so);
547 if (inp == 0)
548 return EINVAL;
549 s = splnet();
550 in_pcbdetach(inp);
551 splx(s);
552 return 0;
553}
554
555static int
556udp_disconnect(struct socket *so)
557{
558 struct inpcb *inp;
559 int s;
560
561 inp = sotoinpcb(so);
562 if (inp == 0)
563 return EINVAL;
564 if (inp->inp_faddr.s_addr == INADDR_ANY)
565 return ENOTCONN;
566
567 s = splnet();
568 in_pcbdisconnect(inp);
569 inp->inp_laddr.s_addr = INADDR_ANY;
570 splx(s);
571 so->so_state &= ~SS_ISCONNECTED; /* XXX */
572 return 0;
573}
574
575static int
576udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
577 struct mbuf *control, struct proc *p)
578{
579 struct inpcb *inp;
580
581 inp = sotoinpcb(so);
582 if (inp == 0) {
583 m_freem(m);
584 return EINVAL;
585 }
586 return udp_output(inp, m, addr, control, p);
587}
588
589static int
590udp_shutdown(struct socket *so)
591{
592 struct inpcb *inp;
593
594 inp = sotoinpcb(so);
595 if (inp == 0)
596 return EINVAL;
597 socantsendmore(so);
598 return 0;
599}
600
601struct pr_usrreqs udp_usrreqs = {
602 udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect,
603 pru_connect2_notsupp, in_control, udp_detach, udp_disconnect,
604 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
605 pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown,
606 in_setsockaddr, sosend, soreceive, soselect
607};
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.38 1997/04/27 20:01:16 wollman 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 sockaddr *,
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 sockaddr *addr;
367 struct mbuf *control;
368 struct proc *p;
369{
370 register struct udpiphdr *ui;
371 register int len = m->m_pkthdr.len;
372 struct in_addr laddr;
373 int s = 0, error = 0;
374
375 if (control)
376 m_freem(control); /* XXX */
377
378 if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
379 error = EMSGSIZE;
380 goto release;
381 }
382
383 if (addr) {
384 laddr = inp->inp_laddr;
385 if (inp->inp_faddr.s_addr != INADDR_ANY) {
386 error = EISCONN;
387 goto release;
388 }
389 /*
390 * Must block input while temporarily connected.
391 */
392 s = splnet();
393 error = in_pcbconnect(inp, addr, p);
394 if (error) {
395 splx(s);
396 goto release;
397 }
398 } else {
399 if (inp->inp_faddr.s_addr == INADDR_ANY) {
400 error = ENOTCONN;
401 goto release;
402 }
403 }
404 /*
405 * Calculate data length and get a mbuf
406 * for UDP and IP headers.
407 */
408 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
409 if (m == 0) {
410 error = ENOBUFS;
411 if (addr)
412 splx(s);
413 goto release;
414 }
415
416 /*
417 * Fill in mbuf with extended UDP header
418 * and addresses and length put into network format.
419 */
420 ui = mtod(m, struct udpiphdr *);
421 ui->ui_next = ui->ui_prev = 0;
422 ui->ui_x1 = 0;
423 ui->ui_pr = IPPROTO_UDP;
424 ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
425 ui->ui_src = inp->inp_laddr;
426 ui->ui_dst = inp->inp_faddr;
427 ui->ui_sport = inp->inp_lport;
428 ui->ui_dport = inp->inp_fport;
429 ui->ui_ulen = ui->ui_len;
430
431 /*
432 * Stuff checksum and output datagram.
433 */
434 ui->ui_sum = 0;
435 if (udpcksum) {
436 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
437 ui->ui_sum = 0xffff;
438 }
439 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
440 ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */
441 ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
442 udpstat.udps_opackets++;
443 error = ip_output(m, inp->inp_options, &inp->inp_route,
444 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
445 inp->inp_moptions);
446
447 if (addr) {
448 in_pcbdisconnect(inp);
449 inp->inp_laddr = laddr; /* XXX rehash? */
450 splx(s);
451 }
452 return (error);
453
454release:
455 m_freem(m);
456 return (error);
457}
458
459static u_long udp_sendspace = 9216; /* really max datagram size */
460 /* 40 1K datagrams */
461SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
462 &udp_sendspace, 0, "");
463
464static u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
465SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
466 &udp_recvspace, 0, "");
467
468static int
469udp_abort(struct socket *so)
470{
471 struct inpcb *inp;
472 int s;
473
474 inp = sotoinpcb(so);
475 if (inp == 0)
476 return EINVAL; /* ??? possible? panic instead? */
477 soisdisconnected(so);
478 s = splnet();
479 in_pcbdetach(inp);
480 splx(s);
481 return 0;
482}
483
484static int
485udp_attach(struct socket *so, int proto, struct proc *p)
486{
487 struct inpcb *inp;
488 int s, error;
489
490 inp = sotoinpcb(so);
491 if (inp != 0)
492 return EINVAL;
493
494 s = splnet();
495 error = in_pcballoc(so, &udbinfo, p);
496 splx(s);
497 if (error)
498 return error;
499 error = soreserve(so, udp_sendspace, udp_recvspace);
500 if (error)
501 return error;
502 ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl;
503 return 0;
504}
505
506static int
507udp_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
508{
509 struct inpcb *inp;
510 int s, error;
511
512 inp = sotoinpcb(so);
513 if (inp == 0)
514 return EINVAL;
515 s = splnet();
516 error = in_pcbbind(inp, nam, p);
517 splx(s);
518 return error;
519}
520
521static int
522udp_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
523{
524 struct inpcb *inp;
525 int s, error;
526
527 inp = sotoinpcb(so);
528 if (inp == 0)
529 return EINVAL;
530 if (inp->inp_faddr.s_addr != INADDR_ANY)
531 return EISCONN;
532 s = splnet();
533 error = in_pcbconnect(inp, nam, p);
534 splx(s);
535 if (error == 0)
536 soisconnected(so);
537 return error;
538}
539
540static int
541udp_detach(struct socket *so)
542{
543 struct inpcb *inp;
544 int s;
545
546 inp = sotoinpcb(so);
547 if (inp == 0)
548 return EINVAL;
549 s = splnet();
550 in_pcbdetach(inp);
551 splx(s);
552 return 0;
553}
554
555static int
556udp_disconnect(struct socket *so)
557{
558 struct inpcb *inp;
559 int s;
560
561 inp = sotoinpcb(so);
562 if (inp == 0)
563 return EINVAL;
564 if (inp->inp_faddr.s_addr == INADDR_ANY)
565 return ENOTCONN;
566
567 s = splnet();
568 in_pcbdisconnect(inp);
569 inp->inp_laddr.s_addr = INADDR_ANY;
570 splx(s);
571 so->so_state &= ~SS_ISCONNECTED; /* XXX */
572 return 0;
573}
574
575static int
576udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
577 struct mbuf *control, struct proc *p)
578{
579 struct inpcb *inp;
580
581 inp = sotoinpcb(so);
582 if (inp == 0) {
583 m_freem(m);
584 return EINVAL;
585 }
586 return udp_output(inp, m, addr, control, p);
587}
588
589static int
590udp_shutdown(struct socket *so)
591{
592 struct inpcb *inp;
593
594 inp = sotoinpcb(so);
595 if (inp == 0)
596 return EINVAL;
597 socantsendmore(so);
598 return 0;
599}
600
601struct pr_usrreqs udp_usrreqs = {
602 udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect,
603 pru_connect2_notsupp, in_control, udp_detach, udp_disconnect,
604 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
605 pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown,
606 in_setsockaddr, sosend, soreceive, soselect
607};