xref: /openbsd-src/sys/netinet/udp_usrreq.c (revision 62a742911104f98b9185b2c6b6007d9b1c36396c)
1 /*	$OpenBSD: udp_usrreq.c,v 1.25 1999/03/27 21:04:20 provos Exp $	*/
2 /*	$NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1988, 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)udp_usrreq.c	8.4 (Berkeley) 1/21/94
37  */
38 
39 /*
40 %%% portions-copyright-nrl-95
41 Portions of this software are Copyright 1995-1998 by Randall Atkinson,
42 Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights
43 Reserved. All rights under this copyright have been assigned to the US
44 Naval Research Laboratory (NRL). The NRL Copyright Notice and License
45 Agreement Version 1.1 (January 17, 1995) applies to these portions of the
46 software.
47 You should have received a copy of the license with this software. If you
48 didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
49 */
50 
51 #include <sys/param.h>
52 #include <sys/malloc.h>
53 #include <sys/mbuf.h>
54 #include <sys/protosw.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/errno.h>
58 #include <sys/stat.h>
59 #include <sys/systm.h>
60 #include <sys/proc.h>
61 
62 #include <vm/vm.h>
63 #include <sys/sysctl.h>
64 
65 #include <net/if.h>
66 #include <net/route.h>
67 
68 #include <netinet/in.h>
69 #include <netinet/in_systm.h>
70 #include <netinet/in_var.h>
71 #include <netinet/ip.h>
72 #include <netinet/in_pcb.h>
73 #include <netinet/ip_var.h>
74 #include <netinet/ip_icmp.h>
75 #include <netinet/udp.h>
76 #include <netinet/udp_var.h>
77 
78 #ifdef IPSEC
79 #include <netinet/ip_ipsp.h>
80 
81 extern int     	check_ipsec_policy  __P((struct inpcb *, u_int32_t));
82 #endif
83 
84 #include <machine/stdarg.h>
85 
86 #ifdef INET6
87 #include <netinet6/in6.h>
88 #include <netinet6/ipv6.h>
89 #include <netinet6/in6_var.h>
90 #include <netinet6/ipv6_var.h>
91 #include <netinet6/ipv6_icmp.h>
92 
93 extern int ipv6_defhoplmt;
94 
95 #endif /* INET6 */
96 
97 /*
98  * UDP protocol implementation.
99  * Per RFC 768, August, 1980.
100  */
101 int	udpcksum = 1;
102 
103 
104 static	void udp_detach __P((struct inpcb *));
105 static	void udp_notify __P((struct inpcb *, int));
106 static	struct mbuf *udp_saveopt __P((caddr_t, int, int));
107 
108 #ifndef UDBHASHSIZE
109 #define	UDBHASHSIZE	128
110 #endif
111 int	udbhashsize = UDBHASHSIZE;
112 
113 /* from in_pcb.c */
114 extern	struct baddynamicports baddynamicports;
115 
116 void
117 udp_init()
118 {
119 
120 	in_pcbinit(&udbtable, udbhashsize);
121 }
122 
123 void
124 #if __STDC__
125 udp_input(struct mbuf *m, ...)
126 #else
127 udp_input(m, va_alist)
128 	struct mbuf *m;
129 	va_dcl
130 #endif
131 {
132 	register struct ip *ip;
133 	register struct udphdr *uh;
134 	register struct inpcb *inp;
135 	struct mbuf *opts = 0;
136 	int len;
137 	struct ip save_ip;
138 	int iphlen;
139 	va_list ap;
140 	u_int16_t savesum;
141 	union {
142 		struct sockaddr sa;
143 		struct sockaddr_in sin;
144 #ifdef INET6
145 		struct sockaddr_in6 sin6;
146 #endif /* INET6 */
147 	} srcsa, dstsa;
148 #ifdef INET6
149 	struct ipv6 *ipv6;
150 	struct sockaddr_in6 src_v4mapped;
151 #endif /* INET6 */
152 #ifdef IPSEC
153 	struct tdb  *tdb = NULL;
154 #endif /* IPSEC */
155 
156 	va_start(ap, m);
157 	iphlen = va_arg(ap, int);
158 	va_end(ap);
159 
160 	udpstat.udps_ipackets++;
161 
162 #ifdef IPSEC
163 	/* Save the last SA which was used to process the mbuf */
164 	if ((m->m_flags & (M_CONF|M_AUTH)) && m->m_pkthdr.tdbi) {
165 		struct tdb_ident *tdbi = m->m_pkthdr.tdbi;
166 		tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
167 		free(m->m_pkthdr.tdbi, M_TEMP);
168 		m->m_pkthdr.tdbi = NULL;
169 	}
170 #endif /* IPSEC */
171 
172 	switch (mtod(m, struct ip *)->ip_v) {
173 	case 4:
174 		ip = mtod(m, struct ip *);
175 #ifdef INET6
176 		ipv6 = NULL;
177 #endif /* INET6 */
178 		srcsa.sa.sa_family = AF_INET;
179 		break;
180 #ifdef INET6
181 	case 6:
182 		ip = NULL;
183 		ipv6 = mtod(m, struct ipv6 *);
184 		srcsa.sa.sa_family = AF_INET6;
185 		break;
186 #endif /* INET6 */
187 	default:
188 		printf("udp_input: received unknown IP version %d",
189 		    mtod(m, struct ip *)->ip_v);
190 		goto bad;
191 	}
192 
193 	/*
194 	 * Strip IP options, if any; should skip this,
195 	 * make available to user, and use on returned packets,
196 	 * but we don't yet have a way to check the checksum
197 	 * with options still present.
198 	 */
199 	/*
200 	 * (contd. from above...)  Furthermore, we may want to strip options
201 	 * for such things as ICMP errors, where options just get in the way.
202 	 */
203 #ifdef INET6
204 	if (ip)
205 #endif /* INET6 */
206 		if (iphlen > sizeof (struct ip)) {
207 			ip_stripoptions(m, (struct mbuf *)0);
208 			iphlen = sizeof(struct ip);
209 		}
210 
211 	/*
212 	 * Get IP and UDP header together in first mbuf.
213 	 */
214 	if (m->m_len < iphlen + sizeof(struct udphdr)) {
215 		if ((m = m_pullup2(m, iphlen + sizeof(struct udphdr))) == 0) {
216 			udpstat.udps_hdrops++;
217 			return;
218 		}
219 #ifdef INET6
220 		if (ipv6)
221 			ipv6 = mtod(m, struct ipv6 *);
222 		else
223 #endif /* INET6 */
224 			ip = mtod(m, struct ip *);
225 	}
226 	uh = (struct udphdr *)(mtod(m, caddr_t) + iphlen);
227 
228 	/*
229 	 * Make mbuf data length reflect UDP length.
230 	 * If not enough data to reflect UDP length, drop.
231 	 */
232 	len = ntohs((u_int16_t)uh->uh_ulen);
233 	if (m->m_pkthdr.len - iphlen != len) {
234 		if (len > (m->m_pkthdr.len - iphlen) ||
235 			len < sizeof(struct udphdr)) {
236 			udpstat.udps_badlen++;
237 			goto bad;
238 		}
239 		m_adj(m, len - (m->m_pkthdr.len - iphlen));
240 	}
241 	/*
242 	 * Save a copy of the IP header in case we want restore it
243 	 * for sending an ICMP error message in response.
244 	 */
245 	if (ip)
246 		save_ip = *ip;
247 
248 	/*
249 	 * Checksum extended UDP header and data.
250 	 * from W.R.Stevens: check incoming udp cksums even if
251 	 *	udpcksum is not set.
252 	 */
253 	savesum = uh->uh_sum;
254 #ifdef INET6
255 	if (ipv6) {
256 		/*
257 		 * In IPv6, the UDP checksum is ALWAYS used.
258 		 */
259 		if ((uh->uh_sum = in6_cksum(m, IPPROTO_UDP, len, iphlen))) {
260 			udpstat.udps_badsum++;
261 			goto bad;
262 		}
263 	} else
264 #endif /* INET6 */
265 	if (uh->uh_sum) {
266 		bzero(((struct ipovly *)ip)->ih_x1,
267 		    sizeof ((struct ipovly *)ip)->ih_x1);
268 		((struct ipovly *)ip)->ih_len = uh->uh_ulen;
269 		if ((uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) != 0) {
270 			udpstat.udps_badsum++;
271 			m_freem(m);
272 			return;
273 		}
274 	} else
275 		udpstat.udps_nosum++;
276 
277 	switch (srcsa.sa.sa_family) {
278 	case AF_INET:
279 		bzero(&srcsa, sizeof(struct sockaddr_in));
280 		srcsa.sin.sin_len = sizeof(struct sockaddr_in);
281 		srcsa.sin.sin_family = AF_INET;
282 		srcsa.sin.sin_port = uh->uh_sport;
283 		srcsa.sin.sin_addr = ip->ip_src;
284 
285 #ifdef INET6
286 		bzero(&src_v4mapped, sizeof(struct sockaddr_in6));
287 		src_v4mapped.sin6_len = sizeof(struct sockaddr_in6);
288 		src_v4mapped.sin6_family = AF_INET6;
289 		src_v4mapped.sin6_port = uh->uh_sport;
290 		CREATE_IPV6_MAPPED(src_v4mapped.sin6_addr, ip->ip_src.s_addr);
291 #endif /* INET6 */
292 
293 		bzero(&dstsa, sizeof(struct sockaddr_in));
294 		dstsa.sin.sin_len = sizeof(struct sockaddr_in);
295 		dstsa.sin.sin_family = AF_INET;
296 		dstsa.sin.sin_port = uh->uh_dport;
297 		dstsa.sin.sin_addr = ip->ip_dst;
298 		break;
299 #ifdef INET6
300 	case AF_INET6:
301 		bzero(&srcsa, sizeof(struct sockaddr_in6));
302 		srcsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
303 		srcsa.sin6.sin6_family = AF_INET6;
304 		srcsa.sin6.sin6_port = uh->uh_sport;
305 		srcsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ipv6->ipv6_versfl;
306 		srcsa.sin6.sin6_addr = ipv6->ipv6_src;
307 
308 		bzero(&dstsa, sizeof(struct sockaddr_in6));
309 		dstsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
310 		dstsa.sin6.sin6_family = AF_INET6;
311 		dstsa.sin6.sin6_port = uh->uh_dport;
312 		dstsa.sin6.sin6_addr = ipv6->ipv6_dst;
313 		break;
314 #endif /* INET6 */
315 	}
316 
317 #ifdef INET6
318 	if ((ipv6 && IN6_IS_ADDR_MULTICAST(&ipv6->ipv6_dst)) ||
319 	    (ip && IN_MULTICAST(ip->ip_dst.s_addr)) ||
320 	    (ip && in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))) {
321 #else /* INET6 */
322 	if (IN_MULTICAST(ip->ip_dst.s_addr) ||
323 	    in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
324 #endif /* INET6 */
325 		struct socket *last;
326 		/*
327 		 * Deliver a multicast or broadcast datagram to *all* sockets
328 		 * for which the local and remote addresses and ports match
329 		 * those of the incoming datagram.  This allows more than
330 		 * one process to receive multi/broadcasts on the same port.
331 		 * (This really ought to be done for unicast datagrams as
332 		 * well, but that would cause problems with existing
333 		 * applications that open both address-specific sockets and
334 		 * a wildcard socket listening to the same port -- they would
335 		 * end up receiving duplicates of every unicast datagram.
336 		 * Those applications open the multiple sockets to overcome an
337 		 * inadequacy of the UDP socket interface, but for backwards
338 		 * compatibility we avoid the problem here rather than
339 		 * fixing the interface.  Maybe 4.5BSD will remedy this?)
340 		 */
341 
342 		iphlen += sizeof(struct udphdr);
343 		m->m_len -= iphlen;
344 		m->m_pkthdr.len -= iphlen;
345 		m->m_data += iphlen;
346 		/*
347 		 * Locate pcb(s) for datagram.
348 		 * (Algorithm copied from raw_intr().)
349 		 */
350 		last = NULL;
351 		for (inp = udbtable.inpt_queue.cqh_first;
352 		    inp != (struct inpcb *)&udbtable.inpt_queue;
353 		    inp = inp->inp_queue.cqe_next) {
354 			if (inp->inp_lport != uh->uh_dport)
355 				continue;
356 #ifdef INET6
357 			if (ipv6) {
358 				if (!(inp->inp_flags & INP_IPV6))
359 					continue;
360 				if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
361 					if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
362 					    &ipv6->ipv6_dst))
363 						continue;
364 			} else
365 #endif /* INET6 */
366 			if (inp->inp_laddr.s_addr != INADDR_ANY) {
367 				if (inp->inp_laddr.s_addr !=
368 				    ip->ip_dst.s_addr)
369 					continue;
370 			}
371 #ifdef INET6
372 			if (ipv6) {
373 				if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
374 					if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
375 					    &ipv6->ipv6_src) ||
376 					    inp->inp_fport != uh->uh_sport)
377 			        continue;
378 			} else
379 #endif /* INET6 */
380 			if (inp->inp_faddr.s_addr != INADDR_ANY) {
381 				if (inp->inp_faddr.s_addr !=
382 				    ip->ip_src.s_addr ||
383 				    inp->inp_fport != uh->uh_sport)
384 					continue;
385 			}
386 
387 			if (last != NULL) {
388 				struct mbuf *n;
389 
390 				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
391 #ifdef INET6
392 					if (ipv6)
393 						opts = ipv6_headertocontrol(m, iphlen, ((struct inpcb *)last->so_pcb)->inp_flags);
394 #endif /* INET6 */
395 					if (sbappendaddr(&last->so_rcv,
396 #ifdef INET6
397 					/*
398 					 * This cruft is needed in (the rare)
399 					 * case I deliver a {multi,broad}cast
400 					 * IPv4 packet to an AF_INET6 socket.
401 					 */
402 					    ((((struct inpcb *)last->so_pcb)->inp_flags
403 					    & INP_IPV6) && ip) ?
404 					    (struct sockaddr *)&src_v4mapped :
405 #endif /* INET6 */
406 					    &srcsa.sa, n, (struct mbuf *)0) == 0) {
407 						m_freem(n);
408 						udpstat.udps_fullsock++;
409 					} else
410 						sorwakeup(last);
411 				}
412 			}
413 			last = inp->inp_socket;
414 			/*
415 			 * Don't look for additional matches if this one does
416 			 * not have either the SO_REUSEPORT or SO_REUSEADDR
417 			 * socket options set.  This heuristic avoids searching
418 			 * through all pcbs in the common case of a non-shared
419 			 * port.  It * assumes that an application will never
420 			 * clear these options after setting them.
421 			 */
422 			if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0)
423 				break;
424 		}
425 
426 		if (last == NULL) {
427 			/*
428 			 * No matching pcb found; discard datagram.
429 			 * (No need to send an ICMP Port Unreachable
430 			 * for a broadcast or multicast datgram.)
431 			 */
432 			udpstat.udps_noportbcast++;
433 			goto bad;
434 		}
435 
436 #ifdef INET6
437 		if (ipv6)
438 			opts = ipv6_headertocontrol(m, iphlen,
439 			    ((struct inpcb *)last->so_pcb)->inp_flags);
440 #endif /* INET6 */
441 		if (sbappendaddr(&last->so_rcv,
442 #ifdef INET6
443 	        /*
444 		 * This cruft is needed in (the rare) case I
445 		 * deliver a {multi,broad}cast IPv4 packet to
446 		 * an AF_INET6 socket.
447 		 */
448 		    ((((struct inpcb *)last->so_pcb)->inp_flags & INP_IPV6) && ip) ?
449 		    (struct sockaddr *)&src_v4mapped :
450 #endif /* INET6 */
451 		    &srcsa.sa, m, (struct mbuf *)0) == 0) {
452 			udpstat.udps_fullsock++;
453 			goto bad;
454 		}
455 		sorwakeup(last);
456 		return;
457 	}
458 	/*
459 	 * Locate pcb for datagram.
460 	 */
461 #ifdef INET6
462 	if (ipv6)
463 		inp = in6_pcbhashlookup(&udbtable, &ipv6->ipv6_src, uh->uh_sport,
464 		    &ipv6->ipv6_dst, uh->uh_dport);
465 	else
466 #endif /* INET6 */
467 	inp = in_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport,
468 	    ip->ip_dst, uh->uh_dport);
469 	if (inp == 0) {
470 		++udpstat.udps_pcbhashmiss;
471 #ifdef INET6
472 		if (ipv6) {
473 			inp = in_pcblookup(&udbtable,
474 			    (struct in_addr *)&(ipv6->ipv6_src),
475 			    uh->uh_sport, (struct in_addr *)&(ipv6->ipv6_dst),
476 			    uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
477 		} else
478 #endif /* INET6 */
479 		inp = in_pcblookup(&udbtable, &ip->ip_src, uh->uh_sport,
480 		    &ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
481 		if (inp == 0) {
482 			udpstat.udps_noport++;
483 			if (m->m_flags & (M_BCAST | M_MCAST)) {
484 				udpstat.udps_noportbcast++;
485 				goto bad;
486 			}
487 			*ip = save_ip;
488 			HTONS(ip->ip_len);
489 			HTONS(ip->ip_id);
490 			HTONS(ip->ip_off);
491 			uh->uh_sum = savesum;
492 #ifdef INET6
493 			if (ipv6)
494 				ipv6_icmp_error(m, ICMPV6_UNREACH,
495 				    ICMPV6_UNREACH_PORT,0);
496 			else
497 #endif /* INET6 */
498 			icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
499 			return;
500 		}
501 	}
502 
503 #ifdef IPSEC
504 	/* Check if this socket requires security for incoming packets */
505 	if ((inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_REQUIRE &&
506 	     !(m->m_flags & M_AUTH)) ||
507 	    (inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_REQUIRE &&
508 	     !(m->m_flags & M_CONF))) {
509 #ifdef notyet
510 #ifdef INET6
511 		if (ipv6)
512 			ipv6_icmp_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0);
513 		else
514 #endif /* INET6 */
515 		icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0);
516 #endif /* notyet */
517 		udpstat.udps_nosec++;
518 		goto bad;
519 	}
520 	/* Use tdb_bind_out for this inp's outbound communication */
521 	if (tdb)
522 		tdb_add_inp(tdb, inp);
523 #endif /*IPSEC */
524 
525 	if (inp->inp_flags & INP_CONTROLOPTS) {
526 		struct mbuf **mp = &opts;
527 
528 #ifdef INET6
529 		if (ipv6) {
530 			if (inp->inp_flags & INP_IPV6)
531 				opts = ipv6_headertocontrol(m, iphlen,
532 				    inp->inp_flags);
533 		} else
534 			if (ip)
535 #endif /* INET6 */
536 		if (inp->inp_flags & INP_RECVDSTADDR) {
537 			*mp = udp_saveopt((caddr_t) &ip->ip_dst,
538 			    sizeof(struct in_addr), IP_RECVDSTADDR);
539 			if (*mp)
540 				mp = &(*mp)->m_next;
541 		}
542 #ifdef notyet
543 		/* options were tossed above */
544 		if (inp->inp_flags & INP_RECVOPTS) {
545 			*mp = udp_saveopt((caddr_t) opts_deleted_above,
546 			    sizeof(struct in_addr), IP_RECVOPTS);
547 			if (*mp)
548 				mp = &(*mp)->m_next;
549 		}
550 		/* ip_srcroute doesn't do what we want here, need to fix */
551 		if (inp->inp_flags & INP_RECVRETOPTS) {
552 			*mp = udp_saveopt((caddr_t) ip_srcroute(),
553 			    sizeof(struct in_addr), IP_RECVRETOPTS);
554 			if (*mp)
555 				mp = &(*mp)->m_next;
556 		}
557 #endif
558 	}
559 	iphlen += sizeof(struct udphdr);
560 	m->m_len -= iphlen;
561 	m->m_pkthdr.len -= iphlen;
562 	m->m_data += iphlen;
563 
564 	if (sbappendaddr(&inp->inp_socket->so_rcv,
565 #ifdef INET6
566 	    /*
567 	     * This cruft is needed to deliver a IPv4 packet to
568 	     * an AF_INET6 socket.
569 	     */
570 	    ((((struct inpcb *)inp->inp_socket->so_pcb)->inp_flags & INP_IPV6)
571 	    && ip) ? (struct sockaddr *)&src_v4mapped :
572 #endif /* INET6 */
573 		&srcsa.sa, m, opts) == 0) {
574 		udpstat.udps_fullsock++;
575 		goto bad;
576 	}
577 	sorwakeup(inp->inp_socket);
578 	return;
579 bad:
580 	m_freem(m);
581 	if (opts)
582 		m_freem(opts);
583 }
584 
585 /*
586  * Create a "control" mbuf containing the specified data
587  * with the specified type for presentation with a datagram.
588  */
589 struct mbuf *
590 udp_saveopt(p, size, type)
591 	caddr_t p;
592 	register int size;
593 	int type;
594 {
595 	register struct cmsghdr *cp;
596 	struct mbuf *m;
597 
598 	if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
599 		return ((struct mbuf *) NULL);
600 	cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
601 	bcopy(p, CMSG_DATA(cp), size);
602 	size += sizeof(*cp);
603 	m->m_len = size;
604 	cp->cmsg_len = size;
605 	cp->cmsg_level = IPPROTO_IP;
606 	cp->cmsg_type = type;
607 	return (m);
608 }
609 
610 /*
611  * Notify a udp user of an asynchronous error;
612  * just wake up so that he can collect error status.
613  */
614 static void
615 udp_notify(inp, errno)
616 	register struct inpcb *inp;
617 	int errno;
618 {
619 	inp->inp_socket->so_error = errno;
620 	sorwakeup(inp->inp_socket);
621 	sowwakeup(inp->inp_socket);
622 }
623 
624 void *
625 udp_ctlinput(cmd, sa, v)
626 	int cmd;
627 	struct sockaddr *sa;
628 	void *v;
629 {
630 	register struct ip *ip = v;
631 	register struct udphdr *uh;
632 	extern int inetctlerrmap[];
633 	void (*notify) __P((struct inpcb *, int)) = udp_notify;
634 	int errno;
635 
636 	if ((unsigned)cmd >= PRC_NCMDS)
637 		return NULL;
638 	errno = inetctlerrmap[cmd];
639 	if (PRC_IS_REDIRECT(cmd))
640 		notify = in_rtchange, ip = 0;
641 	else if (cmd == PRC_HOSTDEAD)
642 		ip = 0;
643 	else if (errno == 0)
644 		return NULL;
645 #ifdef INET6
646 	if (sa->sa_family == AF_INET6) {
647 		if (ip) {
648 			struct ipv6 *ipv6 = (struct ipv6 *)ip;
649 
650 			uh = (struct udphdr *)((caddr_t)ipv6 + sizeof(struct ipv6));
651 			in6_pcbnotify(&udbtable, sa, uh->uh_dport,
652 			    &(ipv6->ipv6_src), uh->uh_sport, cmd, udp_notify);
653 		} else
654 			in6_pcbnotify(&udbtable, sa, 0,
655 			    (struct in6_addr *)&in6addr_any, 0, cmd, udp_notify);
656 	} else
657 #endif /* INET6 */
658 	if (ip) {
659 		uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
660 		in_pcbnotify(&udbtable, sa, uh->uh_dport, ip->ip_src,
661 		    uh->uh_sport, errno, notify);
662 	} else
663 		in_pcbnotifyall(&udbtable, sa, errno, notify);
664 	return NULL;
665 }
666 
667 int
668 #if __STDC__
669 udp_output(struct mbuf *m, ...)
670 #else
671 udp_output(m, va_alist)
672 	struct mbuf *m;
673 	va_dcl
674 #endif
675 {
676 	register struct inpcb *inp;
677 	struct mbuf *addr, *control;
678 	register struct udpiphdr *ui;
679 	register int len = m->m_pkthdr.len;
680 	struct in_addr laddr;
681 	int s = 0, error = 0;
682 	va_list ap;
683 #ifdef INET6
684 	register struct in6_addr laddr6;
685 	int v6packet = 0;
686 	struct ifnet *forceif = NULL;
687 #endif /* INET6 */
688 	int pcbflags = 0;
689 
690 	va_start(ap, m);
691 	inp = va_arg(ap, struct inpcb *);
692 	addr = va_arg(ap, struct mbuf *);
693 	control = va_arg(ap, struct mbuf *);
694 	va_end(ap);
695 
696 #ifndef INET6
697 	if (control)
698 		m_freem(control);		/* XXX */
699 #endif /* INET6 */
700 
701 	if (addr) {
702 	        /*
703 		 * Save current PCB flags because they may change during
704 		 * temporary connection, particularly the INP_IPV6_UNDEC
705 		 * flag.
706 		 */
707                 pcbflags = inp->inp_flags;
708 
709 #ifdef INET6
710 	        if (inp->inp_flags & INP_IPV6)
711 			laddr6 = inp->inp_laddr6;
712 		else
713 #endif /* INET6 */
714 			laddr = inp->inp_laddr;
715 #ifdef INET6
716 		if (((inp->inp_flags & INP_IPV6) &&
717 		    !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) ||
718 		    (inp->inp_faddr.s_addr != INADDR_ANY)) {
719 #else /* INET6 */
720 		if (inp->inp_faddr.s_addr != INADDR_ANY) {
721 #endif /* INET6 */
722 			error = EISCONN;
723 			goto release;
724 		}
725 		/*
726 		 * Must block input while temporarily connected.
727 		 */
728 		s = splsoftnet();
729 		error = in_pcbconnect(inp, addr);
730 		if (error) {
731 			splx(s);
732 			goto release;
733 		}
734 	} else {
735 #ifdef INET6
736 	        if (((inp->inp_flags & INP_IPV6) &&
737 		    IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) ||
738 		    (inp->inp_faddr.s_addr == INADDR_ANY)) {
739 #else /* INET6 */
740 		if (inp->inp_faddr.s_addr == INADDR_ANY) {
741 #endif /* INET6 */
742 			error = ENOTCONN;
743 			goto release;
744 		}
745 	}
746 	/*
747 	 * Calculate data length and get a mbuf
748 	 * for UDP and IP headers.
749 	 */
750 #ifdef INET6
751 	/*
752 	 * Handles IPv4-mapped IPv6 address because temporary connect sets
753 	 * the right flag.
754 	 */
755 	v6packet = ((inp->inp_flags & INP_IPV6) &&
756 		    !(inp->inp_flags & INP_IPV6_MAPPED));
757 
758 	if (!v6packet && control)
759 		m_freem(control);
760 
761 	M_PREPEND(m, v6packet ? (sizeof(struct udphdr) +
762 	    sizeof(struct ipv6)) : sizeof(struct udpiphdr), M_DONTWAIT);
763 #else /* INET6 */
764 	M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
765 #endif /* INET6 */
766 	if (m == 0) {
767 		error = ENOBUFS;
768 		goto bail;
769 	}
770 
771 	/*
772 	 * Compute the packet length of the IP header, and
773 	 * punt if the length looks bogus.
774 	 */
775 	if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) {
776 		error = EMSGSIZE;
777 		goto release;
778 	}
779 
780 	/*
781 	 * Fill in mbuf with extended UDP header
782 	 * and addresses and length put into network format.
783 	 */
784 #ifdef INET6
785 	if (v6packet) {
786 		struct ipv6 *ipv6 = mtod(m, struct ipv6 *);
787 		struct udphdr *uh = (struct udphdr *)(mtod(m, caddr_t) +
788 		    sizeof(struct ipv6));
789 		int payload = sizeof(struct ipv6);
790 
791 		ipv6->ipv6_versfl = htonl(0x60000000) |
792 		    (inp->inp_ipv6.ipv6_versfl & htonl(0x0fffffff));
793 
794 		ipv6->ipv6_hoplimit = inp->inp_ipv6.ipv6_hoplimit;
795 		ipv6->ipv6_nexthdr = IPPROTO_UDP;
796 		ipv6->ipv6_src = inp->inp_laddr6;
797 		ipv6->ipv6_dst = inp->inp_faddr6;
798 		ipv6->ipv6_length = (u_short)len + sizeof(struct udphdr);
799 
800 		uh->uh_sport = inp->inp_lport;
801 		uh->uh_dport = inp->inp_fport;
802 		uh->uh_ulen = htons(ipv6->ipv6_length);
803 		uh->uh_sum = 0;
804 
805 		if (control)
806 			if ((error = ipv6_controltoheader(&m, control,
807 			    &forceif, &payload)))
808 				goto release;
809 
810 		/*
811 		 * Always calculate udp checksum for IPv6 datagrams
812 		 */
813 		if (!(uh->uh_sum = in6_cksum(m, IPPROTO_UDP, len +
814 		    sizeof(struct udphdr), payload)))
815 			uh->uh_sum = 0xffff;
816 
817 		error = ipv6_output(m, &inp->inp_route6,
818 		    inp->inp_socket->so_options & SO_DONTROUTE,
819 		    (inp->inp_flags & INP_IPV6_MCAST)?inp->inp_moptions6:NULL,
820 		    forceif, inp->inp_socket);
821 	} else
822 #endif /* INET6 */
823 	{
824 		ui = mtod(m, struct udpiphdr *);
825 		bzero(ui->ui_x1, sizeof ui->ui_x1);
826 		ui->ui_pr = IPPROTO_UDP;
827 		ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
828 		ui->ui_src = inp->inp_laddr;
829 		ui->ui_dst = inp->inp_faddr;
830 		ui->ui_sport = inp->inp_lport;
831 		ui->ui_dport = inp->inp_fport;
832 		ui->ui_ulen = ui->ui_len;
833 
834 		/*
835 		 * Stuff checksum and output datagram.
836 		 */
837 
838 		ui->ui_sum = 0;
839 		if (udpcksum) {
840 			if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) +
841 			    len)) == 0)
842 				ui->ui_sum = 0xffff;
843 		}
844 		((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
845 #ifdef INET6
846 		/*
847 		 *  For now, we use the default values for ttl and tos for
848 		 *  v4 packets sent using a v6 pcb.  We probably want to
849 		 *  later allow v4 setsockopt operations on a v6 socket to
850 		 *  modify the ttl and tos for v4 packets sent using
851 		 *  the mapped address format.  We really ought to
852 		 *  save the v4 ttl and v6 hoplimit in separate places
853 		 *  instead of craming both in the inp_hu union.
854 		 */
855 		if (inp->inp_flags & INP_IPV6) {
856 			((struct ip *)ui)->ip_ttl = ip_defttl;
857 			((struct ip *)ui)->ip_tos = 0;
858 		} else
859 #endif /* INET6 */
860 		{
861 			((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl;
862 			((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos;
863 		}
864 
865 		udpstat.udps_opackets++;
866 #ifdef INET6
867 		if (inp->inp_flags & INP_IPV6_MCAST)
868 			error = ip_output(m, inp->inp_options, &inp->inp_route,
869 				inp->inp_socket->so_options &
870 				(SO_DONTROUTE | SO_BROADCAST),
871 				NULL, NULL, inp->inp_socket);
872 		else
873 #endif /* INET6 */
874 			error = ip_output(m, inp->inp_options, &inp->inp_route,
875 				inp->inp_socket->so_options &
876 				(SO_DONTROUTE | SO_BROADCAST),
877 		    		inp->inp_moptions, inp, NULL);
878 	}
879 
880 bail:
881 	if (addr) {
882 		in_pcbdisconnect(inp);
883                 inp->inp_flags = pcbflags;
884 #ifdef INET6
885 		if (inp->inp_flags & INP_IPV6)
886 			inp->inp_laddr6 = laddr6;
887 	        else
888 #endif /* INET6 */
889 		inp->inp_laddr = laddr;
890 		splx(s);
891 	}
892 	return (error);
893 
894 release:
895 	m_freem(m);
896 	return (error);
897 }
898 
899 u_int	udp_sendspace = 9216;		/* really max datagram size */
900 u_int	udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
901 					/* 40 1K datagrams */
902 
903 /*ARGSUSED*/
904 int
905 udp_usrreq(so, req, m, addr, control)
906 	struct socket *so;
907 	int req;
908 	struct mbuf *m, *addr, *control;
909 {
910 	struct inpcb *inp = sotoinpcb(so);
911 	int error = 0;
912 	int s;
913 
914 	if (req == PRU_CONTROL) {
915 #ifdef INET6
916 		if (inp->inp_flags & INP_IPV6)
917 			return (in6_control(so, (u_long)m, (caddr_t)addr,
918 			    (struct ifnet *)control, 0));
919 		else
920 #endif /* INET6 */
921 			return (in_control(so, (u_long)m, (caddr_t)addr,
922 			    (struct ifnet *)control));
923 	}
924 	if (inp == NULL && req != PRU_ATTACH) {
925 		error = EINVAL;
926 		goto release;
927 	}
928 	/*
929 	 * Note: need to block udp_input while changing
930 	 * the udp pcb queue and/or pcb addresses.
931 	 */
932 	switch (req) {
933 
934 	case PRU_ATTACH:
935 		if (inp != NULL) {
936 			error = EINVAL;
937 			break;
938 		}
939 		s = splsoftnet();
940 		error = in_pcballoc(so, &udbtable);
941 		splx(s);
942 		if (error)
943 			break;
944 		error = soreserve(so, udp_sendspace, udp_recvspace);
945 		if (error)
946 			break;
947 #ifdef INET6
948 		if (((struct inpcb *)so->so_pcb)->inp_flags & INP_IPV6)
949 			((struct inpcb *) so->so_pcb)->inp_ipv6.ipv6_hoplimit =
950 			    ipv6_defhoplmt;
951 		else
952 #endif /* INET6 */
953 			((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl;
954 		break;
955 
956 	case PRU_DETACH:
957 		udp_detach(inp);
958 		break;
959 
960 	case PRU_BIND:
961 		s = splsoftnet();
962 		error = in_pcbbind(inp, addr);
963 		splx(s);
964 		break;
965 
966 	case PRU_LISTEN:
967 		error = EOPNOTSUPP;
968 		break;
969 
970 	case PRU_CONNECT:
971 #ifdef INET6
972 		if (inp->inp_flags & INP_IPV6) {
973 			if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
974 				error = EISCONN;
975 				break;
976 			}
977 		} else
978 #endif /* INET6 */
979 			if (inp->inp_faddr.s_addr != INADDR_ANY) {
980 				error = EISCONN;
981 				break;
982 			}
983 
984 		s = splsoftnet();
985 		error = in_pcbconnect(inp, addr);
986 		splx(s);
987 		if (error == 0)
988 			soisconnected(so);
989 		break;
990 
991 	case PRU_CONNECT2:
992 		error = EOPNOTSUPP;
993 		break;
994 
995 	case PRU_ACCEPT:
996 		error = EOPNOTSUPP;
997 		break;
998 
999 	case PRU_DISCONNECT:
1000 #ifdef INET6
1001 		if (inp->inp_flags & INP_IPV6) {
1002 			if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
1003 				error = ENOTCONN;
1004 				break;
1005 			}
1006 		} else
1007 #endif /* INET6 */
1008 			if (inp->inp_faddr.s_addr == INADDR_ANY) {
1009 				error = ENOTCONN;
1010 				break;
1011 			}
1012 
1013 		s = splsoftnet();
1014 		in_pcbdisconnect(inp);
1015 #ifdef INET6
1016 		if (inp->inp_flags & INP_IPV6)
1017 			inp->inp_laddr6 = in6addr_any;
1018 		else
1019 #endif /* INET6 */
1020 			inp->inp_laddr.s_addr = INADDR_ANY;
1021 
1022 		splx(s);
1023 		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
1024 		break;
1025 
1026 	case PRU_SHUTDOWN:
1027 		socantsendmore(so);
1028 		break;
1029 
1030 	case PRU_SEND:
1031 #ifdef IPSEC
1032 		error = check_ipsec_policy(inp,0);
1033 		if (error)
1034 			return (error);
1035 #endif
1036 		return (udp_output(m, inp, addr, control));
1037 
1038 	case PRU_ABORT:
1039 		soisdisconnected(so);
1040 		udp_detach(inp);
1041 		break;
1042 
1043 	case PRU_SOCKADDR:
1044 		in_setsockaddr(inp, addr);
1045 		break;
1046 
1047 	case PRU_PEERADDR:
1048 		in_setpeeraddr(inp, addr);
1049 		break;
1050 
1051 	case PRU_SENSE:
1052 		/*
1053 		 * stat: don't bother with a blocksize.
1054 		 */
1055 		/*
1056 		 * Perhaps Path MTU might be returned for a connected
1057 		 * UDP socket in this case.
1058 		 */
1059 		return (0);
1060 
1061 	case PRU_SENDOOB:
1062 	case PRU_FASTTIMO:
1063 	case PRU_SLOWTIMO:
1064 	case PRU_PROTORCV:
1065 	case PRU_PROTOSEND:
1066 		error =  EOPNOTSUPP;
1067 		break;
1068 
1069 	case PRU_RCVD:
1070 	case PRU_RCVOOB:
1071 		return (EOPNOTSUPP);	/* do not free mbuf's */
1072 
1073 	default:
1074 		panic("udp_usrreq");
1075 	}
1076 
1077 release:
1078 	if (control) {
1079 		printf("udp control data unexpectedly retained\n");
1080 		m_freem(control);
1081 	}
1082 	if (m)
1083 		m_freem(m);
1084 	return (error);
1085 }
1086 
1087 static void
1088 udp_detach(inp)
1089 	struct inpcb *inp;
1090 {
1091 	int s = splsoftnet();
1092 
1093 	in_pcbdetach(inp);
1094 	splx(s);
1095 }
1096 
1097 /*
1098  * Sysctl for udp variables.
1099  */
1100 int
1101 udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
1102 	int *name;
1103 	u_int namelen;
1104 	void *oldp;
1105 	size_t *oldlenp;
1106 	void *newp;
1107 	size_t newlen;
1108 {
1109 	/* All sysctl names at this level are terminal. */
1110 	if (namelen != 1)
1111 		return (ENOTDIR);
1112 
1113 	switch (name[0]) {
1114 	case UDPCTL_CHECKSUM:
1115 		return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
1116 	case UDPCTL_BADDYNAMIC:
1117 		return (sysctl_struct(oldp, oldlenp, newp, newlen,
1118 		    baddynamicports.udp, sizeof(baddynamicports.udp)));
1119 	case UDPCTL_RECVSPACE:
1120 		return (sysctl_int(oldp, oldlenp, newp, newlen,&udp_recvspace));
1121 	case UDPCTL_SENDSPACE:
1122 		return (sysctl_int(oldp, oldlenp, newp, newlen,&udp_sendspace));
1123 	default:
1124 		return (ENOPROTOOPT);
1125 	}
1126 	/* NOTREACHED */
1127 }
1128