1139826Simp/*- 253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 353541Sshin * All rights reserved. 453541Sshin * 553541Sshin * Redistribution and use in source and binary forms, with or without 653541Sshin * modification, are permitted provided that the following conditions 753541Sshin * are met: 853541Sshin * 1. Redistributions of source code must retain the above copyright 953541Sshin * notice, this list of conditions and the following disclaimer. 1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1153541Sshin * notice, this list of conditions and the following disclaimer in the 1253541Sshin * documentation and/or other materials provided with the distribution. 1353541Sshin * 3. Neither the name of the project nor the names of its contributors 1453541Sshin * may be used to endorse or promote products derived from this software 1553541Sshin * without specific prior written permission. 1653541Sshin * 1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2053541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2753541Sshin * SUCH DAMAGE. 28174510Sobrien * 29174510Sobrien * $KAME: in6.c,v 1.259 2002/01/21 11:37:50 keiichi Exp $ 3053541Sshin */ 3153541Sshin 32139826Simp/*- 3353541Sshin * Copyright (c) 1982, 1986, 1991, 1993 3453541Sshin * The Regents of the University of California. All rights reserved. 3553541Sshin * 3653541Sshin * Redistribution and use in source and binary forms, with or without 3753541Sshin * modification, are permitted provided that the following conditions 3853541Sshin * are met: 3953541Sshin * 1. Redistributions of source code must retain the above copyright 4053541Sshin * notice, this list of conditions and the following disclaimer. 4153541Sshin * 2. Redistributions in binary form must reproduce the above copyright 4253541Sshin * notice, this list of conditions and the following disclaimer in the 4353541Sshin * documentation and/or other materials provided with the distribution. 4453541Sshin * 4. Neither the name of the University nor the names of its contributors 4553541Sshin * may be used to endorse or promote products derived from this software 4653541Sshin * without specific prior written permission. 4753541Sshin * 4853541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 4953541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5053541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5153541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5253541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5353541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5453541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5553541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5653541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5753541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5853541Sshin * SUCH DAMAGE. 5953541Sshin * 6053541Sshin * @(#)in.c 8.2 (Berkeley) 11/15/93 6153541Sshin */ 6253541Sshin 63174510Sobrien#include <sys/cdefs.h> 64174510Sobrien__FBSDID("$FreeBSD$"); 65174510Sobrien 66207268Skib#include "opt_compat.h" 6762587Sitojun#include "opt_inet.h" 6862587Sitojun#include "opt_inet6.h" 6962587Sitojun 7053541Sshin#include <sys/param.h> 7153541Sshin#include <sys/errno.h> 72186948Sbz#include <sys/jail.h> 7353541Sshin#include <sys/malloc.h> 7453541Sshin#include <sys/socket.h> 7553541Sshin#include <sys/socketvar.h> 7653541Sshin#include <sys/sockio.h> 7753541Sshin#include <sys/systm.h> 78164033Srwatson#include <sys/priv.h> 7953541Sshin#include <sys/proc.h> 8053541Sshin#include <sys/time.h> 8153541Sshin#include <sys/kernel.h> 8253541Sshin#include <sys/syslog.h> 8353541Sshin 8453541Sshin#include <net/if.h> 85197227Sqingli#include <net/if_var.h> 8653541Sshin#include <net/if_types.h> 8753541Sshin#include <net/route.h> 8853541Sshin#include <net/if_dl.h> 89185571Sbz#include <net/vnet.h> 9053541Sshin 9153541Sshin#include <netinet/in.h> 9253541Sshin#include <netinet/in_var.h> 93186119Sqingli#include <net/if_llatbl.h> 9453541Sshin#include <netinet/if_ether.h> 9578064Sume#include <netinet/in_systm.h> 9678064Sume#include <netinet/ip.h> 9778064Sume#include <netinet/in_pcb.h> 98228571Sglebius#include <netinet/ip_carp.h> 9953541Sshin 10062587Sitojun#include <netinet/ip6.h> 10153541Sshin#include <netinet6/ip6_var.h> 10295023Ssuz#include <netinet6/nd6.h> 10353541Sshin#include <netinet6/mld6_var.h> 10462587Sitojun#include <netinet6/ip6_mroute.h> 10553541Sshin#include <netinet6/in6_ifattach.h> 10662587Sitojun#include <netinet6/scope6_var.h> 10778064Sume#include <netinet6/in6_pcb.h> 10862587Sitojun 109250251ShrsVNET_DECLARE(int, icmp6_nodeinfo_oldmcprefix); 110250251Shrs#define V_icmp6_nodeinfo_oldmcprefix VNET(icmp6_nodeinfo_oldmcprefix) 111250251Shrs 11253541Sshin/* 11353541Sshin * Definitions of some costant IP6 addresses. 11453541Sshin */ 11562587Sitojunconst struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 11662587Sitojunconst struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 11762587Sitojunconst struct in6_addr in6addr_nodelocal_allnodes = 11853541Sshin IN6ADDR_NODELOCAL_ALLNODES_INIT; 11962587Sitojunconst struct in6_addr in6addr_linklocal_allnodes = 12053541Sshin IN6ADDR_LINKLOCAL_ALLNODES_INIT; 12162587Sitojunconst struct in6_addr in6addr_linklocal_allrouters = 12253541Sshin IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; 123191672Sbmsconst struct in6_addr in6addr_linklocal_allv2routers = 124191672Sbms IN6ADDR_LINKLOCAL_ALLV2ROUTERS_INIT; 12553541Sshin 12662587Sitojunconst struct in6_addr in6mask0 = IN6MASK0; 12762587Sitojunconst struct in6_addr in6mask32 = IN6MASK32; 12862587Sitojunconst struct in6_addr in6mask64 = IN6MASK64; 12962587Sitojunconst struct in6_addr in6mask96 = IN6MASK96; 13062587Sitojunconst struct in6_addr in6mask128 = IN6MASK128; 13153541Sshin 132126552Sumeconst struct sockaddr_in6 sa6_any = 133126552Sume { sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 }; 13478064Sume 135241916Sdelphijstatic int in6_lifaddr_ioctl(struct socket *, u_long, caddr_t, 136241916Sdelphij struct ifnet *, struct thread *); 137241916Sdelphijstatic int in6_ifinit(struct ifnet *, struct in6_ifaddr *, 138241916Sdelphij struct sockaddr_in6 *, int); 139175162Sobrienstatic void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *); 14053541Sshin 14183934Sbrooksint (*faithprefix_p)(struct in6_addr *); 14283934Sbrooks 143226338Sglebius#define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) 144226338Sglebius#define ia62ifa(ia6) (&((ia6)->ia_ifa)) 145120891Sume 146226338Sglebiusvoid 147226338Sglebiusin6_ifaddloop(struct ifaddr *ifa) 148226338Sglebius{ 149226338Sglebius struct sockaddr_dl gateway; 150226338Sglebius struct sockaddr_in6 mask, addr; 151226338Sglebius struct rtentry rt; 152226338Sglebius struct in6_ifaddr *ia; 153226338Sglebius struct ifnet *ifp; 154226338Sglebius struct llentry *ln; 15578064Sume 156226338Sglebius ia = ifa2ia6(ifa); 157226338Sglebius ifp = ifa->ifa_ifp; 158226338Sglebius IF_AFDATA_LOCK(ifp); 159227460Sqingli ifa->ifa_rtrequest = nd6_rtrequest; 160226338Sglebius ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | 161226338Sglebius LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr); 162226338Sglebius IF_AFDATA_UNLOCK(ifp); 163226338Sglebius if (ln != NULL) { 164226338Sglebius ln->la_expire = 0; /* for IPv6 this means permanent */ 165226338Sglebius ln->ln_state = ND6_LLINFO_REACHABLE; 166226338Sglebius /* 167226338Sglebius * initialize for rtmsg generation 168226338Sglebius */ 169226338Sglebius bzero(&gateway, sizeof(gateway)); 170226338Sglebius gateway.sdl_len = sizeof(gateway); 171226338Sglebius gateway.sdl_family = AF_LINK; 172226338Sglebius gateway.sdl_nlen = 0; 173226338Sglebius gateway.sdl_alen = 6; 174226338Sglebius memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned, 175226338Sglebius sizeof(ln->ll_addr)); 176226338Sglebius LLE_WUNLOCK(ln); 177226338Sglebius } 178226338Sglebius 179226338Sglebius bzero(&rt, sizeof(rt)); 180226338Sglebius rt.rt_gateway = (struct sockaddr *)&gateway; 181226338Sglebius memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); 182226338Sglebius memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); 183226338Sglebius rt_mask(&rt) = (struct sockaddr *)&mask; 184226338Sglebius rt_key(&rt) = (struct sockaddr *)&addr; 185226338Sglebius rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC; 186231852Sbz /* Announce arrival of local address to all FIBs. */ 187226338Sglebius rt_newaddrmsg(RTM_ADD, ifa, 0, &rt); 188226338Sglebius} 189226338Sglebius 190226338Sglebiusvoid 191226338Sglebiusin6_ifremloop(struct ifaddr *ifa) 192226338Sglebius{ 193226338Sglebius struct sockaddr_dl gateway; 194226338Sglebius struct sockaddr_in6 mask, addr; 195226338Sglebius struct rtentry rt0; 196226338Sglebius struct in6_ifaddr *ia; 197226338Sglebius struct ifnet *ifp; 198226338Sglebius 199226338Sglebius ia = ifa2ia6(ifa); 200226338Sglebius ifp = ifa->ifa_ifp; 201249742Soleg memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); 202249742Soleg memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); 203249742Soleg lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr, 204249742Soleg (struct sockaddr *)&mask, LLE_STATIC); 205226338Sglebius 206226338Sglebius /* 207226338Sglebius * initialize for rtmsg generation 208226338Sglebius */ 209226338Sglebius bzero(&gateway, sizeof(gateway)); 210226338Sglebius gateway.sdl_len = sizeof(gateway); 211226338Sglebius gateway.sdl_family = AF_LINK; 212226338Sglebius gateway.sdl_nlen = 0; 213226338Sglebius gateway.sdl_alen = ifp->if_addrlen; 214226338Sglebius bzero(&rt0, sizeof(rt0)); 215226338Sglebius rt0.rt_gateway = (struct sockaddr *)&gateway; 216226338Sglebius rt_mask(&rt0) = (struct sockaddr *)&mask; 217226338Sglebius rt_key(&rt0) = (struct sockaddr *)&addr; 218226338Sglebius rt0.rt_flags = RTF_HOST | RTF_STATIC; 219231852Sbz /* Announce removal of local address to all FIBs. */ 220226338Sglebius rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0); 221226338Sglebius} 222226338Sglebius 22353541Sshinint 224171259Sdelphijin6_mask2len(struct in6_addr *mask, u_char *lim0) 22553541Sshin{ 22678064Sume int x = 0, y; 22778064Sume u_char *lim = lim0, *p; 22853541Sshin 229120891Sume /* ignore the scope_id part */ 230120891Sume if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask)) 23178064Sume lim = (u_char *)mask + sizeof(*mask); 23278064Sume for (p = (u_char *)mask; p < lim; x++, p++) { 23378064Sume if (*p != 0xff) 23453541Sshin break; 23553541Sshin } 23653541Sshin y = 0; 23778064Sume if (p < lim) { 23853541Sshin for (y = 0; y < 8; y++) { 23978064Sume if ((*p & (0x80 >> y)) == 0) 24053541Sshin break; 24153541Sshin } 24253541Sshin } 24378064Sume 24478064Sume /* 24578064Sume * when the limit pointer is given, do a stricter check on the 24678064Sume * remaining bits. 24778064Sume */ 24878064Sume if (p < lim) { 24978064Sume if (y != 0 && (*p & (0x00ff >> y)) != 0) 250120856Sume return (-1); 25178064Sume for (p = p + 1; p < lim; p++) 25278064Sume if (*p != 0) 253120856Sume return (-1); 25478064Sume } 255120891Sume 25653541Sshin return x * 8 + y; 25753541Sshin} 25853541Sshin 259207268Skib#ifdef COMPAT_FREEBSD32 260207268Skibstruct in6_ndifreq32 { 261238945Sglebius char ifname[IFNAMSIZ]; 262238945Sglebius uint32_t ifindex; 263207268Skib}; 264238945Sglebius#define SIOCGDEFIFACE32_IN6 _IOWR('i', 86, struct in6_ndifreq32) 265207268Skib#endif 266207268Skib 26753541Sshinint 268171259Sdelphijin6_control(struct socket *so, u_long cmd, caddr_t data, 269171259Sdelphij struct ifnet *ifp, struct thread *td) 27053541Sshin{ 27153541Sshin struct in6_ifreq *ifr = (struct in6_ifreq *)data; 27278064Sume struct in6_ifaddr *ia = NULL; 27353541Sshin struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; 274151539Ssuz struct sockaddr_in6 *sa6; 275228571Sglebius int carp_attached = 0; 276164033Srwatson int error; 277228768Sglebius u_long ocmd = cmd; 27853541Sshin 279228768Sglebius /* 280228768Sglebius * Compat to make pre-10.x ifconfig(8) operable. 281228768Sglebius */ 282228768Sglebius if (cmd == OSIOCAIFADDR_IN6) 283228768Sglebius cmd = SIOCAIFADDR_IN6; 284228768Sglebius 28562587Sitojun switch (cmd) { 28662587Sitojun case SIOCGETSGCNT_IN6: 28762587Sitojun case SIOCGETMIFCNT_IN6: 288238967Sglebius /* 289231852Sbz * XXX mrt_ioctl has a 3rd, unused, FIB argument in route.c. 290231852Sbz * We cannot see how that would be needed, so do not adjust the 291231852Sbz * KPI blindly; more likely should clean up the IPv4 variant. 292231852Sbz */ 293166938Sbms return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP); 29462587Sitojun } 29553541Sshin 296271185Smarkj switch (cmd) { 297121742Sume case SIOCAADDRCTL_POLICY: 298121742Sume case SIOCDADDRCTL_POLICY: 299164033Srwatson if (td != NULL) { 300164033Srwatson error = priv_check(td, PRIV_NETINET_ADDRCTRL6); 301164033Srwatson if (error) 302164033Srwatson return (error); 303164033Srwatson } 304121742Sume return (in6_src_ioctl(cmd, data)); 305121742Sume } 306121742Sume 30762587Sitojun if (ifp == NULL) 308120856Sume return (EOPNOTSUPP); 30953541Sshin 31053541Sshin switch (cmd) { 31153541Sshin case SIOCSNDFLUSH_IN6: 31253541Sshin case SIOCSPFXFLUSH_IN6: 31353541Sshin case SIOCSRTRFLUSH_IN6: 31462587Sitojun case SIOCSDEFIFACE_IN6: 31562587Sitojun case SIOCSIFINFO_FLAGS: 316193893Scperciva case SIOCSIFINFO_IN6: 317164033Srwatson if (td != NULL) { 318164033Srwatson error = priv_check(td, PRIV_NETINET_ND6); 319164033Srwatson if (error) 320164033Srwatson return (error); 321164033Srwatson } 322120891Sume /* FALLTHROUGH */ 32378064Sume case OSIOCGIFINFO_IN6: 32453541Sshin case SIOCGIFINFO_IN6: 32553541Sshin case SIOCGDRLST_IN6: 32653541Sshin case SIOCGPRLST_IN6: 32753541Sshin case SIOCGNBRINFO_IN6: 32862587Sitojun case SIOCGDEFIFACE_IN6: 329120856Sume return (nd6_ioctl(cmd, data, ifp)); 330207268Skib 331207268Skib#ifdef COMPAT_FREEBSD32 332207268Skib case SIOCGDEFIFACE32_IN6: 333207268Skib { 334207268Skib struct in6_ndifreq ndif; 335207268Skib struct in6_ndifreq32 *ndif32; 336207268Skib 337207268Skib error = nd6_ioctl(SIOCGDEFIFACE_IN6, (caddr_t)&ndif, 338207268Skib ifp); 339207268Skib if (error) 340207268Skib return (error); 341207268Skib ndif32 = (struct in6_ndifreq32 *)data; 342207268Skib ndif32->ifindex = ndif.ifindex; 343207268Skib return (0); 344207268Skib } 345207268Skib#endif 34653541Sshin } 34753541Sshin 34853541Sshin switch (cmd) { 34953541Sshin case SIOCSIFPREFIX_IN6: 35053541Sshin case SIOCDIFPREFIX_IN6: 35153541Sshin case SIOCAIFPREFIX_IN6: 35253541Sshin case SIOCCIFPREFIX_IN6: 35353541Sshin case SIOCSGIFPREFIX_IN6: 35453541Sshin case SIOCGIFPREFIX_IN6: 35578064Sume log(LOG_NOTICE, 35678064Sume "prefix ioctls are now invalidated. " 35778064Sume "please use ifconfig.\n"); 358120856Sume return (EOPNOTSUPP); 35953541Sshin } 36053541Sshin 36195023Ssuz switch (cmd) { 36262587Sitojun case SIOCSSCOPE6: 363164033Srwatson if (td != NULL) { 364164033Srwatson error = priv_check(td, PRIV_NETINET_SCOPE6); 365164033Srwatson if (error) 366164033Srwatson return (error); 367164033Srwatson } 368271185Smarkj /* FALLTHROUGH */ 36962587Sitojun case SIOCGSCOPE6: 37062587Sitojun case SIOCGSCOPE6DEF: 371271185Smarkj return (scope6_ioctl(cmd, data, ifp)); 37262587Sitojun } 37362587Sitojun 37453541Sshin switch (cmd) { 37553541Sshin case SIOCALIFADDR: 376175630Sbz if (td != NULL) { 377175630Sbz error = priv_check(td, PRIV_NET_ADDIFADDR); 378175630Sbz if (error) 379175630Sbz return (error); 380175630Sbz } 381175630Sbz return in6_lifaddr_ioctl(so, cmd, data, ifp, td); 382175630Sbz 38353541Sshin case SIOCDLIFADDR: 384164033Srwatson if (td != NULL) { 385175630Sbz error = priv_check(td, PRIV_NET_DELIFADDR); 386164033Srwatson if (error) 387164033Srwatson return (error); 388164033Srwatson } 389120891Sume /* FALLTHROUGH */ 39053541Sshin case SIOCGLIFADDR: 39183366Sjulian return in6_lifaddr_ioctl(so, cmd, data, ifp, td); 39253541Sshin } 39353541Sshin 39453541Sshin /* 39553541Sshin * Find address for this interface, if it exists. 396151539Ssuz * 397151539Ssuz * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation 398151539Ssuz * only, and used the first interface address as the target of other 399151539Ssuz * operations (without checking ifra_addr). This was because netinet 400151539Ssuz * code/API assumed at most 1 interface address per interface. 401151539Ssuz * Since IPv6 allows a node to assign multiple addresses 402151539Ssuz * on a single interface, we almost always look and check the 403151539Ssuz * presence of ifra_addr, and reject invalid ones here. 404151539Ssuz * It also decreases duplicated code among SIOC*_IN6 operations. 40553541Sshin */ 406151539Ssuz switch (cmd) { 407151539Ssuz case SIOCAIFADDR_IN6: 408151539Ssuz case SIOCSIFPHYADDR_IN6: 409151539Ssuz sa6 = &ifra->ifra_addr; 410151539Ssuz break; 411151539Ssuz case SIOCSIFADDR_IN6: 412151539Ssuz case SIOCGIFADDR_IN6: 413151539Ssuz case SIOCSIFDSTADDR_IN6: 414151539Ssuz case SIOCSIFNETMASK_IN6: 415151539Ssuz case SIOCGIFDSTADDR_IN6: 416151539Ssuz case SIOCGIFNETMASK_IN6: 417151539Ssuz case SIOCDIFADDR_IN6: 418151539Ssuz case SIOCGIFPSRCADDR_IN6: 419151539Ssuz case SIOCGIFPDSTADDR_IN6: 420151539Ssuz case SIOCGIFAFLAG_IN6: 421151539Ssuz case SIOCSNDFLUSH_IN6: 422151539Ssuz case SIOCSPFXFLUSH_IN6: 423151539Ssuz case SIOCSRTRFLUSH_IN6: 424151539Ssuz case SIOCGIFALIFETIME_IN6: 425151539Ssuz case SIOCSIFALIFETIME_IN6: 426151539Ssuz case SIOCGIFSTAT_IN6: 427151539Ssuz case SIOCGIFSTAT_ICMP6: 428151539Ssuz sa6 = &ifr->ifr_addr; 429151539Ssuz break; 430255442Sdes case SIOCSIFADDR: 431255442Sdes case SIOCSIFBRDADDR: 432255442Sdes case SIOCSIFDSTADDR: 433255442Sdes case SIOCSIFNETMASK: 434255442Sdes /* 435255442Sdes * Although we should pass any non-INET6 ioctl requests 436255442Sdes * down to driver, we filter some legacy INET requests. 437255442Sdes * Drivers trust SIOCSIFADDR et al to come from an already 438255442Sdes * privileged layer, and do not perform any credentials 439255442Sdes * checks or input validation. 440255442Sdes */ 441255442Sdes return (EINVAL); 442151539Ssuz default: 443151539Ssuz sa6 = NULL; 444151539Ssuz break; 445151539Ssuz } 446151539Ssuz if (sa6 && sa6->sin6_family == AF_INET6) { 447151539Ssuz if (sa6->sin6_scope_id != 0) 448151539Ssuz error = sa6_embedscope(sa6, 0); 449148385Sume else 450151539Ssuz error = in6_setscope(&sa6->sin6_addr, ifp, NULL); 451148385Sume if (error != 0) 452148385Sume return (error); 453188144Sjamie if (td != NULL && (error = prison_check_ip6(td->td_ucred, 454188144Sjamie &sa6->sin6_addr)) != 0) 455188144Sjamie return (error); 456151539Ssuz ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr); 457151539Ssuz } else 458151539Ssuz ia = NULL; 45953541Sshin 46053541Sshin switch (cmd) { 46178064Sume case SIOCSIFADDR_IN6: 46278064Sume case SIOCSIFDSTADDR_IN6: 46378064Sume case SIOCSIFNETMASK_IN6: 46478064Sume /* 46578064Sume * Since IPv6 allows a node to assign multiple addresses 466151465Ssuz * on a single interface, SIOCSIFxxx ioctls are deprecated. 46778064Sume */ 46878064Sume /* we decided to obsolete this command (20000704) */ 469194760Srwatson error = EINVAL; 470194760Srwatson goto out; 47153541Sshin 47253541Sshin case SIOCDIFADDR_IN6: 47362587Sitojun /* 47478064Sume * for IPv4, we look for existing in_ifaddr here to allow 475151465Ssuz * "ifconfig if0 delete" to remove the first IPv4 address on 476151465Ssuz * the interface. For IPv6, as the spec allows multiple 477151465Ssuz * interface address from the day one, we consider "remove the 478151465Ssuz * first one" semantics to be not preferable. 47962587Sitojun */ 480194760Srwatson if (ia == NULL) { 481194760Srwatson error = EADDRNOTAVAIL; 482194760Srwatson goto out; 483194760Srwatson } 48453541Sshin /* FALLTHROUGH */ 48553541Sshin case SIOCAIFADDR_IN6: 48662587Sitojun /* 48778064Sume * We always require users to specify a valid IPv6 address for 48878064Sume * the corresponding operation. 48962587Sitojun */ 49078064Sume if (ifra->ifra_addr.sin6_family != AF_INET6 || 491194760Srwatson ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) { 492194760Srwatson error = EAFNOSUPPORT; 493194760Srwatson goto out; 494194760Srwatson } 49553541Sshin 496164033Srwatson if (td != NULL) { 497238945Sglebius error = priv_check(td, (cmd == SIOCDIFADDR_IN6) ? 498175630Sbz PRIV_NET_DELIFADDR : PRIV_NET_ADDIFADDR); 499164033Srwatson if (error) 500194760Srwatson goto out; 501164033Srwatson } 502271185Smarkj /* FALLTHROUGH */ 503271185Smarkj case SIOCGIFSTAT_IN6: 504271185Smarkj case SIOCGIFSTAT_ICMP6: 505271185Smarkj if (ifp->if_afdata[AF_INET6] == NULL) { 506271185Smarkj error = EPFNOSUPPORT; 507271185Smarkj goto out; 508271185Smarkj } 50953541Sshin break; 51053541Sshin 51153541Sshin case SIOCGIFADDR_IN6: 51253541Sshin /* This interface is basically deprecated. use SIOCGIFCONF. */ 513120891Sume /* FALLTHROUGH */ 51453541Sshin case SIOCGIFAFLAG_IN6: 51553541Sshin case SIOCGIFNETMASK_IN6: 51653541Sshin case SIOCGIFDSTADDR_IN6: 51753541Sshin case SIOCGIFALIFETIME_IN6: 51853541Sshin /* must think again about its semantics */ 519194760Srwatson if (ia == NULL) { 520194760Srwatson error = EADDRNOTAVAIL; 521194760Srwatson goto out; 522194760Srwatson } 52353541Sshin break; 524194760Srwatson 52553541Sshin case SIOCSIFALIFETIME_IN6: 52653541Sshin { 52753541Sshin struct in6_addrlifetime *lt; 52853541Sshin 529164033Srwatson if (td != NULL) { 530164033Srwatson error = priv_check(td, PRIV_NETINET_ALIFETIME6); 531164033Srwatson if (error) 532194760Srwatson goto out; 533164033Srwatson } 534194760Srwatson if (ia == NULL) { 535194760Srwatson error = EADDRNOTAVAIL; 536194760Srwatson goto out; 537194760Srwatson } 53853541Sshin /* sanity for overflow - beware unsigned */ 53953541Sshin lt = &ifr->ifr_ifru.ifru_lifetime; 540126552Sume if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME && 541253970Shrs lt->ia6t_vltime + time_uptime < time_uptime) { 542194760Srwatson error = EINVAL; 543194760Srwatson goto out; 54453541Sshin } 545126552Sume if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME && 546253970Shrs lt->ia6t_pltime + time_uptime < time_uptime) { 547194760Srwatson error = EINVAL; 548194760Srwatson goto out; 54953541Sshin } 55053541Sshin break; 55153541Sshin } 55253541Sshin } 55353541Sshin 55453541Sshin switch (cmd) { 55553541Sshin case SIOCGIFADDR_IN6: 55653541Sshin ifr->ifr_addr = ia->ia_addr; 557148385Sume if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0) 558194760Srwatson goto out; 55953541Sshin break; 56053541Sshin 56153541Sshin case SIOCGIFDSTADDR_IN6: 562194760Srwatson if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 563194760Srwatson error = EINVAL; 564194760Srwatson goto out; 565194760Srwatson } 56662587Sitojun /* 56762587Sitojun * XXX: should we check if ifa_dstaddr is NULL and return 56862587Sitojun * an error? 56962587Sitojun */ 57053541Sshin ifr->ifr_dstaddr = ia->ia_dstaddr; 571148385Sume if ((error = sa6_recoverscope(&ifr->ifr_dstaddr)) != 0) 572194760Srwatson goto out; 57353541Sshin break; 57453541Sshin 57553541Sshin case SIOCGIFNETMASK_IN6: 57653541Sshin ifr->ifr_addr = ia->ia_prefixmask; 57753541Sshin break; 57853541Sshin 57953541Sshin case SIOCGIFAFLAG_IN6: 58053541Sshin ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags; 58153541Sshin break; 58253541Sshin 58353541Sshin case SIOCGIFSTAT_IN6: 584253086Sae COUNTER_ARRAY_COPY(((struct in6_ifextra *) 585253086Sae ifp->if_afdata[AF_INET6])->in6_ifstat, 586253086Sae &ifr->ifr_ifru.ifru_stat, 587253086Sae sizeof(struct in6_ifstat) / sizeof(uint64_t)); 58853541Sshin break; 58953541Sshin 59053541Sshin case SIOCGIFSTAT_ICMP6: 591253086Sae COUNTER_ARRAY_COPY(((struct in6_ifextra *) 592253086Sae ifp->if_afdata[AF_INET6])->icmp6_ifstat, 593253086Sae &ifr->ifr_ifru.ifru_icmp6stat, 594253086Sae sizeof(struct icmp6_ifstat) / sizeof(uint64_t)); 59553541Sshin break; 59653541Sshin 59753541Sshin case SIOCGIFALIFETIME_IN6: 59853541Sshin ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime; 599151539Ssuz if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 600151539Ssuz time_t maxexpire; 601151539Ssuz struct in6_addrlifetime *retlt = 602151539Ssuz &ifr->ifr_ifru.ifru_lifetime; 603151539Ssuz 604151539Ssuz /* 605151539Ssuz * XXX: adjust expiration time assuming time_t is 606151539Ssuz * signed. 607151539Ssuz */ 608151539Ssuz maxexpire = (-1) & 609151546Ssuz ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); 610151539Ssuz if (ia->ia6_lifetime.ia6t_vltime < 611151539Ssuz maxexpire - ia->ia6_updatetime) { 612151539Ssuz retlt->ia6t_expire = ia->ia6_updatetime + 613151539Ssuz ia->ia6_lifetime.ia6t_vltime; 614151539Ssuz } else 615151539Ssuz retlt->ia6t_expire = maxexpire; 616151539Ssuz } 617151539Ssuz if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 618151539Ssuz time_t maxexpire; 619151539Ssuz struct in6_addrlifetime *retlt = 620151539Ssuz &ifr->ifr_ifru.ifru_lifetime; 621151539Ssuz 622151539Ssuz /* 623151539Ssuz * XXX: adjust expiration time assuming time_t is 624151539Ssuz * signed. 625151539Ssuz */ 626151539Ssuz maxexpire = (-1) & 627151546Ssuz ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); 628151539Ssuz if (ia->ia6_lifetime.ia6t_pltime < 629151539Ssuz maxexpire - ia->ia6_updatetime) { 630151539Ssuz retlt->ia6t_preferred = ia->ia6_updatetime + 631151539Ssuz ia->ia6_lifetime.ia6t_pltime; 632151539Ssuz } else 633151539Ssuz retlt->ia6t_preferred = maxexpire; 634151539Ssuz } 63553541Sshin break; 63653541Sshin 63753541Sshin case SIOCSIFALIFETIME_IN6: 63853541Sshin ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime; 63953541Sshin /* for sanity */ 64053541Sshin if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 64153541Sshin ia->ia6_lifetime.ia6t_expire = 642253970Shrs time_uptime + ia->ia6_lifetime.ia6t_vltime; 64353541Sshin } else 64453541Sshin ia->ia6_lifetime.ia6t_expire = 0; 64553541Sshin if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 64653541Sshin ia->ia6_lifetime.ia6t_preferred = 647253970Shrs time_uptime + ia->ia6_lifetime.ia6t_pltime; 64853541Sshin } else 64953541Sshin ia->ia6_lifetime.ia6t_preferred = 0; 65053541Sshin break; 65153541Sshin 65278064Sume case SIOCAIFADDR_IN6: 65378064Sume { 654194760Srwatson int i; 655151539Ssuz struct nd_prefixctl pr0; 656151539Ssuz struct nd_prefix *pr; 65778064Sume 65862587Sitojun /* 65978064Sume * first, make or update the interface address structure, 66078064Sume * and link it to the list. 66162587Sitojun */ 662151539Ssuz if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0) 663194760Srwatson goto out; 664194760Srwatson if (ia != NULL) 665194760Srwatson ifa_free(&ia->ia_ifa); 666151915Ssuz if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr)) 667151915Ssuz == NULL) { 668171260Sdelphij /* 669151915Ssuz * this can happen when the user specify the 0 valid 670151915Ssuz * lifetime. 671151915Ssuz */ 672151915Ssuz break; 673151915Ssuz } 67453541Sshin 675228768Sglebius if (cmd == ocmd && ifra->ifra_vhid > 0) { 676228571Sglebius if (carp_attach_p != NULL) 677228571Sglebius error = (*carp_attach_p)(&ia->ia_ifa, 678228571Sglebius ifra->ifra_vhid); 679228571Sglebius else 680228571Sglebius error = EPROTONOSUPPORT; 681228571Sglebius if (error) 682228571Sglebius goto out; 683228571Sglebius else 684228571Sglebius carp_attached = 1; 685228571Sglebius } 686228571Sglebius 68778064Sume /* 68878064Sume * then, make the prefix on-link on the interface. 68978064Sume * XXX: we'd rather create the prefix before the address, but 69078064Sume * we need at least one address to install the corresponding 69178064Sume * interface route, so we configure the address first. 69278064Sume */ 69378064Sume 69478064Sume /* 69578064Sume * convert mask to prefix length (prefixmask has already 69678064Sume * been validated in in6_update_ifa(). 69778064Sume */ 69878064Sume bzero(&pr0, sizeof(pr0)); 69978064Sume pr0.ndpr_ifp = ifp; 70078064Sume pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 701120891Sume NULL); 702120891Sume if (pr0.ndpr_plen == 128) { 70378064Sume break; /* we don't need to install a host route. */ 704120891Sume } 70578064Sume pr0.ndpr_prefix = ifra->ifra_addr; 70678064Sume /* apply the mask for safety. */ 70778064Sume for (i = 0; i < 4; i++) { 70878064Sume pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 709120891Sume ifra->ifra_prefixmask.sin6_addr.s6_addr32[i]; 71078064Sume } 71178064Sume /* 71295023Ssuz * XXX: since we don't have an API to set prefix (not address) 71395023Ssuz * lifetimes, we just use the same lifetimes as addresses. 71495023Ssuz * The (temporarily) installed lifetimes can be overridden by 71595023Ssuz * later advertised RAs (when accept_rtadv is non 0), which is 71695023Ssuz * an intended behavior. 71778064Sume */ 71878064Sume pr0.ndpr_raf_onlink = 1; /* should be configurable? */ 71978064Sume pr0.ndpr_raf_auto = 720120891Sume ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0); 72178064Sume pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime; 72278064Sume pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime; 72378064Sume 724120891Sume /* add the prefix if not yet. */ 72578064Sume if ((pr = nd6_prefix_lookup(&pr0)) == NULL) { 72678064Sume /* 72778064Sume * nd6_prelist_add will install the corresponding 72878064Sume * interface route. 72978064Sume */ 730228571Sglebius if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) { 731228571Sglebius if (carp_attached) 732228571Sglebius (*carp_detach_p)(&ia->ia_ifa); 733194760Srwatson goto out; 734228571Sglebius } 73578064Sume if (pr == NULL) { 736228571Sglebius if (carp_attached) 737228571Sglebius (*carp_detach_p)(&ia->ia_ifa); 738120891Sume log(LOG_ERR, "nd6_prelist_add succeeded but " 73978064Sume "no prefix\n"); 740194760Srwatson error = EINVAL; 741194760Srwatson goto out; 74278064Sume } 74378064Sume } 74478064Sume 745151915Ssuz /* relate the address to the prefix */ 746151915Ssuz if (ia->ia6_ndpr == NULL) { 747151915Ssuz ia->ia6_ndpr = pr; 748151915Ssuz pr->ndpr_refcnt++; 74978064Sume 75078064Sume /* 751151915Ssuz * If this is the first autoconf address from the 752151915Ssuz * prefix, create a temporary address as well 753151915Ssuz * (when required). 75478064Sume */ 755151915Ssuz if ((ia->ia6_flags & IN6_IFF_AUTOCONF) && 756181803Sbz V_ip6_use_tempaddr && pr->ndpr_refcnt == 1) { 757151915Ssuz int e; 758151915Ssuz if ((e = in6_tmpifadd(ia, 1, 0)) != 0) { 759151915Ssuz log(LOG_NOTICE, "in6_control: failed " 760151915Ssuz "to create a temporary address, " 761151915Ssuz "errno=%d\n", e); 762151915Ssuz } 763151915Ssuz } 76462587Sitojun } 765151915Ssuz 766151915Ssuz /* 767151915Ssuz * this might affect the status of autoconfigured addresses, 768151915Ssuz * that is, this address might make other addresses detached. 769151915Ssuz */ 770151915Ssuz pfxlist_onlink_check(); 771222730Shrs if (error == 0 && ia) { 772222730Shrs if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) { 773222730Shrs /* 774222730Shrs * Try to clear the flag when a new 775222730Shrs * IPv6 address is added onto an 776222730Shrs * IFDISABLED interface and it 777222730Shrs * succeeds. 778222730Shrs */ 779222730Shrs struct in6_ndireq nd; 780222730Shrs 781222730Shrs memset(&nd, 0, sizeof(nd)); 782222730Shrs nd.ndi.flags = ND_IFINFO(ifp)->flags; 783222730Shrs nd.ndi.flags &= ~ND6_IFF_IFDISABLED; 784222730Shrs if (nd6_ioctl(SIOCSIFINFO_FLAGS, 785222730Shrs (caddr_t)&nd, ifp) < 0) 786222730Shrs log(LOG_NOTICE, "SIOCAIFADDR_IN6: " 787222730Shrs "SIOCSIFINFO_FLAGS for -ifdisabled " 788222730Shrs "failed."); 789222730Shrs /* 790222730Shrs * Ignore failure of clearing the flag 791222730Shrs * intentionally. The failure means 792222730Shrs * address duplication was detected. 793222730Shrs */ 794222730Shrs } 795126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 796222730Shrs } 79778064Sume break; 79878064Sume } 79962587Sitojun 80078064Sume case SIOCDIFADDR_IN6: 80178064Sume { 802151539Ssuz struct nd_prefix *pr; 80378064Sume 80478064Sume /* 80578064Sume * If the address being deleted is the only one that owns 80678064Sume * the corresponding prefix, expire the prefix as well. 807120891Sume * XXX: theoretically, we don't have to worry about such 80878064Sume * relationship, since we separate the address management 80978064Sume * and the prefix management. We do this, however, to provide 81078064Sume * as much backward compatibility as possible in terms of 81178064Sume * the ioctl operation. 812151915Ssuz * Note that in6_purgeaddr() will decrement ndpr_refcnt. 81378064Sume */ 814151915Ssuz pr = ia->ia6_ndpr; 81578064Sume in6_purgeaddr(&ia->ia_ifa); 816151915Ssuz if (pr && pr->ndpr_refcnt == 0) 817151915Ssuz prelist_remove(pr); 818126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 81953541Sshin break; 82078064Sume } 82153541Sshin 82278064Sume default: 823271185Smarkj if (ifp->if_ioctl == NULL) { 824194760Srwatson error = EOPNOTSUPP; 825194760Srwatson goto out; 826194760Srwatson } 827194760Srwatson error = (*ifp->if_ioctl)(ifp, cmd, data); 828194760Srwatson goto out; 82978064Sume } 83053541Sshin 831194760Srwatson error = 0; 832194760Srwatsonout: 833194760Srwatson if (ia != NULL) 834194760Srwatson ifa_free(&ia->ia_ifa); 835194760Srwatson return (error); 83678064Sume} 83753541Sshin 838231852Sbz 83978064Sume/* 840231852Sbz * Join necessary multicast groups. Factored out from in6_update_ifa(). 841231852Sbz * This entire work should only be done once, for the default FIB. 842231852Sbz */ 843231852Sbzstatic int 844231852Sbzin6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra, 845231852Sbz struct in6_ifaddr *ia, int flags, struct in6_multi **in6m_sol) 846231852Sbz{ 847231852Sbz char ip6buf[INET6_ADDRSTRLEN]; 848231852Sbz struct sockaddr_in6 mltaddr, mltmask; 849231852Sbz struct in6_addr llsol; 850231852Sbz struct in6_multi_mship *imm; 851231852Sbz struct rtentry *rt; 852231852Sbz int delay, error; 853231852Sbz 854231852Sbz KASSERT(in6m_sol != NULL, ("%s: in6m_sol is NULL", __func__)); 855231852Sbz 856231852Sbz /* Join solicited multicast addr for new host id. */ 857231852Sbz bzero(&llsol, sizeof(struct in6_addr)); 858231852Sbz llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL; 859231852Sbz llsol.s6_addr32[1] = 0; 860231852Sbz llsol.s6_addr32[2] = htonl(1); 861231852Sbz llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3]; 862231852Sbz llsol.s6_addr8[12] = 0xff; 863231852Sbz if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) { 864231852Sbz /* XXX: should not happen */ 865231852Sbz log(LOG_ERR, "%s: in6_setscope failed\n", __func__); 866231852Sbz goto cleanup; 867231852Sbz } 868231852Sbz delay = 0; 869231852Sbz if ((flags & IN6_IFAUPDATE_DADDELAY)) { 870231852Sbz /* 871231852Sbz * We need a random delay for DAD on the address being 872231852Sbz * configured. It also means delaying transmission of the 873231852Sbz * corresponding MLD report to avoid report collision. 874231852Sbz * [RFC 4861, Section 6.3.7] 875231852Sbz */ 876231852Sbz delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz); 877231852Sbz } 878231852Sbz imm = in6_joingroup(ifp, &llsol, &error, delay); 879231852Sbz if (imm == NULL) { 880231852Sbz nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " 881231852Sbz "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &llsol), 882231852Sbz if_name(ifp), error)); 883231852Sbz goto cleanup; 884231852Sbz } 885231852Sbz LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 886231852Sbz *in6m_sol = imm->i6mm_maddr; 887231852Sbz 888231852Sbz bzero(&mltmask, sizeof(mltmask)); 889231852Sbz mltmask.sin6_len = sizeof(struct sockaddr_in6); 890231852Sbz mltmask.sin6_family = AF_INET6; 891231852Sbz mltmask.sin6_addr = in6mask32; 892231852Sbz#define MLTMASK_LEN 4 /* mltmask's masklen (=32bit=4octet) */ 893231852Sbz 894231852Sbz /* 895231852Sbz * Join link-local all-nodes address. 896231852Sbz */ 897231852Sbz bzero(&mltaddr, sizeof(mltaddr)); 898231852Sbz mltaddr.sin6_len = sizeof(struct sockaddr_in6); 899231852Sbz mltaddr.sin6_family = AF_INET6; 900231852Sbz mltaddr.sin6_addr = in6addr_linklocal_allnodes; 901231852Sbz if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) 902231852Sbz goto cleanup; /* XXX: should not fail */ 903231852Sbz 904231852Sbz /* 905231852Sbz * XXX: do we really need this automatic routes? We should probably 906231852Sbz * reconsider this stuff. Most applications actually do not need the 907231852Sbz * routes, since they usually specify the outgoing interface. 908231852Sbz */ 909231852Sbz rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); 910231852Sbz if (rt != NULL) { 911231852Sbz /* XXX: only works in !SCOPEDROUTING case. */ 912231852Sbz if (memcmp(&mltaddr.sin6_addr, 913231852Sbz &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, 914231852Sbz MLTMASK_LEN)) { 915231852Sbz RTFREE_LOCKED(rt); 916231852Sbz rt = NULL; 917231852Sbz } 918231852Sbz } 919231852Sbz if (rt == NULL) { 920231852Sbz error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, 921231852Sbz (struct sockaddr *)&ia->ia_addr, 922231852Sbz (struct sockaddr *)&mltmask, RTF_UP, 923231852Sbz (struct rtentry **)0, RT_DEFAULT_FIB); 924231852Sbz if (error) 925231852Sbz goto cleanup; 926231852Sbz } else 927231852Sbz RTFREE_LOCKED(rt); 928231852Sbz 929231852Sbz imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0); 930231852Sbz if (imm == NULL) { 931231852Sbz nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " 932231852Sbz "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, 933231852Sbz &mltaddr.sin6_addr), if_name(ifp), error)); 934231852Sbz goto cleanup; 935231852Sbz } 936231852Sbz LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 937231852Sbz 938231852Sbz /* 939231852Sbz * Join node information group address. 940231852Sbz */ 941231852Sbz delay = 0; 942231852Sbz if ((flags & IN6_IFAUPDATE_DADDELAY)) { 943231852Sbz /* 944231852Sbz * The spec does not say anything about delay for this group, 945231852Sbz * but the same logic should apply. 946231852Sbz */ 947231852Sbz delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz); 948231852Sbz } 949231852Sbz if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) { 950231852Sbz /* XXX jinmei */ 951231852Sbz imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay); 952231852Sbz if (imm == NULL) 953231852Sbz nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " 954231852Sbz "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, 955231852Sbz &mltaddr.sin6_addr), if_name(ifp), error)); 956231852Sbz /* XXX not very fatal, go on... */ 957231852Sbz else 958231852Sbz LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 959231852Sbz } 960250251Shrs if (V_icmp6_nodeinfo_oldmcprefix && 961250251Shrs in6_nigroup_oldmcprefix(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) { 962250251Shrs imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay); 963250251Shrs if (imm == NULL) 964250251Shrs nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " 965250251Shrs "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, 966250251Shrs &mltaddr.sin6_addr), if_name(ifp), error)); 967250251Shrs /* XXX not very fatal, go on... */ 968250251Shrs else 969250251Shrs LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 970250251Shrs } 971231852Sbz 972231852Sbz /* 973231852Sbz * Join interface-local all-nodes address. 974231852Sbz * (ff01::1%ifN, and ff01::%ifN/32) 975231852Sbz */ 976231852Sbz mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 977231852Sbz if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) 978231852Sbz goto cleanup; /* XXX: should not fail */ 979231852Sbz /* XXX: again, do we really need the route? */ 980231852Sbz rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); 981231852Sbz if (rt != NULL) { 982231852Sbz if (memcmp(&mltaddr.sin6_addr, 983231852Sbz &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, 984231852Sbz MLTMASK_LEN)) { 985231852Sbz RTFREE_LOCKED(rt); 986231852Sbz rt = NULL; 987231852Sbz } 988231852Sbz } 989231852Sbz if (rt == NULL) { 990231852Sbz error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, 991231852Sbz (struct sockaddr *)&ia->ia_addr, 992231852Sbz (struct sockaddr *)&mltmask, RTF_UP, 993231852Sbz (struct rtentry **)0, RT_DEFAULT_FIB); 994231852Sbz if (error) 995231852Sbz goto cleanup; 996231852Sbz } else 997231852Sbz RTFREE_LOCKED(rt); 998231852Sbz 999231852Sbz imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0); 1000231852Sbz if (imm == NULL) { 1001231852Sbz nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " 1002231852Sbz "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, 1003231852Sbz &mltaddr.sin6_addr), if_name(ifp), error)); 1004231852Sbz goto cleanup; 1005231852Sbz } 1006231852Sbz LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 1007231852Sbz#undef MLTMASK_LEN 1008231852Sbz 1009231852Sbzcleanup: 1010231852Sbz return (error); 1011231852Sbz} 1012231852Sbz 1013231852Sbz/* 101478064Sume * Update parameters of an IPv6 interface address. 101578064Sume * If necessary, a new entry is created and linked into address chains. 101678064Sume * This function is separated from in6_control(). 101778064Sume */ 101878064Sumeint 1019171259Sdelphijin6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, 1020171259Sdelphij struct in6_ifaddr *ia, int flags) 102178064Sume{ 102278064Sume int error = 0, hostIsNew = 0, plen = -1; 102378064Sume struct sockaddr_in6 dst6; 102478064Sume struct in6_addrlifetime *lt; 1025151539Ssuz struct in6_multi *in6m_sol; 1026151539Ssuz int delay; 1027165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 102878064Sume 102978064Sume /* Validate parameters */ 103078064Sume if (ifp == NULL || ifra == NULL) /* this maybe redundant */ 1031120856Sume return (EINVAL); 103278064Sume 103378064Sume /* 103478064Sume * The destination address for a p2p link must have a family 103578064Sume * of AF_UNSPEC or AF_INET6. 103678064Sume */ 103778064Sume if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && 103878064Sume ifra->ifra_dstaddr.sin6_family != AF_INET6 && 103978064Sume ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) 1040120856Sume return (EAFNOSUPPORT); 104178064Sume /* 104278064Sume * validate ifra_prefixmask. don't check sin6_family, netmask 104378064Sume * does not carry fields other than sin6_len. 104478064Sume */ 104578064Sume if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6)) 1046120856Sume return (EINVAL); 104778064Sume /* 104878064Sume * Because the IPv6 address architecture is classless, we require 104978064Sume * users to specify a (non 0) prefix length (mask) for a new address. 105078064Sume * We also require the prefix (when specified) mask is valid, and thus 105178064Sume * reject a non-consecutive mask. 105278064Sume */ 105378064Sume if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0) 1054120856Sume return (EINVAL); 105578064Sume if (ifra->ifra_prefixmask.sin6_len != 0) { 105678064Sume plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 1057120891Sume (u_char *)&ifra->ifra_prefixmask + 1058120891Sume ifra->ifra_prefixmask.sin6_len); 105978064Sume if (plen <= 0) 1060120856Sume return (EINVAL); 1061120891Sume } else { 106262587Sitojun /* 106395023Ssuz * In this case, ia must not be NULL. We just use its prefix 106478064Sume * length. 106562587Sitojun */ 106678064Sume plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 106778064Sume } 106878064Sume /* 106978064Sume * If the destination address on a p2p interface is specified, 107078064Sume * and the address is a scoped one, validate/set the scope 107178064Sume * zone identifier. 107278064Sume */ 107378064Sume dst6 = ifra->ifra_dstaddr; 1074120891Sume if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 && 107578064Sume (dst6.sin6_family == AF_INET6)) { 1076148385Sume struct in6_addr in6_tmp; 1077126552Sume u_int32_t zoneid; 107878064Sume 1079148385Sume in6_tmp = dst6.sin6_addr; 1080148385Sume if (in6_setscope(&in6_tmp, ifp, &zoneid)) 1081148385Sume return (EINVAL); /* XXX: should be impossible */ 1082148385Sume 1083148385Sume if (dst6.sin6_scope_id != 0) { 1084148385Sume if (dst6.sin6_scope_id != zoneid) 1085148385Sume return (EINVAL); 1086148385Sume } else /* user omit to specify the ID. */ 1087126552Sume dst6.sin6_scope_id = zoneid; 1088148385Sume 1089148385Sume /* convert into the internal form */ 1090148385Sume if (sa6_embedscope(&dst6, 0)) 1091148385Sume return (EINVAL); /* XXX: should be impossible */ 109278064Sume } 109378064Sume /* 109478064Sume * The destination address can be specified only for a p2p or a 109578064Sume * loopback interface. If specified, the corresponding prefix length 109678064Sume * must be 128. 109778064Sume */ 109878064Sume if (ifra->ifra_dstaddr.sin6_family == AF_INET6) { 109978064Sume if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) { 1100126552Sume /* XXX: noisy message */ 1101122059Sume nd6log((LOG_INFO, "in6_update_ifa: a destination can " 1102122059Sume "be specified for a p2p or a loopback IF only\n")); 1103120856Sume return (EINVAL); 110478064Sume } 110578064Sume if (plen != 128) { 1106122059Sume nd6log((LOG_INFO, "in6_update_ifa: prefixlen should " 1107122059Sume "be 128 when dstaddr is specified\n")); 1108120856Sume return (EINVAL); 110978064Sume } 111078064Sume } 111178064Sume /* lifetime consistency check */ 111278064Sume lt = &ifra->ifra_lifetime; 1113151539Ssuz if (lt->ia6t_pltime > lt->ia6t_vltime) 1114151539Ssuz return (EINVAL); 111578064Sume if (lt->ia6t_vltime == 0) { 111662587Sitojun /* 111778064Sume * the following log might be noisy, but this is a typical 111878064Sume * configuration mistake or a tool's bug. 111962587Sitojun */ 1120122059Sume nd6log((LOG_INFO, 112178064Sume "in6_update_ifa: valid lifetime is 0 for %s\n", 1122165118Sbz ip6_sprintf(ip6buf, &ifra->ifra_addr.sin6_addr))); 1123151539Ssuz 1124151539Ssuz if (ia == NULL) 1125151539Ssuz return (0); /* there's nothing to do */ 112678064Sume } 112762587Sitojun 112878064Sume /* 112978064Sume * If this is a new address, allocate a new ifaddr and link it 113078064Sume * into chains. 113178064Sume */ 113278064Sume if (ia == NULL) { 113378064Sume hostIsNew = 1; 113479763Sume /* 113579763Sume * When in6_update_ifa() is called in a process of a received 1136120891Sume * RA, it is called under an interrupt context. So, we should 1137120891Sume * call malloc with M_NOWAIT. 113879763Sume */ 1139120891Sume ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR, 1140120891Sume M_NOWAIT); 114178064Sume if (ia == NULL) 114278064Sume return (ENOBUFS); 114378064Sume bzero((caddr_t)ia, sizeof(*ia)); 1144194602Srwatson ifa_init(&ia->ia_ifa); 1145170202Sjinmei LIST_INIT(&ia->ia6_memberships); 1146151539Ssuz /* Initialize the address and masks, and put time stamp */ 114778064Sume ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 114878064Sume ia->ia_addr.sin6_family = AF_INET6; 114978064Sume ia->ia_addr.sin6_len = sizeof(ia->ia_addr); 1150253970Shrs ia->ia6_createtime = time_uptime; 115178064Sume if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { 115278064Sume /* 115378064Sume * XXX: some functions expect that ifa_dstaddr is not 115478064Sume * NULL for p2p interfaces. 115578064Sume */ 1156120891Sume ia->ia_ifa.ifa_dstaddr = 1157120891Sume (struct sockaddr *)&ia->ia_dstaddr; 115878064Sume } else { 115978064Sume ia->ia_ifa.ifa_dstaddr = NULL; 116053541Sshin } 1161108033Shsu ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; 116278064Sume ia->ia_ifp = ifp; 1163194760Srwatson ifa_ref(&ia->ia_ifa); /* if_addrhead */ 1164229621Sjhb IF_ADDR_WLOCK(ifp); 1165191340Srwatson TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); 1166229621Sjhb IF_ADDR_WUNLOCK(ifp); 1167194907Srwatson 1168194971Srwatson ifa_ref(&ia->ia_ifa); /* in6_ifaddrhead */ 1169194971Srwatson IN6_IFADDR_WLOCK(); 1170194907Srwatson TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link); 1171244272Sae LIST_INSERT_HEAD(IN6ADDR_HASH(&ifra->ifra_addr.sin6_addr), 1172244272Sae ia, ia6_hash); 1173194971Srwatson IN6_IFADDR_WUNLOCK(); 117478064Sume } 117578064Sume 1176151539Ssuz /* update timestamp */ 1177253970Shrs ia->ia6_updatetime = time_uptime; 1178151539Ssuz 117978064Sume /* set prefix mask */ 118078064Sume if (ifra->ifra_prefixmask.sin6_len) { 118178064Sume /* 118278064Sume * We prohibit changing the prefix length of an existing 118378064Sume * address, because 118478064Sume * + such an operation should be rare in IPv6, and 118578064Sume * + the operation would confuse prefix management. 118678064Sume */ 118778064Sume if (ia->ia_prefixmask.sin6_len && 118878064Sume in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) { 1189122059Sume nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an" 119078064Sume " existing (%s) address should not be changed\n", 1191165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); 119278064Sume error = EINVAL; 119378064Sume goto unlink; 119453541Sshin } 119578064Sume ia->ia_prefixmask = ifra->ifra_prefixmask; 1196250815Smelifaro ia->ia_prefixmask.sin6_family = AF_INET6; 119778064Sume } 119878064Sume 119978064Sume /* 120078064Sume * If a new destination address is specified, scrub the old one and 120178064Sume * install the new destination. Note that the interface must be 1202120891Sume * p2p or loopback (see the check above.) 120378064Sume */ 120478064Sume if (dst6.sin6_family == AF_INET6 && 1205120891Sume !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) { 120678064Sume int e; 120778064Sume 120878064Sume if ((ia->ia_flags & IFA_ROUTE) != 0 && 1209120891Sume (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) { 1210122059Sume nd6log((LOG_ERR, "in6_update_ifa: failed to remove " 121178064Sume "a route to the old destination: %s\n", 1212165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); 121378064Sume /* proceed anyway... */ 1214120891Sume } else 121578064Sume ia->ia_flags &= ~IFA_ROUTE; 121678064Sume ia->ia_dstaddr = dst6; 121778064Sume } 121853541Sshin 1219148385Sume /* 1220148385Sume * Set lifetimes. We do not refer to ia6t_expire and ia6t_preferred 1221148385Sume * to see if the address is deprecated or invalidated, but initialize 1222148385Sume * these members for applications. 1223148385Sume */ 1224148385Sume ia->ia6_lifetime = ifra->ifra_lifetime; 1225148385Sume if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 1226148385Sume ia->ia6_lifetime.ia6t_expire = 1227253970Shrs time_uptime + ia->ia6_lifetime.ia6t_vltime; 1228148385Sume } else 1229148385Sume ia->ia6_lifetime.ia6t_expire = 0; 1230148385Sume if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 1231148385Sume ia->ia6_lifetime.ia6t_preferred = 1232253970Shrs time_uptime + ia->ia6_lifetime.ia6t_pltime; 1233148385Sume } else 1234148385Sume ia->ia6_lifetime.ia6t_preferred = 0; 1235148385Sume 123678064Sume /* reset the interface and routing table appropriately. */ 123778064Sume if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) 123878064Sume goto unlink; 123978064Sume 124078064Sume /* 1241148385Sume * configure address flags. 1242148385Sume */ 1243148385Sume ia->ia6_flags = ifra->ifra_flags; 1244148385Sume /* 1245148385Sume * backward compatibility - if IN6_IFF_DEPRECATED is set from the 1246148385Sume * userland, make it deprecated. 1247148385Sume */ 1248148385Sume if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) { 1249148385Sume ia->ia6_lifetime.ia6t_pltime = 0; 1250253970Shrs ia->ia6_lifetime.ia6t_preferred = time_uptime; 1251148385Sume } 1252148385Sume /* 1253151539Ssuz * Make the address tentative before joining multicast addresses, 1254151539Ssuz * so that corresponding MLD responses would not have a tentative 1255151539Ssuz * source address. 1256148385Sume */ 1257151539Ssuz ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /* safety */ 1258151539Ssuz if (hostIsNew && in6if_do_dad(ifp)) 1259148385Sume ia->ia6_flags |= IN6_IFF_TENTATIVE; 1260148385Sume 1261197138Shrs /* DAD should be performed after ND6_IFF_IFDISABLED is cleared. */ 1262197138Shrs if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) 1263197138Shrs ia->ia6_flags |= IN6_IFF_TENTATIVE; 1264197138Shrs 1265148385Sume /* 1266148385Sume * We are done if we have simply modified an existing address. 1267148385Sume */ 1268148385Sume if (!hostIsNew) 1269148385Sume return (error); 1270148385Sume 1271148385Sume /* 127278064Sume * Beyond this point, we should call in6_purgeaddr upon an error, 1273120891Sume * not just go to unlink. 127478064Sume */ 127578064Sume 1276231852Sbz /* Join necessary multicast groups. */ 1277151539Ssuz in6m_sol = NULL; 127878064Sume if ((ifp->if_flags & IFF_MULTICAST) != 0) { 1279231852Sbz error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol); 1280231852Sbz if (error) 1281148385Sume goto cleanup; 128278064Sume } 128353541Sshin 1284151539Ssuz /* 1285151539Ssuz * Perform DAD, if needed. 1286231852Sbz * XXX It may be of use, if we can administratively disable DAD. 1287151539Ssuz */ 1288194760Srwatson if (in6if_do_dad(ifp) && ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) && 1289151539Ssuz (ia->ia6_flags & IN6_IFF_TENTATIVE)) 1290151539Ssuz { 1291151539Ssuz int mindelay, maxdelay; 1292151539Ssuz 1293151539Ssuz delay = 0; 1294151539Ssuz if ((flags & IN6_IFAUPDATE_DADDELAY)) { 1295151539Ssuz /* 1296151539Ssuz * We need to impose a delay before sending an NS 1297151539Ssuz * for DAD. Check if we also needed a delay for the 1298151539Ssuz * corresponding MLD message. If we did, the delay 1299151539Ssuz * should be larger than the MLD delay (this could be 1300151539Ssuz * relaxed a bit, but this simple logic is at least 1301151539Ssuz * safe). 1302191672Sbms * XXX: Break data hiding guidelines and look at 1303191672Sbms * state for the solicited multicast group. 1304151539Ssuz */ 1305151539Ssuz mindelay = 0; 1306151539Ssuz if (in6m_sol != NULL && 1307191672Sbms in6m_sol->in6m_state == MLD_REPORTING_MEMBER) { 1308151539Ssuz mindelay = in6m_sol->in6m_timer; 1309151539Ssuz } 1310151539Ssuz maxdelay = MAX_RTR_SOLICITATION_DELAY * hz; 1311151539Ssuz if (maxdelay - mindelay == 0) 1312151539Ssuz delay = 0; 1313151539Ssuz else { 1314151539Ssuz delay = 1315151539Ssuz (arc4random() % (maxdelay - mindelay)) + 1316151539Ssuz mindelay; 1317151539Ssuz } 1318151539Ssuz } 1319151539Ssuz nd6_dad_start((struct ifaddr *)ia, delay); 1320151539Ssuz } 1321151539Ssuz 1322194760Srwatson KASSERT(hostIsNew, ("in6_update_ifa: !hostIsNew")); 1323194760Srwatson ifa_free(&ia->ia_ifa); 1324120856Sume return (error); 132578064Sume 132678064Sume unlink: 132778064Sume /* 132878064Sume * XXX: if a change of an existing address failed, keep the entry 132978064Sume * anyway. 133078064Sume */ 1331194760Srwatson if (hostIsNew) { 1332194943Srwatson in6_unlink_ifa(ia, ifp); 1333194760Srwatson ifa_free(&ia->ia_ifa); 1334194760Srwatson } 1335120856Sume return (error); 1336148385Sume 1337148385Sume cleanup: 1338194760Srwatson KASSERT(hostIsNew, ("in6_update_ifa: cleanup: !hostIsNew")); 1339194760Srwatson ifa_free(&ia->ia_ifa); 1340148385Sume in6_purgeaddr(&ia->ia_ifa); 1341148385Sume return error; 134253541Sshin} 134353541Sshin 1344231852Sbz/* 1345231852Sbz * Leave multicast groups. Factored out from in6_purgeaddr(). 1346231852Sbz * This entire work should only be done once, for the default FIB. 1347231852Sbz */ 1348231852Sbzstatic int 1349231852Sbzin6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0) 135062587Sitojun{ 1351231852Sbz struct sockaddr_in6 mltaddr, mltmask; 1352170202Sjinmei struct in6_multi_mship *imm; 1353192282Sqingli struct rtentry *rt; 1354237571Sdelphij struct sockaddr_in6 sin6; 1355231852Sbz int error; 135662587Sitojun 1357192282Sqingli /* 1358231852Sbz * Leave from multicast groups we have joined for the interface. 1359192282Sqingli */ 1360228966Sjhb while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { 1361170202Sjinmei LIST_REMOVE(imm, i6mm_chain); 1362170202Sjinmei in6_leavegroup(imm); 136362587Sitojun } 136462587Sitojun 1365192282Sqingli /* 1366231852Sbz * Remove the link-local all-nodes address. 1367192282Sqingli */ 1368192282Sqingli bzero(&mltmask, sizeof(mltmask)); 1369192282Sqingli mltmask.sin6_len = sizeof(struct sockaddr_in6); 1370192282Sqingli mltmask.sin6_family = AF_INET6; 1371192282Sqingli mltmask.sin6_addr = in6mask32; 1372192282Sqingli 1373192282Sqingli bzero(&mltaddr, sizeof(mltaddr)); 1374192282Sqingli mltaddr.sin6_len = sizeof(struct sockaddr_in6); 1375192282Sqingli mltaddr.sin6_family = AF_INET6; 1376192282Sqingli mltaddr.sin6_addr = in6addr_linklocal_allnodes; 1377192282Sqingli 1378230494Sbz if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) 1379231852Sbz return (error); 1380192282Sqingli 1381237571Sdelphij /* 1382237571Sdelphij * As for the mltaddr above, proactively prepare the sin6 to avoid 1383237571Sdelphij * rtentry un- and re-locking. 1384237571Sdelphij */ 1385237571Sdelphij if (ifa0 != NULL) { 1386237571Sdelphij bzero(&sin6, sizeof(sin6)); 1387237571Sdelphij sin6.sin6_len = sizeof(sin6); 1388237571Sdelphij sin6.sin6_family = AF_INET6; 1389238945Sglebius memcpy(&sin6.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr, 1390237571Sdelphij sizeof(sin6.sin6_addr)); 1391238222Sbz error = in6_setscope(&sin6.sin6_addr, ifa0->ifa_ifp, NULL); 1392238222Sbz if (error != 0) 1393238222Sbz return (error); 1394237571Sdelphij } 1395237571Sdelphij 1396231852Sbz rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); 1397192282Sqingli if (rt != NULL && rt->rt_gateway != NULL && 1398238945Sglebius (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 1399192282Sqingli &ia->ia_addr.sin6_addr, 1400192282Sqingli sizeof(ia->ia_addr.sin6_addr)) == 0)) { 1401238945Sglebius /* 1402231852Sbz * If no more IPv6 address exists on this interface then 1403231852Sbz * remove the multicast address route. 1404192282Sqingli */ 1405192282Sqingli if (ifa0 == NULL) { 1406238945Sglebius memcpy(&mltaddr.sin6_addr, 1407238945Sglebius &satosin6(rt_key(rt))->sin6_addr, 1408238945Sglebius sizeof(mltaddr.sin6_addr)); 1409192282Sqingli RTFREE_LOCKED(rt); 1410231852Sbz error = in6_rtrequest(RTM_DELETE, 1411231852Sbz (struct sockaddr *)&mltaddr, 1412231852Sbz (struct sockaddr *)&ia->ia_addr, 1413231852Sbz (struct sockaddr *)&mltmask, RTF_UP, 1414231852Sbz (struct rtentry **)0, RT_DEFAULT_FIB); 1415192282Sqingli if (error) 1416231852Sbz log(LOG_INFO, "%s: link-local all-nodes " 1417231852Sbz "multicast address deletion error\n", 1418231852Sbz __func__); 1419192282Sqingli } else { 1420192282Sqingli /* 1421231852Sbz * Replace the gateway of the route. 1422192282Sqingli */ 1423237571Sdelphij memcpy(rt->rt_gateway, &sin6, sizeof(sin6)); 1424192282Sqingli RTFREE_LOCKED(rt); 1425192282Sqingli } 1426192282Sqingli } else { 1427192282Sqingli if (rt != NULL) 1428192282Sqingli RTFREE_LOCKED(rt); 1429192282Sqingli } 1430192282Sqingli 1431192282Sqingli /* 1432231852Sbz * Remove the node-local all-nodes address. 1433192282Sqingli */ 1434192282Sqingli mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 1435231852Sbz if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) 1436231852Sbz return (error); 1437192282Sqingli 1438231852Sbz rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); 1439192282Sqingli if (rt != NULL && rt->rt_gateway != NULL && 1440238945Sglebius (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 1441192282Sqingli &ia->ia_addr.sin6_addr, 1442192282Sqingli sizeof(ia->ia_addr.sin6_addr)) == 0)) { 1443238945Sglebius /* 1444231852Sbz * If no more IPv6 address exists on this interface then 1445231852Sbz * remove the multicast address route. 1446192282Sqingli */ 1447192282Sqingli if (ifa0 == NULL) { 1448238945Sglebius memcpy(&mltaddr.sin6_addr, 1449238945Sglebius &satosin6(rt_key(rt))->sin6_addr, 1450238945Sglebius sizeof(mltaddr.sin6_addr)); 1451192282Sqingli 1452192282Sqingli RTFREE_LOCKED(rt); 1453231852Sbz error = in6_rtrequest(RTM_DELETE, 1454231852Sbz (struct sockaddr *)&mltaddr, 1455231852Sbz (struct sockaddr *)&ia->ia_addr, 1456231852Sbz (struct sockaddr *)&mltmask, RTF_UP, 1457231852Sbz (struct rtentry **)0, RT_DEFAULT_FIB); 1458192282Sqingli if (error) 1459231852Sbz log(LOG_INFO, "%s: node-local all-nodes" 1460231852Sbz "multicast address deletion error\n", 1461231852Sbz __func__); 1462192282Sqingli } else { 1463192282Sqingli /* 1464231852Sbz * Replace the gateway of the route. 1465192282Sqingli */ 1466237571Sdelphij memcpy(rt->rt_gateway, &sin6, sizeof(sin6)); 1467192282Sqingli RTFREE_LOCKED(rt); 1468192282Sqingli } 1469192282Sqingli } else { 1470192282Sqingli if (rt != NULL) 1471192282Sqingli RTFREE_LOCKED(rt); 1472192282Sqingli } 1473192282Sqingli 1474231852Sbz return (0); 1475231852Sbz} 1476231852Sbz 1477231852Sbzvoid 1478231852Sbzin6_purgeaddr(struct ifaddr *ifa) 1479231852Sbz{ 1480231852Sbz struct ifnet *ifp = ifa->ifa_ifp; 1481231852Sbz struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; 1482231852Sbz int plen, error; 1483231852Sbz struct ifaddr *ifa0; 1484231852Sbz 1485231852Sbz if (ifa->ifa_carp) 1486231852Sbz (*carp_detach_p)(ifa); 1487231852Sbz 1488231852Sbz /* 1489231852Sbz * find another IPv6 address as the gateway for the 1490231852Sbz * link-local and node-local all-nodes multicast 1491231852Sbz * address routes 1492231852Sbz */ 1493231852Sbz IF_ADDR_RLOCK(ifp); 1494231852Sbz TAILQ_FOREACH(ifa0, &ifp->if_addrhead, ifa_link) { 1495231852Sbz if ((ifa0->ifa_addr->sa_family != AF_INET6) || 1496231852Sbz memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr, 1497238945Sglebius &ia->ia_addr.sin6_addr, sizeof(struct in6_addr)) == 0) 1498231852Sbz continue; 1499231852Sbz else 1500231852Sbz break; 1501231852Sbz } 1502230506Sbz if (ifa0 != NULL) 1503231852Sbz ifa_ref(ifa0); 1504231852Sbz IF_ADDR_RUNLOCK(ifp); 1505231852Sbz 1506231852Sbz /* 1507231852Sbz * Remove the loopback route to the interface address. 1508238945Sglebius * The check for the current setting of "nd6_useloopback" 1509231852Sbz * is not needed. 1510231852Sbz */ 1511231852Sbz if (ia->ia_flags & IFA_RTSELF) { 1512231852Sbz error = ifa_del_loopback_route((struct ifaddr *)ia, 1513238945Sglebius (struct sockaddr *)&ia->ia_addr); 1514231852Sbz if (error == 0) 1515231852Sbz ia->ia_flags &= ~IFA_RTSELF; 1516231852Sbz } 1517231852Sbz 1518231852Sbz /* stop DAD processing */ 1519231852Sbz nd6_dad_stop(ifa); 1520231852Sbz 1521231852Sbz /* Remove local address entry from lltable. */ 1522231852Sbz in6_ifremloop(ifa); 1523231852Sbz 1524231852Sbz /* Leave multicast groups. */ 1525231852Sbz error = in6_purgeaddr_mc(ifp, ia, ifa0); 1526231852Sbz 1527231852Sbz if (ifa0 != NULL) 1528230506Sbz ifa_free(ifa0); 1529192282Sqingli 1530192282Sqingli plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ 1531192282Sqingli if ((ia->ia_flags & IFA_ROUTE) && plen == 128) { 1532231852Sbz error = rtinit(&(ia->ia_ifa), RTM_DELETE, ia->ia_flags | 1533231852Sbz (ia->ia_dstaddr.sin6_family == AF_INET6) ? RTF_HOST : 0); 1534192282Sqingli if (error != 0) 1535231852Sbz log(LOG_INFO, "%s: err=%d, destination address delete " 1536231852Sbz "failed\n", __func__, error); 1537192282Sqingli ia->ia_flags &= ~IFA_ROUTE; 1538192282Sqingli } 1539192282Sqingli 154078064Sume in6_unlink_ifa(ia, ifp); 154178064Sume} 154278064Sume 154378064Sumestatic void 1544171259Sdelphijin6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) 154578064Sume{ 154678064Sume 1547229621Sjhb IF_ADDR_WLOCK(ifp); 1548191340Srwatson TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); 1549229621Sjhb IF_ADDR_WUNLOCK(ifp); 1550194760Srwatson ifa_free(&ia->ia_ifa); /* if_addrhead */ 155162587Sitojun 1552195102Srwatson /* 1553195102Srwatson * Defer the release of what might be the last reference to the 1554195102Srwatson * in6_ifaddr so that it can't be freed before the remainder of the 1555195102Srwatson * cleanup. 1556195102Srwatson */ 1557194971Srwatson IN6_IFADDR_WLOCK(); 1558194907Srwatson TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link); 1559244272Sae LIST_REMOVE(ia, ia6_hash); 1560194971Srwatson IN6_IFADDR_WUNLOCK(); 156162587Sitojun 156262587Sitojun /* 1563151915Ssuz * Release the reference to the base prefix. There should be a 1564151915Ssuz * positive reference. 156562587Sitojun */ 1566194907Srwatson if (ia->ia6_ndpr == NULL) { 1567151915Ssuz nd6log((LOG_NOTICE, 1568151915Ssuz "in6_unlink_ifa: autoconf'ed address " 1569194907Srwatson "%p has no prefix\n", ia)); 1570151915Ssuz } else { 1571194907Srwatson ia->ia6_ndpr->ndpr_refcnt--; 1572194907Srwatson ia->ia6_ndpr = NULL; 1573151915Ssuz } 157462587Sitojun 1575151915Ssuz /* 1576151915Ssuz * Also, if the address being removed is autoconf'ed, call 1577151915Ssuz * pfxlist_onlink_check() since the release might affect the status of 1578171260Sdelphij * other (detached) addresses. 1579151915Ssuz */ 1580194907Srwatson if ((ia->ia6_flags & IN6_IFF_AUTOCONF)) { 158178064Sume pfxlist_onlink_check(); 158262587Sitojun } 1583195102Srwatson ifa_free(&ia->ia_ifa); /* in6_ifaddrhead */ 158462587Sitojun} 158562587Sitojun 158678064Sumevoid 1587171259Sdelphijin6_purgeif(struct ifnet *ifp) 158878064Sume{ 158978064Sume struct ifaddr *ifa, *nifa; 159078064Sume 1591191340Srwatson TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { 159278064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 159378064Sume continue; 159478064Sume in6_purgeaddr(ifa); 159578064Sume } 159678064Sume 159778064Sume in6_ifdetach(ifp); 159878064Sume} 159978064Sume 160053541Sshin/* 160153541Sshin * SIOC[GAD]LIFADDR. 160262744Sgrog * SIOCGLIFADDR: get first address. (?) 160353541Sshin * SIOCGLIFADDR with IFLR_PREFIX: 160453541Sshin * get first address that matches the specified prefix. 160553541Sshin * SIOCALIFADDR: add the specified address. 160653541Sshin * SIOCALIFADDR with IFLR_PREFIX: 160753541Sshin * add the specified prefix, filling hostid part from 160853541Sshin * the first link-local address. prefixlen must be <= 64. 160953541Sshin * SIOCDLIFADDR: delete the specified address. 161053541Sshin * SIOCDLIFADDR with IFLR_PREFIX: 161153541Sshin * delete the first address that matches the specified prefix. 161253541Sshin * return values: 161353541Sshin * EINVAL on invalid parameters 161453541Sshin * EADDRNOTAVAIL on prefix match failed/specified address not found 161553541Sshin * other values may be returned from in6_ioctl() 161653541Sshin * 161753541Sshin * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64. 161853541Sshin * this is to accomodate address naming scheme other than RFC2374, 161953541Sshin * in the future. 162053541Sshin * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374 162153541Sshin * address encoding scheme. (see figure on page 8) 162253541Sshin */ 162353541Sshinstatic int 1624171259Sdelphijin6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data, 1625171259Sdelphij struct ifnet *ifp, struct thread *td) 162653541Sshin{ 162753541Sshin struct if_laddrreq *iflr = (struct if_laddrreq *)data; 162853541Sshin struct ifaddr *ifa; 162962587Sitojun struct sockaddr *sa; 163053541Sshin 163153541Sshin /* sanity checks */ 163253541Sshin if (!data || !ifp) { 163353541Sshin panic("invalid argument to in6_lifaddr_ioctl"); 1634120891Sume /* NOTREACHED */ 163553541Sshin } 163653541Sshin 163753541Sshin switch (cmd) { 163853541Sshin case SIOCGLIFADDR: 163953541Sshin /* address must be specified on GET with IFLR_PREFIX */ 164053541Sshin if ((iflr->flags & IFLR_PREFIX) == 0) 164153541Sshin break; 164295023Ssuz /* FALLTHROUGH */ 164353541Sshin case SIOCALIFADDR: 164453541Sshin case SIOCDLIFADDR: 164553541Sshin /* address must be specified on ADD and DELETE */ 164662587Sitojun sa = (struct sockaddr *)&iflr->addr; 164762587Sitojun if (sa->sa_family != AF_INET6) 164853541Sshin return EINVAL; 164962587Sitojun if (sa->sa_len != sizeof(struct sockaddr_in6)) 165053541Sshin return EINVAL; 165153541Sshin /* XXX need improvement */ 165262587Sitojun sa = (struct sockaddr *)&iflr->dstaddr; 165362587Sitojun if (sa->sa_family && sa->sa_family != AF_INET6) 165453541Sshin return EINVAL; 165562587Sitojun if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6)) 165653541Sshin return EINVAL; 165753541Sshin break; 165895023Ssuz default: /* shouldn't happen */ 165962587Sitojun#if 0 166062587Sitojun panic("invalid cmd to in6_lifaddr_ioctl"); 166195023Ssuz /* NOTREACHED */ 166262587Sitojun#else 166353541Sshin return EOPNOTSUPP; 166462587Sitojun#endif 166553541Sshin } 166653541Sshin if (sizeof(struct in6_addr) * 8 < iflr->prefixlen) 166753541Sshin return EINVAL; 166853541Sshin 166953541Sshin switch (cmd) { 167053541Sshin case SIOCALIFADDR: 167153541Sshin { 167253541Sshin struct in6_aliasreq ifra; 167353541Sshin struct in6_addr *hostid = NULL; 167453541Sshin int prefixlen; 167553541Sshin 1676194760Srwatson ifa = NULL; 167753541Sshin if ((iflr->flags & IFLR_PREFIX) != 0) { 167853541Sshin struct sockaddr_in6 *sin6; 167953541Sshin 168053541Sshin /* 168153541Sshin * hostid is to fill in the hostid part of the 168253541Sshin * address. hostid points to the first link-local 168353541Sshin * address attached to the interface. 168453541Sshin */ 168562587Sitojun ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); 168653541Sshin if (!ifa) 168753541Sshin return EADDRNOTAVAIL; 168853541Sshin hostid = IFA_IN6(ifa); 168953541Sshin 1690171260Sdelphij /* prefixlen must be <= 64. */ 1691236615Sbz if (64 < iflr->prefixlen) { 1692236615Sbz if (ifa != NULL) 1693236615Sbz ifa_free(ifa); 169453541Sshin return EINVAL; 1695236615Sbz } 169653541Sshin prefixlen = iflr->prefixlen; 169753541Sshin 169853541Sshin /* hostid part must be zero. */ 169953541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 1700126552Sume if (sin6->sin6_addr.s6_addr32[2] != 0 || 1701126552Sume sin6->sin6_addr.s6_addr32[3] != 0) { 1702236615Sbz if (ifa != NULL) 1703236615Sbz ifa_free(ifa); 170453541Sshin return EINVAL; 170553541Sshin } 170653541Sshin } else 170753541Sshin prefixlen = iflr->prefixlen; 170853541Sshin 170953541Sshin /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 171053541Sshin bzero(&ifra, sizeof(ifra)); 1711120891Sume bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name)); 171253541Sshin 171362587Sitojun bcopy(&iflr->addr, &ifra.ifra_addr, 1714120891Sume ((struct sockaddr *)&iflr->addr)->sa_len); 171553541Sshin if (hostid) { 171653541Sshin /* fill in hostid part */ 171753541Sshin ifra.ifra_addr.sin6_addr.s6_addr32[2] = 1718120891Sume hostid->s6_addr32[2]; 171953541Sshin ifra.ifra_addr.sin6_addr.s6_addr32[3] = 1720120891Sume hostid->s6_addr32[3]; 172153541Sshin } 172253541Sshin 1723120891Sume if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */ 172453541Sshin bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 1725120891Sume ((struct sockaddr *)&iflr->dstaddr)->sa_len); 172653541Sshin if (hostid) { 172753541Sshin ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] = 1728120891Sume hostid->s6_addr32[2]; 172953541Sshin ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = 1730120891Sume hostid->s6_addr32[3]; 173153541Sshin } 173253541Sshin } 1733194760Srwatson if (ifa != NULL) 1734194760Srwatson ifa_free(ifa); 173553541Sshin 173653541Sshin ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 1737121168Sume in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); 173853541Sshin 173953541Sshin ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; 174083366Sjulian return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, td); 174153541Sshin } 174253541Sshin case SIOCGLIFADDR: 174353541Sshin case SIOCDLIFADDR: 174453541Sshin { 174553541Sshin struct in6_ifaddr *ia; 174653541Sshin struct in6_addr mask, candidate, match; 174753541Sshin struct sockaddr_in6 *sin6; 174853541Sshin int cmp; 174953541Sshin 175053541Sshin bzero(&mask, sizeof(mask)); 175153541Sshin if (iflr->flags & IFLR_PREFIX) { 175253541Sshin /* lookup a prefix rather than address. */ 1753121168Sume in6_prefixlen2mask(&mask, iflr->prefixlen); 175453541Sshin 175553541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 175653541Sshin bcopy(&sin6->sin6_addr, &match, sizeof(match)); 175753541Sshin match.s6_addr32[0] &= mask.s6_addr32[0]; 175853541Sshin match.s6_addr32[1] &= mask.s6_addr32[1]; 175953541Sshin match.s6_addr32[2] &= mask.s6_addr32[2]; 176053541Sshin match.s6_addr32[3] &= mask.s6_addr32[3]; 176153541Sshin 176253541Sshin /* if you set extra bits, that's wrong */ 176353541Sshin if (bcmp(&match, &sin6->sin6_addr, sizeof(match))) 176453541Sshin return EINVAL; 176553541Sshin 176653541Sshin cmp = 1; 176753541Sshin } else { 176853541Sshin if (cmd == SIOCGLIFADDR) { 176953541Sshin /* on getting an address, take the 1st match */ 177095023Ssuz cmp = 0; /* XXX */ 177153541Sshin } else { 177253541Sshin /* on deleting an address, do exact match */ 1773121168Sume in6_prefixlen2mask(&mask, 128); 177453541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 177553541Sshin bcopy(&sin6->sin6_addr, &match, sizeof(match)); 177653541Sshin 177753541Sshin cmp = 1; 177853541Sshin } 177953541Sshin } 178053541Sshin 1781229621Sjhb IF_ADDR_RLOCK(ifp); 1782191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 178353541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 178453541Sshin continue; 178553541Sshin if (!cmp) 178653541Sshin break; 178778064Sume 178878064Sume /* 178978064Sume * XXX: this is adhoc, but is necessary to allow 179078064Sume * a user to specify fe80::/64 (not /10) for a 179178064Sume * link-local address. 179278064Sume */ 1793148385Sume bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate)); 1794148385Sume in6_clearscope(&candidate); 179553541Sshin candidate.s6_addr32[0] &= mask.s6_addr32[0]; 179653541Sshin candidate.s6_addr32[1] &= mask.s6_addr32[1]; 179753541Sshin candidate.s6_addr32[2] &= mask.s6_addr32[2]; 179853541Sshin candidate.s6_addr32[3] &= mask.s6_addr32[3]; 179953541Sshin if (IN6_ARE_ADDR_EQUAL(&candidate, &match)) 180053541Sshin break; 180153541Sshin } 1802229414Sjhb if (ifa != NULL) 1803229414Sjhb ifa_ref(ifa); 1804229621Sjhb IF_ADDR_RUNLOCK(ifp); 180553541Sshin if (!ifa) 180653541Sshin return EADDRNOTAVAIL; 180753541Sshin ia = ifa2ia6(ifa); 180853541Sshin 180953541Sshin if (cmd == SIOCGLIFADDR) { 1810148385Sume int error; 181178064Sume 181253541Sshin /* fill in the if_laddrreq structure */ 181353541Sshin bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len); 1814148385Sume error = sa6_recoverscope( 1815148385Sume (struct sockaddr_in6 *)&iflr->addr); 1816229414Sjhb if (error != 0) { 1817229414Sjhb ifa_free(ifa); 1818148385Sume return (error); 1819229414Sjhb } 1820148385Sume 182153541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 182253541Sshin bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 1823120891Sume ia->ia_dstaddr.sin6_len); 1824148385Sume error = sa6_recoverscope( 1825148385Sume (struct sockaddr_in6 *)&iflr->dstaddr); 1826229414Sjhb if (error != 0) { 1827229414Sjhb ifa_free(ifa); 1828148385Sume return (error); 1829229414Sjhb } 183053541Sshin } else 183153541Sshin bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 183253541Sshin 183353541Sshin iflr->prefixlen = 1834120891Sume in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 183553541Sshin 183695023Ssuz iflr->flags = ia->ia6_flags; /* XXX */ 1837229414Sjhb ifa_free(ifa); 183853541Sshin 183953541Sshin return 0; 184053541Sshin } else { 184153541Sshin struct in6_aliasreq ifra; 184253541Sshin 184353541Sshin /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 184453541Sshin bzero(&ifra, sizeof(ifra)); 184553541Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 1846120891Sume sizeof(ifra.ifra_name)); 184753541Sshin 184853541Sshin bcopy(&ia->ia_addr, &ifra.ifra_addr, 1849120891Sume ia->ia_addr.sin6_len); 185053541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 185153541Sshin bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 1852120891Sume ia->ia_dstaddr.sin6_len); 185362587Sitojun } else { 185462587Sitojun bzero(&ifra.ifra_dstaddr, 185562587Sitojun sizeof(ifra.ifra_dstaddr)); 185653541Sshin } 185753541Sshin bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr, 1858120891Sume ia->ia_prefixmask.sin6_len); 185953541Sshin 186053541Sshin ifra.ifra_flags = ia->ia6_flags; 1861229414Sjhb ifa_free(ifa); 186253541Sshin return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, 1863120891Sume ifp, td); 186453541Sshin } 186553541Sshin } 186653541Sshin } 186753541Sshin 186895023Ssuz return EOPNOTSUPP; /* just for safety */ 186953541Sshin} 187053541Sshin 187153541Sshin/* 1872231852Sbz * Initialize an interface's IPv6 address and routing table entry. 187353541Sshin */ 187478064Sumestatic int 1875171259Sdelphijin6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, 1876171259Sdelphij struct sockaddr_in6 *sin6, int newhost) 187753541Sshin{ 187878064Sume int error = 0, plen, ifacount = 0; 187978064Sume struct ifaddr *ifa; 188053541Sshin 188153541Sshin /* 188253541Sshin * Give the interface a chance to initialize 188353541Sshin * if this is its first address, 188453541Sshin * and to validate the address if necessary. 188553541Sshin */ 1886229621Sjhb IF_ADDR_RLOCK(ifp); 1887191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 188878064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 188978064Sume continue; 189078064Sume ifacount++; 189178064Sume } 1892229621Sjhb IF_ADDR_RUNLOCK(ifp); 189378064Sume 189478064Sume ia->ia_addr = *sin6; 189578064Sume 1896146883Siedowse if (ifacount <= 1 && ifp->if_ioctl) { 1897146883Siedowse error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); 1898241686Sandre if (error) 1899146883Siedowse return (error); 190053541Sshin } 190153541Sshin 190278064Sume ia->ia_ifa.ifa_metric = ifp->if_metric; 190353541Sshin 190478064Sume /* we could do in(6)_socktrim here, but just omit it at this moment. */ 190578064Sume 190653541Sshin /* 190778064Sume * Special case: 1908124337Sume * If a new destination address is specified for a point-to-point 190978064Sume * interface, install a route to the destination as an interface 1910238945Sglebius * direct route. 1911124337Sume * XXX: the logic below rejects assigning multiple addresses on a p2p 1912159390Sgnn * interface that share the same destination. 191353541Sshin */ 191478064Sume plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ 1915196152Sqingli if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 && 1916196152Sqingli ia->ia_dstaddr.sin6_family == AF_INET6) { 1917159390Sgnn int rtflags = RTF_UP | RTF_HOST; 1918231852Sbz error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags); 1919231852Sbz if (error) 1920120856Sume return (error); 192178064Sume ia->ia_flags |= IFA_ROUTE; 1922226453Sqingli /* 1923226453Sqingli * Handle the case for ::1 . 1924226453Sqingli */ 1925226453Sqingli if (ifp->if_flags & IFF_LOOPBACK) 1926226453Sqingli ia->ia_flags |= IFA_RTSELF; 192753541Sshin } 192853541Sshin 1929195643Sqingli /* 1930195643Sqingli * add a loopback route to self 1931195643Sqingli */ 1932226453Sqingli if (!(ia->ia_flags & IFA_RTSELF) && V_nd6_useloopback) { 1933197227Sqingli error = ifa_add_loopback_route((struct ifaddr *)ia, 1934238945Sglebius (struct sockaddr *)&ia->ia_addr); 1935201282Sqingli if (error == 0) 1936201282Sqingli ia->ia_flags |= IFA_RTSELF; 1937195643Sqingli } 1938195643Sqingli 1939231852Sbz /* Add local address to lltable, if necessary (ex. on p2p link). */ 1940226338Sglebius if (newhost) 1941226338Sglebius in6_ifaddloop(&(ia->ia_ifa)); 194253541Sshin 1943120856Sume return (error); 194453541Sshin} 194553541Sshin 194653541Sshin/* 194753541Sshin * Find an IPv6 interface link-local address specific to an interface. 1948194760Srwatson * ifaddr is returned referenced. 194953541Sshin */ 195053541Sshinstruct in6_ifaddr * 1951171259Sdelphijin6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags) 195253541Sshin{ 195378064Sume struct ifaddr *ifa; 195453541Sshin 1955229621Sjhb IF_ADDR_RLOCK(ifp); 1956191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 195753541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 195853541Sshin continue; 195962587Sitojun if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { 196062587Sitojun if ((((struct in6_ifaddr *)ifa)->ia6_flags & 1961238945Sglebius ignoreflags) != 0) 196262587Sitojun continue; 1963194760Srwatson ifa_ref(ifa); 196453541Sshin break; 196562587Sitojun } 196653541Sshin } 1967229621Sjhb IF_ADDR_RUNLOCK(ifp); 196853541Sshin 1969120856Sume return ((struct in6_ifaddr *)ifa); 197053541Sshin} 197153541Sshin 197253541Sshin 197353541Sshin/* 197453541Sshin * find the internet address corresponding to a given interface and address. 1975194760Srwatson * ifaddr is returned referenced. 197653541Sshin */ 197753541Sshinstruct in6_ifaddr * 1978171259Sdelphijin6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr) 197953541Sshin{ 198078064Sume struct ifaddr *ifa; 198153541Sshin 1982229621Sjhb IF_ADDR_RLOCK(ifp); 1983191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 198453541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 198553541Sshin continue; 1986194760Srwatson if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) { 1987194760Srwatson ifa_ref(ifa); 198853541Sshin break; 1989194760Srwatson } 199053541Sshin } 1991229621Sjhb IF_ADDR_RUNLOCK(ifp); 199253541Sshin 1993120856Sume return ((struct in6_ifaddr *)ifa); 199453541Sshin} 199553541Sshin 199653541Sshin/* 1997252511Shrs * Find a link-local scoped address on ifp and return it if any. 1998252511Shrs */ 1999252511Shrsstruct in6_ifaddr * 2000252511Shrsin6ifa_llaonifp(struct ifnet *ifp) 2001252511Shrs{ 2002252511Shrs struct sockaddr_in6 *sin6; 2003252511Shrs struct ifaddr *ifa; 2004252511Shrs 2005252511Shrs if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) 2006252511Shrs return (NULL); 2007252511Shrs if_addr_rlock(ifp); 2008252511Shrs TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 2009252511Shrs if (ifa->ifa_addr->sa_family != AF_INET6) 2010252511Shrs continue; 2011252511Shrs sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 2012252511Shrs if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || 2013252511Shrs IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr) || 2014252511Shrs IN6_IS_ADDR_MC_NODELOCAL(&sin6->sin6_addr)) 2015252511Shrs break; 2016252511Shrs } 2017252511Shrs if_addr_runlock(ifp); 2018252511Shrs 2019252511Shrs return ((struct in6_ifaddr *)ifa); 2020252511Shrs} 2021252511Shrs 2022252511Shrs/* 2023165118Sbz * Convert IP6 address to printable (loggable) representation. Caller 2024165118Sbz * has to make sure that ip6buf is at least INET6_ADDRSTRLEN long. 202553541Sshin */ 202653541Sshinstatic char digits[] = "0123456789abcdef"; 202753541Sshinchar * 2028165118Sbzip6_sprintf(char *ip6buf, const struct in6_addr *addr) 202953541Sshin{ 2030208284Salfred int i, cnt = 0, maxcnt = 0, idx = 0, index = 0; 203178064Sume char *cp; 2032126552Sume const u_int16_t *a = (const u_int16_t *)addr; 2033126552Sume const u_int8_t *d; 2034165287Sbz int dcolon = 0, zero = 0; 203553541Sshin 2036165118Sbz cp = ip6buf; 203753541Sshin 203853541Sshin for (i = 0; i < 8; i++) { 2039208284Salfred if (*(a + i) == 0) { 2040208284Salfred cnt++; 2041208284Salfred if (cnt == 1) 2042208284Salfred idx = i; 2043208284Salfred } 2044208284Salfred else if (maxcnt < cnt) { 2045208284Salfred maxcnt = cnt; 2046208284Salfred index = idx; 2047208284Salfred cnt = 0; 2048208284Salfred } 2049208284Salfred } 2050208284Salfred if (maxcnt < cnt) { 2051208284Salfred maxcnt = cnt; 2052208284Salfred index = idx; 2053208284Salfred } 2054208284Salfred 2055208284Salfred for (i = 0; i < 8; i++) { 205653541Sshin if (dcolon == 1) { 205753541Sshin if (*a == 0) { 205853541Sshin if (i == 7) 205953541Sshin *cp++ = ':'; 206053541Sshin a++; 206153541Sshin continue; 206253541Sshin } else 206353541Sshin dcolon = 2; 206453541Sshin } 206553541Sshin if (*a == 0) { 2066208284Salfred if (dcolon == 0 && *(a + 1) == 0 && i == index) { 206753541Sshin if (i == 0) 206853541Sshin *cp++ = ':'; 206953541Sshin *cp++ = ':'; 207053541Sshin dcolon = 1; 207153541Sshin } else { 207253541Sshin *cp++ = '0'; 207353541Sshin *cp++ = ':'; 207453541Sshin } 207553541Sshin a++; 207653541Sshin continue; 207753541Sshin } 207891346Salfred d = (const u_char *)a; 2079165287Sbz /* Try to eliminate leading zeros in printout like in :0001. */ 2080165287Sbz zero = 1; 2081165287Sbz *cp = digits[*d >> 4]; 2082165287Sbz if (*cp != '0') { 2083165287Sbz zero = 0; 2084165287Sbz cp++; 2085165287Sbz } 2086165287Sbz *cp = digits[*d++ & 0xf]; 2087165287Sbz if (zero == 0 || (*cp != '0')) { 2088165287Sbz zero = 0; 2089165287Sbz cp++; 2090165287Sbz } 2091165287Sbz *cp = digits[*d >> 4]; 2092165287Sbz if (zero == 0 || (*cp != '0')) { 2093165287Sbz zero = 0; 2094165287Sbz cp++; 2095165287Sbz } 209653541Sshin *cp++ = digits[*d & 0xf]; 209753541Sshin *cp++ = ':'; 209853541Sshin a++; 209953541Sshin } 2100165118Sbz *--cp = '\0'; 2101165118Sbz return (ip6buf); 210253541Sshin} 210353541Sshin 210453541Sshinint 2105171259Sdelphijin6_localaddr(struct in6_addr *in6) 210653541Sshin{ 210753541Sshin struct in6_ifaddr *ia; 210853541Sshin 210953541Sshin if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6)) 211053541Sshin return 1; 211153541Sshin 2112194971Srwatson IN6_IFADDR_RLOCK(); 2113194907Srwatson TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { 211453541Sshin if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr, 2115120891Sume &ia->ia_prefixmask.sin6_addr)) { 2116194971Srwatson IN6_IFADDR_RUNLOCK(); 211753541Sshin return 1; 2118120891Sume } 2119120891Sume } 2120194971Srwatson IN6_IFADDR_RUNLOCK(); 212153541Sshin 212253541Sshin return (0); 212353541Sshin} 212453541Sshin 2125225043Sbz/* 2126225043Sbz * Return 1 if an internet address is for the local host and configured 2127225043Sbz * on one of its interfaces. 2128225043Sbz */ 212978064Sumeint 2130225043Sbzin6_localip(struct in6_addr *in6) 2131225043Sbz{ 2132225043Sbz struct in6_ifaddr *ia; 2133225043Sbz 2134225043Sbz IN6_IFADDR_RLOCK(); 2135244272Sae LIST_FOREACH(ia, IN6ADDR_HASH(in6), ia6_hash) { 2136225043Sbz if (IN6_ARE_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr)) { 2137225043Sbz IN6_IFADDR_RUNLOCK(); 2138225043Sbz return (1); 2139225043Sbz } 2140225043Sbz } 2141225043Sbz IN6_IFADDR_RUNLOCK(); 2142225043Sbz return (0); 2143225043Sbz} 2144225043Sbz 2145225043Sbzint 2146171259Sdelphijin6_is_addr_deprecated(struct sockaddr_in6 *sa6) 214778064Sume{ 214878064Sume struct in6_ifaddr *ia; 214978064Sume 2150194971Srwatson IN6_IFADDR_RLOCK(); 2151244272Sae LIST_FOREACH(ia, IN6ADDR_HASH(&sa6->sin6_addr), ia6_hash) { 2152244272Sae if (IN6_ARE_ADDR_EQUAL(IA6_IN6(ia), &sa6->sin6_addr)) { 2153244272Sae if (ia->ia6_flags & IN6_IFF_DEPRECATED) { 2154244272Sae IN6_IFADDR_RUNLOCK(); 2155244272Sae return (1); /* true */ 2156244272Sae } 2157244272Sae break; 2158194971Srwatson } 215978064Sume } 2160194971Srwatson IN6_IFADDR_RUNLOCK(); 216178064Sume 2162120856Sume return (0); /* false */ 216378064Sume} 216478064Sume 216553541Sshin/* 216653541Sshin * return length of part which dst and src are equal 216753541Sshin * hard coding... 216853541Sshin */ 216953541Sshinint 2170171259Sdelphijin6_matchlen(struct in6_addr *src, struct in6_addr *dst) 217153541Sshin{ 217253541Sshin int match = 0; 217353541Sshin u_char *s = (u_char *)src, *d = (u_char *)dst; 217453541Sshin u_char *lim = s + 16, r; 217553541Sshin 217653541Sshin while (s < lim) 217753541Sshin if ((r = (*d++ ^ *s++)) != 0) { 217853541Sshin while (r < 128) { 217953541Sshin match++; 218053541Sshin r <<= 1; 218153541Sshin } 218253541Sshin break; 218353541Sshin } else 218453541Sshin match += 8; 218553541Sshin return match; 218653541Sshin} 218753541Sshin 218862587Sitojun/* XXX: to be scope conscious */ 218953541Sshinint 2190171259Sdelphijin6_are_prefix_equal(struct in6_addr *p1, struct in6_addr *p2, int len) 219153541Sshin{ 219253541Sshin int bytelen, bitlen; 219353541Sshin 219453541Sshin /* sanity check */ 219553541Sshin if (0 > len || len > 128) { 219653541Sshin log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n", 219753541Sshin len); 2198120856Sume return (0); 219953541Sshin } 220053541Sshin 220153541Sshin bytelen = len / 8; 220253541Sshin bitlen = len % 8; 220353541Sshin 220453541Sshin if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen)) 2205120856Sume return (0); 2206126184Scperciva if (bitlen != 0 && 2207126184Scperciva p1->s6_addr[bytelen] >> (8 - bitlen) != 220853541Sshin p2->s6_addr[bytelen] >> (8 - bitlen)) 2209120856Sume return (0); 221053541Sshin 2211120856Sume return (1); 221253541Sshin} 221353541Sshin 221453541Sshinvoid 2215171259Sdelphijin6_prefixlen2mask(struct in6_addr *maskp, int len) 221653541Sshin{ 221753541Sshin u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 221853541Sshin int bytelen, bitlen, i; 221953541Sshin 222053541Sshin /* sanity check */ 222153541Sshin if (0 > len || len > 128) { 222253541Sshin log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n", 222353541Sshin len); 222453541Sshin return; 222553541Sshin } 222653541Sshin 222753541Sshin bzero(maskp, sizeof(*maskp)); 222853541Sshin bytelen = len / 8; 222953541Sshin bitlen = len % 8; 223053541Sshin for (i = 0; i < bytelen; i++) 223153541Sshin maskp->s6_addr[i] = 0xff; 223253541Sshin if (bitlen) 223353541Sshin maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 223453541Sshin} 223553541Sshin 223653541Sshin/* 223753541Sshin * return the best address out of the same scope. if no address was 223853541Sshin * found, return the first valid address from designated IF. 223953541Sshin */ 224053541Sshinstruct in6_ifaddr * 2241171259Sdelphijin6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) 224253541Sshin{ 224353541Sshin int dst_scope = in6_addrscope(dst), blen = -1, tlen; 224453541Sshin struct ifaddr *ifa; 224553541Sshin struct in6_ifaddr *besta = 0; 224695023Ssuz struct in6_ifaddr *dep[2]; /* last-resort: deprecated */ 224753541Sshin 224853541Sshin dep[0] = dep[1] = NULL; 224953541Sshin 225053541Sshin /* 225153541Sshin * We first look for addresses in the same scope. 225253541Sshin * If there is one, return it. 225353541Sshin * If two or more, return one which matches the dst longest. 225453541Sshin * If none, return one of global addresses assigned other ifs. 225553541Sshin */ 2256229621Sjhb IF_ADDR_RLOCK(ifp); 2257191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 225853541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 225953541Sshin continue; 226053541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 226153541Sshin continue; /* XXX: is there any case to allow anycast? */ 226253541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 226353541Sshin continue; /* don't use this interface */ 226453541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 226553541Sshin continue; 226653541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 2267181803Sbz if (V_ip6_use_deprecated) 226853541Sshin dep[0] = (struct in6_ifaddr *)ifa; 226953541Sshin continue; 227053541Sshin } 227153541Sshin 227253541Sshin if (dst_scope == in6_addrscope(IFA_IN6(ifa))) { 227353541Sshin /* 227453541Sshin * call in6_matchlen() as few as possible 227553541Sshin */ 227653541Sshin if (besta) { 227753541Sshin if (blen == -1) 227853541Sshin blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst); 227953541Sshin tlen = in6_matchlen(IFA_IN6(ifa), dst); 228053541Sshin if (tlen > blen) { 228153541Sshin blen = tlen; 228253541Sshin besta = (struct in6_ifaddr *)ifa; 228353541Sshin } 228453541Sshin } else 228553541Sshin besta = (struct in6_ifaddr *)ifa; 228653541Sshin } 228753541Sshin } 2288191323Srwatson if (besta) { 2289194760Srwatson ifa_ref(&besta->ia_ifa); 2290229621Sjhb IF_ADDR_RUNLOCK(ifp); 2291120856Sume return (besta); 2292191323Srwatson } 229353541Sshin 2294191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 229553541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 229653541Sshin continue; 229753541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 229853541Sshin continue; /* XXX: is there any case to allow anycast? */ 229953541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 230053541Sshin continue; /* don't use this interface */ 230153541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 230253541Sshin continue; 230353541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 2304181803Sbz if (V_ip6_use_deprecated) 230553541Sshin dep[1] = (struct in6_ifaddr *)ifa; 230653541Sshin continue; 230753541Sshin } 230853541Sshin 2309194760Srwatson if (ifa != NULL) 2310194760Srwatson ifa_ref(ifa); 2311229621Sjhb IF_ADDR_RUNLOCK(ifp); 231253541Sshin return (struct in6_ifaddr *)ifa; 231353541Sshin } 231453541Sshin 231553541Sshin /* use the last-resort values, that are, deprecated addresses */ 2316236327Semax if (dep[0]) { 2317236327Semax ifa_ref((struct ifaddr *)dep[0]); 2318236327Semax IF_ADDR_RUNLOCK(ifp); 231953541Sshin return dep[0]; 2320236327Semax } 2321236327Semax if (dep[1]) { 2322236327Semax ifa_ref((struct ifaddr *)dep[1]); 2323236327Semax IF_ADDR_RUNLOCK(ifp); 232453541Sshin return dep[1]; 2325236327Semax } 232653541Sshin 2327236327Semax IF_ADDR_RUNLOCK(ifp); 232853541Sshin return NULL; 232953541Sshin} 233053541Sshin 233153541Sshin/* 233253541Sshin * perform DAD when interface becomes IFF_UP. 233353541Sshin */ 233453541Sshinvoid 2335171259Sdelphijin6_if_up(struct ifnet *ifp) 233653541Sshin{ 233753541Sshin struct ifaddr *ifa; 233853541Sshin struct in6_ifaddr *ia; 233953541Sshin 2340229621Sjhb IF_ADDR_RLOCK(ifp); 2341191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 234253541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 234353541Sshin continue; 234453541Sshin ia = (struct in6_ifaddr *)ifa; 2345151539Ssuz if (ia->ia6_flags & IN6_IFF_TENTATIVE) { 2346151539Ssuz /* 2347151539Ssuz * The TENTATIVE flag was likely set by hand 2348151539Ssuz * beforehand, implicitly indicating the need for DAD. 2349151539Ssuz * We may be able to skip the random delay in this 2350151539Ssuz * case, but we impose delays just in case. 2351151539Ssuz */ 2352151539Ssuz nd6_dad_start(ifa, 2353151539Ssuz arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz)); 2354151539Ssuz } 235553541Sshin } 2356229621Sjhb IF_ADDR_RUNLOCK(ifp); 2357151539Ssuz 2358151539Ssuz /* 2359151539Ssuz * special cases, like 6to4, are handled in in6_ifattach 2360151539Ssuz */ 2361151539Ssuz in6_ifattach(ifp, NULL); 236253541Sshin} 236353541Sshin 236478064Sumeint 2365171259Sdelphijin6if_do_dad(struct ifnet *ifp) 236678064Sume{ 236778064Sume if ((ifp->if_flags & IFF_LOOPBACK) != 0) 2368120856Sume return (0); 236978064Sume 2370197138Shrs if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) 2371197138Shrs return (0); 2372197138Shrs 237378064Sume switch (ifp->if_type) { 237478064Sume#ifdef IFT_DUMMY 237578064Sume case IFT_DUMMY: 237678064Sume#endif 237778064Sume case IFT_FAITH: 237878064Sume /* 237978064Sume * These interfaces do not have the IFF_LOOPBACK flag, 238078064Sume * but loop packets back. We do not have to do DAD on such 238178064Sume * interfaces. We should even omit it, because loop-backed 238278064Sume * NS would confuse the DAD procedure. 238378064Sume */ 2384120856Sume return (0); 238578064Sume default: 238678064Sume /* 238778064Sume * Our DAD routine requires the interface up and running. 238878064Sume * However, some interfaces can be up before the RUNNING 238978064Sume * status. Additionaly, users may try to assign addresses 239078064Sume * before the interface becomes up (or running). 239178064Sume * We simply skip DAD in such a case as a work around. 239278064Sume * XXX: we should rather mark "tentative" on such addresses, 239378064Sume * and do DAD after the interface becomes ready. 239478064Sume */ 2395148887Srwatson if (!((ifp->if_flags & IFF_UP) && 2396148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 2397120856Sume return (0); 239878064Sume 2399120856Sume return (1); 240078064Sume } 240178064Sume} 240278064Sume 240353541Sshin/* 240453541Sshin * Calculate max IPv6 MTU through all the interfaces and store it 240553541Sshin * to in6_maxmtu. 240653541Sshin */ 240753541Sshinvoid 2408171259Sdelphijin6_setmaxmtu(void) 240953541Sshin{ 241053541Sshin unsigned long maxmtu = 0; 241153541Sshin struct ifnet *ifp; 241253541Sshin 2413196481Srwatson IFNET_RLOCK_NOSLEEP(); 2414228966Sjhb TAILQ_FOREACH(ifp, &V_ifnet, if_list) { 2415121283Sume /* this function can be called during ifnet initialization */ 2416121283Sume if (!ifp->if_afdata[AF_INET6]) 2417121283Sume continue; 241853541Sshin if ((ifp->if_flags & IFF_LOOPBACK) == 0 && 2419121283Sume IN6_LINKMTU(ifp) > maxmtu) 2420121283Sume maxmtu = IN6_LINKMTU(ifp); 242153541Sshin } 2422196481Srwatson IFNET_RUNLOCK_NOSLEEP(); 2423238945Sglebius if (maxmtu) /* update only when maxmtu is positive */ 2424181803Sbz V_in6_maxmtu = maxmtu; 242553541Sshin} 242653541Sshin 2427151539Ssuz/* 2428151539Ssuz * Provide the length of interface identifiers to be used for the link attached 2429151539Ssuz * to the given interface. The length should be defined in "IPv6 over 2430151539Ssuz * xxx-link" document. Note that address architecture might also define 2431151539Ssuz * the length for a particular set of address prefixes, regardless of the 2432151539Ssuz * link type. As clarified in rfc2462bis, those two definitions should be 2433151539Ssuz * consistent, and those really are as of August 2004. 2434151539Ssuz */ 2435151539Ssuzint 2436171259Sdelphijin6_if2idlen(struct ifnet *ifp) 2437151539Ssuz{ 2438151539Ssuz switch (ifp->if_type) { 2439151539Ssuz case IFT_ETHER: /* RFC2464 */ 2440151539Ssuz#ifdef IFT_PROPVIRTUAL 2441151539Ssuz case IFT_PROPVIRTUAL: /* XXX: no RFC. treat it as ether */ 2442151539Ssuz#endif 2443151539Ssuz#ifdef IFT_L2VLAN 2444151539Ssuz case IFT_L2VLAN: /* ditto */ 2445151539Ssuz#endif 2446151539Ssuz#ifdef IFT_IEEE80211 2447151539Ssuz case IFT_IEEE80211: /* ditto */ 2448151539Ssuz#endif 2449151539Ssuz#ifdef IFT_MIP 2450151539Ssuz case IFT_MIP: /* ditto */ 2451151539Ssuz#endif 2452219819Sjeff case IFT_INFINIBAND: 2453151539Ssuz return (64); 2454151539Ssuz case IFT_FDDI: /* RFC2467 */ 2455151539Ssuz return (64); 2456151539Ssuz case IFT_ISO88025: /* RFC2470 (IPv6 over Token Ring) */ 2457151539Ssuz return (64); 2458151539Ssuz case IFT_PPP: /* RFC2472 */ 2459151539Ssuz return (64); 2460151539Ssuz case IFT_ARCNET: /* RFC2497 */ 2461151539Ssuz return (64); 2462151539Ssuz case IFT_FRELAY: /* RFC2590 */ 2463151539Ssuz return (64); 2464151539Ssuz case IFT_IEEE1394: /* RFC3146 */ 2465151539Ssuz return (64); 2466151539Ssuz case IFT_GIF: 2467151539Ssuz return (64); /* draft-ietf-v6ops-mech-v2-07 */ 2468151539Ssuz case IFT_LOOP: 2469151539Ssuz return (64); /* XXX: is this really correct? */ 2470151539Ssuz default: 2471151539Ssuz /* 2472151539Ssuz * Unknown link type: 2473151539Ssuz * It might be controversial to use the today's common constant 2474151539Ssuz * of 64 for these cases unconditionally. For full compliance, 2475151539Ssuz * we should return an error in this case. On the other hand, 2476151539Ssuz * if we simply miss the standard for the link type or a new 2477151539Ssuz * standard is defined for a new link type, the IFID length 2478151539Ssuz * is very likely to be the common constant. As a compromise, 2479151539Ssuz * we always use the constant, but make an explicit notice 2480151539Ssuz * indicating the "unknown" case. 2481151539Ssuz */ 2482151539Ssuz printf("in6_if2idlen: unknown link type (%d)\n", ifp->if_type); 2483151539Ssuz return (64); 2484151539Ssuz } 2485151539Ssuz} 2486151539Ssuz 2487186119Sqingli#include <sys/sysctl.h> 2488186119Sqingli 2489186119Sqinglistruct in6_llentry { 2490186119Sqingli struct llentry base; 2491186119Sqingli struct sockaddr_in6 l3_addr6; 2492186119Sqingli}; 2493186119Sqingli 2494232054Skmacy/* 2495232054Skmacy * Deletes an address from the address table. 2496232054Skmacy * This function is called by the timer functions 2497232054Skmacy * such as arptimer() and nd6_llinfo_timer(), and 2498232054Skmacy * the caller does the locking. 2499232054Skmacy */ 2500232054Skmacystatic void 2501232054Skmacyin6_lltable_free(struct lltable *llt, struct llentry *lle) 2502232054Skmacy{ 2503232054Skmacy LLE_WUNLOCK(lle); 2504232054Skmacy LLE_LOCK_DESTROY(lle); 2505232054Skmacy free(lle, M_LLTABLE); 2506232054Skmacy} 2507232054Skmacy 2508186119Sqinglistatic struct llentry * 2509186119Sqingliin6_lltable_new(const struct sockaddr *l3addr, u_int flags) 2510186119Sqingli{ 2511186119Sqingli struct in6_llentry *lle; 2512186119Sqingli 2513238945Sglebius lle = malloc(sizeof(struct in6_llentry), M_LLTABLE, M_NOWAIT | M_ZERO); 2514186119Sqingli if (lle == NULL) /* NB: caller generates msg */ 2515186119Sqingli return NULL; 2516186119Sqingli 2517186119Sqingli lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr; 2518186119Sqingli lle->base.lle_refcnt = 1; 2519232054Skmacy lle->base.lle_free = in6_lltable_free; 2520186119Sqingli LLE_LOCK_INIT(&lle->base); 2521216022Sbz callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock, 2522216022Sbz CALLOUT_RETURNUNLOCKED); 2523216022Sbz 2524238945Sglebius return (&lle->base); 2525186119Sqingli} 2526186119Sqingli 2527186119Sqinglistatic void 2528238945Sglebiusin6_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix, 2529238945Sglebius const struct sockaddr *mask, u_int flags) 2530192476Sqingli{ 2531192476Sqingli const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix; 2532192476Sqingli const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask; 2533192476Sqingli struct llentry *lle, *next; 2534238945Sglebius int i; 2535192476Sqingli 2536222143Sqingli /* 2537238945Sglebius * (flags & LLE_STATIC) means deleting all entries 2538238945Sglebius * including static ND6 entries. 2539222143Sqingli */ 2540238990Sglebius IF_AFDATA_WLOCK(llt->llt_ifp); 2541238945Sglebius for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { 2542192476Sqingli LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 2543192476Sqingli if (IN6_ARE_MASKED_ADDR_EQUAL( 2544238990Sglebius &satosin6(L3_ADDR(lle))->sin6_addr, 2545238990Sglebius &pfx->sin6_addr, &msk->sin6_addr) && 2546238990Sglebius ((flags & LLE_STATIC) || 2547238990Sglebius !(lle->la_flags & LLE_STATIC))) { 2548192476Sqingli LLE_WLOCK(lle); 2549238990Sglebius if (callout_stop(&lle->la_timer)) 2550206481Sbz LLE_REMREF(lle); 2551192476Sqingli llentry_free(lle); 2552192476Sqingli } 2553192476Sqingli } 2554192476Sqingli } 2555238990Sglebius IF_AFDATA_WUNLOCK(llt->llt_ifp); 2556192476Sqingli} 2557192476Sqingli 2558186119Sqinglistatic int 2559238945Sglebiusin6_lltable_rtcheck(struct ifnet *ifp, 2560238945Sglebius u_int flags, 2561201282Sqingli const struct sockaddr *l3addr) 2562186119Sqingli{ 2563186119Sqingli struct rtentry *rt; 2564186119Sqingli char ip6buf[INET6_ADDRSTRLEN]; 2565186119Sqingli 2566186119Sqingli KASSERT(l3addr->sa_family == AF_INET6, 2567186119Sqingli ("sin_family %d", l3addr->sa_family)); 2568186119Sqingli 2569231852Sbz /* Our local addresses are always only installed on the default FIB. */ 2570186119Sqingli /* XXX rtalloc1 should take a const param */ 2571231852Sbz rt = in6_rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0, 2572231852Sbz RT_DEFAULT_FIB); 2573186119Sqingli if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) { 2574186119Sqingli struct ifaddr *ifa; 2575238945Sglebius /* 2576238945Sglebius * Create an ND6 cache for an IPv6 neighbor 2577186119Sqingli * that is not covered by our own prefix. 2578186119Sqingli */ 2579186119Sqingli /* XXX ifaof_ifpforaddr should take a const param */ 2580186119Sqingli ifa = ifaof_ifpforaddr(__DECONST(struct sockaddr *, l3addr), ifp); 2581186119Sqingli if (ifa != NULL) { 2582194760Srwatson ifa_free(ifa); 2583186119Sqingli if (rt != NULL) 2584187946Sbz RTFREE_LOCKED(rt); 2585186119Sqingli return 0; 2586186119Sqingli } 2587186119Sqingli log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", 2588186119Sqingli ip6_sprintf(ip6buf, &((const struct sockaddr_in6 *)l3addr)->sin6_addr)); 2589186119Sqingli if (rt != NULL) 2590187946Sbz RTFREE_LOCKED(rt); 2591186119Sqingli return EINVAL; 2592186119Sqingli } 2593187946Sbz RTFREE_LOCKED(rt); 2594186119Sqingli return 0; 2595186119Sqingli} 2596186119Sqingli 2597186119Sqinglistatic struct llentry * 2598186119Sqingliin6_lltable_lookup(struct lltable *llt, u_int flags, 2599186119Sqingli const struct sockaddr *l3addr) 2600186119Sqingli{ 2601186119Sqingli const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; 2602186119Sqingli struct ifnet *ifp = llt->llt_ifp; 2603186119Sqingli struct llentry *lle; 2604186119Sqingli struct llentries *lleh; 2605186119Sqingli u_int hashkey; 2606186119Sqingli 2607186119Sqingli IF_AFDATA_LOCK_ASSERT(ifp); 2608186119Sqingli KASSERT(l3addr->sa_family == AF_INET6, 2609186119Sqingli ("sin_family %d", l3addr->sa_family)); 2610186119Sqingli 2611186119Sqingli hashkey = sin6->sin6_addr.s6_addr32[3]; 2612186119Sqingli lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; 2613186119Sqingli LIST_FOREACH(lle, lleh, lle_next) { 2614186708Sqingli struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)L3_ADDR(lle); 2615186119Sqingli if (lle->la_flags & LLE_DELETED) 2616186119Sqingli continue; 2617238945Sglebius if (bcmp(&sa6->sin6_addr, &sin6->sin6_addr, 2618238945Sglebius sizeof(struct in6_addr)) == 0) 2619186119Sqingli break; 2620186119Sqingli } 2621186119Sqingli 2622186119Sqingli if (lle == NULL) { 2623186119Sqingli if (!(flags & LLE_CREATE)) 2624186119Sqingli return (NULL); 2625260504Sae IF_AFDATA_WLOCK_ASSERT(ifp); 2626186119Sqingli /* 2627186119Sqingli * A route that covers the given address must have 2628186119Sqingli * been installed 1st because we are doing a resolution, 2629186119Sqingli * verify this. 2630186119Sqingli */ 2631186119Sqingli if (!(flags & LLE_IFADDR) && 2632201282Sqingli in6_lltable_rtcheck(ifp, flags, l3addr) != 0) 2633186119Sqingli return NULL; 2634186119Sqingli 2635186119Sqingli lle = in6_lltable_new(l3addr, flags); 2636186119Sqingli if (lle == NULL) { 2637186119Sqingli log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); 2638186119Sqingli return NULL; 2639186119Sqingli } 2640186119Sqingli lle->la_flags = flags & ~LLE_CREATE; 2641186119Sqingli if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { 2642186119Sqingli bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); 2643186119Sqingli lle->la_flags |= (LLE_VALID | LLE_STATIC); 2644186119Sqingli } 2645186119Sqingli 2646186119Sqingli lle->lle_tbl = llt; 2647186119Sqingli lle->lle_head = lleh; 2648238990Sglebius lle->la_flags |= LLE_LINKED; 2649186119Sqingli LIST_INSERT_HEAD(lleh, lle, lle_next); 2650186119Sqingli } else if (flags & LLE_DELETE) { 2651186392Sqingli if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) { 2652186392Sqingli LLE_WLOCK(lle); 2653238990Sglebius lle->la_flags |= LLE_DELETED; 2654198418Sqingli#ifdef DIAGNOSTIC 2655249742Soleg log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); 2656238967Sglebius#endif 2657249742Soleg if ((lle->la_flags & 2658249742Soleg (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC) 2659249742Soleg llentry_free(lle); 2660249742Soleg else 2661249742Soleg LLE_WUNLOCK(lle); 2662186392Sqingli } 2663186119Sqingli lle = (void *)-1; 2664186119Sqingli } 2665186119Sqingli if (LLE_IS_VALID(lle)) { 2666186119Sqingli if (flags & LLE_EXCLUSIVE) 2667186119Sqingli LLE_WLOCK(lle); 2668186119Sqingli else 2669186119Sqingli LLE_RLOCK(lle); 2670186119Sqingli } 2671186119Sqingli return (lle); 2672186119Sqingli} 2673186119Sqingli 2674186119Sqinglistatic int 2675186119Sqingliin6_lltable_dump(struct lltable *llt, struct sysctl_req *wr) 2676186119Sqingli{ 2677186119Sqingli struct ifnet *ifp = llt->llt_ifp; 2678186119Sqingli struct llentry *lle; 2679186119Sqingli /* XXX stack use */ 2680186119Sqingli struct { 2681186119Sqingli struct rt_msghdr rtm; 2682186119Sqingli struct sockaddr_in6 sin6; 2683186119Sqingli /* 2684186119Sqingli * ndp.c assumes that sdl is word aligned 2685186119Sqingli */ 2686186119Sqingli#ifdef __LP64__ 2687186119Sqingli uint32_t pad; 2688186119Sqingli#endif 2689186119Sqingli struct sockaddr_dl sdl; 2690186119Sqingli } ndpc; 2691186119Sqingli int i, error; 2692186119Sqingli 2693196864Sqingli if (ifp->if_flags & IFF_LOOPBACK) 2694196864Sqingli return 0; 2695196864Sqingli 2696196535Srwatson LLTABLE_LOCK_ASSERT(); 2697186119Sqingli 2698186119Sqingli error = 0; 2699186119Sqingli for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { 2700186119Sqingli LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 2701186119Sqingli struct sockaddr_dl *sdl; 2702186119Sqingli 2703186119Sqingli /* skip deleted or invalid entries */ 2704186119Sqingli if ((lle->la_flags & (LLE_DELETED|LLE_VALID)) != LLE_VALID) 2705186119Sqingli continue; 2706186980Sbz /* Skip if jailed and not a valid IP of the prison. */ 2707188144Sjamie if (prison_if(wr->td->td_ucred, L3_ADDR(lle)) != 0) 2708186980Sbz continue; 2709186119Sqingli /* 2710186119Sqingli * produce a msg made of: 2711186119Sqingli * struct rt_msghdr; 2712186119Sqingli * struct sockaddr_in6 (IPv6) 2713186119Sqingli * struct sockaddr_dl; 2714186119Sqingli */ 2715186119Sqingli bzero(&ndpc, sizeof(ndpc)); 2716186119Sqingli ndpc.rtm.rtm_msglen = sizeof(ndpc); 2717187094Sqingli ndpc.rtm.rtm_version = RTM_VERSION; 2718187094Sqingli ndpc.rtm.rtm_type = RTM_GET; 2719187094Sqingli ndpc.rtm.rtm_flags = RTF_UP; 2720187094Sqingli ndpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; 2721186119Sqingli ndpc.sin6.sin6_family = AF_INET6; 2722186119Sqingli ndpc.sin6.sin6_len = sizeof(ndpc.sin6); 2723186119Sqingli bcopy(L3_ADDR(lle), &ndpc.sin6, L3_ADDR_LEN(lle)); 2724243903Shrs if (V_deembed_scopeid) 2725243903Shrs sa6_recoverscope(&ndpc.sin6); 2726186119Sqingli 2727186119Sqingli /* publish */ 2728186119Sqingli if (lle->la_flags & LLE_PUB) 2729186119Sqingli ndpc.rtm.rtm_flags |= RTF_ANNOUNCE; 2730186119Sqingli 2731186119Sqingli sdl = &ndpc.sdl; 2732186119Sqingli sdl->sdl_family = AF_LINK; 2733186119Sqingli sdl->sdl_len = sizeof(*sdl); 2734186119Sqingli sdl->sdl_alen = ifp->if_addrlen; 2735186119Sqingli sdl->sdl_index = ifp->if_index; 2736186119Sqingli sdl->sdl_type = ifp->if_type; 2737186119Sqingli bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); 2738186119Sqingli ndpc.rtm.rtm_rmx.rmx_expire = 2739186119Sqingli lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; 2740186500Sqingli ndpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); 2741186119Sqingli if (lle->la_flags & LLE_STATIC) 2742186119Sqingli ndpc.rtm.rtm_flags |= RTF_STATIC; 2743186119Sqingli ndpc.rtm.rtm_index = ifp->if_index; 2744186119Sqingli error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc)); 2745186119Sqingli if (error) 2746186119Sqingli break; 2747186119Sqingli } 2748186119Sqingli } 2749186119Sqingli return error; 2750186119Sqingli} 2751186119Sqingli 2752121161Sumevoid * 2753171259Sdelphijin6_domifattach(struct ifnet *ifp) 2754121161Sume{ 2755121161Sume struct in6_ifextra *ext; 2756121161Sume 2757253841Shrs /* There are not IPv6-capable interfaces. */ 2758253841Shrs switch (ifp->if_type) { 2759253841Shrs case IFT_PFLOG: 2760253841Shrs case IFT_PFSYNC: 2761253841Shrs case IFT_USB: 2762253841Shrs return (NULL); 2763253841Shrs } 2764121161Sume ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK); 2765121161Sume bzero(ext, sizeof(*ext)); 2766121161Sume 2767253101Sae ext->in6_ifstat = malloc(sizeof(counter_u64_t) * 2768253101Sae sizeof(struct in6_ifstat) / sizeof(uint64_t), M_IFADDR, M_WAITOK); 2769253086Sae COUNTER_ARRAY_ALLOC(ext->in6_ifstat, 2770253086Sae sizeof(struct in6_ifstat) / sizeof(uint64_t), M_WAITOK); 2771121161Sume 2772253101Sae ext->icmp6_ifstat = malloc(sizeof(counter_u64_t) * 2773253101Sae sizeof(struct icmp6_ifstat) / sizeof(uint64_t), M_IFADDR, 2774253086Sae M_WAITOK); 2775253086Sae COUNTER_ARRAY_ALLOC(ext->icmp6_ifstat, 2776253086Sae sizeof(struct icmp6_ifstat) / sizeof(uint64_t), M_WAITOK); 2777121161Sume 2778121161Sume ext->nd_ifinfo = nd6_ifattach(ifp); 2779121161Sume ext->scope6_id = scope6_ifattach(ifp); 2780186119Sqingli ext->lltable = lltable_init(ifp, AF_INET6); 2781186119Sqingli if (ext->lltable != NULL) { 2782192476Sqingli ext->lltable->llt_prefix_free = in6_lltable_prefix_free; 2783186119Sqingli ext->lltable->llt_lookup = in6_lltable_lookup; 2784186119Sqingli ext->lltable->llt_dump = in6_lltable_dump; 2785186119Sqingli } 2786191672Sbms 2787191672Sbms ext->mld_ifinfo = mld_domifattach(ifp); 2788191672Sbms 2789121161Sume return ext; 2790121161Sume} 2791121161Sume 2792121161Sumevoid 2793171259Sdelphijin6_domifdetach(struct ifnet *ifp, void *aux) 2794121161Sume{ 2795121161Sume struct in6_ifextra *ext = (struct in6_ifextra *)aux; 2796121161Sume 2797191672Sbms mld_domifdetach(ifp); 2798121161Sume scope6_ifdetach(ext->scope6_id); 2799121161Sume nd6_ifdetach(ext->nd_ifinfo); 2800186119Sqingli lltable_free(ext->lltable); 2801253086Sae COUNTER_ARRAY_FREE(ext->in6_ifstat, 2802253086Sae sizeof(struct in6_ifstat) / sizeof(uint64_t)); 2803121161Sume free(ext->in6_ifstat, M_IFADDR); 2804253086Sae COUNTER_ARRAY_FREE(ext->icmp6_ifstat, 2805253086Sae sizeof(struct icmp6_ifstat) / sizeof(uint64_t)); 2806121161Sume free(ext->icmp6_ifstat, M_IFADDR); 2807121161Sume free(ext, M_IFADDR); 2808121161Sume} 2809121161Sume 281053541Sshin/* 281195023Ssuz * Convert sockaddr_in6 to sockaddr_in. Original sockaddr_in6 must be 281253541Sshin * v4 mapped addr or v4 compat addr 281353541Sshin */ 281453541Sshinvoid 281553541Sshinin6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 281653541Sshin{ 2817171259Sdelphij 281853541Sshin bzero(sin, sizeof(*sin)); 281953541Sshin sin->sin_len = sizeof(struct sockaddr_in); 282053541Sshin sin->sin_family = AF_INET; 282153541Sshin sin->sin_port = sin6->sin6_port; 2822120891Sume sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3]; 282353541Sshin} 282453541Sshin 282553541Sshin/* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */ 282653541Sshinvoid 282753541Sshinin6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 282853541Sshin{ 282953541Sshin bzero(sin6, sizeof(*sin6)); 283053541Sshin sin6->sin6_len = sizeof(struct sockaddr_in6); 283153541Sshin sin6->sin6_family = AF_INET6; 283253541Sshin sin6->sin6_port = sin->sin_port; 283353541Sshin sin6->sin6_addr.s6_addr32[0] = 0; 283453541Sshin sin6->sin6_addr.s6_addr32[1] = 0; 283553541Sshin sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP; 283653541Sshin sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; 283753541Sshin} 283853541Sshin 283953541Sshin/* Convert sockaddr_in6 into sockaddr_in. */ 284053541Sshinvoid 284153541Sshinin6_sin6_2_sin_in_sock(struct sockaddr *nam) 284253541Sshin{ 284353541Sshin struct sockaddr_in *sin_p; 284453541Sshin struct sockaddr_in6 sin6; 284553541Sshin 284653541Sshin /* 284753541Sshin * Save original sockaddr_in6 addr and convert it 284853541Sshin * to sockaddr_in. 284953541Sshin */ 285053541Sshin sin6 = *(struct sockaddr_in6 *)nam; 285153541Sshin sin_p = (struct sockaddr_in *)nam; 285253541Sshin in6_sin6_2_sin(sin_p, &sin6); 285353541Sshin} 285453541Sshin 285553541Sshin/* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */ 285653541Sshinvoid 285753541Sshinin6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam) 285853541Sshin{ 285953541Sshin struct sockaddr_in *sin_p; 286053541Sshin struct sockaddr_in6 *sin6_p; 286153541Sshin 2862238945Sglebius sin6_p = malloc(sizeof *sin6_p, M_SONAME, M_WAITOK); 286353541Sshin sin_p = (struct sockaddr_in *)*nam; 286453541Sshin in6_sin_2_v4mapsin6(sin_p, sin6_p); 2865184205Sdes free(*nam, M_SONAME); 286653541Sshin *nam = (struct sockaddr *)sin6_p; 286753541Sshin} 2868