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> 9853541Sshin 9962587Sitojun#include <netinet/ip6.h> 10053541Sshin#include <netinet6/ip6_var.h> 10195023Ssuz#include <netinet6/nd6.h> 10253541Sshin#include <netinet6/mld6_var.h> 10362587Sitojun#include <netinet6/ip6_mroute.h> 10453541Sshin#include <netinet6/in6_ifattach.h> 10562587Sitojun#include <netinet6/scope6_var.h> 10678064Sume#include <netinet6/in6_pcb.h> 10762587Sitojun 108252021ShrsVNET_DECLARE(int, icmp6_nodeinfo_oldmcprefix); 109252021Shrs#define V_icmp6_nodeinfo_oldmcprefix VNET(icmp6_nodeinfo_oldmcprefix) 110252021Shrs 11153541Sshin/* 11253541Sshin * Definitions of some costant IP6 addresses. 11353541Sshin */ 11462587Sitojunconst struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 11562587Sitojunconst struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 11662587Sitojunconst struct in6_addr in6addr_nodelocal_allnodes = 11753541Sshin IN6ADDR_NODELOCAL_ALLNODES_INIT; 11862587Sitojunconst struct in6_addr in6addr_linklocal_allnodes = 11953541Sshin IN6ADDR_LINKLOCAL_ALLNODES_INIT; 12062587Sitojunconst struct in6_addr in6addr_linklocal_allrouters = 12153541Sshin IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; 122191672Sbmsconst struct in6_addr in6addr_linklocal_allv2routers = 123191672Sbms IN6ADDR_LINKLOCAL_ALLV2ROUTERS_INIT; 12453541Sshin 12562587Sitojunconst struct in6_addr in6mask0 = IN6MASK0; 12662587Sitojunconst struct in6_addr in6mask32 = IN6MASK32; 12762587Sitojunconst struct in6_addr in6mask64 = IN6MASK64; 12862587Sitojunconst struct in6_addr in6mask96 = IN6MASK96; 12962587Sitojunconst struct in6_addr in6mask128 = IN6MASK128; 13053541Sshin 131126552Sumeconst struct sockaddr_in6 sa6_any = 132126552Sume { sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 }; 13378064Sume 134244524Sdelphijstatic int in6_lifaddr_ioctl(struct socket *, u_long, caddr_t, 135244524Sdelphij struct ifnet *, struct thread *); 136244524Sdelphijstatic int in6_ifinit(struct ifnet *, struct in6_ifaddr *, 137244524Sdelphij struct sockaddr_in6 *, int); 138175162Sobrienstatic void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *); 13953541Sshin 14083934Sbrooksint (*faithprefix_p)(struct in6_addr *); 14183934Sbrooks 142226570Sglebius#define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) 143226570Sglebius#define ia62ifa(ia6) (&((ia6)->ia_ifa)) 144120891Sume 145226570Sglebiusvoid 146226570Sglebiusin6_ifaddloop(struct ifaddr *ifa) 147226570Sglebius{ 148226570Sglebius struct sockaddr_dl gateway; 149226570Sglebius struct sockaddr_in6 mask, addr; 150226570Sglebius struct rtentry rt; 151226570Sglebius struct in6_ifaddr *ia; 152226570Sglebius struct ifnet *ifp; 153226570Sglebius struct llentry *ln; 15478064Sume 155226570Sglebius ia = ifa2ia6(ifa); 156226570Sglebius ifp = ifa->ifa_ifp; 157226570Sglebius IF_AFDATA_LOCK(ifp); 158230604Sqingli ifa->ifa_rtrequest = nd6_rtrequest; 159226570Sglebius ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | 160226570Sglebius LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr); 161226570Sglebius IF_AFDATA_UNLOCK(ifp); 162226570Sglebius if (ln != NULL) { 163226570Sglebius ln->la_expire = 0; /* for IPv6 this means permanent */ 164226570Sglebius ln->ln_state = ND6_LLINFO_REACHABLE; 165226570Sglebius /* 166226570Sglebius * initialize for rtmsg generation 167226570Sglebius */ 168226570Sglebius bzero(&gateway, sizeof(gateway)); 169226570Sglebius gateway.sdl_len = sizeof(gateway); 170226570Sglebius gateway.sdl_family = AF_LINK; 171226570Sglebius gateway.sdl_nlen = 0; 172226570Sglebius gateway.sdl_alen = 6; 173226570Sglebius memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned, 174226570Sglebius sizeof(ln->ll_addr)); 175226570Sglebius LLE_WUNLOCK(ln); 176226570Sglebius } 177226570Sglebius 178226570Sglebius bzero(&rt, sizeof(rt)); 179226570Sglebius rt.rt_gateway = (struct sockaddr *)&gateway; 180226570Sglebius memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); 181226570Sglebius memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); 182226570Sglebius rt_mask(&rt) = (struct sockaddr *)&mask; 183226570Sglebius rt_key(&rt) = (struct sockaddr *)&addr; 184226570Sglebius rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC; 185232292Sbz /* Announce arrival of local address to all FIBs. */ 186226570Sglebius rt_newaddrmsg(RTM_ADD, ifa, 0, &rt); 187226570Sglebius} 188226570Sglebius 189226570Sglebiusvoid 190226570Sglebiusin6_ifremloop(struct ifaddr *ifa) 191226570Sglebius{ 192226570Sglebius struct sockaddr_dl gateway; 193226570Sglebius struct sockaddr_in6 mask, addr; 194226570Sglebius struct rtentry rt0; 195226570Sglebius struct in6_ifaddr *ia; 196226570Sglebius struct ifnet *ifp; 197226570Sglebius 198226570Sglebius ia = ifa2ia6(ifa); 199226570Sglebius ifp = ifa->ifa_ifp; 200250927Soleg memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); 201250927Soleg memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); 202250927Soleg lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr, 203250927Soleg (struct sockaddr *)&mask, LLE_STATIC); 204226570Sglebius 205226570Sglebius /* 206226570Sglebius * initialize for rtmsg generation 207226570Sglebius */ 208226570Sglebius bzero(&gateway, sizeof(gateway)); 209226570Sglebius gateway.sdl_len = sizeof(gateway); 210226570Sglebius gateway.sdl_family = AF_LINK; 211226570Sglebius gateway.sdl_nlen = 0; 212226570Sglebius gateway.sdl_alen = ifp->if_addrlen; 213226570Sglebius bzero(&rt0, sizeof(rt0)); 214226570Sglebius rt0.rt_gateway = (struct sockaddr *)&gateway; 215226570Sglebius rt_mask(&rt0) = (struct sockaddr *)&mask; 216226570Sglebius rt_key(&rt0) = (struct sockaddr *)&addr; 217226570Sglebius rt0.rt_flags = RTF_HOST | RTF_STATIC; 218232292Sbz /* Announce removal of local address to all FIBs. */ 219226570Sglebius rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0); 220226570Sglebius} 221226570Sglebius 22253541Sshinint 223171259Sdelphijin6_mask2len(struct in6_addr *mask, u_char *lim0) 22453541Sshin{ 22578064Sume int x = 0, y; 22678064Sume u_char *lim = lim0, *p; 22753541Sshin 228120891Sume /* ignore the scope_id part */ 229120891Sume if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask)) 23078064Sume lim = (u_char *)mask + sizeof(*mask); 23178064Sume for (p = (u_char *)mask; p < lim; x++, p++) { 23278064Sume if (*p != 0xff) 23353541Sshin break; 23453541Sshin } 23553541Sshin y = 0; 23678064Sume if (p < lim) { 23753541Sshin for (y = 0; y < 8; y++) { 23878064Sume if ((*p & (0x80 >> y)) == 0) 23953541Sshin break; 24053541Sshin } 24153541Sshin } 24278064Sume 24378064Sume /* 24478064Sume * when the limit pointer is given, do a stricter check on the 24578064Sume * remaining bits. 24678064Sume */ 24778064Sume if (p < lim) { 24878064Sume if (y != 0 && (*p & (0x00ff >> y)) != 0) 249120856Sume return (-1); 25078064Sume for (p = p + 1; p < lim; p++) 25178064Sume if (*p != 0) 252120856Sume return (-1); 25378064Sume } 254120891Sume 25553541Sshin return x * 8 + y; 25653541Sshin} 25753541Sshin 258207268Skib#ifdef COMPAT_FREEBSD32 259207268Skibstruct in6_ndifreq32 { 260240310Sglebius char ifname[IFNAMSIZ]; 261240310Sglebius uint32_t ifindex; 262207268Skib}; 263240310Sglebius#define SIOCGDEFIFACE32_IN6 _IOWR('i', 86, struct in6_ndifreq32) 264207268Skib#endif 265207268Skib 26653541Sshinint 267171259Sdelphijin6_control(struct socket *so, u_long cmd, caddr_t data, 268171259Sdelphij struct ifnet *ifp, struct thread *td) 26953541Sshin{ 27053541Sshin struct in6_ifreq *ifr = (struct in6_ifreq *)data; 27178064Sume struct in6_ifaddr *ia = NULL; 27253541Sshin struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; 273151539Ssuz struct sockaddr_in6 *sa6; 274164033Srwatson int error; 27553541Sshin 27662587Sitojun switch (cmd) { 27762587Sitojun case SIOCGETSGCNT_IN6: 27862587Sitojun case SIOCGETMIFCNT_IN6: 279240310Sglebius /* 280232292Sbz * XXX mrt_ioctl has a 3rd, unused, FIB argument in route.c. 281232292Sbz * We cannot see how that would be needed, so do not adjust the 282232292Sbz * KPI blindly; more likely should clean up the IPv4 variant. 283232292Sbz */ 284166938Sbms return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP); 28562587Sitojun } 28653541Sshin 287121742Sume switch(cmd) { 288121742Sume case SIOCAADDRCTL_POLICY: 289121742Sume case SIOCDADDRCTL_POLICY: 290164033Srwatson if (td != NULL) { 291164033Srwatson error = priv_check(td, PRIV_NETINET_ADDRCTRL6); 292164033Srwatson if (error) 293164033Srwatson return (error); 294164033Srwatson } 295121742Sume return (in6_src_ioctl(cmd, data)); 296121742Sume } 297121742Sume 29862587Sitojun if (ifp == NULL) 299120856Sume return (EOPNOTSUPP); 30053541Sshin 30153541Sshin switch (cmd) { 30253541Sshin case SIOCSNDFLUSH_IN6: 30353541Sshin case SIOCSPFXFLUSH_IN6: 30453541Sshin case SIOCSRTRFLUSH_IN6: 30562587Sitojun case SIOCSDEFIFACE_IN6: 30662587Sitojun case SIOCSIFINFO_FLAGS: 307193893Scperciva case SIOCSIFINFO_IN6: 308164033Srwatson if (td != NULL) { 309164033Srwatson error = priv_check(td, PRIV_NETINET_ND6); 310164033Srwatson if (error) 311164033Srwatson return (error); 312164033Srwatson } 313120891Sume /* FALLTHROUGH */ 31478064Sume case OSIOCGIFINFO_IN6: 31553541Sshin case SIOCGIFINFO_IN6: 31653541Sshin case SIOCGDRLST_IN6: 31753541Sshin case SIOCGPRLST_IN6: 31853541Sshin case SIOCGNBRINFO_IN6: 31962587Sitojun case SIOCGDEFIFACE_IN6: 320120856Sume return (nd6_ioctl(cmd, data, ifp)); 321207268Skib 322207268Skib#ifdef COMPAT_FREEBSD32 323207268Skib case SIOCGDEFIFACE32_IN6: 324207268Skib { 325207268Skib struct in6_ndifreq ndif; 326207268Skib struct in6_ndifreq32 *ndif32; 327207268Skib 328207268Skib error = nd6_ioctl(SIOCGDEFIFACE_IN6, (caddr_t)&ndif, 329207268Skib ifp); 330207268Skib if (error) 331207268Skib return (error); 332207268Skib ndif32 = (struct in6_ndifreq32 *)data; 333207268Skib ndif32->ifindex = ndif.ifindex; 334207268Skib return (0); 335207268Skib } 336207268Skib#endif 33753541Sshin } 33853541Sshin 33953541Sshin switch (cmd) { 34053541Sshin case SIOCSIFPREFIX_IN6: 34153541Sshin case SIOCDIFPREFIX_IN6: 34253541Sshin case SIOCAIFPREFIX_IN6: 34353541Sshin case SIOCCIFPREFIX_IN6: 34453541Sshin case SIOCSGIFPREFIX_IN6: 34553541Sshin case SIOCGIFPREFIX_IN6: 34678064Sume log(LOG_NOTICE, 34778064Sume "prefix ioctls are now invalidated. " 34878064Sume "please use ifconfig.\n"); 349120856Sume return (EOPNOTSUPP); 35053541Sshin } 35153541Sshin 35295023Ssuz switch (cmd) { 35362587Sitojun case SIOCSSCOPE6: 354164033Srwatson if (td != NULL) { 355164033Srwatson error = priv_check(td, PRIV_NETINET_SCOPE6); 356164033Srwatson if (error) 357164033Srwatson return (error); 358164033Srwatson } 359121161Sume return (scope6_set(ifp, 360121161Sume (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 36162587Sitojun case SIOCGSCOPE6: 362121161Sume return (scope6_get(ifp, 363121161Sume (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 36462587Sitojun case SIOCGSCOPE6DEF: 365121161Sume return (scope6_get_default((struct scope6_id *) 366121161Sume ifr->ifr_ifru.ifru_scope_id)); 36762587Sitojun } 36862587Sitojun 36953541Sshin switch (cmd) { 37053541Sshin case SIOCALIFADDR: 371175630Sbz if (td != NULL) { 372175630Sbz error = priv_check(td, PRIV_NET_ADDIFADDR); 373175630Sbz if (error) 374175630Sbz return (error); 375175630Sbz } 376175630Sbz return in6_lifaddr_ioctl(so, cmd, data, ifp, td); 377175630Sbz 37853541Sshin case SIOCDLIFADDR: 379164033Srwatson if (td != NULL) { 380175630Sbz error = priv_check(td, PRIV_NET_DELIFADDR); 381164033Srwatson if (error) 382164033Srwatson return (error); 383164033Srwatson } 384120891Sume /* FALLTHROUGH */ 38553541Sshin case SIOCGLIFADDR: 38683366Sjulian return in6_lifaddr_ioctl(so, cmd, data, ifp, td); 38753541Sshin } 38853541Sshin 38953541Sshin /* 39053541Sshin * Find address for this interface, if it exists. 391151539Ssuz * 392151539Ssuz * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation 393151539Ssuz * only, and used the first interface address as the target of other 394151539Ssuz * operations (without checking ifra_addr). This was because netinet 395151539Ssuz * code/API assumed at most 1 interface address per interface. 396151539Ssuz * Since IPv6 allows a node to assign multiple addresses 397151539Ssuz * on a single interface, we almost always look and check the 398151539Ssuz * presence of ifra_addr, and reject invalid ones here. 399151539Ssuz * It also decreases duplicated code among SIOC*_IN6 operations. 40053541Sshin */ 401151539Ssuz switch (cmd) { 402151539Ssuz case SIOCAIFADDR_IN6: 403151539Ssuz case SIOCSIFPHYADDR_IN6: 404151539Ssuz sa6 = &ifra->ifra_addr; 405151539Ssuz break; 406151539Ssuz case SIOCSIFADDR_IN6: 407151539Ssuz case SIOCGIFADDR_IN6: 408151539Ssuz case SIOCSIFDSTADDR_IN6: 409151539Ssuz case SIOCSIFNETMASK_IN6: 410151539Ssuz case SIOCGIFDSTADDR_IN6: 411151539Ssuz case SIOCGIFNETMASK_IN6: 412151539Ssuz case SIOCDIFADDR_IN6: 413151539Ssuz case SIOCGIFPSRCADDR_IN6: 414151539Ssuz case SIOCGIFPDSTADDR_IN6: 415151539Ssuz case SIOCGIFAFLAG_IN6: 416151539Ssuz case SIOCSNDFLUSH_IN6: 417151539Ssuz case SIOCSPFXFLUSH_IN6: 418151539Ssuz case SIOCSRTRFLUSH_IN6: 419151539Ssuz case SIOCGIFALIFETIME_IN6: 420151539Ssuz case SIOCSIFALIFETIME_IN6: 421151539Ssuz case SIOCGIFSTAT_IN6: 422151539Ssuz case SIOCGIFSTAT_ICMP6: 423151539Ssuz sa6 = &ifr->ifr_addr; 424151539Ssuz break; 425255443Sdes case SIOCSIFADDR: 426255443Sdes case SIOCSIFBRDADDR: 427255443Sdes case SIOCSIFDSTADDR: 428255443Sdes case SIOCSIFNETMASK: 429255443Sdes /* 430255443Sdes * Although we should pass any non-INET6 ioctl requests 431255443Sdes * down to driver, we filter some legacy INET requests. 432255443Sdes * Drivers trust SIOCSIFADDR et al to come from an already 433255443Sdes * privileged layer, and do not perform any credentials 434255443Sdes * checks or input validation. 435255443Sdes */ 436255443Sdes return (EINVAL); 437151539Ssuz default: 438151539Ssuz sa6 = NULL; 439151539Ssuz break; 440151539Ssuz } 441151539Ssuz if (sa6 && sa6->sin6_family == AF_INET6) { 442151539Ssuz if (sa6->sin6_scope_id != 0) 443151539Ssuz error = sa6_embedscope(sa6, 0); 444148385Sume else 445151539Ssuz error = in6_setscope(&sa6->sin6_addr, ifp, NULL); 446148385Sume if (error != 0) 447148385Sume return (error); 448188144Sjamie if (td != NULL && (error = prison_check_ip6(td->td_ucred, 449188144Sjamie &sa6->sin6_addr)) != 0) 450188144Sjamie return (error); 451151539Ssuz ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr); 452151539Ssuz } else 453151539Ssuz ia = NULL; 45453541Sshin 45553541Sshin switch (cmd) { 45678064Sume case SIOCSIFADDR_IN6: 45778064Sume case SIOCSIFDSTADDR_IN6: 45878064Sume case SIOCSIFNETMASK_IN6: 45978064Sume /* 46078064Sume * Since IPv6 allows a node to assign multiple addresses 461151465Ssuz * on a single interface, SIOCSIFxxx ioctls are deprecated. 46278064Sume */ 46378064Sume /* we decided to obsolete this command (20000704) */ 464194760Srwatson error = EINVAL; 465194760Srwatson goto out; 46653541Sshin 46753541Sshin case SIOCDIFADDR_IN6: 46862587Sitojun /* 46978064Sume * for IPv4, we look for existing in_ifaddr here to allow 470151465Ssuz * "ifconfig if0 delete" to remove the first IPv4 address on 471151465Ssuz * the interface. For IPv6, as the spec allows multiple 472151465Ssuz * interface address from the day one, we consider "remove the 473151465Ssuz * first one" semantics to be not preferable. 47462587Sitojun */ 475194760Srwatson if (ia == NULL) { 476194760Srwatson error = EADDRNOTAVAIL; 477194760Srwatson goto out; 478194760Srwatson } 47953541Sshin /* FALLTHROUGH */ 48053541Sshin case SIOCAIFADDR_IN6: 48162587Sitojun /* 48278064Sume * We always require users to specify a valid IPv6 address for 48378064Sume * the corresponding operation. 48462587Sitojun */ 48578064Sume if (ifra->ifra_addr.sin6_family != AF_INET6 || 486194760Srwatson ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) { 487194760Srwatson error = EAFNOSUPPORT; 488194760Srwatson goto out; 489194760Srwatson } 49053541Sshin 491164033Srwatson if (td != NULL) { 492240310Sglebius error = priv_check(td, (cmd == SIOCDIFADDR_IN6) ? 493175630Sbz PRIV_NET_DELIFADDR : PRIV_NET_ADDIFADDR); 494164033Srwatson if (error) 495194760Srwatson goto out; 496164033Srwatson } 49753541Sshin break; 49853541Sshin 49953541Sshin case SIOCGIFADDR_IN6: 50053541Sshin /* This interface is basically deprecated. use SIOCGIFCONF. */ 501120891Sume /* FALLTHROUGH */ 50253541Sshin case SIOCGIFAFLAG_IN6: 50353541Sshin case SIOCGIFNETMASK_IN6: 50453541Sshin case SIOCGIFDSTADDR_IN6: 50553541Sshin case SIOCGIFALIFETIME_IN6: 50653541Sshin /* must think again about its semantics */ 507194760Srwatson if (ia == NULL) { 508194760Srwatson error = EADDRNOTAVAIL; 509194760Srwatson goto out; 510194760Srwatson } 51153541Sshin break; 512194760Srwatson 51353541Sshin case SIOCSIFALIFETIME_IN6: 51453541Sshin { 51553541Sshin struct in6_addrlifetime *lt; 51653541Sshin 517164033Srwatson if (td != NULL) { 518164033Srwatson error = priv_check(td, PRIV_NETINET_ALIFETIME6); 519164033Srwatson if (error) 520194760Srwatson goto out; 521164033Srwatson } 522194760Srwatson if (ia == NULL) { 523194760Srwatson error = EADDRNOTAVAIL; 524194760Srwatson goto out; 525194760Srwatson } 52653541Sshin /* sanity for overflow - beware unsigned */ 52753541Sshin lt = &ifr->ifr_ifru.ifru_lifetime; 528126552Sume if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME && 529126552Sume lt->ia6t_vltime + time_second < time_second) { 530194760Srwatson error = EINVAL; 531194760Srwatson goto out; 53253541Sshin } 533126552Sume if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME && 534126552Sume lt->ia6t_pltime + time_second < time_second) { 535194760Srwatson error = EINVAL; 536194760Srwatson goto out; 53753541Sshin } 53853541Sshin break; 53953541Sshin } 54053541Sshin } 54153541Sshin 54253541Sshin switch (cmd) { 54353541Sshin case SIOCGIFADDR_IN6: 54453541Sshin ifr->ifr_addr = ia->ia_addr; 545148385Sume if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0) 546194760Srwatson goto out; 54753541Sshin break; 54853541Sshin 54953541Sshin case SIOCGIFDSTADDR_IN6: 550194760Srwatson if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 551194760Srwatson error = EINVAL; 552194760Srwatson goto out; 553194760Srwatson } 55462587Sitojun /* 55562587Sitojun * XXX: should we check if ifa_dstaddr is NULL and return 55662587Sitojun * an error? 55762587Sitojun */ 55853541Sshin ifr->ifr_dstaddr = ia->ia_dstaddr; 559148385Sume if ((error = sa6_recoverscope(&ifr->ifr_dstaddr)) != 0) 560194760Srwatson goto out; 56153541Sshin break; 56253541Sshin 56353541Sshin case SIOCGIFNETMASK_IN6: 56453541Sshin ifr->ifr_addr = ia->ia_prefixmask; 56553541Sshin break; 56653541Sshin 56753541Sshin case SIOCGIFAFLAG_IN6: 56853541Sshin ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags; 56953541Sshin break; 57053541Sshin 57153541Sshin case SIOCGIFSTAT_IN6: 572194760Srwatson if (ifp == NULL) { 573194760Srwatson error = EINVAL; 574194760Srwatson goto out; 575194760Srwatson } 576121161Sume bzero(&ifr->ifr_ifru.ifru_stat, 577121161Sume sizeof(ifr->ifr_ifru.ifru_stat)); 578121161Sume ifr->ifr_ifru.ifru_stat = 579121161Sume *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat; 58053541Sshin break; 58153541Sshin 58253541Sshin case SIOCGIFSTAT_ICMP6: 583194760Srwatson if (ifp == NULL) { 584194760Srwatson error = EINVAL; 585194760Srwatson goto out; 586194760Srwatson } 587155454Sgnn bzero(&ifr->ifr_ifru.ifru_icmp6stat, 588121161Sume sizeof(ifr->ifr_ifru.ifru_icmp6stat)); 589121161Sume ifr->ifr_ifru.ifru_icmp6stat = 590121161Sume *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat; 59153541Sshin break; 59253541Sshin 59353541Sshin case SIOCGIFALIFETIME_IN6: 59453541Sshin ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime; 595151539Ssuz if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 596151539Ssuz time_t maxexpire; 597151539Ssuz struct in6_addrlifetime *retlt = 598151539Ssuz &ifr->ifr_ifru.ifru_lifetime; 599151539Ssuz 600151539Ssuz /* 601151539Ssuz * XXX: adjust expiration time assuming time_t is 602151539Ssuz * signed. 603151539Ssuz */ 604151539Ssuz maxexpire = (-1) & 605151546Ssuz ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); 606151539Ssuz if (ia->ia6_lifetime.ia6t_vltime < 607151539Ssuz maxexpire - ia->ia6_updatetime) { 608151539Ssuz retlt->ia6t_expire = ia->ia6_updatetime + 609151539Ssuz ia->ia6_lifetime.ia6t_vltime; 610151539Ssuz } else 611151539Ssuz retlt->ia6t_expire = maxexpire; 612151539Ssuz } 613151539Ssuz if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 614151539Ssuz time_t maxexpire; 615151539Ssuz struct in6_addrlifetime *retlt = 616151539Ssuz &ifr->ifr_ifru.ifru_lifetime; 617151539Ssuz 618151539Ssuz /* 619151539Ssuz * XXX: adjust expiration time assuming time_t is 620151539Ssuz * signed. 621151539Ssuz */ 622151539Ssuz maxexpire = (-1) & 623151546Ssuz ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); 624151539Ssuz if (ia->ia6_lifetime.ia6t_pltime < 625151539Ssuz maxexpire - ia->ia6_updatetime) { 626151539Ssuz retlt->ia6t_preferred = ia->ia6_updatetime + 627151539Ssuz ia->ia6_lifetime.ia6t_pltime; 628151539Ssuz } else 629151539Ssuz retlt->ia6t_preferred = maxexpire; 630151539Ssuz } 63153541Sshin break; 63253541Sshin 63353541Sshin case SIOCSIFALIFETIME_IN6: 63453541Sshin ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime; 63553541Sshin /* for sanity */ 63653541Sshin if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 63753541Sshin ia->ia6_lifetime.ia6t_expire = 63853541Sshin time_second + ia->ia6_lifetime.ia6t_vltime; 63953541Sshin } else 64053541Sshin ia->ia6_lifetime.ia6t_expire = 0; 64153541Sshin if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 64253541Sshin ia->ia6_lifetime.ia6t_preferred = 64353541Sshin time_second + ia->ia6_lifetime.ia6t_pltime; 64453541Sshin } else 64553541Sshin ia->ia6_lifetime.ia6t_preferred = 0; 64653541Sshin break; 64753541Sshin 64878064Sume case SIOCAIFADDR_IN6: 64978064Sume { 650194760Srwatson int i; 651151539Ssuz struct nd_prefixctl pr0; 652151539Ssuz struct nd_prefix *pr; 65378064Sume 65462587Sitojun /* 65578064Sume * first, make or update the interface address structure, 65678064Sume * and link it to the list. 65762587Sitojun */ 658151539Ssuz if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0) 659194760Srwatson goto out; 660194760Srwatson if (ia != NULL) 661194760Srwatson ifa_free(&ia->ia_ifa); 662151915Ssuz if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr)) 663151915Ssuz == NULL) { 664171260Sdelphij /* 665151915Ssuz * this can happen when the user specify the 0 valid 666151915Ssuz * lifetime. 667151915Ssuz */ 668151915Ssuz break; 669151915Ssuz } 67053541Sshin 67178064Sume /* 67278064Sume * then, make the prefix on-link on the interface. 67378064Sume * XXX: we'd rather create the prefix before the address, but 67478064Sume * we need at least one address to install the corresponding 67578064Sume * interface route, so we configure the address first. 67678064Sume */ 67778064Sume 67878064Sume /* 67978064Sume * convert mask to prefix length (prefixmask has already 68078064Sume * been validated in in6_update_ifa(). 68178064Sume */ 68278064Sume bzero(&pr0, sizeof(pr0)); 68378064Sume pr0.ndpr_ifp = ifp; 68478064Sume pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 685120891Sume NULL); 686120891Sume if (pr0.ndpr_plen == 128) { 68778064Sume break; /* we don't need to install a host route. */ 688120891Sume } 68978064Sume pr0.ndpr_prefix = ifra->ifra_addr; 69078064Sume /* apply the mask for safety. */ 69178064Sume for (i = 0; i < 4; i++) { 69278064Sume pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 693120891Sume ifra->ifra_prefixmask.sin6_addr.s6_addr32[i]; 69478064Sume } 69578064Sume /* 69695023Ssuz * XXX: since we don't have an API to set prefix (not address) 69795023Ssuz * lifetimes, we just use the same lifetimes as addresses. 69895023Ssuz * The (temporarily) installed lifetimes can be overridden by 69995023Ssuz * later advertised RAs (when accept_rtadv is non 0), which is 70095023Ssuz * an intended behavior. 70178064Sume */ 70278064Sume pr0.ndpr_raf_onlink = 1; /* should be configurable? */ 70378064Sume pr0.ndpr_raf_auto = 704120891Sume ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0); 70578064Sume pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime; 70678064Sume pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime; 70778064Sume 708120891Sume /* add the prefix if not yet. */ 70978064Sume if ((pr = nd6_prefix_lookup(&pr0)) == NULL) { 71078064Sume /* 71178064Sume * nd6_prelist_add will install the corresponding 71278064Sume * interface route. 71378064Sume */ 71478064Sume if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) 715194760Srwatson goto out; 71678064Sume if (pr == NULL) { 717120891Sume log(LOG_ERR, "nd6_prelist_add succeeded but " 71878064Sume "no prefix\n"); 719194760Srwatson error = EINVAL; 720194760Srwatson goto out; 72178064Sume } 72278064Sume } 72378064Sume 724151915Ssuz /* relate the address to the prefix */ 725151915Ssuz if (ia->ia6_ndpr == NULL) { 726151915Ssuz ia->ia6_ndpr = pr; 727151915Ssuz pr->ndpr_refcnt++; 72878064Sume 72978064Sume /* 730151915Ssuz * If this is the first autoconf address from the 731151915Ssuz * prefix, create a temporary address as well 732151915Ssuz * (when required). 73378064Sume */ 734151915Ssuz if ((ia->ia6_flags & IN6_IFF_AUTOCONF) && 735181803Sbz V_ip6_use_tempaddr && pr->ndpr_refcnt == 1) { 736151915Ssuz int e; 737151915Ssuz if ((e = in6_tmpifadd(ia, 1, 0)) != 0) { 738151915Ssuz log(LOG_NOTICE, "in6_control: failed " 739151915Ssuz "to create a temporary address, " 740151915Ssuz "errno=%d\n", e); 741151915Ssuz } 742151915Ssuz } 74362587Sitojun } 744151915Ssuz 745151915Ssuz /* 746151915Ssuz * this might affect the status of autoconfigured addresses, 747151915Ssuz * that is, this address might make other addresses detached. 748151915Ssuz */ 749151915Ssuz pfxlist_onlink_check(); 750222730Shrs if (error == 0 && ia) { 751222730Shrs if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) { 752222730Shrs /* 753222730Shrs * Try to clear the flag when a new 754222730Shrs * IPv6 address is added onto an 755222730Shrs * IFDISABLED interface and it 756222730Shrs * succeeds. 757222730Shrs */ 758222730Shrs struct in6_ndireq nd; 759222730Shrs 760222730Shrs memset(&nd, 0, sizeof(nd)); 761222730Shrs nd.ndi.flags = ND_IFINFO(ifp)->flags; 762222730Shrs nd.ndi.flags &= ~ND6_IFF_IFDISABLED; 763222730Shrs if (nd6_ioctl(SIOCSIFINFO_FLAGS, 764222730Shrs (caddr_t)&nd, ifp) < 0) 765222730Shrs log(LOG_NOTICE, "SIOCAIFADDR_IN6: " 766222730Shrs "SIOCSIFINFO_FLAGS for -ifdisabled " 767222730Shrs "failed."); 768222730Shrs /* 769222730Shrs * Ignore failure of clearing the flag 770222730Shrs * intentionally. The failure means 771222730Shrs * address duplication was detected. 772222730Shrs */ 773222730Shrs } 774126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 775222730Shrs } 77678064Sume break; 77778064Sume } 77862587Sitojun 77978064Sume case SIOCDIFADDR_IN6: 78078064Sume { 781151539Ssuz struct nd_prefix *pr; 78278064Sume 78378064Sume /* 78478064Sume * If the address being deleted is the only one that owns 78578064Sume * the corresponding prefix, expire the prefix as well. 786120891Sume * XXX: theoretically, we don't have to worry about such 78778064Sume * relationship, since we separate the address management 78878064Sume * and the prefix management. We do this, however, to provide 78978064Sume * as much backward compatibility as possible in terms of 79078064Sume * the ioctl operation. 791151915Ssuz * Note that in6_purgeaddr() will decrement ndpr_refcnt. 79278064Sume */ 793151915Ssuz pr = ia->ia6_ndpr; 79478064Sume in6_purgeaddr(&ia->ia_ifa); 795151915Ssuz if (pr && pr->ndpr_refcnt == 0) 796151915Ssuz prelist_remove(pr); 797126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 79853541Sshin break; 79978064Sume } 80053541Sshin 80178064Sume default: 802194760Srwatson if (ifp == NULL || ifp->if_ioctl == 0) { 803194760Srwatson error = EOPNOTSUPP; 804194760Srwatson goto out; 805194760Srwatson } 806194760Srwatson error = (*ifp->if_ioctl)(ifp, cmd, data); 807194760Srwatson goto out; 80878064Sume } 80953541Sshin 810194760Srwatson error = 0; 811194760Srwatsonout: 812194760Srwatson if (ia != NULL) 813194760Srwatson ifa_free(&ia->ia_ifa); 814194760Srwatson return (error); 81578064Sume} 81653541Sshin 817232292Sbz 81878064Sume/* 819232292Sbz * Join necessary multicast groups. Factored out from in6_update_ifa(). 820232292Sbz * This entire work should only be done once, for the default FIB. 821232292Sbz */ 822232292Sbzstatic int 823232292Sbzin6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra, 824232292Sbz struct in6_ifaddr *ia, int flags, struct in6_multi **in6m_sol) 825232292Sbz{ 826232292Sbz char ip6buf[INET6_ADDRSTRLEN]; 827232292Sbz struct sockaddr_in6 mltaddr, mltmask; 828232292Sbz struct in6_addr llsol; 829232292Sbz struct in6_multi_mship *imm; 830232292Sbz struct rtentry *rt; 831232292Sbz int delay, error; 832232292Sbz 833232292Sbz KASSERT(in6m_sol != NULL, ("%s: in6m_sol is NULL", __func__)); 834232292Sbz 835232292Sbz /* Join solicited multicast addr for new host id. */ 836232292Sbz bzero(&llsol, sizeof(struct in6_addr)); 837232292Sbz llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL; 838232292Sbz llsol.s6_addr32[1] = 0; 839232292Sbz llsol.s6_addr32[2] = htonl(1); 840232292Sbz llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3]; 841232292Sbz llsol.s6_addr8[12] = 0xff; 842232292Sbz if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) { 843232292Sbz /* XXX: should not happen */ 844232292Sbz log(LOG_ERR, "%s: in6_setscope failed\n", __func__); 845232292Sbz goto cleanup; 846232292Sbz } 847232292Sbz delay = 0; 848232292Sbz if ((flags & IN6_IFAUPDATE_DADDELAY)) { 849232292Sbz /* 850232292Sbz * We need a random delay for DAD on the address being 851232292Sbz * configured. It also means delaying transmission of the 852232292Sbz * corresponding MLD report to avoid report collision. 853232292Sbz * [RFC 4861, Section 6.3.7] 854232292Sbz */ 855232292Sbz delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz); 856232292Sbz } 857232292Sbz imm = in6_joingroup(ifp, &llsol, &error, delay); 858232292Sbz if (imm == NULL) { 859232292Sbz nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " 860232292Sbz "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &llsol), 861232292Sbz if_name(ifp), error)); 862232292Sbz goto cleanup; 863232292Sbz } 864232292Sbz LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 865232292Sbz *in6m_sol = imm->i6mm_maddr; 866232292Sbz 867232292Sbz bzero(&mltmask, sizeof(mltmask)); 868232292Sbz mltmask.sin6_len = sizeof(struct sockaddr_in6); 869232292Sbz mltmask.sin6_family = AF_INET6; 870232292Sbz mltmask.sin6_addr = in6mask32; 871232292Sbz#define MLTMASK_LEN 4 /* mltmask's masklen (=32bit=4octet) */ 872232292Sbz 873232292Sbz /* 874232292Sbz * Join link-local all-nodes address. 875232292Sbz */ 876232292Sbz bzero(&mltaddr, sizeof(mltaddr)); 877232292Sbz mltaddr.sin6_len = sizeof(struct sockaddr_in6); 878232292Sbz mltaddr.sin6_family = AF_INET6; 879232292Sbz mltaddr.sin6_addr = in6addr_linklocal_allnodes; 880232292Sbz if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) 881232292Sbz goto cleanup; /* XXX: should not fail */ 882232292Sbz 883232292Sbz /* 884232292Sbz * XXX: do we really need this automatic routes? We should probably 885232292Sbz * reconsider this stuff. Most applications actually do not need the 886232292Sbz * routes, since they usually specify the outgoing interface. 887232292Sbz */ 888232292Sbz rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); 889232292Sbz if (rt != NULL) { 890232292Sbz /* XXX: only works in !SCOPEDROUTING case. */ 891232292Sbz if (memcmp(&mltaddr.sin6_addr, 892232292Sbz &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, 893232292Sbz MLTMASK_LEN)) { 894232292Sbz RTFREE_LOCKED(rt); 895232292Sbz rt = NULL; 896232292Sbz } 897232292Sbz } 898232292Sbz if (rt == NULL) { 899232292Sbz error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, 900232292Sbz (struct sockaddr *)&ia->ia_addr, 901232292Sbz (struct sockaddr *)&mltmask, RTF_UP, 902232292Sbz (struct rtentry **)0, RT_DEFAULT_FIB); 903232292Sbz if (error) 904232292Sbz goto cleanup; 905232292Sbz } else 906232292Sbz RTFREE_LOCKED(rt); 907232292Sbz 908232292Sbz imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0); 909232292Sbz if (imm == NULL) { 910232292Sbz nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " 911232292Sbz "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, 912232292Sbz &mltaddr.sin6_addr), if_name(ifp), error)); 913232292Sbz goto cleanup; 914232292Sbz } 915232292Sbz LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 916232292Sbz 917232292Sbz /* 918232292Sbz * Join node information group address. 919232292Sbz */ 920232292Sbz delay = 0; 921232292Sbz if ((flags & IN6_IFAUPDATE_DADDELAY)) { 922232292Sbz /* 923232292Sbz * The spec does not say anything about delay for this group, 924232292Sbz * but the same logic should apply. 925232292Sbz */ 926232292Sbz delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz); 927232292Sbz } 928232292Sbz if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) { 929232292Sbz /* XXX jinmei */ 930232292Sbz imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay); 931232292Sbz if (imm == NULL) 932232292Sbz nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " 933232292Sbz "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, 934232292Sbz &mltaddr.sin6_addr), if_name(ifp), error)); 935232292Sbz /* XXX not very fatal, go on... */ 936232292Sbz else 937232292Sbz LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 938232292Sbz } 939252021Shrs if (V_icmp6_nodeinfo_oldmcprefix && 940252021Shrs in6_nigroup_oldmcprefix(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) { 941252021Shrs imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay); 942252021Shrs if (imm == NULL) 943252021Shrs nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " 944252021Shrs "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, 945252021Shrs &mltaddr.sin6_addr), if_name(ifp), error)); 946252021Shrs /* XXX not very fatal, go on... */ 947252021Shrs else 948252021Shrs LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 949252021Shrs } 950232292Sbz 951232292Sbz /* 952232292Sbz * Join interface-local all-nodes address. 953232292Sbz * (ff01::1%ifN, and ff01::%ifN/32) 954232292Sbz */ 955232292Sbz mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 956232292Sbz if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) 957232292Sbz goto cleanup; /* XXX: should not fail */ 958232292Sbz /* XXX: again, do we really need the route? */ 959232292Sbz rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); 960232292Sbz if (rt != NULL) { 961232292Sbz if (memcmp(&mltaddr.sin6_addr, 962232292Sbz &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, 963232292Sbz MLTMASK_LEN)) { 964232292Sbz RTFREE_LOCKED(rt); 965232292Sbz rt = NULL; 966232292Sbz } 967232292Sbz } 968232292Sbz if (rt == NULL) { 969232292Sbz error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, 970232292Sbz (struct sockaddr *)&ia->ia_addr, 971232292Sbz (struct sockaddr *)&mltmask, RTF_UP, 972232292Sbz (struct rtentry **)0, RT_DEFAULT_FIB); 973232292Sbz if (error) 974232292Sbz goto cleanup; 975232292Sbz } else 976232292Sbz RTFREE_LOCKED(rt); 977232292Sbz 978232292Sbz imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0); 979232292Sbz if (imm == NULL) { 980232292Sbz nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " 981232292Sbz "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, 982232292Sbz &mltaddr.sin6_addr), if_name(ifp), error)); 983232292Sbz goto cleanup; 984232292Sbz } 985232292Sbz LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 986232292Sbz#undef MLTMASK_LEN 987232292Sbz 988232292Sbzcleanup: 989232292Sbz return (error); 990232292Sbz} 991232292Sbz 992232292Sbz/* 99378064Sume * Update parameters of an IPv6 interface address. 99478064Sume * If necessary, a new entry is created and linked into address chains. 99578064Sume * This function is separated from in6_control(). 99678064Sume * XXX: should this be performed under splnet()? 99778064Sume */ 99878064Sumeint 999171259Sdelphijin6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, 1000171259Sdelphij struct in6_ifaddr *ia, int flags) 100178064Sume{ 100278064Sume int error = 0, hostIsNew = 0, plen = -1; 100378064Sume struct sockaddr_in6 dst6; 100478064Sume struct in6_addrlifetime *lt; 1005151539Ssuz struct in6_multi *in6m_sol; 1006151539Ssuz int delay; 1007165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 100878064Sume 100978064Sume /* Validate parameters */ 101078064Sume if (ifp == NULL || ifra == NULL) /* this maybe redundant */ 1011120856Sume return (EINVAL); 101278064Sume 101378064Sume /* 101478064Sume * The destination address for a p2p link must have a family 101578064Sume * of AF_UNSPEC or AF_INET6. 101678064Sume */ 101778064Sume if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && 101878064Sume ifra->ifra_dstaddr.sin6_family != AF_INET6 && 101978064Sume ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) 1020120856Sume return (EAFNOSUPPORT); 102178064Sume /* 102278064Sume * validate ifra_prefixmask. don't check sin6_family, netmask 102378064Sume * does not carry fields other than sin6_len. 102478064Sume */ 102578064Sume if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6)) 1026120856Sume return (EINVAL); 102778064Sume /* 102878064Sume * Because the IPv6 address architecture is classless, we require 102978064Sume * users to specify a (non 0) prefix length (mask) for a new address. 103078064Sume * We also require the prefix (when specified) mask is valid, and thus 103178064Sume * reject a non-consecutive mask. 103278064Sume */ 103378064Sume if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0) 1034120856Sume return (EINVAL); 103578064Sume if (ifra->ifra_prefixmask.sin6_len != 0) { 103678064Sume plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 1037120891Sume (u_char *)&ifra->ifra_prefixmask + 1038120891Sume ifra->ifra_prefixmask.sin6_len); 103978064Sume if (plen <= 0) 1040120856Sume return (EINVAL); 1041120891Sume } else { 104262587Sitojun /* 104395023Ssuz * In this case, ia must not be NULL. We just use its prefix 104478064Sume * length. 104562587Sitojun */ 104678064Sume plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 104778064Sume } 104878064Sume /* 104978064Sume * If the destination address on a p2p interface is specified, 105078064Sume * and the address is a scoped one, validate/set the scope 105178064Sume * zone identifier. 105278064Sume */ 105378064Sume dst6 = ifra->ifra_dstaddr; 1054120891Sume if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 && 105578064Sume (dst6.sin6_family == AF_INET6)) { 1056148385Sume struct in6_addr in6_tmp; 1057126552Sume u_int32_t zoneid; 105878064Sume 1059148385Sume in6_tmp = dst6.sin6_addr; 1060148385Sume if (in6_setscope(&in6_tmp, ifp, &zoneid)) 1061148385Sume return (EINVAL); /* XXX: should be impossible */ 1062148385Sume 1063148385Sume if (dst6.sin6_scope_id != 0) { 1064148385Sume if (dst6.sin6_scope_id != zoneid) 1065148385Sume return (EINVAL); 1066148385Sume } else /* user omit to specify the ID. */ 1067126552Sume dst6.sin6_scope_id = zoneid; 1068148385Sume 1069148385Sume /* convert into the internal form */ 1070148385Sume if (sa6_embedscope(&dst6, 0)) 1071148385Sume return (EINVAL); /* XXX: should be impossible */ 107278064Sume } 107378064Sume /* 107478064Sume * The destination address can be specified only for a p2p or a 107578064Sume * loopback interface. If specified, the corresponding prefix length 107678064Sume * must be 128. 107778064Sume */ 107878064Sume if (ifra->ifra_dstaddr.sin6_family == AF_INET6) { 107978064Sume if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) { 1080126552Sume /* XXX: noisy message */ 1081122059Sume nd6log((LOG_INFO, "in6_update_ifa: a destination can " 1082122059Sume "be specified for a p2p or a loopback IF only\n")); 1083120856Sume return (EINVAL); 108478064Sume } 108578064Sume if (plen != 128) { 1086122059Sume nd6log((LOG_INFO, "in6_update_ifa: prefixlen should " 1087122059Sume "be 128 when dstaddr is specified\n")); 1088120856Sume return (EINVAL); 108978064Sume } 109078064Sume } 109178064Sume /* lifetime consistency check */ 109278064Sume lt = &ifra->ifra_lifetime; 1093151539Ssuz if (lt->ia6t_pltime > lt->ia6t_vltime) 1094151539Ssuz return (EINVAL); 109578064Sume if (lt->ia6t_vltime == 0) { 109662587Sitojun /* 109778064Sume * the following log might be noisy, but this is a typical 109878064Sume * configuration mistake or a tool's bug. 109962587Sitojun */ 1100122059Sume nd6log((LOG_INFO, 110178064Sume "in6_update_ifa: valid lifetime is 0 for %s\n", 1102165118Sbz ip6_sprintf(ip6buf, &ifra->ifra_addr.sin6_addr))); 1103151539Ssuz 1104151539Ssuz if (ia == NULL) 1105151539Ssuz return (0); /* there's nothing to do */ 110678064Sume } 110762587Sitojun 110878064Sume /* 110978064Sume * If this is a new address, allocate a new ifaddr and link it 111078064Sume * into chains. 111178064Sume */ 111278064Sume if (ia == NULL) { 111378064Sume hostIsNew = 1; 111479763Sume /* 111579763Sume * When in6_update_ifa() is called in a process of a received 1116120891Sume * RA, it is called under an interrupt context. So, we should 1117120891Sume * call malloc with M_NOWAIT. 111879763Sume */ 1119120891Sume ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR, 1120120891Sume M_NOWAIT); 112178064Sume if (ia == NULL) 112278064Sume return (ENOBUFS); 112378064Sume bzero((caddr_t)ia, sizeof(*ia)); 1124194602Srwatson ifa_init(&ia->ia_ifa); 1125170202Sjinmei LIST_INIT(&ia->ia6_memberships); 1126151539Ssuz /* Initialize the address and masks, and put time stamp */ 112778064Sume ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 112878064Sume ia->ia_addr.sin6_family = AF_INET6; 112978064Sume ia->ia_addr.sin6_len = sizeof(ia->ia_addr); 1130151539Ssuz ia->ia6_createtime = time_second; 113178064Sume if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { 113278064Sume /* 113378064Sume * XXX: some functions expect that ifa_dstaddr is not 113478064Sume * NULL for p2p interfaces. 113578064Sume */ 1136120891Sume ia->ia_ifa.ifa_dstaddr = 1137120891Sume (struct sockaddr *)&ia->ia_dstaddr; 113878064Sume } else { 113978064Sume ia->ia_ifa.ifa_dstaddr = NULL; 114053541Sshin } 1141108033Shsu ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; 114278064Sume ia->ia_ifp = ifp; 1143194760Srwatson ifa_ref(&ia->ia_ifa); /* if_addrhead */ 1144233200Sjhb IF_ADDR_WLOCK(ifp); 1145191340Srwatson TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); 1146233200Sjhb IF_ADDR_WUNLOCK(ifp); 1147194907Srwatson 1148194971Srwatson ifa_ref(&ia->ia_ifa); /* in6_ifaddrhead */ 1149194971Srwatson IN6_IFADDR_WLOCK(); 1150194907Srwatson TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link); 1151194971Srwatson IN6_IFADDR_WUNLOCK(); 115278064Sume } 115378064Sume 1154151539Ssuz /* update timestamp */ 1155151539Ssuz ia->ia6_updatetime = time_second; 1156151539Ssuz 115778064Sume /* set prefix mask */ 115878064Sume if (ifra->ifra_prefixmask.sin6_len) { 115978064Sume /* 116078064Sume * We prohibit changing the prefix length of an existing 116178064Sume * address, because 116278064Sume * + such an operation should be rare in IPv6, and 116378064Sume * + the operation would confuse prefix management. 116478064Sume */ 116578064Sume if (ia->ia_prefixmask.sin6_len && 116678064Sume in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) { 1167122059Sume nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an" 116878064Sume " existing (%s) address should not be changed\n", 1169165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); 117078064Sume error = EINVAL; 117178064Sume goto unlink; 117253541Sshin } 117378064Sume ia->ia_prefixmask = ifra->ifra_prefixmask; 117478064Sume } 117578064Sume 117678064Sume /* 117778064Sume * If a new destination address is specified, scrub the old one and 117878064Sume * install the new destination. Note that the interface must be 1179120891Sume * p2p or loopback (see the check above.) 118078064Sume */ 118178064Sume if (dst6.sin6_family == AF_INET6 && 1182120891Sume !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) { 118378064Sume int e; 118478064Sume 118578064Sume if ((ia->ia_flags & IFA_ROUTE) != 0 && 1186120891Sume (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) { 1187122059Sume nd6log((LOG_ERR, "in6_update_ifa: failed to remove " 118878064Sume "a route to the old destination: %s\n", 1189165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); 119078064Sume /* proceed anyway... */ 1191120891Sume } else 119278064Sume ia->ia_flags &= ~IFA_ROUTE; 119378064Sume ia->ia_dstaddr = dst6; 119478064Sume } 119553541Sshin 1196148385Sume /* 1197148385Sume * Set lifetimes. We do not refer to ia6t_expire and ia6t_preferred 1198148385Sume * to see if the address is deprecated or invalidated, but initialize 1199148385Sume * these members for applications. 1200148385Sume */ 1201148385Sume ia->ia6_lifetime = ifra->ifra_lifetime; 1202148385Sume if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 1203148385Sume ia->ia6_lifetime.ia6t_expire = 1204148385Sume time_second + ia->ia6_lifetime.ia6t_vltime; 1205148385Sume } else 1206148385Sume ia->ia6_lifetime.ia6t_expire = 0; 1207148385Sume if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 1208148385Sume ia->ia6_lifetime.ia6t_preferred = 1209148385Sume time_second + ia->ia6_lifetime.ia6t_pltime; 1210148385Sume } else 1211148385Sume ia->ia6_lifetime.ia6t_preferred = 0; 1212148385Sume 121378064Sume /* reset the interface and routing table appropriately. */ 121478064Sume if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) 121578064Sume goto unlink; 121678064Sume 121778064Sume /* 1218148385Sume * configure address flags. 1219148385Sume */ 1220148385Sume ia->ia6_flags = ifra->ifra_flags; 1221148385Sume /* 1222148385Sume * backward compatibility - if IN6_IFF_DEPRECATED is set from the 1223148385Sume * userland, make it deprecated. 1224148385Sume */ 1225148385Sume if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) { 1226148385Sume ia->ia6_lifetime.ia6t_pltime = 0; 1227148385Sume ia->ia6_lifetime.ia6t_preferred = time_second; 1228148385Sume } 1229148385Sume /* 1230151539Ssuz * Make the address tentative before joining multicast addresses, 1231151539Ssuz * so that corresponding MLD responses would not have a tentative 1232151539Ssuz * source address. 1233148385Sume */ 1234151539Ssuz ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /* safety */ 1235151539Ssuz if (hostIsNew && in6if_do_dad(ifp)) 1236148385Sume ia->ia6_flags |= IN6_IFF_TENTATIVE; 1237148385Sume 1238197138Shrs /* DAD should be performed after ND6_IFF_IFDISABLED is cleared. */ 1239197138Shrs if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) 1240197138Shrs ia->ia6_flags |= IN6_IFF_TENTATIVE; 1241197138Shrs 1242148385Sume /* 1243148385Sume * We are done if we have simply modified an existing address. 1244148385Sume */ 1245148385Sume if (!hostIsNew) 1246148385Sume return (error); 1247148385Sume 1248148385Sume /* 124978064Sume * Beyond this point, we should call in6_purgeaddr upon an error, 1250120891Sume * not just go to unlink. 125178064Sume */ 125278064Sume 1253232292Sbz /* Join necessary multicast groups. */ 1254151539Ssuz in6m_sol = NULL; 125578064Sume if ((ifp->if_flags & IFF_MULTICAST) != 0) { 1256232292Sbz error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol); 1257232292Sbz if (error) 1258148385Sume goto cleanup; 125978064Sume } 126053541Sshin 1261151539Ssuz /* 1262151539Ssuz * Perform DAD, if needed. 1263232292Sbz * XXX It may be of use, if we can administratively disable DAD. 1264151539Ssuz */ 1265194760Srwatson if (in6if_do_dad(ifp) && ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) && 1266151539Ssuz (ia->ia6_flags & IN6_IFF_TENTATIVE)) 1267151539Ssuz { 1268151539Ssuz int mindelay, maxdelay; 1269151539Ssuz 1270151539Ssuz delay = 0; 1271151539Ssuz if ((flags & IN6_IFAUPDATE_DADDELAY)) { 1272151539Ssuz /* 1273151539Ssuz * We need to impose a delay before sending an NS 1274151539Ssuz * for DAD. Check if we also needed a delay for the 1275151539Ssuz * corresponding MLD message. If we did, the delay 1276151539Ssuz * should be larger than the MLD delay (this could be 1277151539Ssuz * relaxed a bit, but this simple logic is at least 1278151539Ssuz * safe). 1279191672Sbms * XXX: Break data hiding guidelines and look at 1280191672Sbms * state for the solicited multicast group. 1281151539Ssuz */ 1282151539Ssuz mindelay = 0; 1283151539Ssuz if (in6m_sol != NULL && 1284191672Sbms in6m_sol->in6m_state == MLD_REPORTING_MEMBER) { 1285151539Ssuz mindelay = in6m_sol->in6m_timer; 1286151539Ssuz } 1287151539Ssuz maxdelay = MAX_RTR_SOLICITATION_DELAY * hz; 1288151539Ssuz if (maxdelay - mindelay == 0) 1289151539Ssuz delay = 0; 1290151539Ssuz else { 1291151539Ssuz delay = 1292151539Ssuz (arc4random() % (maxdelay - mindelay)) + 1293151539Ssuz mindelay; 1294151539Ssuz } 1295151539Ssuz } 1296151539Ssuz nd6_dad_start((struct ifaddr *)ia, delay); 1297151539Ssuz } 1298151539Ssuz 1299194760Srwatson KASSERT(hostIsNew, ("in6_update_ifa: !hostIsNew")); 1300194760Srwatson ifa_free(&ia->ia_ifa); 1301120856Sume return (error); 130278064Sume 130378064Sume unlink: 130478064Sume /* 130578064Sume * XXX: if a change of an existing address failed, keep the entry 130678064Sume * anyway. 130778064Sume */ 1308194760Srwatson if (hostIsNew) { 1309194943Srwatson in6_unlink_ifa(ia, ifp); 1310194760Srwatson ifa_free(&ia->ia_ifa); 1311194760Srwatson } 1312120856Sume return (error); 1313148385Sume 1314148385Sume cleanup: 1315194760Srwatson KASSERT(hostIsNew, ("in6_update_ifa: cleanup: !hostIsNew")); 1316194760Srwatson ifa_free(&ia->ia_ifa); 1317148385Sume in6_purgeaddr(&ia->ia_ifa); 1318148385Sume return error; 131953541Sshin} 132053541Sshin 1321232292Sbz/* 1322232292Sbz * Leave multicast groups. Factored out from in6_purgeaddr(). 1323232292Sbz * This entire work should only be done once, for the default FIB. 1324232292Sbz */ 1325232292Sbzstatic int 1326232292Sbzin6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0) 132762587Sitojun{ 1328232292Sbz struct sockaddr_in6 mltaddr, mltmask; 1329170202Sjinmei struct in6_multi_mship *imm; 1330192282Sqingli struct rtentry *rt; 1331237945Sdelphij struct sockaddr_in6 sin6; 1332232292Sbz int error; 133362587Sitojun 1334192282Sqingli /* 1335232292Sbz * Leave from multicast groups we have joined for the interface. 1336192282Sqingli */ 1337233046Sjhb while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { 1338170202Sjinmei LIST_REMOVE(imm, i6mm_chain); 1339170202Sjinmei in6_leavegroup(imm); 134062587Sitojun } 134162587Sitojun 1342192282Sqingli /* 1343232292Sbz * Remove the link-local all-nodes address. 1344192282Sqingli */ 1345192282Sqingli bzero(&mltmask, sizeof(mltmask)); 1346192282Sqingli mltmask.sin6_len = sizeof(struct sockaddr_in6); 1347192282Sqingli mltmask.sin6_family = AF_INET6; 1348192282Sqingli mltmask.sin6_addr = in6mask32; 1349192282Sqingli 1350192282Sqingli bzero(&mltaddr, sizeof(mltaddr)); 1351192282Sqingli mltaddr.sin6_len = sizeof(struct sockaddr_in6); 1352192282Sqingli mltaddr.sin6_family = AF_INET6; 1353192282Sqingli mltaddr.sin6_addr = in6addr_linklocal_allnodes; 1354192282Sqingli 1355231319Sbz if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) 1356232292Sbz return (error); 1357192282Sqingli 1358237945Sdelphij /* 1359237945Sdelphij * As for the mltaddr above, proactively prepare the sin6 to avoid 1360237945Sdelphij * rtentry un- and re-locking. 1361237945Sdelphij */ 1362237945Sdelphij if (ifa0 != NULL) { 1363237945Sdelphij bzero(&sin6, sizeof(sin6)); 1364237945Sdelphij sin6.sin6_len = sizeof(sin6); 1365237945Sdelphij sin6.sin6_family = AF_INET6; 1366240310Sglebius memcpy(&sin6.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr, 1367237945Sdelphij sizeof(sin6.sin6_addr)); 1368238476Sbz error = in6_setscope(&sin6.sin6_addr, ifa0->ifa_ifp, NULL); 1369238476Sbz if (error != 0) 1370238476Sbz return (error); 1371237945Sdelphij } 1372237945Sdelphij 1373232292Sbz rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); 1374192282Sqingli if (rt != NULL && rt->rt_gateway != NULL && 1375240310Sglebius (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 1376192282Sqingli &ia->ia_addr.sin6_addr, 1377192282Sqingli sizeof(ia->ia_addr.sin6_addr)) == 0)) { 1378240310Sglebius /* 1379232292Sbz * If no more IPv6 address exists on this interface then 1380232292Sbz * remove the multicast address route. 1381192282Sqingli */ 1382192282Sqingli if (ifa0 == NULL) { 1383240310Sglebius memcpy(&mltaddr.sin6_addr, 1384240310Sglebius &satosin6(rt_key(rt))->sin6_addr, 1385240310Sglebius sizeof(mltaddr.sin6_addr)); 1386192282Sqingli RTFREE_LOCKED(rt); 1387232292Sbz error = in6_rtrequest(RTM_DELETE, 1388232292Sbz (struct sockaddr *)&mltaddr, 1389232292Sbz (struct sockaddr *)&ia->ia_addr, 1390232292Sbz (struct sockaddr *)&mltmask, RTF_UP, 1391232292Sbz (struct rtentry **)0, RT_DEFAULT_FIB); 1392192282Sqingli if (error) 1393232292Sbz log(LOG_INFO, "%s: link-local all-nodes " 1394232292Sbz "multicast address deletion error\n", 1395232292Sbz __func__); 1396192282Sqingli } else { 1397192282Sqingli /* 1398232292Sbz * Replace the gateway of the route. 1399192282Sqingli */ 1400237945Sdelphij memcpy(rt->rt_gateway, &sin6, sizeof(sin6)); 1401192282Sqingli RTFREE_LOCKED(rt); 1402192282Sqingli } 1403192282Sqingli } else { 1404192282Sqingli if (rt != NULL) 1405192282Sqingli RTFREE_LOCKED(rt); 1406192282Sqingli } 1407192282Sqingli 1408192282Sqingli /* 1409232292Sbz * Remove the node-local all-nodes address. 1410192282Sqingli */ 1411192282Sqingli mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 1412232292Sbz if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) 1413232292Sbz return (error); 1414192282Sqingli 1415232292Sbz rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); 1416192282Sqingli if (rt != NULL && rt->rt_gateway != NULL && 1417240310Sglebius (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 1418192282Sqingli &ia->ia_addr.sin6_addr, 1419192282Sqingli sizeof(ia->ia_addr.sin6_addr)) == 0)) { 1420240310Sglebius /* 1421232292Sbz * If no more IPv6 address exists on this interface then 1422232292Sbz * remove the multicast address route. 1423192282Sqingli */ 1424192282Sqingli if (ifa0 == NULL) { 1425240310Sglebius memcpy(&mltaddr.sin6_addr, 1426240310Sglebius &satosin6(rt_key(rt))->sin6_addr, 1427240310Sglebius sizeof(mltaddr.sin6_addr)); 1428192282Sqingli 1429192282Sqingli RTFREE_LOCKED(rt); 1430232292Sbz error = in6_rtrequest(RTM_DELETE, 1431232292Sbz (struct sockaddr *)&mltaddr, 1432232292Sbz (struct sockaddr *)&ia->ia_addr, 1433232292Sbz (struct sockaddr *)&mltmask, RTF_UP, 1434232292Sbz (struct rtentry **)0, RT_DEFAULT_FIB); 1435192282Sqingli if (error) 1436232292Sbz log(LOG_INFO, "%s: node-local all-nodes" 1437232292Sbz "multicast address deletion error\n", 1438232292Sbz __func__); 1439192282Sqingli } else { 1440192282Sqingli /* 1441232292Sbz * Replace the gateway of the route. 1442192282Sqingli */ 1443237945Sdelphij memcpy(rt->rt_gateway, &sin6, sizeof(sin6)); 1444192282Sqingli RTFREE_LOCKED(rt); 1445192282Sqingli } 1446192282Sqingli } else { 1447192282Sqingli if (rt != NULL) 1448192282Sqingli RTFREE_LOCKED(rt); 1449192282Sqingli } 1450192282Sqingli 1451232292Sbz return (0); 1452232292Sbz} 1453232292Sbz 1454232292Sbzvoid 1455232292Sbzin6_purgeaddr(struct ifaddr *ifa) 1456232292Sbz{ 1457232292Sbz struct ifnet *ifp = ifa->ifa_ifp; 1458232292Sbz struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; 1459232292Sbz int plen, error; 1460232292Sbz struct ifaddr *ifa0; 1461232292Sbz 1462232292Sbz /* 1463232292Sbz * find another IPv6 address as the gateway for the 1464232292Sbz * link-local and node-local all-nodes multicast 1465232292Sbz * address routes 1466232292Sbz */ 1467233200Sjhb IF_ADDR_RLOCK(ifp); 1468232292Sbz TAILQ_FOREACH(ifa0, &ifp->if_addrhead, ifa_link) { 1469232292Sbz if ((ifa0->ifa_addr->sa_family != AF_INET6) || 1470232292Sbz memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr, 1471240310Sglebius &ia->ia_addr.sin6_addr, sizeof(struct in6_addr)) == 0) 1472232292Sbz continue; 1473232292Sbz else 1474232292Sbz break; 1475232292Sbz } 1476231324Sbz if (ifa0 != NULL) 1477232292Sbz ifa_ref(ifa0); 1478233200Sjhb IF_ADDR_RUNLOCK(ifp); 1479232292Sbz 1480232292Sbz /* 1481232292Sbz * Remove the loopback route to the interface address. 1482240310Sglebius * The check for the current setting of "nd6_useloopback" 1483232292Sbz * is not needed. 1484232292Sbz */ 1485232292Sbz if (ia->ia_flags & IFA_RTSELF) { 1486232292Sbz error = ifa_del_loopback_route((struct ifaddr *)ia, 1487240310Sglebius (struct sockaddr *)&ia->ia_addr); 1488232292Sbz if (error == 0) 1489232292Sbz ia->ia_flags &= ~IFA_RTSELF; 1490232292Sbz } 1491232292Sbz 1492232292Sbz /* stop DAD processing */ 1493232292Sbz nd6_dad_stop(ifa); 1494232292Sbz 1495232292Sbz /* Remove local address entry from lltable. */ 1496232292Sbz in6_ifremloop(ifa); 1497232292Sbz 1498232292Sbz /* Leave multicast groups. */ 1499232292Sbz error = in6_purgeaddr_mc(ifp, ia, ifa0); 1500232292Sbz 1501232292Sbz if (ifa0 != NULL) 1502231324Sbz ifa_free(ifa0); 1503192282Sqingli 1504192282Sqingli plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ 1505192282Sqingli if ((ia->ia_flags & IFA_ROUTE) && plen == 128) { 1506232292Sbz error = rtinit(&(ia->ia_ifa), RTM_DELETE, ia->ia_flags | 1507232292Sbz (ia->ia_dstaddr.sin6_family == AF_INET6) ? RTF_HOST : 0); 1508192282Sqingli if (error != 0) 1509232292Sbz log(LOG_INFO, "%s: err=%d, destination address delete " 1510232292Sbz "failed\n", __func__, error); 1511192282Sqingli ia->ia_flags &= ~IFA_ROUTE; 1512192282Sqingli } 1513192282Sqingli 151478064Sume in6_unlink_ifa(ia, ifp); 151578064Sume} 151678064Sume 151778064Sumestatic void 1518171259Sdelphijin6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) 151978064Sume{ 152078064Sume int s = splnet(); 152178064Sume 1522233200Sjhb IF_ADDR_WLOCK(ifp); 1523191340Srwatson TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); 1524233200Sjhb IF_ADDR_WUNLOCK(ifp); 1525194760Srwatson ifa_free(&ia->ia_ifa); /* if_addrhead */ 152662587Sitojun 1527195102Srwatson /* 1528195102Srwatson * Defer the release of what might be the last reference to the 1529195102Srwatson * in6_ifaddr so that it can't be freed before the remainder of the 1530195102Srwatson * cleanup. 1531195102Srwatson */ 1532194971Srwatson IN6_IFADDR_WLOCK(); 1533194907Srwatson TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link); 1534194971Srwatson IN6_IFADDR_WUNLOCK(); 153562587Sitojun 153662587Sitojun /* 1537151915Ssuz * Release the reference to the base prefix. There should be a 1538151915Ssuz * positive reference. 153962587Sitojun */ 1540194907Srwatson if (ia->ia6_ndpr == NULL) { 1541151915Ssuz nd6log((LOG_NOTICE, 1542151915Ssuz "in6_unlink_ifa: autoconf'ed address " 1543194907Srwatson "%p has no prefix\n", ia)); 1544151915Ssuz } else { 1545194907Srwatson ia->ia6_ndpr->ndpr_refcnt--; 1546194907Srwatson ia->ia6_ndpr = NULL; 1547151915Ssuz } 154862587Sitojun 1549151915Ssuz /* 1550151915Ssuz * Also, if the address being removed is autoconf'ed, call 1551151915Ssuz * pfxlist_onlink_check() since the release might affect the status of 1552171260Sdelphij * other (detached) addresses. 1553151915Ssuz */ 1554194907Srwatson if ((ia->ia6_flags & IN6_IFF_AUTOCONF)) { 155578064Sume pfxlist_onlink_check(); 155662587Sitojun } 1557195102Srwatson ifa_free(&ia->ia_ifa); /* in6_ifaddrhead */ 155878064Sume splx(s); 155962587Sitojun} 156062587Sitojun 156178064Sumevoid 1562171259Sdelphijin6_purgeif(struct ifnet *ifp) 156378064Sume{ 156478064Sume struct ifaddr *ifa, *nifa; 156578064Sume 1566191340Srwatson TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { 156778064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 156878064Sume continue; 156978064Sume in6_purgeaddr(ifa); 157078064Sume } 157178064Sume 157278064Sume in6_ifdetach(ifp); 157378064Sume} 157478064Sume 157553541Sshin/* 157653541Sshin * SIOC[GAD]LIFADDR. 157762744Sgrog * SIOCGLIFADDR: get first address. (?) 157853541Sshin * SIOCGLIFADDR with IFLR_PREFIX: 157953541Sshin * get first address that matches the specified prefix. 158053541Sshin * SIOCALIFADDR: add the specified address. 158153541Sshin * SIOCALIFADDR with IFLR_PREFIX: 158253541Sshin * add the specified prefix, filling hostid part from 158353541Sshin * the first link-local address. prefixlen must be <= 64. 158453541Sshin * SIOCDLIFADDR: delete the specified address. 158553541Sshin * SIOCDLIFADDR with IFLR_PREFIX: 158653541Sshin * delete the first address that matches the specified prefix. 158753541Sshin * return values: 158853541Sshin * EINVAL on invalid parameters 158953541Sshin * EADDRNOTAVAIL on prefix match failed/specified address not found 159053541Sshin * other values may be returned from in6_ioctl() 159153541Sshin * 159253541Sshin * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64. 159353541Sshin * this is to accomodate address naming scheme other than RFC2374, 159453541Sshin * in the future. 159553541Sshin * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374 159653541Sshin * address encoding scheme. (see figure on page 8) 159753541Sshin */ 159853541Sshinstatic int 1599171259Sdelphijin6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data, 1600171259Sdelphij struct ifnet *ifp, struct thread *td) 160153541Sshin{ 160253541Sshin struct if_laddrreq *iflr = (struct if_laddrreq *)data; 160353541Sshin struct ifaddr *ifa; 160462587Sitojun struct sockaddr *sa; 160553541Sshin 160653541Sshin /* sanity checks */ 160753541Sshin if (!data || !ifp) { 160853541Sshin panic("invalid argument to in6_lifaddr_ioctl"); 1609120891Sume /* NOTREACHED */ 161053541Sshin } 161153541Sshin 161253541Sshin switch (cmd) { 161353541Sshin case SIOCGLIFADDR: 161453541Sshin /* address must be specified on GET with IFLR_PREFIX */ 161553541Sshin if ((iflr->flags & IFLR_PREFIX) == 0) 161653541Sshin break; 161795023Ssuz /* FALLTHROUGH */ 161853541Sshin case SIOCALIFADDR: 161953541Sshin case SIOCDLIFADDR: 162053541Sshin /* address must be specified on ADD and DELETE */ 162162587Sitojun sa = (struct sockaddr *)&iflr->addr; 162262587Sitojun if (sa->sa_family != AF_INET6) 162353541Sshin return EINVAL; 162462587Sitojun if (sa->sa_len != sizeof(struct sockaddr_in6)) 162553541Sshin return EINVAL; 162653541Sshin /* XXX need improvement */ 162762587Sitojun sa = (struct sockaddr *)&iflr->dstaddr; 162862587Sitojun if (sa->sa_family && sa->sa_family != AF_INET6) 162953541Sshin return EINVAL; 163062587Sitojun if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6)) 163153541Sshin return EINVAL; 163253541Sshin break; 163395023Ssuz default: /* shouldn't happen */ 163462587Sitojun#if 0 163562587Sitojun panic("invalid cmd to in6_lifaddr_ioctl"); 163695023Ssuz /* NOTREACHED */ 163762587Sitojun#else 163853541Sshin return EOPNOTSUPP; 163962587Sitojun#endif 164053541Sshin } 164153541Sshin if (sizeof(struct in6_addr) * 8 < iflr->prefixlen) 164253541Sshin return EINVAL; 164353541Sshin 164453541Sshin switch (cmd) { 164553541Sshin case SIOCALIFADDR: 164653541Sshin { 164753541Sshin struct in6_aliasreq ifra; 164853541Sshin struct in6_addr *hostid = NULL; 164953541Sshin int prefixlen; 165053541Sshin 1651194760Srwatson ifa = NULL; 165253541Sshin if ((iflr->flags & IFLR_PREFIX) != 0) { 165353541Sshin struct sockaddr_in6 *sin6; 165453541Sshin 165553541Sshin /* 165653541Sshin * hostid is to fill in the hostid part of the 165753541Sshin * address. hostid points to the first link-local 165853541Sshin * address attached to the interface. 165953541Sshin */ 166062587Sitojun ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); 166153541Sshin if (!ifa) 166253541Sshin return EADDRNOTAVAIL; 166353541Sshin hostid = IFA_IN6(ifa); 166453541Sshin 1665171260Sdelphij /* prefixlen must be <= 64. */ 1666236826Sbz if (64 < iflr->prefixlen) { 1667236826Sbz if (ifa != NULL) 1668236826Sbz ifa_free(ifa); 166953541Sshin return EINVAL; 1670236826Sbz } 167153541Sshin prefixlen = iflr->prefixlen; 167253541Sshin 167353541Sshin /* hostid part must be zero. */ 167453541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 1675126552Sume if (sin6->sin6_addr.s6_addr32[2] != 0 || 1676126552Sume sin6->sin6_addr.s6_addr32[3] != 0) { 1677236826Sbz if (ifa != NULL) 1678236826Sbz ifa_free(ifa); 167953541Sshin return EINVAL; 168053541Sshin } 168153541Sshin } else 168253541Sshin prefixlen = iflr->prefixlen; 168353541Sshin 168453541Sshin /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 168553541Sshin bzero(&ifra, sizeof(ifra)); 1686120891Sume bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name)); 168753541Sshin 168862587Sitojun bcopy(&iflr->addr, &ifra.ifra_addr, 1689120891Sume ((struct sockaddr *)&iflr->addr)->sa_len); 169053541Sshin if (hostid) { 169153541Sshin /* fill in hostid part */ 169253541Sshin ifra.ifra_addr.sin6_addr.s6_addr32[2] = 1693120891Sume hostid->s6_addr32[2]; 169453541Sshin ifra.ifra_addr.sin6_addr.s6_addr32[3] = 1695120891Sume hostid->s6_addr32[3]; 169653541Sshin } 169753541Sshin 1698120891Sume if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */ 169953541Sshin bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 1700120891Sume ((struct sockaddr *)&iflr->dstaddr)->sa_len); 170153541Sshin if (hostid) { 170253541Sshin ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] = 1703120891Sume hostid->s6_addr32[2]; 170453541Sshin ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = 1705120891Sume hostid->s6_addr32[3]; 170653541Sshin } 170753541Sshin } 1708194760Srwatson if (ifa != NULL) 1709194760Srwatson ifa_free(ifa); 171053541Sshin 171153541Sshin ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 1712121168Sume in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); 171353541Sshin 171453541Sshin ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; 171583366Sjulian return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, td); 171653541Sshin } 171753541Sshin case SIOCGLIFADDR: 171853541Sshin case SIOCDLIFADDR: 171953541Sshin { 172053541Sshin struct in6_ifaddr *ia; 172153541Sshin struct in6_addr mask, candidate, match; 172253541Sshin struct sockaddr_in6 *sin6; 172353541Sshin int cmp; 172453541Sshin 172553541Sshin bzero(&mask, sizeof(mask)); 172653541Sshin if (iflr->flags & IFLR_PREFIX) { 172753541Sshin /* lookup a prefix rather than address. */ 1728121168Sume in6_prefixlen2mask(&mask, iflr->prefixlen); 172953541Sshin 173053541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 173153541Sshin bcopy(&sin6->sin6_addr, &match, sizeof(match)); 173253541Sshin match.s6_addr32[0] &= mask.s6_addr32[0]; 173353541Sshin match.s6_addr32[1] &= mask.s6_addr32[1]; 173453541Sshin match.s6_addr32[2] &= mask.s6_addr32[2]; 173553541Sshin match.s6_addr32[3] &= mask.s6_addr32[3]; 173653541Sshin 173753541Sshin /* if you set extra bits, that's wrong */ 173853541Sshin if (bcmp(&match, &sin6->sin6_addr, sizeof(match))) 173953541Sshin return EINVAL; 174053541Sshin 174153541Sshin cmp = 1; 174253541Sshin } else { 174353541Sshin if (cmd == SIOCGLIFADDR) { 174453541Sshin /* on getting an address, take the 1st match */ 174595023Ssuz cmp = 0; /* XXX */ 174653541Sshin } else { 174753541Sshin /* on deleting an address, do exact match */ 1748121168Sume in6_prefixlen2mask(&mask, 128); 174953541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 175053541Sshin bcopy(&sin6->sin6_addr, &match, sizeof(match)); 175153541Sshin 175253541Sshin cmp = 1; 175353541Sshin } 175453541Sshin } 175553541Sshin 1756233200Sjhb IF_ADDR_RLOCK(ifp); 1757191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 175853541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 175953541Sshin continue; 176053541Sshin if (!cmp) 176153541Sshin break; 176278064Sume 176378064Sume /* 176478064Sume * XXX: this is adhoc, but is necessary to allow 176578064Sume * a user to specify fe80::/64 (not /10) for a 176678064Sume * link-local address. 176778064Sume */ 1768148385Sume bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate)); 1769148385Sume in6_clearscope(&candidate); 177053541Sshin candidate.s6_addr32[0] &= mask.s6_addr32[0]; 177153541Sshin candidate.s6_addr32[1] &= mask.s6_addr32[1]; 177253541Sshin candidate.s6_addr32[2] &= mask.s6_addr32[2]; 177353541Sshin candidate.s6_addr32[3] &= mask.s6_addr32[3]; 177453541Sshin if (IN6_ARE_ADDR_EQUAL(&candidate, &match)) 177553541Sshin break; 177653541Sshin } 1777230074Sjhb if (ifa != NULL) 1778230074Sjhb ifa_ref(ifa); 1779233200Sjhb IF_ADDR_RUNLOCK(ifp); 178053541Sshin if (!ifa) 178153541Sshin return EADDRNOTAVAIL; 178253541Sshin ia = ifa2ia6(ifa); 178353541Sshin 178453541Sshin if (cmd == SIOCGLIFADDR) { 1785148385Sume int error; 178678064Sume 178753541Sshin /* fill in the if_laddrreq structure */ 178853541Sshin bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len); 1789148385Sume error = sa6_recoverscope( 1790148385Sume (struct sockaddr_in6 *)&iflr->addr); 1791230074Sjhb if (error != 0) { 1792230074Sjhb ifa_free(ifa); 1793148385Sume return (error); 1794230074Sjhb } 1795148385Sume 179653541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 179753541Sshin bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 1798120891Sume ia->ia_dstaddr.sin6_len); 1799148385Sume error = sa6_recoverscope( 1800148385Sume (struct sockaddr_in6 *)&iflr->dstaddr); 1801230074Sjhb if (error != 0) { 1802230074Sjhb ifa_free(ifa); 1803148385Sume return (error); 1804230074Sjhb } 180553541Sshin } else 180653541Sshin bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 180753541Sshin 180853541Sshin iflr->prefixlen = 1809120891Sume in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 181053541Sshin 181195023Ssuz iflr->flags = ia->ia6_flags; /* XXX */ 1812230074Sjhb ifa_free(ifa); 181353541Sshin 181453541Sshin return 0; 181553541Sshin } else { 181653541Sshin struct in6_aliasreq ifra; 181753541Sshin 181853541Sshin /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 181953541Sshin bzero(&ifra, sizeof(ifra)); 182053541Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 1821120891Sume sizeof(ifra.ifra_name)); 182253541Sshin 182353541Sshin bcopy(&ia->ia_addr, &ifra.ifra_addr, 1824120891Sume ia->ia_addr.sin6_len); 182553541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 182653541Sshin bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 1827120891Sume ia->ia_dstaddr.sin6_len); 182862587Sitojun } else { 182962587Sitojun bzero(&ifra.ifra_dstaddr, 183062587Sitojun sizeof(ifra.ifra_dstaddr)); 183153541Sshin } 183253541Sshin bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr, 1833120891Sume ia->ia_prefixmask.sin6_len); 183453541Sshin 183553541Sshin ifra.ifra_flags = ia->ia6_flags; 1836230074Sjhb ifa_free(ifa); 183753541Sshin return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, 1838120891Sume ifp, td); 183953541Sshin } 184053541Sshin } 184153541Sshin } 184253541Sshin 184395023Ssuz return EOPNOTSUPP; /* just for safety */ 184453541Sshin} 184553541Sshin 184653541Sshin/* 1847232292Sbz * Initialize an interface's IPv6 address and routing table entry. 184853541Sshin */ 184978064Sumestatic int 1850171259Sdelphijin6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, 1851171259Sdelphij struct sockaddr_in6 *sin6, int newhost) 185253541Sshin{ 185378064Sume int error = 0, plen, ifacount = 0; 185453541Sshin int s = splimp(); 185578064Sume struct ifaddr *ifa; 185653541Sshin 185753541Sshin /* 185853541Sshin * Give the interface a chance to initialize 185953541Sshin * if this is its first address, 186053541Sshin * and to validate the address if necessary. 186153541Sshin */ 1862233200Sjhb IF_ADDR_RLOCK(ifp); 1863191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 186478064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 186578064Sume continue; 186678064Sume ifacount++; 186778064Sume } 1868233200Sjhb IF_ADDR_RUNLOCK(ifp); 186978064Sume 187078064Sume ia->ia_addr = *sin6; 187178064Sume 1872146883Siedowse if (ifacount <= 1 && ifp->if_ioctl) { 1873146883Siedowse error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); 1874146883Siedowse if (error) { 1875146883Siedowse splx(s); 1876146883Siedowse return (error); 1877146883Siedowse } 187853541Sshin } 187978064Sume splx(s); 188053541Sshin 188178064Sume ia->ia_ifa.ifa_metric = ifp->if_metric; 188253541Sshin 188378064Sume /* we could do in(6)_socktrim here, but just omit it at this moment. */ 188478064Sume 188553541Sshin /* 188678064Sume * Special case: 1887124337Sume * If a new destination address is specified for a point-to-point 188878064Sume * interface, install a route to the destination as an interface 1889240310Sglebius * direct route. 1890124337Sume * XXX: the logic below rejects assigning multiple addresses on a p2p 1891159390Sgnn * interface that share the same destination. 189253541Sshin */ 189378064Sume plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ 1894196152Sqingli if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 && 1895196152Sqingli ia->ia_dstaddr.sin6_family == AF_INET6) { 1896159390Sgnn int rtflags = RTF_UP | RTF_HOST; 1897232292Sbz error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags); 1898232292Sbz if (error) 1899120856Sume return (error); 190078064Sume ia->ia_flags |= IFA_ROUTE; 1901226455Sqingli /* 1902226455Sqingli * Handle the case for ::1 . 1903226455Sqingli */ 1904226455Sqingli if (ifp->if_flags & IFF_LOOPBACK) 1905226455Sqingli ia->ia_flags |= IFA_RTSELF; 190653541Sshin } 190753541Sshin 1908195643Sqingli /* 1909195643Sqingli * add a loopback route to self 1910195643Sqingli */ 1911226455Sqingli if (!(ia->ia_flags & IFA_RTSELF) && V_nd6_useloopback) { 1912197227Sqingli error = ifa_add_loopback_route((struct ifaddr *)ia, 1913240310Sglebius (struct sockaddr *)&ia->ia_addr); 1914201282Sqingli if (error == 0) 1915201282Sqingli ia->ia_flags |= IFA_RTSELF; 1916195643Sqingli } 1917195643Sqingli 1918232292Sbz /* Add local address to lltable, if necessary (ex. on p2p link). */ 1919226570Sglebius if (newhost) 1920226570Sglebius in6_ifaddloop(&(ia->ia_ifa)); 192153541Sshin 1922120856Sume return (error); 192353541Sshin} 192453541Sshin 192553541Sshin/* 192653541Sshin * Find an IPv6 interface link-local address specific to an interface. 1927194760Srwatson * ifaddr is returned referenced. 192853541Sshin */ 192953541Sshinstruct in6_ifaddr * 1930171259Sdelphijin6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags) 193153541Sshin{ 193278064Sume struct ifaddr *ifa; 193353541Sshin 1934233200Sjhb IF_ADDR_RLOCK(ifp); 1935191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 193653541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 193753541Sshin continue; 193862587Sitojun if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { 193962587Sitojun if ((((struct in6_ifaddr *)ifa)->ia6_flags & 1940240310Sglebius ignoreflags) != 0) 194162587Sitojun continue; 1942194760Srwatson ifa_ref(ifa); 194353541Sshin break; 194462587Sitojun } 194553541Sshin } 1946233200Sjhb IF_ADDR_RUNLOCK(ifp); 194753541Sshin 1948120856Sume return ((struct in6_ifaddr *)ifa); 194953541Sshin} 195053541Sshin 195153541Sshin 195253541Sshin/* 195353541Sshin * find the internet address corresponding to a given interface and address. 1954194760Srwatson * ifaddr is returned referenced. 195553541Sshin */ 195653541Sshinstruct in6_ifaddr * 1957171259Sdelphijin6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr) 195853541Sshin{ 195978064Sume struct ifaddr *ifa; 196053541Sshin 1961233200Sjhb IF_ADDR_RLOCK(ifp); 1962191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 196353541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 196453541Sshin continue; 1965194760Srwatson if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) { 1966194760Srwatson ifa_ref(ifa); 196753541Sshin break; 1968194760Srwatson } 196953541Sshin } 1970233200Sjhb IF_ADDR_RUNLOCK(ifp); 197153541Sshin 1972120856Sume return ((struct in6_ifaddr *)ifa); 197353541Sshin} 197453541Sshin 197553541Sshin/* 1976253239Shrs * Find a link-local scoped address on ifp and return it if any. 1977253239Shrs */ 1978253239Shrsstruct in6_ifaddr * 1979253239Shrsin6ifa_llaonifp(struct ifnet *ifp) 1980253239Shrs{ 1981253239Shrs struct sockaddr_in6 *sin6; 1982253239Shrs struct ifaddr *ifa; 1983253239Shrs 1984253239Shrs if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) 1985253239Shrs return (NULL); 1986253239Shrs if_addr_rlock(ifp); 1987253239Shrs TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 1988253239Shrs if (ifa->ifa_addr->sa_family != AF_INET6) 1989253239Shrs continue; 1990253239Shrs sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 1991253239Shrs if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || 1992253239Shrs IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr) || 1993253239Shrs IN6_IS_ADDR_MC_NODELOCAL(&sin6->sin6_addr)) 1994253239Shrs break; 1995253239Shrs } 1996253239Shrs if_addr_runlock(ifp); 1997253239Shrs 1998253239Shrs return ((struct in6_ifaddr *)ifa); 1999253239Shrs} 2000253239Shrs 2001253239Shrs/* 2002165118Sbz * Convert IP6 address to printable (loggable) representation. Caller 2003165118Sbz * has to make sure that ip6buf is at least INET6_ADDRSTRLEN long. 200453541Sshin */ 200553541Sshinstatic char digits[] = "0123456789abcdef"; 200653541Sshinchar * 2007165118Sbzip6_sprintf(char *ip6buf, const struct in6_addr *addr) 200853541Sshin{ 2009208284Salfred int i, cnt = 0, maxcnt = 0, idx = 0, index = 0; 201078064Sume char *cp; 2011126552Sume const u_int16_t *a = (const u_int16_t *)addr; 2012126552Sume const u_int8_t *d; 2013165287Sbz int dcolon = 0, zero = 0; 201453541Sshin 2015165118Sbz cp = ip6buf; 201653541Sshin 201753541Sshin for (i = 0; i < 8; i++) { 2018208284Salfred if (*(a + i) == 0) { 2019208284Salfred cnt++; 2020208284Salfred if (cnt == 1) 2021208284Salfred idx = i; 2022208284Salfred } 2023208284Salfred else if (maxcnt < cnt) { 2024208284Salfred maxcnt = cnt; 2025208284Salfred index = idx; 2026208284Salfred cnt = 0; 2027208284Salfred } 2028208284Salfred } 2029208284Salfred if (maxcnt < cnt) { 2030208284Salfred maxcnt = cnt; 2031208284Salfred index = idx; 2032208284Salfred } 2033208284Salfred 2034208284Salfred for (i = 0; i < 8; i++) { 203553541Sshin if (dcolon == 1) { 203653541Sshin if (*a == 0) { 203753541Sshin if (i == 7) 203853541Sshin *cp++ = ':'; 203953541Sshin a++; 204053541Sshin continue; 204153541Sshin } else 204253541Sshin dcolon = 2; 204353541Sshin } 204453541Sshin if (*a == 0) { 2045208284Salfred if (dcolon == 0 && *(a + 1) == 0 && i == index) { 204653541Sshin if (i == 0) 204753541Sshin *cp++ = ':'; 204853541Sshin *cp++ = ':'; 204953541Sshin dcolon = 1; 205053541Sshin } else { 205153541Sshin *cp++ = '0'; 205253541Sshin *cp++ = ':'; 205353541Sshin } 205453541Sshin a++; 205553541Sshin continue; 205653541Sshin } 205791346Salfred d = (const u_char *)a; 2058165287Sbz /* Try to eliminate leading zeros in printout like in :0001. */ 2059165287Sbz zero = 1; 2060165287Sbz *cp = digits[*d >> 4]; 2061165287Sbz if (*cp != '0') { 2062165287Sbz zero = 0; 2063165287Sbz cp++; 2064165287Sbz } 2065165287Sbz *cp = digits[*d++ & 0xf]; 2066165287Sbz if (zero == 0 || (*cp != '0')) { 2067165287Sbz zero = 0; 2068165287Sbz cp++; 2069165287Sbz } 2070165287Sbz *cp = digits[*d >> 4]; 2071165287Sbz if (zero == 0 || (*cp != '0')) { 2072165287Sbz zero = 0; 2073165287Sbz cp++; 2074165287Sbz } 207553541Sshin *cp++ = digits[*d & 0xf]; 207653541Sshin *cp++ = ':'; 207753541Sshin a++; 207853541Sshin } 2079165118Sbz *--cp = '\0'; 2080165118Sbz return (ip6buf); 208153541Sshin} 208253541Sshin 208353541Sshinint 2084171259Sdelphijin6_localaddr(struct in6_addr *in6) 208553541Sshin{ 208653541Sshin struct in6_ifaddr *ia; 208753541Sshin 208853541Sshin if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6)) 208953541Sshin return 1; 209053541Sshin 2091194971Srwatson IN6_IFADDR_RLOCK(); 2092194907Srwatson TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { 209353541Sshin if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr, 2094120891Sume &ia->ia_prefixmask.sin6_addr)) { 2095194971Srwatson IN6_IFADDR_RUNLOCK(); 209653541Sshin return 1; 2097120891Sume } 2098120891Sume } 2099194971Srwatson IN6_IFADDR_RUNLOCK(); 210053541Sshin 210153541Sshin return (0); 210253541Sshin} 210353541Sshin 2104225043Sbz/* 2105225043Sbz * Return 1 if an internet address is for the local host and configured 2106225043Sbz * on one of its interfaces. 2107225043Sbz */ 210878064Sumeint 2109225043Sbzin6_localip(struct in6_addr *in6) 2110225043Sbz{ 2111225043Sbz struct in6_ifaddr *ia; 2112225043Sbz 2113225043Sbz IN6_IFADDR_RLOCK(); 2114225043Sbz TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { 2115225043Sbz if (IN6_ARE_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr)) { 2116225043Sbz IN6_IFADDR_RUNLOCK(); 2117225043Sbz return (1); 2118225043Sbz } 2119225043Sbz } 2120225043Sbz IN6_IFADDR_RUNLOCK(); 2121225043Sbz return (0); 2122225043Sbz} 2123225043Sbz 2124225043Sbz 2125225043Sbzint 2126171259Sdelphijin6_is_addr_deprecated(struct sockaddr_in6 *sa6) 212778064Sume{ 212878064Sume struct in6_ifaddr *ia; 212978064Sume 2130194971Srwatson IN6_IFADDR_RLOCK(); 2131194907Srwatson TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { 213278064Sume if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 2133240310Sglebius &sa6->sin6_addr) && 2134194971Srwatson (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) { 2135194971Srwatson IN6_IFADDR_RUNLOCK(); 2136120856Sume return (1); /* true */ 2137194971Srwatson } 213878064Sume 213978064Sume /* XXX: do we still have to go thru the rest of the list? */ 214078064Sume } 2141194971Srwatson IN6_IFADDR_RUNLOCK(); 214278064Sume 2143120856Sume return (0); /* false */ 214478064Sume} 214578064Sume 214653541Sshin/* 214753541Sshin * return length of part which dst and src are equal 214853541Sshin * hard coding... 214953541Sshin */ 215053541Sshinint 2151171259Sdelphijin6_matchlen(struct in6_addr *src, struct in6_addr *dst) 215253541Sshin{ 215353541Sshin int match = 0; 215453541Sshin u_char *s = (u_char *)src, *d = (u_char *)dst; 215553541Sshin u_char *lim = s + 16, r; 215653541Sshin 215753541Sshin while (s < lim) 215853541Sshin if ((r = (*d++ ^ *s++)) != 0) { 215953541Sshin while (r < 128) { 216053541Sshin match++; 216153541Sshin r <<= 1; 216253541Sshin } 216353541Sshin break; 216453541Sshin } else 216553541Sshin match += 8; 216653541Sshin return match; 216753541Sshin} 216853541Sshin 216962587Sitojun/* XXX: to be scope conscious */ 217053541Sshinint 2171171259Sdelphijin6_are_prefix_equal(struct in6_addr *p1, struct in6_addr *p2, int len) 217253541Sshin{ 217353541Sshin int bytelen, bitlen; 217453541Sshin 217553541Sshin /* sanity check */ 217653541Sshin if (0 > len || len > 128) { 217753541Sshin log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n", 217853541Sshin len); 2179120856Sume return (0); 218053541Sshin } 218153541Sshin 218253541Sshin bytelen = len / 8; 218353541Sshin bitlen = len % 8; 218453541Sshin 218553541Sshin if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen)) 2186120856Sume return (0); 2187126184Scperciva if (bitlen != 0 && 2188126184Scperciva p1->s6_addr[bytelen] >> (8 - bitlen) != 218953541Sshin p2->s6_addr[bytelen] >> (8 - bitlen)) 2190120856Sume return (0); 219153541Sshin 2192120856Sume return (1); 219353541Sshin} 219453541Sshin 219553541Sshinvoid 2196171259Sdelphijin6_prefixlen2mask(struct in6_addr *maskp, int len) 219753541Sshin{ 219853541Sshin u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 219953541Sshin int bytelen, bitlen, i; 220053541Sshin 220153541Sshin /* sanity check */ 220253541Sshin if (0 > len || len > 128) { 220353541Sshin log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n", 220453541Sshin len); 220553541Sshin return; 220653541Sshin } 220753541Sshin 220853541Sshin bzero(maskp, sizeof(*maskp)); 220953541Sshin bytelen = len / 8; 221053541Sshin bitlen = len % 8; 221153541Sshin for (i = 0; i < bytelen; i++) 221253541Sshin maskp->s6_addr[i] = 0xff; 221353541Sshin if (bitlen) 221453541Sshin maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 221553541Sshin} 221653541Sshin 221753541Sshin/* 221853541Sshin * return the best address out of the same scope. if no address was 221953541Sshin * found, return the first valid address from designated IF. 222053541Sshin */ 222153541Sshinstruct in6_ifaddr * 2222171259Sdelphijin6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) 222353541Sshin{ 222453541Sshin int dst_scope = in6_addrscope(dst), blen = -1, tlen; 222553541Sshin struct ifaddr *ifa; 222653541Sshin struct in6_ifaddr *besta = 0; 222795023Ssuz struct in6_ifaddr *dep[2]; /* last-resort: deprecated */ 222853541Sshin 222953541Sshin dep[0] = dep[1] = NULL; 223053541Sshin 223153541Sshin /* 223253541Sshin * We first look for addresses in the same scope. 223353541Sshin * If there is one, return it. 223453541Sshin * If two or more, return one which matches the dst longest. 223553541Sshin * If none, return one of global addresses assigned other ifs. 223653541Sshin */ 2237233200Sjhb IF_ADDR_RLOCK(ifp); 2238191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 223953541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 224053541Sshin continue; 224153541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 224253541Sshin continue; /* XXX: is there any case to allow anycast? */ 224353541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 224453541Sshin continue; /* don't use this interface */ 224553541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 224653541Sshin continue; 224753541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 2248181803Sbz if (V_ip6_use_deprecated) 224953541Sshin dep[0] = (struct in6_ifaddr *)ifa; 225053541Sshin continue; 225153541Sshin } 225253541Sshin 225353541Sshin if (dst_scope == in6_addrscope(IFA_IN6(ifa))) { 225453541Sshin /* 225553541Sshin * call in6_matchlen() as few as possible 225653541Sshin */ 225753541Sshin if (besta) { 225853541Sshin if (blen == -1) 225953541Sshin blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst); 226053541Sshin tlen = in6_matchlen(IFA_IN6(ifa), dst); 226153541Sshin if (tlen > blen) { 226253541Sshin blen = tlen; 226353541Sshin besta = (struct in6_ifaddr *)ifa; 226453541Sshin } 226553541Sshin } else 226653541Sshin besta = (struct in6_ifaddr *)ifa; 226753541Sshin } 226853541Sshin } 2269191323Srwatson if (besta) { 2270194760Srwatson ifa_ref(&besta->ia_ifa); 2271233200Sjhb IF_ADDR_RUNLOCK(ifp); 2272120856Sume return (besta); 2273191323Srwatson } 227453541Sshin 2275191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 227653541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 227753541Sshin continue; 227853541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 227953541Sshin continue; /* XXX: is there any case to allow anycast? */ 228053541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 228153541Sshin continue; /* don't use this interface */ 228253541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 228353541Sshin continue; 228453541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 2285181803Sbz if (V_ip6_use_deprecated) 228653541Sshin dep[1] = (struct in6_ifaddr *)ifa; 228753541Sshin continue; 228853541Sshin } 228953541Sshin 2290194760Srwatson if (ifa != NULL) 2291194760Srwatson ifa_ref(ifa); 2292233200Sjhb IF_ADDR_RUNLOCK(ifp); 229353541Sshin return (struct in6_ifaddr *)ifa; 229453541Sshin } 229553541Sshin 229653541Sshin /* use the last-resort values, that are, deprecated addresses */ 2297236606Sbz if (dep[0]) { 2298236606Sbz ifa_ref((struct ifaddr *)dep[0]); 2299236606Sbz IF_ADDR_RUNLOCK(ifp); 230053541Sshin return dep[0]; 2301236606Sbz } 2302236606Sbz if (dep[1]) { 2303236606Sbz ifa_ref((struct ifaddr *)dep[1]); 2304236606Sbz IF_ADDR_RUNLOCK(ifp); 230553541Sshin return dep[1]; 2306236606Sbz } 230753541Sshin 2308236606Sbz IF_ADDR_RUNLOCK(ifp); 230953541Sshin return NULL; 231053541Sshin} 231153541Sshin 231253541Sshin/* 231353541Sshin * perform DAD when interface becomes IFF_UP. 231453541Sshin */ 231553541Sshinvoid 2316171259Sdelphijin6_if_up(struct ifnet *ifp) 231753541Sshin{ 231853541Sshin struct ifaddr *ifa; 231953541Sshin struct in6_ifaddr *ia; 232053541Sshin 2321233200Sjhb IF_ADDR_RLOCK(ifp); 2322191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 232353541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 232453541Sshin continue; 232553541Sshin ia = (struct in6_ifaddr *)ifa; 2326151539Ssuz if (ia->ia6_flags & IN6_IFF_TENTATIVE) { 2327151539Ssuz /* 2328151539Ssuz * The TENTATIVE flag was likely set by hand 2329151539Ssuz * beforehand, implicitly indicating the need for DAD. 2330151539Ssuz * We may be able to skip the random delay in this 2331151539Ssuz * case, but we impose delays just in case. 2332151539Ssuz */ 2333151539Ssuz nd6_dad_start(ifa, 2334151539Ssuz arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz)); 2335151539Ssuz } 233653541Sshin } 2337233200Sjhb IF_ADDR_RUNLOCK(ifp); 2338151539Ssuz 2339151539Ssuz /* 2340151539Ssuz * special cases, like 6to4, are handled in in6_ifattach 2341151539Ssuz */ 2342151539Ssuz in6_ifattach(ifp, NULL); 234353541Sshin} 234453541Sshin 234578064Sumeint 2346171259Sdelphijin6if_do_dad(struct ifnet *ifp) 234778064Sume{ 234878064Sume if ((ifp->if_flags & IFF_LOOPBACK) != 0) 2349120856Sume return (0); 235078064Sume 2351197138Shrs if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) 2352197138Shrs return (0); 2353197138Shrs 235478064Sume switch (ifp->if_type) { 235578064Sume#ifdef IFT_DUMMY 235678064Sume case IFT_DUMMY: 235778064Sume#endif 235878064Sume case IFT_FAITH: 235978064Sume /* 236078064Sume * These interfaces do not have the IFF_LOOPBACK flag, 236178064Sume * but loop packets back. We do not have to do DAD on such 236278064Sume * interfaces. We should even omit it, because loop-backed 236378064Sume * NS would confuse the DAD procedure. 236478064Sume */ 2365120856Sume return (0); 236678064Sume default: 236778064Sume /* 236878064Sume * Our DAD routine requires the interface up and running. 236978064Sume * However, some interfaces can be up before the RUNNING 237078064Sume * status. Additionaly, users may try to assign addresses 237178064Sume * before the interface becomes up (or running). 237278064Sume * We simply skip DAD in such a case as a work around. 237378064Sume * XXX: we should rather mark "tentative" on such addresses, 237478064Sume * and do DAD after the interface becomes ready. 237578064Sume */ 2376148887Srwatson if (!((ifp->if_flags & IFF_UP) && 2377148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 2378120856Sume return (0); 237978064Sume 2380120856Sume return (1); 238178064Sume } 238278064Sume} 238378064Sume 238453541Sshin/* 238553541Sshin * Calculate max IPv6 MTU through all the interfaces and store it 238653541Sshin * to in6_maxmtu. 238753541Sshin */ 238853541Sshinvoid 2389171259Sdelphijin6_setmaxmtu(void) 239053541Sshin{ 239153541Sshin unsigned long maxmtu = 0; 239253541Sshin struct ifnet *ifp; 239353541Sshin 2394196481Srwatson IFNET_RLOCK_NOSLEEP(); 2395233046Sjhb TAILQ_FOREACH(ifp, &V_ifnet, if_list) { 2396121283Sume /* this function can be called during ifnet initialization */ 2397121283Sume if (!ifp->if_afdata[AF_INET6]) 2398121283Sume continue; 239953541Sshin if ((ifp->if_flags & IFF_LOOPBACK) == 0 && 2400121283Sume IN6_LINKMTU(ifp) > maxmtu) 2401121283Sume maxmtu = IN6_LINKMTU(ifp); 240253541Sshin } 2403196481Srwatson IFNET_RUNLOCK_NOSLEEP(); 2404240310Sglebius if (maxmtu) /* update only when maxmtu is positive */ 2405181803Sbz V_in6_maxmtu = maxmtu; 240653541Sshin} 240753541Sshin 2408151539Ssuz/* 2409151539Ssuz * Provide the length of interface identifiers to be used for the link attached 2410151539Ssuz * to the given interface. The length should be defined in "IPv6 over 2411151539Ssuz * xxx-link" document. Note that address architecture might also define 2412151539Ssuz * the length for a particular set of address prefixes, regardless of the 2413151539Ssuz * link type. As clarified in rfc2462bis, those two definitions should be 2414151539Ssuz * consistent, and those really are as of August 2004. 2415151539Ssuz */ 2416151539Ssuzint 2417171259Sdelphijin6_if2idlen(struct ifnet *ifp) 2418151539Ssuz{ 2419151539Ssuz switch (ifp->if_type) { 2420151539Ssuz case IFT_ETHER: /* RFC2464 */ 2421151539Ssuz#ifdef IFT_PROPVIRTUAL 2422151539Ssuz case IFT_PROPVIRTUAL: /* XXX: no RFC. treat it as ether */ 2423151539Ssuz#endif 2424151539Ssuz#ifdef IFT_L2VLAN 2425151539Ssuz case IFT_L2VLAN: /* ditto */ 2426151539Ssuz#endif 2427151539Ssuz#ifdef IFT_IEEE80211 2428151539Ssuz case IFT_IEEE80211: /* ditto */ 2429151539Ssuz#endif 2430151539Ssuz#ifdef IFT_MIP 2431151539Ssuz case IFT_MIP: /* ditto */ 2432151539Ssuz#endif 2433219819Sjeff case IFT_INFINIBAND: 2434151539Ssuz return (64); 2435151539Ssuz case IFT_FDDI: /* RFC2467 */ 2436151539Ssuz return (64); 2437151539Ssuz case IFT_ISO88025: /* RFC2470 (IPv6 over Token Ring) */ 2438151539Ssuz return (64); 2439151539Ssuz case IFT_PPP: /* RFC2472 */ 2440151539Ssuz return (64); 2441151539Ssuz case IFT_ARCNET: /* RFC2497 */ 2442151539Ssuz return (64); 2443151539Ssuz case IFT_FRELAY: /* RFC2590 */ 2444151539Ssuz return (64); 2445151539Ssuz case IFT_IEEE1394: /* RFC3146 */ 2446151539Ssuz return (64); 2447151539Ssuz case IFT_GIF: 2448151539Ssuz return (64); /* draft-ietf-v6ops-mech-v2-07 */ 2449151539Ssuz case IFT_LOOP: 2450151539Ssuz return (64); /* XXX: is this really correct? */ 2451151539Ssuz default: 2452151539Ssuz /* 2453151539Ssuz * Unknown link type: 2454151539Ssuz * It might be controversial to use the today's common constant 2455151539Ssuz * of 64 for these cases unconditionally. For full compliance, 2456151539Ssuz * we should return an error in this case. On the other hand, 2457151539Ssuz * if we simply miss the standard for the link type or a new 2458151539Ssuz * standard is defined for a new link type, the IFID length 2459151539Ssuz * is very likely to be the common constant. As a compromise, 2460151539Ssuz * we always use the constant, but make an explicit notice 2461151539Ssuz * indicating the "unknown" case. 2462151539Ssuz */ 2463151539Ssuz printf("in6_if2idlen: unknown link type (%d)\n", ifp->if_type); 2464151539Ssuz return (64); 2465151539Ssuz } 2466151539Ssuz} 2467151539Ssuz 2468186119Sqingli#include <sys/sysctl.h> 2469186119Sqingli 2470186119Sqinglistruct in6_llentry { 2471186119Sqingli struct llentry base; 2472186119Sqingli struct sockaddr_in6 l3_addr6; 2473186119Sqingli}; 2474186119Sqingli 2475240309Sglebius/* 2476240309Sglebius * Deletes an address from the address table. 2477240309Sglebius * This function is called by the timer functions 2478240309Sglebius * such as arptimer() and nd6_llinfo_timer(), and 2479240309Sglebius * the caller does the locking. 2480240309Sglebius */ 2481240309Sglebiusstatic void 2482240309Sglebiusin6_lltable_free(struct lltable *llt, struct llentry *lle) 2483240309Sglebius{ 2484240309Sglebius LLE_WUNLOCK(lle); 2485240309Sglebius LLE_LOCK_DESTROY(lle); 2486240309Sglebius free(lle, M_LLTABLE); 2487240309Sglebius} 2488240309Sglebius 2489186119Sqinglistatic struct llentry * 2490186119Sqingliin6_lltable_new(const struct sockaddr *l3addr, u_int flags) 2491186119Sqingli{ 2492186119Sqingli struct in6_llentry *lle; 2493186119Sqingli 2494240310Sglebius lle = malloc(sizeof(struct in6_llentry), M_LLTABLE, M_NOWAIT | M_ZERO); 2495186119Sqingli if (lle == NULL) /* NB: caller generates msg */ 2496186119Sqingli return NULL; 2497186119Sqingli 2498186119Sqingli lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr; 2499186119Sqingli lle->base.lle_refcnt = 1; 2500240309Sglebius lle->base.lle_free = in6_lltable_free; 2501186119Sqingli LLE_LOCK_INIT(&lle->base); 2502216022Sbz callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock, 2503216022Sbz CALLOUT_RETURNUNLOCKED); 2504216022Sbz 2505240310Sglebius return (&lle->base); 2506186119Sqingli} 2507186119Sqingli 2508186119Sqinglistatic void 2509240310Sglebiusin6_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix, 2510240310Sglebius const struct sockaddr *mask, u_int flags) 2511192476Sqingli{ 2512192476Sqingli const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix; 2513192476Sqingli const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask; 2514192476Sqingli struct llentry *lle, *next; 2515240310Sglebius int i; 2516192476Sqingli 2517222143Sqingli /* 2518240310Sglebius * (flags & LLE_STATIC) means deleting all entries 2519240310Sglebius * including static ND6 entries. 2520222143Sqingli */ 2521240313Sglebius IF_AFDATA_WLOCK(llt->llt_ifp); 2522240310Sglebius for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { 2523192476Sqingli LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 2524192476Sqingli if (IN6_ARE_MASKED_ADDR_EQUAL( 2525240313Sglebius &satosin6(L3_ADDR(lle))->sin6_addr, 2526240313Sglebius &pfx->sin6_addr, &msk->sin6_addr) && 2527240313Sglebius ((flags & LLE_STATIC) || 2528240313Sglebius !(lle->la_flags & LLE_STATIC))) { 2529192476Sqingli LLE_WLOCK(lle); 2530240313Sglebius if (callout_stop(&lle->la_timer)) 2531206481Sbz LLE_REMREF(lle); 2532192476Sqingli llentry_free(lle); 2533192476Sqingli } 2534192476Sqingli } 2535192476Sqingli } 2536240313Sglebius IF_AFDATA_WUNLOCK(llt->llt_ifp); 2537192476Sqingli} 2538192476Sqingli 2539186119Sqinglistatic int 2540240310Sglebiusin6_lltable_rtcheck(struct ifnet *ifp, 2541240310Sglebius u_int flags, 2542201282Sqingli const struct sockaddr *l3addr) 2543186119Sqingli{ 2544186119Sqingli struct rtentry *rt; 2545186119Sqingli char ip6buf[INET6_ADDRSTRLEN]; 2546186119Sqingli 2547186119Sqingli KASSERT(l3addr->sa_family == AF_INET6, 2548186119Sqingli ("sin_family %d", l3addr->sa_family)); 2549186119Sqingli 2550232292Sbz /* Our local addresses are always only installed on the default FIB. */ 2551186119Sqingli /* XXX rtalloc1 should take a const param */ 2552232292Sbz rt = in6_rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0, 2553232292Sbz RT_DEFAULT_FIB); 2554186119Sqingli if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) { 2555186119Sqingli struct ifaddr *ifa; 2556240310Sglebius /* 2557240310Sglebius * Create an ND6 cache for an IPv6 neighbor 2558186119Sqingli * that is not covered by our own prefix. 2559186119Sqingli */ 2560186119Sqingli /* XXX ifaof_ifpforaddr should take a const param */ 2561186119Sqingli ifa = ifaof_ifpforaddr(__DECONST(struct sockaddr *, l3addr), ifp); 2562186119Sqingli if (ifa != NULL) { 2563194760Srwatson ifa_free(ifa); 2564186119Sqingli if (rt != NULL) 2565187946Sbz RTFREE_LOCKED(rt); 2566186119Sqingli return 0; 2567186119Sqingli } 2568186119Sqingli log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", 2569186119Sqingli ip6_sprintf(ip6buf, &((const struct sockaddr_in6 *)l3addr)->sin6_addr)); 2570186119Sqingli if (rt != NULL) 2571187946Sbz RTFREE_LOCKED(rt); 2572186119Sqingli return EINVAL; 2573186119Sqingli } 2574187946Sbz RTFREE_LOCKED(rt); 2575186119Sqingli return 0; 2576186119Sqingli} 2577186119Sqingli 2578186119Sqinglistatic struct llentry * 2579186119Sqingliin6_lltable_lookup(struct lltable *llt, u_int flags, 2580186119Sqingli const struct sockaddr *l3addr) 2581186119Sqingli{ 2582186119Sqingli const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; 2583186119Sqingli struct ifnet *ifp = llt->llt_ifp; 2584186119Sqingli struct llentry *lle; 2585186119Sqingli struct llentries *lleh; 2586186119Sqingli u_int hashkey; 2587186119Sqingli 2588186119Sqingli IF_AFDATA_LOCK_ASSERT(ifp); 2589186119Sqingli KASSERT(l3addr->sa_family == AF_INET6, 2590186119Sqingli ("sin_family %d", l3addr->sa_family)); 2591186119Sqingli 2592186119Sqingli hashkey = sin6->sin6_addr.s6_addr32[3]; 2593186119Sqingli lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; 2594186119Sqingli LIST_FOREACH(lle, lleh, lle_next) { 2595186708Sqingli struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)L3_ADDR(lle); 2596186119Sqingli if (lle->la_flags & LLE_DELETED) 2597186119Sqingli continue; 2598240310Sglebius if (bcmp(&sa6->sin6_addr, &sin6->sin6_addr, 2599240310Sglebius sizeof(struct in6_addr)) == 0) 2600186119Sqingli break; 2601186119Sqingli } 2602186119Sqingli 2603186119Sqingli if (lle == NULL) { 2604186119Sqingli if (!(flags & LLE_CREATE)) 2605186119Sqingli return (NULL); 2606260510Sae IF_AFDATA_WLOCK_ASSERT(ifp); 2607186119Sqingli /* 2608186119Sqingli * A route that covers the given address must have 2609186119Sqingli * been installed 1st because we are doing a resolution, 2610186119Sqingli * verify this. 2611186119Sqingli */ 2612186119Sqingli if (!(flags & LLE_IFADDR) && 2613201282Sqingli in6_lltable_rtcheck(ifp, flags, l3addr) != 0) 2614186119Sqingli return NULL; 2615186119Sqingli 2616186119Sqingli lle = in6_lltable_new(l3addr, flags); 2617186119Sqingli if (lle == NULL) { 2618186119Sqingli log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); 2619186119Sqingli return NULL; 2620186119Sqingli } 2621186119Sqingli lle->la_flags = flags & ~LLE_CREATE; 2622186119Sqingli if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { 2623186119Sqingli bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); 2624186119Sqingli lle->la_flags |= (LLE_VALID | LLE_STATIC); 2625186119Sqingli } 2626186119Sqingli 2627186119Sqingli lle->lle_tbl = llt; 2628186119Sqingli lle->lle_head = lleh; 2629240313Sglebius lle->la_flags |= LLE_LINKED; 2630186119Sqingli LIST_INSERT_HEAD(lleh, lle, lle_next); 2631186119Sqingli } else if (flags & LLE_DELETE) { 2632186392Sqingli if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) { 2633186392Sqingli LLE_WLOCK(lle); 2634240313Sglebius lle->la_flags |= LLE_DELETED; 2635198418Sqingli#ifdef DIAGNOSTIC 2636250927Soleg log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); 2637240310Sglebius#endif 2638250927Soleg if ((lle->la_flags & 2639250927Soleg (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC) 2640250927Soleg llentry_free(lle); 2641250927Soleg else 2642250927Soleg LLE_WUNLOCK(lle); 2643186392Sqingli } 2644186119Sqingli lle = (void *)-1; 2645186119Sqingli } 2646186119Sqingli if (LLE_IS_VALID(lle)) { 2647186119Sqingli if (flags & LLE_EXCLUSIVE) 2648186119Sqingli LLE_WLOCK(lle); 2649186119Sqingli else 2650186119Sqingli LLE_RLOCK(lle); 2651186119Sqingli } 2652186119Sqingli return (lle); 2653186119Sqingli} 2654186119Sqingli 2655186119Sqinglistatic int 2656186119Sqingliin6_lltable_dump(struct lltable *llt, struct sysctl_req *wr) 2657186119Sqingli{ 2658186119Sqingli struct ifnet *ifp = llt->llt_ifp; 2659186119Sqingli struct llentry *lle; 2660186119Sqingli /* XXX stack use */ 2661186119Sqingli struct { 2662186119Sqingli struct rt_msghdr rtm; 2663186119Sqingli struct sockaddr_in6 sin6; 2664186119Sqingli /* 2665186119Sqingli * ndp.c assumes that sdl is word aligned 2666186119Sqingli */ 2667186119Sqingli#ifdef __LP64__ 2668186119Sqingli uint32_t pad; 2669186119Sqingli#endif 2670186119Sqingli struct sockaddr_dl sdl; 2671186119Sqingli } ndpc; 2672186119Sqingli int i, error; 2673186119Sqingli 2674196864Sqingli if (ifp->if_flags & IFF_LOOPBACK) 2675196864Sqingli return 0; 2676196864Sqingli 2677196535Srwatson LLTABLE_LOCK_ASSERT(); 2678186119Sqingli 2679186119Sqingli error = 0; 2680186119Sqingli for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { 2681186119Sqingli LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 2682186119Sqingli struct sockaddr_dl *sdl; 2683186119Sqingli 2684186119Sqingli /* skip deleted or invalid entries */ 2685186119Sqingli if ((lle->la_flags & (LLE_DELETED|LLE_VALID)) != LLE_VALID) 2686186119Sqingli continue; 2687186980Sbz /* Skip if jailed and not a valid IP of the prison. */ 2688188144Sjamie if (prison_if(wr->td->td_ucred, L3_ADDR(lle)) != 0) 2689186980Sbz continue; 2690186119Sqingli /* 2691186119Sqingli * produce a msg made of: 2692186119Sqingli * struct rt_msghdr; 2693186119Sqingli * struct sockaddr_in6 (IPv6) 2694186119Sqingli * struct sockaddr_dl; 2695186119Sqingli */ 2696186119Sqingli bzero(&ndpc, sizeof(ndpc)); 2697186119Sqingli ndpc.rtm.rtm_msglen = sizeof(ndpc); 2698187094Sqingli ndpc.rtm.rtm_version = RTM_VERSION; 2699187094Sqingli ndpc.rtm.rtm_type = RTM_GET; 2700187094Sqingli ndpc.rtm.rtm_flags = RTF_UP; 2701187094Sqingli ndpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; 2702186119Sqingli ndpc.sin6.sin6_family = AF_INET6; 2703186119Sqingli ndpc.sin6.sin6_len = sizeof(ndpc.sin6); 2704186119Sqingli bcopy(L3_ADDR(lle), &ndpc.sin6, L3_ADDR_LEN(lle)); 2705186119Sqingli 2706186119Sqingli /* publish */ 2707186119Sqingli if (lle->la_flags & LLE_PUB) 2708186119Sqingli ndpc.rtm.rtm_flags |= RTF_ANNOUNCE; 2709186119Sqingli 2710186119Sqingli sdl = &ndpc.sdl; 2711186119Sqingli sdl->sdl_family = AF_LINK; 2712186119Sqingli sdl->sdl_len = sizeof(*sdl); 2713186119Sqingli sdl->sdl_alen = ifp->if_addrlen; 2714186119Sqingli sdl->sdl_index = ifp->if_index; 2715186119Sqingli sdl->sdl_type = ifp->if_type; 2716186119Sqingli bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); 2717186119Sqingli ndpc.rtm.rtm_rmx.rmx_expire = 2718186119Sqingli lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; 2719186500Sqingli ndpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); 2720186119Sqingli if (lle->la_flags & LLE_STATIC) 2721186119Sqingli ndpc.rtm.rtm_flags |= RTF_STATIC; 2722186119Sqingli ndpc.rtm.rtm_index = ifp->if_index; 2723186119Sqingli error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc)); 2724186119Sqingli if (error) 2725186119Sqingli break; 2726186119Sqingli } 2727186119Sqingli } 2728186119Sqingli return error; 2729186119Sqingli} 2730186119Sqingli 2731121161Sumevoid * 2732171259Sdelphijin6_domifattach(struct ifnet *ifp) 2733121161Sume{ 2734121161Sume struct in6_ifextra *ext; 2735121161Sume 2736121161Sume ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK); 2737121161Sume bzero(ext, sizeof(*ext)); 2738121161Sume 2739121161Sume ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat), 2740121161Sume M_IFADDR, M_WAITOK); 2741121161Sume bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat)); 2742121161Sume 2743121161Sume ext->icmp6_ifstat = 2744121161Sume (struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat), 2745121161Sume M_IFADDR, M_WAITOK); 2746121161Sume bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat)); 2747121161Sume 2748121161Sume ext->nd_ifinfo = nd6_ifattach(ifp); 2749121161Sume ext->scope6_id = scope6_ifattach(ifp); 2750186119Sqingli ext->lltable = lltable_init(ifp, AF_INET6); 2751186119Sqingli if (ext->lltable != NULL) { 2752192476Sqingli ext->lltable->llt_prefix_free = in6_lltable_prefix_free; 2753186119Sqingli ext->lltable->llt_lookup = in6_lltable_lookup; 2754186119Sqingli ext->lltable->llt_dump = in6_lltable_dump; 2755186119Sqingli } 2756191672Sbms 2757191672Sbms ext->mld_ifinfo = mld_domifattach(ifp); 2758191672Sbms 2759121161Sume return ext; 2760121161Sume} 2761121161Sume 2762121161Sumevoid 2763171259Sdelphijin6_domifdetach(struct ifnet *ifp, void *aux) 2764121161Sume{ 2765121161Sume struct in6_ifextra *ext = (struct in6_ifextra *)aux; 2766121161Sume 2767191672Sbms mld_domifdetach(ifp); 2768121161Sume scope6_ifdetach(ext->scope6_id); 2769121161Sume nd6_ifdetach(ext->nd_ifinfo); 2770186119Sqingli lltable_free(ext->lltable); 2771121161Sume free(ext->in6_ifstat, M_IFADDR); 2772121161Sume free(ext->icmp6_ifstat, M_IFADDR); 2773121161Sume free(ext, M_IFADDR); 2774121161Sume} 2775121161Sume 277653541Sshin/* 277795023Ssuz * Convert sockaddr_in6 to sockaddr_in. Original sockaddr_in6 must be 277853541Sshin * v4 mapped addr or v4 compat addr 277953541Sshin */ 278053541Sshinvoid 278153541Sshinin6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 278253541Sshin{ 2783171259Sdelphij 278453541Sshin bzero(sin, sizeof(*sin)); 278553541Sshin sin->sin_len = sizeof(struct sockaddr_in); 278653541Sshin sin->sin_family = AF_INET; 278753541Sshin sin->sin_port = sin6->sin6_port; 2788120891Sume sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3]; 278953541Sshin} 279053541Sshin 279153541Sshin/* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */ 279253541Sshinvoid 279353541Sshinin6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 279453541Sshin{ 279553541Sshin bzero(sin6, sizeof(*sin6)); 279653541Sshin sin6->sin6_len = sizeof(struct sockaddr_in6); 279753541Sshin sin6->sin6_family = AF_INET6; 279853541Sshin sin6->sin6_port = sin->sin_port; 279953541Sshin sin6->sin6_addr.s6_addr32[0] = 0; 280053541Sshin sin6->sin6_addr.s6_addr32[1] = 0; 280153541Sshin sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP; 280253541Sshin sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; 280353541Sshin} 280453541Sshin 280553541Sshin/* Convert sockaddr_in6 into sockaddr_in. */ 280653541Sshinvoid 280753541Sshinin6_sin6_2_sin_in_sock(struct sockaddr *nam) 280853541Sshin{ 280953541Sshin struct sockaddr_in *sin_p; 281053541Sshin struct sockaddr_in6 sin6; 281153541Sshin 281253541Sshin /* 281353541Sshin * Save original sockaddr_in6 addr and convert it 281453541Sshin * to sockaddr_in. 281553541Sshin */ 281653541Sshin sin6 = *(struct sockaddr_in6 *)nam; 281753541Sshin sin_p = (struct sockaddr_in *)nam; 281853541Sshin in6_sin6_2_sin(sin_p, &sin6); 281953541Sshin} 282053541Sshin 282153541Sshin/* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */ 282253541Sshinvoid 282353541Sshinin6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam) 282453541Sshin{ 282553541Sshin struct sockaddr_in *sin_p; 282653541Sshin struct sockaddr_in6 *sin6_p; 282753541Sshin 2828240310Sglebius sin6_p = malloc(sizeof *sin6_p, M_SONAME, M_WAITOK); 282953541Sshin sin_p = (struct sockaddr_in *)*nam; 283053541Sshin in6_sin_2_v4mapsin6(sin_p, sin6_p); 2831184205Sdes free(*nam, M_SONAME); 283253541Sshin *nam = (struct sockaddr *)sin6_p; 283353541Sshin} 2834