in6.c revision 146883
162587Sitojun/* $FreeBSD: head/sys/netinet6/in6.c 146883 2005-06-02 00:04:08Z iedowse $ */ 295023Ssuz/* $KAME: in6.c,v 1.259 2002/01/21 11:37:50 keiichi Exp $ */ 362587Sitojun 4139826Simp/*- 553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 653541Sshin * All rights reserved. 753541Sshin * 853541Sshin * Redistribution and use in source and binary forms, with or without 953541Sshin * modification, are permitted provided that the following conditions 1053541Sshin * are met: 1153541Sshin * 1. Redistributions of source code must retain the above copyright 1253541Sshin * notice, this list of conditions and the following disclaimer. 1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1453541Sshin * notice, this list of conditions and the following disclaimer in the 1553541Sshin * documentation and/or other materials provided with the distribution. 1653541Sshin * 3. Neither the name of the project nor the names of its contributors 1753541Sshin * may be used to endorse or promote products derived from this software 1853541Sshin * without specific prior written permission. 1953541Sshin * 2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2353541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3053541Sshin * SUCH DAMAGE. 3153541Sshin */ 3253541Sshin 33139826Simp/*- 3453541Sshin * Copyright (c) 1982, 1986, 1991, 1993 3553541Sshin * The Regents of the University of California. All rights reserved. 3653541Sshin * 3753541Sshin * Redistribution and use in source and binary forms, with or without 3853541Sshin * modification, are permitted provided that the following conditions 3953541Sshin * are met: 4053541Sshin * 1. Redistributions of source code must retain the above copyright 4153541Sshin * notice, this list of conditions and the following disclaimer. 4253541Sshin * 2. Redistributions in binary form must reproduce the above copyright 4353541Sshin * notice, this list of conditions and the following disclaimer in the 4453541Sshin * documentation and/or other materials provided with the distribution. 4553541Sshin * 4. Neither the name of the University nor the names of its contributors 4653541Sshin * may be used to endorse or promote products derived from this software 4753541Sshin * without specific prior written permission. 4853541Sshin * 4953541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5053541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5153541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5253541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5353541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5453541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5553541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5653541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5753541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5853541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5953541Sshin * SUCH DAMAGE. 6053541Sshin * 6153541Sshin * @(#)in.c 8.2 (Berkeley) 11/15/93 6253541Sshin */ 6353541Sshin 6462587Sitojun#include "opt_inet.h" 6562587Sitojun#include "opt_inet6.h" 6662587Sitojun 6753541Sshin#include <sys/param.h> 6853541Sshin#include <sys/errno.h> 6953541Sshin#include <sys/malloc.h> 7053541Sshin#include <sys/socket.h> 7153541Sshin#include <sys/socketvar.h> 7253541Sshin#include <sys/sockio.h> 7353541Sshin#include <sys/systm.h> 7453541Sshin#include <sys/proc.h> 7553541Sshin#include <sys/time.h> 7653541Sshin#include <sys/kernel.h> 7753541Sshin#include <sys/syslog.h> 7853541Sshin 7953541Sshin#include <net/if.h> 8053541Sshin#include <net/if_types.h> 8153541Sshin#include <net/route.h> 8253541Sshin#include <net/if_dl.h> 8353541Sshin 8453541Sshin#include <netinet/in.h> 8553541Sshin#include <netinet/in_var.h> 8653541Sshin#include <netinet/if_ether.h> 8778064Sume#include <netinet/in_systm.h> 8878064Sume#include <netinet/ip.h> 8978064Sume#include <netinet/in_pcb.h> 9053541Sshin 9162587Sitojun#include <netinet/ip6.h> 9253541Sshin#include <netinet6/ip6_var.h> 9395023Ssuz#include <netinet6/nd6.h> 9453541Sshin#include <netinet6/mld6_var.h> 9562587Sitojun#include <netinet6/ip6_mroute.h> 9653541Sshin#include <netinet6/in6_ifattach.h> 9762587Sitojun#include <netinet6/scope6_var.h> 9878064Sume#include <netinet6/in6_pcb.h> 9962587Sitojun 10053541Sshin#include <net/net_osdep.h> 10153541Sshin 10253541SshinMALLOC_DEFINE(M_IPMADDR, "in6_multi", "internet multicast address"); 10353541Sshin 10453541Sshin/* 10553541Sshin * Definitions of some costant IP6 addresses. 10653541Sshin */ 10762587Sitojunconst struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 10862587Sitojunconst struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 10962587Sitojunconst struct in6_addr in6addr_nodelocal_allnodes = 11053541Sshin IN6ADDR_NODELOCAL_ALLNODES_INIT; 11162587Sitojunconst struct in6_addr in6addr_linklocal_allnodes = 11253541Sshin IN6ADDR_LINKLOCAL_ALLNODES_INIT; 11362587Sitojunconst struct in6_addr in6addr_linklocal_allrouters = 11453541Sshin IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; 11553541Sshin 11662587Sitojunconst struct in6_addr in6mask0 = IN6MASK0; 11762587Sitojunconst struct in6_addr in6mask32 = IN6MASK32; 11862587Sitojunconst struct in6_addr in6mask64 = IN6MASK64; 11962587Sitojunconst struct in6_addr in6mask96 = IN6MASK96; 12062587Sitojunconst struct in6_addr in6mask128 = IN6MASK128; 12153541Sshin 122126552Sumeconst struct sockaddr_in6 sa6_any = 123126552Sume { sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 }; 12478064Sume 12562587Sitojunstatic int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, 12683366Sjulian struct ifnet *, struct thread *)); 12778064Sumestatic int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *, 128120891Sume struct sockaddr_in6 *, int)); 12978064Sumestatic void in6_unlink_ifa __P((struct in6_ifaddr *, struct ifnet *)); 13053541Sshin 13162587Sitojunstruct in6_multihead in6_multihead; /* XXX BSS initialization */ 13283934Sbrooksint (*faithprefix_p)(struct in6_addr *); 13383934Sbrooks 13453541Sshin/* 13553541Sshin * Subroutine for in6_ifaddloop() and in6_ifremloop(). 13653541Sshin * This routine does actual work. 13753541Sshin */ 13853541Sshinstatic void 13953541Sshinin6_ifloop_request(int cmd, struct ifaddr *ifa) 14053541Sshin{ 14153541Sshin struct sockaddr_in6 all1_sa; 14278064Sume struct rtentry *nrt = NULL; 14378064Sume int e; 144120891Sume 14553541Sshin bzero(&all1_sa, sizeof(all1_sa)); 14678064Sume all1_sa.sin6_family = AF_INET6; 14778064Sume all1_sa.sin6_len = sizeof(struct sockaddr_in6); 14853541Sshin all1_sa.sin6_addr = in6mask128; 14978064Sume 15062587Sitojun /* 15178064Sume * We specify the address itself as the gateway, and set the 15278064Sume * RTF_LLINFO flag, so that the corresponding host route would have 15378064Sume * the flag, and thus applications that assume traditional behavior 15478064Sume * would be happy. Note that we assume the caller of the function 15578064Sume * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest, 15678064Sume * which changes the outgoing interface to the loopback interface. 15762587Sitojun */ 15878064Sume e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr, 159120891Sume (struct sockaddr *)&all1_sa, RTF_UP|RTF_HOST|RTF_LLINFO, &nrt); 16078064Sume if (e != 0) { 161120891Sume /* XXX need more descriptive message */ 16278064Sume log(LOG_ERR, "in6_ifloop_request: " 16378064Sume "%s operation failed for %s (errno=%d)\n", 16478064Sume cmd == RTM_ADD ? "ADD" : "DELETE", 16578064Sume ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr), 16678064Sume e); 16778064Sume } 16853541Sshin 169120727Ssam if (nrt) { 170120727Ssam RT_LOCK(nrt); 171120727Ssam /* 172120727Ssam * Make sure rt_ifa be equal to IFA, the second argument of 173120727Ssam * the function. We need this because when we refer to 174120727Ssam * rt_ifa->ia6_flags in ip6_input, we assume that the rt_ifa 175120727Ssam * points to the address instead of the loopback address. 176120727Ssam */ 177120727Ssam if (cmd == RTM_ADD && ifa != nrt->rt_ifa) { 178120727Ssam IFAFREE(nrt->rt_ifa); 179120727Ssam IFAREF(ifa); 180120727Ssam nrt->rt_ifa = ifa; 181120727Ssam } 18278064Sume 183120727Ssam /* 184120727Ssam * Report the addition/removal of the address to the routing 185120727Ssam * socket. 186120727Ssam * 187120727Ssam * XXX: since we called rtinit for a p2p interface with a 188120727Ssam * destination, we end up reporting twice in such a case. 189120727Ssam * Should we rather omit the second report? 190120727Ssam */ 19178064Sume rt_newaddrmsg(cmd, ifa, e, nrt); 19278064Sume if (cmd == RTM_DELETE) { 193120727Ssam rtfree(nrt); 19478064Sume } else { 19578064Sume /* the cmd must be RTM_ADD here */ 196122334Ssam RT_REMREF(nrt); 197120727Ssam RT_UNLOCK(nrt); 19878064Sume } 19978064Sume } 20053541Sshin} 20153541Sshin 20253541Sshin/* 20378064Sume * Add ownaddr as loopback rtentry. We previously add the route only if 20478064Sume * necessary (ex. on a p2p link). However, since we now manage addresses 20578064Sume * separately from prefixes, we should always add the route. We can't 20678064Sume * rely on the cloning mechanism from the corresponding interface route 20778064Sume * any more. 20853541Sshin */ 209142215Sglebiusvoid 21053541Sshinin6_ifaddloop(struct ifaddr *ifa) 21153541Sshin{ 21278064Sume struct rtentry *rt; 213121716Ssam int need_loop; 21453541Sshin 21578064Sume /* If there is no loopback entry, allocate one. */ 21678064Sume rt = rtalloc1(ifa->ifa_addr, 0, 0); 217121716Ssam need_loop = (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 || 218121716Ssam (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0); 21978064Sume if (rt) 220120727Ssam rtfree(rt); 221121716Ssam if (need_loop) 222121716Ssam in6_ifloop_request(RTM_ADD, ifa); 22353541Sshin} 22453541Sshin 22553541Sshin/* 22653541Sshin * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(), 22753541Sshin * if it exists. 22853541Sshin */ 229142215Sglebiusvoid 23053541Sshinin6_ifremloop(struct ifaddr *ifa) 23153541Sshin{ 23262587Sitojun struct in6_ifaddr *ia; 23378064Sume struct rtentry *rt; 23462587Sitojun int ia_count = 0; 23553541Sshin 23662587Sitojun /* 23778064Sume * Some of BSD variants do not remove cloned routes 23862587Sitojun * from an interface direct route, when removing the direct route 23978064Sume * (see comments in net/net_osdep.h). Even for variants that do remove 24078064Sume * cloned routes, they could fail to remove the cloned routes when 24178064Sume * we handle multple addresses that share a common prefix. 24278064Sume * So, we should remove the route corresponding to the deleted address 24362587Sitojun * regardless of the result of in6_is_ifloop_auto(). 24462587Sitojun */ 24578064Sume 24678064Sume /* 24795023Ssuz * Delete the entry only if exact one ifa exists. More than one ifa 24878064Sume * can exist if we assign a same single address to multiple 24978064Sume * (probably p2p) interfaces. 25078064Sume * XXX: we should avoid such a configuration in IPv6... 25178064Sume */ 25278064Sume for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 25378064Sume if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) { 25478064Sume ia_count++; 25578064Sume if (ia_count > 1) 25678064Sume break; 25753541Sshin } 25878064Sume } 25978064Sume 26078064Sume if (ia_count == 1) { 26178064Sume /* 26278064Sume * Before deleting, check if a corresponding loopbacked host 26395023Ssuz * route surely exists. With this check, we can avoid to 26478064Sume * delete an interface direct route whose destination is same 265120891Sume * as the address being removed. This can happen when removing 26678064Sume * a subnet-router anycast address on an interface attahced 26778064Sume * to a shared medium. 26878064Sume */ 26978064Sume rt = rtalloc1(ifa->ifa_addr, 0, 0); 270120727Ssam if (rt != NULL) { 271120727Ssam if ((rt->rt_flags & RTF_HOST) != 0 && 272120727Ssam (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { 273120727Ssam rtfree(rt); 274120727Ssam in6_ifloop_request(RTM_DELETE, ifa); 275120727Ssam } else 276120727Ssam RT_UNLOCK(rt); 27778064Sume } 27853541Sshin } 27953541Sshin} 28053541Sshin 28153541Sshinint 28278064Sumein6_mask2len(mask, lim0) 28353541Sshin struct in6_addr *mask; 28478064Sume u_char *lim0; 28553541Sshin{ 28678064Sume int x = 0, y; 28778064Sume u_char *lim = lim0, *p; 28853541Sshin 289120891Sume /* ignore the scope_id part */ 290120891Sume if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask)) 29178064Sume lim = (u_char *)mask + sizeof(*mask); 29278064Sume for (p = (u_char *)mask; p < lim; x++, p++) { 29378064Sume if (*p != 0xff) 29453541Sshin break; 29553541Sshin } 29653541Sshin y = 0; 29778064Sume if (p < lim) { 29853541Sshin for (y = 0; y < 8; y++) { 29978064Sume if ((*p & (0x80 >> y)) == 0) 30053541Sshin break; 30153541Sshin } 30253541Sshin } 30378064Sume 30478064Sume /* 30578064Sume * when the limit pointer is given, do a stricter check on the 30678064Sume * remaining bits. 30778064Sume */ 30878064Sume if (p < lim) { 30978064Sume if (y != 0 && (*p & (0x00ff >> y)) != 0) 310120856Sume return (-1); 31178064Sume for (p = p + 1; p < lim; p++) 31278064Sume if (*p != 0) 313120856Sume return (-1); 31478064Sume } 315120891Sume 31653541Sshin return x * 8 + y; 31753541Sshin} 31853541Sshin 31953541Sshin#define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) 32062587Sitojun#define ia62ifa(ia6) (&((ia6)->ia_ifa)) 32153541Sshin 32253541Sshinint 32383366Sjulianin6_control(so, cmd, data, ifp, td) 32453541Sshin struct socket *so; 32553541Sshin u_long cmd; 32653541Sshin caddr_t data; 32753541Sshin struct ifnet *ifp; 32883366Sjulian struct thread *td; 32953541Sshin{ 33053541Sshin struct in6_ifreq *ifr = (struct in6_ifreq *)data; 33178064Sume struct in6_ifaddr *ia = NULL; 33253541Sshin struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; 33353541Sshin int privileged; 33453541Sshin 33553541Sshin privileged = 0; 33693593Sjhb if (td == NULL || !suser(td)) 33753541Sshin privileged++; 33853541Sshin 33962587Sitojun switch (cmd) { 34062587Sitojun case SIOCGETSGCNT_IN6: 34162587Sitojun case SIOCGETMIFCNT_IN6: 34262587Sitojun return (mrt6_ioctl(cmd, data)); 34362587Sitojun } 34453541Sshin 345121742Sume switch(cmd) { 346121742Sume case SIOCAADDRCTL_POLICY: 347121742Sume case SIOCDADDRCTL_POLICY: 348121742Sume if (!privileged) 349121742Sume return (EPERM); 350121742Sume return (in6_src_ioctl(cmd, data)); 351121742Sume } 352121742Sume 35362587Sitojun if (ifp == NULL) 354120856Sume return (EOPNOTSUPP); 35553541Sshin 35653541Sshin switch (cmd) { 35753541Sshin case SIOCSNDFLUSH_IN6: 35853541Sshin case SIOCSPFXFLUSH_IN6: 35953541Sshin case SIOCSRTRFLUSH_IN6: 36062587Sitojun case SIOCSDEFIFACE_IN6: 36162587Sitojun case SIOCSIFINFO_FLAGS: 36253541Sshin if (!privileged) 363120856Sume return (EPERM); 364120891Sume /* FALLTHROUGH */ 36578064Sume case OSIOCGIFINFO_IN6: 36653541Sshin case SIOCGIFINFO_IN6: 36753541Sshin case SIOCGDRLST_IN6: 36853541Sshin case SIOCGPRLST_IN6: 36953541Sshin case SIOCGNBRINFO_IN6: 37062587Sitojun case SIOCGDEFIFACE_IN6: 371120856Sume return (nd6_ioctl(cmd, data, ifp)); 37253541Sshin } 37353541Sshin 37453541Sshin switch (cmd) { 37553541Sshin case SIOCSIFPREFIX_IN6: 37653541Sshin case SIOCDIFPREFIX_IN6: 37753541Sshin case SIOCAIFPREFIX_IN6: 37853541Sshin case SIOCCIFPREFIX_IN6: 37953541Sshin case SIOCSGIFPREFIX_IN6: 38053541Sshin case SIOCGIFPREFIX_IN6: 38178064Sume log(LOG_NOTICE, 38278064Sume "prefix ioctls are now invalidated. " 38378064Sume "please use ifconfig.\n"); 384120856Sume return (EOPNOTSUPP); 38553541Sshin } 38653541Sshin 38795023Ssuz switch (cmd) { 38862587Sitojun case SIOCSSCOPE6: 38962587Sitojun if (!privileged) 390120856Sume return (EPERM); 391121161Sume return (scope6_set(ifp, 392121161Sume (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 39362587Sitojun case SIOCGSCOPE6: 394121161Sume return (scope6_get(ifp, 395121161Sume (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 39662587Sitojun case SIOCGSCOPE6DEF: 397121161Sume return (scope6_get_default((struct scope6_id *) 398121161Sume ifr->ifr_ifru.ifru_scope_id)); 39962587Sitojun } 40062587Sitojun 40153541Sshin switch (cmd) { 40253541Sshin case SIOCALIFADDR: 40353541Sshin case SIOCDLIFADDR: 40453541Sshin if (!privileged) 405120856Sume return (EPERM); 406120891Sume /* FALLTHROUGH */ 40753541Sshin case SIOCGLIFADDR: 40883366Sjulian return in6_lifaddr_ioctl(so, cmd, data, ifp, td); 40953541Sshin } 41053541Sshin 41153541Sshin /* 41253541Sshin * Find address for this interface, if it exists. 41353541Sshin */ 41462587Sitojun if (ifra->ifra_addr.sin6_family == AF_INET6) { /* XXX */ 41553541Sshin struct sockaddr_in6 *sa6 = 41653541Sshin (struct sockaddr_in6 *)&ifra->ifra_addr; 41753541Sshin 41853541Sshin if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { 41953541Sshin if (sa6->sin6_addr.s6_addr16[1] == 0) { 42078064Sume /* link ID is not embedded by the user */ 42153541Sshin sa6->sin6_addr.s6_addr16[1] = 422120891Sume htons(ifp->if_index); 42362587Sitojun } else if (sa6->sin6_addr.s6_addr16[1] != 424120891Sume htons(ifp->if_index)) { 425120856Sume return (EINVAL); /* link ID contradicts */ 42662587Sitojun } 42753541Sshin if (sa6->sin6_scope_id) { 42853541Sshin if (sa6->sin6_scope_id != 42953541Sshin (u_int32_t)ifp->if_index) 430120856Sume return (EINVAL); 43153541Sshin sa6->sin6_scope_id = 0; /* XXX: good way? */ 43253541Sshin } 43353541Sshin } 43462587Sitojun ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr); 43553541Sshin } 43653541Sshin 43753541Sshin switch (cmd) { 43878064Sume case SIOCSIFADDR_IN6: 43978064Sume case SIOCSIFDSTADDR_IN6: 44078064Sume case SIOCSIFNETMASK_IN6: 44178064Sume /* 44278064Sume * Since IPv6 allows a node to assign multiple addresses 44378064Sume * on a single interface, SIOCSIFxxx ioctls are not suitable 44478064Sume * and should be unused. 44578064Sume */ 44678064Sume /* we decided to obsolete this command (20000704) */ 447120856Sume return (EINVAL); 44853541Sshin 44953541Sshin case SIOCDIFADDR_IN6: 45062587Sitojun /* 45178064Sume * for IPv4, we look for existing in_ifaddr here to allow 45262587Sitojun * "ifconfig if0 delete" to remove first IPv4 address on the 45362587Sitojun * interface. For IPv6, as the spec allow multiple interface 45462587Sitojun * address from the day one, we consider "remove the first one" 45578064Sume * semantics to be not preferable. 45662587Sitojun */ 45762587Sitojun if (ia == NULL) 458120856Sume return (EADDRNOTAVAIL); 45953541Sshin /* FALLTHROUGH */ 46053541Sshin case SIOCAIFADDR_IN6: 46162587Sitojun /* 46278064Sume * We always require users to specify a valid IPv6 address for 46378064Sume * the corresponding operation. 46462587Sitojun */ 46578064Sume if (ifra->ifra_addr.sin6_family != AF_INET6 || 46678064Sume ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) 467120856Sume return (EAFNOSUPPORT); 46853541Sshin if (!privileged) 469120856Sume return (EPERM); 47053541Sshin 47153541Sshin break; 47253541Sshin 47353541Sshin case SIOCGIFADDR_IN6: 47453541Sshin /* This interface is basically deprecated. use SIOCGIFCONF. */ 475120891Sume /* FALLTHROUGH */ 47653541Sshin case SIOCGIFAFLAG_IN6: 47753541Sshin case SIOCGIFNETMASK_IN6: 47853541Sshin case SIOCGIFDSTADDR_IN6: 47953541Sshin case SIOCGIFALIFETIME_IN6: 48053541Sshin /* must think again about its semantics */ 48162587Sitojun if (ia == NULL) 482120856Sume return (EADDRNOTAVAIL); 48353541Sshin break; 48453541Sshin case SIOCSIFALIFETIME_IN6: 48553541Sshin { 48653541Sshin struct in6_addrlifetime *lt; 48753541Sshin 48853541Sshin if (!privileged) 489120856Sume return (EPERM); 49062587Sitojun if (ia == NULL) 491120856Sume return (EADDRNOTAVAIL); 49253541Sshin /* sanity for overflow - beware unsigned */ 49353541Sshin lt = &ifr->ifr_ifru.ifru_lifetime; 494126552Sume if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME && 495126552Sume lt->ia6t_vltime + time_second < time_second) { 49653541Sshin return EINVAL; 49753541Sshin } 498126552Sume if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME && 499126552Sume lt->ia6t_pltime + time_second < time_second) { 50053541Sshin return EINVAL; 50153541Sshin } 50253541Sshin break; 50353541Sshin } 50453541Sshin } 50553541Sshin 50653541Sshin switch (cmd) { 50753541Sshin 50853541Sshin case SIOCGIFADDR_IN6: 50953541Sshin ifr->ifr_addr = ia->ia_addr; 51053541Sshin break; 51153541Sshin 51253541Sshin case SIOCGIFDSTADDR_IN6: 51353541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 514120856Sume return (EINVAL); 51562587Sitojun /* 51662587Sitojun * XXX: should we check if ifa_dstaddr is NULL and return 51762587Sitojun * an error? 51862587Sitojun */ 51953541Sshin ifr->ifr_dstaddr = ia->ia_dstaddr; 52053541Sshin break; 52153541Sshin 52253541Sshin case SIOCGIFNETMASK_IN6: 52353541Sshin ifr->ifr_addr = ia->ia_prefixmask; 52453541Sshin break; 52553541Sshin 52653541Sshin case SIOCGIFAFLAG_IN6: 52753541Sshin ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags; 52853541Sshin break; 52953541Sshin 53053541Sshin case SIOCGIFSTAT_IN6: 531121167Sume if (ifp == NULL) 532121167Sume return EINVAL; 533121161Sume bzero(&ifr->ifr_ifru.ifru_stat, 534121161Sume sizeof(ifr->ifr_ifru.ifru_stat)); 535121161Sume ifr->ifr_ifru.ifru_stat = 536121161Sume *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat; 53753541Sshin break; 53853541Sshin 53953541Sshin case SIOCGIFSTAT_ICMP6: 54053541Sshin if (ifp == NULL) 54153541Sshin return EINVAL; 542121161Sume bzero(&ifr->ifr_ifru.ifru_stat, 543121161Sume sizeof(ifr->ifr_ifru.ifru_icmp6stat)); 544121161Sume ifr->ifr_ifru.ifru_icmp6stat = 545121161Sume *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat; 54653541Sshin break; 54753541Sshin 54853541Sshin case SIOCGIFALIFETIME_IN6: 54953541Sshin ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime; 55053541Sshin break; 55153541Sshin 55253541Sshin case SIOCSIFALIFETIME_IN6: 55353541Sshin ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime; 55453541Sshin /* for sanity */ 55553541Sshin if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 55653541Sshin ia->ia6_lifetime.ia6t_expire = 55753541Sshin time_second + ia->ia6_lifetime.ia6t_vltime; 55853541Sshin } else 55953541Sshin ia->ia6_lifetime.ia6t_expire = 0; 56053541Sshin if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 56153541Sshin ia->ia6_lifetime.ia6t_preferred = 56253541Sshin time_second + ia->ia6_lifetime.ia6t_pltime; 56353541Sshin } else 56453541Sshin ia->ia6_lifetime.ia6t_preferred = 0; 56553541Sshin break; 56653541Sshin 56778064Sume case SIOCAIFADDR_IN6: 56878064Sume { 56978064Sume int i, error = 0; 57078064Sume struct nd_prefix pr0, *pr; 57178064Sume 57262587Sitojun /* 57378064Sume * first, make or update the interface address structure, 57478064Sume * and link it to the list. 57562587Sitojun */ 57678064Sume if ((error = in6_update_ifa(ifp, ifra, ia)) != 0) 577120856Sume return (error); 57853541Sshin 57978064Sume /* 58078064Sume * then, make the prefix on-link on the interface. 58178064Sume * XXX: we'd rather create the prefix before the address, but 58278064Sume * we need at least one address to install the corresponding 58378064Sume * interface route, so we configure the address first. 58478064Sume */ 58578064Sume 58678064Sume /* 58778064Sume * convert mask to prefix length (prefixmask has already 58878064Sume * been validated in in6_update_ifa(). 58978064Sume */ 59078064Sume bzero(&pr0, sizeof(pr0)); 59178064Sume pr0.ndpr_ifp = ifp; 59278064Sume pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 593120891Sume NULL); 594120891Sume if (pr0.ndpr_plen == 128) { 59578064Sume break; /* we don't need to install a host route. */ 596120891Sume } 59778064Sume pr0.ndpr_prefix = ifra->ifra_addr; 59878064Sume pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr; 59978064Sume /* apply the mask for safety. */ 60078064Sume for (i = 0; i < 4; i++) { 60178064Sume pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 602120891Sume ifra->ifra_prefixmask.sin6_addr.s6_addr32[i]; 60378064Sume } 60478064Sume /* 60595023Ssuz * XXX: since we don't have an API to set prefix (not address) 60695023Ssuz * lifetimes, we just use the same lifetimes as addresses. 60795023Ssuz * The (temporarily) installed lifetimes can be overridden by 60895023Ssuz * later advertised RAs (when accept_rtadv is non 0), which is 60995023Ssuz * an intended behavior. 61078064Sume */ 61178064Sume pr0.ndpr_raf_onlink = 1; /* should be configurable? */ 61278064Sume pr0.ndpr_raf_auto = 613120891Sume ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0); 61478064Sume pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime; 61578064Sume pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime; 61678064Sume 617120891Sume /* add the prefix if not yet. */ 61878064Sume if ((pr = nd6_prefix_lookup(&pr0)) == NULL) { 61978064Sume /* 62078064Sume * nd6_prelist_add will install the corresponding 62178064Sume * interface route. 62278064Sume */ 62378064Sume if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) 624120856Sume return (error); 62578064Sume if (pr == NULL) { 626120891Sume log(LOG_ERR, "nd6_prelist_add succeeded but " 62778064Sume "no prefix\n"); 628120856Sume return (EINVAL); /* XXX panic here? */ 62978064Sume } 63078064Sume } 63178064Sume if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr)) 63278064Sume == NULL) { 63378064Sume /* XXX: this should not happen! */ 63478064Sume log(LOG_ERR, "in6_control: addition succeeded, but" 63578064Sume " no ifaddr\n"); 63678064Sume } else { 63778064Sume if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && 63878064Sume ia->ia6_ndpr == NULL) { /* new autoconfed addr */ 63978064Sume ia->ia6_ndpr = pr; 64078064Sume pr->ndpr_refcnt++; 64178064Sume 64278064Sume /* 64378064Sume * If this is the first autoconf address from 64478064Sume * the prefix, create a temporary address 64578064Sume * as well (when specified). 64678064Sume */ 64778064Sume if (ip6_use_tempaddr && 64878064Sume pr->ndpr_refcnt == 1) { 64978064Sume int e; 65078064Sume if ((e = in6_tmpifadd(ia, 1)) != 0) { 65178064Sume log(LOG_NOTICE, "in6_control: " 65278064Sume "failed to create a " 65378064Sume "temporary address, " 654122059Sume "errno=%d\n", e); 65578064Sume } 65662587Sitojun } 65762587Sitojun } 65878064Sume 65978064Sume /* 66078064Sume * this might affect the status of autoconfigured 66178064Sume * addresses, that is, this address might make 66278064Sume * other addresses detached. 66378064Sume */ 66478064Sume pfxlist_onlink_check(); 66562587Sitojun } 666126264Smlaier if (error == 0 && ia) 667126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 66878064Sume break; 66978064Sume } 67062587Sitojun 67178064Sume case SIOCDIFADDR_IN6: 67278064Sume { 67378064Sume int i = 0; 67478064Sume struct nd_prefix pr0, *pr; 67578064Sume 67678064Sume /* 67778064Sume * If the address being deleted is the only one that owns 67878064Sume * the corresponding prefix, expire the prefix as well. 679120891Sume * XXX: theoretically, we don't have to worry about such 68078064Sume * relationship, since we separate the address management 68178064Sume * and the prefix management. We do this, however, to provide 68278064Sume * as much backward compatibility as possible in terms of 68378064Sume * the ioctl operation. 68478064Sume */ 68578064Sume bzero(&pr0, sizeof(pr0)); 68678064Sume pr0.ndpr_ifp = ifp; 68778064Sume pr0.ndpr_plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, 68878064Sume NULL); 68978064Sume if (pr0.ndpr_plen == 128) 69078064Sume goto purgeaddr; 69178064Sume pr0.ndpr_prefix = ia->ia_addr; 69278064Sume pr0.ndpr_mask = ia->ia_prefixmask.sin6_addr; 69378064Sume for (i = 0; i < 4; i++) { 69478064Sume pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 69578064Sume ia->ia_prefixmask.sin6_addr.s6_addr32[i]; 69678064Sume } 69778064Sume /* 69878064Sume * The logic of the following condition is a bit complicated. 69978064Sume * We expire the prefix when 70078064Sume * 1. the address obeys autoconfiguration and it is the 70178064Sume * only owner of the associated prefix, or 70278064Sume * 2. the address does not obey autoconf and there is no 70378064Sume * other owner of the prefix. 70478064Sume */ 70578064Sume if ((pr = nd6_prefix_lookup(&pr0)) != NULL && 70678064Sume (((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && 70778064Sume pr->ndpr_refcnt == 1) || 70878064Sume ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0 && 70978064Sume pr->ndpr_refcnt == 0))) { 71078064Sume pr->ndpr_expire = 1; /* XXX: just for expiration */ 71178064Sume } 71278064Sume 71378064Sume purgeaddr: 71478064Sume in6_purgeaddr(&ia->ia_ifa); 715126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 71653541Sshin break; 71778064Sume } 71853541Sshin 71978064Sume default: 72078064Sume if (ifp == NULL || ifp->if_ioctl == 0) 721120856Sume return (EOPNOTSUPP); 722120856Sume return ((*ifp->if_ioctl)(ifp, cmd, data)); 72378064Sume } 72453541Sshin 725120856Sume return (0); 72678064Sume} 72753541Sshin 72878064Sume/* 72978064Sume * Update parameters of an IPv6 interface address. 73078064Sume * If necessary, a new entry is created and linked into address chains. 73178064Sume * This function is separated from in6_control(). 73278064Sume * XXX: should this be performed under splnet()? 73378064Sume */ 73478064Sumeint 73578064Sumein6_update_ifa(ifp, ifra, ia) 73678064Sume struct ifnet *ifp; 73778064Sume struct in6_aliasreq *ifra; 73878064Sume struct in6_ifaddr *ia; 73978064Sume{ 74078064Sume int error = 0, hostIsNew = 0, plen = -1; 74178064Sume struct in6_ifaddr *oia; 74278064Sume struct sockaddr_in6 dst6; 74378064Sume struct in6_addrlifetime *lt; 74478064Sume 74578064Sume /* Validate parameters */ 74678064Sume if (ifp == NULL || ifra == NULL) /* this maybe redundant */ 747120856Sume return (EINVAL); 74878064Sume 74978064Sume /* 75078064Sume * The destination address for a p2p link must have a family 75178064Sume * of AF_UNSPEC or AF_INET6. 75278064Sume */ 75378064Sume if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && 75478064Sume ifra->ifra_dstaddr.sin6_family != AF_INET6 && 75578064Sume ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) 756120856Sume return (EAFNOSUPPORT); 75778064Sume /* 75878064Sume * validate ifra_prefixmask. don't check sin6_family, netmask 75978064Sume * does not carry fields other than sin6_len. 76078064Sume */ 76178064Sume if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6)) 762120856Sume return (EINVAL); 76378064Sume /* 76478064Sume * Because the IPv6 address architecture is classless, we require 76578064Sume * users to specify a (non 0) prefix length (mask) for a new address. 76678064Sume * We also require the prefix (when specified) mask is valid, and thus 76778064Sume * reject a non-consecutive mask. 76878064Sume */ 76978064Sume if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0) 770120856Sume return (EINVAL); 77178064Sume if (ifra->ifra_prefixmask.sin6_len != 0) { 77278064Sume plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 773120891Sume (u_char *)&ifra->ifra_prefixmask + 774120891Sume ifra->ifra_prefixmask.sin6_len); 77578064Sume if (plen <= 0) 776120856Sume return (EINVAL); 777120891Sume } else { 77862587Sitojun /* 77995023Ssuz * In this case, ia must not be NULL. We just use its prefix 78078064Sume * length. 78162587Sitojun */ 78278064Sume plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 78378064Sume } 78478064Sume /* 78578064Sume * If the destination address on a p2p interface is specified, 78678064Sume * and the address is a scoped one, validate/set the scope 78778064Sume * zone identifier. 78878064Sume */ 78978064Sume dst6 = ifra->ifra_dstaddr; 790120891Sume if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 && 79178064Sume (dst6.sin6_family == AF_INET6)) { 792126552Sume u_int32_t zoneid; 79378064Sume 79478064Sume if ((error = in6_recoverscope(&dst6, 795120891Sume &ifra->ifra_dstaddr.sin6_addr, ifp)) != 0) 796120856Sume return (error); 797126552Sume if (in6_addr2zoneid(ifp, &dst6.sin6_addr, &zoneid)) 798121315Sume return (EINVAL); 79978064Sume if (dst6.sin6_scope_id == 0) /* user omit to specify the ID. */ 800126552Sume dst6.sin6_scope_id = zoneid; 801126552Sume else if (dst6.sin6_scope_id != zoneid) 802120856Sume return (EINVAL); /* scope ID mismatch. */ 80378064Sume if ((error = in6_embedscope(&dst6.sin6_addr, &dst6, NULL, NULL)) 80478064Sume != 0) 805120856Sume return (error); 80678064Sume dst6.sin6_scope_id = 0; /* XXX */ 80778064Sume } 80878064Sume /* 80978064Sume * The destination address can be specified only for a p2p or a 81078064Sume * loopback interface. If specified, the corresponding prefix length 81178064Sume * must be 128. 81278064Sume */ 81378064Sume if (ifra->ifra_dstaddr.sin6_family == AF_INET6) { 81478064Sume if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) { 815126552Sume /* XXX: noisy message */ 816122059Sume nd6log((LOG_INFO, "in6_update_ifa: a destination can " 817122059Sume "be specified for a p2p or a loopback IF only\n")); 818120856Sume return (EINVAL); 81978064Sume } 82078064Sume if (plen != 128) { 821122059Sume nd6log((LOG_INFO, "in6_update_ifa: prefixlen should " 822122059Sume "be 128 when dstaddr is specified\n")); 823120856Sume return (EINVAL); 82478064Sume } 82578064Sume } 82678064Sume /* lifetime consistency check */ 82778064Sume lt = &ifra->ifra_lifetime; 82878064Sume if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME 82978064Sume && lt->ia6t_vltime + time_second < time_second) { 83078064Sume return EINVAL; 83178064Sume } 83278064Sume if (lt->ia6t_vltime == 0) { 83362587Sitojun /* 83478064Sume * the following log might be noisy, but this is a typical 83578064Sume * configuration mistake or a tool's bug. 83662587Sitojun */ 837122059Sume nd6log((LOG_INFO, 83878064Sume "in6_update_ifa: valid lifetime is 0 for %s\n", 839122059Sume ip6_sprintf(&ifra->ifra_addr.sin6_addr))); 84078064Sume } 84178064Sume if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME 84278064Sume && lt->ia6t_pltime + time_second < time_second) { 84378064Sume return EINVAL; 84478064Sume } 84562587Sitojun 84678064Sume /* 84778064Sume * If this is a new address, allocate a new ifaddr and link it 84878064Sume * into chains. 84978064Sume */ 85078064Sume if (ia == NULL) { 85178064Sume hostIsNew = 1; 85279763Sume /* 85379763Sume * When in6_update_ifa() is called in a process of a received 854120891Sume * RA, it is called under an interrupt context. So, we should 855120891Sume * call malloc with M_NOWAIT. 85679763Sume */ 857120891Sume ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR, 858120891Sume M_NOWAIT); 85978064Sume if (ia == NULL) 86078064Sume return (ENOBUFS); 86178064Sume bzero((caddr_t)ia, sizeof(*ia)); 86278064Sume /* Initialize the address and masks */ 863108033Shsu IFA_LOCK_INIT(&ia->ia_ifa); 86478064Sume ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 86578064Sume ia->ia_addr.sin6_family = AF_INET6; 86678064Sume ia->ia_addr.sin6_len = sizeof(ia->ia_addr); 86778064Sume if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { 86878064Sume /* 86978064Sume * XXX: some functions expect that ifa_dstaddr is not 87078064Sume * NULL for p2p interfaces. 87178064Sume */ 872120891Sume ia->ia_ifa.ifa_dstaddr = 873120891Sume (struct sockaddr *)&ia->ia_dstaddr; 87478064Sume } else { 87578064Sume ia->ia_ifa.ifa_dstaddr = NULL; 87653541Sshin } 877108033Shsu ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; 87878064Sume 87978064Sume ia->ia_ifp = ifp; 88078064Sume if ((oia = in6_ifaddr) != NULL) { 88178064Sume for ( ; oia->ia_next; oia = oia->ia_next) 88278064Sume continue; 88378064Sume oia->ia_next = ia; 88478064Sume } else 88578064Sume in6_ifaddr = ia; 88678064Sume 887108033Shsu ia->ia_ifa.ifa_refcnt = 1; 888108033Shsu TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); 88978064Sume } 89078064Sume 89178064Sume /* set prefix mask */ 89278064Sume if (ifra->ifra_prefixmask.sin6_len) { 89378064Sume /* 89478064Sume * We prohibit changing the prefix length of an existing 89578064Sume * address, because 89678064Sume * + such an operation should be rare in IPv6, and 89778064Sume * + the operation would confuse prefix management. 89878064Sume */ 89978064Sume if (ia->ia_prefixmask.sin6_len && 90078064Sume in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) { 901122059Sume nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an" 90278064Sume " existing (%s) address should not be changed\n", 903122059Sume ip6_sprintf(&ia->ia_addr.sin6_addr))); 90478064Sume error = EINVAL; 90578064Sume goto unlink; 90653541Sshin } 90778064Sume ia->ia_prefixmask = ifra->ifra_prefixmask; 90878064Sume } 90978064Sume 91078064Sume /* 91178064Sume * If a new destination address is specified, scrub the old one and 91278064Sume * install the new destination. Note that the interface must be 913120891Sume * p2p or loopback (see the check above.) 91478064Sume */ 91578064Sume if (dst6.sin6_family == AF_INET6 && 916120891Sume !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) { 91778064Sume int e; 91878064Sume 91978064Sume if ((ia->ia_flags & IFA_ROUTE) != 0 && 920120891Sume (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) { 921122059Sume nd6log((LOG_ERR, "in6_update_ifa: failed to remove " 92278064Sume "a route to the old destination: %s\n", 923122059Sume ip6_sprintf(&ia->ia_addr.sin6_addr))); 92478064Sume /* proceed anyway... */ 925120891Sume } else 92678064Sume ia->ia_flags &= ~IFA_ROUTE; 92778064Sume ia->ia_dstaddr = dst6; 92878064Sume } 92953541Sshin 93078064Sume /* reset the interface and routing table appropriately. */ 93178064Sume if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) 93278064Sume goto unlink; 93378064Sume 93478064Sume /* 93578064Sume * Beyond this point, we should call in6_purgeaddr upon an error, 936120891Sume * not just go to unlink. 93778064Sume */ 93878064Sume 93978064Sume if ((ifp->if_flags & IFF_MULTICAST) != 0) { 94078064Sume struct sockaddr_in6 mltaddr, mltmask; 94178064Sume struct in6_multi *in6m; 94278064Sume 94378064Sume if (hostIsNew) { 944120891Sume /* join solicited multicast addr for new host id */ 94553541Sshin struct in6_addr llsol; 946120891Sume 94753541Sshin bzero(&llsol, sizeof(struct in6_addr)); 94853541Sshin llsol.s6_addr16[0] = htons(0xff02); 94953541Sshin llsol.s6_addr16[1] = htons(ifp->if_index); 95053541Sshin llsol.s6_addr32[1] = 0; 95153541Sshin llsol.s6_addr32[2] = htonl(1); 95253541Sshin llsol.s6_addr32[3] = 95353541Sshin ifra->ifra_addr.sin6_addr.s6_addr32[3]; 95453541Sshin llsol.s6_addr8[12] = 0xff; 95578064Sume (void)in6_addmulti(&llsol, ifp, &error); 95678064Sume if (error != 0) { 957122059Sume nd6log((LOG_WARNING, 95878064Sume "in6_update_ifa: addmulti failed for " 95978064Sume "%s on %s (errno=%d)\n", 96078064Sume ip6_sprintf(&llsol), if_name(ifp), 961122059Sume error)); 96278064Sume in6_purgeaddr((struct ifaddr *)ia); 963120856Sume return (error); 96478064Sume } 96553541Sshin } 96653541Sshin 96778064Sume bzero(&mltmask, sizeof(mltmask)); 96878064Sume mltmask.sin6_len = sizeof(struct sockaddr_in6); 96978064Sume mltmask.sin6_family = AF_INET6; 97078064Sume mltmask.sin6_addr = in6mask32; 97153541Sshin 97253541Sshin /* 97378064Sume * join link-local all-nodes address 97471207Sitojun */ 97578064Sume bzero(&mltaddr, sizeof(mltaddr)); 97678064Sume mltaddr.sin6_len = sizeof(struct sockaddr_in6); 97778064Sume mltaddr.sin6_family = AF_INET6; 97878064Sume mltaddr.sin6_addr = in6addr_linklocal_allnodes; 97978064Sume mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 98071207Sitojun 98178064Sume IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 98278064Sume if (in6m == NULL) { 98378064Sume rtrequest(RTM_ADD, 98478064Sume (struct sockaddr *)&mltaddr, 98578064Sume (struct sockaddr *)&ia->ia_addr, 98678064Sume (struct sockaddr *)&mltmask, 98778064Sume RTF_UP|RTF_CLONING, /* xxx */ 98878064Sume (struct rtentry **)0); 98978064Sume (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); 99078064Sume if (error != 0) { 991122059Sume nd6log((LOG_WARNING, 99278064Sume "in6_update_ifa: addmulti failed for " 99378064Sume "%s on %s (errno=%d)\n", 994122059Sume ip6_sprintf(&mltaddr.sin6_addr), 995122059Sume if_name(ifp), error)); 99678064Sume } 99778064Sume } 99878064Sume 99971207Sitojun /* 100078064Sume * join node information group address 100153541Sshin */ 100278064Sume#define hostnamelen strlen(hostname) 100378064Sume if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr) 100478064Sume == 0) { 100578064Sume IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 100678064Sume if (in6m == NULL && ia != NULL) { 100778064Sume (void)in6_addmulti(&mltaddr.sin6_addr, 100878064Sume ifp, &error); 100978064Sume if (error != 0) { 1010122059Sume nd6log((LOG_WARNING, "in6_update_ifa: " 101178064Sume "addmulti failed for " 101278064Sume "%s on %s (errno=%d)\n", 1013122059Sume ip6_sprintf(&mltaddr.sin6_addr), 1014122059Sume if_name(ifp), error)); 101578064Sume } 101662587Sitojun } 101753541Sshin } 101878064Sume#undef hostnamelen 101953541Sshin 102078064Sume /* 102178064Sume * join node-local all-nodes address, on loopback. 102278064Sume * XXX: since "node-local" is obsoleted by interface-local, 102378064Sume * we have to join the group on every interface with 102478064Sume * some interface-boundary restriction. 102578064Sume */ 102678064Sume if (ifp->if_flags & IFF_LOOPBACK) { 102781115Sume struct in6_ifaddr *ia_loop; 102881115Sume 102978064Sume struct in6_addr loop6 = in6addr_loopback; 103081115Sume ia_loop = in6ifa_ifpwithaddr(ifp, &loop6); 103153541Sshin 103278064Sume mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 103378064Sume 103478064Sume IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 103581115Sume if (in6m == NULL && ia_loop != NULL) { 103678064Sume rtrequest(RTM_ADD, 103778064Sume (struct sockaddr *)&mltaddr, 103881115Sume (struct sockaddr *)&ia_loop->ia_addr, 103978064Sume (struct sockaddr *)&mltmask, 104078064Sume RTF_UP, 104178064Sume (struct rtentry **)0); 104278064Sume (void)in6_addmulti(&mltaddr.sin6_addr, ifp, 104378064Sume &error); 104478064Sume if (error != 0) { 1045122059Sume nd6log((LOG_WARNING, "in6_update_ifa: " 104678064Sume "addmulti failed for %s on %s " 104778064Sume "(errno=%d)\n", 1048122059Sume ip6_sprintf(&mltaddr.sin6_addr), 1049122059Sume if_name(ifp), error)); 105078064Sume } 105178064Sume } 105253541Sshin } 105378064Sume } 105453541Sshin 105578064Sume ia->ia6_flags = ifra->ifra_flags; 105678064Sume ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/ 105778064Sume ia->ia6_flags &= ~IN6_IFF_NODAD; /* Mobile IPv6 */ 105853541Sshin 105978064Sume ia->ia6_lifetime = ifra->ifra_lifetime; 106078064Sume /* for sanity */ 106178064Sume if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 106278064Sume ia->ia6_lifetime.ia6t_expire = 106378064Sume time_second + ia->ia6_lifetime.ia6t_vltime; 106478064Sume } else 106578064Sume ia->ia6_lifetime.ia6t_expire = 0; 106678064Sume if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 106778064Sume ia->ia6_lifetime.ia6t_preferred = 106878064Sume time_second + ia->ia6_lifetime.ia6t_pltime; 106978064Sume } else 107078064Sume ia->ia6_lifetime.ia6t_preferred = 0; 107153541Sshin 107278064Sume /* 107378064Sume * Perform DAD, if needed. 107478064Sume * XXX It may be of use, if we can administratively 107578064Sume * disable DAD. 107678064Sume */ 107778064Sume if (in6if_do_dad(ifp) && (ifra->ifra_flags & IN6_IFF_NODAD) == 0) { 107878064Sume ia->ia6_flags |= IN6_IFF_TENTATIVE; 107978064Sume nd6_dad_start((struct ifaddr *)ia, NULL); 108053541Sshin } 108178064Sume 1082120856Sume return (error); 108378064Sume 108478064Sume unlink: 108578064Sume /* 108678064Sume * XXX: if a change of an existing address failed, keep the entry 108778064Sume * anyway. 108878064Sume */ 108978064Sume if (hostIsNew) 109078064Sume in6_unlink_ifa(ia, ifp); 1091120856Sume return (error); 109253541Sshin} 109353541Sshin 109462587Sitojunvoid 109578064Sumein6_purgeaddr(ifa) 109662587Sitojun struct ifaddr *ifa; 109762587Sitojun{ 109878064Sume struct ifnet *ifp = ifa->ifa_ifp; 109978064Sume struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; 110062587Sitojun 110178064Sume /* stop DAD processing */ 110278064Sume nd6_dad_stop(ifa); 110362587Sitojun 110478064Sume /* 110578064Sume * delete route to the destination of the address being purged. 110678064Sume * The interface must be p2p or loopback in this case. 110778064Sume */ 110878064Sume if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) { 110978064Sume int e; 111078064Sume 111178064Sume if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) 111278064Sume != 0) { 111378064Sume log(LOG_ERR, "in6_purgeaddr: failed to remove " 111478064Sume "a route to the p2p destination: %s on %s, " 111578064Sume "errno=%d\n", 111678064Sume ip6_sprintf(&ia->ia_addr.sin6_addr), if_name(ifp), 111778064Sume e); 111878064Sume /* proceed anyway... */ 1119120891Sume } else 112078064Sume ia->ia_flags &= ~IFA_ROUTE; 112178064Sume } 112278064Sume 112378064Sume /* Remove ownaddr's loopback rtentry, if it exists. */ 112478064Sume in6_ifremloop(&(ia->ia_ifa)); 112578064Sume 112662587Sitojun if (ifp->if_flags & IFF_MULTICAST) { 112762587Sitojun /* 112862587Sitojun * delete solicited multicast addr for deleting host id 112962587Sitojun */ 113062587Sitojun struct in6_multi *in6m; 113162587Sitojun struct in6_addr llsol; 113262587Sitojun bzero(&llsol, sizeof(struct in6_addr)); 113362587Sitojun llsol.s6_addr16[0] = htons(0xff02); 113462587Sitojun llsol.s6_addr16[1] = htons(ifp->if_index); 113562587Sitojun llsol.s6_addr32[1] = 0; 113662587Sitojun llsol.s6_addr32[2] = htonl(1); 113762587Sitojun llsol.s6_addr32[3] = 113862587Sitojun ia->ia_addr.sin6_addr.s6_addr32[3]; 113962587Sitojun llsol.s6_addr8[12] = 0xff; 114062587Sitojun 114162587Sitojun IN6_LOOKUP_MULTI(llsol, ifp, in6m); 114262587Sitojun if (in6m) 114362587Sitojun in6_delmulti(in6m); 114462587Sitojun } 114562587Sitojun 114678064Sume in6_unlink_ifa(ia, ifp); 114778064Sume} 114878064Sume 114978064Sumestatic void 115078064Sumein6_unlink_ifa(ia, ifp) 115178064Sume struct in6_ifaddr *ia; 115278064Sume struct ifnet *ifp; 115378064Sume{ 115478064Sume struct in6_ifaddr *oia; 115578064Sume int s = splnet(); 115678064Sume 115762587Sitojun TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); 115862587Sitojun 115962587Sitojun oia = ia; 116062587Sitojun if (oia == (ia = in6_ifaddr)) 116162587Sitojun in6_ifaddr = ia->ia_next; 116262587Sitojun else { 116362587Sitojun while (ia->ia_next && (ia->ia_next != oia)) 116462587Sitojun ia = ia->ia_next; 116562587Sitojun if (ia->ia_next) 116662587Sitojun ia->ia_next = oia->ia_next; 116778064Sume else { 116878064Sume /* search failed */ 116978064Sume printf("Couldn't unlink in6_ifaddr from in6_ifaddr\n"); 117078064Sume } 117162587Sitojun } 117262587Sitojun 117362587Sitojun /* 117478064Sume * When an autoconfigured address is being removed, release the 117578064Sume * reference to the base prefix. Also, since the release might 117678064Sume * affect the status of other (detached) addresses, call 117778064Sume * pfxlist_onlink_check(). 117862587Sitojun */ 117978064Sume if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) { 118078064Sume if (oia->ia6_ndpr == NULL) { 1181122059Sume nd6log((LOG_NOTICE, "in6_unlink_ifa: autoconf'ed address " 1182122059Sume "%p has no prefix\n", oia)); 118378064Sume } else { 118478064Sume oia->ia6_ndpr->ndpr_refcnt--; 118578064Sume oia->ia6_flags &= ~IN6_IFF_AUTOCONF; 118678064Sume oia->ia6_ndpr = NULL; 118778064Sume } 118862587Sitojun 118978064Sume pfxlist_onlink_check(); 119062587Sitojun } 119178064Sume 119278064Sume /* 119378064Sume * release another refcnt for the link from in6_ifaddr. 119478064Sume * Note that we should decrement the refcnt at least once for all *BSD. 119578064Sume */ 119662587Sitojun IFAFREE(&oia->ia_ifa); 119778064Sume 119878064Sume splx(s); 119962587Sitojun} 120062587Sitojun 120178064Sumevoid 120278064Sumein6_purgeif(ifp) 120378064Sume struct ifnet *ifp; 120478064Sume{ 120578064Sume struct ifaddr *ifa, *nifa; 120678064Sume 1207120891Sume for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa) { 120878064Sume nifa = TAILQ_NEXT(ifa, ifa_list); 120978064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 121078064Sume continue; 121178064Sume in6_purgeaddr(ifa); 121278064Sume } 121378064Sume 121478064Sume in6_ifdetach(ifp); 121578064Sume} 121678064Sume 121753541Sshin/* 121853541Sshin * SIOC[GAD]LIFADDR. 121962744Sgrog * SIOCGLIFADDR: get first address. (?) 122053541Sshin * SIOCGLIFADDR with IFLR_PREFIX: 122153541Sshin * get first address that matches the specified prefix. 122253541Sshin * SIOCALIFADDR: add the specified address. 122353541Sshin * SIOCALIFADDR with IFLR_PREFIX: 122453541Sshin * add the specified prefix, filling hostid part from 122553541Sshin * the first link-local address. prefixlen must be <= 64. 122653541Sshin * SIOCDLIFADDR: delete the specified address. 122753541Sshin * SIOCDLIFADDR with IFLR_PREFIX: 122853541Sshin * delete the first address that matches the specified prefix. 122953541Sshin * return values: 123053541Sshin * EINVAL on invalid parameters 123153541Sshin * EADDRNOTAVAIL on prefix match failed/specified address not found 123253541Sshin * other values may be returned from in6_ioctl() 123353541Sshin * 123453541Sshin * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64. 123553541Sshin * this is to accomodate address naming scheme other than RFC2374, 123653541Sshin * in the future. 123753541Sshin * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374 123853541Sshin * address encoding scheme. (see figure on page 8) 123953541Sshin */ 124053541Sshinstatic int 124183366Sjulianin6_lifaddr_ioctl(so, cmd, data, ifp, td) 124253541Sshin struct socket *so; 124353541Sshin u_long cmd; 124453541Sshin caddr_t data; 124553541Sshin struct ifnet *ifp; 124683366Sjulian struct thread *td; 124753541Sshin{ 124853541Sshin struct if_laddrreq *iflr = (struct if_laddrreq *)data; 124953541Sshin struct ifaddr *ifa; 125062587Sitojun struct sockaddr *sa; 125153541Sshin 125253541Sshin /* sanity checks */ 125353541Sshin if (!data || !ifp) { 125453541Sshin panic("invalid argument to in6_lifaddr_ioctl"); 1255120891Sume /* NOTREACHED */ 125653541Sshin } 125753541Sshin 125853541Sshin switch (cmd) { 125953541Sshin case SIOCGLIFADDR: 126053541Sshin /* address must be specified on GET with IFLR_PREFIX */ 126153541Sshin if ((iflr->flags & IFLR_PREFIX) == 0) 126253541Sshin break; 126395023Ssuz /* FALLTHROUGH */ 126453541Sshin case SIOCALIFADDR: 126553541Sshin case SIOCDLIFADDR: 126653541Sshin /* address must be specified on ADD and DELETE */ 126762587Sitojun sa = (struct sockaddr *)&iflr->addr; 126862587Sitojun if (sa->sa_family != AF_INET6) 126953541Sshin return EINVAL; 127062587Sitojun if (sa->sa_len != sizeof(struct sockaddr_in6)) 127153541Sshin return EINVAL; 127253541Sshin /* XXX need improvement */ 127362587Sitojun sa = (struct sockaddr *)&iflr->dstaddr; 127462587Sitojun if (sa->sa_family && sa->sa_family != AF_INET6) 127553541Sshin return EINVAL; 127662587Sitojun if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6)) 127753541Sshin return EINVAL; 127853541Sshin break; 127995023Ssuz default: /* shouldn't happen */ 128062587Sitojun#if 0 128162587Sitojun panic("invalid cmd to in6_lifaddr_ioctl"); 128295023Ssuz /* NOTREACHED */ 128362587Sitojun#else 128453541Sshin return EOPNOTSUPP; 128562587Sitojun#endif 128653541Sshin } 128753541Sshin if (sizeof(struct in6_addr) * 8 < iflr->prefixlen) 128853541Sshin return EINVAL; 128953541Sshin 129053541Sshin switch (cmd) { 129153541Sshin case SIOCALIFADDR: 129253541Sshin { 129353541Sshin struct in6_aliasreq ifra; 129453541Sshin struct in6_addr *hostid = NULL; 129553541Sshin int prefixlen; 129653541Sshin 129753541Sshin if ((iflr->flags & IFLR_PREFIX) != 0) { 129853541Sshin struct sockaddr_in6 *sin6; 129953541Sshin 130053541Sshin /* 130153541Sshin * hostid is to fill in the hostid part of the 130253541Sshin * address. hostid points to the first link-local 130353541Sshin * address attached to the interface. 130453541Sshin */ 130562587Sitojun ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); 130653541Sshin if (!ifa) 130753541Sshin return EADDRNOTAVAIL; 130853541Sshin hostid = IFA_IN6(ifa); 130953541Sshin 131053541Sshin /* prefixlen must be <= 64. */ 131153541Sshin if (64 < iflr->prefixlen) 131253541Sshin return EINVAL; 131353541Sshin prefixlen = iflr->prefixlen; 131453541Sshin 131553541Sshin /* hostid part must be zero. */ 131653541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 1317126552Sume if (sin6->sin6_addr.s6_addr32[2] != 0 || 1318126552Sume sin6->sin6_addr.s6_addr32[3] != 0) { 131953541Sshin return EINVAL; 132053541Sshin } 132153541Sshin } else 132253541Sshin prefixlen = iflr->prefixlen; 132353541Sshin 132453541Sshin /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 132553541Sshin bzero(&ifra, sizeof(ifra)); 1326120891Sume bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name)); 132753541Sshin 132862587Sitojun bcopy(&iflr->addr, &ifra.ifra_addr, 1329120891Sume ((struct sockaddr *)&iflr->addr)->sa_len); 133053541Sshin if (hostid) { 133153541Sshin /* fill in hostid part */ 133253541Sshin ifra.ifra_addr.sin6_addr.s6_addr32[2] = 1333120891Sume hostid->s6_addr32[2]; 133453541Sshin ifra.ifra_addr.sin6_addr.s6_addr32[3] = 1335120891Sume hostid->s6_addr32[3]; 133653541Sshin } 133753541Sshin 1338120891Sume if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */ 133953541Sshin bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 1340120891Sume ((struct sockaddr *)&iflr->dstaddr)->sa_len); 134153541Sshin if (hostid) { 134253541Sshin ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] = 1343120891Sume hostid->s6_addr32[2]; 134453541Sshin ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = 1345120891Sume hostid->s6_addr32[3]; 134653541Sshin } 134753541Sshin } 134853541Sshin 134953541Sshin ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 1350121168Sume in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); 135153541Sshin 135253541Sshin ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; 135383366Sjulian return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, td); 135453541Sshin } 135553541Sshin case SIOCGLIFADDR: 135653541Sshin case SIOCDLIFADDR: 135753541Sshin { 135853541Sshin struct in6_ifaddr *ia; 135953541Sshin struct in6_addr mask, candidate, match; 136053541Sshin struct sockaddr_in6 *sin6; 136153541Sshin int cmp; 136253541Sshin 136353541Sshin bzero(&mask, sizeof(mask)); 136453541Sshin if (iflr->flags & IFLR_PREFIX) { 136553541Sshin /* lookup a prefix rather than address. */ 1366121168Sume in6_prefixlen2mask(&mask, iflr->prefixlen); 136753541Sshin 136853541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 136953541Sshin bcopy(&sin6->sin6_addr, &match, sizeof(match)); 137053541Sshin match.s6_addr32[0] &= mask.s6_addr32[0]; 137153541Sshin match.s6_addr32[1] &= mask.s6_addr32[1]; 137253541Sshin match.s6_addr32[2] &= mask.s6_addr32[2]; 137353541Sshin match.s6_addr32[3] &= mask.s6_addr32[3]; 137453541Sshin 137553541Sshin /* if you set extra bits, that's wrong */ 137653541Sshin if (bcmp(&match, &sin6->sin6_addr, sizeof(match))) 137753541Sshin return EINVAL; 137853541Sshin 137953541Sshin cmp = 1; 138053541Sshin } else { 138153541Sshin if (cmd == SIOCGLIFADDR) { 138253541Sshin /* on getting an address, take the 1st match */ 138395023Ssuz cmp = 0; /* XXX */ 138453541Sshin } else { 138553541Sshin /* on deleting an address, do exact match */ 1386121168Sume in6_prefixlen2mask(&mask, 128); 138753541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 138853541Sshin bcopy(&sin6->sin6_addr, &match, sizeof(match)); 138953541Sshin 139053541Sshin cmp = 1; 139153541Sshin } 139253541Sshin } 139353541Sshin 1394120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 139553541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 139653541Sshin continue; 139753541Sshin if (!cmp) 139853541Sshin break; 139978064Sume 140053541Sshin bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate)); 140178064Sume /* 140278064Sume * XXX: this is adhoc, but is necessary to allow 140378064Sume * a user to specify fe80::/64 (not /10) for a 140478064Sume * link-local address. 140578064Sume */ 140678064Sume if (IN6_IS_ADDR_LINKLOCAL(&candidate)) 140778064Sume candidate.s6_addr16[1] = 0; 140853541Sshin candidate.s6_addr32[0] &= mask.s6_addr32[0]; 140953541Sshin candidate.s6_addr32[1] &= mask.s6_addr32[1]; 141053541Sshin candidate.s6_addr32[2] &= mask.s6_addr32[2]; 141153541Sshin candidate.s6_addr32[3] &= mask.s6_addr32[3]; 141253541Sshin if (IN6_ARE_ADDR_EQUAL(&candidate, &match)) 141353541Sshin break; 141453541Sshin } 141553541Sshin if (!ifa) 141653541Sshin return EADDRNOTAVAIL; 141753541Sshin ia = ifa2ia6(ifa); 141853541Sshin 141953541Sshin if (cmd == SIOCGLIFADDR) { 142078064Sume struct sockaddr_in6 *s6; 142178064Sume 142253541Sshin /* fill in the if_laddrreq structure */ 142353541Sshin bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len); 142478064Sume s6 = (struct sockaddr_in6 *)&iflr->addr; 142578064Sume if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { 142678064Sume s6->sin6_addr.s6_addr16[1] = 0; 1427121315Sume if (in6_addr2zoneid(ifp, &s6->sin6_addr, 1428121315Sume &s6->sin6_scope_id)) 1429126552Sume return (EINVAL); /* XXX */ 143078064Sume } 143153541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 143253541Sshin bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 1433120891Sume ia->ia_dstaddr.sin6_len); 143478064Sume s6 = (struct sockaddr_in6 *)&iflr->dstaddr; 143578064Sume if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { 143678064Sume s6->sin6_addr.s6_addr16[1] = 0; 1437121315Sume if (in6_addr2zoneid(ifp, 1438121315Sume &s6->sin6_addr, &s6->sin6_scope_id)) 1439121315Sume return (EINVAL); /* EINVAL */ 144078064Sume } 144153541Sshin } else 144253541Sshin bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 144353541Sshin 144453541Sshin iflr->prefixlen = 1445120891Sume in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 144653541Sshin 144795023Ssuz iflr->flags = ia->ia6_flags; /* XXX */ 144853541Sshin 144953541Sshin return 0; 145053541Sshin } else { 145153541Sshin struct in6_aliasreq ifra; 145253541Sshin 145353541Sshin /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 145453541Sshin bzero(&ifra, sizeof(ifra)); 145553541Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 1456120891Sume sizeof(ifra.ifra_name)); 145753541Sshin 145853541Sshin bcopy(&ia->ia_addr, &ifra.ifra_addr, 1459120891Sume ia->ia_addr.sin6_len); 146053541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 146153541Sshin bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 1462120891Sume ia->ia_dstaddr.sin6_len); 146362587Sitojun } else { 146462587Sitojun bzero(&ifra.ifra_dstaddr, 146562587Sitojun sizeof(ifra.ifra_dstaddr)); 146653541Sshin } 146753541Sshin bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr, 1468120891Sume ia->ia_prefixmask.sin6_len); 146953541Sshin 147053541Sshin ifra.ifra_flags = ia->ia6_flags; 147153541Sshin return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, 1472120891Sume ifp, td); 147353541Sshin } 147453541Sshin } 147553541Sshin } 147653541Sshin 147795023Ssuz return EOPNOTSUPP; /* just for safety */ 147853541Sshin} 147953541Sshin 148053541Sshin/* 148153541Sshin * Initialize an interface's intetnet6 address 148253541Sshin * and routing table entry. 148353541Sshin */ 148478064Sumestatic int 148578064Sumein6_ifinit(ifp, ia, sin6, newhost) 148653541Sshin struct ifnet *ifp; 148753541Sshin struct in6_ifaddr *ia; 148853541Sshin struct sockaddr_in6 *sin6; 148978064Sume int newhost; 149053541Sshin{ 149178064Sume int error = 0, plen, ifacount = 0; 149253541Sshin int s = splimp(); 149378064Sume struct ifaddr *ifa; 149453541Sshin 149553541Sshin /* 149653541Sshin * Give the interface a chance to initialize 149753541Sshin * if this is its first address, 149853541Sshin * and to validate the address if necessary. 149953541Sshin */ 1500120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 150178064Sume if (ifa->ifa_addr == NULL) 150278064Sume continue; /* just for safety */ 150378064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 150478064Sume continue; 150578064Sume ifacount++; 150678064Sume } 150778064Sume 150878064Sume ia->ia_addr = *sin6; 150978064Sume 1510146883Siedowse if (ifacount <= 1 && ifp->if_ioctl) { 1511146883Siedowse IFF_LOCKGIANT(ifp); 1512146883Siedowse error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); 1513146883Siedowse IFF_UNLOCKGIANT(ifp); 1514146883Siedowse if (error) { 1515146883Siedowse splx(s); 1516146883Siedowse return (error); 1517146883Siedowse } 151853541Sshin } 151978064Sume splx(s); 152053541Sshin 152178064Sume ia->ia_ifa.ifa_metric = ifp->if_metric; 152253541Sshin 152378064Sume /* we could do in(6)_socktrim here, but just omit it at this moment. */ 152478064Sume 152553541Sshin /* 152678064Sume * Special case: 1527124337Sume * If a new destination address is specified for a point-to-point 152878064Sume * interface, install a route to the destination as an interface 152978064Sume * direct route. 1530124337Sume * XXX: the logic below rejects assigning multiple addresses on a p2p 1531124337Sume * interface that share a same destination. 153253541Sshin */ 153378064Sume plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ 1534124337Sume if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 && 1535124337Sume ia->ia_dstaddr.sin6_family == AF_INET6) { 153678064Sume if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, 153778064Sume RTF_UP | RTF_HOST)) != 0) 1538120856Sume return (error); 153978064Sume ia->ia_flags |= IFA_ROUTE; 154053541Sshin } 154178064Sume if (plen < 128) { 154278064Sume /* 154378064Sume * The RTF_CLONING flag is necessary for in6_is_ifloop_auto(). 154478064Sume */ 154578064Sume ia->ia_ifa.ifa_flags |= RTF_CLONING; 154678064Sume } 154753541Sshin 154895023Ssuz /* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */ 154978064Sume if (newhost) { 155078064Sume /* set the rtrequest function to create llinfo */ 155178064Sume ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; 155278064Sume in6_ifaddloop(&(ia->ia_ifa)); 155378064Sume } 155453541Sshin 1555120856Sume return (error); 155653541Sshin} 155753541Sshin 1558142215Sglebiusstruct in6_multi_mship * 1559142215Sglebiusin6_joingroup(ifp, addr, errorp) 1560142215Sglebius struct ifnet *ifp; 1561142215Sglebius struct in6_addr *addr; 1562142215Sglebius int *errorp; 1563142215Sglebius{ 1564142215Sglebius struct in6_multi_mship *imm; 1565142215Sglebius 1566142215Sglebius imm = malloc(sizeof(*imm), M_IPMADDR, M_NOWAIT); 1567142215Sglebius if (!imm) { 1568142215Sglebius *errorp = ENOBUFS; 1569142215Sglebius return NULL; 1570142215Sglebius } 1571142215Sglebius imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp); 1572142215Sglebius if (!imm->i6mm_maddr) { 1573142215Sglebius /* *errorp is alrady set */ 1574142215Sglebius free(imm, M_IPMADDR); 1575142215Sglebius return NULL; 1576142215Sglebius } 1577142215Sglebius return imm; 1578142215Sglebius} 1579142215Sglebius 1580142215Sglebiusint 1581142215Sglebiusin6_leavegroup(imm) 1582142215Sglebius struct in6_multi_mship *imm; 1583142215Sglebius{ 1584142215Sglebius 1585142215Sglebius if (imm->i6mm_maddr) 1586142215Sglebius in6_delmulti(imm->i6mm_maddr); 1587142215Sglebius free(imm, M_IPMADDR); 1588142215Sglebius return 0; 1589142215Sglebius} 1590142215Sglebius 159153541Sshin/* 159253541Sshin * Find an IPv6 interface link-local address specific to an interface. 159353541Sshin */ 159453541Sshinstruct in6_ifaddr * 159562587Sitojunin6ifa_ifpforlinklocal(ifp, ignoreflags) 159653541Sshin struct ifnet *ifp; 159762587Sitojun int ignoreflags; 159853541Sshin{ 159978064Sume struct ifaddr *ifa; 160053541Sshin 1601120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 160253541Sshin if (ifa->ifa_addr == NULL) 160353541Sshin continue; /* just for safety */ 160453541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 160553541Sshin continue; 160662587Sitojun if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { 160762587Sitojun if ((((struct in6_ifaddr *)ifa)->ia6_flags & 160862587Sitojun ignoreflags) != 0) 160962587Sitojun continue; 161053541Sshin break; 161162587Sitojun } 161253541Sshin } 161353541Sshin 1614120856Sume return ((struct in6_ifaddr *)ifa); 161553541Sshin} 161653541Sshin 161753541Sshin 161853541Sshin/* 161953541Sshin * find the internet address corresponding to a given interface and address. 162053541Sshin */ 162153541Sshinstruct in6_ifaddr * 162253541Sshinin6ifa_ifpwithaddr(ifp, addr) 162353541Sshin struct ifnet *ifp; 162453541Sshin struct in6_addr *addr; 162553541Sshin{ 162678064Sume struct ifaddr *ifa; 162753541Sshin 1628120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 162953541Sshin if (ifa->ifa_addr == NULL) 163053541Sshin continue; /* just for safety */ 163153541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 163253541Sshin continue; 163353541Sshin if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) 163453541Sshin break; 163553541Sshin } 163653541Sshin 1637120856Sume return ((struct in6_ifaddr *)ifa); 163853541Sshin} 163953541Sshin 164053541Sshin/* 164153541Sshin * Convert IP6 address to printable (loggable) representation. 164253541Sshin */ 164353541Sshinstatic char digits[] = "0123456789abcdef"; 164453541Sshinstatic int ip6round = 0; 164553541Sshinchar * 164653541Sshinip6_sprintf(addr) 164778064Sume const struct in6_addr *addr; 164853541Sshin{ 164953541Sshin static char ip6buf[8][48]; 165078064Sume int i; 165178064Sume char *cp; 1652126552Sume const u_int16_t *a = (const u_int16_t *)addr; 1653126552Sume const u_int8_t *d; 165453541Sshin int dcolon = 0; 165553541Sshin 165653541Sshin ip6round = (ip6round + 1) & 7; 165753541Sshin cp = ip6buf[ip6round]; 165853541Sshin 165953541Sshin for (i = 0; i < 8; i++) { 166053541Sshin if (dcolon == 1) { 166153541Sshin if (*a == 0) { 166253541Sshin if (i == 7) 166353541Sshin *cp++ = ':'; 166453541Sshin a++; 166553541Sshin continue; 166653541Sshin } else 166753541Sshin dcolon = 2; 166853541Sshin } 166953541Sshin if (*a == 0) { 167053541Sshin if (dcolon == 0 && *(a + 1) == 0) { 167153541Sshin if (i == 0) 167253541Sshin *cp++ = ':'; 167353541Sshin *cp++ = ':'; 167453541Sshin dcolon = 1; 167553541Sshin } else { 167653541Sshin *cp++ = '0'; 167753541Sshin *cp++ = ':'; 167853541Sshin } 167953541Sshin a++; 168053541Sshin continue; 168153541Sshin } 168291346Salfred d = (const u_char *)a; 168353541Sshin *cp++ = digits[*d >> 4]; 168453541Sshin *cp++ = digits[*d++ & 0xf]; 168553541Sshin *cp++ = digits[*d >> 4]; 168653541Sshin *cp++ = digits[*d & 0xf]; 168753541Sshin *cp++ = ':'; 168853541Sshin a++; 168953541Sshin } 169053541Sshin *--cp = 0; 1691120856Sume return (ip6buf[ip6round]); 169253541Sshin} 169353541Sshin 169453541Sshinint 169553541Sshinin6_localaddr(in6) 169653541Sshin struct in6_addr *in6; 169753541Sshin{ 169853541Sshin struct in6_ifaddr *ia; 169953541Sshin 170053541Sshin if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6)) 170153541Sshin return 1; 170253541Sshin 1703120891Sume for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 170453541Sshin if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr, 1705120891Sume &ia->ia_prefixmask.sin6_addr)) { 170653541Sshin return 1; 1707120891Sume } 1708120891Sume } 170953541Sshin 171053541Sshin return (0); 171153541Sshin} 171253541Sshin 171378064Sumeint 171478064Sumein6_is_addr_deprecated(sa6) 171578064Sume struct sockaddr_in6 *sa6; 171678064Sume{ 171778064Sume struct in6_ifaddr *ia; 171878064Sume 171978064Sume for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 172078064Sume if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 172178064Sume &sa6->sin6_addr) && 172278064Sume (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) 1723120856Sume return (1); /* true */ 172478064Sume 172578064Sume /* XXX: do we still have to go thru the rest of the list? */ 172678064Sume } 172778064Sume 1728120856Sume return (0); /* false */ 172978064Sume} 173078064Sume 173153541Sshin/* 173253541Sshin * return length of part which dst and src are equal 173353541Sshin * hard coding... 173453541Sshin */ 173553541Sshinint 173653541Sshinin6_matchlen(src, dst) 173753541Sshinstruct in6_addr *src, *dst; 173853541Sshin{ 173953541Sshin int match = 0; 174053541Sshin u_char *s = (u_char *)src, *d = (u_char *)dst; 174153541Sshin u_char *lim = s + 16, r; 174253541Sshin 174353541Sshin while (s < lim) 174453541Sshin if ((r = (*d++ ^ *s++)) != 0) { 174553541Sshin while (r < 128) { 174653541Sshin match++; 174753541Sshin r <<= 1; 174853541Sshin } 174953541Sshin break; 175053541Sshin } else 175153541Sshin match += 8; 175253541Sshin return match; 175353541Sshin} 175453541Sshin 175562587Sitojun/* XXX: to be scope conscious */ 175653541Sshinint 175753541Sshinin6_are_prefix_equal(p1, p2, len) 175853541Sshin struct in6_addr *p1, *p2; 175953541Sshin int len; 176053541Sshin{ 176153541Sshin int bytelen, bitlen; 176253541Sshin 176353541Sshin /* sanity check */ 176453541Sshin if (0 > len || len > 128) { 176553541Sshin log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n", 176653541Sshin len); 1767120856Sume return (0); 176853541Sshin } 176953541Sshin 177053541Sshin bytelen = len / 8; 177153541Sshin bitlen = len % 8; 177253541Sshin 177353541Sshin if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen)) 1774120856Sume return (0); 1775126184Scperciva if (bitlen != 0 && 1776126184Scperciva p1->s6_addr[bytelen] >> (8 - bitlen) != 177753541Sshin p2->s6_addr[bytelen] >> (8 - bitlen)) 1778120856Sume return (0); 177953541Sshin 1780120856Sume return (1); 178153541Sshin} 178253541Sshin 178353541Sshinvoid 178453541Sshinin6_prefixlen2mask(maskp, len) 178553541Sshin struct in6_addr *maskp; 178653541Sshin int len; 178753541Sshin{ 178853541Sshin u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 178953541Sshin int bytelen, bitlen, i; 179053541Sshin 179153541Sshin /* sanity check */ 179253541Sshin if (0 > len || len > 128) { 179353541Sshin log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n", 179453541Sshin len); 179553541Sshin return; 179653541Sshin } 179753541Sshin 179853541Sshin bzero(maskp, sizeof(*maskp)); 179953541Sshin bytelen = len / 8; 180053541Sshin bitlen = len % 8; 180153541Sshin for (i = 0; i < bytelen; i++) 180253541Sshin maskp->s6_addr[i] = 0xff; 180353541Sshin if (bitlen) 180453541Sshin maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 180553541Sshin} 180653541Sshin 180753541Sshin/* 180853541Sshin * return the best address out of the same scope. if no address was 180953541Sshin * found, return the first valid address from designated IF. 181053541Sshin */ 181153541Sshinstruct in6_ifaddr * 181253541Sshinin6_ifawithifp(ifp, dst) 181378064Sume struct ifnet *ifp; 181478064Sume struct in6_addr *dst; 181553541Sshin{ 181653541Sshin int dst_scope = in6_addrscope(dst), blen = -1, tlen; 181753541Sshin struct ifaddr *ifa; 181853541Sshin struct in6_ifaddr *besta = 0; 181995023Ssuz struct in6_ifaddr *dep[2]; /* last-resort: deprecated */ 182053541Sshin 182153541Sshin dep[0] = dep[1] = NULL; 182253541Sshin 182353541Sshin /* 182453541Sshin * We first look for addresses in the same scope. 182553541Sshin * If there is one, return it. 182653541Sshin * If two or more, return one which matches the dst longest. 182753541Sshin * If none, return one of global addresses assigned other ifs. 182853541Sshin */ 1829120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 183053541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 183153541Sshin continue; 183253541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 183353541Sshin continue; /* XXX: is there any case to allow anycast? */ 183453541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 183553541Sshin continue; /* don't use this interface */ 183653541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 183753541Sshin continue; 183853541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 183953541Sshin if (ip6_use_deprecated) 184053541Sshin dep[0] = (struct in6_ifaddr *)ifa; 184153541Sshin continue; 184253541Sshin } 184353541Sshin 184453541Sshin if (dst_scope == in6_addrscope(IFA_IN6(ifa))) { 184553541Sshin /* 184653541Sshin * call in6_matchlen() as few as possible 184753541Sshin */ 184853541Sshin if (besta) { 184953541Sshin if (blen == -1) 185053541Sshin blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst); 185153541Sshin tlen = in6_matchlen(IFA_IN6(ifa), dst); 185253541Sshin if (tlen > blen) { 185353541Sshin blen = tlen; 185453541Sshin besta = (struct in6_ifaddr *)ifa; 185553541Sshin } 185653541Sshin } else 185753541Sshin besta = (struct in6_ifaddr *)ifa; 185853541Sshin } 185953541Sshin } 186053541Sshin if (besta) 1861120856Sume return (besta); 186253541Sshin 1863120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 186453541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 186553541Sshin continue; 186653541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 186753541Sshin continue; /* XXX: is there any case to allow anycast? */ 186853541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 186953541Sshin continue; /* don't use this interface */ 187053541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 187153541Sshin continue; 187253541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 187353541Sshin if (ip6_use_deprecated) 187453541Sshin dep[1] = (struct in6_ifaddr *)ifa; 187553541Sshin continue; 187653541Sshin } 187753541Sshin 187853541Sshin return (struct in6_ifaddr *)ifa; 187953541Sshin } 188053541Sshin 188153541Sshin /* use the last-resort values, that are, deprecated addresses */ 188253541Sshin if (dep[0]) 188353541Sshin return dep[0]; 188453541Sshin if (dep[1]) 188553541Sshin return dep[1]; 188653541Sshin 188753541Sshin return NULL; 188853541Sshin} 188953541Sshin 189053541Sshin/* 189153541Sshin * perform DAD when interface becomes IFF_UP. 189253541Sshin */ 189353541Sshinvoid 189453541Sshinin6_if_up(ifp) 189553541Sshin struct ifnet *ifp; 189653541Sshin{ 189753541Sshin struct ifaddr *ifa; 189853541Sshin struct in6_ifaddr *ia; 189953541Sshin int dad_delay; /* delay ticks before DAD output */ 190053541Sshin 190162587Sitojun /* 190262587Sitojun * special cases, like 6to4, are handled in in6_ifattach 190362587Sitojun */ 190462587Sitojun in6_ifattach(ifp, NULL); 190553541Sshin 190653541Sshin dad_delay = 0; 1907120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 190853541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 190953541Sshin continue; 191053541Sshin ia = (struct in6_ifaddr *)ifa; 191153541Sshin if (ia->ia6_flags & IN6_IFF_TENTATIVE) 191253541Sshin nd6_dad_start(ifa, &dad_delay); 191353541Sshin } 191453541Sshin} 191553541Sshin 191678064Sumeint 191778064Sumein6if_do_dad(ifp) 191878064Sume struct ifnet *ifp; 191978064Sume{ 192078064Sume if ((ifp->if_flags & IFF_LOOPBACK) != 0) 1921120856Sume return (0); 192278064Sume 192378064Sume switch (ifp->if_type) { 192478064Sume#ifdef IFT_DUMMY 192578064Sume case IFT_DUMMY: 192678064Sume#endif 192778064Sume case IFT_FAITH: 192878064Sume /* 192978064Sume * These interfaces do not have the IFF_LOOPBACK flag, 193078064Sume * but loop packets back. We do not have to do DAD on such 193178064Sume * interfaces. We should even omit it, because loop-backed 193278064Sume * NS would confuse the DAD procedure. 193378064Sume */ 1934120856Sume return (0); 193578064Sume default: 193678064Sume /* 193778064Sume * Our DAD routine requires the interface up and running. 193878064Sume * However, some interfaces can be up before the RUNNING 193978064Sume * status. Additionaly, users may try to assign addresses 194078064Sume * before the interface becomes up (or running). 194178064Sume * We simply skip DAD in such a case as a work around. 194278064Sume * XXX: we should rather mark "tentative" on such addresses, 194378064Sume * and do DAD after the interface becomes ready. 194478064Sume */ 194578064Sume if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != 194678064Sume (IFF_UP|IFF_RUNNING)) 1947120856Sume return (0); 194878064Sume 1949120856Sume return (1); 195078064Sume } 195178064Sume} 195278064Sume 195353541Sshin/* 195453541Sshin * Calculate max IPv6 MTU through all the interfaces and store it 195553541Sshin * to in6_maxmtu. 195653541Sshin */ 195753541Sshinvoid 195853541Sshinin6_setmaxmtu() 195953541Sshin{ 196053541Sshin unsigned long maxmtu = 0; 196153541Sshin struct ifnet *ifp; 196253541Sshin 1963108172Shsu IFNET_RLOCK(); 1964120891Sume for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { 1965121283Sume /* this function can be called during ifnet initialization */ 1966121283Sume if (!ifp->if_afdata[AF_INET6]) 1967121283Sume continue; 196853541Sshin if ((ifp->if_flags & IFF_LOOPBACK) == 0 && 1969121283Sume IN6_LINKMTU(ifp) > maxmtu) 1970121283Sume maxmtu = IN6_LINKMTU(ifp); 197153541Sshin } 1972108172Shsu IFNET_RUNLOCK(); 1973120891Sume if (maxmtu) /* update only when maxmtu is positive */ 197453541Sshin in6_maxmtu = maxmtu; 197553541Sshin} 197653541Sshin 1977121161Sumevoid * 1978121161Sumein6_domifattach(ifp) 1979121161Sume struct ifnet *ifp; 1980121161Sume{ 1981121161Sume struct in6_ifextra *ext; 1982121161Sume 1983121161Sume ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK); 1984121161Sume bzero(ext, sizeof(*ext)); 1985121161Sume 1986121161Sume ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat), 1987121161Sume M_IFADDR, M_WAITOK); 1988121161Sume bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat)); 1989121161Sume 1990121161Sume ext->icmp6_ifstat = 1991121161Sume (struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat), 1992121161Sume M_IFADDR, M_WAITOK); 1993121161Sume bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat)); 1994121161Sume 1995121161Sume ext->nd_ifinfo = nd6_ifattach(ifp); 1996121161Sume ext->scope6_id = scope6_ifattach(ifp); 1997121161Sume return ext; 1998121161Sume} 1999121161Sume 2000121161Sumevoid 2001121161Sumein6_domifdetach(ifp, aux) 2002121161Sume struct ifnet *ifp; 2003121161Sume void *aux; 2004121161Sume{ 2005121161Sume struct in6_ifextra *ext = (struct in6_ifextra *)aux; 2006121161Sume 2007121161Sume scope6_ifdetach(ext->scope6_id); 2008121161Sume nd6_ifdetach(ext->nd_ifinfo); 2009121161Sume free(ext->in6_ifstat, M_IFADDR); 2010121161Sume free(ext->icmp6_ifstat, M_IFADDR); 2011121161Sume free(ext, M_IFADDR); 2012121161Sume} 2013121161Sume 201453541Sshin/* 201595023Ssuz * Convert sockaddr_in6 to sockaddr_in. Original sockaddr_in6 must be 201653541Sshin * v4 mapped addr or v4 compat addr 201753541Sshin */ 201853541Sshinvoid 201953541Sshinin6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 202053541Sshin{ 202153541Sshin bzero(sin, sizeof(*sin)); 202253541Sshin sin->sin_len = sizeof(struct sockaddr_in); 202353541Sshin sin->sin_family = AF_INET; 202453541Sshin sin->sin_port = sin6->sin6_port; 2025120891Sume sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3]; 202653541Sshin} 202753541Sshin 202853541Sshin/* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */ 202953541Sshinvoid 203053541Sshinin6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 203153541Sshin{ 203253541Sshin bzero(sin6, sizeof(*sin6)); 203353541Sshin sin6->sin6_len = sizeof(struct sockaddr_in6); 203453541Sshin sin6->sin6_family = AF_INET6; 203553541Sshin sin6->sin6_port = sin->sin_port; 203653541Sshin sin6->sin6_addr.s6_addr32[0] = 0; 203753541Sshin sin6->sin6_addr.s6_addr32[1] = 0; 203853541Sshin sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP; 203953541Sshin sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; 204053541Sshin} 204153541Sshin 204253541Sshin/* Convert sockaddr_in6 into sockaddr_in. */ 204353541Sshinvoid 204453541Sshinin6_sin6_2_sin_in_sock(struct sockaddr *nam) 204553541Sshin{ 204653541Sshin struct sockaddr_in *sin_p; 204753541Sshin struct sockaddr_in6 sin6; 204853541Sshin 204953541Sshin /* 205053541Sshin * Save original sockaddr_in6 addr and convert it 205153541Sshin * to sockaddr_in. 205253541Sshin */ 205353541Sshin sin6 = *(struct sockaddr_in6 *)nam; 205453541Sshin sin_p = (struct sockaddr_in *)nam; 205553541Sshin in6_sin6_2_sin(sin_p, &sin6); 205653541Sshin} 205753541Sshin 205853541Sshin/* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */ 205953541Sshinvoid 206053541Sshinin6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam) 206153541Sshin{ 206253541Sshin struct sockaddr_in *sin_p; 206353541Sshin struct sockaddr_in6 *sin6_p; 206453541Sshin 206553541Sshin MALLOC(sin6_p, struct sockaddr_in6 *, sizeof *sin6_p, M_SONAME, 2066111119Simp M_WAITOK); 206753541Sshin sin_p = (struct sockaddr_in *)*nam; 206853541Sshin in6_sin_2_v4mapsin6(sin_p, sin6_p); 206953541Sshin FREE(*nam, M_SONAME); 207053541Sshin *nam = (struct sockaddr *)sin6_p; 207153541Sshin} 2072