in6.c revision 148887
162587Sitojun/* $FreeBSD: head/sys/netinet6/in6.c 148887 2005-08-09 10:20:02Z rwatson $ */ 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; 333148385Sume int error, 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 */ 415148385Sume int error = 0; 41653541Sshin 417148385Sume if (ifra->ifra_addr.sin6_scope_id != 0) 418148385Sume error = sa6_embedscope(&ifra->ifra_addr, 0); 419148385Sume else 420148385Sume error = in6_setscope(&ifra->ifra_addr.sin6_addr, 421148385Sume ifp, NULL); 422148385Sume if (error != 0) 423148385Sume return (error); 42462587Sitojun ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr); 42553541Sshin } 42653541Sshin 42753541Sshin switch (cmd) { 42878064Sume case SIOCSIFADDR_IN6: 42978064Sume case SIOCSIFDSTADDR_IN6: 43078064Sume case SIOCSIFNETMASK_IN6: 43178064Sume /* 43278064Sume * Since IPv6 allows a node to assign multiple addresses 43378064Sume * on a single interface, SIOCSIFxxx ioctls are not suitable 43478064Sume * and should be unused. 43578064Sume */ 43678064Sume /* we decided to obsolete this command (20000704) */ 437120856Sume return (EINVAL); 43853541Sshin 43953541Sshin case SIOCDIFADDR_IN6: 44062587Sitojun /* 44178064Sume * for IPv4, we look for existing in_ifaddr here to allow 44262587Sitojun * "ifconfig if0 delete" to remove first IPv4 address on the 44362587Sitojun * interface. For IPv6, as the spec allow multiple interface 44462587Sitojun * address from the day one, we consider "remove the first one" 44578064Sume * semantics to be not preferable. 44662587Sitojun */ 44762587Sitojun if (ia == NULL) 448120856Sume return (EADDRNOTAVAIL); 44953541Sshin /* FALLTHROUGH */ 45053541Sshin case SIOCAIFADDR_IN6: 45162587Sitojun /* 45278064Sume * We always require users to specify a valid IPv6 address for 45378064Sume * the corresponding operation. 45462587Sitojun */ 45578064Sume if (ifra->ifra_addr.sin6_family != AF_INET6 || 45678064Sume ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) 457120856Sume return (EAFNOSUPPORT); 45853541Sshin if (!privileged) 459120856Sume return (EPERM); 46053541Sshin 46153541Sshin break; 46253541Sshin 46353541Sshin case SIOCGIFADDR_IN6: 46453541Sshin /* This interface is basically deprecated. use SIOCGIFCONF. */ 465120891Sume /* FALLTHROUGH */ 46653541Sshin case SIOCGIFAFLAG_IN6: 46753541Sshin case SIOCGIFNETMASK_IN6: 46853541Sshin case SIOCGIFDSTADDR_IN6: 46953541Sshin case SIOCGIFALIFETIME_IN6: 47053541Sshin /* must think again about its semantics */ 47162587Sitojun if (ia == NULL) 472120856Sume return (EADDRNOTAVAIL); 47353541Sshin break; 47453541Sshin case SIOCSIFALIFETIME_IN6: 47553541Sshin { 47653541Sshin struct in6_addrlifetime *lt; 47753541Sshin 47853541Sshin if (!privileged) 479120856Sume return (EPERM); 48062587Sitojun if (ia == NULL) 481120856Sume return (EADDRNOTAVAIL); 48253541Sshin /* sanity for overflow - beware unsigned */ 48353541Sshin lt = &ifr->ifr_ifru.ifru_lifetime; 484126552Sume if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME && 485126552Sume lt->ia6t_vltime + time_second < time_second) { 48653541Sshin return EINVAL; 48753541Sshin } 488126552Sume if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME && 489126552Sume lt->ia6t_pltime + time_second < time_second) { 49053541Sshin return EINVAL; 49153541Sshin } 49253541Sshin break; 49353541Sshin } 49453541Sshin } 49553541Sshin 49653541Sshin switch (cmd) { 49753541Sshin 49853541Sshin case SIOCGIFADDR_IN6: 49953541Sshin ifr->ifr_addr = ia->ia_addr; 500148385Sume if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0) 501148385Sume return (error); 50253541Sshin break; 50353541Sshin 50453541Sshin case SIOCGIFDSTADDR_IN6: 50553541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 506120856Sume return (EINVAL); 50762587Sitojun /* 50862587Sitojun * XXX: should we check if ifa_dstaddr is NULL and return 50962587Sitojun * an error? 51062587Sitojun */ 51153541Sshin ifr->ifr_dstaddr = ia->ia_dstaddr; 512148385Sume if ((error = sa6_recoverscope(&ifr->ifr_dstaddr)) != 0) 513148385Sume return (error); 51453541Sshin break; 51553541Sshin 51653541Sshin case SIOCGIFNETMASK_IN6: 51753541Sshin ifr->ifr_addr = ia->ia_prefixmask; 51853541Sshin break; 51953541Sshin 52053541Sshin case SIOCGIFAFLAG_IN6: 52153541Sshin ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags; 52253541Sshin break; 52353541Sshin 52453541Sshin case SIOCGIFSTAT_IN6: 525121167Sume if (ifp == NULL) 526121167Sume return EINVAL; 527121161Sume bzero(&ifr->ifr_ifru.ifru_stat, 528121161Sume sizeof(ifr->ifr_ifru.ifru_stat)); 529121161Sume ifr->ifr_ifru.ifru_stat = 530121161Sume *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat; 53153541Sshin break; 53253541Sshin 53353541Sshin case SIOCGIFSTAT_ICMP6: 53453541Sshin if (ifp == NULL) 53553541Sshin return EINVAL; 536121161Sume bzero(&ifr->ifr_ifru.ifru_stat, 537121161Sume sizeof(ifr->ifr_ifru.ifru_icmp6stat)); 538121161Sume ifr->ifr_ifru.ifru_icmp6stat = 539121161Sume *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat; 54053541Sshin break; 54153541Sshin 54253541Sshin case SIOCGIFALIFETIME_IN6: 54353541Sshin ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime; 54453541Sshin break; 54553541Sshin 54653541Sshin case SIOCSIFALIFETIME_IN6: 54753541Sshin ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime; 54853541Sshin /* for sanity */ 54953541Sshin if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 55053541Sshin ia->ia6_lifetime.ia6t_expire = 55153541Sshin time_second + ia->ia6_lifetime.ia6t_vltime; 55253541Sshin } else 55353541Sshin ia->ia6_lifetime.ia6t_expire = 0; 55453541Sshin if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 55553541Sshin ia->ia6_lifetime.ia6t_preferred = 55653541Sshin time_second + ia->ia6_lifetime.ia6t_pltime; 55753541Sshin } else 55853541Sshin ia->ia6_lifetime.ia6t_preferred = 0; 55953541Sshin break; 56053541Sshin 56178064Sume case SIOCAIFADDR_IN6: 56278064Sume { 56378064Sume int i, error = 0; 56478064Sume struct nd_prefix pr0, *pr; 56578064Sume 56662587Sitojun /* 56778064Sume * first, make or update the interface address structure, 56878064Sume * and link it to the list. 56962587Sitojun */ 57078064Sume if ((error = in6_update_ifa(ifp, ifra, ia)) != 0) 571120856Sume return (error); 57253541Sshin 57378064Sume /* 57478064Sume * then, make the prefix on-link on the interface. 57578064Sume * XXX: we'd rather create the prefix before the address, but 57678064Sume * we need at least one address to install the corresponding 57778064Sume * interface route, so we configure the address first. 57878064Sume */ 57978064Sume 58078064Sume /* 58178064Sume * convert mask to prefix length (prefixmask has already 58278064Sume * been validated in in6_update_ifa(). 58378064Sume */ 58478064Sume bzero(&pr0, sizeof(pr0)); 58578064Sume pr0.ndpr_ifp = ifp; 58678064Sume pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 587120891Sume NULL); 588120891Sume if (pr0.ndpr_plen == 128) { 58978064Sume break; /* we don't need to install a host route. */ 590120891Sume } 59178064Sume pr0.ndpr_prefix = ifra->ifra_addr; 59278064Sume pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr; 59378064Sume /* apply the mask for safety. */ 59478064Sume for (i = 0; i < 4; i++) { 59578064Sume pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 596120891Sume ifra->ifra_prefixmask.sin6_addr.s6_addr32[i]; 59778064Sume } 59878064Sume /* 59995023Ssuz * XXX: since we don't have an API to set prefix (not address) 60095023Ssuz * lifetimes, we just use the same lifetimes as addresses. 60195023Ssuz * The (temporarily) installed lifetimes can be overridden by 60295023Ssuz * later advertised RAs (when accept_rtadv is non 0), which is 60395023Ssuz * an intended behavior. 60478064Sume */ 60578064Sume pr0.ndpr_raf_onlink = 1; /* should be configurable? */ 60678064Sume pr0.ndpr_raf_auto = 607120891Sume ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0); 60878064Sume pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime; 60978064Sume pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime; 61078064Sume 611120891Sume /* add the prefix if not yet. */ 61278064Sume if ((pr = nd6_prefix_lookup(&pr0)) == NULL) { 61378064Sume /* 61478064Sume * nd6_prelist_add will install the corresponding 61578064Sume * interface route. 61678064Sume */ 61778064Sume if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) 618120856Sume return (error); 61978064Sume if (pr == NULL) { 620120891Sume log(LOG_ERR, "nd6_prelist_add succeeded but " 62178064Sume "no prefix\n"); 622120856Sume return (EINVAL); /* XXX panic here? */ 62378064Sume } 62478064Sume } 62578064Sume if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr)) 62678064Sume == NULL) { 62778064Sume /* XXX: this should not happen! */ 62878064Sume log(LOG_ERR, "in6_control: addition succeeded, but" 62978064Sume " no ifaddr\n"); 63078064Sume } else { 63178064Sume if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && 63278064Sume ia->ia6_ndpr == NULL) { /* new autoconfed addr */ 63378064Sume ia->ia6_ndpr = pr; 63478064Sume pr->ndpr_refcnt++; 63578064Sume 63678064Sume /* 63778064Sume * If this is the first autoconf address from 63878064Sume * the prefix, create a temporary address 63978064Sume * as well (when specified). 64078064Sume */ 64178064Sume if (ip6_use_tempaddr && 64278064Sume pr->ndpr_refcnt == 1) { 64378064Sume int e; 64478064Sume if ((e = in6_tmpifadd(ia, 1)) != 0) { 64578064Sume log(LOG_NOTICE, "in6_control: " 64678064Sume "failed to create a " 64778064Sume "temporary address, " 648122059Sume "errno=%d\n", e); 64978064Sume } 65062587Sitojun } 65162587Sitojun } 65278064Sume 65378064Sume /* 65478064Sume * this might affect the status of autoconfigured 65578064Sume * addresses, that is, this address might make 65678064Sume * other addresses detached. 65778064Sume */ 65878064Sume pfxlist_onlink_check(); 65962587Sitojun } 660126264Smlaier if (error == 0 && ia) 661126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 66278064Sume break; 66378064Sume } 66462587Sitojun 66578064Sume case SIOCDIFADDR_IN6: 66678064Sume { 66778064Sume int i = 0; 66878064Sume struct nd_prefix pr0, *pr; 66978064Sume 67078064Sume /* 67178064Sume * If the address being deleted is the only one that owns 67278064Sume * the corresponding prefix, expire the prefix as well. 673120891Sume * XXX: theoretically, we don't have to worry about such 67478064Sume * relationship, since we separate the address management 67578064Sume * and the prefix management. We do this, however, to provide 67678064Sume * as much backward compatibility as possible in terms of 67778064Sume * the ioctl operation. 67878064Sume */ 67978064Sume bzero(&pr0, sizeof(pr0)); 68078064Sume pr0.ndpr_ifp = ifp; 68178064Sume pr0.ndpr_plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, 68278064Sume NULL); 68378064Sume if (pr0.ndpr_plen == 128) 68478064Sume goto purgeaddr; 68578064Sume pr0.ndpr_prefix = ia->ia_addr; 68678064Sume pr0.ndpr_mask = ia->ia_prefixmask.sin6_addr; 68778064Sume for (i = 0; i < 4; i++) { 68878064Sume pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 68978064Sume ia->ia_prefixmask.sin6_addr.s6_addr32[i]; 69078064Sume } 69178064Sume /* 69278064Sume * The logic of the following condition is a bit complicated. 69378064Sume * We expire the prefix when 69478064Sume * 1. the address obeys autoconfiguration and it is the 69578064Sume * only owner of the associated prefix, or 69678064Sume * 2. the address does not obey autoconf and there is no 69778064Sume * other owner of the prefix. 69878064Sume */ 69978064Sume if ((pr = nd6_prefix_lookup(&pr0)) != NULL && 70078064Sume (((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && 70178064Sume pr->ndpr_refcnt == 1) || 70278064Sume ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0 && 70378064Sume pr->ndpr_refcnt == 0))) { 70478064Sume pr->ndpr_expire = 1; /* XXX: just for expiration */ 70578064Sume } 70678064Sume 70778064Sume purgeaddr: 70878064Sume in6_purgeaddr(&ia->ia_ifa); 709126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 71053541Sshin break; 71178064Sume } 71253541Sshin 71378064Sume default: 71478064Sume if (ifp == NULL || ifp->if_ioctl == 0) 715120856Sume return (EOPNOTSUPP); 716120856Sume return ((*ifp->if_ioctl)(ifp, cmd, data)); 71778064Sume } 71853541Sshin 719120856Sume return (0); 72078064Sume} 72153541Sshin 72278064Sume/* 72378064Sume * Update parameters of an IPv6 interface address. 72478064Sume * If necessary, a new entry is created and linked into address chains. 72578064Sume * This function is separated from in6_control(). 72678064Sume * XXX: should this be performed under splnet()? 72778064Sume */ 72878064Sumeint 72978064Sumein6_update_ifa(ifp, ifra, ia) 73078064Sume struct ifnet *ifp; 73178064Sume struct in6_aliasreq *ifra; 73278064Sume struct in6_ifaddr *ia; 73378064Sume{ 73478064Sume int error = 0, hostIsNew = 0, plen = -1; 73578064Sume struct in6_ifaddr *oia; 73678064Sume struct sockaddr_in6 dst6; 73778064Sume struct in6_addrlifetime *lt; 738148385Sume struct rtentry *rt; 73978064Sume 74078064Sume /* Validate parameters */ 74178064Sume if (ifp == NULL || ifra == NULL) /* this maybe redundant */ 742120856Sume return (EINVAL); 74378064Sume 74478064Sume /* 74578064Sume * The destination address for a p2p link must have a family 74678064Sume * of AF_UNSPEC or AF_INET6. 74778064Sume */ 74878064Sume if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && 74978064Sume ifra->ifra_dstaddr.sin6_family != AF_INET6 && 75078064Sume ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) 751120856Sume return (EAFNOSUPPORT); 75278064Sume /* 75378064Sume * validate ifra_prefixmask. don't check sin6_family, netmask 75478064Sume * does not carry fields other than sin6_len. 75578064Sume */ 75678064Sume if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6)) 757120856Sume return (EINVAL); 75878064Sume /* 75978064Sume * Because the IPv6 address architecture is classless, we require 76078064Sume * users to specify a (non 0) prefix length (mask) for a new address. 76178064Sume * We also require the prefix (when specified) mask is valid, and thus 76278064Sume * reject a non-consecutive mask. 76378064Sume */ 76478064Sume if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0) 765120856Sume return (EINVAL); 76678064Sume if (ifra->ifra_prefixmask.sin6_len != 0) { 76778064Sume plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 768120891Sume (u_char *)&ifra->ifra_prefixmask + 769120891Sume ifra->ifra_prefixmask.sin6_len); 77078064Sume if (plen <= 0) 771120856Sume return (EINVAL); 772120891Sume } else { 77362587Sitojun /* 77495023Ssuz * In this case, ia must not be NULL. We just use its prefix 77578064Sume * length. 77662587Sitojun */ 77778064Sume plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 77878064Sume } 77978064Sume /* 78078064Sume * If the destination address on a p2p interface is specified, 78178064Sume * and the address is a scoped one, validate/set the scope 78278064Sume * zone identifier. 78378064Sume */ 78478064Sume dst6 = ifra->ifra_dstaddr; 785120891Sume if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 && 78678064Sume (dst6.sin6_family == AF_INET6)) { 787148385Sume struct in6_addr in6_tmp; 788126552Sume u_int32_t zoneid; 78978064Sume 790148385Sume in6_tmp = dst6.sin6_addr; 791148385Sume if (in6_setscope(&in6_tmp, ifp, &zoneid)) 792148385Sume return (EINVAL); /* XXX: should be impossible */ 793148385Sume 794148385Sume if (dst6.sin6_scope_id != 0) { 795148385Sume if (dst6.sin6_scope_id != zoneid) 796148385Sume return (EINVAL); 797148385Sume } else /* user omit to specify the ID. */ 798126552Sume dst6.sin6_scope_id = zoneid; 799148385Sume 800148385Sume /* convert into the internal form */ 801148385Sume if (sa6_embedscope(&dst6, 0)) 802148385Sume return (EINVAL); /* XXX: should be impossible */ 80378064Sume } 80478064Sume /* 80578064Sume * The destination address can be specified only for a p2p or a 80678064Sume * loopback interface. If specified, the corresponding prefix length 80778064Sume * must be 128. 80878064Sume */ 80978064Sume if (ifra->ifra_dstaddr.sin6_family == AF_INET6) { 81078064Sume if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) { 811126552Sume /* XXX: noisy message */ 812122059Sume nd6log((LOG_INFO, "in6_update_ifa: a destination can " 813122059Sume "be specified for a p2p or a loopback IF only\n")); 814120856Sume return (EINVAL); 81578064Sume } 81678064Sume if (plen != 128) { 817122059Sume nd6log((LOG_INFO, "in6_update_ifa: prefixlen should " 818122059Sume "be 128 when dstaddr is specified\n")); 819120856Sume return (EINVAL); 82078064Sume } 82178064Sume } 82278064Sume /* lifetime consistency check */ 82378064Sume lt = &ifra->ifra_lifetime; 82478064Sume if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME 82578064Sume && lt->ia6t_vltime + time_second < time_second) { 82678064Sume return EINVAL; 82778064Sume } 82878064Sume if (lt->ia6t_vltime == 0) { 82962587Sitojun /* 83078064Sume * the following log might be noisy, but this is a typical 83178064Sume * configuration mistake or a tool's bug. 83262587Sitojun */ 833122059Sume nd6log((LOG_INFO, 83478064Sume "in6_update_ifa: valid lifetime is 0 for %s\n", 835122059Sume ip6_sprintf(&ifra->ifra_addr.sin6_addr))); 83678064Sume } 83778064Sume if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME 83878064Sume && lt->ia6t_pltime + time_second < time_second) { 83978064Sume return EINVAL; 84078064Sume } 84162587Sitojun 84278064Sume /* 84378064Sume * If this is a new address, allocate a new ifaddr and link it 84478064Sume * into chains. 84578064Sume */ 84678064Sume if (ia == NULL) { 84778064Sume hostIsNew = 1; 84879763Sume /* 84979763Sume * When in6_update_ifa() is called in a process of a received 850120891Sume * RA, it is called under an interrupt context. So, we should 851120891Sume * call malloc with M_NOWAIT. 85279763Sume */ 853120891Sume ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR, 854120891Sume M_NOWAIT); 85578064Sume if (ia == NULL) 85678064Sume return (ENOBUFS); 85778064Sume bzero((caddr_t)ia, sizeof(*ia)); 85878064Sume /* Initialize the address and masks */ 859108033Shsu IFA_LOCK_INIT(&ia->ia_ifa); 86078064Sume ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 86178064Sume ia->ia_addr.sin6_family = AF_INET6; 86278064Sume ia->ia_addr.sin6_len = sizeof(ia->ia_addr); 86378064Sume if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { 86478064Sume /* 86578064Sume * XXX: some functions expect that ifa_dstaddr is not 86678064Sume * NULL for p2p interfaces. 86778064Sume */ 868120891Sume ia->ia_ifa.ifa_dstaddr = 869120891Sume (struct sockaddr *)&ia->ia_dstaddr; 87078064Sume } else { 87178064Sume ia->ia_ifa.ifa_dstaddr = NULL; 87253541Sshin } 873108033Shsu ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; 87478064Sume 87578064Sume ia->ia_ifp = ifp; 87678064Sume if ((oia = in6_ifaddr) != NULL) { 87778064Sume for ( ; oia->ia_next; oia = oia->ia_next) 87878064Sume continue; 87978064Sume oia->ia_next = ia; 88078064Sume } else 88178064Sume in6_ifaddr = ia; 88278064Sume 883108033Shsu ia->ia_ifa.ifa_refcnt = 1; 884108033Shsu TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); 88578064Sume } 88678064Sume 88778064Sume /* set prefix mask */ 88878064Sume if (ifra->ifra_prefixmask.sin6_len) { 88978064Sume /* 89078064Sume * We prohibit changing the prefix length of an existing 89178064Sume * address, because 89278064Sume * + such an operation should be rare in IPv6, and 89378064Sume * + the operation would confuse prefix management. 89478064Sume */ 89578064Sume if (ia->ia_prefixmask.sin6_len && 89678064Sume in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) { 897122059Sume nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an" 89878064Sume " existing (%s) address should not be changed\n", 899122059Sume ip6_sprintf(&ia->ia_addr.sin6_addr))); 90078064Sume error = EINVAL; 90178064Sume goto unlink; 90253541Sshin } 90378064Sume ia->ia_prefixmask = ifra->ifra_prefixmask; 90478064Sume } 90578064Sume 90678064Sume /* 90778064Sume * If a new destination address is specified, scrub the old one and 90878064Sume * install the new destination. Note that the interface must be 909120891Sume * p2p or loopback (see the check above.) 91078064Sume */ 91178064Sume if (dst6.sin6_family == AF_INET6 && 912120891Sume !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) { 91378064Sume int e; 91478064Sume 91578064Sume if ((ia->ia_flags & IFA_ROUTE) != 0 && 916120891Sume (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) { 917122059Sume nd6log((LOG_ERR, "in6_update_ifa: failed to remove " 91878064Sume "a route to the old destination: %s\n", 919122059Sume ip6_sprintf(&ia->ia_addr.sin6_addr))); 92078064Sume /* proceed anyway... */ 921120891Sume } else 92278064Sume ia->ia_flags &= ~IFA_ROUTE; 92378064Sume ia->ia_dstaddr = dst6; 92478064Sume } 92553541Sshin 926148385Sume /* 927148385Sume * Set lifetimes. We do not refer to ia6t_expire and ia6t_preferred 928148385Sume * to see if the address is deprecated or invalidated, but initialize 929148385Sume * these members for applications. 930148385Sume */ 931148385Sume ia->ia6_lifetime = ifra->ifra_lifetime; 932148385Sume if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 933148385Sume ia->ia6_lifetime.ia6t_expire = 934148385Sume time_second + ia->ia6_lifetime.ia6t_vltime; 935148385Sume } else 936148385Sume ia->ia6_lifetime.ia6t_expire = 0; 937148385Sume if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 938148385Sume ia->ia6_lifetime.ia6t_preferred = 939148385Sume time_second + ia->ia6_lifetime.ia6t_pltime; 940148385Sume } else 941148385Sume ia->ia6_lifetime.ia6t_preferred = 0; 942148385Sume 94378064Sume /* reset the interface and routing table appropriately. */ 94478064Sume if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) 94578064Sume goto unlink; 94678064Sume 94778064Sume /* 948148385Sume * configure address flags. 949148385Sume */ 950148385Sume ia->ia6_flags = ifra->ifra_flags; 951148385Sume ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /* safety */ 952148385Sume ia->ia6_flags &= ~IN6_IFF_NODAD; /* Mobile IPv6 */ 953148385Sume /* 954148385Sume * backward compatibility - if IN6_IFF_DEPRECATED is set from the 955148385Sume * userland, make it deprecated. 956148385Sume */ 957148385Sume if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) { 958148385Sume ia->ia6_lifetime.ia6t_pltime = 0; 959148385Sume ia->ia6_lifetime.ia6t_preferred = time_second; 960148385Sume } 961148385Sume 962148385Sume /* 963148385Sume * Perform DAD, if needed. 964148385Sume * XXX It may be of use, if we can administratively 965148385Sume * disable DAD. 966148385Sume */ 967148385Sume if (in6if_do_dad(ifp) && hostIsNew && 968148385Sume (ifra->ifra_flags & IN6_IFF_NODAD) == 0) { 969148385Sume ia->ia6_flags |= IN6_IFF_TENTATIVE; 970148385Sume nd6_dad_start((struct ifaddr *)ia, NULL); 971148385Sume } 972148385Sume 973148385Sume /* 974148385Sume * We are done if we have simply modified an existing address. 975148385Sume */ 976148385Sume if (!hostIsNew) 977148385Sume return (error); 978148385Sume 979148385Sume /* 98078064Sume * Beyond this point, we should call in6_purgeaddr upon an error, 981120891Sume * not just go to unlink. 98278064Sume */ 98378064Sume 98478064Sume if ((ifp->if_flags & IFF_MULTICAST) != 0) { 98578064Sume struct sockaddr_in6 mltaddr, mltmask; 98678064Sume struct in6_multi *in6m; 987148385Sume struct in6_addr llsol; 98878064Sume 989148385Sume /* join solicited multicast addr for new host id */ 990148385Sume bzero(&llsol, sizeof(struct in6_addr)); 991148385Sume llsol.s6_addr16[0] = htons(0xff02); 992148385Sume llsol.s6_addr32[1] = 0; 993148385Sume llsol.s6_addr32[2] = htonl(1); 994148385Sume llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3]; 995148385Sume llsol.s6_addr8[12] = 0xff; 996148385Sume if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) { 997148385Sume /* XXX: should not happen */ 998148385Sume log(LOG_ERR, "in6_update_ifa: " 999148385Sume "in6_setscope failed\n"); 1000148385Sume goto cleanup; 100153541Sshin } 1002148385Sume (void)in6_addmulti(&llsol, ifp, &error); 1003148385Sume if (error != 0) { 1004148385Sume nd6log((LOG_WARNING, 1005148385Sume "in6_update_ifa: addmulti failed for " 1006148385Sume "%s on %s (errno=%d)\n", 1007148385Sume ip6_sprintf(&llsol), if_name(ifp), 1008148385Sume error)); 1009148385Sume goto cleanup; 1010148385Sume } 101153541Sshin 101278064Sume bzero(&mltmask, sizeof(mltmask)); 101378064Sume mltmask.sin6_len = sizeof(struct sockaddr_in6); 101478064Sume mltmask.sin6_family = AF_INET6; 101578064Sume mltmask.sin6_addr = in6mask32; 101653541Sshin 101753541Sshin /* 101878064Sume * join link-local all-nodes address 101971207Sitojun */ 102078064Sume bzero(&mltaddr, sizeof(mltaddr)); 102178064Sume mltaddr.sin6_len = sizeof(struct sockaddr_in6); 102278064Sume mltaddr.sin6_family = AF_INET6; 102378064Sume mltaddr.sin6_addr = in6addr_linklocal_allnodes; 1024148385Sume if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 1025148385Sume 0) 1026148385Sume goto cleanup; /* XXX: should not fail */ 102771207Sitojun 1028148385Sume /* 1029148385Sume * XXX: do we really need this automatic routes? 1030148385Sume * We should probably reconsider this stuff. Most applications 1031148385Sume * actually do not need the routes, since they usually specify 1032148385Sume * the outgoing interface. 1033148385Sume */ 1034148385Sume rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL); 1035148385Sume if (rt) { 1036148385Sume /* 1037148385Sume * 32bit came from "mltmask" 1038148385Sume */ 1039148385Sume if (memcmp(&mltaddr.sin6_addr, 1040148385Sume &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, 1041148385Sume 32 / 8)) { 1042148385Sume RTFREE_LOCKED(rt); 1043148385Sume rt = NULL; 1044148385Sume } 1045148385Sume } 1046148385Sume if (!rt) { 1047148385Sume /* XXX: we need RTF_CLONING to fake nd6_rtrequest */ 1048148385Sume error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, 1049148385Sume (struct sockaddr *)&ia->ia_addr, 1050148385Sume (struct sockaddr *)&mltmask, RTF_UP | RTF_CLONING, 1051148385Sume (struct rtentry **)0); 1052148385Sume if (error) 1053148385Sume goto cleanup; 1054148385Sume } else 1055148385Sume RTFREE_LOCKED(rt); 1056148385Sume 105778064Sume IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 105878064Sume if (in6m == NULL) { 105978064Sume (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); 106078064Sume if (error != 0) { 1061122059Sume nd6log((LOG_WARNING, 106278064Sume "in6_update_ifa: addmulti failed for " 106378064Sume "%s on %s (errno=%d)\n", 1064122059Sume ip6_sprintf(&mltaddr.sin6_addr), 1065122059Sume if_name(ifp), error)); 1066148385Sume goto cleanup; 106778064Sume } 106878064Sume } 106978064Sume 107071207Sitojun /* 107178064Sume * join node information group address 107253541Sshin */ 107378064Sume#define hostnamelen strlen(hostname) 107478064Sume if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr) 107578064Sume == 0) { 107678064Sume IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 1077148385Sume if (in6m == NULL) { 107878064Sume (void)in6_addmulti(&mltaddr.sin6_addr, 107978064Sume ifp, &error); 108078064Sume if (error != 0) { 1081122059Sume nd6log((LOG_WARNING, "in6_update_ifa: " 108278064Sume "addmulti failed for " 108378064Sume "%s on %s (errno=%d)\n", 1084122059Sume ip6_sprintf(&mltaddr.sin6_addr), 1085122059Sume if_name(ifp), error)); 1086148385Sume goto cleanup; 108778064Sume } 108862587Sitojun } 108953541Sshin } 109078064Sume#undef hostnamelen 109153541Sshin 109278064Sume /* 1093148385Sume * join interface-local all-nodes address. 1094148385Sume * (ff01::1%ifN, and ff01::%ifN/32) 109578064Sume */ 1096148385Sume mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 1097148385Sume if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) 1098148385Sume != 0) 1099148385Sume goto cleanup; /* XXX: should not fail */ 1100148385Sume /* XXX: again, do we really need the route? */ 1101148385Sume rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL); 1102148385Sume if (rt) { 1103148385Sume /* 32bit came from "mltmask" */ 1104148385Sume if (memcmp(&mltaddr.sin6_addr, 1105148385Sume &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, 1106148385Sume 32 / 8)) { 1107148385Sume RTFREE_LOCKED(rt); 1108148385Sume rt = NULL; 1109148385Sume } 1110148385Sume } 1111148385Sume if (!rt) { 1112148385Sume error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, 1113148385Sume (struct sockaddr *)&ia->ia_addr, 1114148385Sume (struct sockaddr *)&mltmask, RTF_UP | RTF_CLONING, 1115148385Sume (struct rtentry **)0); 1116148385Sume if (error) 1117148385Sume goto cleanup; 1118148385Sume } else 1119148385Sume RTFREE_LOCKED(rt); 112081115Sume 1121148385Sume IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 1122148385Sume if (in6m == NULL) { 1123148385Sume (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); 1124148385Sume if (error != 0) { 1125148385Sume nd6log((LOG_WARNING, "in6_update_ifa: " 1126148385Sume "addmulti failed for %s on %s " 1127148385Sume "(errno=%d)\n", 1128148385Sume ip6_sprintf(&mltaddr.sin6_addr), 1129148385Sume if_name(ifp), error)); 1130148385Sume goto cleanup; 113178064Sume } 113253541Sshin } 113378064Sume } 113453541Sshin 1135120856Sume return (error); 113678064Sume 113778064Sume unlink: 113878064Sume /* 113978064Sume * XXX: if a change of an existing address failed, keep the entry 114078064Sume * anyway. 114178064Sume */ 114278064Sume if (hostIsNew) 114378064Sume in6_unlink_ifa(ia, ifp); 1144120856Sume return (error); 1145148385Sume 1146148385Sume cleanup: 1147148385Sume in6_purgeaddr(&ia->ia_ifa); 1148148385Sume return error; 114953541Sshin} 115053541Sshin 115162587Sitojunvoid 115278064Sumein6_purgeaddr(ifa) 115362587Sitojun struct ifaddr *ifa; 115462587Sitojun{ 115578064Sume struct ifnet *ifp = ifa->ifa_ifp; 115678064Sume struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; 115762587Sitojun 115878064Sume /* stop DAD processing */ 115978064Sume nd6_dad_stop(ifa); 116062587Sitojun 116178064Sume /* 116278064Sume * delete route to the destination of the address being purged. 116378064Sume * The interface must be p2p or loopback in this case. 116478064Sume */ 116578064Sume if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) { 116678064Sume int e; 116778064Sume 116878064Sume if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) 116978064Sume != 0) { 117078064Sume log(LOG_ERR, "in6_purgeaddr: failed to remove " 117178064Sume "a route to the p2p destination: %s on %s, " 117278064Sume "errno=%d\n", 117378064Sume ip6_sprintf(&ia->ia_addr.sin6_addr), if_name(ifp), 117478064Sume e); 117578064Sume /* proceed anyway... */ 1176120891Sume } else 117778064Sume ia->ia_flags &= ~IFA_ROUTE; 117878064Sume } 117978064Sume 118078064Sume /* Remove ownaddr's loopback rtentry, if it exists. */ 118178064Sume in6_ifremloop(&(ia->ia_ifa)); 118278064Sume 118362587Sitojun if (ifp->if_flags & IFF_MULTICAST) { 118462587Sitojun /* 118562587Sitojun * delete solicited multicast addr for deleting host id 118662587Sitojun */ 118762587Sitojun struct in6_multi *in6m; 118862587Sitojun struct in6_addr llsol; 118962587Sitojun bzero(&llsol, sizeof(struct in6_addr)); 119062587Sitojun llsol.s6_addr16[0] = htons(0xff02); 119162587Sitojun llsol.s6_addr32[1] = 0; 119262587Sitojun llsol.s6_addr32[2] = htonl(1); 119362587Sitojun llsol.s6_addr32[3] = 119462587Sitojun ia->ia_addr.sin6_addr.s6_addr32[3]; 119562587Sitojun llsol.s6_addr8[12] = 0xff; 1196148385Sume (void)in6_setscope(&llsol, ifp, NULL); /* XXX proceed anyway */ 119762587Sitojun 119862587Sitojun IN6_LOOKUP_MULTI(llsol, ifp, in6m); 119962587Sitojun if (in6m) 120062587Sitojun in6_delmulti(in6m); 120162587Sitojun } 120262587Sitojun 120378064Sume in6_unlink_ifa(ia, ifp); 120478064Sume} 120578064Sume 120678064Sumestatic void 120778064Sumein6_unlink_ifa(ia, ifp) 120878064Sume struct in6_ifaddr *ia; 120978064Sume struct ifnet *ifp; 121078064Sume{ 121178064Sume struct in6_ifaddr *oia; 121278064Sume int s = splnet(); 121378064Sume 121462587Sitojun TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); 121562587Sitojun 121662587Sitojun oia = ia; 121762587Sitojun if (oia == (ia = in6_ifaddr)) 121862587Sitojun in6_ifaddr = ia->ia_next; 121962587Sitojun else { 122062587Sitojun while (ia->ia_next && (ia->ia_next != oia)) 122162587Sitojun ia = ia->ia_next; 122262587Sitojun if (ia->ia_next) 122362587Sitojun ia->ia_next = oia->ia_next; 122478064Sume else { 122578064Sume /* search failed */ 122678064Sume printf("Couldn't unlink in6_ifaddr from in6_ifaddr\n"); 122778064Sume } 122862587Sitojun } 122962587Sitojun 123062587Sitojun /* 123178064Sume * When an autoconfigured address is being removed, release the 123278064Sume * reference to the base prefix. Also, since the release might 123378064Sume * affect the status of other (detached) addresses, call 123478064Sume * pfxlist_onlink_check(). 123562587Sitojun */ 123678064Sume if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) { 123778064Sume if (oia->ia6_ndpr == NULL) { 1238122059Sume nd6log((LOG_NOTICE, "in6_unlink_ifa: autoconf'ed address " 1239122059Sume "%p has no prefix\n", oia)); 124078064Sume } else { 124178064Sume oia->ia6_ndpr->ndpr_refcnt--; 124278064Sume oia->ia6_flags &= ~IN6_IFF_AUTOCONF; 124378064Sume oia->ia6_ndpr = NULL; 124478064Sume } 124562587Sitojun 124678064Sume pfxlist_onlink_check(); 124762587Sitojun } 124878064Sume 124978064Sume /* 125078064Sume * release another refcnt for the link from in6_ifaddr. 125178064Sume * Note that we should decrement the refcnt at least once for all *BSD. 125278064Sume */ 125362587Sitojun IFAFREE(&oia->ia_ifa); 125478064Sume 125578064Sume splx(s); 125662587Sitojun} 125762587Sitojun 125878064Sumevoid 125978064Sumein6_purgeif(ifp) 126078064Sume struct ifnet *ifp; 126178064Sume{ 126278064Sume struct ifaddr *ifa, *nifa; 126378064Sume 1264120891Sume for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa) { 126578064Sume nifa = TAILQ_NEXT(ifa, ifa_list); 126678064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 126778064Sume continue; 126878064Sume in6_purgeaddr(ifa); 126978064Sume } 127078064Sume 127178064Sume in6_ifdetach(ifp); 127278064Sume} 127378064Sume 127453541Sshin/* 127553541Sshin * SIOC[GAD]LIFADDR. 127662744Sgrog * SIOCGLIFADDR: get first address. (?) 127753541Sshin * SIOCGLIFADDR with IFLR_PREFIX: 127853541Sshin * get first address that matches the specified prefix. 127953541Sshin * SIOCALIFADDR: add the specified address. 128053541Sshin * SIOCALIFADDR with IFLR_PREFIX: 128153541Sshin * add the specified prefix, filling hostid part from 128253541Sshin * the first link-local address. prefixlen must be <= 64. 128353541Sshin * SIOCDLIFADDR: delete the specified address. 128453541Sshin * SIOCDLIFADDR with IFLR_PREFIX: 128553541Sshin * delete the first address that matches the specified prefix. 128653541Sshin * return values: 128753541Sshin * EINVAL on invalid parameters 128853541Sshin * EADDRNOTAVAIL on prefix match failed/specified address not found 128953541Sshin * other values may be returned from in6_ioctl() 129053541Sshin * 129153541Sshin * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64. 129253541Sshin * this is to accomodate address naming scheme other than RFC2374, 129353541Sshin * in the future. 129453541Sshin * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374 129553541Sshin * address encoding scheme. (see figure on page 8) 129653541Sshin */ 129753541Sshinstatic int 129883366Sjulianin6_lifaddr_ioctl(so, cmd, data, ifp, td) 129953541Sshin struct socket *so; 130053541Sshin u_long cmd; 130153541Sshin caddr_t data; 130253541Sshin struct ifnet *ifp; 130383366Sjulian struct thread *td; 130453541Sshin{ 130553541Sshin struct if_laddrreq *iflr = (struct if_laddrreq *)data; 130653541Sshin struct ifaddr *ifa; 130762587Sitojun struct sockaddr *sa; 130853541Sshin 130953541Sshin /* sanity checks */ 131053541Sshin if (!data || !ifp) { 131153541Sshin panic("invalid argument to in6_lifaddr_ioctl"); 1312120891Sume /* NOTREACHED */ 131353541Sshin } 131453541Sshin 131553541Sshin switch (cmd) { 131653541Sshin case SIOCGLIFADDR: 131753541Sshin /* address must be specified on GET with IFLR_PREFIX */ 131853541Sshin if ((iflr->flags & IFLR_PREFIX) == 0) 131953541Sshin break; 132095023Ssuz /* FALLTHROUGH */ 132153541Sshin case SIOCALIFADDR: 132253541Sshin case SIOCDLIFADDR: 132353541Sshin /* address must be specified on ADD and DELETE */ 132462587Sitojun sa = (struct sockaddr *)&iflr->addr; 132562587Sitojun if (sa->sa_family != AF_INET6) 132653541Sshin return EINVAL; 132762587Sitojun if (sa->sa_len != sizeof(struct sockaddr_in6)) 132853541Sshin return EINVAL; 132953541Sshin /* XXX need improvement */ 133062587Sitojun sa = (struct sockaddr *)&iflr->dstaddr; 133162587Sitojun if (sa->sa_family && sa->sa_family != AF_INET6) 133253541Sshin return EINVAL; 133362587Sitojun if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6)) 133453541Sshin return EINVAL; 133553541Sshin break; 133695023Ssuz default: /* shouldn't happen */ 133762587Sitojun#if 0 133862587Sitojun panic("invalid cmd to in6_lifaddr_ioctl"); 133995023Ssuz /* NOTREACHED */ 134062587Sitojun#else 134153541Sshin return EOPNOTSUPP; 134262587Sitojun#endif 134353541Sshin } 134453541Sshin if (sizeof(struct in6_addr) * 8 < iflr->prefixlen) 134553541Sshin return EINVAL; 134653541Sshin 134753541Sshin switch (cmd) { 134853541Sshin case SIOCALIFADDR: 134953541Sshin { 135053541Sshin struct in6_aliasreq ifra; 135153541Sshin struct in6_addr *hostid = NULL; 135253541Sshin int prefixlen; 135353541Sshin 135453541Sshin if ((iflr->flags & IFLR_PREFIX) != 0) { 135553541Sshin struct sockaddr_in6 *sin6; 135653541Sshin 135753541Sshin /* 135853541Sshin * hostid is to fill in the hostid part of the 135953541Sshin * address. hostid points to the first link-local 136053541Sshin * address attached to the interface. 136153541Sshin */ 136262587Sitojun ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); 136353541Sshin if (!ifa) 136453541Sshin return EADDRNOTAVAIL; 136553541Sshin hostid = IFA_IN6(ifa); 136653541Sshin 136753541Sshin /* prefixlen must be <= 64. */ 136853541Sshin if (64 < iflr->prefixlen) 136953541Sshin return EINVAL; 137053541Sshin prefixlen = iflr->prefixlen; 137153541Sshin 137253541Sshin /* hostid part must be zero. */ 137353541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 1374126552Sume if (sin6->sin6_addr.s6_addr32[2] != 0 || 1375126552Sume sin6->sin6_addr.s6_addr32[3] != 0) { 137653541Sshin return EINVAL; 137753541Sshin } 137853541Sshin } else 137953541Sshin prefixlen = iflr->prefixlen; 138053541Sshin 138153541Sshin /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 138253541Sshin bzero(&ifra, sizeof(ifra)); 1383120891Sume bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name)); 138453541Sshin 138562587Sitojun bcopy(&iflr->addr, &ifra.ifra_addr, 1386120891Sume ((struct sockaddr *)&iflr->addr)->sa_len); 138753541Sshin if (hostid) { 138853541Sshin /* fill in hostid part */ 138953541Sshin ifra.ifra_addr.sin6_addr.s6_addr32[2] = 1390120891Sume hostid->s6_addr32[2]; 139153541Sshin ifra.ifra_addr.sin6_addr.s6_addr32[3] = 1392120891Sume hostid->s6_addr32[3]; 139353541Sshin } 139453541Sshin 1395120891Sume if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */ 139653541Sshin bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 1397120891Sume ((struct sockaddr *)&iflr->dstaddr)->sa_len); 139853541Sshin if (hostid) { 139953541Sshin ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] = 1400120891Sume hostid->s6_addr32[2]; 140153541Sshin ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = 1402120891Sume hostid->s6_addr32[3]; 140353541Sshin } 140453541Sshin } 140553541Sshin 140653541Sshin ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 1407121168Sume in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); 140853541Sshin 140953541Sshin ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; 141083366Sjulian return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, td); 141153541Sshin } 141253541Sshin case SIOCGLIFADDR: 141353541Sshin case SIOCDLIFADDR: 141453541Sshin { 141553541Sshin struct in6_ifaddr *ia; 141653541Sshin struct in6_addr mask, candidate, match; 141753541Sshin struct sockaddr_in6 *sin6; 141853541Sshin int cmp; 141953541Sshin 142053541Sshin bzero(&mask, sizeof(mask)); 142153541Sshin if (iflr->flags & IFLR_PREFIX) { 142253541Sshin /* lookup a prefix rather than address. */ 1423121168Sume in6_prefixlen2mask(&mask, iflr->prefixlen); 142453541Sshin 142553541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 142653541Sshin bcopy(&sin6->sin6_addr, &match, sizeof(match)); 142753541Sshin match.s6_addr32[0] &= mask.s6_addr32[0]; 142853541Sshin match.s6_addr32[1] &= mask.s6_addr32[1]; 142953541Sshin match.s6_addr32[2] &= mask.s6_addr32[2]; 143053541Sshin match.s6_addr32[3] &= mask.s6_addr32[3]; 143153541Sshin 143253541Sshin /* if you set extra bits, that's wrong */ 143353541Sshin if (bcmp(&match, &sin6->sin6_addr, sizeof(match))) 143453541Sshin return EINVAL; 143553541Sshin 143653541Sshin cmp = 1; 143753541Sshin } else { 143853541Sshin if (cmd == SIOCGLIFADDR) { 143953541Sshin /* on getting an address, take the 1st match */ 144095023Ssuz cmp = 0; /* XXX */ 144153541Sshin } else { 144253541Sshin /* on deleting an address, do exact match */ 1443121168Sume in6_prefixlen2mask(&mask, 128); 144453541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 144553541Sshin bcopy(&sin6->sin6_addr, &match, sizeof(match)); 144653541Sshin 144753541Sshin cmp = 1; 144853541Sshin } 144953541Sshin } 145053541Sshin 1451120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 145253541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 145353541Sshin continue; 145453541Sshin if (!cmp) 145553541Sshin break; 145678064Sume 145778064Sume /* 145878064Sume * XXX: this is adhoc, but is necessary to allow 145978064Sume * a user to specify fe80::/64 (not /10) for a 146078064Sume * link-local address. 146178064Sume */ 1462148385Sume bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate)); 1463148385Sume in6_clearscope(&candidate); 146453541Sshin candidate.s6_addr32[0] &= mask.s6_addr32[0]; 146553541Sshin candidate.s6_addr32[1] &= mask.s6_addr32[1]; 146653541Sshin candidate.s6_addr32[2] &= mask.s6_addr32[2]; 146753541Sshin candidate.s6_addr32[3] &= mask.s6_addr32[3]; 146853541Sshin if (IN6_ARE_ADDR_EQUAL(&candidate, &match)) 146953541Sshin break; 147053541Sshin } 147153541Sshin if (!ifa) 147253541Sshin return EADDRNOTAVAIL; 147353541Sshin ia = ifa2ia6(ifa); 147453541Sshin 147553541Sshin if (cmd == SIOCGLIFADDR) { 1476148385Sume int error; 147778064Sume 147853541Sshin /* fill in the if_laddrreq structure */ 147953541Sshin bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len); 1480148385Sume error = sa6_recoverscope( 1481148385Sume (struct sockaddr_in6 *)&iflr->addr); 1482148385Sume if (error != 0) 1483148385Sume return (error); 1484148385Sume 148553541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 148653541Sshin bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 1487120891Sume ia->ia_dstaddr.sin6_len); 1488148385Sume error = sa6_recoverscope( 1489148385Sume (struct sockaddr_in6 *)&iflr->dstaddr); 1490148385Sume if (error != 0) 1491148385Sume return (error); 149253541Sshin } else 149353541Sshin bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 149453541Sshin 149553541Sshin iflr->prefixlen = 1496120891Sume in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 149753541Sshin 149895023Ssuz iflr->flags = ia->ia6_flags; /* XXX */ 149953541Sshin 150053541Sshin return 0; 150153541Sshin } else { 150253541Sshin struct in6_aliasreq ifra; 150353541Sshin 150453541Sshin /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 150553541Sshin bzero(&ifra, sizeof(ifra)); 150653541Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 1507120891Sume sizeof(ifra.ifra_name)); 150853541Sshin 150953541Sshin bcopy(&ia->ia_addr, &ifra.ifra_addr, 1510120891Sume ia->ia_addr.sin6_len); 151153541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 151253541Sshin bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 1513120891Sume ia->ia_dstaddr.sin6_len); 151462587Sitojun } else { 151562587Sitojun bzero(&ifra.ifra_dstaddr, 151662587Sitojun sizeof(ifra.ifra_dstaddr)); 151753541Sshin } 151853541Sshin bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr, 1519120891Sume ia->ia_prefixmask.sin6_len); 152053541Sshin 152153541Sshin ifra.ifra_flags = ia->ia6_flags; 152253541Sshin return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, 1523120891Sume ifp, td); 152453541Sshin } 152553541Sshin } 152653541Sshin } 152753541Sshin 152895023Ssuz return EOPNOTSUPP; /* just for safety */ 152953541Sshin} 153053541Sshin 153153541Sshin/* 153253541Sshin * Initialize an interface's intetnet6 address 153353541Sshin * and routing table entry. 153453541Sshin */ 153578064Sumestatic int 153678064Sumein6_ifinit(ifp, ia, sin6, newhost) 153753541Sshin struct ifnet *ifp; 153853541Sshin struct in6_ifaddr *ia; 153953541Sshin struct sockaddr_in6 *sin6; 154078064Sume int newhost; 154153541Sshin{ 154278064Sume int error = 0, plen, ifacount = 0; 154353541Sshin int s = splimp(); 154478064Sume struct ifaddr *ifa; 154553541Sshin 154653541Sshin /* 154753541Sshin * Give the interface a chance to initialize 154853541Sshin * if this is its first address, 154953541Sshin * and to validate the address if necessary. 155053541Sshin */ 1551120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 155278064Sume if (ifa->ifa_addr == NULL) 155378064Sume continue; /* just for safety */ 155478064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 155578064Sume continue; 155678064Sume ifacount++; 155778064Sume } 155878064Sume 155978064Sume ia->ia_addr = *sin6; 156078064Sume 1561146883Siedowse if (ifacount <= 1 && ifp->if_ioctl) { 1562146883Siedowse IFF_LOCKGIANT(ifp); 1563146883Siedowse error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); 1564146883Siedowse IFF_UNLOCKGIANT(ifp); 1565146883Siedowse if (error) { 1566146883Siedowse splx(s); 1567146883Siedowse return (error); 1568146883Siedowse } 156953541Sshin } 157078064Sume splx(s); 157153541Sshin 157278064Sume ia->ia_ifa.ifa_metric = ifp->if_metric; 157353541Sshin 157478064Sume /* we could do in(6)_socktrim here, but just omit it at this moment. */ 157578064Sume 157653541Sshin /* 157778064Sume * Special case: 1578124337Sume * If a new destination address is specified for a point-to-point 157978064Sume * interface, install a route to the destination as an interface 158078064Sume * direct route. 1581124337Sume * XXX: the logic below rejects assigning multiple addresses on a p2p 1582124337Sume * interface that share a same destination. 158353541Sshin */ 158478064Sume plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ 1585124337Sume if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 && 1586124337Sume ia->ia_dstaddr.sin6_family == AF_INET6) { 158778064Sume if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, 158878064Sume RTF_UP | RTF_HOST)) != 0) 1589120856Sume return (error); 159078064Sume ia->ia_flags |= IFA_ROUTE; 159153541Sshin } 159278064Sume if (plen < 128) { 159378064Sume /* 159478064Sume * The RTF_CLONING flag is necessary for in6_is_ifloop_auto(). 159578064Sume */ 159678064Sume ia->ia_ifa.ifa_flags |= RTF_CLONING; 159778064Sume } 159853541Sshin 159995023Ssuz /* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */ 160078064Sume if (newhost) { 160178064Sume /* set the rtrequest function to create llinfo */ 160278064Sume ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; 160378064Sume in6_ifaddloop(&(ia->ia_ifa)); 160478064Sume } 160553541Sshin 1606120856Sume return (error); 160753541Sshin} 160853541Sshin 1609142215Sglebiusstruct in6_multi_mship * 1610142215Sglebiusin6_joingroup(ifp, addr, errorp) 1611142215Sglebius struct ifnet *ifp; 1612142215Sglebius struct in6_addr *addr; 1613142215Sglebius int *errorp; 1614142215Sglebius{ 1615142215Sglebius struct in6_multi_mship *imm; 1616142215Sglebius 1617142215Sglebius imm = malloc(sizeof(*imm), M_IPMADDR, M_NOWAIT); 1618142215Sglebius if (!imm) { 1619142215Sglebius *errorp = ENOBUFS; 1620142215Sglebius return NULL; 1621142215Sglebius } 1622142215Sglebius imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp); 1623142215Sglebius if (!imm->i6mm_maddr) { 1624142215Sglebius /* *errorp is alrady set */ 1625142215Sglebius free(imm, M_IPMADDR); 1626142215Sglebius return NULL; 1627142215Sglebius } 1628142215Sglebius return imm; 1629142215Sglebius} 1630142215Sglebius 1631142215Sglebiusint 1632142215Sglebiusin6_leavegroup(imm) 1633142215Sglebius struct in6_multi_mship *imm; 1634142215Sglebius{ 1635142215Sglebius 1636142215Sglebius if (imm->i6mm_maddr) 1637142215Sglebius in6_delmulti(imm->i6mm_maddr); 1638142215Sglebius free(imm, M_IPMADDR); 1639142215Sglebius return 0; 1640142215Sglebius} 1641142215Sglebius 164253541Sshin/* 164353541Sshin * Find an IPv6 interface link-local address specific to an interface. 164453541Sshin */ 164553541Sshinstruct in6_ifaddr * 164662587Sitojunin6ifa_ifpforlinklocal(ifp, ignoreflags) 164753541Sshin struct ifnet *ifp; 164862587Sitojun int ignoreflags; 164953541Sshin{ 165078064Sume struct ifaddr *ifa; 165153541Sshin 1652120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 165353541Sshin if (ifa->ifa_addr == NULL) 165453541Sshin continue; /* just for safety */ 165553541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 165653541Sshin continue; 165762587Sitojun if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { 165862587Sitojun if ((((struct in6_ifaddr *)ifa)->ia6_flags & 165962587Sitojun ignoreflags) != 0) 166062587Sitojun continue; 166153541Sshin break; 166262587Sitojun } 166353541Sshin } 166453541Sshin 1665120856Sume return ((struct in6_ifaddr *)ifa); 166653541Sshin} 166753541Sshin 166853541Sshin 166953541Sshin/* 167053541Sshin * find the internet address corresponding to a given interface and address. 167153541Sshin */ 167253541Sshinstruct in6_ifaddr * 167353541Sshinin6ifa_ifpwithaddr(ifp, addr) 167453541Sshin struct ifnet *ifp; 167553541Sshin struct in6_addr *addr; 167653541Sshin{ 167778064Sume struct ifaddr *ifa; 167853541Sshin 1679120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 168053541Sshin if (ifa->ifa_addr == NULL) 168153541Sshin continue; /* just for safety */ 168253541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 168353541Sshin continue; 168453541Sshin if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) 168553541Sshin break; 168653541Sshin } 168753541Sshin 1688120856Sume return ((struct in6_ifaddr *)ifa); 168953541Sshin} 169053541Sshin 169153541Sshin/* 169253541Sshin * Convert IP6 address to printable (loggable) representation. 169353541Sshin */ 169453541Sshinstatic char digits[] = "0123456789abcdef"; 169553541Sshinstatic int ip6round = 0; 169653541Sshinchar * 169753541Sshinip6_sprintf(addr) 169878064Sume const struct in6_addr *addr; 169953541Sshin{ 170053541Sshin static char ip6buf[8][48]; 170178064Sume int i; 170278064Sume char *cp; 1703126552Sume const u_int16_t *a = (const u_int16_t *)addr; 1704126552Sume const u_int8_t *d; 170553541Sshin int dcolon = 0; 170653541Sshin 170753541Sshin ip6round = (ip6round + 1) & 7; 170853541Sshin cp = ip6buf[ip6round]; 170953541Sshin 171053541Sshin for (i = 0; i < 8; i++) { 171153541Sshin if (dcolon == 1) { 171253541Sshin if (*a == 0) { 171353541Sshin if (i == 7) 171453541Sshin *cp++ = ':'; 171553541Sshin a++; 171653541Sshin continue; 171753541Sshin } else 171853541Sshin dcolon = 2; 171953541Sshin } 172053541Sshin if (*a == 0) { 172153541Sshin if (dcolon == 0 && *(a + 1) == 0) { 172253541Sshin if (i == 0) 172353541Sshin *cp++ = ':'; 172453541Sshin *cp++ = ':'; 172553541Sshin dcolon = 1; 172653541Sshin } else { 172753541Sshin *cp++ = '0'; 172853541Sshin *cp++ = ':'; 172953541Sshin } 173053541Sshin a++; 173153541Sshin continue; 173253541Sshin } 173391346Salfred d = (const u_char *)a; 173453541Sshin *cp++ = digits[*d >> 4]; 173553541Sshin *cp++ = digits[*d++ & 0xf]; 173653541Sshin *cp++ = digits[*d >> 4]; 173753541Sshin *cp++ = digits[*d & 0xf]; 173853541Sshin *cp++ = ':'; 173953541Sshin a++; 174053541Sshin } 174153541Sshin *--cp = 0; 1742120856Sume return (ip6buf[ip6round]); 174353541Sshin} 174453541Sshin 174553541Sshinint 174653541Sshinin6_localaddr(in6) 174753541Sshin struct in6_addr *in6; 174853541Sshin{ 174953541Sshin struct in6_ifaddr *ia; 175053541Sshin 175153541Sshin if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6)) 175253541Sshin return 1; 175353541Sshin 1754120891Sume for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 175553541Sshin if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr, 1756120891Sume &ia->ia_prefixmask.sin6_addr)) { 175753541Sshin return 1; 1758120891Sume } 1759120891Sume } 176053541Sshin 176153541Sshin return (0); 176253541Sshin} 176353541Sshin 176478064Sumeint 176578064Sumein6_is_addr_deprecated(sa6) 176678064Sume struct sockaddr_in6 *sa6; 176778064Sume{ 176878064Sume struct in6_ifaddr *ia; 176978064Sume 177078064Sume for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 177178064Sume if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 177278064Sume &sa6->sin6_addr) && 177378064Sume (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) 1774120856Sume return (1); /* true */ 177578064Sume 177678064Sume /* XXX: do we still have to go thru the rest of the list? */ 177778064Sume } 177878064Sume 1779120856Sume return (0); /* false */ 178078064Sume} 178178064Sume 178253541Sshin/* 178353541Sshin * return length of part which dst and src are equal 178453541Sshin * hard coding... 178553541Sshin */ 178653541Sshinint 178753541Sshinin6_matchlen(src, dst) 178853541Sshinstruct in6_addr *src, *dst; 178953541Sshin{ 179053541Sshin int match = 0; 179153541Sshin u_char *s = (u_char *)src, *d = (u_char *)dst; 179253541Sshin u_char *lim = s + 16, r; 179353541Sshin 179453541Sshin while (s < lim) 179553541Sshin if ((r = (*d++ ^ *s++)) != 0) { 179653541Sshin while (r < 128) { 179753541Sshin match++; 179853541Sshin r <<= 1; 179953541Sshin } 180053541Sshin break; 180153541Sshin } else 180253541Sshin match += 8; 180353541Sshin return match; 180453541Sshin} 180553541Sshin 180662587Sitojun/* XXX: to be scope conscious */ 180753541Sshinint 180853541Sshinin6_are_prefix_equal(p1, p2, len) 180953541Sshin struct in6_addr *p1, *p2; 181053541Sshin int len; 181153541Sshin{ 181253541Sshin int bytelen, bitlen; 181353541Sshin 181453541Sshin /* sanity check */ 181553541Sshin if (0 > len || len > 128) { 181653541Sshin log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n", 181753541Sshin len); 1818120856Sume return (0); 181953541Sshin } 182053541Sshin 182153541Sshin bytelen = len / 8; 182253541Sshin bitlen = len % 8; 182353541Sshin 182453541Sshin if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen)) 1825120856Sume return (0); 1826126184Scperciva if (bitlen != 0 && 1827126184Scperciva p1->s6_addr[bytelen] >> (8 - bitlen) != 182853541Sshin p2->s6_addr[bytelen] >> (8 - bitlen)) 1829120856Sume return (0); 183053541Sshin 1831120856Sume return (1); 183253541Sshin} 183353541Sshin 183453541Sshinvoid 183553541Sshinin6_prefixlen2mask(maskp, len) 183653541Sshin struct in6_addr *maskp; 183753541Sshin int len; 183853541Sshin{ 183953541Sshin u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 184053541Sshin int bytelen, bitlen, i; 184153541Sshin 184253541Sshin /* sanity check */ 184353541Sshin if (0 > len || len > 128) { 184453541Sshin log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n", 184553541Sshin len); 184653541Sshin return; 184753541Sshin } 184853541Sshin 184953541Sshin bzero(maskp, sizeof(*maskp)); 185053541Sshin bytelen = len / 8; 185153541Sshin bitlen = len % 8; 185253541Sshin for (i = 0; i < bytelen; i++) 185353541Sshin maskp->s6_addr[i] = 0xff; 185453541Sshin if (bitlen) 185553541Sshin maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 185653541Sshin} 185753541Sshin 185853541Sshin/* 185953541Sshin * return the best address out of the same scope. if no address was 186053541Sshin * found, return the first valid address from designated IF. 186153541Sshin */ 186253541Sshinstruct in6_ifaddr * 186353541Sshinin6_ifawithifp(ifp, dst) 186478064Sume struct ifnet *ifp; 186578064Sume struct in6_addr *dst; 186653541Sshin{ 186753541Sshin int dst_scope = in6_addrscope(dst), blen = -1, tlen; 186853541Sshin struct ifaddr *ifa; 186953541Sshin struct in6_ifaddr *besta = 0; 187095023Ssuz struct in6_ifaddr *dep[2]; /* last-resort: deprecated */ 187153541Sshin 187253541Sshin dep[0] = dep[1] = NULL; 187353541Sshin 187453541Sshin /* 187553541Sshin * We first look for addresses in the same scope. 187653541Sshin * If there is one, return it. 187753541Sshin * If two or more, return one which matches the dst longest. 187853541Sshin * If none, return one of global addresses assigned other ifs. 187953541Sshin */ 1880120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 188153541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 188253541Sshin continue; 188353541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 188453541Sshin continue; /* XXX: is there any case to allow anycast? */ 188553541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 188653541Sshin continue; /* don't use this interface */ 188753541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 188853541Sshin continue; 188953541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 189053541Sshin if (ip6_use_deprecated) 189153541Sshin dep[0] = (struct in6_ifaddr *)ifa; 189253541Sshin continue; 189353541Sshin } 189453541Sshin 189553541Sshin if (dst_scope == in6_addrscope(IFA_IN6(ifa))) { 189653541Sshin /* 189753541Sshin * call in6_matchlen() as few as possible 189853541Sshin */ 189953541Sshin if (besta) { 190053541Sshin if (blen == -1) 190153541Sshin blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst); 190253541Sshin tlen = in6_matchlen(IFA_IN6(ifa), dst); 190353541Sshin if (tlen > blen) { 190453541Sshin blen = tlen; 190553541Sshin besta = (struct in6_ifaddr *)ifa; 190653541Sshin } 190753541Sshin } else 190853541Sshin besta = (struct in6_ifaddr *)ifa; 190953541Sshin } 191053541Sshin } 191153541Sshin if (besta) 1912120856Sume return (besta); 191353541Sshin 1914120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 191553541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 191653541Sshin continue; 191753541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 191853541Sshin continue; /* XXX: is there any case to allow anycast? */ 191953541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 192053541Sshin continue; /* don't use this interface */ 192153541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 192253541Sshin continue; 192353541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 192453541Sshin if (ip6_use_deprecated) 192553541Sshin dep[1] = (struct in6_ifaddr *)ifa; 192653541Sshin continue; 192753541Sshin } 192853541Sshin 192953541Sshin return (struct in6_ifaddr *)ifa; 193053541Sshin } 193153541Sshin 193253541Sshin /* use the last-resort values, that are, deprecated addresses */ 193353541Sshin if (dep[0]) 193453541Sshin return dep[0]; 193553541Sshin if (dep[1]) 193653541Sshin return dep[1]; 193753541Sshin 193853541Sshin return NULL; 193953541Sshin} 194053541Sshin 194153541Sshin/* 194253541Sshin * perform DAD when interface becomes IFF_UP. 194353541Sshin */ 194453541Sshinvoid 194553541Sshinin6_if_up(ifp) 194653541Sshin struct ifnet *ifp; 194753541Sshin{ 194853541Sshin struct ifaddr *ifa; 194953541Sshin struct in6_ifaddr *ia; 195053541Sshin int dad_delay; /* delay ticks before DAD output */ 195153541Sshin 195262587Sitojun /* 195362587Sitojun * special cases, like 6to4, are handled in in6_ifattach 195462587Sitojun */ 195562587Sitojun in6_ifattach(ifp, NULL); 195653541Sshin 195753541Sshin dad_delay = 0; 1958120891Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 195953541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 196053541Sshin continue; 196153541Sshin ia = (struct in6_ifaddr *)ifa; 196253541Sshin if (ia->ia6_flags & IN6_IFF_TENTATIVE) 196353541Sshin nd6_dad_start(ifa, &dad_delay); 196453541Sshin } 196553541Sshin} 196653541Sshin 196778064Sumeint 196878064Sumein6if_do_dad(ifp) 196978064Sume struct ifnet *ifp; 197078064Sume{ 197178064Sume if ((ifp->if_flags & IFF_LOOPBACK) != 0) 1972120856Sume return (0); 197378064Sume 197478064Sume switch (ifp->if_type) { 197578064Sume#ifdef IFT_DUMMY 197678064Sume case IFT_DUMMY: 197778064Sume#endif 197878064Sume case IFT_FAITH: 197978064Sume /* 198078064Sume * These interfaces do not have the IFF_LOOPBACK flag, 198178064Sume * but loop packets back. We do not have to do DAD on such 198278064Sume * interfaces. We should even omit it, because loop-backed 198378064Sume * NS would confuse the DAD procedure. 198478064Sume */ 1985120856Sume return (0); 198678064Sume default: 198778064Sume /* 198878064Sume * Our DAD routine requires the interface up and running. 198978064Sume * However, some interfaces can be up before the RUNNING 199078064Sume * status. Additionaly, users may try to assign addresses 199178064Sume * before the interface becomes up (or running). 199278064Sume * We simply skip DAD in such a case as a work around. 199378064Sume * XXX: we should rather mark "tentative" on such addresses, 199478064Sume * and do DAD after the interface becomes ready. 199578064Sume */ 1996148887Srwatson if (!((ifp->if_flags & IFF_UP) && 1997148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 1998120856Sume return (0); 199978064Sume 2000120856Sume return (1); 200178064Sume } 200278064Sume} 200378064Sume 200453541Sshin/* 200553541Sshin * Calculate max IPv6 MTU through all the interfaces and store it 200653541Sshin * to in6_maxmtu. 200753541Sshin */ 200853541Sshinvoid 200953541Sshinin6_setmaxmtu() 201053541Sshin{ 201153541Sshin unsigned long maxmtu = 0; 201253541Sshin struct ifnet *ifp; 201353541Sshin 2014108172Shsu IFNET_RLOCK(); 2015120891Sume for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { 2016121283Sume /* this function can be called during ifnet initialization */ 2017121283Sume if (!ifp->if_afdata[AF_INET6]) 2018121283Sume continue; 201953541Sshin if ((ifp->if_flags & IFF_LOOPBACK) == 0 && 2020121283Sume IN6_LINKMTU(ifp) > maxmtu) 2021121283Sume maxmtu = IN6_LINKMTU(ifp); 202253541Sshin } 2023108172Shsu IFNET_RUNLOCK(); 2024120891Sume if (maxmtu) /* update only when maxmtu is positive */ 202553541Sshin in6_maxmtu = maxmtu; 202653541Sshin} 202753541Sshin 2028121161Sumevoid * 2029121161Sumein6_domifattach(ifp) 2030121161Sume struct ifnet *ifp; 2031121161Sume{ 2032121161Sume struct in6_ifextra *ext; 2033121161Sume 2034121161Sume ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK); 2035121161Sume bzero(ext, sizeof(*ext)); 2036121161Sume 2037121161Sume ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat), 2038121161Sume M_IFADDR, M_WAITOK); 2039121161Sume bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat)); 2040121161Sume 2041121161Sume ext->icmp6_ifstat = 2042121161Sume (struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat), 2043121161Sume M_IFADDR, M_WAITOK); 2044121161Sume bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat)); 2045121161Sume 2046121161Sume ext->nd_ifinfo = nd6_ifattach(ifp); 2047121161Sume ext->scope6_id = scope6_ifattach(ifp); 2048121161Sume return ext; 2049121161Sume} 2050121161Sume 2051121161Sumevoid 2052121161Sumein6_domifdetach(ifp, aux) 2053121161Sume struct ifnet *ifp; 2054121161Sume void *aux; 2055121161Sume{ 2056121161Sume struct in6_ifextra *ext = (struct in6_ifextra *)aux; 2057121161Sume 2058121161Sume scope6_ifdetach(ext->scope6_id); 2059121161Sume nd6_ifdetach(ext->nd_ifinfo); 2060121161Sume free(ext->in6_ifstat, M_IFADDR); 2061121161Sume free(ext->icmp6_ifstat, M_IFADDR); 2062121161Sume free(ext, M_IFADDR); 2063121161Sume} 2064121161Sume 206553541Sshin/* 206695023Ssuz * Convert sockaddr_in6 to sockaddr_in. Original sockaddr_in6 must be 206753541Sshin * v4 mapped addr or v4 compat addr 206853541Sshin */ 206953541Sshinvoid 207053541Sshinin6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 207153541Sshin{ 207253541Sshin bzero(sin, sizeof(*sin)); 207353541Sshin sin->sin_len = sizeof(struct sockaddr_in); 207453541Sshin sin->sin_family = AF_INET; 207553541Sshin sin->sin_port = sin6->sin6_port; 2076120891Sume sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3]; 207753541Sshin} 207853541Sshin 207953541Sshin/* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */ 208053541Sshinvoid 208153541Sshinin6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 208253541Sshin{ 208353541Sshin bzero(sin6, sizeof(*sin6)); 208453541Sshin sin6->sin6_len = sizeof(struct sockaddr_in6); 208553541Sshin sin6->sin6_family = AF_INET6; 208653541Sshin sin6->sin6_port = sin->sin_port; 208753541Sshin sin6->sin6_addr.s6_addr32[0] = 0; 208853541Sshin sin6->sin6_addr.s6_addr32[1] = 0; 208953541Sshin sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP; 209053541Sshin sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; 209153541Sshin} 209253541Sshin 209353541Sshin/* Convert sockaddr_in6 into sockaddr_in. */ 209453541Sshinvoid 209553541Sshinin6_sin6_2_sin_in_sock(struct sockaddr *nam) 209653541Sshin{ 209753541Sshin struct sockaddr_in *sin_p; 209853541Sshin struct sockaddr_in6 sin6; 209953541Sshin 210053541Sshin /* 210153541Sshin * Save original sockaddr_in6 addr and convert it 210253541Sshin * to sockaddr_in. 210353541Sshin */ 210453541Sshin sin6 = *(struct sockaddr_in6 *)nam; 210553541Sshin sin_p = (struct sockaddr_in *)nam; 210653541Sshin in6_sin6_2_sin(sin_p, &sin6); 210753541Sshin} 210853541Sshin 210953541Sshin/* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */ 211053541Sshinvoid 211153541Sshinin6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam) 211253541Sshin{ 211353541Sshin struct sockaddr_in *sin_p; 211453541Sshin struct sockaddr_in6 *sin6_p; 211553541Sshin 211653541Sshin MALLOC(sin6_p, struct sockaddr_in6 *, sizeof *sin6_p, M_SONAME, 2117111119Simp M_WAITOK); 211853541Sshin sin_p = (struct sockaddr_in *)*nam; 211953541Sshin in6_sin_2_v4mapsin6(sin_p, sin6_p); 212053541Sshin FREE(*nam, M_SONAME); 212153541Sshin *nam = (struct sockaddr *)sin6_p; 212253541Sshin} 2123