1686cdd19SJun-ichiro itojun Hagino /* $FreeBSD$ */ 2686cdd19SJun-ichiro itojun Hagino /* $KAME: in6.c,v 1.87 2000/07/03 15:44:21 itojun Exp $ */ 3686cdd19SJun-ichiro itojun Hagino 482cd038dSYoshinobu Inoue /* 582cd038dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 682cd038dSYoshinobu Inoue * All rights reserved. 782cd038dSYoshinobu Inoue * 882cd038dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 982cd038dSYoshinobu Inoue * modification, are permitted provided that the following conditions 1082cd038dSYoshinobu Inoue * are met: 1182cd038dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 1282cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1382cd038dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1482cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1582cd038dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1682cd038dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1782cd038dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 1882cd038dSYoshinobu Inoue * without specific prior written permission. 1982cd038dSYoshinobu Inoue * 2082cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2182cd038dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2282cd038dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2382cd038dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2482cd038dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2582cd038dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2682cd038dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2782cd038dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2882cd038dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2982cd038dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3082cd038dSYoshinobu Inoue * SUCH DAMAGE. 3182cd038dSYoshinobu Inoue */ 3282cd038dSYoshinobu Inoue 3382cd038dSYoshinobu Inoue /* 3482cd038dSYoshinobu Inoue * Copyright (c) 1982, 1986, 1991, 1993 3582cd038dSYoshinobu Inoue * The Regents of the University of California. All rights reserved. 3682cd038dSYoshinobu Inoue * 3782cd038dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 3882cd038dSYoshinobu Inoue * modification, are permitted provided that the following conditions 3982cd038dSYoshinobu Inoue * are met: 4082cd038dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 4182cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 4282cd038dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 4382cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 4482cd038dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 4582cd038dSYoshinobu Inoue * 3. All advertising materials mentioning features or use of this software 4682cd038dSYoshinobu Inoue * must display the following acknowledgement: 4782cd038dSYoshinobu Inoue * This product includes software developed by the University of 4882cd038dSYoshinobu Inoue * California, Berkeley and its contributors. 4982cd038dSYoshinobu Inoue * 4. Neither the name of the University nor the names of its contributors 5082cd038dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 5182cd038dSYoshinobu Inoue * without specific prior written permission. 5282cd038dSYoshinobu Inoue * 5382cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5482cd038dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5582cd038dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5682cd038dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5782cd038dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5882cd038dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5982cd038dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6082cd038dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6182cd038dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6282cd038dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6382cd038dSYoshinobu Inoue * SUCH DAMAGE. 6482cd038dSYoshinobu Inoue * 6582cd038dSYoshinobu Inoue * @(#)in.c 8.2 (Berkeley) 11/15/93 6682cd038dSYoshinobu Inoue */ 6782cd038dSYoshinobu Inoue 68686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h" 69686cdd19SJun-ichiro itojun Hagino #include "opt_inet6.h" 70686cdd19SJun-ichiro itojun Hagino 7182cd038dSYoshinobu Inoue #include <sys/param.h> 7282cd038dSYoshinobu Inoue #include <sys/errno.h> 7382cd038dSYoshinobu Inoue #include <sys/malloc.h> 7482cd038dSYoshinobu Inoue #include <sys/socket.h> 7582cd038dSYoshinobu Inoue #include <sys/socketvar.h> 7682cd038dSYoshinobu Inoue #include <sys/sockio.h> 7782cd038dSYoshinobu Inoue #include <sys/systm.h> 7882cd038dSYoshinobu Inoue #include <sys/proc.h> 7982cd038dSYoshinobu Inoue #include <sys/time.h> 8082cd038dSYoshinobu Inoue #include <sys/kernel.h> 8182cd038dSYoshinobu Inoue #include <sys/syslog.h> 8282cd038dSYoshinobu Inoue 8382cd038dSYoshinobu Inoue #include <net/if.h> 8482cd038dSYoshinobu Inoue #include <net/if_types.h> 8582cd038dSYoshinobu Inoue #include <net/route.h> 8682cd038dSYoshinobu Inoue #include <net/if_dl.h> 8782cd038dSYoshinobu Inoue 8882cd038dSYoshinobu Inoue #include <netinet/in.h> 8982cd038dSYoshinobu Inoue #include <netinet/in_var.h> 9082cd038dSYoshinobu Inoue #include <netinet/if_ether.h> 9182cd038dSYoshinobu Inoue 9282cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 93686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h> 9482cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h> 9582cd038dSYoshinobu Inoue #include <netinet6/mld6_var.h> 96686cdd19SJun-ichiro itojun Hagino #include <netinet6/ip6_mroute.h> 9782cd038dSYoshinobu Inoue #include <netinet6/in6_ifattach.h> 98686cdd19SJun-ichiro itojun Hagino #include <netinet6/scope6_var.h> 99686cdd19SJun-ichiro itojun Hagino 100686cdd19SJun-ichiro itojun Hagino #include "gif.h" 101cfa1ca9dSYoshinobu Inoue #if NGIF > 0 102cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h> 103cfa1ca9dSYoshinobu Inoue #endif 10482cd038dSYoshinobu Inoue 10582cd038dSYoshinobu Inoue #include <net/net_osdep.h> 10682cd038dSYoshinobu Inoue 10782cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IPMADDR, "in6_multi", "internet multicast address"); 10882cd038dSYoshinobu Inoue 10982cd038dSYoshinobu Inoue /* 11082cd038dSYoshinobu Inoue * Definitions of some costant IP6 addresses. 11182cd038dSYoshinobu Inoue */ 11282cd038dSYoshinobu Inoue const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 11382cd038dSYoshinobu Inoue const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 11482cd038dSYoshinobu Inoue const struct in6_addr in6addr_nodelocal_allnodes = 11582cd038dSYoshinobu Inoue IN6ADDR_NODELOCAL_ALLNODES_INIT; 11682cd038dSYoshinobu Inoue const struct in6_addr in6addr_linklocal_allnodes = 11782cd038dSYoshinobu Inoue IN6ADDR_LINKLOCAL_ALLNODES_INIT; 11882cd038dSYoshinobu Inoue const struct in6_addr in6addr_linklocal_allrouters = 11982cd038dSYoshinobu Inoue IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; 12082cd038dSYoshinobu Inoue 12182cd038dSYoshinobu Inoue const struct in6_addr in6mask0 = IN6MASK0; 12282cd038dSYoshinobu Inoue const struct in6_addr in6mask32 = IN6MASK32; 12382cd038dSYoshinobu Inoue const struct in6_addr in6mask64 = IN6MASK64; 12482cd038dSYoshinobu Inoue const struct in6_addr in6mask96 = IN6MASK96; 12582cd038dSYoshinobu Inoue const struct in6_addr in6mask128 = IN6MASK128; 12682cd038dSYoshinobu Inoue 12782cd038dSYoshinobu Inoue static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, 12882cd038dSYoshinobu Inoue struct ifnet *, struct proc *)); 12982cd038dSYoshinobu Inoue 130686cdd19SJun-ichiro itojun Hagino struct in6_multihead in6_multihead; /* XXX BSS initialization */ 13182cd038dSYoshinobu Inoue 13282cd038dSYoshinobu Inoue /* 13382cd038dSYoshinobu Inoue * Check if the loopback entry will be automatically generated. 13482cd038dSYoshinobu Inoue * if 0 returned, will not be automatically generated. 13582cd038dSYoshinobu Inoue * if 1 returned, will be automatically generated. 13682cd038dSYoshinobu Inoue */ 13782cd038dSYoshinobu Inoue static int 13882cd038dSYoshinobu Inoue in6_is_ifloop_auto(struct ifaddr *ifa) 13982cd038dSYoshinobu Inoue { 14082cd038dSYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)s) 14182cd038dSYoshinobu Inoue /* 14282cd038dSYoshinobu Inoue * If RTF_CLONING is unset, or (IFF_LOOPBACK | IFF_POINTOPOINT), 14382cd038dSYoshinobu Inoue * or netmask is all0 or all1, then cloning will not happen, 14482cd038dSYoshinobu Inoue * then we can't rely on its loopback entry generation. 14582cd038dSYoshinobu Inoue */ 14682cd038dSYoshinobu Inoue if ((ifa->ifa_flags & RTF_CLONING) == 0 || 14782cd038dSYoshinobu Inoue (ifa->ifa_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) || 14882cd038dSYoshinobu Inoue (SIN6(ifa->ifa_netmask)->sin6_len == sizeof(struct sockaddr_in6) 14982cd038dSYoshinobu Inoue && 15082cd038dSYoshinobu Inoue IN6_ARE_ADDR_EQUAL(&SIN6(ifa->ifa_netmask)->sin6_addr, 15182cd038dSYoshinobu Inoue &in6mask128)) || 15282cd038dSYoshinobu Inoue ((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_len == 0) 15382cd038dSYoshinobu Inoue return 0; 15482cd038dSYoshinobu Inoue else 15582cd038dSYoshinobu Inoue return 1; 15682cd038dSYoshinobu Inoue #undef SIN6 15782cd038dSYoshinobu Inoue } 15882cd038dSYoshinobu Inoue 15982cd038dSYoshinobu Inoue /* 16082cd038dSYoshinobu Inoue * Subroutine for in6_ifaddloop() and in6_ifremloop(). 16182cd038dSYoshinobu Inoue * This routine does actual work. 16282cd038dSYoshinobu Inoue */ 16382cd038dSYoshinobu Inoue static void 16482cd038dSYoshinobu Inoue in6_ifloop_request(int cmd, struct ifaddr *ifa) 16582cd038dSYoshinobu Inoue { 16682cd038dSYoshinobu Inoue struct sockaddr_in6 lo_sa; 16782cd038dSYoshinobu Inoue struct sockaddr_in6 all1_sa; 16882cd038dSYoshinobu Inoue struct rtentry *nrt = NULL; 16982cd038dSYoshinobu Inoue 17082cd038dSYoshinobu Inoue bzero(&lo_sa, sizeof(lo_sa)); 17182cd038dSYoshinobu Inoue bzero(&all1_sa, sizeof(all1_sa)); 17282cd038dSYoshinobu Inoue lo_sa.sin6_family = AF_INET6; 17382cd038dSYoshinobu Inoue lo_sa.sin6_len = sizeof(struct sockaddr_in6); 17482cd038dSYoshinobu Inoue all1_sa = lo_sa; 17582cd038dSYoshinobu Inoue lo_sa.sin6_addr = in6addr_loopback; 17682cd038dSYoshinobu Inoue all1_sa.sin6_addr = in6mask128; 17782cd038dSYoshinobu Inoue 178686cdd19SJun-ichiro itojun Hagino /* 179686cdd19SJun-ichiro itojun Hagino * So we add or remove static loopback entry, here. 180686cdd19SJun-ichiro itojun Hagino * This request for deletion could fail, e.g. when we remove 181686cdd19SJun-ichiro itojun Hagino * an address right after adding it. 182686cdd19SJun-ichiro itojun Hagino */ 18382cd038dSYoshinobu Inoue rtrequest(cmd, ifa->ifa_addr, 18482cd038dSYoshinobu Inoue (struct sockaddr *)&lo_sa, 18582cd038dSYoshinobu Inoue (struct sockaddr *)&all1_sa, 18682cd038dSYoshinobu Inoue RTF_UP|RTF_HOST, &nrt); 18782cd038dSYoshinobu Inoue 18882cd038dSYoshinobu Inoue /* 18982cd038dSYoshinobu Inoue * Make sure rt_ifa be equal to IFA, the second argument of the 19082cd038dSYoshinobu Inoue * function. 19182cd038dSYoshinobu Inoue * We need this because when we refer rt_ifa->ia6_flags in ip6_input, 19282cd038dSYoshinobu Inoue * we assume that the rt_ifa points to the address instead of the 19382cd038dSYoshinobu Inoue * loopback address. 19482cd038dSYoshinobu Inoue */ 19582cd038dSYoshinobu Inoue if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) { 196686cdd19SJun-ichiro itojun Hagino IFAFREE(nrt->rt_ifa); 19782cd038dSYoshinobu Inoue ifa->ifa_refcnt++; 19882cd038dSYoshinobu Inoue nrt->rt_ifa = ifa; 19982cd038dSYoshinobu Inoue } 20082cd038dSYoshinobu Inoue if (nrt) 20182cd038dSYoshinobu Inoue nrt->rt_refcnt--; 20282cd038dSYoshinobu Inoue } 20382cd038dSYoshinobu Inoue 20482cd038dSYoshinobu Inoue /* 20582cd038dSYoshinobu Inoue * Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). 20682cd038dSYoshinobu Inoue * Because, KAME needs loopback rtentry for ownaddr check in 20782cd038dSYoshinobu Inoue * ip6_input(). 20882cd038dSYoshinobu Inoue */ 20982cd038dSYoshinobu Inoue static void 21082cd038dSYoshinobu Inoue in6_ifaddloop(struct ifaddr *ifa) 21182cd038dSYoshinobu Inoue { 21282cd038dSYoshinobu Inoue if (!in6_is_ifloop_auto(ifa)) { 21382cd038dSYoshinobu Inoue struct rtentry *rt; 21482cd038dSYoshinobu Inoue 21582cd038dSYoshinobu Inoue /* If there is no loopback entry, allocate one. */ 21682cd038dSYoshinobu Inoue rt = rtalloc1(ifa->ifa_addr, 0, 0); 21782cd038dSYoshinobu Inoue if (rt == 0 || (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) 21882cd038dSYoshinobu Inoue in6_ifloop_request(RTM_ADD, ifa); 21982cd038dSYoshinobu Inoue if (rt) 22082cd038dSYoshinobu Inoue rt->rt_refcnt--; 22182cd038dSYoshinobu Inoue } 22282cd038dSYoshinobu Inoue } 22382cd038dSYoshinobu Inoue 22482cd038dSYoshinobu Inoue /* 22582cd038dSYoshinobu Inoue * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(), 22682cd038dSYoshinobu Inoue * if it exists. 22782cd038dSYoshinobu Inoue */ 22882cd038dSYoshinobu Inoue static void 22982cd038dSYoshinobu Inoue in6_ifremloop(struct ifaddr *ifa) 23082cd038dSYoshinobu Inoue { 23182cd038dSYoshinobu Inoue struct in6_ifaddr *ia; 23282cd038dSYoshinobu Inoue int ia_count = 0; 23382cd038dSYoshinobu Inoue 234686cdd19SJun-ichiro itojun Hagino /* 235686cdd19SJun-ichiro itojun Hagino * All BSD variants except BSD/OS do not remove cloned routes 236686cdd19SJun-ichiro itojun Hagino * from an interface direct route, when removing the direct route 237686cdd19SJun-ichiro itojun Hagino * (see commens in net/net_osdep.h). 238686cdd19SJun-ichiro itojun Hagino * So we should remove the route corresponding to the deleted address 239686cdd19SJun-ichiro itojun Hagino * regardless of the result of in6_is_ifloop_auto(). 240686cdd19SJun-ichiro itojun Hagino */ 241686cdd19SJun-ichiro itojun Hagino if (1) 242686cdd19SJun-ichiro itojun Hagino { 24382cd038dSYoshinobu Inoue /* If only one ifa for the loopback entry, delete it. */ 24482cd038dSYoshinobu Inoue for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 24582cd038dSYoshinobu Inoue if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), 24682cd038dSYoshinobu Inoue &ia->ia_addr.sin6_addr)) { 24782cd038dSYoshinobu Inoue ia_count++; 24882cd038dSYoshinobu Inoue if (ia_count > 1) 24982cd038dSYoshinobu Inoue break; 25082cd038dSYoshinobu Inoue } 25182cd038dSYoshinobu Inoue } 25282cd038dSYoshinobu Inoue if (ia_count == 1) 25382cd038dSYoshinobu Inoue in6_ifloop_request(RTM_DELETE, ifa); 25482cd038dSYoshinobu Inoue } 25582cd038dSYoshinobu Inoue } 25682cd038dSYoshinobu Inoue 25782cd038dSYoshinobu Inoue int 25882cd038dSYoshinobu Inoue in6_ifindex2scopeid(idx) 25982cd038dSYoshinobu Inoue int idx; 26082cd038dSYoshinobu Inoue { 26182cd038dSYoshinobu Inoue struct ifnet *ifp; 26282cd038dSYoshinobu Inoue struct ifaddr *ifa; 26382cd038dSYoshinobu Inoue struct sockaddr_in6 *sin6; 26482cd038dSYoshinobu Inoue 26582cd038dSYoshinobu Inoue if (idx < 0 || if_index < idx) 26682cd038dSYoshinobu Inoue return -1; 26782cd038dSYoshinobu Inoue ifp = ifindex2ifnet[idx]; 26882cd038dSYoshinobu Inoue 269cfa1ca9dSYoshinobu Inoue TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 27082cd038dSYoshinobu Inoue { 27182cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6) 27282cd038dSYoshinobu Inoue continue; 27382cd038dSYoshinobu Inoue sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 27482cd038dSYoshinobu Inoue if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) 27582cd038dSYoshinobu Inoue return sin6->sin6_scope_id & 0xffff; 27682cd038dSYoshinobu Inoue } 27782cd038dSYoshinobu Inoue 27882cd038dSYoshinobu Inoue return -1; 27982cd038dSYoshinobu Inoue } 28082cd038dSYoshinobu Inoue 28182cd038dSYoshinobu Inoue int 28282cd038dSYoshinobu Inoue in6_mask2len(mask) 28382cd038dSYoshinobu Inoue struct in6_addr *mask; 28482cd038dSYoshinobu Inoue { 28582cd038dSYoshinobu Inoue int x, y; 28682cd038dSYoshinobu Inoue 28782cd038dSYoshinobu Inoue for (x = 0; x < sizeof(*mask); x++) { 28882cd038dSYoshinobu Inoue if (mask->s6_addr8[x] != 0xff) 28982cd038dSYoshinobu Inoue break; 29082cd038dSYoshinobu Inoue } 29182cd038dSYoshinobu Inoue y = 0; 29282cd038dSYoshinobu Inoue if (x < sizeof(*mask)) { 29382cd038dSYoshinobu Inoue for (y = 0; y < 8; y++) { 29482cd038dSYoshinobu Inoue if ((mask->s6_addr8[x] & (0x80 >> y)) == 0) 29582cd038dSYoshinobu Inoue break; 29682cd038dSYoshinobu Inoue } 29782cd038dSYoshinobu Inoue } 29882cd038dSYoshinobu Inoue return x * 8 + y; 29982cd038dSYoshinobu Inoue } 30082cd038dSYoshinobu Inoue 30182cd038dSYoshinobu Inoue void 30282cd038dSYoshinobu Inoue in6_len2mask(mask, len) 30382cd038dSYoshinobu Inoue struct in6_addr *mask; 30482cd038dSYoshinobu Inoue int len; 30582cd038dSYoshinobu Inoue { 30682cd038dSYoshinobu Inoue int i; 30782cd038dSYoshinobu Inoue 30882cd038dSYoshinobu Inoue bzero(mask, sizeof(*mask)); 30982cd038dSYoshinobu Inoue for (i = 0; i < len / 8; i++) 31082cd038dSYoshinobu Inoue mask->s6_addr8[i] = 0xff; 31182cd038dSYoshinobu Inoue if (len % 8) 31282cd038dSYoshinobu Inoue mask->s6_addr8[i] = (0xff00 >> (len % 8)) & 0xff; 31382cd038dSYoshinobu Inoue } 31482cd038dSYoshinobu Inoue 31582cd038dSYoshinobu Inoue #define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) 316686cdd19SJun-ichiro itojun Hagino #define ia62ifa(ia6) (&((ia6)->ia_ifa)) 31782cd038dSYoshinobu Inoue 31882cd038dSYoshinobu Inoue int 31982cd038dSYoshinobu Inoue in6_control(so, cmd, data, ifp, p) 32082cd038dSYoshinobu Inoue struct socket *so; 32182cd038dSYoshinobu Inoue u_long cmd; 32282cd038dSYoshinobu Inoue caddr_t data; 32382cd038dSYoshinobu Inoue struct ifnet *ifp; 32482cd038dSYoshinobu Inoue struct proc *p; 32582cd038dSYoshinobu Inoue { 32682cd038dSYoshinobu Inoue struct in6_ifreq *ifr = (struct in6_ifreq *)data; 327686cdd19SJun-ichiro itojun Hagino struct in6_ifaddr *ia = NULL, *oia; 32882cd038dSYoshinobu Inoue struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; 329686cdd19SJun-ichiro itojun Hagino struct sockaddr_in6 oldaddr; 330686cdd19SJun-ichiro itojun Hagino #ifdef COMPAT_IN6IFIOCTL 331686cdd19SJun-ichiro itojun Hagino struct sockaddr_in6 net; 332686cdd19SJun-ichiro itojun Hagino #endif 33382cd038dSYoshinobu Inoue int error = 0, hostIsNew, prefixIsNew; 334686cdd19SJun-ichiro itojun Hagino int newifaddr; 33582cd038dSYoshinobu Inoue int privileged; 33682cd038dSYoshinobu Inoue 33782cd038dSYoshinobu Inoue privileged = 0; 3389d786e66SYoshinobu Inoue if (p == NULL || !suser(p)) 33982cd038dSYoshinobu Inoue privileged++; 34082cd038dSYoshinobu Inoue 34182cd038dSYoshinobu Inoue /* 34282cd038dSYoshinobu Inoue * xxx should prevent processes for link-local addresses? 34382cd038dSYoshinobu Inoue */ 34482cd038dSYoshinobu Inoue #if NGIF > 0 34582cd038dSYoshinobu Inoue if (ifp && ifp->if_type == IFT_GIF) { 34682cd038dSYoshinobu Inoue switch (cmd) { 34782cd038dSYoshinobu Inoue case SIOCSIFPHYADDR_IN6: 34882cd038dSYoshinobu Inoue if (!privileged) 34982cd038dSYoshinobu Inoue return(EPERM); 35082cd038dSYoshinobu Inoue /*fall through*/ 35182cd038dSYoshinobu Inoue case SIOCGIFPSRCADDR_IN6: 35282cd038dSYoshinobu Inoue case SIOCGIFPDSTADDR_IN6: 35382cd038dSYoshinobu Inoue return gif_ioctl(ifp, cmd, data); 35482cd038dSYoshinobu Inoue } 35582cd038dSYoshinobu Inoue } 35682cd038dSYoshinobu Inoue #endif 357686cdd19SJun-ichiro itojun Hagino switch (cmd) { 358686cdd19SJun-ichiro itojun Hagino case SIOCGETSGCNT_IN6: 359686cdd19SJun-ichiro itojun Hagino case SIOCGETMIFCNT_IN6: 360686cdd19SJun-ichiro itojun Hagino return (mrt6_ioctl(cmd, data)); 361686cdd19SJun-ichiro itojun Hagino } 36282cd038dSYoshinobu Inoue 363686cdd19SJun-ichiro itojun Hagino if (ifp == NULL) 36482cd038dSYoshinobu Inoue return(EOPNOTSUPP); 36582cd038dSYoshinobu Inoue 36682cd038dSYoshinobu Inoue switch (cmd) { 36782cd038dSYoshinobu Inoue case SIOCSNDFLUSH_IN6: 36882cd038dSYoshinobu Inoue case SIOCSPFXFLUSH_IN6: 36982cd038dSYoshinobu Inoue case SIOCSRTRFLUSH_IN6: 370686cdd19SJun-ichiro itojun Hagino case SIOCSDEFIFACE_IN6: 371686cdd19SJun-ichiro itojun Hagino case SIOCSIFINFO_FLAGS: 37282cd038dSYoshinobu Inoue if (!privileged) 37382cd038dSYoshinobu Inoue return(EPERM); 37482cd038dSYoshinobu Inoue /*fall through*/ 37582cd038dSYoshinobu Inoue case SIOCGIFINFO_IN6: 37682cd038dSYoshinobu Inoue case SIOCGDRLST_IN6: 37782cd038dSYoshinobu Inoue case SIOCGPRLST_IN6: 37882cd038dSYoshinobu Inoue case SIOCGNBRINFO_IN6: 379686cdd19SJun-ichiro itojun Hagino case SIOCGDEFIFACE_IN6: 38082cd038dSYoshinobu Inoue return(nd6_ioctl(cmd, data, ifp)); 38182cd038dSYoshinobu Inoue } 38282cd038dSYoshinobu Inoue 38382cd038dSYoshinobu Inoue switch (cmd) { 38482cd038dSYoshinobu Inoue case SIOCSIFPREFIX_IN6: 38582cd038dSYoshinobu Inoue case SIOCDIFPREFIX_IN6: 38682cd038dSYoshinobu Inoue case SIOCAIFPREFIX_IN6: 38782cd038dSYoshinobu Inoue case SIOCCIFPREFIX_IN6: 38882cd038dSYoshinobu Inoue case SIOCSGIFPREFIX_IN6: 38982cd038dSYoshinobu Inoue if (!privileged) 39082cd038dSYoshinobu Inoue return(EPERM); 39182cd038dSYoshinobu Inoue /*fall through*/ 39282cd038dSYoshinobu Inoue case SIOCGIFPREFIX_IN6: 3939c275a58SYoshinobu Inoue if (ip6_forwarding == 0) 3949c275a58SYoshinobu Inoue return(EPERM); 39582cd038dSYoshinobu Inoue return(in6_prefix_ioctl(so, cmd, data, ifp)); 39682cd038dSYoshinobu Inoue } 39782cd038dSYoshinobu Inoue 39882cd038dSYoshinobu Inoue switch(cmd) { 399686cdd19SJun-ichiro itojun Hagino case SIOCSSCOPE6: 400686cdd19SJun-ichiro itojun Hagino if (!privileged) 401686cdd19SJun-ichiro itojun Hagino return(EPERM); 402686cdd19SJun-ichiro itojun Hagino return(scope6_set(ifp, ifr->ifr_ifru.ifru_scope_id)); 403686cdd19SJun-ichiro itojun Hagino break; 404686cdd19SJun-ichiro itojun Hagino case SIOCGSCOPE6: 405686cdd19SJun-ichiro itojun Hagino return(scope6_get(ifp, ifr->ifr_ifru.ifru_scope_id)); 406686cdd19SJun-ichiro itojun Hagino break; 407686cdd19SJun-ichiro itojun Hagino case SIOCGSCOPE6DEF: 408686cdd19SJun-ichiro itojun Hagino return(scope6_get_default(ifr->ifr_ifru.ifru_scope_id)); 409686cdd19SJun-ichiro itojun Hagino break; 410686cdd19SJun-ichiro itojun Hagino } 411686cdd19SJun-ichiro itojun Hagino 412686cdd19SJun-ichiro itojun Hagino switch (cmd) { 41382cd038dSYoshinobu Inoue case SIOCALIFADDR: 41482cd038dSYoshinobu Inoue case SIOCDLIFADDR: 41582cd038dSYoshinobu Inoue if (!privileged) 41682cd038dSYoshinobu Inoue return(EPERM); 41782cd038dSYoshinobu Inoue /*fall through*/ 41882cd038dSYoshinobu Inoue case SIOCGLIFADDR: 41982cd038dSYoshinobu Inoue return in6_lifaddr_ioctl(so, cmd, data, ifp, p); 42082cd038dSYoshinobu Inoue } 42182cd038dSYoshinobu Inoue 42282cd038dSYoshinobu Inoue /* 42382cd038dSYoshinobu Inoue * Find address for this interface, if it exists. 42482cd038dSYoshinobu Inoue */ 425686cdd19SJun-ichiro itojun Hagino if (ifra->ifra_addr.sin6_family == AF_INET6) { /* XXX */ 42682cd038dSYoshinobu Inoue struct sockaddr_in6 *sa6 = 42782cd038dSYoshinobu Inoue (struct sockaddr_in6 *)&ifra->ifra_addr; 42882cd038dSYoshinobu Inoue 42982cd038dSYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { 43082cd038dSYoshinobu Inoue if (sa6->sin6_addr.s6_addr16[1] == 0) { 43182cd038dSYoshinobu Inoue /* interface ID is not embedded by the user */ 43282cd038dSYoshinobu Inoue sa6->sin6_addr.s6_addr16[1] = 43382cd038dSYoshinobu Inoue htons(ifp->if_index); 434686cdd19SJun-ichiro itojun Hagino } else if (sa6->sin6_addr.s6_addr16[1] != 435686cdd19SJun-ichiro itojun Hagino htons(ifp->if_index)) { 43682cd038dSYoshinobu Inoue return(EINVAL); /* ifid is contradict */ 437686cdd19SJun-ichiro itojun Hagino } 43882cd038dSYoshinobu Inoue if (sa6->sin6_scope_id) { 43982cd038dSYoshinobu Inoue if (sa6->sin6_scope_id != 44082cd038dSYoshinobu Inoue (u_int32_t)ifp->if_index) 44182cd038dSYoshinobu Inoue return(EINVAL); 44282cd038dSYoshinobu Inoue sa6->sin6_scope_id = 0; /* XXX: good way? */ 44382cd038dSYoshinobu Inoue } 44482cd038dSYoshinobu Inoue } 44582cd038dSYoshinobu Inoue ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr); 446686cdd19SJun-ichiro itojun Hagino } 44782cd038dSYoshinobu Inoue 44882cd038dSYoshinobu Inoue switch (cmd) { 44982cd038dSYoshinobu Inoue 45082cd038dSYoshinobu Inoue case SIOCDIFADDR_IN6: 451686cdd19SJun-ichiro itojun Hagino /* 452686cdd19SJun-ichiro itojun Hagino * for IPv4, we look for existing in6_ifaddr here to allow 453686cdd19SJun-ichiro itojun Hagino * "ifconfig if0 delete" to remove first IPv4 address on the 454686cdd19SJun-ichiro itojun Hagino * interface. For IPv6, as the spec allow multiple interface 455686cdd19SJun-ichiro itojun Hagino * address from the day one, we consider "remove the first one" 456686cdd19SJun-ichiro itojun Hagino * semantics to be not preferrable. 457686cdd19SJun-ichiro itojun Hagino */ 458686cdd19SJun-ichiro itojun Hagino if (ia == NULL) 45982cd038dSYoshinobu Inoue return(EADDRNOTAVAIL); 46082cd038dSYoshinobu Inoue /* FALLTHROUGH */ 46182cd038dSYoshinobu Inoue case SIOCAIFADDR_IN6: 46282cd038dSYoshinobu Inoue case SIOCSIFADDR_IN6: 463686cdd19SJun-ichiro itojun Hagino #ifdef COMPAT_IN6IFIOCTL 46482cd038dSYoshinobu Inoue case SIOCSIFDSTADDR_IN6: 465686cdd19SJun-ichiro itojun Hagino case SIOCSIFNETMASK_IN6: 466686cdd19SJun-ichiro itojun Hagino /* 467686cdd19SJun-ichiro itojun Hagino * Since IPv6 allows a node to assign multiple addresses 468686cdd19SJun-ichiro itojun Hagino * on a single interface, SIOCSIFxxx ioctls are not suitable 469686cdd19SJun-ichiro itojun Hagino * and should be unused. 470686cdd19SJun-ichiro itojun Hagino */ 471686cdd19SJun-ichiro itojun Hagino #endif 472686cdd19SJun-ichiro itojun Hagino if (ifra->ifra_addr.sin6_family != AF_INET6) 473686cdd19SJun-ichiro itojun Hagino return(EAFNOSUPPORT); 47482cd038dSYoshinobu Inoue if (!privileged) 47582cd038dSYoshinobu Inoue return(EPERM); 476686cdd19SJun-ichiro itojun Hagino if (ia == NULL) { 47782cd038dSYoshinobu Inoue ia = (struct in6_ifaddr *) 47882cd038dSYoshinobu Inoue malloc(sizeof(*ia), M_IFADDR, M_WAITOK); 47982cd038dSYoshinobu Inoue if (ia == NULL) 48082cd038dSYoshinobu Inoue return (ENOBUFS); 48182cd038dSYoshinobu Inoue bzero((caddr_t)ia, sizeof(*ia)); 482686cdd19SJun-ichiro itojun Hagino /* Initialize the address and masks */ 48382cd038dSYoshinobu Inoue ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 484686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_family = AF_INET6; 485686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_len = sizeof(ia->ia_addr); 486686cdd19SJun-ichiro itojun Hagino #if 1 487686cdd19SJun-ichiro itojun Hagino if (ifp->if_flags & IFF_POINTOPOINT) { 48882cd038dSYoshinobu Inoue ia->ia_ifa.ifa_dstaddr 48982cd038dSYoshinobu Inoue = (struct sockaddr *)&ia->ia_dstaddr; 490686cdd19SJun-ichiro itojun Hagino ia->ia_dstaddr.sin6_family = AF_INET6; 491686cdd19SJun-ichiro itojun Hagino ia->ia_dstaddr.sin6_len = sizeof(ia->ia_dstaddr); 492686cdd19SJun-ichiro itojun Hagino } else { 493686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_dstaddr = NULL; 494686cdd19SJun-ichiro itojun Hagino bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr)); 495686cdd19SJun-ichiro itojun Hagino } 496686cdd19SJun-ichiro itojun Hagino #else /* always initilize by NULL */ 497686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_dstaddr = NULL; 498686cdd19SJun-ichiro itojun Hagino bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr)); 499686cdd19SJun-ichiro itojun Hagino #endif 50082cd038dSYoshinobu Inoue ia->ia_ifa.ifa_netmask 50182cd038dSYoshinobu Inoue = (struct sockaddr *)&ia->ia_prefixmask; 50282cd038dSYoshinobu Inoue 50382cd038dSYoshinobu Inoue ia->ia_ifp = ifp; 50482cd038dSYoshinobu Inoue if ((oia = in6_ifaddr) != NULL) { 50582cd038dSYoshinobu Inoue for ( ; oia->ia_next; oia = oia->ia_next) 50682cd038dSYoshinobu Inoue continue; 50782cd038dSYoshinobu Inoue oia->ia_next = ia; 50882cd038dSYoshinobu Inoue } else 50982cd038dSYoshinobu Inoue in6_ifaddr = ia; 510686cdd19SJun-ichiro itojun Hagino /* gain a refcnt for the link from in6_ifaddr */ 511686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_refcnt++; 512686cdd19SJun-ichiro itojun Hagino 513686cdd19SJun-ichiro itojun Hagino TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, 514686cdd19SJun-ichiro itojun Hagino ifa_list); 515686cdd19SJun-ichiro itojun Hagino /* gain another refcnt for the link from if_addrlist */ 516686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_refcnt++; 517686cdd19SJun-ichiro itojun Hagino 518686cdd19SJun-ichiro itojun Hagino newifaddr = 1; 519686cdd19SJun-ichiro itojun Hagino } else 520686cdd19SJun-ichiro itojun Hagino newifaddr = 0; 52182cd038dSYoshinobu Inoue 52282cd038dSYoshinobu Inoue if (cmd == SIOCAIFADDR_IN6) { 52382cd038dSYoshinobu Inoue /* sanity for overflow - beware unsigned */ 52482cd038dSYoshinobu Inoue struct in6_addrlifetime *lt; 52582cd038dSYoshinobu Inoue lt = &ifra->ifra_lifetime; 52682cd038dSYoshinobu Inoue if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME 52782cd038dSYoshinobu Inoue && lt->ia6t_vltime + time_second < time_second) { 52882cd038dSYoshinobu Inoue return EINVAL; 52982cd038dSYoshinobu Inoue } 53082cd038dSYoshinobu Inoue if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME 53182cd038dSYoshinobu Inoue && lt->ia6t_pltime + time_second < time_second) { 53282cd038dSYoshinobu Inoue return EINVAL; 53382cd038dSYoshinobu Inoue } 53482cd038dSYoshinobu Inoue } 53582cd038dSYoshinobu Inoue break; 53682cd038dSYoshinobu Inoue 53782cd038dSYoshinobu Inoue case SIOCGIFADDR_IN6: 53882cd038dSYoshinobu Inoue /* This interface is basically deprecated. use SIOCGIFCONF. */ 53982cd038dSYoshinobu Inoue /* fall through */ 54082cd038dSYoshinobu Inoue case SIOCGIFAFLAG_IN6: 54182cd038dSYoshinobu Inoue case SIOCGIFNETMASK_IN6: 54282cd038dSYoshinobu Inoue case SIOCGIFDSTADDR_IN6: 54382cd038dSYoshinobu Inoue case SIOCGIFALIFETIME_IN6: 54482cd038dSYoshinobu Inoue /* must think again about its semantics */ 545686cdd19SJun-ichiro itojun Hagino if (ia == NULL) 54682cd038dSYoshinobu Inoue return(EADDRNOTAVAIL); 54782cd038dSYoshinobu Inoue break; 54882cd038dSYoshinobu Inoue case SIOCSIFALIFETIME_IN6: 54982cd038dSYoshinobu Inoue { 55082cd038dSYoshinobu Inoue struct in6_addrlifetime *lt; 55182cd038dSYoshinobu Inoue 55282cd038dSYoshinobu Inoue if (!privileged) 55382cd038dSYoshinobu Inoue return(EPERM); 554686cdd19SJun-ichiro itojun Hagino if (ia == NULL) 55582cd038dSYoshinobu Inoue return(EADDRNOTAVAIL); 55682cd038dSYoshinobu Inoue /* sanity for overflow - beware unsigned */ 55782cd038dSYoshinobu Inoue lt = &ifr->ifr_ifru.ifru_lifetime; 55882cd038dSYoshinobu Inoue if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME 55982cd038dSYoshinobu Inoue && lt->ia6t_vltime + time_second < time_second) { 56082cd038dSYoshinobu Inoue return EINVAL; 56182cd038dSYoshinobu Inoue } 56282cd038dSYoshinobu Inoue if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME 56382cd038dSYoshinobu Inoue && lt->ia6t_pltime + time_second < time_second) { 56482cd038dSYoshinobu Inoue return EINVAL; 56582cd038dSYoshinobu Inoue } 56682cd038dSYoshinobu Inoue break; 56782cd038dSYoshinobu Inoue } 56882cd038dSYoshinobu Inoue } 56982cd038dSYoshinobu Inoue 57082cd038dSYoshinobu Inoue switch (cmd) { 57182cd038dSYoshinobu Inoue 57282cd038dSYoshinobu Inoue case SIOCGIFADDR_IN6: 57382cd038dSYoshinobu Inoue ifr->ifr_addr = ia->ia_addr; 57482cd038dSYoshinobu Inoue break; 57582cd038dSYoshinobu Inoue 57682cd038dSYoshinobu Inoue case SIOCGIFDSTADDR_IN6: 57782cd038dSYoshinobu Inoue if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 57882cd038dSYoshinobu Inoue return(EINVAL); 579686cdd19SJun-ichiro itojun Hagino /* 580686cdd19SJun-ichiro itojun Hagino * XXX: should we check if ifa_dstaddr is NULL and return 581686cdd19SJun-ichiro itojun Hagino * an error? 582686cdd19SJun-ichiro itojun Hagino */ 58382cd038dSYoshinobu Inoue ifr->ifr_dstaddr = ia->ia_dstaddr; 58482cd038dSYoshinobu Inoue break; 58582cd038dSYoshinobu Inoue 58682cd038dSYoshinobu Inoue case SIOCGIFNETMASK_IN6: 58782cd038dSYoshinobu Inoue ifr->ifr_addr = ia->ia_prefixmask; 58882cd038dSYoshinobu Inoue break; 58982cd038dSYoshinobu Inoue 59082cd038dSYoshinobu Inoue case SIOCGIFAFLAG_IN6: 59182cd038dSYoshinobu Inoue ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags; 59282cd038dSYoshinobu Inoue break; 59382cd038dSYoshinobu Inoue 59482cd038dSYoshinobu Inoue case SIOCGIFSTAT_IN6: 59582cd038dSYoshinobu Inoue if (ifp == NULL) 59682cd038dSYoshinobu Inoue return EINVAL; 59782cd038dSYoshinobu Inoue if (in6_ifstat == NULL || ifp->if_index >= in6_ifstatmax 59882cd038dSYoshinobu Inoue || in6_ifstat[ifp->if_index] == NULL) { 59982cd038dSYoshinobu Inoue /* return EAFNOSUPPORT? */ 60082cd038dSYoshinobu Inoue bzero(&ifr->ifr_ifru.ifru_stat, 60182cd038dSYoshinobu Inoue sizeof(ifr->ifr_ifru.ifru_stat)); 60282cd038dSYoshinobu Inoue } else 60382cd038dSYoshinobu Inoue ifr->ifr_ifru.ifru_stat = *in6_ifstat[ifp->if_index]; 60482cd038dSYoshinobu Inoue break; 60582cd038dSYoshinobu Inoue 60682cd038dSYoshinobu Inoue case SIOCGIFSTAT_ICMP6: 60782cd038dSYoshinobu Inoue if (ifp == NULL) 60882cd038dSYoshinobu Inoue return EINVAL; 60982cd038dSYoshinobu Inoue if (icmp6_ifstat == NULL || ifp->if_index >= icmp6_ifstatmax || 61082cd038dSYoshinobu Inoue icmp6_ifstat[ifp->if_index] == NULL) { 61182cd038dSYoshinobu Inoue /* return EAFNOSUPPORT? */ 61282cd038dSYoshinobu Inoue bzero(&ifr->ifr_ifru.ifru_stat, 61382cd038dSYoshinobu Inoue sizeof(ifr->ifr_ifru.ifru_icmp6stat)); 61482cd038dSYoshinobu Inoue } else 61582cd038dSYoshinobu Inoue ifr->ifr_ifru.ifru_icmp6stat = 61682cd038dSYoshinobu Inoue *icmp6_ifstat[ifp->if_index]; 61782cd038dSYoshinobu Inoue break; 61882cd038dSYoshinobu Inoue 619686cdd19SJun-ichiro itojun Hagino #ifdef COMPAT_IN6IFIOCTL /* should be unused */ 62082cd038dSYoshinobu Inoue case SIOCSIFDSTADDR_IN6: 62182cd038dSYoshinobu Inoue if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 62282cd038dSYoshinobu Inoue return(EINVAL); 62382cd038dSYoshinobu Inoue oldaddr = ia->ia_dstaddr; 62482cd038dSYoshinobu Inoue ia->ia_dstaddr = ifr->ifr_dstaddr; 62582cd038dSYoshinobu Inoue 62682cd038dSYoshinobu Inoue /* link-local index check */ 62782cd038dSYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) { 62882cd038dSYoshinobu Inoue if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) { 62982cd038dSYoshinobu Inoue /* interface ID is not embedded by the user */ 63082cd038dSYoshinobu Inoue ia->ia_dstaddr.sin6_addr.s6_addr16[1] 63182cd038dSYoshinobu Inoue = htons(ifp->if_index); 632686cdd19SJun-ichiro itojun Hagino } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] != 63382cd038dSYoshinobu Inoue htons(ifp->if_index)) { 63482cd038dSYoshinobu Inoue ia->ia_dstaddr = oldaddr; 63582cd038dSYoshinobu Inoue return(EINVAL); /* ifid is contradict */ 63682cd038dSYoshinobu Inoue } 63782cd038dSYoshinobu Inoue } 63882cd038dSYoshinobu Inoue 63982cd038dSYoshinobu Inoue if (ifp->if_ioctl && (error = (ifp->if_ioctl) 64082cd038dSYoshinobu Inoue (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) { 64182cd038dSYoshinobu Inoue ia->ia_dstaddr = oldaddr; 64282cd038dSYoshinobu Inoue return(error); 64382cd038dSYoshinobu Inoue } 644686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 64582cd038dSYoshinobu Inoue if (ia->ia_flags & IFA_ROUTE) { 64682cd038dSYoshinobu Inoue ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr; 64782cd038dSYoshinobu Inoue rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 64882cd038dSYoshinobu Inoue ia->ia_ifa.ifa_dstaddr = 64982cd038dSYoshinobu Inoue (struct sockaddr *)&ia->ia_dstaddr; 65082cd038dSYoshinobu Inoue rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 65182cd038dSYoshinobu Inoue } 65282cd038dSYoshinobu Inoue break; 65382cd038dSYoshinobu Inoue 654686cdd19SJun-ichiro itojun Hagino #endif 65582cd038dSYoshinobu Inoue case SIOCGIFALIFETIME_IN6: 65682cd038dSYoshinobu Inoue ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime; 65782cd038dSYoshinobu Inoue break; 65882cd038dSYoshinobu Inoue 65982cd038dSYoshinobu Inoue case SIOCSIFALIFETIME_IN6: 66082cd038dSYoshinobu Inoue ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime; 66182cd038dSYoshinobu Inoue /* for sanity */ 66282cd038dSYoshinobu Inoue if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 66382cd038dSYoshinobu Inoue ia->ia6_lifetime.ia6t_expire = 66482cd038dSYoshinobu Inoue time_second + ia->ia6_lifetime.ia6t_vltime; 66582cd038dSYoshinobu Inoue } else 66682cd038dSYoshinobu Inoue ia->ia6_lifetime.ia6t_expire = 0; 66782cd038dSYoshinobu Inoue if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 66882cd038dSYoshinobu Inoue ia->ia6_lifetime.ia6t_preferred = 66982cd038dSYoshinobu Inoue time_second + ia->ia6_lifetime.ia6t_pltime; 67082cd038dSYoshinobu Inoue } else 67182cd038dSYoshinobu Inoue ia->ia6_lifetime.ia6t_preferred = 0; 67282cd038dSYoshinobu Inoue break; 67382cd038dSYoshinobu Inoue 67482cd038dSYoshinobu Inoue case SIOCSIFADDR_IN6: 675686cdd19SJun-ichiro itojun Hagino error = in6_ifinit(ifp, ia, &ifr->ifr_addr, 1); 676686cdd19SJun-ichiro itojun Hagino #if 0 677686cdd19SJun-ichiro itojun Hagino /* 678686cdd19SJun-ichiro itojun Hagino * the code chokes if we are to assign multiple addresses with 679686cdd19SJun-ichiro itojun Hagino * the same address prefix (rtinit() will return EEXIST, which 680686cdd19SJun-ichiro itojun Hagino * is not fatal actually). we will get memory leak if we 681686cdd19SJun-ichiro itojun Hagino * don't do it. 682686cdd19SJun-ichiro itojun Hagino * -> we may want to hide EEXIST from rtinit(). 683686cdd19SJun-ichiro itojun Hagino */ 684686cdd19SJun-ichiro itojun Hagino undo: 685686cdd19SJun-ichiro itojun Hagino if (error && newifaddr) { 686686cdd19SJun-ichiro itojun Hagino TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); 687686cdd19SJun-ichiro itojun Hagino /* release a refcnt for the link from if_addrlist */ 688686cdd19SJun-ichiro itojun Hagino IFAFREE(&ia->ia_ifa); 68982cd038dSYoshinobu Inoue 690686cdd19SJun-ichiro itojun Hagino oia = ia; 691686cdd19SJun-ichiro itojun Hagino if (oia == (ia = in6_ifaddr)) 692686cdd19SJun-ichiro itojun Hagino in6_ifaddr = ia->ia_next; 693686cdd19SJun-ichiro itojun Hagino else { 694686cdd19SJun-ichiro itojun Hagino while (ia->ia_next && (ia->ia_next != oia)) 695686cdd19SJun-ichiro itojun Hagino ia = ia->ia_next; 696686cdd19SJun-ichiro itojun Hagino if (ia->ia_next) 697686cdd19SJun-ichiro itojun Hagino ia->ia_next = oia->ia_next; 698686cdd19SJun-ichiro itojun Hagino else { 699686cdd19SJun-ichiro itojun Hagino printf("Didn't unlink in6_ifaddr " 700686cdd19SJun-ichiro itojun Hagino "from list\n"); 701686cdd19SJun-ichiro itojun Hagino } 702686cdd19SJun-ichiro itojun Hagino } 703686cdd19SJun-ichiro itojun Hagino /* release another refcnt for the link from in6_ifaddr */ 704686cdd19SJun-ichiro itojun Hagino IFAFREE(&oia->ia_ifa); 705686cdd19SJun-ichiro itojun Hagino } 706686cdd19SJun-ichiro itojun Hagino #endif 707686cdd19SJun-ichiro itojun Hagino return error; 708686cdd19SJun-ichiro itojun Hagino 709686cdd19SJun-ichiro itojun Hagino #ifdef COMPAT_IN6IFIOCTL /* XXX should be unused */ 71082cd038dSYoshinobu Inoue case SIOCSIFNETMASK_IN6: 71182cd038dSYoshinobu Inoue ia->ia_prefixmask = ifr->ifr_addr; 71282cd038dSYoshinobu Inoue bzero(&net, sizeof(net)); 71382cd038dSYoshinobu Inoue net.sin6_len = sizeof(struct sockaddr_in6); 71482cd038dSYoshinobu Inoue net.sin6_family = AF_INET6; 71582cd038dSYoshinobu Inoue net.sin6_port = htons(0); 71682cd038dSYoshinobu Inoue net.sin6_flowinfo = htonl(0); 71782cd038dSYoshinobu Inoue net.sin6_addr.s6_addr32[0] 71882cd038dSYoshinobu Inoue = ia->ia_addr.sin6_addr.s6_addr32[0] & 71982cd038dSYoshinobu Inoue ia->ia_prefixmask.sin6_addr.s6_addr32[0]; 72082cd038dSYoshinobu Inoue net.sin6_addr.s6_addr32[1] 72182cd038dSYoshinobu Inoue = ia->ia_addr.sin6_addr.s6_addr32[1] & 72282cd038dSYoshinobu Inoue ia->ia_prefixmask.sin6_addr.s6_addr32[1]; 72382cd038dSYoshinobu Inoue net.sin6_addr.s6_addr32[2] 72482cd038dSYoshinobu Inoue = ia->ia_addr.sin6_addr.s6_addr32[2] & 72582cd038dSYoshinobu Inoue ia->ia_prefixmask.sin6_addr.s6_addr32[2]; 72682cd038dSYoshinobu Inoue net.sin6_addr.s6_addr32[3] 72782cd038dSYoshinobu Inoue = ia->ia_addr.sin6_addr.s6_addr32[3] & 72882cd038dSYoshinobu Inoue ia->ia_prefixmask.sin6_addr.s6_addr32[3]; 72982cd038dSYoshinobu Inoue ia->ia_net = net; 73082cd038dSYoshinobu Inoue break; 731686cdd19SJun-ichiro itojun Hagino #endif 73282cd038dSYoshinobu Inoue 73382cd038dSYoshinobu Inoue case SIOCAIFADDR_IN6: 73482cd038dSYoshinobu Inoue prefixIsNew = 0; 73582cd038dSYoshinobu Inoue hostIsNew = 1; 73682cd038dSYoshinobu Inoue 73782cd038dSYoshinobu Inoue if (ifra->ifra_addr.sin6_len == 0) { 73882cd038dSYoshinobu Inoue ifra->ifra_addr = ia->ia_addr; 73982cd038dSYoshinobu Inoue hostIsNew = 0; 74082cd038dSYoshinobu Inoue } else if (IN6_ARE_ADDR_EQUAL(&ifra->ifra_addr.sin6_addr, 74182cd038dSYoshinobu Inoue &ia->ia_addr.sin6_addr)) 74282cd038dSYoshinobu Inoue hostIsNew = 0; 74382cd038dSYoshinobu Inoue 744686cdd19SJun-ichiro itojun Hagino /* Validate address families: */ 745686cdd19SJun-ichiro itojun Hagino /* 746686cdd19SJun-ichiro itojun Hagino * The destination address for a p2p link must have a family 747686cdd19SJun-ichiro itojun Hagino * of AF_UNSPEC or AF_INET6. 748686cdd19SJun-ichiro itojun Hagino */ 749686cdd19SJun-ichiro itojun Hagino if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && 750686cdd19SJun-ichiro itojun Hagino ifra->ifra_dstaddr.sin6_family != AF_INET6 && 751686cdd19SJun-ichiro itojun Hagino ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) 752686cdd19SJun-ichiro itojun Hagino return(EAFNOSUPPORT); 753686cdd19SJun-ichiro itojun Hagino /* 754686cdd19SJun-ichiro itojun Hagino * The prefixmask must have a family of AF_UNSPEC or AF_INET6. 755686cdd19SJun-ichiro itojun Hagino */ 756686cdd19SJun-ichiro itojun Hagino if (ifra->ifra_prefixmask.sin6_family != AF_INET6 && 757686cdd19SJun-ichiro itojun Hagino ifra->ifra_prefixmask.sin6_family != AF_UNSPEC) 758686cdd19SJun-ichiro itojun Hagino return(EAFNOSUPPORT); 759686cdd19SJun-ichiro itojun Hagino 76082cd038dSYoshinobu Inoue if (ifra->ifra_prefixmask.sin6_len) { 76182cd038dSYoshinobu Inoue in6_ifscrub(ifp, ia); 76282cd038dSYoshinobu Inoue ia->ia_prefixmask = ifra->ifra_prefixmask; 76382cd038dSYoshinobu Inoue prefixIsNew = 1; 76482cd038dSYoshinobu Inoue } 76582cd038dSYoshinobu Inoue if ((ifp->if_flags & IFF_POINTOPOINT) && 76682cd038dSYoshinobu Inoue (ifra->ifra_dstaddr.sin6_family == AF_INET6)) { 76782cd038dSYoshinobu Inoue in6_ifscrub(ifp, ia); 768686cdd19SJun-ichiro itojun Hagino oldaddr = ia->ia_dstaddr; 76982cd038dSYoshinobu Inoue ia->ia_dstaddr = ifra->ifra_dstaddr; 77082cd038dSYoshinobu Inoue /* link-local index check: should be a separate function? */ 77182cd038dSYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) { 77282cd038dSYoshinobu Inoue if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) { 77382cd038dSYoshinobu Inoue /* 77482cd038dSYoshinobu Inoue * interface ID is not embedded by 77582cd038dSYoshinobu Inoue * the user 77682cd038dSYoshinobu Inoue */ 77782cd038dSYoshinobu Inoue ia->ia_dstaddr.sin6_addr.s6_addr16[1] 77882cd038dSYoshinobu Inoue = htons(ifp->if_index); 779686cdd19SJun-ichiro itojun Hagino } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] != 78082cd038dSYoshinobu Inoue htons(ifp->if_index)) { 78182cd038dSYoshinobu Inoue ia->ia_dstaddr = oldaddr; 78282cd038dSYoshinobu Inoue return(EINVAL); /* ifid is contradict */ 78382cd038dSYoshinobu Inoue } 78482cd038dSYoshinobu Inoue } 78582cd038dSYoshinobu Inoue prefixIsNew = 1; /* We lie; but effect's the same */ 78682cd038dSYoshinobu Inoue } 787686cdd19SJun-ichiro itojun Hagino if (hostIsNew || prefixIsNew) { 78882cd038dSYoshinobu Inoue error = in6_ifinit(ifp, ia, &ifra->ifra_addr, 0); 789686cdd19SJun-ichiro itojun Hagino #if 0 790686cdd19SJun-ichiro itojun Hagino if (error) 791686cdd19SJun-ichiro itojun Hagino goto undo; 792686cdd19SJun-ichiro itojun Hagino #endif 793686cdd19SJun-ichiro itojun Hagino } 794686cdd19SJun-ichiro itojun Hagino if (hostIsNew && (ifp->if_flags & IFF_MULTICAST)) { 79582cd038dSYoshinobu Inoue int error_local = 0; 79682cd038dSYoshinobu Inoue 79782cd038dSYoshinobu Inoue /* 79882cd038dSYoshinobu Inoue * join solicited multicast addr for new host id 79982cd038dSYoshinobu Inoue */ 80082cd038dSYoshinobu Inoue struct in6_addr llsol; 80182cd038dSYoshinobu Inoue bzero(&llsol, sizeof(struct in6_addr)); 80282cd038dSYoshinobu Inoue llsol.s6_addr16[0] = htons(0xff02); 80382cd038dSYoshinobu Inoue llsol.s6_addr16[1] = htons(ifp->if_index); 80482cd038dSYoshinobu Inoue llsol.s6_addr32[1] = 0; 80582cd038dSYoshinobu Inoue llsol.s6_addr32[2] = htonl(1); 80682cd038dSYoshinobu Inoue llsol.s6_addr32[3] = 80782cd038dSYoshinobu Inoue ifra->ifra_addr.sin6_addr.s6_addr32[3]; 80882cd038dSYoshinobu Inoue llsol.s6_addr8[12] = 0xff; 80982cd038dSYoshinobu Inoue (void)in6_addmulti(&llsol, ifp, &error_local); 81082cd038dSYoshinobu Inoue if (error == 0) 81182cd038dSYoshinobu Inoue error = error_local; 81282cd038dSYoshinobu Inoue } 81382cd038dSYoshinobu Inoue 81482cd038dSYoshinobu Inoue ia->ia6_flags = ifra->ifra_flags; 81582cd038dSYoshinobu Inoue ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/ 81682cd038dSYoshinobu Inoue 81782cd038dSYoshinobu Inoue ia->ia6_lifetime = ifra->ifra_lifetime; 81882cd038dSYoshinobu Inoue /* for sanity */ 81982cd038dSYoshinobu Inoue if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 82082cd038dSYoshinobu Inoue ia->ia6_lifetime.ia6t_expire = 82182cd038dSYoshinobu Inoue time_second + ia->ia6_lifetime.ia6t_vltime; 82282cd038dSYoshinobu Inoue } else 82382cd038dSYoshinobu Inoue ia->ia6_lifetime.ia6t_expire = 0; 82482cd038dSYoshinobu Inoue if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 82582cd038dSYoshinobu Inoue ia->ia6_lifetime.ia6t_preferred = 82682cd038dSYoshinobu Inoue time_second + ia->ia6_lifetime.ia6t_pltime; 82782cd038dSYoshinobu Inoue } else 82882cd038dSYoshinobu Inoue ia->ia6_lifetime.ia6t_preferred = 0; 82982cd038dSYoshinobu Inoue 83082cd038dSYoshinobu Inoue /* 83182cd038dSYoshinobu Inoue * Perform DAD, if needed. 83282cd038dSYoshinobu Inoue * XXX It may be of use, if we can administratively 83382cd038dSYoshinobu Inoue * disable DAD. 83482cd038dSYoshinobu Inoue */ 83582cd038dSYoshinobu Inoue switch (ifp->if_type) { 83682cd038dSYoshinobu Inoue case IFT_ARCNET: 83782cd038dSYoshinobu Inoue case IFT_ETHER: 83882cd038dSYoshinobu Inoue case IFT_FDDI: 839686cdd19SJun-ichiro itojun Hagino #if 0 840686cdd19SJun-ichiro itojun Hagino case IFT_ATM: 841686cdd19SJun-ichiro itojun Hagino case IFT_SLIP: 842686cdd19SJun-ichiro itojun Hagino case IFT_PPP: 843686cdd19SJun-ichiro itojun Hagino #endif 844686cdd19SJun-ichiro itojun Hagino { 84582cd038dSYoshinobu Inoue ia->ia6_flags |= IN6_IFF_TENTATIVE; 84682cd038dSYoshinobu Inoue nd6_dad_start((struct ifaddr *)ia, NULL); 847686cdd19SJun-ichiro itojun Hagino } 84882cd038dSYoshinobu Inoue break; 84982cd038dSYoshinobu Inoue #ifdef IFT_DUMMY 85082cd038dSYoshinobu Inoue case IFT_DUMMY: 85182cd038dSYoshinobu Inoue #endif 85282cd038dSYoshinobu Inoue case IFT_FAITH: 85382cd038dSYoshinobu Inoue case IFT_GIF: 85482cd038dSYoshinobu Inoue case IFT_LOOP: 85582cd038dSYoshinobu Inoue default: 85682cd038dSYoshinobu Inoue break; 85782cd038dSYoshinobu Inoue } 85882cd038dSYoshinobu Inoue 85982cd038dSYoshinobu Inoue if (hostIsNew) { 86082cd038dSYoshinobu Inoue int iilen; 86182cd038dSYoshinobu Inoue int error_local = 0; 86282cd038dSYoshinobu Inoue 86382cd038dSYoshinobu Inoue iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) - 86482cd038dSYoshinobu Inoue in6_mask2len(&ia->ia_prefixmask.sin6_addr); 86582cd038dSYoshinobu Inoue error_local = in6_prefix_add_ifid(iilen, ia); 86682cd038dSYoshinobu Inoue if (error == 0) 86782cd038dSYoshinobu Inoue error = error_local; 86882cd038dSYoshinobu Inoue } 86982cd038dSYoshinobu Inoue 87082cd038dSYoshinobu Inoue return(error); 87182cd038dSYoshinobu Inoue 87282cd038dSYoshinobu Inoue case SIOCDIFADDR_IN6: 873686cdd19SJun-ichiro itojun Hagino in6_purgeaddr(&ia->ia_ifa, ifp); 874686cdd19SJun-ichiro itojun Hagino break; 875686cdd19SJun-ichiro itojun Hagino 876686cdd19SJun-ichiro itojun Hagino default: 877686cdd19SJun-ichiro itojun Hagino if (ifp == NULL || ifp->if_ioctl == 0) 878686cdd19SJun-ichiro itojun Hagino return(EOPNOTSUPP); 879686cdd19SJun-ichiro itojun Hagino return((*ifp->if_ioctl)(ifp, cmd, data)); 880686cdd19SJun-ichiro itojun Hagino } 881686cdd19SJun-ichiro itojun Hagino return(0); 882686cdd19SJun-ichiro itojun Hagino } 883686cdd19SJun-ichiro itojun Hagino 884686cdd19SJun-ichiro itojun Hagino void 885686cdd19SJun-ichiro itojun Hagino in6_purgeaddr(ifa, ifp) 886686cdd19SJun-ichiro itojun Hagino struct ifaddr *ifa; 887686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 888686cdd19SJun-ichiro itojun Hagino { 889686cdd19SJun-ichiro itojun Hagino struct in6_ifaddr *oia, *ia = (void *) ifa; 890686cdd19SJun-ichiro itojun Hagino int plen; 891686cdd19SJun-ichiro itojun Hagino 89282cd038dSYoshinobu Inoue in6_ifscrub(ifp, ia); 89382cd038dSYoshinobu Inoue 89482cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_MULTICAST) { 89582cd038dSYoshinobu Inoue /* 89682cd038dSYoshinobu Inoue * delete solicited multicast addr for deleting host id 89782cd038dSYoshinobu Inoue */ 89882cd038dSYoshinobu Inoue struct in6_multi *in6m; 89982cd038dSYoshinobu Inoue struct in6_addr llsol; 90082cd038dSYoshinobu Inoue bzero(&llsol, sizeof(struct in6_addr)); 90182cd038dSYoshinobu Inoue llsol.s6_addr16[0] = htons(0xff02); 90282cd038dSYoshinobu Inoue llsol.s6_addr16[1] = htons(ifp->if_index); 90382cd038dSYoshinobu Inoue llsol.s6_addr32[1] = 0; 90482cd038dSYoshinobu Inoue llsol.s6_addr32[2] = htonl(1); 90582cd038dSYoshinobu Inoue llsol.s6_addr32[3] = 90682cd038dSYoshinobu Inoue ia->ia_addr.sin6_addr.s6_addr32[3]; 90782cd038dSYoshinobu Inoue llsol.s6_addr8[12] = 0xff; 90882cd038dSYoshinobu Inoue 90982cd038dSYoshinobu Inoue IN6_LOOKUP_MULTI(llsol, ifp, in6m); 91082cd038dSYoshinobu Inoue if (in6m) 91182cd038dSYoshinobu Inoue in6_delmulti(in6m); 91282cd038dSYoshinobu Inoue } 91382cd038dSYoshinobu Inoue 914686cdd19SJun-ichiro itojun Hagino TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); 915686cdd19SJun-ichiro itojun Hagino /* release a refcnt for the link from if_addrlist */ 916686cdd19SJun-ichiro itojun Hagino IFAFREE(&ia->ia_ifa); 917686cdd19SJun-ichiro itojun Hagino 91882cd038dSYoshinobu Inoue oia = ia; 91982cd038dSYoshinobu Inoue if (oia == (ia = in6_ifaddr)) 92082cd038dSYoshinobu Inoue in6_ifaddr = ia->ia_next; 92182cd038dSYoshinobu Inoue else { 92282cd038dSYoshinobu Inoue while (ia->ia_next && (ia->ia_next != oia)) 92382cd038dSYoshinobu Inoue ia = ia->ia_next; 92482cd038dSYoshinobu Inoue if (ia->ia_next) 92582cd038dSYoshinobu Inoue ia->ia_next = oia->ia_next; 92682cd038dSYoshinobu Inoue else 92782cd038dSYoshinobu Inoue printf("Didn't unlink in6_ifaddr from list\n"); 92882cd038dSYoshinobu Inoue } 92982cd038dSYoshinobu Inoue { 93082cd038dSYoshinobu Inoue int iilen; 93182cd038dSYoshinobu Inoue 932686cdd19SJun-ichiro itojun Hagino plen = in6_mask2len(&oia->ia_prefixmask.sin6_addr); 933686cdd19SJun-ichiro itojun Hagino iilen = (sizeof(oia->ia_prefixmask.sin6_addr) << 3) - plen; 93482cd038dSYoshinobu Inoue in6_prefix_remove_ifid(iilen, oia); 93582cd038dSYoshinobu Inoue } 93682cd038dSYoshinobu Inoue 937686cdd19SJun-ichiro itojun Hagino /* 938686cdd19SJun-ichiro itojun Hagino * Check if we have another address that has the same prefix of 939686cdd19SJun-ichiro itojun Hagino * the purged address. If we have one, reinstall the corresponding 940686cdd19SJun-ichiro itojun Hagino * interface route. 941686cdd19SJun-ichiro itojun Hagino */ 942686cdd19SJun-ichiro itojun Hagino for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 943686cdd19SJun-ichiro itojun Hagino int e; 944686cdd19SJun-ichiro itojun Hagino 945686cdd19SJun-ichiro itojun Hagino if (in6_are_prefix_equal(&ia->ia_addr.sin6_addr, 946686cdd19SJun-ichiro itojun Hagino &oia->ia_addr.sin6_addr, plen)) { 947686cdd19SJun-ichiro itojun Hagino if ((e = rtinit(&(ia->ia_ifa), (int)RTM_ADD, 948686cdd19SJun-ichiro itojun Hagino ia->ia_flags)) == 0) { 949686cdd19SJun-ichiro itojun Hagino ia->ia_flags |= IFA_ROUTE; 950686cdd19SJun-ichiro itojun Hagino break; 95182cd038dSYoshinobu Inoue } 952686cdd19SJun-ichiro itojun Hagino else { 953686cdd19SJun-ichiro itojun Hagino log(LOG_NOTICE, 954686cdd19SJun-ichiro itojun Hagino "in6_purgeaddr: failed to add an interface" 955686cdd19SJun-ichiro itojun Hagino " route for %s/%d on %s, errno = %d\n", 956686cdd19SJun-ichiro itojun Hagino ip6_sprintf(&ia->ia_addr.sin6_addr), 957686cdd19SJun-ichiro itojun Hagino plen, if_name(ia->ia_ifp), e); 958686cdd19SJun-ichiro itojun Hagino /* still trying */ 959686cdd19SJun-ichiro itojun Hagino } 960686cdd19SJun-ichiro itojun Hagino } 961686cdd19SJun-ichiro itojun Hagino } 962686cdd19SJun-ichiro itojun Hagino 963686cdd19SJun-ichiro itojun Hagino /* release another refcnt for the link from in6_ifaddr */ 964686cdd19SJun-ichiro itojun Hagino IFAFREE(&oia->ia_ifa); 96582cd038dSYoshinobu Inoue } 96682cd038dSYoshinobu Inoue 96782cd038dSYoshinobu Inoue /* 96882cd038dSYoshinobu Inoue * SIOC[GAD]LIFADDR. 969686cdd19SJun-ichiro itojun Hagino * SIOCGLIFADDR: get first address. (???) 97082cd038dSYoshinobu Inoue * SIOCGLIFADDR with IFLR_PREFIX: 97182cd038dSYoshinobu Inoue * get first address that matches the specified prefix. 97282cd038dSYoshinobu Inoue * SIOCALIFADDR: add the specified address. 97382cd038dSYoshinobu Inoue * SIOCALIFADDR with IFLR_PREFIX: 97482cd038dSYoshinobu Inoue * add the specified prefix, filling hostid part from 97582cd038dSYoshinobu Inoue * the first link-local address. prefixlen must be <= 64. 97682cd038dSYoshinobu Inoue * SIOCDLIFADDR: delete the specified address. 97782cd038dSYoshinobu Inoue * SIOCDLIFADDR with IFLR_PREFIX: 97882cd038dSYoshinobu Inoue * delete the first address that matches the specified prefix. 97982cd038dSYoshinobu Inoue * return values: 98082cd038dSYoshinobu Inoue * EINVAL on invalid parameters 98182cd038dSYoshinobu Inoue * EADDRNOTAVAIL on prefix match failed/specified address not found 98282cd038dSYoshinobu Inoue * other values may be returned from in6_ioctl() 98382cd038dSYoshinobu Inoue * 98482cd038dSYoshinobu Inoue * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64. 98582cd038dSYoshinobu Inoue * this is to accomodate address naming scheme other than RFC2374, 98682cd038dSYoshinobu Inoue * in the future. 98782cd038dSYoshinobu Inoue * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374 98882cd038dSYoshinobu Inoue * address encoding scheme. (see figure on page 8) 98982cd038dSYoshinobu Inoue */ 99082cd038dSYoshinobu Inoue static int 99182cd038dSYoshinobu Inoue in6_lifaddr_ioctl(so, cmd, data, ifp, p) 99282cd038dSYoshinobu Inoue struct socket *so; 99382cd038dSYoshinobu Inoue u_long cmd; 99482cd038dSYoshinobu Inoue caddr_t data; 99582cd038dSYoshinobu Inoue struct ifnet *ifp; 99682cd038dSYoshinobu Inoue struct proc *p; 99782cd038dSYoshinobu Inoue { 99882cd038dSYoshinobu Inoue struct if_laddrreq *iflr = (struct if_laddrreq *)data; 99982cd038dSYoshinobu Inoue struct ifaddr *ifa; 1000686cdd19SJun-ichiro itojun Hagino struct sockaddr *sa; 100182cd038dSYoshinobu Inoue 100282cd038dSYoshinobu Inoue /* sanity checks */ 100382cd038dSYoshinobu Inoue if (!data || !ifp) { 100482cd038dSYoshinobu Inoue panic("invalid argument to in6_lifaddr_ioctl"); 100582cd038dSYoshinobu Inoue /*NOTRECHED*/ 100682cd038dSYoshinobu Inoue } 100782cd038dSYoshinobu Inoue 100882cd038dSYoshinobu Inoue switch (cmd) { 100982cd038dSYoshinobu Inoue case SIOCGLIFADDR: 101082cd038dSYoshinobu Inoue /* address must be specified on GET with IFLR_PREFIX */ 101182cd038dSYoshinobu Inoue if ((iflr->flags & IFLR_PREFIX) == 0) 101282cd038dSYoshinobu Inoue break; 101382cd038dSYoshinobu Inoue /*FALLTHROUGH*/ 101482cd038dSYoshinobu Inoue case SIOCALIFADDR: 101582cd038dSYoshinobu Inoue case SIOCDLIFADDR: 101682cd038dSYoshinobu Inoue /* address must be specified on ADD and DELETE */ 1017686cdd19SJun-ichiro itojun Hagino sa = (struct sockaddr *)&iflr->addr; 1018686cdd19SJun-ichiro itojun Hagino if (sa->sa_family != AF_INET6) 101982cd038dSYoshinobu Inoue return EINVAL; 1020686cdd19SJun-ichiro itojun Hagino if (sa->sa_len != sizeof(struct sockaddr_in6)) 102182cd038dSYoshinobu Inoue return EINVAL; 102282cd038dSYoshinobu Inoue /* XXX need improvement */ 1023686cdd19SJun-ichiro itojun Hagino sa = (struct sockaddr *)&iflr->dstaddr; 1024686cdd19SJun-ichiro itojun Hagino if (sa->sa_family && sa->sa_family != AF_INET6) 102582cd038dSYoshinobu Inoue return EINVAL; 1026686cdd19SJun-ichiro itojun Hagino if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6)) 102782cd038dSYoshinobu Inoue return EINVAL; 102882cd038dSYoshinobu Inoue break; 102982cd038dSYoshinobu Inoue default: /*shouldn't happen*/ 1030686cdd19SJun-ichiro itojun Hagino #if 0 1031686cdd19SJun-ichiro itojun Hagino panic("invalid cmd to in6_lifaddr_ioctl"); 1032686cdd19SJun-ichiro itojun Hagino /*NOTREACHED*/ 1033686cdd19SJun-ichiro itojun Hagino #else 103482cd038dSYoshinobu Inoue return EOPNOTSUPP; 1035686cdd19SJun-ichiro itojun Hagino #endif 103682cd038dSYoshinobu Inoue } 103782cd038dSYoshinobu Inoue if (sizeof(struct in6_addr) * 8 < iflr->prefixlen) 103882cd038dSYoshinobu Inoue return EINVAL; 103982cd038dSYoshinobu Inoue 104082cd038dSYoshinobu Inoue switch (cmd) { 104182cd038dSYoshinobu Inoue case SIOCALIFADDR: 104282cd038dSYoshinobu Inoue { 104382cd038dSYoshinobu Inoue struct in6_aliasreq ifra; 104482cd038dSYoshinobu Inoue struct in6_addr *hostid = NULL; 104582cd038dSYoshinobu Inoue int prefixlen; 104682cd038dSYoshinobu Inoue 104782cd038dSYoshinobu Inoue if ((iflr->flags & IFLR_PREFIX) != 0) { 104882cd038dSYoshinobu Inoue struct sockaddr_in6 *sin6; 104982cd038dSYoshinobu Inoue 105082cd038dSYoshinobu Inoue /* 105182cd038dSYoshinobu Inoue * hostid is to fill in the hostid part of the 105282cd038dSYoshinobu Inoue * address. hostid points to the first link-local 105382cd038dSYoshinobu Inoue * address attached to the interface. 105482cd038dSYoshinobu Inoue */ 1055686cdd19SJun-ichiro itojun Hagino ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); 105682cd038dSYoshinobu Inoue if (!ifa) 105782cd038dSYoshinobu Inoue return EADDRNOTAVAIL; 105882cd038dSYoshinobu Inoue hostid = IFA_IN6(ifa); 105982cd038dSYoshinobu Inoue 106082cd038dSYoshinobu Inoue /* prefixlen must be <= 64. */ 106182cd038dSYoshinobu Inoue if (64 < iflr->prefixlen) 106282cd038dSYoshinobu Inoue return EINVAL; 106382cd038dSYoshinobu Inoue prefixlen = iflr->prefixlen; 106482cd038dSYoshinobu Inoue 106582cd038dSYoshinobu Inoue /* hostid part must be zero. */ 106682cd038dSYoshinobu Inoue sin6 = (struct sockaddr_in6 *)&iflr->addr; 106782cd038dSYoshinobu Inoue if (sin6->sin6_addr.s6_addr32[2] != 0 106882cd038dSYoshinobu Inoue || sin6->sin6_addr.s6_addr32[3] != 0) { 106982cd038dSYoshinobu Inoue return EINVAL; 107082cd038dSYoshinobu Inoue } 107182cd038dSYoshinobu Inoue } else 107282cd038dSYoshinobu Inoue prefixlen = iflr->prefixlen; 107382cd038dSYoshinobu Inoue 107482cd038dSYoshinobu Inoue /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 107582cd038dSYoshinobu Inoue bzero(&ifra, sizeof(ifra)); 107682cd038dSYoshinobu Inoue bcopy(iflr->iflr_name, ifra.ifra_name, 107782cd038dSYoshinobu Inoue sizeof(ifra.ifra_name)); 107882cd038dSYoshinobu Inoue 1079686cdd19SJun-ichiro itojun Hagino bcopy(&iflr->addr, &ifra.ifra_addr, 1080686cdd19SJun-ichiro itojun Hagino ((struct sockaddr *)&iflr->addr)->sa_len); 108182cd038dSYoshinobu Inoue if (hostid) { 108282cd038dSYoshinobu Inoue /* fill in hostid part */ 108382cd038dSYoshinobu Inoue ifra.ifra_addr.sin6_addr.s6_addr32[2] = 108482cd038dSYoshinobu Inoue hostid->s6_addr32[2]; 108582cd038dSYoshinobu Inoue ifra.ifra_addr.sin6_addr.s6_addr32[3] = 108682cd038dSYoshinobu Inoue hostid->s6_addr32[3]; 108782cd038dSYoshinobu Inoue } 108882cd038dSYoshinobu Inoue 1089686cdd19SJun-ichiro itojun Hagino if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /*XXX*/ 109082cd038dSYoshinobu Inoue bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 1091686cdd19SJun-ichiro itojun Hagino ((struct sockaddr *)&iflr->dstaddr)->sa_len); 109282cd038dSYoshinobu Inoue if (hostid) { 109382cd038dSYoshinobu Inoue ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] = 109482cd038dSYoshinobu Inoue hostid->s6_addr32[2]; 109582cd038dSYoshinobu Inoue ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = 109682cd038dSYoshinobu Inoue hostid->s6_addr32[3]; 109782cd038dSYoshinobu Inoue } 109882cd038dSYoshinobu Inoue } 109982cd038dSYoshinobu Inoue 110082cd038dSYoshinobu Inoue ifra.ifra_prefixmask.sin6_family = AF_INET6; 110182cd038dSYoshinobu Inoue ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 110282cd038dSYoshinobu Inoue in6_len2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); 110382cd038dSYoshinobu Inoue 110482cd038dSYoshinobu Inoue ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; 110582cd038dSYoshinobu Inoue return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, p); 110682cd038dSYoshinobu Inoue } 110782cd038dSYoshinobu Inoue case SIOCGLIFADDR: 110882cd038dSYoshinobu Inoue case SIOCDLIFADDR: 110982cd038dSYoshinobu Inoue { 111082cd038dSYoshinobu Inoue struct in6_ifaddr *ia; 111182cd038dSYoshinobu Inoue struct in6_addr mask, candidate, match; 111282cd038dSYoshinobu Inoue struct sockaddr_in6 *sin6; 111382cd038dSYoshinobu Inoue int cmp; 111482cd038dSYoshinobu Inoue 111582cd038dSYoshinobu Inoue bzero(&mask, sizeof(mask)); 111682cd038dSYoshinobu Inoue if (iflr->flags & IFLR_PREFIX) { 111782cd038dSYoshinobu Inoue /* lookup a prefix rather than address. */ 111882cd038dSYoshinobu Inoue in6_len2mask(&mask, iflr->prefixlen); 111982cd038dSYoshinobu Inoue 112082cd038dSYoshinobu Inoue sin6 = (struct sockaddr_in6 *)&iflr->addr; 112182cd038dSYoshinobu Inoue bcopy(&sin6->sin6_addr, &match, sizeof(match)); 112282cd038dSYoshinobu Inoue match.s6_addr32[0] &= mask.s6_addr32[0]; 112382cd038dSYoshinobu Inoue match.s6_addr32[1] &= mask.s6_addr32[1]; 112482cd038dSYoshinobu Inoue match.s6_addr32[2] &= mask.s6_addr32[2]; 112582cd038dSYoshinobu Inoue match.s6_addr32[3] &= mask.s6_addr32[3]; 112682cd038dSYoshinobu Inoue 112782cd038dSYoshinobu Inoue /* if you set extra bits, that's wrong */ 112882cd038dSYoshinobu Inoue if (bcmp(&match, &sin6->sin6_addr, sizeof(match))) 112982cd038dSYoshinobu Inoue return EINVAL; 113082cd038dSYoshinobu Inoue 113182cd038dSYoshinobu Inoue cmp = 1; 113282cd038dSYoshinobu Inoue } else { 113382cd038dSYoshinobu Inoue if (cmd == SIOCGLIFADDR) { 113482cd038dSYoshinobu Inoue /* on getting an address, take the 1st match */ 113582cd038dSYoshinobu Inoue cmp = 0; /*XXX*/ 113682cd038dSYoshinobu Inoue } else { 113782cd038dSYoshinobu Inoue /* on deleting an address, do exact match */ 113882cd038dSYoshinobu Inoue in6_len2mask(&mask, 128); 113982cd038dSYoshinobu Inoue sin6 = (struct sockaddr_in6 *)&iflr->addr; 114082cd038dSYoshinobu Inoue bcopy(&sin6->sin6_addr, &match, sizeof(match)); 114182cd038dSYoshinobu Inoue 114282cd038dSYoshinobu Inoue cmp = 1; 114382cd038dSYoshinobu Inoue } 114482cd038dSYoshinobu Inoue } 114582cd038dSYoshinobu Inoue 1146cfa1ca9dSYoshinobu Inoue TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 114782cd038dSYoshinobu Inoue { 114882cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6) 114982cd038dSYoshinobu Inoue continue; 115082cd038dSYoshinobu Inoue if (!cmp) 115182cd038dSYoshinobu Inoue break; 115282cd038dSYoshinobu Inoue bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate)); 115382cd038dSYoshinobu Inoue candidate.s6_addr32[0] &= mask.s6_addr32[0]; 115482cd038dSYoshinobu Inoue candidate.s6_addr32[1] &= mask.s6_addr32[1]; 115582cd038dSYoshinobu Inoue candidate.s6_addr32[2] &= mask.s6_addr32[2]; 115682cd038dSYoshinobu Inoue candidate.s6_addr32[3] &= mask.s6_addr32[3]; 115782cd038dSYoshinobu Inoue if (IN6_ARE_ADDR_EQUAL(&candidate, &match)) 115882cd038dSYoshinobu Inoue break; 115982cd038dSYoshinobu Inoue } 116082cd038dSYoshinobu Inoue if (!ifa) 116182cd038dSYoshinobu Inoue return EADDRNOTAVAIL; 116282cd038dSYoshinobu Inoue ia = ifa2ia6(ifa); 116382cd038dSYoshinobu Inoue 116482cd038dSYoshinobu Inoue if (cmd == SIOCGLIFADDR) { 116582cd038dSYoshinobu Inoue /* fill in the if_laddrreq structure */ 116682cd038dSYoshinobu Inoue bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len); 116782cd038dSYoshinobu Inoue 116882cd038dSYoshinobu Inoue if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 116982cd038dSYoshinobu Inoue bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 117082cd038dSYoshinobu Inoue ia->ia_dstaddr.sin6_len); 117182cd038dSYoshinobu Inoue } else 117282cd038dSYoshinobu Inoue bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 117382cd038dSYoshinobu Inoue 117482cd038dSYoshinobu Inoue iflr->prefixlen = 117582cd038dSYoshinobu Inoue in6_mask2len(&ia->ia_prefixmask.sin6_addr); 117682cd038dSYoshinobu Inoue 117782cd038dSYoshinobu Inoue iflr->flags = ia->ia6_flags; /*XXX*/ 117882cd038dSYoshinobu Inoue 117982cd038dSYoshinobu Inoue return 0; 118082cd038dSYoshinobu Inoue } else { 118182cd038dSYoshinobu Inoue struct in6_aliasreq ifra; 118282cd038dSYoshinobu Inoue 118382cd038dSYoshinobu Inoue /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 118482cd038dSYoshinobu Inoue bzero(&ifra, sizeof(ifra)); 118582cd038dSYoshinobu Inoue bcopy(iflr->iflr_name, ifra.ifra_name, 118682cd038dSYoshinobu Inoue sizeof(ifra.ifra_name)); 118782cd038dSYoshinobu Inoue 118882cd038dSYoshinobu Inoue bcopy(&ia->ia_addr, &ifra.ifra_addr, 118982cd038dSYoshinobu Inoue ia->ia_addr.sin6_len); 119082cd038dSYoshinobu Inoue if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 119182cd038dSYoshinobu Inoue bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 119282cd038dSYoshinobu Inoue ia->ia_dstaddr.sin6_len); 1193686cdd19SJun-ichiro itojun Hagino } else { 1194686cdd19SJun-ichiro itojun Hagino bzero(&ifra.ifra_dstaddr, 1195686cdd19SJun-ichiro itojun Hagino sizeof(ifra.ifra_dstaddr)); 119682cd038dSYoshinobu Inoue } 119782cd038dSYoshinobu Inoue bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr, 119882cd038dSYoshinobu Inoue ia->ia_prefixmask.sin6_len); 119982cd038dSYoshinobu Inoue 120082cd038dSYoshinobu Inoue ifra.ifra_flags = ia->ia6_flags; 120182cd038dSYoshinobu Inoue return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, 120282cd038dSYoshinobu Inoue ifp, p); 120382cd038dSYoshinobu Inoue } 120482cd038dSYoshinobu Inoue } 120582cd038dSYoshinobu Inoue } 120682cd038dSYoshinobu Inoue 120782cd038dSYoshinobu Inoue return EOPNOTSUPP; /*just for safety*/ 120882cd038dSYoshinobu Inoue } 120982cd038dSYoshinobu Inoue 121082cd038dSYoshinobu Inoue /* 121182cd038dSYoshinobu Inoue * Delete any existing route for an interface. 121282cd038dSYoshinobu Inoue */ 121382cd038dSYoshinobu Inoue void 121482cd038dSYoshinobu Inoue in6_ifscrub(ifp, ia) 121582cd038dSYoshinobu Inoue register struct ifnet *ifp; 121682cd038dSYoshinobu Inoue register struct in6_ifaddr *ia; 121782cd038dSYoshinobu Inoue { 121882cd038dSYoshinobu Inoue if ((ia->ia_flags & IFA_ROUTE) == 0) 121982cd038dSYoshinobu Inoue return; 122082cd038dSYoshinobu Inoue if (ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) 122182cd038dSYoshinobu Inoue rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 122282cd038dSYoshinobu Inoue else 122382cd038dSYoshinobu Inoue rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 122482cd038dSYoshinobu Inoue ia->ia_flags &= ~IFA_ROUTE; 122582cd038dSYoshinobu Inoue 122682cd038dSYoshinobu Inoue /* Remove ownaddr's loopback rtentry, if it exists. */ 122782cd038dSYoshinobu Inoue in6_ifremloop(&(ia->ia_ifa)); 122882cd038dSYoshinobu Inoue } 122982cd038dSYoshinobu Inoue 123082cd038dSYoshinobu Inoue /* 123182cd038dSYoshinobu Inoue * Initialize an interface's intetnet6 address 123282cd038dSYoshinobu Inoue * and routing table entry. 123382cd038dSYoshinobu Inoue */ 123482cd038dSYoshinobu Inoue int 123582cd038dSYoshinobu Inoue in6_ifinit(ifp, ia, sin6, scrub) 123682cd038dSYoshinobu Inoue struct ifnet *ifp; 123782cd038dSYoshinobu Inoue struct in6_ifaddr *ia; 123882cd038dSYoshinobu Inoue struct sockaddr_in6 *sin6; 123982cd038dSYoshinobu Inoue int scrub; 124082cd038dSYoshinobu Inoue { 124182cd038dSYoshinobu Inoue struct sockaddr_in6 oldaddr; 124282cd038dSYoshinobu Inoue int error, flags = RTF_UP; 124382cd038dSYoshinobu Inoue int s = splimp(); 124482cd038dSYoshinobu Inoue 124582cd038dSYoshinobu Inoue oldaddr = ia->ia_addr; 124682cd038dSYoshinobu Inoue ia->ia_addr = *sin6; 124782cd038dSYoshinobu Inoue /* 124882cd038dSYoshinobu Inoue * Give the interface a chance to initialize 124982cd038dSYoshinobu Inoue * if this is its first address, 125082cd038dSYoshinobu Inoue * and to validate the address if necessary. 125182cd038dSYoshinobu Inoue */ 125282cd038dSYoshinobu Inoue if (ifp->if_ioctl && 125382cd038dSYoshinobu Inoue (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { 125482cd038dSYoshinobu Inoue splx(s); 125582cd038dSYoshinobu Inoue ia->ia_addr = oldaddr; 125682cd038dSYoshinobu Inoue return(error); 125782cd038dSYoshinobu Inoue } 125882cd038dSYoshinobu Inoue 125982cd038dSYoshinobu Inoue switch (ifp->if_type) { 126082cd038dSYoshinobu Inoue case IFT_ARCNET: 126182cd038dSYoshinobu Inoue case IFT_ETHER: 126282cd038dSYoshinobu Inoue case IFT_FDDI: 126382cd038dSYoshinobu Inoue ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; 126482cd038dSYoshinobu Inoue ia->ia_ifa.ifa_flags |= RTF_CLONING; 126582cd038dSYoshinobu Inoue break; 126682cd038dSYoshinobu Inoue case IFT_PPP: 126782cd038dSYoshinobu Inoue ia->ia_ifa.ifa_rtrequest = nd6_p2p_rtrequest; 126882cd038dSYoshinobu Inoue ia->ia_ifa.ifa_flags |= RTF_CLONING; 126982cd038dSYoshinobu Inoue break; 127082cd038dSYoshinobu Inoue } 127182cd038dSYoshinobu Inoue 127282cd038dSYoshinobu Inoue splx(s); 127382cd038dSYoshinobu Inoue if (scrub) { 127482cd038dSYoshinobu Inoue ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 127582cd038dSYoshinobu Inoue in6_ifscrub(ifp, ia); 127682cd038dSYoshinobu Inoue ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 127782cd038dSYoshinobu Inoue } 127882cd038dSYoshinobu Inoue /* xxx 127982cd038dSYoshinobu Inoue * in_socktrim 128082cd038dSYoshinobu Inoue */ 128182cd038dSYoshinobu Inoue /* 128282cd038dSYoshinobu Inoue * Add route for the network. 128382cd038dSYoshinobu Inoue */ 128482cd038dSYoshinobu Inoue ia->ia_ifa.ifa_metric = ifp->if_metric; 128582cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_LOOPBACK) { 128682cd038dSYoshinobu Inoue ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; 128782cd038dSYoshinobu Inoue flags |= RTF_HOST; 128882cd038dSYoshinobu Inoue } else if (ifp->if_flags & IFF_POINTOPOINT) { 128982cd038dSYoshinobu Inoue if (ia->ia_dstaddr.sin6_family != AF_INET6) 129082cd038dSYoshinobu Inoue return(0); 129182cd038dSYoshinobu Inoue flags |= RTF_HOST; 129282cd038dSYoshinobu Inoue } 129382cd038dSYoshinobu Inoue if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) 129482cd038dSYoshinobu Inoue ia->ia_flags |= IFA_ROUTE; 1295686cdd19SJun-ichiro itojun Hagino /* XXX check if the subnet route points to the same interface */ 1296686cdd19SJun-ichiro itojun Hagino if (error == EEXIST) 1297686cdd19SJun-ichiro itojun Hagino error = 0; 129882cd038dSYoshinobu Inoue 129982cd038dSYoshinobu Inoue /* Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). */ 130082cd038dSYoshinobu Inoue in6_ifaddloop(&(ia->ia_ifa)); 130182cd038dSYoshinobu Inoue 130282cd038dSYoshinobu Inoue return(error); 130382cd038dSYoshinobu Inoue } 130482cd038dSYoshinobu Inoue 130582cd038dSYoshinobu Inoue /* 130682cd038dSYoshinobu Inoue * Add an address to the list of IP6 multicast addresses for a 130782cd038dSYoshinobu Inoue * given interface. 130882cd038dSYoshinobu Inoue */ 130982cd038dSYoshinobu Inoue struct in6_multi * 131082cd038dSYoshinobu Inoue in6_addmulti(maddr6, ifp, errorp) 131182cd038dSYoshinobu Inoue register struct in6_addr *maddr6; 131282cd038dSYoshinobu Inoue register struct ifnet *ifp; 131382cd038dSYoshinobu Inoue int *errorp; 131482cd038dSYoshinobu Inoue { 131582cd038dSYoshinobu Inoue struct in6_multi *in6m; 131682cd038dSYoshinobu Inoue struct sockaddr_in6 sin6; 131782cd038dSYoshinobu Inoue struct ifmultiaddr *ifma; 131882cd038dSYoshinobu Inoue int s = splnet(); 131982cd038dSYoshinobu Inoue 132082cd038dSYoshinobu Inoue *errorp = 0; 132182cd038dSYoshinobu Inoue 132282cd038dSYoshinobu Inoue /* 132382cd038dSYoshinobu Inoue * Call generic routine to add membership or increment 132482cd038dSYoshinobu Inoue * refcount. It wants addresses in the form of a sockaddr, 132582cd038dSYoshinobu Inoue * so we build one here (being careful to zero the unused bytes). 132682cd038dSYoshinobu Inoue */ 132782cd038dSYoshinobu Inoue bzero(&sin6, sizeof sin6); 132882cd038dSYoshinobu Inoue sin6.sin6_family = AF_INET6; 132982cd038dSYoshinobu Inoue sin6.sin6_len = sizeof sin6; 133082cd038dSYoshinobu Inoue sin6.sin6_addr = *maddr6; 133182cd038dSYoshinobu Inoue *errorp = if_addmulti(ifp, (struct sockaddr *)&sin6, &ifma); 133282cd038dSYoshinobu Inoue if (*errorp) { 133382cd038dSYoshinobu Inoue splx(s); 133482cd038dSYoshinobu Inoue return 0; 133582cd038dSYoshinobu Inoue } 133682cd038dSYoshinobu Inoue 133782cd038dSYoshinobu Inoue /* 133882cd038dSYoshinobu Inoue * If ifma->ifma_protospec is null, then if_addmulti() created 133982cd038dSYoshinobu Inoue * a new record. Otherwise, we are done. 134082cd038dSYoshinobu Inoue */ 134182cd038dSYoshinobu Inoue if (ifma->ifma_protospec != 0) 134282cd038dSYoshinobu Inoue return ifma->ifma_protospec; 134382cd038dSYoshinobu Inoue 134482cd038dSYoshinobu Inoue /* XXX - if_addmulti uses M_WAITOK. Can this really be called 134582cd038dSYoshinobu Inoue at interrupt time? If so, need to fix if_addmulti. XXX */ 134682cd038dSYoshinobu Inoue in6m = (struct in6_multi *)malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT); 134782cd038dSYoshinobu Inoue if (in6m == NULL) { 134882cd038dSYoshinobu Inoue splx(s); 134982cd038dSYoshinobu Inoue return (NULL); 135082cd038dSYoshinobu Inoue } 135182cd038dSYoshinobu Inoue 135282cd038dSYoshinobu Inoue bzero(in6m, sizeof *in6m); 135382cd038dSYoshinobu Inoue in6m->in6m_addr = *maddr6; 135482cd038dSYoshinobu Inoue in6m->in6m_ifp = ifp; 135582cd038dSYoshinobu Inoue in6m->in6m_ifma = ifma; 135682cd038dSYoshinobu Inoue ifma->ifma_protospec = in6m; 135782cd038dSYoshinobu Inoue LIST_INSERT_HEAD(&in6_multihead, in6m, in6m_entry); 135882cd038dSYoshinobu Inoue 135982cd038dSYoshinobu Inoue /* 136082cd038dSYoshinobu Inoue * Let MLD6 know that we have joined a new IP6 multicast 136182cd038dSYoshinobu Inoue * group. 136282cd038dSYoshinobu Inoue */ 136382cd038dSYoshinobu Inoue mld6_start_listening(in6m); 136482cd038dSYoshinobu Inoue splx(s); 136582cd038dSYoshinobu Inoue return(in6m); 136682cd038dSYoshinobu Inoue } 136782cd038dSYoshinobu Inoue 136882cd038dSYoshinobu Inoue /* 136982cd038dSYoshinobu Inoue * Delete a multicast address record. 137082cd038dSYoshinobu Inoue */ 137182cd038dSYoshinobu Inoue void 137282cd038dSYoshinobu Inoue in6_delmulti(in6m) 137382cd038dSYoshinobu Inoue struct in6_multi *in6m; 137482cd038dSYoshinobu Inoue { 137582cd038dSYoshinobu Inoue struct ifmultiaddr *ifma = in6m->in6m_ifma; 137682cd038dSYoshinobu Inoue int s = splnet(); 137782cd038dSYoshinobu Inoue 137882cd038dSYoshinobu Inoue if (ifma->ifma_refcount == 1) { 137982cd038dSYoshinobu Inoue /* 138082cd038dSYoshinobu Inoue * No remaining claims to this record; let MLD6 know 138182cd038dSYoshinobu Inoue * that we are leaving the multicast group. 138282cd038dSYoshinobu Inoue */ 138382cd038dSYoshinobu Inoue mld6_stop_listening(in6m); 138482cd038dSYoshinobu Inoue ifma->ifma_protospec = 0; 138582cd038dSYoshinobu Inoue LIST_REMOVE(in6m, in6m_entry); 138682cd038dSYoshinobu Inoue free(in6m, M_IPMADDR); 138782cd038dSYoshinobu Inoue } 138882cd038dSYoshinobu Inoue /* XXX - should be separate API for when we have an ifma? */ 138982cd038dSYoshinobu Inoue if_delmulti(ifma->ifma_ifp, ifma->ifma_addr); 139082cd038dSYoshinobu Inoue splx(s); 139182cd038dSYoshinobu Inoue } 139282cd038dSYoshinobu Inoue 139382cd038dSYoshinobu Inoue /* 139482cd038dSYoshinobu Inoue * Find an IPv6 interface link-local address specific to an interface. 139582cd038dSYoshinobu Inoue */ 139682cd038dSYoshinobu Inoue struct in6_ifaddr * 1397686cdd19SJun-ichiro itojun Hagino in6ifa_ifpforlinklocal(ifp, ignoreflags) 139882cd038dSYoshinobu Inoue struct ifnet *ifp; 1399686cdd19SJun-ichiro itojun Hagino int ignoreflags; 140082cd038dSYoshinobu Inoue { 140182cd038dSYoshinobu Inoue register struct ifaddr *ifa; 140282cd038dSYoshinobu Inoue 1403cfa1ca9dSYoshinobu Inoue TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 140482cd038dSYoshinobu Inoue { 140582cd038dSYoshinobu Inoue if (ifa->ifa_addr == NULL) 140682cd038dSYoshinobu Inoue continue; /* just for safety */ 140782cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6) 140882cd038dSYoshinobu Inoue continue; 1409686cdd19SJun-ichiro itojun Hagino if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { 1410686cdd19SJun-ichiro itojun Hagino if ((((struct in6_ifaddr *)ifa)->ia6_flags & 1411686cdd19SJun-ichiro itojun Hagino ignoreflags) != 0) 1412686cdd19SJun-ichiro itojun Hagino continue; 141382cd038dSYoshinobu Inoue break; 141482cd038dSYoshinobu Inoue } 1415686cdd19SJun-ichiro itojun Hagino } 141682cd038dSYoshinobu Inoue 141782cd038dSYoshinobu Inoue return((struct in6_ifaddr *)ifa); 141882cd038dSYoshinobu Inoue } 141982cd038dSYoshinobu Inoue 142082cd038dSYoshinobu Inoue 142182cd038dSYoshinobu Inoue /* 142282cd038dSYoshinobu Inoue * find the internet address corresponding to a given interface and address. 142382cd038dSYoshinobu Inoue */ 142482cd038dSYoshinobu Inoue struct in6_ifaddr * 142582cd038dSYoshinobu Inoue in6ifa_ifpwithaddr(ifp, addr) 142682cd038dSYoshinobu Inoue struct ifnet *ifp; 142782cd038dSYoshinobu Inoue struct in6_addr *addr; 142882cd038dSYoshinobu Inoue { 142982cd038dSYoshinobu Inoue register struct ifaddr *ifa; 143082cd038dSYoshinobu Inoue 1431cfa1ca9dSYoshinobu Inoue TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 143282cd038dSYoshinobu Inoue { 143382cd038dSYoshinobu Inoue if (ifa->ifa_addr == NULL) 143482cd038dSYoshinobu Inoue continue; /* just for safety */ 143582cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6) 143682cd038dSYoshinobu Inoue continue; 143782cd038dSYoshinobu Inoue if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) 143882cd038dSYoshinobu Inoue break; 143982cd038dSYoshinobu Inoue } 144082cd038dSYoshinobu Inoue 144182cd038dSYoshinobu Inoue return((struct in6_ifaddr *)ifa); 144282cd038dSYoshinobu Inoue } 144382cd038dSYoshinobu Inoue 144482cd038dSYoshinobu Inoue /* 144582cd038dSYoshinobu Inoue * Convert IP6 address to printable (loggable) representation. 144682cd038dSYoshinobu Inoue */ 144782cd038dSYoshinobu Inoue static char digits[] = "0123456789abcdef"; 144882cd038dSYoshinobu Inoue static int ip6round = 0; 144982cd038dSYoshinobu Inoue char * 145082cd038dSYoshinobu Inoue ip6_sprintf(addr) 145182cd038dSYoshinobu Inoue register struct in6_addr *addr; 145282cd038dSYoshinobu Inoue { 145382cd038dSYoshinobu Inoue static char ip6buf[8][48]; 145482cd038dSYoshinobu Inoue register int i; 145582cd038dSYoshinobu Inoue register char *cp; 145682cd038dSYoshinobu Inoue register u_short *a = (u_short *)addr; 145782cd038dSYoshinobu Inoue register u_char *d; 145882cd038dSYoshinobu Inoue int dcolon = 0; 145982cd038dSYoshinobu Inoue 146082cd038dSYoshinobu Inoue ip6round = (ip6round + 1) & 7; 146182cd038dSYoshinobu Inoue cp = ip6buf[ip6round]; 146282cd038dSYoshinobu Inoue 146382cd038dSYoshinobu Inoue for (i = 0; i < 8; i++) { 146482cd038dSYoshinobu Inoue if (dcolon == 1) { 146582cd038dSYoshinobu Inoue if (*a == 0) { 146682cd038dSYoshinobu Inoue if (i == 7) 146782cd038dSYoshinobu Inoue *cp++ = ':'; 146882cd038dSYoshinobu Inoue a++; 146982cd038dSYoshinobu Inoue continue; 147082cd038dSYoshinobu Inoue } else 147182cd038dSYoshinobu Inoue dcolon = 2; 147282cd038dSYoshinobu Inoue } 147382cd038dSYoshinobu Inoue if (*a == 0) { 147482cd038dSYoshinobu Inoue if (dcolon == 0 && *(a + 1) == 0) { 147582cd038dSYoshinobu Inoue if (i == 0) 147682cd038dSYoshinobu Inoue *cp++ = ':'; 147782cd038dSYoshinobu Inoue *cp++ = ':'; 147882cd038dSYoshinobu Inoue dcolon = 1; 147982cd038dSYoshinobu Inoue } else { 148082cd038dSYoshinobu Inoue *cp++ = '0'; 148182cd038dSYoshinobu Inoue *cp++ = ':'; 148282cd038dSYoshinobu Inoue } 148382cd038dSYoshinobu Inoue a++; 148482cd038dSYoshinobu Inoue continue; 148582cd038dSYoshinobu Inoue } 148682cd038dSYoshinobu Inoue d = (u_char *)a; 148782cd038dSYoshinobu Inoue *cp++ = digits[*d >> 4]; 148882cd038dSYoshinobu Inoue *cp++ = digits[*d++ & 0xf]; 148982cd038dSYoshinobu Inoue *cp++ = digits[*d >> 4]; 149082cd038dSYoshinobu Inoue *cp++ = digits[*d & 0xf]; 149182cd038dSYoshinobu Inoue *cp++ = ':'; 149282cd038dSYoshinobu Inoue a++; 149382cd038dSYoshinobu Inoue } 149482cd038dSYoshinobu Inoue *--cp = 0; 149582cd038dSYoshinobu Inoue return(ip6buf[ip6round]); 149682cd038dSYoshinobu Inoue } 149782cd038dSYoshinobu Inoue 149882cd038dSYoshinobu Inoue int 149982cd038dSYoshinobu Inoue in6_localaddr(in6) 150082cd038dSYoshinobu Inoue struct in6_addr *in6; 150182cd038dSYoshinobu Inoue { 150282cd038dSYoshinobu Inoue struct in6_ifaddr *ia; 150382cd038dSYoshinobu Inoue 150482cd038dSYoshinobu Inoue if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6)) 150582cd038dSYoshinobu Inoue return 1; 150682cd038dSYoshinobu Inoue 150782cd038dSYoshinobu Inoue for (ia = in6_ifaddr; ia; ia = ia->ia_next) 150882cd038dSYoshinobu Inoue if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr, 150982cd038dSYoshinobu Inoue &ia->ia_prefixmask.sin6_addr)) 151082cd038dSYoshinobu Inoue return 1; 151182cd038dSYoshinobu Inoue 151282cd038dSYoshinobu Inoue return (0); 151382cd038dSYoshinobu Inoue } 151482cd038dSYoshinobu Inoue 151582cd038dSYoshinobu Inoue /* 151682cd038dSYoshinobu Inoue * return length of part which dst and src are equal 151782cd038dSYoshinobu Inoue * hard coding... 151882cd038dSYoshinobu Inoue */ 151982cd038dSYoshinobu Inoue int 152082cd038dSYoshinobu Inoue in6_matchlen(src, dst) 152182cd038dSYoshinobu Inoue struct in6_addr *src, *dst; 152282cd038dSYoshinobu Inoue { 152382cd038dSYoshinobu Inoue int match = 0; 152482cd038dSYoshinobu Inoue u_char *s = (u_char *)src, *d = (u_char *)dst; 152582cd038dSYoshinobu Inoue u_char *lim = s + 16, r; 152682cd038dSYoshinobu Inoue 152782cd038dSYoshinobu Inoue while (s < lim) 152882cd038dSYoshinobu Inoue if ((r = (*d++ ^ *s++)) != 0) { 152982cd038dSYoshinobu Inoue while (r < 128) { 153082cd038dSYoshinobu Inoue match++; 153182cd038dSYoshinobu Inoue r <<= 1; 153282cd038dSYoshinobu Inoue } 153382cd038dSYoshinobu Inoue break; 153482cd038dSYoshinobu Inoue } else 153582cd038dSYoshinobu Inoue match += 8; 153682cd038dSYoshinobu Inoue return match; 153782cd038dSYoshinobu Inoue } 153882cd038dSYoshinobu Inoue 1539686cdd19SJun-ichiro itojun Hagino /* XXX: to be scope conscious */ 154082cd038dSYoshinobu Inoue int 154182cd038dSYoshinobu Inoue in6_are_prefix_equal(p1, p2, len) 154282cd038dSYoshinobu Inoue struct in6_addr *p1, *p2; 154382cd038dSYoshinobu Inoue int len; 154482cd038dSYoshinobu Inoue { 154582cd038dSYoshinobu Inoue int bytelen, bitlen; 154682cd038dSYoshinobu Inoue 154782cd038dSYoshinobu Inoue /* sanity check */ 154882cd038dSYoshinobu Inoue if (0 > len || len > 128) { 154982cd038dSYoshinobu Inoue log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n", 155082cd038dSYoshinobu Inoue len); 155182cd038dSYoshinobu Inoue return(0); 155282cd038dSYoshinobu Inoue } 155382cd038dSYoshinobu Inoue 155482cd038dSYoshinobu Inoue bytelen = len / 8; 155582cd038dSYoshinobu Inoue bitlen = len % 8; 155682cd038dSYoshinobu Inoue 155782cd038dSYoshinobu Inoue if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen)) 155882cd038dSYoshinobu Inoue return(0); 155982cd038dSYoshinobu Inoue if (p1->s6_addr[bytelen] >> (8 - bitlen) != 156082cd038dSYoshinobu Inoue p2->s6_addr[bytelen] >> (8 - bitlen)) 156182cd038dSYoshinobu Inoue return(0); 156282cd038dSYoshinobu Inoue 156382cd038dSYoshinobu Inoue return(1); 156482cd038dSYoshinobu Inoue } 156582cd038dSYoshinobu Inoue 156682cd038dSYoshinobu Inoue void 156782cd038dSYoshinobu Inoue in6_prefixlen2mask(maskp, len) 156882cd038dSYoshinobu Inoue struct in6_addr *maskp; 156982cd038dSYoshinobu Inoue int len; 157082cd038dSYoshinobu Inoue { 157182cd038dSYoshinobu Inoue u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 157282cd038dSYoshinobu Inoue int bytelen, bitlen, i; 157382cd038dSYoshinobu Inoue 157482cd038dSYoshinobu Inoue /* sanity check */ 157582cd038dSYoshinobu Inoue if (0 > len || len > 128) { 157682cd038dSYoshinobu Inoue log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n", 157782cd038dSYoshinobu Inoue len); 157882cd038dSYoshinobu Inoue return; 157982cd038dSYoshinobu Inoue } 158082cd038dSYoshinobu Inoue 158182cd038dSYoshinobu Inoue bzero(maskp, sizeof(*maskp)); 158282cd038dSYoshinobu Inoue bytelen = len / 8; 158382cd038dSYoshinobu Inoue bitlen = len % 8; 158482cd038dSYoshinobu Inoue for (i = 0; i < bytelen; i++) 158582cd038dSYoshinobu Inoue maskp->s6_addr[i] = 0xff; 158682cd038dSYoshinobu Inoue if (bitlen) 158782cd038dSYoshinobu Inoue maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 158882cd038dSYoshinobu Inoue } 158982cd038dSYoshinobu Inoue 159082cd038dSYoshinobu Inoue /* 159182cd038dSYoshinobu Inoue * return the best address out of the same scope 159282cd038dSYoshinobu Inoue */ 159382cd038dSYoshinobu Inoue struct in6_ifaddr * 1594686cdd19SJun-ichiro itojun Hagino in6_ifawithscope(oifp, dst) 1595686cdd19SJun-ichiro itojun Hagino register struct ifnet *oifp; 159682cd038dSYoshinobu Inoue register struct in6_addr *dst; 159782cd038dSYoshinobu Inoue { 1598686cdd19SJun-ichiro itojun Hagino int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0; 1599686cdd19SJun-ichiro itojun Hagino int blen = -1; 160082cd038dSYoshinobu Inoue struct ifaddr *ifa; 1601686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 1602686cdd19SJun-ichiro itojun Hagino struct in6_ifaddr *ifa_best = NULL; 160382cd038dSYoshinobu Inoue 1604686cdd19SJun-ichiro itojun Hagino if (oifp == NULL) { 1605686cdd19SJun-ichiro itojun Hagino printf("in6_ifawithscope: output interface is not specified\n"); 1606686cdd19SJun-ichiro itojun Hagino return(NULL); 1607686cdd19SJun-ichiro itojun Hagino } 160882cd038dSYoshinobu Inoue 160982cd038dSYoshinobu Inoue /* 1610686cdd19SJun-ichiro itojun Hagino * We search for all addresses on all interfaces from the beginning. 1611686cdd19SJun-ichiro itojun Hagino * Comparing an interface with the outgoing interface will be done 1612686cdd19SJun-ichiro itojun Hagino * only at the final stage of tiebreaking. 161382cd038dSYoshinobu Inoue */ 1614686cdd19SJun-ichiro itojun Hagino for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) 1615686cdd19SJun-ichiro itojun Hagino { 1616686cdd19SJun-ichiro itojun Hagino /* 1617686cdd19SJun-ichiro itojun Hagino * We can never take an address that breaks the scope zone 1618686cdd19SJun-ichiro itojun Hagino * of the destination. 1619686cdd19SJun-ichiro itojun Hagino */ 1620686cdd19SJun-ichiro itojun Hagino if (in6_addr2scopeid(ifp, dst) != in6_addr2scopeid(oifp, dst)) 1621686cdd19SJun-ichiro itojun Hagino continue; 1622686cdd19SJun-ichiro itojun Hagino 1623cfa1ca9dSYoshinobu Inoue TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 162482cd038dSYoshinobu Inoue { 1625686cdd19SJun-ichiro itojun Hagino int tlen = -1, dscopecmp, bscopecmp, matchcmp; 1626686cdd19SJun-ichiro itojun Hagino 162782cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6) 162882cd038dSYoshinobu Inoue continue; 162982cd038dSYoshinobu Inoue 1630686cdd19SJun-ichiro itojun Hagino src_scope = in6_addrscope(IFA_IN6(ifa)); 1631686cdd19SJun-ichiro itojun Hagino 163282cd038dSYoshinobu Inoue /* 1633686cdd19SJun-ichiro itojun Hagino * Don't use an address before completing DAD 1634686cdd19SJun-ichiro itojun Hagino * nor a duplicated address. 163582cd038dSYoshinobu Inoue */ 1636686cdd19SJun-ichiro itojun Hagino if (((struct in6_ifaddr *)ifa)->ia6_flags & 1637686cdd19SJun-ichiro itojun Hagino IN6_IFF_NOTREADY) 1638686cdd19SJun-ichiro itojun Hagino continue; 1639686cdd19SJun-ichiro itojun Hagino 1640686cdd19SJun-ichiro itojun Hagino /* XXX: is there any case to allow anycasts? */ 1641686cdd19SJun-ichiro itojun Hagino if (((struct in6_ifaddr *)ifa)->ia6_flags & 1642686cdd19SJun-ichiro itojun Hagino IN6_IFF_ANYCAST) 1643686cdd19SJun-ichiro itojun Hagino continue; 1644686cdd19SJun-ichiro itojun Hagino 1645686cdd19SJun-ichiro itojun Hagino if (((struct in6_ifaddr *)ifa)->ia6_flags & 1646686cdd19SJun-ichiro itojun Hagino IN6_IFF_DETACHED) 1647686cdd19SJun-ichiro itojun Hagino continue; 1648686cdd19SJun-ichiro itojun Hagino 1649686cdd19SJun-ichiro itojun Hagino /* 1650686cdd19SJun-ichiro itojun Hagino * If this is the first address we find, 1651686cdd19SJun-ichiro itojun Hagino * keep it anyway. 1652686cdd19SJun-ichiro itojun Hagino */ 1653686cdd19SJun-ichiro itojun Hagino if (ifa_best == NULL) 1654686cdd19SJun-ichiro itojun Hagino goto replace; 1655686cdd19SJun-ichiro itojun Hagino 1656686cdd19SJun-ichiro itojun Hagino /* 1657686cdd19SJun-ichiro itojun Hagino * ifa_best is never NULL beyond this line except 1658686cdd19SJun-ichiro itojun Hagino * within the block labeled "replace". 1659686cdd19SJun-ichiro itojun Hagino */ 1660686cdd19SJun-ichiro itojun Hagino 1661686cdd19SJun-ichiro itojun Hagino /* 1662686cdd19SJun-ichiro itojun Hagino * If ifa_best has a smaller scope than dst and 1663686cdd19SJun-ichiro itojun Hagino * the current address has a larger one than 1664686cdd19SJun-ichiro itojun Hagino * (or equal to) dst, always replace ifa_best. 1665686cdd19SJun-ichiro itojun Hagino * Also, if the current address has a smaller scope 1666686cdd19SJun-ichiro itojun Hagino * than dst, ignore it unless ifa_best also has a 1667686cdd19SJun-ichiro itojun Hagino * smaller scope. 1668686cdd19SJun-ichiro itojun Hagino */ 1669686cdd19SJun-ichiro itojun Hagino if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 && 1670686cdd19SJun-ichiro itojun Hagino IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0) 1671686cdd19SJun-ichiro itojun Hagino goto replace; 1672686cdd19SJun-ichiro itojun Hagino if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 && 1673686cdd19SJun-ichiro itojun Hagino IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0) 1674686cdd19SJun-ichiro itojun Hagino continue; 1675686cdd19SJun-ichiro itojun Hagino 1676686cdd19SJun-ichiro itojun Hagino /* 1677686cdd19SJun-ichiro itojun Hagino * A deprecated address SHOULD NOT be used in new 1678686cdd19SJun-ichiro itojun Hagino * communications if an alternate (non-deprecated) 1679686cdd19SJun-ichiro itojun Hagino * address is available and has sufficient scope. 1680686cdd19SJun-ichiro itojun Hagino * RFC 2462, Section 5.5.4. 1681686cdd19SJun-ichiro itojun Hagino */ 1682686cdd19SJun-ichiro itojun Hagino if (((struct in6_ifaddr *)ifa)->ia6_flags & 1683686cdd19SJun-ichiro itojun Hagino IN6_IFF_DEPRECATED) { 1684686cdd19SJun-ichiro itojun Hagino /* 1685686cdd19SJun-ichiro itojun Hagino * Ignore any deprecated addresses if 1686686cdd19SJun-ichiro itojun Hagino * specified by configuration. 1687686cdd19SJun-ichiro itojun Hagino */ 1688686cdd19SJun-ichiro itojun Hagino if (!ip6_use_deprecated) 1689686cdd19SJun-ichiro itojun Hagino continue; 1690686cdd19SJun-ichiro itojun Hagino 1691686cdd19SJun-ichiro itojun Hagino /* 1692686cdd19SJun-ichiro itojun Hagino * If we have already found a non-deprecated 1693686cdd19SJun-ichiro itojun Hagino * candidate, just ignore deprecated addresses. 1694686cdd19SJun-ichiro itojun Hagino */ 1695686cdd19SJun-ichiro itojun Hagino if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) 1696686cdd19SJun-ichiro itojun Hagino == 0) 1697686cdd19SJun-ichiro itojun Hagino continue; 1698686cdd19SJun-ichiro itojun Hagino } 1699686cdd19SJun-ichiro itojun Hagino 1700686cdd19SJun-ichiro itojun Hagino /* 1701686cdd19SJun-ichiro itojun Hagino * A non-deprecated address is always preferred 1702686cdd19SJun-ichiro itojun Hagino * to a deprecated one regardless of scopes and 1703686cdd19SJun-ichiro itojun Hagino * address matching. 1704686cdd19SJun-ichiro itojun Hagino */ 1705686cdd19SJun-ichiro itojun Hagino if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) && 1706686cdd19SJun-ichiro itojun Hagino (((struct in6_ifaddr *)ifa)->ia6_flags & 1707686cdd19SJun-ichiro itojun Hagino IN6_IFF_DEPRECATED) == 0) 1708686cdd19SJun-ichiro itojun Hagino goto replace; 1709686cdd19SJun-ichiro itojun Hagino 1710686cdd19SJun-ichiro itojun Hagino /* 1711686cdd19SJun-ichiro itojun Hagino * At this point, we have two cases: 1712686cdd19SJun-ichiro itojun Hagino * 1. we are looking at a non-deprecated address, 1713686cdd19SJun-ichiro itojun Hagino * and ifa_best is also non-deprecated. 1714686cdd19SJun-ichiro itojun Hagino * 2. we are looking at a deprecated address, 1715686cdd19SJun-ichiro itojun Hagino * and ifa_best is also deprecated. 1716686cdd19SJun-ichiro itojun Hagino * Also, we do not have to consider a case where 1717686cdd19SJun-ichiro itojun Hagino * the scope of if_best is larger(smaller) than dst and 1718686cdd19SJun-ichiro itojun Hagino * the scope of the current address is smaller(larger) 1719686cdd19SJun-ichiro itojun Hagino * than dst. Such a case has already been covered. 1720686cdd19SJun-ichiro itojun Hagino * Tiebreaking is done according to the following 1721686cdd19SJun-ichiro itojun Hagino * items: 1722686cdd19SJun-ichiro itojun Hagino * - the scope comparison between the address and 1723686cdd19SJun-ichiro itojun Hagino * dst (dscopecmp) 1724686cdd19SJun-ichiro itojun Hagino * - the scope comparison between the address and 1725686cdd19SJun-ichiro itojun Hagino * ifa_best (bscopecmp) 1726686cdd19SJun-ichiro itojun Hagino * - if the address match dst longer than ifa_best 1727686cdd19SJun-ichiro itojun Hagino * (matchcmp) 1728686cdd19SJun-ichiro itojun Hagino * - if the address is on the outgoing I/F (outI/F) 1729686cdd19SJun-ichiro itojun Hagino * 1730686cdd19SJun-ichiro itojun Hagino * Roughly speaking, the selection policy is 1731686cdd19SJun-ichiro itojun Hagino * - the most important item is scope. The same scope 1732686cdd19SJun-ichiro itojun Hagino * is best. Then search for a larger scope. 1733686cdd19SJun-ichiro itojun Hagino * Smaller scopes are the last resort. 1734686cdd19SJun-ichiro itojun Hagino * - A deprecated address is chosen only when we have 1735686cdd19SJun-ichiro itojun Hagino * no address that has an enough scope, but is 1736686cdd19SJun-ichiro itojun Hagino * prefered to any addresses of smaller scopes. 1737686cdd19SJun-ichiro itojun Hagino * - Longest address match against dst is considered 1738686cdd19SJun-ichiro itojun Hagino * only for addresses that has the same scope of dst. 1739686cdd19SJun-ichiro itojun Hagino * - If there is no other reasons to choose one, 1740686cdd19SJun-ichiro itojun Hagino * addresses on the outgoing I/F are preferred. 1741686cdd19SJun-ichiro itojun Hagino * 1742686cdd19SJun-ichiro itojun Hagino * The precise decision table is as follows: 1743686cdd19SJun-ichiro itojun Hagino * dscopecmp bscopecmp matchcmp outI/F | replace? 1744686cdd19SJun-ichiro itojun Hagino * !equal equal N/A Yes | Yes (1) 1745686cdd19SJun-ichiro itojun Hagino * !equal equal N/A No | No (2) 1746686cdd19SJun-ichiro itojun Hagino * larger larger N/A N/A | No (3) 1747686cdd19SJun-ichiro itojun Hagino * larger smaller N/A N/A | Yes (4) 1748686cdd19SJun-ichiro itojun Hagino * smaller larger N/A N/A | Yes (5) 1749686cdd19SJun-ichiro itojun Hagino * smaller smaller N/A N/A | No (6) 1750686cdd19SJun-ichiro itojun Hagino * equal smaller N/A N/A | Yes (7) 1751686cdd19SJun-ichiro itojun Hagino * equal larger (already done) 1752686cdd19SJun-ichiro itojun Hagino * equal equal larger N/A | Yes (8) 1753686cdd19SJun-ichiro itojun Hagino * equal equal smaller N/A | No (9) 1754686cdd19SJun-ichiro itojun Hagino * equal equal equal Yes | Yes (a) 1755686cdd19SJun-ichiro itojun Hagino * eaual eqaul equal No | No (b) 1756686cdd19SJun-ichiro itojun Hagino */ 1757686cdd19SJun-ichiro itojun Hagino dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope); 1758686cdd19SJun-ichiro itojun Hagino bscopecmp = IN6_ARE_SCOPE_CMP(src_scope, best_scope); 1759686cdd19SJun-ichiro itojun Hagino 1760686cdd19SJun-ichiro itojun Hagino if (dscopecmp && bscopecmp == 0) { 1761686cdd19SJun-ichiro itojun Hagino if (oifp == ifp) /* (1) */ 1762686cdd19SJun-ichiro itojun Hagino goto replace; 1763686cdd19SJun-ichiro itojun Hagino continue; /* (2) */ 1764686cdd19SJun-ichiro itojun Hagino } 1765686cdd19SJun-ichiro itojun Hagino if (dscopecmp > 0) { 1766686cdd19SJun-ichiro itojun Hagino if (bscopecmp > 0) /* (3) */ 1767686cdd19SJun-ichiro itojun Hagino continue; 1768686cdd19SJun-ichiro itojun Hagino goto replace; /* (4) */ 1769686cdd19SJun-ichiro itojun Hagino } 1770686cdd19SJun-ichiro itojun Hagino if (dscopecmp < 0) { 1771686cdd19SJun-ichiro itojun Hagino if (bscopecmp > 0) /* (5) */ 1772686cdd19SJun-ichiro itojun Hagino goto replace; 1773686cdd19SJun-ichiro itojun Hagino continue; /* (6) */ 1774686cdd19SJun-ichiro itojun Hagino } 1775686cdd19SJun-ichiro itojun Hagino 1776686cdd19SJun-ichiro itojun Hagino /* now dscopecmp must be 0 */ 1777686cdd19SJun-ichiro itojun Hagino if (bscopecmp < 0) 1778686cdd19SJun-ichiro itojun Hagino goto replace; /* (7) */ 1779686cdd19SJun-ichiro itojun Hagino 1780686cdd19SJun-ichiro itojun Hagino /* 1781686cdd19SJun-ichiro itojun Hagino * At last both dscopecmp and bscopecmp must be 0. 1782686cdd19SJun-ichiro itojun Hagino * We need address matching against dst for 1783686cdd19SJun-ichiro itojun Hagino * tiebreaking. 1784686cdd19SJun-ichiro itojun Hagino */ 178582cd038dSYoshinobu Inoue tlen = in6_matchlen(IFA_IN6(ifa), dst); 1786686cdd19SJun-ichiro itojun Hagino matchcmp = tlen - blen; 1787686cdd19SJun-ichiro itojun Hagino if (matchcmp > 0) /* (8) */ 1788686cdd19SJun-ichiro itojun Hagino goto replace; 1789686cdd19SJun-ichiro itojun Hagino if (matchcmp < 0) /* (9) */ 1790686cdd19SJun-ichiro itojun Hagino continue; 1791686cdd19SJun-ichiro itojun Hagino if (oifp == ifp) /* (a) */ 1792686cdd19SJun-ichiro itojun Hagino goto replace; 1793686cdd19SJun-ichiro itojun Hagino continue; /* (b) */ 179482cd038dSYoshinobu Inoue 1795686cdd19SJun-ichiro itojun Hagino replace: 1796686cdd19SJun-ichiro itojun Hagino ifa_best = (struct in6_ifaddr *)ifa; 1797686cdd19SJun-ichiro itojun Hagino blen = tlen >= 0 ? tlen : 1798686cdd19SJun-ichiro itojun Hagino in6_matchlen(IFA_IN6(ifa), dst); 1799686cdd19SJun-ichiro itojun Hagino best_scope = in6_addrscope(&ifa_best->ia_addr.sin6_addr); 180082cd038dSYoshinobu Inoue } 180182cd038dSYoshinobu Inoue } 180282cd038dSYoshinobu Inoue 1803686cdd19SJun-ichiro itojun Hagino /* count statistics for future improvements */ 1804686cdd19SJun-ichiro itojun Hagino if (ifa_best == NULL) 1805686cdd19SJun-ichiro itojun Hagino ip6stat.ip6s_sources_none++; 1806686cdd19SJun-ichiro itojun Hagino else { 1807686cdd19SJun-ichiro itojun Hagino if (oifp == ifa_best->ia_ifp) 1808686cdd19SJun-ichiro itojun Hagino ip6stat.ip6s_sources_sameif[best_scope]++; 1809686cdd19SJun-ichiro itojun Hagino else 1810686cdd19SJun-ichiro itojun Hagino ip6stat.ip6s_sources_otherif[best_scope]++; 1811686cdd19SJun-ichiro itojun Hagino 1812686cdd19SJun-ichiro itojun Hagino if (best_scope == dst_scope) 1813686cdd19SJun-ichiro itojun Hagino ip6stat.ip6s_sources_samescope[best_scope]++; 1814686cdd19SJun-ichiro itojun Hagino else 1815686cdd19SJun-ichiro itojun Hagino ip6stat.ip6s_sources_otherscope[best_scope]++; 1816686cdd19SJun-ichiro itojun Hagino 1817686cdd19SJun-ichiro itojun Hagino if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) != 0) 1818686cdd19SJun-ichiro itojun Hagino ip6stat.ip6s_sources_deprecated[best_scope]++; 1819836b116aSYoshinobu Inoue } 1820836b116aSYoshinobu Inoue 1821686cdd19SJun-ichiro itojun Hagino return(ifa_best); 182282cd038dSYoshinobu Inoue } 182382cd038dSYoshinobu Inoue 182482cd038dSYoshinobu Inoue /* 182582cd038dSYoshinobu Inoue * return the best address out of the same scope. if no address was 182682cd038dSYoshinobu Inoue * found, return the first valid address from designated IF. 182782cd038dSYoshinobu Inoue */ 182882cd038dSYoshinobu Inoue struct in6_ifaddr * 182982cd038dSYoshinobu Inoue in6_ifawithifp(ifp, dst) 183082cd038dSYoshinobu Inoue register struct ifnet *ifp; 183182cd038dSYoshinobu Inoue register struct in6_addr *dst; 183282cd038dSYoshinobu Inoue { 183382cd038dSYoshinobu Inoue int dst_scope = in6_addrscope(dst), blen = -1, tlen; 183482cd038dSYoshinobu Inoue struct ifaddr *ifa; 183582cd038dSYoshinobu Inoue struct in6_ifaddr *besta = 0; 183682cd038dSYoshinobu Inoue struct in6_ifaddr *dep[2]; /*last-resort: deprecated*/ 183782cd038dSYoshinobu Inoue 183882cd038dSYoshinobu Inoue dep[0] = dep[1] = NULL; 183982cd038dSYoshinobu Inoue 184082cd038dSYoshinobu Inoue /* 184182cd038dSYoshinobu Inoue * We first look for addresses in the same scope. 184282cd038dSYoshinobu Inoue * If there is one, return it. 184382cd038dSYoshinobu Inoue * If two or more, return one which matches the dst longest. 184482cd038dSYoshinobu Inoue * If none, return one of global addresses assigned other ifs. 184582cd038dSYoshinobu Inoue */ 1846cfa1ca9dSYoshinobu Inoue TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 184782cd038dSYoshinobu Inoue { 184882cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6) 184982cd038dSYoshinobu Inoue continue; 185082cd038dSYoshinobu Inoue if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 185182cd038dSYoshinobu Inoue continue; /* XXX: is there any case to allow anycast? */ 185282cd038dSYoshinobu Inoue if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 185382cd038dSYoshinobu Inoue continue; /* don't use this interface */ 185482cd038dSYoshinobu Inoue if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 185582cd038dSYoshinobu Inoue continue; 185682cd038dSYoshinobu Inoue if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 185782cd038dSYoshinobu Inoue if (ip6_use_deprecated) 185882cd038dSYoshinobu Inoue dep[0] = (struct in6_ifaddr *)ifa; 185982cd038dSYoshinobu Inoue continue; 186082cd038dSYoshinobu Inoue } 186182cd038dSYoshinobu Inoue 186282cd038dSYoshinobu Inoue if (dst_scope == in6_addrscope(IFA_IN6(ifa))) { 186382cd038dSYoshinobu Inoue /* 186482cd038dSYoshinobu Inoue * call in6_matchlen() as few as possible 186582cd038dSYoshinobu Inoue */ 186682cd038dSYoshinobu Inoue if (besta) { 186782cd038dSYoshinobu Inoue if (blen == -1) 186882cd038dSYoshinobu Inoue blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst); 186982cd038dSYoshinobu Inoue tlen = in6_matchlen(IFA_IN6(ifa), dst); 187082cd038dSYoshinobu Inoue if (tlen > blen) { 187182cd038dSYoshinobu Inoue blen = tlen; 187282cd038dSYoshinobu Inoue besta = (struct in6_ifaddr *)ifa; 187382cd038dSYoshinobu Inoue } 187482cd038dSYoshinobu Inoue } else 187582cd038dSYoshinobu Inoue besta = (struct in6_ifaddr *)ifa; 187682cd038dSYoshinobu Inoue } 187782cd038dSYoshinobu Inoue } 187882cd038dSYoshinobu Inoue if (besta) 187982cd038dSYoshinobu Inoue return(besta); 188082cd038dSYoshinobu Inoue 1881cfa1ca9dSYoshinobu Inoue TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 188282cd038dSYoshinobu Inoue { 188382cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6) 188482cd038dSYoshinobu Inoue continue; 188582cd038dSYoshinobu Inoue if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 188682cd038dSYoshinobu Inoue continue; /* XXX: is there any case to allow anycast? */ 188782cd038dSYoshinobu Inoue if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 188882cd038dSYoshinobu Inoue continue; /* don't use this interface */ 188982cd038dSYoshinobu Inoue if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 189082cd038dSYoshinobu Inoue continue; 189182cd038dSYoshinobu Inoue if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 189282cd038dSYoshinobu Inoue if (ip6_use_deprecated) 189382cd038dSYoshinobu Inoue dep[1] = (struct in6_ifaddr *)ifa; 189482cd038dSYoshinobu Inoue continue; 189582cd038dSYoshinobu Inoue } 189682cd038dSYoshinobu Inoue 189782cd038dSYoshinobu Inoue return (struct in6_ifaddr *)ifa; 189882cd038dSYoshinobu Inoue } 189982cd038dSYoshinobu Inoue 190082cd038dSYoshinobu Inoue /* use the last-resort values, that are, deprecated addresses */ 190182cd038dSYoshinobu Inoue if (dep[0]) 190282cd038dSYoshinobu Inoue return dep[0]; 190382cd038dSYoshinobu Inoue if (dep[1]) 190482cd038dSYoshinobu Inoue return dep[1]; 190582cd038dSYoshinobu Inoue 190682cd038dSYoshinobu Inoue return NULL; 190782cd038dSYoshinobu Inoue } 190882cd038dSYoshinobu Inoue 190982cd038dSYoshinobu Inoue /* 191082cd038dSYoshinobu Inoue * perform DAD when interface becomes IFF_UP. 191182cd038dSYoshinobu Inoue */ 191282cd038dSYoshinobu Inoue void 191382cd038dSYoshinobu Inoue in6_if_up(ifp) 191482cd038dSYoshinobu Inoue struct ifnet *ifp; 191582cd038dSYoshinobu Inoue { 191682cd038dSYoshinobu Inoue struct ifaddr *ifa; 191782cd038dSYoshinobu Inoue struct in6_ifaddr *ia; 191882cd038dSYoshinobu Inoue int dad_delay; /* delay ticks before DAD output */ 191982cd038dSYoshinobu Inoue 1920686cdd19SJun-ichiro itojun Hagino /* 1921686cdd19SJun-ichiro itojun Hagino * special cases, like 6to4, are handled in in6_ifattach 1922686cdd19SJun-ichiro itojun Hagino */ 1923686cdd19SJun-ichiro itojun Hagino in6_ifattach(ifp, NULL); 192482cd038dSYoshinobu Inoue 192582cd038dSYoshinobu Inoue dad_delay = 0; 1926cfa1ca9dSYoshinobu Inoue TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 192782cd038dSYoshinobu Inoue { 192882cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6) 192982cd038dSYoshinobu Inoue continue; 193082cd038dSYoshinobu Inoue ia = (struct in6_ifaddr *)ifa; 193182cd038dSYoshinobu Inoue if (ia->ia6_flags & IN6_IFF_TENTATIVE) 193282cd038dSYoshinobu Inoue nd6_dad_start(ifa, &dad_delay); 193382cd038dSYoshinobu Inoue } 193482cd038dSYoshinobu Inoue } 193582cd038dSYoshinobu Inoue 193682cd038dSYoshinobu Inoue /* 193782cd038dSYoshinobu Inoue * Calculate max IPv6 MTU through all the interfaces and store it 193882cd038dSYoshinobu Inoue * to in6_maxmtu. 193982cd038dSYoshinobu Inoue */ 194082cd038dSYoshinobu Inoue void 194182cd038dSYoshinobu Inoue in6_setmaxmtu() 194282cd038dSYoshinobu Inoue { 194382cd038dSYoshinobu Inoue unsigned long maxmtu = 0; 194482cd038dSYoshinobu Inoue struct ifnet *ifp; 194582cd038dSYoshinobu Inoue 194682cd038dSYoshinobu Inoue for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) 194782cd038dSYoshinobu Inoue { 194882cd038dSYoshinobu Inoue if ((ifp->if_flags & IFF_LOOPBACK) == 0 && 194982cd038dSYoshinobu Inoue nd_ifinfo[ifp->if_index].linkmtu > maxmtu) 195082cd038dSYoshinobu Inoue maxmtu = nd_ifinfo[ifp->if_index].linkmtu; 195182cd038dSYoshinobu Inoue } 195282cd038dSYoshinobu Inoue if (maxmtu) /* update only when maxmtu is positive */ 195382cd038dSYoshinobu Inoue in6_maxmtu = maxmtu; 195482cd038dSYoshinobu Inoue } 195582cd038dSYoshinobu Inoue 195682cd038dSYoshinobu Inoue /* 195782cd038dSYoshinobu Inoue * Convert sockaddr_in6 to sockaddr_in. Original sockaddr_in6 must be 195882cd038dSYoshinobu Inoue * v4 mapped addr or v4 compat addr 195982cd038dSYoshinobu Inoue */ 196082cd038dSYoshinobu Inoue void 196182cd038dSYoshinobu Inoue in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 196282cd038dSYoshinobu Inoue { 196382cd038dSYoshinobu Inoue bzero(sin, sizeof(*sin)); 196482cd038dSYoshinobu Inoue sin->sin_len = sizeof(struct sockaddr_in); 196582cd038dSYoshinobu Inoue sin->sin_family = AF_INET; 196682cd038dSYoshinobu Inoue sin->sin_port = sin6->sin6_port; 196782cd038dSYoshinobu Inoue sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3]; 196882cd038dSYoshinobu Inoue } 196982cd038dSYoshinobu Inoue 197082cd038dSYoshinobu Inoue /* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */ 197182cd038dSYoshinobu Inoue void 197282cd038dSYoshinobu Inoue in6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 197382cd038dSYoshinobu Inoue { 197482cd038dSYoshinobu Inoue bzero(sin6, sizeof(*sin6)); 197582cd038dSYoshinobu Inoue sin6->sin6_len = sizeof(struct sockaddr_in6); 197682cd038dSYoshinobu Inoue sin6->sin6_family = AF_INET6; 197782cd038dSYoshinobu Inoue sin6->sin6_port = sin->sin_port; 197882cd038dSYoshinobu Inoue sin6->sin6_addr.s6_addr32[0] = 0; 197982cd038dSYoshinobu Inoue sin6->sin6_addr.s6_addr32[1] = 0; 198082cd038dSYoshinobu Inoue sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP; 198182cd038dSYoshinobu Inoue sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; 198282cd038dSYoshinobu Inoue } 198382cd038dSYoshinobu Inoue 198482cd038dSYoshinobu Inoue /* Convert sockaddr_in6 into sockaddr_in. */ 198582cd038dSYoshinobu Inoue void 198682cd038dSYoshinobu Inoue in6_sin6_2_sin_in_sock(struct sockaddr *nam) 198782cd038dSYoshinobu Inoue { 198882cd038dSYoshinobu Inoue struct sockaddr_in *sin_p; 198982cd038dSYoshinobu Inoue struct sockaddr_in6 sin6; 199082cd038dSYoshinobu Inoue 199182cd038dSYoshinobu Inoue /* 199282cd038dSYoshinobu Inoue * Save original sockaddr_in6 addr and convert it 199382cd038dSYoshinobu Inoue * to sockaddr_in. 199482cd038dSYoshinobu Inoue */ 199582cd038dSYoshinobu Inoue sin6 = *(struct sockaddr_in6 *)nam; 199682cd038dSYoshinobu Inoue sin_p = (struct sockaddr_in *)nam; 199782cd038dSYoshinobu Inoue in6_sin6_2_sin(sin_p, &sin6); 199882cd038dSYoshinobu Inoue } 199982cd038dSYoshinobu Inoue 200082cd038dSYoshinobu Inoue /* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */ 200182cd038dSYoshinobu Inoue void 200282cd038dSYoshinobu Inoue in6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam) 200382cd038dSYoshinobu Inoue { 200482cd038dSYoshinobu Inoue struct sockaddr_in *sin_p; 200582cd038dSYoshinobu Inoue struct sockaddr_in6 *sin6_p; 200682cd038dSYoshinobu Inoue 200782cd038dSYoshinobu Inoue MALLOC(sin6_p, struct sockaddr_in6 *, sizeof *sin6_p, M_SONAME, 200882cd038dSYoshinobu Inoue M_WAITOK); 200982cd038dSYoshinobu Inoue sin_p = (struct sockaddr_in *)*nam; 201082cd038dSYoshinobu Inoue in6_sin_2_v4mapsin6(sin_p, sin6_p); 201182cd038dSYoshinobu Inoue FREE(*nam, M_SONAME); 201282cd038dSYoshinobu Inoue *nam = (struct sockaddr *)sin6_p; 201382cd038dSYoshinobu Inoue } 2014