xref: /netbsd-src/sys/netinet6/udp6_usrreq.c (revision 3b435a73967be44dfb4a27315acd72bfacde430c)
1 /*	$NetBSD: udp6_usrreq.c,v 1.13 1999/09/13 12:15:56 itojun Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1982, 1986, 1989, 1993
34  *	The Regents of the University of California.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *	This product includes software developed by the University of
47  *	California, Berkeley and its contributors.
48  * 4. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  *
64  *	@(#)udp_var.h	8.1 (Berkeley) 6/10/93
65  */
66 
67 #ifdef __NetBSD__	/*XXX*/
68 #include "opt_ipsec.h"
69 #endif
70 
71 #include <sys/param.h>
72 #include <sys/malloc.h>
73 #include <sys/mbuf.h>
74 #include <sys/protosw.h>
75 #include <sys/socket.h>
76 #include <sys/socketvar.h>
77 #include <sys/errno.h>
78 #include <sys/stat.h>
79 #include <sys/systm.h>
80 #ifdef __NetBSD__
81 #include <sys/proc.h>
82 #endif
83 #include <sys/syslog.h>
84 
85 #include <net/if.h>
86 #include <net/route.h>
87 #include <net/if_types.h>
88 
89 #include <netinet/in.h>
90 #include <netinet/in_var.h>
91 #include <netinet6/ip6.h>
92 #include <netinet6/in6_pcb.h>
93 #include <netinet6/ip6_var.h>
94 #include <netinet6/icmp6.h>
95 #include <netinet6/udp6.h>
96 #include <netinet6/udp6_var.h>
97 
98 #ifdef IPSEC
99 #include <netinet6/ipsec.h>
100 #endif /*IPSEC*/
101 
102 #include "faith.h"
103 
104 /*
105  * UDP protocol inplementation.
106  * Per RFC 768, August, 1980.
107  */
108 
109 struct	in6pcb *udp6_last_in6pcb = &udb6;
110 
111 static	int in6_mcmatch __P((struct in6pcb *, struct in6_addr *, struct ifnet *));
112 static	void udp6_detach __P((struct in6pcb *));
113 static	void udp6_notify __P((struct in6pcb *, int));
114 
115 void
116 udp6_init()
117 {
118 	udb6.in6p_next = udb6.in6p_prev = &udb6;
119 }
120 
121 static int
122 in6_mcmatch(in6p, ia6, ifp)
123 	struct in6pcb *in6p;
124 	register struct in6_addr *ia6;
125 	struct ifnet *ifp;
126 {
127 	struct ip6_moptions *im6o = in6p->in6p_moptions;
128 	struct in6_multi_mship *imm;
129 
130 	if (im6o == NULL)
131 		return 0;
132 
133 	for (imm = im6o->im6o_memberships.lh_first; imm != NULL;
134 	     imm = imm->i6mm_chain.le_next) {
135 		if ((ifp == NULL ||
136 		     imm->i6mm_maddr->in6m_ifp == ifp) &&
137 		    IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
138 				       ia6))
139 			return 1;
140 	}
141 	return 0;
142 }
143 
144 int
145 udp6_input(mp, offp, proto)
146 	struct mbuf **mp;
147 	int *offp, proto;
148 {
149 	struct mbuf *m = *mp;
150 	register struct ip6_hdr *ip6;
151 	register struct udphdr *uh;
152 	register struct in6pcb *in6p;
153 	struct	mbuf *opts = 0;
154 	int off = *offp;
155 	int plen, ulen;
156 	struct sockaddr_in6 udp_in6;
157 
158 #if defined(NFAITH) && 0 < NFAITH
159 	if (m->m_pkthdr.rcvif) {
160 		if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
161 			/* send icmp6 host unreach? */
162 			m_freem(m);
163 			return IPPROTO_DONE;
164 		}
165 	}
166 #endif
167 	udp6stat.udp6s_ipackets++;
168 
169 	IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
170 
171 	ip6 = mtod(m, struct ip6_hdr *);
172 	plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
173 	uh = (struct udphdr *)((caddr_t)ip6 + off);
174 	ulen = ntohs((u_short)uh->uh_ulen);
175 
176 	if (plen != ulen) {
177 		udp6stat.udp6s_badlen++;
178 		goto bad;
179 	}
180 
181 	/*
182 	 * Checksum extended UDP header and data.
183 	 */
184 	if (uh->uh_sum == 0)
185 		udp6stat.udp6s_nosum++;
186 	else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
187 		udp6stat.udp6s_badsum++;
188 		goto bad;
189 	}
190 
191 	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
192 		struct	in6pcb *last;
193 
194 		/*
195 		 * Deliver a multicast datagram to all sockets
196 		 * for which the local and remote addresses and ports match
197 		 * those of the incoming datagram.  This allows more than
198 		 * one process to receive multicasts on the same port.
199 		 * (This really ought to be done for unicast datagrams as
200 		 * well, but that would cause problems with existing
201 		 * applications that open both address-specific sockets and
202 		 * a wildcard socket listening to the same port -- they would
203 		 * end up receiving duplicates of every unicast datagram.
204 		 * Those applications open the multiple sockets to overcome an
205 		 * inadequacy of the UDP socket interface, but for backwards
206 		 * compatibility we avoid the problem here rather than
207 		 * fixing the interface.  Maybe 4.5BSD will remedy this?)
208 		 */
209 
210 		/*
211 		 * In a case that laddr should be set to the link-local
212 		 * address (this happens in RIPng), the multicast address
213 		 * specified in the received packet does not match with
214 		 * laddr. To cure this situation, the matching is relaxed
215 		 * if the receiving interface is the same as one specified
216 		 * in the socket and if the destination multicast address
217 		 * matches one of the multicast groups specified in the socket.
218 		 */
219 
220 		/*
221 		 * Construct sockaddr format source address.
222 		 */
223 		bzero(&udp_in6, sizeof(udp_in6));
224 		udp_in6.sin6_len = sizeof(struct sockaddr_in6);
225 		udp_in6.sin6_family = AF_INET6;
226 		udp_in6.sin6_port = uh->uh_sport;
227 		udp_in6.sin6_addr = ip6->ip6_src;
228 		if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
229 			udp_in6.sin6_addr.s6_addr16[1] = 0;
230 		if (m->m_pkthdr.rcvif) {
231 			if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr)) {
232 				udp_in6.sin6_scope_id =
233 					m->m_pkthdr.rcvif->if_index;
234 			} else
235 				udp_in6.sin6_scope_id = 0;
236 		} else
237 			udp_in6.sin6_scope_id = 0;
238 		/*
239 		 * KAME note: usually we drop udphdr from mbuf here.
240 		 * We need udphdr for IPsec processing so we do that later.
241 		 */
242 
243 		/*
244 		 * Locate pcb(s) for datagram.
245 		 * (Algorithm copied from raw_intr().)
246 		 */
247 		last = NULL;
248 		for (in6p = udb6.in6p_next;
249 		     in6p != &udb6;
250 		     in6p = in6p->in6p_next) {
251 			if (in6p->in6p_lport != uh->uh_dport)
252 				continue;
253 			if (!IN6_IS_ADDR_ANY(&in6p->in6p_laddr)) {
254 				if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
255 							&ip6->ip6_dst) &&
256 				    !in6_mcmatch(in6p, &ip6->ip6_dst,
257 						 m->m_pkthdr.rcvif))
258 					continue;
259 			}
260 			if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
261 				if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
262 							&ip6->ip6_src) ||
263 				   in6p->in6p_fport != uh->uh_sport)
264 					continue;
265 			}
266 
267 			if (last != NULL) {
268 				struct	mbuf *n;
269 
270 #ifdef IPSEC
271 				/*
272 				 * Check AH/ESP integrity.
273 				 */
274 				if (last != NULL && ipsec6_in_reject(m, last)) {
275 					ipsec6stat.in_polvio++;
276 					/* do not inject data into pcb */
277 				} else
278 #endif /*IPSEC*/
279 				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
280 					/*
281 					 * KAME NOTE: do not
282 					 * m_copy(m, offset, ...) above.
283 					 * sbappendaddr() expects M_PKTHDR,
284 					 * and m_copy() will copy M_PKTHDR
285 					 * only if offset is 0.
286 					 */
287 					if (last->in6p_flags & IN6P_CONTROLOPTS
288 					 || last->in6p_socket->so_options & SO_TIMESTAMP) {
289 						ip6_savecontrol(last, &opts,
290 								ip6, n);
291 					}
292 
293 					m_adj(n, off + sizeof(struct udphdr));
294 					if (sbappendaddr(&last->in6p_socket->so_rcv,
295 							(struct sockaddr *)&udp_in6,
296 							n, opts) == 0) {
297 						m_freem(n);
298 						if (opts)
299 							m_freem(opts);
300 						udp6stat.udp6s_fullsock++;
301 					} else
302 						sorwakeup(last->in6p_socket);
303 					opts = 0;
304 				}
305 			}
306 			last = in6p;
307 			/*
308 			 * Don't look for additional matches if this one does
309 			 * not have either the SO_REUSEPORT or SO_REUSEADDR
310 			 * socket options set.  This heuristic avoids searching
311 			 * through all pcbs in the common case of a non-shared
312 			 * port.  It assumes that an application will never
313 			 * clear these options after setting them.
314 			 */
315 			if ((last->in6p_socket->so_options &
316 			     (SO_REUSEPORT|SO_REUSEADDR)) == 0)
317 				break;
318 		}
319 
320 		if (last == NULL) {
321 			/*
322 			 * No matching pcb found; discard datagram.
323 			 * (No need to send an ICMP Port Unreachable
324 			 * for a broadcast or multicast datgram.)
325 			 */
326 			udp6stat.udp6s_noport++;
327 			udp6stat.udp6s_noportmcast++;
328 			goto bad;
329 		}
330 #ifdef IPSEC
331 		/*
332 		 * Check AH/ESP integrity.
333 		 */
334 		if (last != NULL && ipsec6_in_reject(m, last)) {
335 			ipsec6stat.in_polvio++;
336 			goto bad;
337 		}
338 #endif /*IPSEC*/
339 		if (last->in6p_flags & IN6P_CONTROLOPTS
340 		 || last->in6p_socket->so_options & SO_TIMESTAMP) {
341 			ip6_savecontrol(last, &opts, ip6, m);
342 		}
343 
344 		m_adj(m, off + sizeof(struct udphdr));
345 		if (sbappendaddr(&last->in6p_socket->so_rcv,
346 				(struct sockaddr *)&udp_in6,
347 				m, opts) == 0) {
348 			udp6stat.udp6s_fullsock++;
349 			goto bad;
350 		}
351 		sorwakeup(last->in6p_socket);
352 		return IPPROTO_DONE;
353 	}
354 	/*
355 	 * Locate pcb for datagram.
356 	 */
357 	in6p = udp6_last_in6pcb;
358 	if (in6p->in6p_lport != uh->uh_dport ||
359 	   in6p->in6p_fport != uh->uh_sport ||
360 	   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src) ||
361 	   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) {
362 		in6p = in6_pcblookup(&udb6,
363 				     &ip6->ip6_src, uh->uh_sport,
364 				     &ip6->ip6_dst, uh->uh_dport,
365 				     IN6PLOOKUP_WILDCARD);
366 		if (in6p)
367 			udp6_last_in6pcb = in6p;
368 		udp6stat.udp6ps_pcbcachemiss++;
369 	}
370 	if (in6p == 0) {
371 		udp6stat.udp6s_noport++;
372 		if (m->m_flags & M_MCAST) {
373 			printf("UDP6: M_MCAST is set in a unicast packet.\n");
374 			udp6stat.udp6s_noportmcast++;
375 			goto bad;
376 		}
377 		icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
378 		return IPPROTO_DONE;
379 	}
380 #ifdef IPSEC
381 	/*
382 	 * Check AH/ESP integrity.
383 	 */
384 	if (in6p != NULL && ipsec6_in_reject(m, in6p)) {
385 		ipsec6stat.in_polvio++;
386 		goto bad;
387 	}
388 #endif /*IPSEC*/
389 
390 	/*
391 	 * Construct sockaddr format source address.
392 	 * Stuff source address and datagram in user buffer.
393 	 */
394 	bzero(&udp_in6, sizeof(udp_in6));
395 	udp_in6.sin6_len = sizeof(struct sockaddr_in6);
396 	udp_in6.sin6_family = AF_INET6;
397 	udp_in6.sin6_port = uh->uh_sport;
398 	udp_in6.sin6_addr = ip6->ip6_src;
399 	if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
400 		udp_in6.sin6_addr.s6_addr16[1] = 0;
401 	if (m->m_pkthdr.rcvif) {
402 		if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
403 			udp_in6.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
404 		else
405 			udp_in6.sin6_scope_id = 0;
406 	} else
407 		udp_in6.sin6_scope_id = 0;
408 	if (in6p->in6p_flags & IN6P_CONTROLOPTS
409 	 || in6p->in6p_socket->so_options & SO_TIMESTAMP) {
410 		ip6_savecontrol(in6p, &opts, ip6, m);
411 	}
412 
413 	m_adj(m, off + sizeof(struct udphdr));
414 	if (sbappendaddr(&in6p->in6p_socket->so_rcv,
415 			(struct sockaddr *)&udp_in6,
416 			m, opts) == 0) {
417 		udp6stat.udp6s_fullsock++;
418 		goto bad;
419 	}
420 	sorwakeup(in6p->in6p_socket);
421 	return IPPROTO_DONE;
422 bad:
423 	if (m)
424 		m_freem(m);
425 	if (opts)
426 		m_freem(opts);
427 	return IPPROTO_DONE;
428 }
429 
430 /*
431  * Notify a udp user of an asynchronous error;
432  * just wake up so tat he can collect error status.
433  */
434 static	void
435 udp6_notify(in6p, errno)
436 	register struct in6pcb *in6p;
437 	int errno;
438 {
439 	in6p->in6p_socket->so_error = errno;
440 	sorwakeup(in6p->in6p_socket);
441 	sowwakeup(in6p->in6p_socket);
442 }
443 
444 void
445 udp6_ctlinput(cmd, sa, ip6, m, off)
446 	int cmd;
447 	struct sockaddr *sa;
448 	register struct ip6_hdr *ip6;
449 	struct mbuf *m;
450 	int off;
451 {
452 	register struct udphdr *uhp;
453 	struct udphdr uh;
454 	struct sockaddr_in6 sa6;
455 
456 	if (sa->sa_family != AF_INET6 ||
457 	    sa->sa_len != sizeof(struct sockaddr_in6))
458 		return;
459 #if 0
460 	if (cmd == PRC_IFNEWADDR)
461 		in6_mrejoin(&udb6);
462 	else
463 #endif
464 	if (!PRC_IS_REDIRECT(cmd) &&
465 	    ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0))
466 		return;
467 
468 	/* translate addresses into internal form */
469 	sa6 = *(struct sockaddr_in6 *)sa;
470 	if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr))
471 		sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
472 
473 	if (ip6) {
474 		/*
475 		 * XXX: We assume that when IPV6 is non NULL,
476 		 * M and OFF are valid.
477 		 */
478 		struct in6_addr s;
479 
480 		/* translate addresses into internal form */
481 		memcpy(&s, &ip6->ip6_src, sizeof(s));
482 		if (IN6_IS_ADDR_LINKLOCAL(&s))
483 			s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
484 
485 		if (m->m_len < off + sizeof(uh)) {
486 			/*
487 			 * this should be rare case,
488 			 * so we compromise on this copy...
489 			 */
490 			m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
491 			uhp = &uh;
492 		} else
493 			uhp = (struct udphdr *)(mtod(m, caddr_t) + off);
494 		(void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6,
495 					uhp->uh_dport, &s,
496 					uhp->uh_sport, cmd, udp6_notify);
497 	} else {
498 		(void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6, 0,
499 					&zeroin6_addr, 0, cmd, udp6_notify);
500 	}
501 }
502 
503 int
504 udp6_output(in6p, m, addr6, control)
505 	register struct in6pcb *in6p;
506 	register struct mbuf *m;
507 	struct mbuf *addr6, *control;
508 {
509 	register int ulen = m->m_pkthdr.len;
510 	int plen = sizeof(struct udphdr) + ulen;
511 	struct ip6_hdr *ip6;
512 	struct udphdr *udp6;
513 	struct	in6_addr laddr6;
514 	int s = 0, error = 0;
515 	struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
516 	int priv = 0;
517 	struct proc *p = curproc;	/* XXX */
518 
519 	if (p && !suser(p->p_ucred, &p->p_acflag))
520 		priv = 1;
521 	if (control) {
522 		if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
523 			goto release;
524 		in6p->in6p_outputopts = &opt;
525 	}
526 
527 	if (addr6) {
528 		laddr6 = in6p->in6p_laddr;
529 		if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
530 			error = EISCONN;
531 			goto release;
532 		}
533 		/*
534 		 * Must block input while temporarily connected.
535 		 */
536 		s = splsoftnet();
537 		error = in6_pcbconnect(in6p, addr6);
538 		if (error) {
539 			splx(s);
540 			goto release;
541 		}
542 	} else {
543 		if (IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
544 			error = ENOTCONN;
545 			goto release;
546 		}
547 	}
548 	/*
549 	 * Calculate data length and get a mbuf
550 	 * for UDP and IP6 headers.
551 	 */
552 	M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr), M_DONTWAIT);
553 	if (m == 0) {
554 		error = ENOBUFS;
555 		if (addr6)
556 			splx(s);
557 		goto release;
558 	}
559 
560 	/*
561 	 * Stuff checksum and output datagram.
562 	 */
563 	ip6 = mtod(m, struct ip6_hdr *);
564 	ip6->ip6_flow	= in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
565 	ip6->ip6_vfc 	= IPV6_VERSION;
566 #if 0				/* ip6_plen will be filled in ip6_output. */
567 	ip6->ip6_plen	= htons((u_short)plen);
568 #endif
569 	ip6->ip6_nxt	= IPPROTO_UDP;
570 	ip6->ip6_hlim	= in6p->in6p_ip6.ip6_hlim; /* XXX */
571 	ip6->ip6_src	= in6p->in6p_laddr;
572 	ip6->ip6_dst	= in6p->in6p_faddr;
573 
574 	udp6 = (struct udphdr *)(ip6 + 1);
575 	udp6->uh_sport = in6p->in6p_lport;
576 	udp6->uh_dport = in6p->in6p_fport;
577 	udp6->uh_ulen  = htons((u_short)plen);
578 	udp6->uh_sum   = 0;
579 
580 	if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
581 					sizeof(struct ip6_hdr), plen)) == 0) {
582 		udp6->uh_sum = 0xffff;
583 	}
584 
585 	udp6stat.udp6s_opackets++;
586 
587 #ifdef IPSEC
588 	m->m_pkthdr.rcvif = (struct ifnet *)in6p->in6p_socket;
589 #endif /*IPSEC*/
590 	error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
591 			    0, in6p->in6p_moptions);
592 
593 	if (addr6) {
594 		in6_pcbdisconnect(in6p);
595 		in6p->in6p_laddr = laddr6;
596 		splx(s);
597 	}
598 	goto releaseopt;
599 
600 release:
601 	m_freem(m);
602 
603 releaseopt:
604 	if (control) {
605 		in6p->in6p_outputopts = stickyopt;
606 		m_freem(control);
607 	}
608 	return(error);
609 }
610 
611 extern	int udp6_sendspace;
612 extern	int udp6_recvspace;
613 
614 int
615 udp6_usrreq(so, req, m, addr6, control, p)
616 	struct socket *so;
617 	int req;
618 	struct mbuf *m, *addr6, *control;
619 	struct proc *p;
620 {
621 	struct	in6pcb *in6p = sotoin6pcb(so);
622 	int	error = 0;
623 	int	s;
624 
625 	/*
626 	 * MAPPED_ADDR implementation info:
627 	 *  Mapped addr support for PRU_CONTROL is not necessary.
628 	 *  Because typical user of PRU_CONTROL is such as ifconfig,
629 	 *  and they don't associate any addr to their socket.  Then
630 	 *  socket family is only hint about the PRU_CONTROL'ed address
631 	 *  family, especially when getting addrs from kernel.
632 	 *  So AF_INET socket need to be used to control AF_INET addrs,
633 	 *  and AF_INET6 socket for AF_INET6 addrs.
634 	 */
635 	if (req == PRU_CONTROL)
636 		return(in6_control(so, (u_long)m, (caddr_t)addr6,
637 				   (struct ifnet *)control, p));
638 
639 	if (in6p == NULL && req != PRU_ATTACH) {
640 		error = EINVAL;
641 		goto release;
642 	}
643 
644 	switch (req) {
645 	case PRU_ATTACH:
646 		/*
647 		 * MAPPED_ADDR implementation spec:
648 		 *  Always attach for IPv6,
649 		 *  and only when necessary for IPv4.
650 		 */
651 		if (in6p != NULL) {
652 			error = EINVAL;
653 			break;
654 		}
655 		s = splsoftnet();
656 		error = in6_pcballoc(so, &udb6);
657 		splx(s);
658 		if (error)
659 			break;
660 		error = soreserve(so, udp6_sendspace, udp6_recvspace);
661 		if (error)
662 			break;
663 		in6p = sotoin6pcb(so);
664 		in6p->in6p_ip6.ip6_hlim = ip6_defhlim;
665 		in6p->in6p_cksum = -1;	/* just to be sure */
666 #ifdef IPSEC
667 		if ((error = ipsec_init_policy(&in6p->in6p_sp)) != 0)
668 			in6_pcbdetach(in6p);
669 #endif /*IPSEC*/
670 		break;
671 
672 	case PRU_DETACH:
673 		udp6_detach(in6p);
674 		break;
675 
676 	case PRU_BIND:
677 		s = splsoftnet();
678 		error = in6_pcbbind(in6p, addr6);
679 		splx(s);
680 		break;
681 
682 	case PRU_LISTEN:
683 		error = EOPNOTSUPP;
684 		break;
685 
686 	case PRU_CONNECT:
687 		if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
688 			error = EISCONN;
689 			break;
690 		}
691 		s = splsoftnet();
692 		error = in6_pcbconnect(in6p, addr6);
693 		if (ip6_auto_flowlabel) {
694 			in6p->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
695 			in6p->in6p_flowinfo |=
696 				(htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
697 		}
698 		splx(s);
699 		if (error == 0)
700 			soisconnected(so);
701 		break;
702 
703 	case PRU_CONNECT2:
704 		error = EOPNOTSUPP;
705 		break;
706 
707 	case PRU_ACCEPT:
708 		error = EOPNOTSUPP;
709 		break;
710 
711 	case PRU_DISCONNECT:
712 		if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
713 			error = ENOTCONN;
714 			break;
715 		}
716 		s = splsoftnet();
717 		in6_pcbdisconnect(in6p);
718 		bzero((caddr_t)&in6p->in6p_laddr, sizeof(in6p->in6p_laddr));
719 		splx(s);
720 		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
721 		break;
722 
723 	case PRU_SHUTDOWN:
724 		socantsendmore(so);
725 		break;
726 
727 	case PRU_SEND:
728 		return(udp6_output(in6p, m, addr6, control));
729 
730 	case PRU_ABORT:
731 		soisdisconnected(so);
732 		udp6_detach(in6p);
733 		break;
734 
735 	case PRU_SOCKADDR:
736 		in6_setsockaddr(in6p, addr6);
737 		break;
738 
739 	case PRU_PEERADDR:
740 		in6_setpeeraddr(in6p, addr6);
741 		break;
742 
743 	case PRU_SENSE:
744 		/*
745 		 * stat: don't bother with a blocksize
746 		 */
747 		return(0);
748 
749 	case PRU_SENDOOB:
750 	case PRU_FASTTIMO:
751 	case PRU_SLOWTIMO:
752 	case PRU_PROTORCV:
753 	case PRU_PROTOSEND:
754 		error = EOPNOTSUPP;
755 		break;
756 
757 	case PRU_RCVD:
758 	case PRU_RCVOOB:
759 		return(EOPNOTSUPP);	/* do not free mbuf's */
760 
761 	default:
762 		panic("udp6_usrreq");
763 	}
764 
765 release:
766 	if (control) {
767 		printf("udp control data unexpectedly retained\n");
768 		m_freem(control);
769 	}
770 	if (m)
771 		m_freem(m);
772 	return(error);
773 }
774 
775 static void
776 udp6_detach(in6p)
777 	struct in6pcb *in6p;
778 {
779 	int	s = splsoftnet();
780 
781 	if (in6p == udp6_last_in6pcb)
782 		udp6_last_in6pcb = &udb6;
783 	in6_pcbdetach(in6p);
784 	splx(s);
785 }
786 
787 #ifdef __bsdi__
788 int *udp6_sysvars[] = UDP6CTL_VARS;
789 
790 int
791 udp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
792 	int	*name;
793 	u_int	namelen;
794 	void	*oldp;
795 	size_t	*oldlenp;
796 	void	*newp;
797 	size_t	newlen;
798 {
799 	if (name[0] >= UDP6CTL_MAXID)
800 		return (EOPNOTSUPP);
801 	switch (name[0]) {
802 	case UDP6CTL_STATS:
803 		return sysctl_rdtrunc(oldp, oldlenp, newp, &udp6stat,
804 		    sizeof(udp6stat));
805 
806 	default:
807 		return (sysctl_int_arr(udp6_sysvars, name, namelen,
808 		    oldp, oldlenp, newp, newlen));
809 	}
810 }
811 #endif /*__bsdi__*/
812 
813 #ifdef __NetBSD__
814 #include <vm/vm.h>
815 #include <sys/sysctl.h>
816 
817 int
818 udp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
819 	int *name;
820 	u_int namelen;
821 	void *oldp;
822 	size_t *oldlenp;
823 	void *newp;
824 	size_t newlen;
825 {
826 	/* All sysctl names at this level are terminal. */
827 	if (namelen != 1)
828 		return ENOTDIR;
829 
830 	switch (name[0]) {
831 
832 	case UDP6CTL_SENDMAX:
833 		return sysctl_int(oldp, oldlenp, newp, newlen,
834 		    &udp6_sendspace);
835 	case UDP6CTL_RECVSPACE:
836 		return sysctl_int(oldp, oldlenp, newp, newlen,
837 		    &udp6_recvspace);
838 	default:
839 		return ENOPROTOOPT;
840 	}
841 	/* NOTREACHED */
842 }
843 #endif
844