in6_pcb.c revision 55679
153541Sshin/* 253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 353541Sshin * All rights reserved. 453541Sshin * 553541Sshin * Redistribution and use in source and binary forms, with or without 653541Sshin * modification, are permitted provided that the following conditions 753541Sshin * are met: 853541Sshin * 1. Redistributions of source code must retain the above copyright 953541Sshin * notice, this list of conditions and the following disclaimer. 1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1153541Sshin * notice, this list of conditions and the following disclaimer in the 1253541Sshin * documentation and/or other materials provided with the distribution. 1353541Sshin * 3. Neither the name of the project nor the names of its contributors 1453541Sshin * may be used to endorse or promote products derived from this software 1553541Sshin * without specific prior written permission. 1653541Sshin * 1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2053541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2753541Sshin * SUCH DAMAGE. 2853541Sshin * 2953541Sshin * $FreeBSD: head/sys/netinet6/in6_pcb.c 55679 2000-01-09 19:17:30Z shin $ 3053541Sshin */ 3153541Sshin 3253541Sshin/* 3353541Sshin * Copyright (c) 1982, 1986, 1991, 1993 3453541Sshin * The Regents of the University of California. All rights reserved. 3553541Sshin * 3653541Sshin * Redistribution and use in source and binary forms, with or without 3753541Sshin * modification, are permitted provided that the following conditions 3853541Sshin * are met: 3953541Sshin * 1. Redistributions of source code must retain the above copyright 4053541Sshin * notice, this list of conditions and the following disclaimer. 4153541Sshin * 2. Redistributions in binary form must reproduce the above copyright 4253541Sshin * notice, this list of conditions and the following disclaimer in the 4353541Sshin * documentation and/or other materials provided with the distribution. 4453541Sshin * 3. All advertising materials mentioning features or use of this software 4553541Sshin * must display the following acknowledgement: 4653541Sshin * This product includes software developed by the University of 4753541Sshin * California, Berkeley and its contributors. 4853541Sshin * 4. Neither the name of the University nor the names of its contributors 4953541Sshin * may be used to endorse or promote products derived from this software 5053541Sshin * without specific prior written permission. 5153541Sshin * 5253541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5353541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5453541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5553541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5653541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5753541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5853541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5953541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6053541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6153541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6253541Sshin * SUCH DAMAGE. 6353541Sshin * 6453541Sshin * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94 6553541Sshin * $FreeBSD: head/sys/netinet6/in6_pcb.c 55679 2000-01-09 19:17:30Z shin $ 6653541Sshin */ 6753541Sshin 6855009Sshin#include "opt_ipsec.h" 6953541Sshin 7053541Sshin#include <sys/param.h> 7153541Sshin#include <sys/systm.h> 7253541Sshin#include <sys/malloc.h> 7353541Sshin#include <sys/mbuf.h> 7455679Sshin#include <sys/domain.h> 7553541Sshin#include <sys/protosw.h> 7653541Sshin#include <sys/socket.h> 7753541Sshin#include <sys/socketvar.h> 7853541Sshin#include <sys/sockio.h> 7953541Sshin#include <sys/errno.h> 8053541Sshin#include <sys/time.h> 8153541Sshin#include <sys/proc.h> 8253541Sshin#include <sys/jail.h> 8353541Sshin 8453541Sshin#include <vm/vm_zone.h> 8553541Sshin 8653541Sshin#include <net/if.h> 8753541Sshin#include <net/if_types.h> 8853541Sshin#include <net/route.h> 8953541Sshin 9053541Sshin#include <netinet/in.h> 9153541Sshin#include <netinet/in_var.h> 9253541Sshin#include <netinet/in_systm.h> 9353541Sshin#include <netinet6/ip6.h> 9455679Sshin#include <netinet/ip_var.h> 9553541Sshin#include <netinet6/ip6_var.h> 9653541Sshin#include <netinet6/nd6.h> 9753541Sshin#include <netinet/in_pcb.h> 9853541Sshin#include <netinet6/in6_pcb.h> 9953541Sshin 10054263Sshin#include "faith.h" 10153541Sshin 10253541Sshin#ifdef IPSEC 10353541Sshin#include <netinet6/ipsec.h> 10455009Sshin#include <netinet6/ah.h> 10553541Sshin#include <netinet6/ipsec6.h> 10655009Sshin#include <netinet6/ah6.h> 10753541Sshin#include <netkey/key.h> 10855009Sshin#ifdef IPSEC_DEBUG 10953541Sshin#include <netkey/key_debug.h> 11053541Sshin#else 11155009Sshin#define KEYDEBUG(lev,arg) 11255009Sshin#endif /* IPSEC_DEBUG */ 11353541Sshin#endif /* IPSEC */ 11453541Sshin 11553541Sshinstruct in6_addr zeroin6_addr; 11653541Sshin 11753541Sshinint 11853541Sshinin6_pcbbind(inp, nam, p) 11953541Sshin register struct inpcb *inp; 12053541Sshin struct sockaddr *nam; 12153541Sshin struct proc *p; 12253541Sshin{ 12353541Sshin struct socket *so = inp->inp_socket; 12453541Sshin unsigned short *lastport; 12553541Sshin struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL; 12653541Sshin struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 12753541Sshin u_short lport = 0; 12853541Sshin int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 12953541Sshin int error; 13053541Sshin 13153541Sshin if (!in6_ifaddr) /* XXX broken! */ 13253541Sshin return (EADDRNOTAVAIL); 13353541Sshin if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) 13453541Sshin return(EINVAL); 13553541Sshin if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 13653541Sshin wild = 1; 13753541Sshin if (nam) { 13853541Sshin sin6 = (struct sockaddr_in6 *)nam; 13953541Sshin if (nam->sa_len != sizeof(*sin6)) 14053541Sshin return(EINVAL); 14153541Sshin /* 14253541Sshin * family check. 14353541Sshin */ 14453541Sshin if (nam->sa_family != AF_INET6) 14553541Sshin return(EAFNOSUPPORT); 14653541Sshin 14753541Sshin /* 14853541Sshin * If the scope of the destination is link-local, embed the 14953541Sshin * interface index in the address. 15053541Sshin */ 15153541Sshin if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { 15253541Sshin /* XXX boundary check is assumed to be already done. */ 15353541Sshin /* XXX sin6_scope_id is weaker than advanced-api. */ 15453541Sshin struct in6_pktinfo *pi; 15553541Sshin if (inp->in6p_outputopts && 15653541Sshin (pi = inp->in6p_outputopts->ip6po_pktinfo) && 15753541Sshin pi->ipi6_ifindex) { 15853541Sshin sin6->sin6_addr.s6_addr16[1] 15953541Sshin = htons(pi->ipi6_ifindex); 16053541Sshin } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) 16153541Sshin && inp->in6p_moptions 16253541Sshin && inp->in6p_moptions->im6o_multicast_ifp) { 16353541Sshin sin6->sin6_addr.s6_addr16[1] = 16453541Sshin htons(inp->in6p_moptions->im6o_multicast_ifp->if_index); 16553541Sshin } else if (sin6->sin6_scope_id) { 16653541Sshin /* boundary check */ 16753541Sshin if (sin6->sin6_scope_id < 0 16853541Sshin || if_index < sin6->sin6_scope_id) { 16953541Sshin return ENXIO; /* XXX EINVAL? */ 17053541Sshin } 17153541Sshin sin6->sin6_addr.s6_addr16[1] 17253541Sshin = htons(sin6->sin6_scope_id & 0xffff);/*XXX*/ 17353541Sshin /* this must be cleared for ifa_ifwithaddr() */ 17453541Sshin sin6->sin6_scope_id = 0; 17553541Sshin } 17653541Sshin } 17753541Sshin 17853541Sshin lport = sin6->sin6_port; 17953541Sshin if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 18053541Sshin /* 18153541Sshin * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 18253541Sshin * allow compepte duplication of binding if 18353541Sshin * SO_REUSEPORT is set, or if SO_REUSEADDR is set 18453541Sshin * and a multicast address is bound on both 18553541Sshin * new and duplicated sockets. 18653541Sshin */ 18753541Sshin if (so->so_options & SO_REUSEADDR) 18853541Sshin reuseport = SO_REUSEADDR|SO_REUSEPORT; 18953541Sshin } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 19053541Sshin struct ifaddr *ia = NULL; 19153541Sshin 19253541Sshin sin6->sin6_port = 0; /* yech... */ 19353541Sshin if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0) 19453541Sshin return(EADDRNOTAVAIL); 19553541Sshin 19653541Sshin /* 19753541Sshin * XXX: bind to an anycast address might accidentally 19853541Sshin * cause sending a packet with anycast source address. 19953541Sshin */ 20053541Sshin if (ia && 20153541Sshin ((struct in6_ifaddr *)ia)->ia6_flags & 20253541Sshin (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| 20353541Sshin IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { 20453541Sshin return(EADDRNOTAVAIL); 20553541Sshin } 20653541Sshin } 20753541Sshin if (lport) { 20853541Sshin struct inpcb *t; 20953541Sshin 21053541Sshin /* GROSS */ 21153541Sshin if (ntohs(lport) < IPV6PORT_RESERVED && p && 21253541Sshin suser_xxx(0, p, PRISON_ROOT)) 21353541Sshin return(EACCES); 21453541Sshin if (so->so_cred->cr_uid != 0 && 21553541Sshin !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 21655679Sshin t = in6_pcblookup_local(pcbinfo, 21753541Sshin &sin6->sin6_addr, lport, 21853541Sshin INPLOOKUP_WILDCARD); 21953541Sshin if (t && 22053541Sshin (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || 22153541Sshin !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || 22253541Sshin (t->inp_socket->so_options & 22353541Sshin SO_REUSEPORT) == 0) && 22453541Sshin (so->so_cred->cr_uid != 22553541Sshin t->inp_socket->so_cred->cr_uid)) 22653541Sshin return (EADDRINUSE); 22755679Sshin if (ip6_mapped_addr_on != 0 && 22855679Sshin IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 22955679Sshin struct sockaddr_in sin; 23055679Sshin 23155679Sshin in6_sin6_2_sin(&sin, sin6); 23255679Sshin t = in_pcblookup_local(pcbinfo, 23355679Sshin sin.sin_addr, lport, 23455679Sshin INPLOOKUP_WILDCARD); 23555679Sshin if (t && 23655679Sshin (so->so_cred->cr_uid != 23755679Sshin t->inp_socket->so_cred->cr_uid) && 23855679Sshin (ntohl(t->inp_laddr.s_addr) != 23955679Sshin INADDR_ANY || 24055679Sshin INP_SOCKAF(so) == 24155679Sshin INP_SOCKAF(t->inp_socket))) 24255679Sshin return (EADDRINUSE); 24355679Sshin } 24453541Sshin } 24553541Sshin t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr, 24653541Sshin lport, wild); 24753541Sshin if (t && (reuseport & t->inp_socket->so_options) == 0) 24853541Sshin return(EADDRINUSE); 24955679Sshin if (ip6_mapped_addr_on != 0 && 25055679Sshin IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 25155679Sshin struct sockaddr_in sin; 25255679Sshin 25355679Sshin in6_sin6_2_sin(&sin, sin6); 25455679Sshin t = in_pcblookup_local(pcbinfo, sin.sin_addr, 25555679Sshin lport, wild); 25655679Sshin if (t && 25755679Sshin (reuseport & t->inp_socket->so_options) 25855679Sshin == 0 && 25955679Sshin (ntohl(t->inp_laddr.s_addr) 26055679Sshin != INADDR_ANY || 26155679Sshin INP_SOCKAF(so) == 26255679Sshin INP_SOCKAF(t->inp_socket))) 26355679Sshin return (EADDRINUSE); 26455679Sshin } 26553541Sshin } 26653541Sshin inp->in6p_laddr = sin6->sin6_addr; 26753541Sshin } 26853541Sshin if (lport == 0) { 26953541Sshin ushort first, last; 27053541Sshin int count; 27153541Sshin 27253541Sshin inp->inp_flags |= INP_ANONPORT; 27353541Sshin 27453541Sshin if (inp->inp_flags & INP_HIGHPORT) { 27553541Sshin first = ipport_hifirstauto; /* sysctl */ 27653541Sshin last = ipport_hilastauto; 27753541Sshin lastport = &pcbinfo->lasthi; 27853541Sshin } else if (inp->inp_flags & INP_LOWPORT) { 27953541Sshin if (p && (error = suser_xxx(0, p, PRISON_ROOT))) 28053541Sshin return error; 28153541Sshin first = ipport_lowfirstauto; /* 1023 */ 28253541Sshin last = ipport_lowlastauto; /* 600 */ 28353541Sshin lastport = &pcbinfo->lastlow; 28453541Sshin } else { 28553541Sshin first = ipport_firstauto; /* sysctl */ 28653541Sshin last = ipport_lastauto; 28753541Sshin lastport = &pcbinfo->lastport; 28853541Sshin } 28953541Sshin /* 29053541Sshin * Simple check to ensure all ports are not used up causing 29153541Sshin * a deadlock here. 29253541Sshin * 29353541Sshin * We split the two cases (up and down) so that the direction 29453541Sshin * is not being tested on each round of the loop. 29553541Sshin */ 29653541Sshin if (first > last) { 29753541Sshin /* 29853541Sshin * counting down 29953541Sshin */ 30053541Sshin count = first - last; 30153541Sshin 30253541Sshin do { 30353541Sshin if (count-- < 0) { /* completely used? */ 30453541Sshin /* 30553541Sshin * Undo any address bind that may have 30653541Sshin * occurred above. 30753541Sshin */ 30853541Sshin inp->in6p_laddr = in6addr_any; 30953541Sshin return (EAGAIN); 31053541Sshin } 31153541Sshin --*lastport; 31253541Sshin if (*lastport > first || *lastport < last) 31353541Sshin *lastport = first; 31453541Sshin lport = htons(*lastport); 31553541Sshin } while (in6_pcblookup_local(pcbinfo, 31653541Sshin &inp->in6p_laddr, lport, wild)); 31753541Sshin } else { 31853541Sshin /* 31953541Sshin * counting up 32053541Sshin */ 32153541Sshin count = last - first; 32253541Sshin 32353541Sshin do { 32453541Sshin if (count-- < 0) { /* completely used? */ 32553541Sshin /* 32653541Sshin * Undo any address bind that may have 32753541Sshin * occurred above. 32853541Sshin */ 32953541Sshin inp->in6p_laddr = in6addr_any; 33053541Sshin return (EAGAIN); 33153541Sshin } 33253541Sshin ++*lastport; 33353541Sshin if (*lastport < first || *lastport > last) 33453541Sshin *lastport = first; 33553541Sshin lport = htons(*lastport); 33653541Sshin } while (in6_pcblookup_local(pcbinfo, 33753541Sshin &inp->in6p_laddr, lport, wild)); 33853541Sshin } 33953541Sshin } 34053541Sshin inp->inp_lport = lport; 34153541Sshin if (in_pcbinshash(inp) != 0) { 34253541Sshin inp->in6p_laddr = in6addr_any; 34353541Sshin inp->inp_lport = 0; 34453541Sshin return (EAGAIN); 34553541Sshin } 34653541Sshin inp->in6p_flowinfo = sin6 ? sin6->sin6_flowinfo : 0; /*XXX*/ 34753541Sshin return(0); 34853541Sshin} 34953541Sshin 35053541Sshin/* 35153541Sshin * Transform old in6_pcbconnect() into an inner subroutine for new 35253541Sshin * in6_pcbconnect(): Do some validity-checking on the remote 35353541Sshin * address (in mbuf 'nam') and then determine local host address 35453541Sshin * (i.e., which interface) to use to access that remote host. 35553541Sshin * 35653541Sshin * This preserves definition of in6_pcbconnect(), while supporting a 35753541Sshin * slightly different version for T/TCP. (This is more than 35853541Sshin * a bit of a kludge, but cleaning up the internal interfaces would 35953541Sshin * have forced minor changes in every protocol). 36053541Sshin */ 36153541Sshin 36253541Sshinint 36353541Sshinin6_pcbladdr(inp, nam, plocal_addr6) 36453541Sshin register struct inpcb *inp; 36553541Sshin struct sockaddr *nam; 36653541Sshin struct in6_addr **plocal_addr6; 36753541Sshin{ 36853541Sshin register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; 36953541Sshin struct in6_pktinfo *pi; 37053541Sshin struct ifnet *ifp = NULL; 37153541Sshin int error = 0; 37253541Sshin 37353541Sshin if (nam->sa_len != sizeof (*sin6)) 37453541Sshin return (EINVAL); 37553541Sshin if (sin6->sin6_family != AF_INET6) 37653541Sshin return (EAFNOSUPPORT); 37753541Sshin if (sin6->sin6_port == 0) 37853541Sshin return (EADDRNOTAVAIL); 37953541Sshin 38053541Sshin /* 38153541Sshin * If the scope of the destination is link-local, embed the interface 38253541Sshin * index in the address. 38353541Sshin */ 38453541Sshin if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { 38553541Sshin /* XXX boundary check is assumed to be already done. */ 38653541Sshin /* XXX sin6_scope_id is weaker than advanced-api. */ 38753541Sshin if (inp->in6p_outputopts && 38853541Sshin (pi = inp->in6p_outputopts->ip6po_pktinfo) && 38953541Sshin pi->ipi6_ifindex) { 39053541Sshin sin6->sin6_addr.s6_addr16[1] = htons(pi->ipi6_ifindex); 39153541Sshin ifp = ifindex2ifnet[pi->ipi6_ifindex]; 39253541Sshin } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) && 39353541Sshin inp->in6p_moptions && 39453541Sshin inp->in6p_moptions->im6o_multicast_ifp) { 39553541Sshin sin6->sin6_addr.s6_addr16[1] = 39653541Sshin htons(inp->in6p_moptions->im6o_multicast_ifp->if_index); 39753541Sshin ifp = ifindex2ifnet[inp->in6p_moptions->im6o_multicast_ifp->if_index]; 39853541Sshin } else if (sin6->sin6_scope_id) { 39953541Sshin /* boundary check */ 40053541Sshin if (sin6->sin6_scope_id < 0 40153541Sshin || if_index < sin6->sin6_scope_id) { 40253541Sshin return ENXIO; /* XXX EINVAL? */ 40353541Sshin } 40453541Sshin sin6->sin6_addr.s6_addr16[1] 40553541Sshin = htons(sin6->sin6_scope_id & 0xffff);/*XXX*/ 40653541Sshin ifp = ifindex2ifnet[sin6->sin6_scope_id]; 40753541Sshin } 40853541Sshin } 40953541Sshin 41053541Sshin if (in6_ifaddr) { 41153541Sshin /* 41253541Sshin * If the destination address is UNSPECIFIED addr, 41353541Sshin * use the loopback addr, e.g ::1. 41453541Sshin */ 41553541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) 41653541Sshin sin6->sin6_addr = in6addr_loopback; 41753541Sshin } 41853541Sshin { 41953541Sshin /* 42053541Sshin * XXX: in6_selectsrc might replace the bound local address 42153541Sshin * with the address specified by setsockopt(IPV6_PKTINFO). 42253541Sshin * Is it the intended behavior? 42353541Sshin */ 42453541Sshin *plocal_addr6 = in6_selectsrc(sin6, inp->in6p_outputopts, 42553541Sshin inp->in6p_moptions, 42653541Sshin &inp->in6p_route, 42753541Sshin &inp->in6p_laddr, &error); 42853541Sshin if (*plocal_addr6 == 0) { 42953541Sshin if (error == 0) 43053541Sshin error = EADDRNOTAVAIL; 43153541Sshin return(error); 43253541Sshin } 43353541Sshin /* 43453541Sshin * Don't do pcblookup call here; return interface in 43553541Sshin * plocal_addr6 43653541Sshin * and exit to caller, that will do the lookup. 43753541Sshin */ 43853541Sshin } 43953541Sshin 44053541Sshin if (inp->in6p_route.ro_rt) 44153541Sshin ifp = inp->in6p_route.ro_rt->rt_ifp; 44253541Sshin 44353541Sshin inp->in6p_ip6_hlim = (u_int8_t)in6_selecthlim(inp, ifp); 44453541Sshin 44553541Sshin return(0); 44653541Sshin} 44753541Sshin 44853541Sshin/* 44953541Sshin * Outer subroutine: 45053541Sshin * Connect from a socket to a specified address. 45153541Sshin * Both address and port must be specified in argument sin. 45253541Sshin * If don't have a local address for this socket yet, 45353541Sshin * then pick one. 45453541Sshin */ 45553541Sshinint 45653541Sshinin6_pcbconnect(inp, nam, p) 45753541Sshin register struct inpcb *inp; 45853541Sshin struct sockaddr *nam; 45953541Sshin struct proc *p; 46053541Sshin{ 46153541Sshin struct in6_addr *addr6; 46253541Sshin register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; 46353541Sshin int error; 46453541Sshin 46553541Sshin /* 46653541Sshin * Call inner routine, to assign local interface address. 46753541Sshin */ 46853541Sshin if ((error = in6_pcbladdr(inp, nam, &addr6)) != 0) 46953541Sshin return(error); 47053541Sshin 47153541Sshin if (in6_pcblookup_hash(inp->inp_pcbinfo, &sin6->sin6_addr, 47253541Sshin sin6->sin6_port, 47353541Sshin IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) 47453541Sshin ? addr6 : &inp->in6p_laddr, 47553541Sshin inp->inp_lport, 0, NULL) != NULL) { 47653541Sshin return (EADDRINUSE); 47753541Sshin } 47853541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { 47953541Sshin if (inp->inp_lport == 0) { 48053541Sshin error = in6_pcbbind(inp, (struct sockaddr *)0, p); 48153541Sshin if (error) 48253541Sshin return (error); 48353541Sshin } 48453541Sshin inp->in6p_laddr = *addr6; 48553541Sshin } 48653541Sshin inp->in6p_faddr = sin6->sin6_addr; 48753541Sshin inp->inp_fport = sin6->sin6_port; 48853541Sshin /* 48953541Sshin * xxx kazu flowlabel is necessary for connect? 49053541Sshin * but if this line is missing, the garbage value remains. 49153541Sshin */ 49253541Sshin inp->in6p_flowinfo = sin6->sin6_flowinfo; 49355679Sshin#ifdef INET6 49455679Sshin if ((inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) == 0 && 49555679Sshin ip6_auto_flowlable != 0) 49655679Sshin inp->in6p_flowinfo |= 49755679Sshin (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); 49855679Sshin#endif 49953541Sshin 50053541Sshin in_pcbrehash(inp); 50153541Sshin return (0); 50253541Sshin} 50353541Sshin 50453541Sshin/* 50553541Sshin * Return an IPv6 address, which is the most appropriate for given 50653541Sshin * destination and user specified options. 50753541Sshin * If necessary, this function lookups the routing table and return 50853541Sshin * an entry to the caller for later use. 50953541Sshin */ 51053541Sshinstruct in6_addr * 51153541Sshinin6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) 51253541Sshin struct sockaddr_in6 *dstsock; 51353541Sshin struct ip6_pktopts *opts; 51453541Sshin struct ip6_moptions *mopts; 51553541Sshin struct route_in6 *ro; 51653541Sshin struct in6_addr *laddr; 51753541Sshin int *errorp; 51853541Sshin{ 51953541Sshin struct in6_addr *dst; 52053541Sshin struct in6_ifaddr *ia6 = 0; 52153541Sshin struct in6_pktinfo *pi = NULL; 52253541Sshin 52353541Sshin dst = &dstsock->sin6_addr; 52453541Sshin *errorp = 0; 52553541Sshin 52653541Sshin /* 52753541Sshin * If the source address is explicitly specified by the caller, 52853541Sshin * use it. 52953541Sshin */ 53053541Sshin if (opts && (pi = opts->ip6po_pktinfo) && 53153541Sshin !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) 53253541Sshin return(&pi->ipi6_addr); 53353541Sshin 53453541Sshin /* 53553541Sshin * If the source address is not specified but the socket(if any) 53653541Sshin * is already bound, use the bound address. 53753541Sshin */ 53853541Sshin if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) 53953541Sshin return(laddr); 54053541Sshin 54153541Sshin /* 54253541Sshin * If the caller doesn't specify the source address but 54353541Sshin * the outgoing interface, use an address associated with 54453541Sshin * the interface. 54553541Sshin */ 54653541Sshin if (pi && pi->ipi6_ifindex) { 54753541Sshin /* XXX boundary check is assumed to be already done. */ 54853541Sshin ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex], 54953541Sshin dst); 55053541Sshin if (ia6 == 0) { 55153541Sshin *errorp = EADDRNOTAVAIL; 55253541Sshin return(0); 55353541Sshin } 55453541Sshin return(&satosin6(&ia6->ia_addr)->sin6_addr); 55553541Sshin } 55653541Sshin 55753541Sshin /* 55853541Sshin * If the destination address is a link-local unicast address or 55953541Sshin * a multicast address, and if the outgoing interface is specified 56053541Sshin * by the sin6_scope_id filed, use an address associated with the 56153541Sshin * interface. 56253541Sshin * XXX: We're now trying to define more specific semantics of 56353541Sshin * sin6_scope_id field, so this part will be rewritten in 56453541Sshin * the near future. 56553541Sshin */ 56653541Sshin if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) && 56753541Sshin dstsock->sin6_scope_id) { 56853541Sshin /* 56953541Sshin * I'm not sure if boundary check for scope_id is done 57053541Sshin * somewhere... 57153541Sshin */ 57253541Sshin if (dstsock->sin6_scope_id < 0 || 57353541Sshin if_index < dstsock->sin6_scope_id) { 57453541Sshin *errorp = ENXIO; /* XXX: better error? */ 57553541Sshin return(0); 57653541Sshin } 57753541Sshin ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id], 57853541Sshin dst); 57953541Sshin if (ia6 == 0) { 58053541Sshin *errorp = EADDRNOTAVAIL; 58153541Sshin return(0); 58253541Sshin } 58353541Sshin return(&satosin6(&ia6->ia_addr)->sin6_addr); 58453541Sshin } 58553541Sshin 58653541Sshin /* 58753541Sshin * If the destination address is a multicast address and 58853541Sshin * the outgoing interface for the address is specified 58953541Sshin * by the caller, use an address associated with the interface. 59053541Sshin * There is a sanity check here; if the destination has node-local 59153541Sshin * scope, the outgoing interfacde should be a loopback address. 59253541Sshin * Even if the outgoing interface is not specified, we also 59353541Sshin * choose a loopback interface as the outgoing interface. 59453541Sshin */ 59553541Sshin if (IN6_IS_ADDR_MULTICAST(dst)) { 59653541Sshin struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL; 59753541Sshin 59853541Sshin if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) { 59953541Sshin ifp = &loif[0]; 60053541Sshin } 60153541Sshin 60253541Sshin if (ifp) { 60353541Sshin ia6 = in6_ifawithscope(ifp, dst); 60453541Sshin if (ia6 == 0) { 60553541Sshin *errorp = EADDRNOTAVAIL; 60653541Sshin return(0); 60753541Sshin } 60853541Sshin return(&ia6->ia_addr.sin6_addr); 60953541Sshin } 61053541Sshin } 61153541Sshin 61253541Sshin /* 61353541Sshin * If the next hop address for the packet is specified 61453541Sshin * by caller, use an address associated with the route 61553541Sshin * to the next hop. 61653541Sshin */ 61753541Sshin { 61853541Sshin struct sockaddr_in6 *sin6_next; 61953541Sshin struct rtentry *rt; 62053541Sshin 62153541Sshin if (opts && opts->ip6po_nexthop) { 62253541Sshin sin6_next = satosin6(opts->ip6po_nexthop); 62353541Sshin rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL); 62453541Sshin if (rt) { 62553541Sshin ia6 = in6_ifawithscope(rt->rt_ifp, dst); 62653541Sshin if (ia6 == 0) 62753541Sshin ia6 = ifatoia6(rt->rt_ifa); 62853541Sshin } 62953541Sshin if (ia6 == 0) { 63053541Sshin *errorp = EADDRNOTAVAIL; 63153541Sshin return(0); 63253541Sshin } 63353541Sshin return(&satosin6(&ia6->ia_addr)->sin6_addr); 63453541Sshin } 63553541Sshin } 63653541Sshin 63753541Sshin /* 63853541Sshin * If route is known or can be allocated now, 63953541Sshin * our src addr is taken from the i/f, else punt. 64053541Sshin */ 64153541Sshin if (ro) { 64253541Sshin if (ro->ro_rt && 64353541Sshin !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) { 64453541Sshin RTFREE(ro->ro_rt); 64553541Sshin ro->ro_rt = (struct rtentry *)0; 64653541Sshin } 64753541Sshin if (ro->ro_rt == (struct rtentry *)0 || 64853541Sshin ro->ro_rt->rt_ifp == (struct ifnet *)0) { 64953541Sshin /* No route yet, so try to acquire one */ 65053541Sshin bzero(&ro->ro_dst, sizeof(struct sockaddr_in6)); 65153541Sshin ro->ro_dst.sin6_family = AF_INET6; 65253541Sshin ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6); 65353541Sshin ro->ro_dst.sin6_addr = *dst; 65453541Sshin if (IN6_IS_ADDR_MULTICAST(dst)) { 65553541Sshin ro->ro_rt = rtalloc1(&((struct route *)ro) 65653541Sshin ->ro_dst, 0, 0UL); 65753541Sshin } else { 65854350Sshin rtalloc((struct route *)ro); 65953541Sshin } 66053541Sshin } 66153541Sshin 66253541Sshin /* 66353541Sshin * in_pcbconnect() checks out IFF_LOOPBACK to skip using 66453541Sshin * the address. But we don't know why it does so. 66553541Sshin * It is necessary to ensure the scope even for lo0 66653541Sshin * so doesn't check out IFF_LOOPBACK. 66753541Sshin */ 66853541Sshin 66953541Sshin if (ro->ro_rt) { 67053541Sshin ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst); 67153541Sshin if (ia6 == 0) /* xxx scope error ?*/ 67253541Sshin ia6 = ifatoia6(ro->ro_rt->rt_ifa); 67353541Sshin } 67453541Sshin if (ia6 == 0) { 67553541Sshin *errorp = EHOSTUNREACH; /* no route */ 67653541Sshin return(0); 67753541Sshin } 67853541Sshin return(&satosin6(&ia6->ia_addr)->sin6_addr); 67953541Sshin } 68053541Sshin 68153541Sshin *errorp = EADDRNOTAVAIL; 68253541Sshin return(0); 68353541Sshin} 68453541Sshin 68553541Sshin/* 68653541Sshin * Default hop limit selection. The precedence is as follows: 68753541Sshin * 1. Hoplimit valued specified via ioctl. 68853541Sshin * 2. (If the outgoing interface is detected) the current 68953541Sshin * hop limit of the interface specified by router advertisement. 69053541Sshin * 3. The system default hoplimit. 69153541Sshin*/ 69253541Sshinint 69353541Sshinin6_selecthlim(in6p, ifp) 69453541Sshin struct in6pcb *in6p; 69553541Sshin struct ifnet *ifp; 69653541Sshin{ 69753541Sshin if (in6p && in6p->in6p_hops >= 0) 69853541Sshin return(in6p->in6p_hops); 69953541Sshin else if (ifp) 70053541Sshin return(nd_ifinfo[ifp->if_index].chlim); 70153541Sshin else 70253541Sshin return(ip6_defhlim); 70353541Sshin} 70453541Sshin 70553541Sshinvoid 70653541Sshinin6_pcbdisconnect(inp) 70753541Sshin struct inpcb *inp; 70853541Sshin{ 70953541Sshin bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr)); 71053541Sshin inp->inp_fport = 0; 71153541Sshin in_pcbrehash(inp); 71253541Sshin if (inp->inp_socket->so_state & SS_NOFDREF) 71353541Sshin in6_pcbdetach(inp); 71453541Sshin} 71553541Sshin 71653541Sshinvoid 71753541Sshinin6_pcbdetach(inp) 71853541Sshin struct inpcb *inp; 71953541Sshin{ 72053541Sshin struct socket *so = inp->inp_socket; 72153541Sshin struct inpcbinfo *ipi = inp->inp_pcbinfo; 72253541Sshin 72353541Sshin#ifdef IPSEC 72453541Sshin if (sotoinpcb(so) != 0) 72553541Sshin key_freeso(so); 72653541Sshin ipsec6_delete_pcbpolicy(inp); 72753541Sshin#endif /* IPSEC */ 72853541Sshin inp->inp_gencnt = ++ipi->ipi_gencnt; 72953541Sshin in_pcbremlists(inp); 73053541Sshin sotoinpcb(so) = 0; 73153541Sshin sofree(so); 73253541Sshin if (inp->in6p_options) 73353541Sshin m_freem(inp->in6p_options); 73453541Sshin if (inp->in6p_outputopts) { 73553541Sshin if (inp->in6p_outputopts->ip6po_rthdr && 73653541Sshin inp->in6p_outputopts->ip6po_route.ro_rt) 73753541Sshin RTFREE(inp->in6p_outputopts->ip6po_route.ro_rt); 73853541Sshin if (inp->in6p_outputopts->ip6po_m) 73953541Sshin (void)m_free(inp->in6p_outputopts->ip6po_m); 74053541Sshin free(inp->in6p_outputopts, M_IP6OPT); 74153541Sshin } 74253541Sshin if (inp->in6p_route.ro_rt) 74353541Sshin rtfree(inp->in6p_route.ro_rt); 74453541Sshin ip6_freemoptions(inp->in6p_moptions); 74555679Sshin 74655679Sshin /* Check and free IPv4 related resources in case of mapped addr */ 74755679Sshin if (inp->inp_options) 74855679Sshin (void)m_free(inp->inp_options); 74955679Sshin if (inp->inp_route.ro_rt) 75055679Sshin rtfree(inp->inp_route.ro_rt); 75155679Sshin ip_freemoptions(inp->inp_moptions); 75255679Sshin 75353541Sshin inp->inp_vflag = 0; 75453541Sshin zfreei(ipi->ipi_zone, inp); 75553541Sshin} 75653541Sshin 75753541Sshin/* 75853541Sshin * The calling convention of in6_setsockaddr() and in6_setpeeraddr() was 75953541Sshin * modified to match the pru_sockaddr() and pru_peeraddr() entry points 76053541Sshin * in struct pr_usrreqs, so that protocols can just reference then directly 76153541Sshin * without the need for a wrapper function. The socket must have a valid 76253541Sshin * (i.e., non-nil) PCB, but it should be impossible to get an invalid one 76353541Sshin * except through a kernel programming error, so it is acceptable to panic 76453541Sshin * (or in this case trap) if the PCB is invalid. (Actually, we don't trap 76553541Sshin * because there actually /is/ a programming error somewhere... XXX) 76653541Sshin */ 76753541Sshinint 76853541Sshinin6_setsockaddr(so, nam) 76953541Sshin struct socket *so; 77053541Sshin struct sockaddr **nam; 77153541Sshin{ 77253541Sshin int s; 77353541Sshin register struct inpcb *inp; 77453541Sshin register struct sockaddr_in6 *sin6; 77553541Sshin 77653541Sshin /* 77753541Sshin * Do the malloc first in case it blocks. 77853541Sshin */ 77953541Sshin MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_WAITOK); 78053541Sshin bzero(sin6, sizeof *sin6); 78153541Sshin sin6->sin6_family = AF_INET6; 78253541Sshin sin6->sin6_len = sizeof(*sin6); 78353541Sshin 78453541Sshin s = splnet(); 78553541Sshin inp = sotoinpcb(so); 78653541Sshin if (!inp) { 78753541Sshin splx(s); 78853541Sshin free(sin6, M_SONAME); 78953541Sshin return EINVAL; 79053541Sshin } 79153541Sshin sin6->sin6_port = inp->inp_lport; 79253541Sshin sin6->sin6_addr = inp->in6p_laddr; 79353541Sshin splx(s); 79453541Sshin if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) 79553541Sshin sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]); 79653541Sshin else 79753541Sshin sin6->sin6_scope_id = 0; /*XXX*/ 79853541Sshin if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) 79953541Sshin sin6->sin6_addr.s6_addr16[1] = 0; 80053541Sshin 80153541Sshin *nam = (struct sockaddr *)sin6; 80253541Sshin return 0; 80353541Sshin} 80453541Sshin 80553541Sshinint 80653541Sshinin6_setpeeraddr(so, nam) 80753541Sshin struct socket *so; 80853541Sshin struct sockaddr **nam; 80953541Sshin{ 81053541Sshin int s; 81153541Sshin struct inpcb *inp; 81253541Sshin register struct sockaddr_in6 *sin6; 81353541Sshin 81453541Sshin /* 81553541Sshin * Do the malloc first in case it blocks. 81653541Sshin */ 81753541Sshin MALLOC(sin6, struct sockaddr_in6 *, sizeof(*sin6), M_SONAME, M_WAITOK); 81853541Sshin bzero((caddr_t)sin6, sizeof (*sin6)); 81953541Sshin sin6->sin6_family = AF_INET6; 82053541Sshin sin6->sin6_len = sizeof(struct sockaddr_in6); 82153541Sshin 82253541Sshin s = splnet(); 82353541Sshin inp = sotoinpcb(so); 82453541Sshin if (!inp) { 82553541Sshin splx(s); 82653541Sshin free(sin6, M_SONAME); 82753541Sshin return EINVAL; 82853541Sshin } 82953541Sshin sin6->sin6_port = inp->inp_fport; 83053541Sshin sin6->sin6_addr = inp->in6p_faddr; 83153541Sshin splx(s); 83253541Sshin if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) 83353541Sshin sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]); 83453541Sshin else 83553541Sshin sin6->sin6_scope_id = 0; /*XXX*/ 83653541Sshin if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) 83753541Sshin sin6->sin6_addr.s6_addr16[1] = 0; 83853541Sshin 83953541Sshin *nam = (struct sockaddr *)sin6; 84053541Sshin return 0; 84153541Sshin} 84253541Sshin 84353541Sshinint 84453541Sshinin6_mapped_sockaddr(struct socket *so, struct sockaddr **nam) 84553541Sshin{ 84653541Sshin struct inpcb *inp = sotoinpcb(so); 84753541Sshin int error; 84853541Sshin 84953541Sshin if (inp == NULL) 85053541Sshin return EINVAL; 85153541Sshin if (inp->inp_vflag & INP_IPV4) { 85253541Sshin error = in_setsockaddr(so, nam); 85354952Seivind if (error == 0) 85453541Sshin in6_sin_2_v4mapsin6_in_sock(nam); 85553541Sshin } else 85653541Sshin error = in6_setsockaddr(so, nam); 85753541Sshin 85853541Sshin return error; 85953541Sshin} 86053541Sshin 86153541Sshinint 86253541Sshinin6_mapped_peeraddr(struct socket *so, struct sockaddr **nam) 86353541Sshin{ 86453541Sshin struct inpcb *inp = sotoinpcb(so); 86553541Sshin int error; 86653541Sshin 86753541Sshin if (inp == NULL) 86853541Sshin return EINVAL; 86953541Sshin if (inp->inp_vflag & INP_IPV4) { 87053541Sshin error = in_setpeeraddr(so, nam); 87154952Seivind if (error == 0) 87253541Sshin in6_sin_2_v4mapsin6_in_sock(nam); 87353541Sshin } else 87453541Sshin error = in6_setpeeraddr(so, nam); 87553541Sshin 87653541Sshin return error; 87753541Sshin} 87853541Sshin 87953541Sshin/* 88053541Sshin * Pass some notification to all connections of a protocol 88153541Sshin * associated with address dst. The local address and/or port numbers 88253541Sshin * may be specified to limit the search. The "usual action" will be 88353541Sshin * taken, depending on the ctlinput cmd. The caller must filter any 88453541Sshin * cmds that are uninteresting (e.g., no error in the map). 88553541Sshin * Call the protocol specific routine (if any) to report 88653541Sshin * any errors for each matching socket. 88753541Sshin * 88853541Sshin * Must be called at splnet. 88953541Sshin */ 89053541Sshinvoid 89153541Sshinin6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify) 89253541Sshin struct inpcbhead *head; 89353541Sshin struct sockaddr *dst; 89453541Sshin u_int fport_arg, lport_arg; 89553541Sshin struct in6_addr *laddr6; 89653541Sshin int cmd; 89753541Sshin void (*notify) __P((struct inpcb *, int)); 89853541Sshin{ 89953541Sshin struct inpcb *inp, *oinp; 90053541Sshin struct in6_addr faddr6; 90153541Sshin u_short fport = fport_arg, lport = lport_arg; 90253541Sshin int errno, s; 90353541Sshin 90453541Sshin if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6) 90553541Sshin return; 90653541Sshin faddr6 = ((struct sockaddr_in6 *)dst)->sin6_addr; 90753541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&faddr6)) 90853541Sshin return; 90953541Sshin 91053541Sshin /* 91153541Sshin * Redirects go to all references to the destination, 91253541Sshin * and use in_rtchange to invalidate the route cache. 91353541Sshin * Dead host indications: notify all references to the destination. 91453541Sshin * Otherwise, if we have knowledge of the local port and address, 91553541Sshin * deliver only to that socket. 91653541Sshin */ 91753541Sshin if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 91853541Sshin fport = 0; 91953541Sshin lport = 0; 92053541Sshin bzero((caddr_t)laddr6, sizeof(*laddr6)); 92153541Sshin if (cmd != PRC_HOSTDEAD) 92253541Sshin notify = in6_rtchange; 92353541Sshin } 92453541Sshin errno = inet6ctlerrmap[cmd]; 92553541Sshin s = splnet(); 92653541Sshin for (inp = LIST_FIRST(head); inp != NULL;) { 92754952Seivind if ((inp->inp_vflag & INP_IPV6) == 0) { 92853541Sshin inp = LIST_NEXT(inp, inp_list); 92953541Sshin continue; 93053541Sshin } 93153541Sshin if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &faddr6) || 93253541Sshin inp->inp_socket == 0 || 93353541Sshin (lport && inp->inp_lport != lport) || 93453541Sshin (!IN6_IS_ADDR_UNSPECIFIED(laddr6) && 93553541Sshin !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr6)) || 93653541Sshin (fport && inp->inp_fport != fport)) { 93753541Sshin inp = LIST_NEXT(inp, inp_list); 93853541Sshin continue; 93953541Sshin } 94053541Sshin oinp = inp; 94153541Sshin inp = LIST_NEXT(inp, inp_list); 94253541Sshin if (notify) 94353541Sshin (*notify)(oinp, errno); 94453541Sshin } 94553541Sshin splx(s); 94653541Sshin} 94753541Sshin 94853541Sshin/* 94953541Sshin * Lookup a PCB based on the local address and port. 95053541Sshin */ 95153541Sshinstruct inpcb * 95253541Sshinin6_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) 95353541Sshin struct inpcbinfo *pcbinfo; 95453541Sshin struct in6_addr *laddr; 95553541Sshin u_int lport_arg; 95653541Sshin int wild_okay; 95753541Sshin{ 95853541Sshin register struct inpcb *inp; 95953541Sshin int matchwild = 3, wildcard; 96053541Sshin u_short lport = lport_arg; 96153541Sshin 96253541Sshin if (!wild_okay) { 96353541Sshin struct inpcbhead *head; 96453541Sshin /* 96553541Sshin * Look for an unconnected (wildcard foreign addr) PCB that 96653541Sshin * matches the local address and port we're looking for. 96753541Sshin */ 96853541Sshin head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, 96953541Sshin pcbinfo->hashmask)]; 97053541Sshin LIST_FOREACH(inp, head, inp_hash) { 97154952Seivind if ((inp->inp_vflag & INP_IPV6) == 0) 97253541Sshin continue; 97353541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) && 97453541Sshin IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) && 97553541Sshin inp->inp_lport == lport) { 97653541Sshin /* 97753541Sshin * Found. 97853541Sshin */ 97953541Sshin return (inp); 98053541Sshin } 98153541Sshin } 98253541Sshin /* 98353541Sshin * Not found. 98453541Sshin */ 98553541Sshin return (NULL); 98653541Sshin } else { 98753541Sshin struct inpcbporthead *porthash; 98853541Sshin struct inpcbport *phd; 98953541Sshin struct inpcb *match = NULL; 99053541Sshin /* 99153541Sshin * Best fit PCB lookup. 99253541Sshin * 99353541Sshin * First see if this local port is in use by looking on the 99453541Sshin * port hash list. 99553541Sshin */ 99653541Sshin porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport, 99753541Sshin pcbinfo->porthashmask)]; 99853541Sshin LIST_FOREACH(phd, porthash, phd_hash) { 99953541Sshin if (phd->phd_port == lport) 100053541Sshin break; 100153541Sshin } 100253541Sshin if (phd != NULL) { 100353541Sshin /* 100453541Sshin * Port is in use by one or more PCBs. Look for best 100553541Sshin * fit. 100653541Sshin */ 100753541Sshin LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) { 100853541Sshin wildcard = 0; 100954952Seivind if ((inp->inp_vflag & INP_IPV6) == 0) 101053541Sshin continue; 101153541Sshin if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) 101253541Sshin wildcard++; 101353541Sshin if (!IN6_IS_ADDR_UNSPECIFIED( 101453541Sshin &inp->in6p_laddr)) { 101553541Sshin if (IN6_IS_ADDR_UNSPECIFIED(laddr)) 101653541Sshin wildcard++; 101753541Sshin else if (!IN6_ARE_ADDR_EQUAL( 101853541Sshin &inp->in6p_laddr, laddr)) 101953541Sshin continue; 102053541Sshin } else { 102153541Sshin if (!IN6_IS_ADDR_UNSPECIFIED(laddr)) 102253541Sshin wildcard++; 102353541Sshin } 102453541Sshin if (wildcard < matchwild) { 102553541Sshin match = inp; 102653541Sshin matchwild = wildcard; 102753541Sshin if (matchwild == 0) { 102853541Sshin break; 102953541Sshin } 103053541Sshin } 103153541Sshin } 103253541Sshin } 103353541Sshin return (match); 103453541Sshin } 103553541Sshin} 103653541Sshin 103753541Sshin/* 103853541Sshin * Check for alternatives when higher level complains 103953541Sshin * about service problems. For now, invalidate cached 104053541Sshin * routing information. If the route was created dynamically 104153541Sshin * (by a redirect), time to try a default gateway again. 104253541Sshin */ 104353541Sshinvoid 104453541Sshinin6_losing(in6p) 104553541Sshin struct inpcb *in6p; 104653541Sshin{ 104753541Sshin struct rtentry *rt; 104853541Sshin struct rt_addrinfo info; 104953541Sshin 105053541Sshin if ((rt = in6p->in6p_route.ro_rt) != NULL) { 105153541Sshin in6p->in6p_route.ro_rt = 0; 105253541Sshin bzero((caddr_t)&info, sizeof(info)); 105353541Sshin info.rti_info[RTAX_DST] = 105453541Sshin (struct sockaddr *)&in6p->in6p_route.ro_dst; 105553541Sshin info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 105653541Sshin info.rti_info[RTAX_NETMASK] = rt_mask(rt); 105753541Sshin rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 105853541Sshin if (rt->rt_flags & RTF_DYNAMIC) 105953541Sshin (void)rtrequest(RTM_DELETE, rt_key(rt), 106053541Sshin rt->rt_gateway, rt_mask(rt), rt->rt_flags, 106153541Sshin (struct rtentry **)0); 106253541Sshin else 106353541Sshin /* 106453541Sshin * A new route can be allocated 106553541Sshin * the next time output is attempted. 106653541Sshin */ 106753541Sshin rtfree(rt); 106853541Sshin } 106953541Sshin} 107053541Sshin 107153541Sshin/* 107253541Sshin * After a routing change, flush old routing 107353541Sshin * and allocate a (hopefully) better one. 107453541Sshin */ 107553541Sshinvoid 107653541Sshinin6_rtchange(inp, errno) 107753541Sshin struct inpcb *inp; 107853541Sshin int errno; 107953541Sshin{ 108053541Sshin if (inp->in6p_route.ro_rt) { 108153541Sshin rtfree(inp->in6p_route.ro_rt); 108253541Sshin inp->in6p_route.ro_rt = 0; 108353541Sshin /* 108453541Sshin * A new route can be allocated the next time 108553541Sshin * output is attempted. 108653541Sshin */ 108753541Sshin } 108853541Sshin} 108953541Sshin 109053541Sshin/* 109153541Sshin * Lookup PCB in hash list. 109253541Sshin */ 109353541Sshinstruct inpcb * 109453541Sshinin6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) 109553541Sshin struct inpcbinfo *pcbinfo; 109653541Sshin struct in6_addr *faddr, *laddr; 109753541Sshin u_int fport_arg, lport_arg; 109853541Sshin int wildcard; 109953541Sshin struct ifnet *ifp; 110053541Sshin{ 110153541Sshin struct inpcbhead *head; 110253541Sshin register struct inpcb *inp; 110353541Sshin u_short fport = fport_arg, lport = lport_arg; 110453541Sshin 110553541Sshin /* 110653541Sshin * First look for an exact match. 110753541Sshin */ 110853541Sshin head = &pcbinfo->hashbase[INP_PCBHASH(faddr->s6_addr32[3] /* XXX */, 110953541Sshin lport, fport, 111053541Sshin pcbinfo->hashmask)]; 111154263Sshin LIST_FOREACH(inp, head, inp_hash) { 111254952Seivind if ((inp->inp_vflag & INP_IPV6) == 0) 111353541Sshin continue; 111453541Sshin if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) && 111553541Sshin IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) && 111653541Sshin inp->inp_fport == fport && 111753541Sshin inp->inp_lport == lport) { 111853541Sshin /* 111953541Sshin * Found. 112053541Sshin */ 112153541Sshin return (inp); 112253541Sshin } 112353541Sshin } 112453541Sshin if (wildcard) { 112553541Sshin struct inpcb *local_wild = NULL; 112653541Sshin 112753541Sshin head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, 112853541Sshin pcbinfo->hashmask)]; 112954263Sshin LIST_FOREACH(inp, head, inp_hash) { 113054952Seivind if ((inp->inp_vflag & INP_IPV6) == 0) 113153541Sshin continue; 113253541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) && 113353541Sshin inp->inp_lport == lport) { 113453541Sshin#if defined(NFAITH) && NFAITH > 0 113553541Sshin if (ifp && ifp->if_type == IFT_FAITH && 113653541Sshin (inp->inp_flags & INP_FAITH) == 0) 113753541Sshin continue; 113853541Sshin#endif 113953541Sshin if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, 114053541Sshin laddr)) 114153541Sshin return (inp); 114253541Sshin else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) 114353541Sshin local_wild = inp; 114453541Sshin } 114553541Sshin } 114653541Sshin return (local_wild); 114753541Sshin } 114853541Sshin 114953541Sshin /* 115053541Sshin * Not found. 115153541Sshin */ 115253541Sshin return (NULL); 115353541Sshin} 115453541Sshin 115553541Sshinvoid 115653541Sshininit_sin6(struct sockaddr_in6 *sin6, struct mbuf *m) 115753541Sshin{ 115853541Sshin struct ip6_hdr *ip; 115953541Sshin 116053541Sshin ip = mtod(m, struct ip6_hdr *); 116153541Sshin bzero(sin6, sizeof(*sin6)); 116253541Sshin sin6->sin6_len = sizeof(*sin6); 116353541Sshin sin6->sin6_family = AF_INET6; 116453541Sshin sin6->sin6_addr = ip->ip6_src; 116553541Sshin if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) 116653541Sshin sin6->sin6_addr.s6_addr16[1] = 0; 116753541Sshin sin6->sin6_scope_id = 116853541Sshin (m->m_pkthdr.rcvif && IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) 116953541Sshin ? m->m_pkthdr.rcvif->if_index : 0; 117053541Sshin 117153541Sshin return; 117253541Sshin} 1173