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