in6.c revision 196864
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: head/sys/netinet6/in6.c 196864 2009-09-05 16:43:16Z qingli $"); 65174510Sobrien 6662587Sitojun#include "opt_inet.h" 6762587Sitojun#include "opt_inet6.h" 6862587Sitojun 6953541Sshin#include <sys/param.h> 7053541Sshin#include <sys/errno.h> 71186948Sbz#include <sys/jail.h> 7253541Sshin#include <sys/malloc.h> 7353541Sshin#include <sys/socket.h> 7453541Sshin#include <sys/socketvar.h> 7553541Sshin#include <sys/sockio.h> 7653541Sshin#include <sys/systm.h> 77164033Srwatson#include <sys/priv.h> 7853541Sshin#include <sys/proc.h> 7953541Sshin#include <sys/time.h> 8053541Sshin#include <sys/kernel.h> 8153541Sshin#include <sys/syslog.h> 8253541Sshin 8353541Sshin#include <net/if.h> 8453541Sshin#include <net/if_types.h> 8553541Sshin#include <net/route.h> 8653541Sshin#include <net/if_dl.h> 87185571Sbz#include <net/vnet.h> 8853541Sshin 8953541Sshin#include <netinet/in.h> 9053541Sshin#include <netinet/in_var.h> 91186119Sqingli#include <net/if_llatbl.h> 9253541Sshin#include <netinet/if_ether.h> 9378064Sume#include <netinet/in_systm.h> 9478064Sume#include <netinet/ip.h> 9578064Sume#include <netinet/in_pcb.h> 9653541Sshin 9762587Sitojun#include <netinet/ip6.h> 9853541Sshin#include <netinet6/ip6_var.h> 9995023Ssuz#include <netinet6/nd6.h> 10053541Sshin#include <netinet6/mld6_var.h> 10162587Sitojun#include <netinet6/ip6_mroute.h> 10253541Sshin#include <netinet6/in6_ifattach.h> 10362587Sitojun#include <netinet6/scope6_var.h> 10478064Sume#include <netinet6/in6_pcb.h> 10562587Sitojun 10653541Sshin/* 10753541Sshin * Definitions of some costant IP6 addresses. 10853541Sshin */ 10962587Sitojunconst struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 11062587Sitojunconst struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 11162587Sitojunconst struct in6_addr in6addr_nodelocal_allnodes = 11253541Sshin IN6ADDR_NODELOCAL_ALLNODES_INIT; 11362587Sitojunconst struct in6_addr in6addr_linklocal_allnodes = 11453541Sshin IN6ADDR_LINKLOCAL_ALLNODES_INIT; 11562587Sitojunconst struct in6_addr in6addr_linklocal_allrouters = 11653541Sshin IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; 117191672Sbmsconst struct in6_addr in6addr_linklocal_allv2routers = 118191672Sbms IN6ADDR_LINKLOCAL_ALLV2ROUTERS_INIT; 11953541Sshin 12062587Sitojunconst struct in6_addr in6mask0 = IN6MASK0; 12162587Sitojunconst struct in6_addr in6mask32 = IN6MASK32; 12262587Sitojunconst struct in6_addr in6mask64 = IN6MASK64; 12362587Sitojunconst struct in6_addr in6mask96 = IN6MASK96; 12462587Sitojunconst struct in6_addr in6mask128 = IN6MASK128; 12553541Sshin 126126552Sumeconst struct sockaddr_in6 sa6_any = 127126552Sume { sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 }; 12878064Sume 12962587Sitojunstatic int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, 13083366Sjulian struct ifnet *, struct thread *)); 13178064Sumestatic int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *, 132120891Sume struct sockaddr_in6 *, int)); 133175162Sobrienstatic void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *); 13453541Sshin 13583934Sbrooksint (*faithprefix_p)(struct in6_addr *); 13683934Sbrooks 137120891Sume 13878064Sume 13953541Sshinint 140171259Sdelphijin6_mask2len(struct in6_addr *mask, u_char *lim0) 14153541Sshin{ 14278064Sume int x = 0, y; 14378064Sume u_char *lim = lim0, *p; 14453541Sshin 145120891Sume /* ignore the scope_id part */ 146120891Sume if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask)) 14778064Sume lim = (u_char *)mask + sizeof(*mask); 14878064Sume for (p = (u_char *)mask; p < lim; x++, p++) { 14978064Sume if (*p != 0xff) 15053541Sshin break; 15153541Sshin } 15253541Sshin y = 0; 15378064Sume if (p < lim) { 15453541Sshin for (y = 0; y < 8; y++) { 15578064Sume if ((*p & (0x80 >> y)) == 0) 15653541Sshin break; 15753541Sshin } 15853541Sshin } 15978064Sume 16078064Sume /* 16178064Sume * when the limit pointer is given, do a stricter check on the 16278064Sume * remaining bits. 16378064Sume */ 16478064Sume if (p < lim) { 16578064Sume if (y != 0 && (*p & (0x00ff >> y)) != 0) 166120856Sume return (-1); 16778064Sume for (p = p + 1; p < lim; p++) 16878064Sume if (*p != 0) 169120856Sume return (-1); 17078064Sume } 171120891Sume 17253541Sshin return x * 8 + y; 17353541Sshin} 17453541Sshin 17553541Sshin#define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) 17662587Sitojun#define ia62ifa(ia6) (&((ia6)->ia_ifa)) 17753541Sshin 17853541Sshinint 179171259Sdelphijin6_control(struct socket *so, u_long cmd, caddr_t data, 180171259Sdelphij struct ifnet *ifp, struct thread *td) 18153541Sshin{ 18253541Sshin struct in6_ifreq *ifr = (struct in6_ifreq *)data; 18378064Sume struct in6_ifaddr *ia = NULL; 18453541Sshin struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; 185151539Ssuz struct sockaddr_in6 *sa6; 186164033Srwatson int error; 18753541Sshin 18862587Sitojun switch (cmd) { 18962587Sitojun case SIOCGETSGCNT_IN6: 19062587Sitojun case SIOCGETMIFCNT_IN6: 191166938Sbms return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP); 19262587Sitojun } 19353541Sshin 194121742Sume switch(cmd) { 195121742Sume case SIOCAADDRCTL_POLICY: 196121742Sume case SIOCDADDRCTL_POLICY: 197164033Srwatson if (td != NULL) { 198164033Srwatson error = priv_check(td, PRIV_NETINET_ADDRCTRL6); 199164033Srwatson if (error) 200164033Srwatson return (error); 201164033Srwatson } 202121742Sume return (in6_src_ioctl(cmd, data)); 203121742Sume } 204121742Sume 20562587Sitojun if (ifp == NULL) 206120856Sume return (EOPNOTSUPP); 20753541Sshin 20853541Sshin switch (cmd) { 20953541Sshin case SIOCSNDFLUSH_IN6: 21053541Sshin case SIOCSPFXFLUSH_IN6: 21153541Sshin case SIOCSRTRFLUSH_IN6: 21262587Sitojun case SIOCSDEFIFACE_IN6: 21362587Sitojun case SIOCSIFINFO_FLAGS: 214193893Scperciva case SIOCSIFINFO_IN6: 215164033Srwatson if (td != NULL) { 216164033Srwatson error = priv_check(td, PRIV_NETINET_ND6); 217164033Srwatson if (error) 218164033Srwatson return (error); 219164033Srwatson } 220120891Sume /* FALLTHROUGH */ 22178064Sume case OSIOCGIFINFO_IN6: 22253541Sshin case SIOCGIFINFO_IN6: 22353541Sshin case SIOCGDRLST_IN6: 22453541Sshin case SIOCGPRLST_IN6: 22553541Sshin case SIOCGNBRINFO_IN6: 22662587Sitojun case SIOCGDEFIFACE_IN6: 227120856Sume return (nd6_ioctl(cmd, data, ifp)); 22853541Sshin } 22953541Sshin 23053541Sshin switch (cmd) { 23153541Sshin case SIOCSIFPREFIX_IN6: 23253541Sshin case SIOCDIFPREFIX_IN6: 23353541Sshin case SIOCAIFPREFIX_IN6: 23453541Sshin case SIOCCIFPREFIX_IN6: 23553541Sshin case SIOCSGIFPREFIX_IN6: 23653541Sshin case SIOCGIFPREFIX_IN6: 23778064Sume log(LOG_NOTICE, 23878064Sume "prefix ioctls are now invalidated. " 23978064Sume "please use ifconfig.\n"); 240120856Sume return (EOPNOTSUPP); 24153541Sshin } 24253541Sshin 24395023Ssuz switch (cmd) { 24462587Sitojun case SIOCSSCOPE6: 245164033Srwatson if (td != NULL) { 246164033Srwatson error = priv_check(td, PRIV_NETINET_SCOPE6); 247164033Srwatson if (error) 248164033Srwatson return (error); 249164033Srwatson } 250121161Sume return (scope6_set(ifp, 251121161Sume (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 25262587Sitojun case SIOCGSCOPE6: 253121161Sume return (scope6_get(ifp, 254121161Sume (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 25562587Sitojun case SIOCGSCOPE6DEF: 256121161Sume return (scope6_get_default((struct scope6_id *) 257121161Sume ifr->ifr_ifru.ifru_scope_id)); 25862587Sitojun } 25962587Sitojun 26053541Sshin switch (cmd) { 26153541Sshin case SIOCALIFADDR: 262175630Sbz if (td != NULL) { 263175630Sbz error = priv_check(td, PRIV_NET_ADDIFADDR); 264175630Sbz if (error) 265175630Sbz return (error); 266175630Sbz } 267175630Sbz return in6_lifaddr_ioctl(so, cmd, data, ifp, td); 268175630Sbz 26953541Sshin case SIOCDLIFADDR: 270164033Srwatson if (td != NULL) { 271175630Sbz error = priv_check(td, PRIV_NET_DELIFADDR); 272164033Srwatson if (error) 273164033Srwatson return (error); 274164033Srwatson } 275120891Sume /* FALLTHROUGH */ 27653541Sshin case SIOCGLIFADDR: 27783366Sjulian return in6_lifaddr_ioctl(so, cmd, data, ifp, td); 27853541Sshin } 27953541Sshin 28053541Sshin /* 28153541Sshin * Find address for this interface, if it exists. 282151539Ssuz * 283151539Ssuz * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation 284151539Ssuz * only, and used the first interface address as the target of other 285151539Ssuz * operations (without checking ifra_addr). This was because netinet 286151539Ssuz * code/API assumed at most 1 interface address per interface. 287151539Ssuz * Since IPv6 allows a node to assign multiple addresses 288151539Ssuz * on a single interface, we almost always look and check the 289151539Ssuz * presence of ifra_addr, and reject invalid ones here. 290151539Ssuz * It also decreases duplicated code among SIOC*_IN6 operations. 29153541Sshin */ 292151539Ssuz switch (cmd) { 293151539Ssuz case SIOCAIFADDR_IN6: 294151539Ssuz case SIOCSIFPHYADDR_IN6: 295151539Ssuz sa6 = &ifra->ifra_addr; 296151539Ssuz break; 297151539Ssuz case SIOCSIFADDR_IN6: 298151539Ssuz case SIOCGIFADDR_IN6: 299151539Ssuz case SIOCSIFDSTADDR_IN6: 300151539Ssuz case SIOCSIFNETMASK_IN6: 301151539Ssuz case SIOCGIFDSTADDR_IN6: 302151539Ssuz case SIOCGIFNETMASK_IN6: 303151539Ssuz case SIOCDIFADDR_IN6: 304151539Ssuz case SIOCGIFPSRCADDR_IN6: 305151539Ssuz case SIOCGIFPDSTADDR_IN6: 306151539Ssuz case SIOCGIFAFLAG_IN6: 307151539Ssuz case SIOCSNDFLUSH_IN6: 308151539Ssuz case SIOCSPFXFLUSH_IN6: 309151539Ssuz case SIOCSRTRFLUSH_IN6: 310151539Ssuz case SIOCGIFALIFETIME_IN6: 311151539Ssuz case SIOCSIFALIFETIME_IN6: 312151539Ssuz case SIOCGIFSTAT_IN6: 313151539Ssuz case SIOCGIFSTAT_ICMP6: 314151539Ssuz sa6 = &ifr->ifr_addr; 315151539Ssuz break; 316151539Ssuz default: 317151539Ssuz sa6 = NULL; 318151539Ssuz break; 319151539Ssuz } 320151539Ssuz if (sa6 && sa6->sin6_family == AF_INET6) { 321151539Ssuz if (sa6->sin6_scope_id != 0) 322151539Ssuz error = sa6_embedscope(sa6, 0); 323148385Sume else 324151539Ssuz error = in6_setscope(&sa6->sin6_addr, ifp, NULL); 325148385Sume if (error != 0) 326148385Sume return (error); 327188144Sjamie if (td != NULL && (error = prison_check_ip6(td->td_ucred, 328188144Sjamie &sa6->sin6_addr)) != 0) 329188144Sjamie return (error); 330151539Ssuz ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr); 331151539Ssuz } else 332151539Ssuz ia = NULL; 33353541Sshin 33453541Sshin switch (cmd) { 33578064Sume case SIOCSIFADDR_IN6: 33678064Sume case SIOCSIFDSTADDR_IN6: 33778064Sume case SIOCSIFNETMASK_IN6: 33878064Sume /* 33978064Sume * Since IPv6 allows a node to assign multiple addresses 340151465Ssuz * on a single interface, SIOCSIFxxx ioctls are deprecated. 34178064Sume */ 34278064Sume /* we decided to obsolete this command (20000704) */ 343194760Srwatson error = EINVAL; 344194760Srwatson goto out; 34553541Sshin 34653541Sshin case SIOCDIFADDR_IN6: 34762587Sitojun /* 34878064Sume * for IPv4, we look for existing in_ifaddr here to allow 349151465Ssuz * "ifconfig if0 delete" to remove the first IPv4 address on 350151465Ssuz * the interface. For IPv6, as the spec allows multiple 351151465Ssuz * interface address from the day one, we consider "remove the 352151465Ssuz * first one" semantics to be not preferable. 35362587Sitojun */ 354194760Srwatson if (ia == NULL) { 355194760Srwatson error = EADDRNOTAVAIL; 356194760Srwatson goto out; 357194760Srwatson } 35853541Sshin /* FALLTHROUGH */ 35953541Sshin case SIOCAIFADDR_IN6: 36062587Sitojun /* 36178064Sume * We always require users to specify a valid IPv6 address for 36278064Sume * the corresponding operation. 36362587Sitojun */ 36478064Sume if (ifra->ifra_addr.sin6_family != AF_INET6 || 365194760Srwatson ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) { 366194760Srwatson error = EAFNOSUPPORT; 367194760Srwatson goto out; 368194760Srwatson } 36953541Sshin 370164033Srwatson if (td != NULL) { 371175630Sbz error = priv_check(td, (cmd == SIOCDIFADDR_IN6) ? 372175630Sbz PRIV_NET_DELIFADDR : PRIV_NET_ADDIFADDR); 373164033Srwatson if (error) 374194760Srwatson goto out; 375164033Srwatson } 37653541Sshin break; 37753541Sshin 37853541Sshin case SIOCGIFADDR_IN6: 37953541Sshin /* This interface is basically deprecated. use SIOCGIFCONF. */ 380120891Sume /* FALLTHROUGH */ 38153541Sshin case SIOCGIFAFLAG_IN6: 38253541Sshin case SIOCGIFNETMASK_IN6: 38353541Sshin case SIOCGIFDSTADDR_IN6: 38453541Sshin case SIOCGIFALIFETIME_IN6: 38553541Sshin /* must think again about its semantics */ 386194760Srwatson if (ia == NULL) { 387194760Srwatson error = EADDRNOTAVAIL; 388194760Srwatson goto out; 389194760Srwatson } 39053541Sshin break; 391194760Srwatson 39253541Sshin case SIOCSIFALIFETIME_IN6: 39353541Sshin { 39453541Sshin struct in6_addrlifetime *lt; 39553541Sshin 396164033Srwatson if (td != NULL) { 397164033Srwatson error = priv_check(td, PRIV_NETINET_ALIFETIME6); 398164033Srwatson if (error) 399194760Srwatson goto out; 400164033Srwatson } 401194760Srwatson if (ia == NULL) { 402194760Srwatson error = EADDRNOTAVAIL; 403194760Srwatson goto out; 404194760Srwatson } 40553541Sshin /* sanity for overflow - beware unsigned */ 40653541Sshin lt = &ifr->ifr_ifru.ifru_lifetime; 407126552Sume if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME && 408126552Sume lt->ia6t_vltime + time_second < time_second) { 409194760Srwatson error = EINVAL; 410194760Srwatson goto out; 41153541Sshin } 412126552Sume if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME && 413126552Sume lt->ia6t_pltime + time_second < time_second) { 414194760Srwatson error = EINVAL; 415194760Srwatson goto out; 41653541Sshin } 41753541Sshin break; 41853541Sshin } 41953541Sshin } 42053541Sshin 42153541Sshin switch (cmd) { 42253541Sshin case SIOCGIFADDR_IN6: 42353541Sshin ifr->ifr_addr = ia->ia_addr; 424148385Sume if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0) 425194760Srwatson goto out; 42653541Sshin break; 42753541Sshin 42853541Sshin case SIOCGIFDSTADDR_IN6: 429194760Srwatson if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 430194760Srwatson error = EINVAL; 431194760Srwatson goto out; 432194760Srwatson } 43362587Sitojun /* 43462587Sitojun * XXX: should we check if ifa_dstaddr is NULL and return 43562587Sitojun * an error? 43662587Sitojun */ 43753541Sshin ifr->ifr_dstaddr = ia->ia_dstaddr; 438148385Sume if ((error = sa6_recoverscope(&ifr->ifr_dstaddr)) != 0) 439194760Srwatson goto out; 44053541Sshin break; 44153541Sshin 44253541Sshin case SIOCGIFNETMASK_IN6: 44353541Sshin ifr->ifr_addr = ia->ia_prefixmask; 44453541Sshin break; 44553541Sshin 44653541Sshin case SIOCGIFAFLAG_IN6: 44753541Sshin ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags; 44853541Sshin break; 44953541Sshin 45053541Sshin case SIOCGIFSTAT_IN6: 451194760Srwatson if (ifp == NULL) { 452194760Srwatson error = EINVAL; 453194760Srwatson goto out; 454194760Srwatson } 455121161Sume bzero(&ifr->ifr_ifru.ifru_stat, 456121161Sume sizeof(ifr->ifr_ifru.ifru_stat)); 457121161Sume ifr->ifr_ifru.ifru_stat = 458121161Sume *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat; 45953541Sshin break; 46053541Sshin 46153541Sshin case SIOCGIFSTAT_ICMP6: 462194760Srwatson if (ifp == NULL) { 463194760Srwatson error = EINVAL; 464194760Srwatson goto out; 465194760Srwatson } 466155454Sgnn bzero(&ifr->ifr_ifru.ifru_icmp6stat, 467121161Sume sizeof(ifr->ifr_ifru.ifru_icmp6stat)); 468121161Sume ifr->ifr_ifru.ifru_icmp6stat = 469121161Sume *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat; 47053541Sshin break; 47153541Sshin 47253541Sshin case SIOCGIFALIFETIME_IN6: 47353541Sshin ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime; 474151539Ssuz if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 475151539Ssuz time_t maxexpire; 476151539Ssuz struct in6_addrlifetime *retlt = 477151539Ssuz &ifr->ifr_ifru.ifru_lifetime; 478151539Ssuz 479151539Ssuz /* 480151539Ssuz * XXX: adjust expiration time assuming time_t is 481151539Ssuz * signed. 482151539Ssuz */ 483151539Ssuz maxexpire = (-1) & 484151546Ssuz ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); 485151539Ssuz if (ia->ia6_lifetime.ia6t_vltime < 486151539Ssuz maxexpire - ia->ia6_updatetime) { 487151539Ssuz retlt->ia6t_expire = ia->ia6_updatetime + 488151539Ssuz ia->ia6_lifetime.ia6t_vltime; 489151539Ssuz } else 490151539Ssuz retlt->ia6t_expire = maxexpire; 491151539Ssuz } 492151539Ssuz if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 493151539Ssuz time_t maxexpire; 494151539Ssuz struct in6_addrlifetime *retlt = 495151539Ssuz &ifr->ifr_ifru.ifru_lifetime; 496151539Ssuz 497151539Ssuz /* 498151539Ssuz * XXX: adjust expiration time assuming time_t is 499151539Ssuz * signed. 500151539Ssuz */ 501151539Ssuz maxexpire = (-1) & 502151546Ssuz ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); 503151539Ssuz if (ia->ia6_lifetime.ia6t_pltime < 504151539Ssuz maxexpire - ia->ia6_updatetime) { 505151539Ssuz retlt->ia6t_preferred = ia->ia6_updatetime + 506151539Ssuz ia->ia6_lifetime.ia6t_pltime; 507151539Ssuz } else 508151539Ssuz retlt->ia6t_preferred = maxexpire; 509151539Ssuz } 51053541Sshin break; 51153541Sshin 51253541Sshin case SIOCSIFALIFETIME_IN6: 51353541Sshin ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime; 51453541Sshin /* for sanity */ 51553541Sshin if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 51653541Sshin ia->ia6_lifetime.ia6t_expire = 51753541Sshin time_second + ia->ia6_lifetime.ia6t_vltime; 51853541Sshin } else 51953541Sshin ia->ia6_lifetime.ia6t_expire = 0; 52053541Sshin if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 52153541Sshin ia->ia6_lifetime.ia6t_preferred = 52253541Sshin time_second + ia->ia6_lifetime.ia6t_pltime; 52353541Sshin } else 52453541Sshin ia->ia6_lifetime.ia6t_preferred = 0; 52553541Sshin break; 52653541Sshin 52778064Sume case SIOCAIFADDR_IN6: 52878064Sume { 529194760Srwatson int i; 530151539Ssuz struct nd_prefixctl pr0; 531151539Ssuz struct nd_prefix *pr; 53278064Sume 53362587Sitojun /* 53478064Sume * first, make or update the interface address structure, 53578064Sume * and link it to the list. 53662587Sitojun */ 537151539Ssuz if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0) 538194760Srwatson goto out; 539194760Srwatson if (ia != NULL) 540194760Srwatson ifa_free(&ia->ia_ifa); 541151915Ssuz if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr)) 542151915Ssuz == NULL) { 543171260Sdelphij /* 544151915Ssuz * this can happen when the user specify the 0 valid 545151915Ssuz * lifetime. 546151915Ssuz */ 547151915Ssuz break; 548151915Ssuz } 54953541Sshin 55078064Sume /* 55178064Sume * then, make the prefix on-link on the interface. 55278064Sume * XXX: we'd rather create the prefix before the address, but 55378064Sume * we need at least one address to install the corresponding 55478064Sume * interface route, so we configure the address first. 55578064Sume */ 55678064Sume 55778064Sume /* 55878064Sume * convert mask to prefix length (prefixmask has already 55978064Sume * been validated in in6_update_ifa(). 56078064Sume */ 56178064Sume bzero(&pr0, sizeof(pr0)); 56278064Sume pr0.ndpr_ifp = ifp; 56378064Sume pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 564120891Sume NULL); 565120891Sume if (pr0.ndpr_plen == 128) { 56678064Sume break; /* we don't need to install a host route. */ 567120891Sume } 56878064Sume pr0.ndpr_prefix = ifra->ifra_addr; 56978064Sume /* apply the mask for safety. */ 57078064Sume for (i = 0; i < 4; i++) { 57178064Sume pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 572120891Sume ifra->ifra_prefixmask.sin6_addr.s6_addr32[i]; 57378064Sume } 57478064Sume /* 57595023Ssuz * XXX: since we don't have an API to set prefix (not address) 57695023Ssuz * lifetimes, we just use the same lifetimes as addresses. 57795023Ssuz * The (temporarily) installed lifetimes can be overridden by 57895023Ssuz * later advertised RAs (when accept_rtadv is non 0), which is 57995023Ssuz * an intended behavior. 58078064Sume */ 58178064Sume pr0.ndpr_raf_onlink = 1; /* should be configurable? */ 58278064Sume pr0.ndpr_raf_auto = 583120891Sume ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0); 58478064Sume pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime; 58578064Sume pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime; 58678064Sume 587120891Sume /* add the prefix if not yet. */ 58878064Sume if ((pr = nd6_prefix_lookup(&pr0)) == NULL) { 58978064Sume /* 59078064Sume * nd6_prelist_add will install the corresponding 59178064Sume * interface route. 59278064Sume */ 59378064Sume if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) 594194760Srwatson goto out; 59578064Sume if (pr == NULL) { 596120891Sume log(LOG_ERR, "nd6_prelist_add succeeded but " 59778064Sume "no prefix\n"); 598194760Srwatson error = EINVAL; 599194760Srwatson goto out; 60078064Sume } 60178064Sume } 60278064Sume 603151915Ssuz /* relate the address to the prefix */ 604151915Ssuz if (ia->ia6_ndpr == NULL) { 605151915Ssuz ia->ia6_ndpr = pr; 606151915Ssuz pr->ndpr_refcnt++; 60778064Sume 60878064Sume /* 609151915Ssuz * If this is the first autoconf address from the 610151915Ssuz * prefix, create a temporary address as well 611151915Ssuz * (when required). 61278064Sume */ 613151915Ssuz if ((ia->ia6_flags & IN6_IFF_AUTOCONF) && 614181803Sbz V_ip6_use_tempaddr && pr->ndpr_refcnt == 1) { 615151915Ssuz int e; 616151915Ssuz if ((e = in6_tmpifadd(ia, 1, 0)) != 0) { 617151915Ssuz log(LOG_NOTICE, "in6_control: failed " 618151915Ssuz "to create a temporary address, " 619151915Ssuz "errno=%d\n", e); 620151915Ssuz } 621151915Ssuz } 62262587Sitojun } 623151915Ssuz 624151915Ssuz /* 625151915Ssuz * this might affect the status of autoconfigured addresses, 626151915Ssuz * that is, this address might make other addresses detached. 627151915Ssuz */ 628151915Ssuz pfxlist_onlink_check(); 629126264Smlaier if (error == 0 && ia) 630126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 63178064Sume break; 63278064Sume } 63362587Sitojun 63478064Sume case SIOCDIFADDR_IN6: 63578064Sume { 636151539Ssuz struct nd_prefix *pr; 63778064Sume 63878064Sume /* 63978064Sume * If the address being deleted is the only one that owns 64078064Sume * the corresponding prefix, expire the prefix as well. 641120891Sume * XXX: theoretically, we don't have to worry about such 64278064Sume * relationship, since we separate the address management 64378064Sume * and the prefix management. We do this, however, to provide 64478064Sume * as much backward compatibility as possible in terms of 64578064Sume * the ioctl operation. 646151915Ssuz * Note that in6_purgeaddr() will decrement ndpr_refcnt. 64778064Sume */ 648151915Ssuz pr = ia->ia6_ndpr; 64978064Sume in6_purgeaddr(&ia->ia_ifa); 650151915Ssuz if (pr && pr->ndpr_refcnt == 0) 651151915Ssuz prelist_remove(pr); 652126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 65353541Sshin break; 65478064Sume } 65553541Sshin 65678064Sume default: 657194760Srwatson if (ifp == NULL || ifp->if_ioctl == 0) { 658194760Srwatson error = EOPNOTSUPP; 659194760Srwatson goto out; 660194760Srwatson } 661194760Srwatson error = (*ifp->if_ioctl)(ifp, cmd, data); 662194760Srwatson goto out; 66378064Sume } 66453541Sshin 665194760Srwatson error = 0; 666194760Srwatsonout: 667194760Srwatson if (ia != NULL) 668194760Srwatson ifa_free(&ia->ia_ifa); 669194760Srwatson return (error); 67078064Sume} 67153541Sshin 67278064Sume/* 67378064Sume * Update parameters of an IPv6 interface address. 67478064Sume * If necessary, a new entry is created and linked into address chains. 67578064Sume * This function is separated from in6_control(). 67678064Sume * XXX: should this be performed under splnet()? 67778064Sume */ 67878064Sumeint 679171259Sdelphijin6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, 680171259Sdelphij struct in6_ifaddr *ia, int flags) 68178064Sume{ 68278064Sume int error = 0, hostIsNew = 0, plen = -1; 68378064Sume struct sockaddr_in6 dst6; 68478064Sume struct in6_addrlifetime *lt; 685151539Ssuz struct in6_multi_mship *imm; 686151539Ssuz struct in6_multi *in6m_sol; 687148385Sume struct rtentry *rt; 688151539Ssuz int delay; 689165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 69078064Sume 69178064Sume /* Validate parameters */ 69278064Sume if (ifp == NULL || ifra == NULL) /* this maybe redundant */ 693120856Sume return (EINVAL); 69478064Sume 69578064Sume /* 69678064Sume * The destination address for a p2p link must have a family 69778064Sume * of AF_UNSPEC or AF_INET6. 69878064Sume */ 69978064Sume if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && 70078064Sume ifra->ifra_dstaddr.sin6_family != AF_INET6 && 70178064Sume ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) 702120856Sume return (EAFNOSUPPORT); 70378064Sume /* 70478064Sume * validate ifra_prefixmask. don't check sin6_family, netmask 70578064Sume * does not carry fields other than sin6_len. 70678064Sume */ 70778064Sume if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6)) 708120856Sume return (EINVAL); 70978064Sume /* 71078064Sume * Because the IPv6 address architecture is classless, we require 71178064Sume * users to specify a (non 0) prefix length (mask) for a new address. 71278064Sume * We also require the prefix (when specified) mask is valid, and thus 71378064Sume * reject a non-consecutive mask. 71478064Sume */ 71578064Sume if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0) 716120856Sume return (EINVAL); 71778064Sume if (ifra->ifra_prefixmask.sin6_len != 0) { 71878064Sume plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 719120891Sume (u_char *)&ifra->ifra_prefixmask + 720120891Sume ifra->ifra_prefixmask.sin6_len); 72178064Sume if (plen <= 0) 722120856Sume return (EINVAL); 723120891Sume } else { 72462587Sitojun /* 72595023Ssuz * In this case, ia must not be NULL. We just use its prefix 72678064Sume * length. 72762587Sitojun */ 72878064Sume plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 72978064Sume } 73078064Sume /* 73178064Sume * If the destination address on a p2p interface is specified, 73278064Sume * and the address is a scoped one, validate/set the scope 73378064Sume * zone identifier. 73478064Sume */ 73578064Sume dst6 = ifra->ifra_dstaddr; 736120891Sume if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 && 73778064Sume (dst6.sin6_family == AF_INET6)) { 738148385Sume struct in6_addr in6_tmp; 739126552Sume u_int32_t zoneid; 74078064Sume 741148385Sume in6_tmp = dst6.sin6_addr; 742148385Sume if (in6_setscope(&in6_tmp, ifp, &zoneid)) 743148385Sume return (EINVAL); /* XXX: should be impossible */ 744148385Sume 745148385Sume if (dst6.sin6_scope_id != 0) { 746148385Sume if (dst6.sin6_scope_id != zoneid) 747148385Sume return (EINVAL); 748148385Sume } else /* user omit to specify the ID. */ 749126552Sume dst6.sin6_scope_id = zoneid; 750148385Sume 751148385Sume /* convert into the internal form */ 752148385Sume if (sa6_embedscope(&dst6, 0)) 753148385Sume return (EINVAL); /* XXX: should be impossible */ 75478064Sume } 75578064Sume /* 75678064Sume * The destination address can be specified only for a p2p or a 75778064Sume * loopback interface. If specified, the corresponding prefix length 75878064Sume * must be 128. 75978064Sume */ 76078064Sume if (ifra->ifra_dstaddr.sin6_family == AF_INET6) { 76178064Sume if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) { 762126552Sume /* XXX: noisy message */ 763122059Sume nd6log((LOG_INFO, "in6_update_ifa: a destination can " 764122059Sume "be specified for a p2p or a loopback IF only\n")); 765120856Sume return (EINVAL); 76678064Sume } 76778064Sume if (plen != 128) { 768122059Sume nd6log((LOG_INFO, "in6_update_ifa: prefixlen should " 769122059Sume "be 128 when dstaddr is specified\n")); 770120856Sume return (EINVAL); 77178064Sume } 77278064Sume } 77378064Sume /* lifetime consistency check */ 77478064Sume lt = &ifra->ifra_lifetime; 775151539Ssuz if (lt->ia6t_pltime > lt->ia6t_vltime) 776151539Ssuz return (EINVAL); 77778064Sume if (lt->ia6t_vltime == 0) { 77862587Sitojun /* 77978064Sume * the following log might be noisy, but this is a typical 78078064Sume * configuration mistake or a tool's bug. 78162587Sitojun */ 782122059Sume nd6log((LOG_INFO, 78378064Sume "in6_update_ifa: valid lifetime is 0 for %s\n", 784165118Sbz ip6_sprintf(ip6buf, &ifra->ifra_addr.sin6_addr))); 785151539Ssuz 786151539Ssuz if (ia == NULL) 787151539Ssuz return (0); /* there's nothing to do */ 78878064Sume } 78962587Sitojun 79078064Sume /* 79178064Sume * If this is a new address, allocate a new ifaddr and link it 79278064Sume * into chains. 79378064Sume */ 79478064Sume if (ia == NULL) { 79578064Sume hostIsNew = 1; 79679763Sume /* 79779763Sume * When in6_update_ifa() is called in a process of a received 798120891Sume * RA, it is called under an interrupt context. So, we should 799120891Sume * call malloc with M_NOWAIT. 80079763Sume */ 801120891Sume ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR, 802120891Sume M_NOWAIT); 80378064Sume if (ia == NULL) 80478064Sume return (ENOBUFS); 80578064Sume bzero((caddr_t)ia, sizeof(*ia)); 806194602Srwatson ifa_init(&ia->ia_ifa); 807170202Sjinmei LIST_INIT(&ia->ia6_memberships); 808151539Ssuz /* Initialize the address and masks, and put time stamp */ 80978064Sume ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 81078064Sume ia->ia_addr.sin6_family = AF_INET6; 81178064Sume ia->ia_addr.sin6_len = sizeof(ia->ia_addr); 812151539Ssuz ia->ia6_createtime = time_second; 81378064Sume if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { 81478064Sume /* 81578064Sume * XXX: some functions expect that ifa_dstaddr is not 81678064Sume * NULL for p2p interfaces. 81778064Sume */ 818120891Sume ia->ia_ifa.ifa_dstaddr = 819120891Sume (struct sockaddr *)&ia->ia_dstaddr; 82078064Sume } else { 82178064Sume ia->ia_ifa.ifa_dstaddr = NULL; 82253541Sshin } 823108033Shsu ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; 82478064Sume ia->ia_ifp = ifp; 825194760Srwatson ifa_ref(&ia->ia_ifa); /* if_addrhead */ 826191323Srwatson IF_ADDR_LOCK(ifp); 827191340Srwatson TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); 828191323Srwatson IF_ADDR_UNLOCK(ifp); 829194907Srwatson 830194971Srwatson ifa_ref(&ia->ia_ifa); /* in6_ifaddrhead */ 831194971Srwatson IN6_IFADDR_WLOCK(); 832194907Srwatson TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link); 833194971Srwatson IN6_IFADDR_WUNLOCK(); 83478064Sume } 83578064Sume 836151539Ssuz /* update timestamp */ 837151539Ssuz ia->ia6_updatetime = time_second; 838151539Ssuz 83978064Sume /* set prefix mask */ 84078064Sume if (ifra->ifra_prefixmask.sin6_len) { 84178064Sume /* 84278064Sume * We prohibit changing the prefix length of an existing 84378064Sume * address, because 84478064Sume * + such an operation should be rare in IPv6, and 84578064Sume * + the operation would confuse prefix management. 84678064Sume */ 84778064Sume if (ia->ia_prefixmask.sin6_len && 84878064Sume in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) { 849122059Sume nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an" 85078064Sume " existing (%s) address should not be changed\n", 851165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); 85278064Sume error = EINVAL; 85378064Sume goto unlink; 85453541Sshin } 85578064Sume ia->ia_prefixmask = ifra->ifra_prefixmask; 85678064Sume } 85778064Sume 85878064Sume /* 85978064Sume * If a new destination address is specified, scrub the old one and 86078064Sume * install the new destination. Note that the interface must be 861120891Sume * p2p or loopback (see the check above.) 86278064Sume */ 86378064Sume if (dst6.sin6_family == AF_INET6 && 864120891Sume !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) { 86578064Sume int e; 86678064Sume 86778064Sume if ((ia->ia_flags & IFA_ROUTE) != 0 && 868120891Sume (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) { 869122059Sume nd6log((LOG_ERR, "in6_update_ifa: failed to remove " 87078064Sume "a route to the old destination: %s\n", 871165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); 87278064Sume /* proceed anyway... */ 873120891Sume } else 87478064Sume ia->ia_flags &= ~IFA_ROUTE; 87578064Sume ia->ia_dstaddr = dst6; 87678064Sume } 87753541Sshin 878148385Sume /* 879148385Sume * Set lifetimes. We do not refer to ia6t_expire and ia6t_preferred 880148385Sume * to see if the address is deprecated or invalidated, but initialize 881148385Sume * these members for applications. 882148385Sume */ 883148385Sume ia->ia6_lifetime = ifra->ifra_lifetime; 884148385Sume if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 885148385Sume ia->ia6_lifetime.ia6t_expire = 886148385Sume time_second + ia->ia6_lifetime.ia6t_vltime; 887148385Sume } else 888148385Sume ia->ia6_lifetime.ia6t_expire = 0; 889148385Sume if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 890148385Sume ia->ia6_lifetime.ia6t_preferred = 891148385Sume time_second + ia->ia6_lifetime.ia6t_pltime; 892148385Sume } else 893148385Sume ia->ia6_lifetime.ia6t_preferred = 0; 894148385Sume 89578064Sume /* reset the interface and routing table appropriately. */ 89678064Sume if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) 89778064Sume goto unlink; 89878064Sume 89978064Sume /* 900148385Sume * configure address flags. 901148385Sume */ 902148385Sume ia->ia6_flags = ifra->ifra_flags; 903148385Sume /* 904148385Sume * backward compatibility - if IN6_IFF_DEPRECATED is set from the 905148385Sume * userland, make it deprecated. 906148385Sume */ 907148385Sume if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) { 908148385Sume ia->ia6_lifetime.ia6t_pltime = 0; 909148385Sume ia->ia6_lifetime.ia6t_preferred = time_second; 910148385Sume } 911148385Sume /* 912151539Ssuz * Make the address tentative before joining multicast addresses, 913151539Ssuz * so that corresponding MLD responses would not have a tentative 914151539Ssuz * source address. 915148385Sume */ 916151539Ssuz ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /* safety */ 917151539Ssuz if (hostIsNew && in6if_do_dad(ifp)) 918148385Sume ia->ia6_flags |= IN6_IFF_TENTATIVE; 919148385Sume 920148385Sume /* 921148385Sume * We are done if we have simply modified an existing address. 922148385Sume */ 923148385Sume if (!hostIsNew) 924148385Sume return (error); 925148385Sume 926148385Sume /* 92778064Sume * Beyond this point, we should call in6_purgeaddr upon an error, 928120891Sume * not just go to unlink. 92978064Sume */ 93078064Sume 931151465Ssuz /* Join necessary multicast groups */ 932151539Ssuz in6m_sol = NULL; 93378064Sume if ((ifp->if_flags & IFF_MULTICAST) != 0) { 93478064Sume struct sockaddr_in6 mltaddr, mltmask; 935148385Sume struct in6_addr llsol; 93678064Sume 937148385Sume /* join solicited multicast addr for new host id */ 938148385Sume bzero(&llsol, sizeof(struct in6_addr)); 939151465Ssuz llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL; 940148385Sume llsol.s6_addr32[1] = 0; 941148385Sume llsol.s6_addr32[2] = htonl(1); 942148385Sume llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3]; 943148385Sume llsol.s6_addr8[12] = 0xff; 944148385Sume if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) { 945148385Sume /* XXX: should not happen */ 946148385Sume log(LOG_ERR, "in6_update_ifa: " 947148385Sume "in6_setscope failed\n"); 948148385Sume goto cleanup; 94953541Sshin } 950151539Ssuz delay = 0; 951151539Ssuz if ((flags & IN6_IFAUPDATE_DADDELAY)) { 952151539Ssuz /* 953151539Ssuz * We need a random delay for DAD on the address 954151539Ssuz * being configured. It also means delaying 955151539Ssuz * transmission of the corresponding MLD report to 956151539Ssuz * avoid report collision. 957151539Ssuz * [draft-ietf-ipv6-rfc2462bis-02.txt] 958151539Ssuz */ 959151539Ssuz delay = arc4random() % 960151539Ssuz (MAX_RTR_SOLICITATION_DELAY * hz); 961151539Ssuz } 962151539Ssuz imm = in6_joingroup(ifp, &llsol, &error, delay); 963170202Sjinmei if (imm == NULL) { 964148385Sume nd6log((LOG_WARNING, 965148385Sume "in6_update_ifa: addmulti failed for " 966148385Sume "%s on %s (errno=%d)\n", 967165118Sbz ip6_sprintf(ip6buf, &llsol), if_name(ifp), 968148385Sume error)); 969195102Srwatson goto cleanup; 970148385Sume } 971170202Sjinmei LIST_INSERT_HEAD(&ia->ia6_memberships, 972170202Sjinmei imm, i6mm_chain); 973151539Ssuz in6m_sol = imm->i6mm_maddr; 97453541Sshin 97578064Sume bzero(&mltmask, sizeof(mltmask)); 97678064Sume mltmask.sin6_len = sizeof(struct sockaddr_in6); 97778064Sume mltmask.sin6_family = AF_INET6; 97878064Sume mltmask.sin6_addr = in6mask32; 979151465Ssuz#define MLTMASK_LEN 4 /* mltmask's masklen (=32bit=4octet) */ 98053541Sshin 98153541Sshin /* 98278064Sume * join link-local all-nodes address 98371207Sitojun */ 98478064Sume bzero(&mltaddr, sizeof(mltaddr)); 98578064Sume mltaddr.sin6_len = sizeof(struct sockaddr_in6); 98678064Sume mltaddr.sin6_family = AF_INET6; 98778064Sume mltaddr.sin6_addr = in6addr_linklocal_allnodes; 988148385Sume if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 989148385Sume 0) 990148385Sume goto cleanup; /* XXX: should not fail */ 99171207Sitojun 992148385Sume /* 993148385Sume * XXX: do we really need this automatic routes? 994148385Sume * We should probably reconsider this stuff. Most applications 995148385Sume * actually do not need the routes, since they usually specify 996148385Sume * the outgoing interface. 997148385Sume */ 998148385Sume rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL); 999148385Sume if (rt) { 1000174375Sjulian /* XXX: only works in !SCOPEDROUTING case. */ 1001148385Sume if (memcmp(&mltaddr.sin6_addr, 1002148385Sume &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, 1003151465Ssuz MLTMASK_LEN)) { 1004148385Sume RTFREE_LOCKED(rt); 1005148385Sume rt = NULL; 1006148385Sume } 1007148385Sume } 1008148385Sume if (!rt) { 1009148385Sume error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, 1010148385Sume (struct sockaddr *)&ia->ia_addr, 1011186119Sqingli (struct sockaddr *)&mltmask, RTF_UP, 1012148385Sume (struct rtentry **)0); 1013148385Sume if (error) 1014148385Sume goto cleanup; 1015151539Ssuz } else { 1016151539Ssuz RTFREE_LOCKED(rt); 1017151539Ssuz } 101878064Sume 1019151539Ssuz imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0); 1020151539Ssuz if (!imm) { 1021151539Ssuz nd6log((LOG_WARNING, 1022151539Ssuz "in6_update_ifa: addmulti failed for " 1023151539Ssuz "%s on %s (errno=%d)\n", 1024165118Sbz ip6_sprintf(ip6buf, &mltaddr.sin6_addr), 1025151539Ssuz if_name(ifp), error)); 1026151539Ssuz goto cleanup; 1027151539Ssuz } 1028170202Sjinmei LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 1029151539Ssuz 103071207Sitojun /* 103178064Sume * join node information group address 103253541Sshin */ 1033151539Ssuz delay = 0; 1034151539Ssuz if ((flags & IN6_IFAUPDATE_DADDELAY)) { 1035151539Ssuz /* 1036151539Ssuz * The spec doesn't say anything about delay for this 1037151539Ssuz * group, but the same logic should apply. 1038151539Ssuz */ 1039151539Ssuz delay = arc4random() % 1040151539Ssuz (MAX_RTR_SOLICITATION_DELAY * hz); 1041151539Ssuz } 1042192895Sjamie if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) { 1043151539Ssuz imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 1044151539Ssuz delay); /* XXX jinmei */ 1045151539Ssuz if (!imm) { 1046151539Ssuz nd6log((LOG_WARNING, "in6_update_ifa: " 1047151539Ssuz "addmulti failed for %s on %s " 1048151539Ssuz "(errno=%d)\n", 1049165118Sbz ip6_sprintf(ip6buf, &mltaddr.sin6_addr), 1050151539Ssuz if_name(ifp), error)); 1051151539Ssuz /* XXX not very fatal, go on... */ 1052170202Sjinmei } else { 1053170202Sjinmei LIST_INSERT_HEAD(&ia->ia6_memberships, 1054170202Sjinmei imm, i6mm_chain); 105562587Sitojun } 1056192895Sjamie } 105753541Sshin 105878064Sume /* 1059148385Sume * join interface-local all-nodes address. 1060148385Sume * (ff01::1%ifN, and ff01::%ifN/32) 106178064Sume */ 1062148385Sume mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 1063148385Sume if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) 1064148385Sume != 0) 1065148385Sume goto cleanup; /* XXX: should not fail */ 1066148385Sume /* XXX: again, do we really need the route? */ 1067148385Sume rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL); 1068148385Sume if (rt) { 1069148385Sume if (memcmp(&mltaddr.sin6_addr, 1070148385Sume &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, 1071151465Ssuz MLTMASK_LEN)) { 1072148385Sume RTFREE_LOCKED(rt); 1073148385Sume rt = NULL; 1074148385Sume } 1075148385Sume } 1076148385Sume if (!rt) { 1077148385Sume error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, 1078148385Sume (struct sockaddr *)&ia->ia_addr, 1079186119Sqingli (struct sockaddr *)&mltmask, RTF_UP, 1080148385Sume (struct rtentry **)0); 1081148385Sume if (error) 1082148385Sume goto cleanup; 1083148385Sume } else 1084148385Sume RTFREE_LOCKED(rt); 108581115Sume 1086151539Ssuz imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0); 1087151539Ssuz if (!imm) { 1088151539Ssuz nd6log((LOG_WARNING, "in6_update_ifa: " 1089151539Ssuz "addmulti failed for %s on %s " 1090151539Ssuz "(errno=%d)\n", 1091165118Sbz ip6_sprintf(ip6buf, &mltaddr.sin6_addr), 1092151539Ssuz if_name(ifp), error)); 1093151539Ssuz goto cleanup; 1094151539Ssuz } 1095170202Sjinmei LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); 1096151465Ssuz#undef MLTMASK_LEN 109778064Sume } 109853541Sshin 1099151539Ssuz /* 1100151539Ssuz * Perform DAD, if needed. 1101151539Ssuz * XXX It may be of use, if we can administratively 1102151539Ssuz * disable DAD. 1103151539Ssuz */ 1104194760Srwatson if (in6if_do_dad(ifp) && ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) && 1105151539Ssuz (ia->ia6_flags & IN6_IFF_TENTATIVE)) 1106151539Ssuz { 1107151539Ssuz int mindelay, maxdelay; 1108151539Ssuz 1109151539Ssuz delay = 0; 1110151539Ssuz if ((flags & IN6_IFAUPDATE_DADDELAY)) { 1111151539Ssuz /* 1112151539Ssuz * We need to impose a delay before sending an NS 1113151539Ssuz * for DAD. Check if we also needed a delay for the 1114151539Ssuz * corresponding MLD message. If we did, the delay 1115151539Ssuz * should be larger than the MLD delay (this could be 1116151539Ssuz * relaxed a bit, but this simple logic is at least 1117151539Ssuz * safe). 1118191672Sbms * XXX: Break data hiding guidelines and look at 1119191672Sbms * state for the solicited multicast group. 1120151539Ssuz */ 1121151539Ssuz mindelay = 0; 1122151539Ssuz if (in6m_sol != NULL && 1123191672Sbms in6m_sol->in6m_state == MLD_REPORTING_MEMBER) { 1124151539Ssuz mindelay = in6m_sol->in6m_timer; 1125151539Ssuz } 1126151539Ssuz maxdelay = MAX_RTR_SOLICITATION_DELAY * hz; 1127151539Ssuz if (maxdelay - mindelay == 0) 1128151539Ssuz delay = 0; 1129151539Ssuz else { 1130151539Ssuz delay = 1131151539Ssuz (arc4random() % (maxdelay - mindelay)) + 1132151539Ssuz mindelay; 1133151539Ssuz } 1134151539Ssuz } 1135151539Ssuz nd6_dad_start((struct ifaddr *)ia, delay); 1136151539Ssuz } 1137151539Ssuz 1138194760Srwatson KASSERT(hostIsNew, ("in6_update_ifa: !hostIsNew")); 1139194760Srwatson ifa_free(&ia->ia_ifa); 1140120856Sume return (error); 114178064Sume 114278064Sume unlink: 114378064Sume /* 114478064Sume * XXX: if a change of an existing address failed, keep the entry 114578064Sume * anyway. 114678064Sume */ 1147194760Srwatson if (hostIsNew) { 1148194943Srwatson in6_unlink_ifa(ia, ifp); 1149194760Srwatson ifa_free(&ia->ia_ifa); 1150194760Srwatson } 1151120856Sume return (error); 1152148385Sume 1153148385Sume cleanup: 1154194760Srwatson KASSERT(hostIsNew, ("in6_update_ifa: cleanup: !hostIsNew")); 1155194760Srwatson ifa_free(&ia->ia_ifa); 1156148385Sume in6_purgeaddr(&ia->ia_ifa); 1157148385Sume return error; 115853541Sshin} 115953541Sshin 116062587Sitojunvoid 1161171259Sdelphijin6_purgeaddr(struct ifaddr *ifa) 116262587Sitojun{ 116378064Sume struct ifnet *ifp = ifa->ifa_ifp; 116478064Sume struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; 1165170202Sjinmei struct in6_multi_mship *imm; 1166192282Sqingli struct sockaddr_in6 mltaddr, mltmask; 1167192282Sqingli struct rtentry rt0; 1168192282Sqingli struct sockaddr_dl gateway; 1169192282Sqingli struct sockaddr_in6 mask, addr; 1170192282Sqingli int plen, error; 1171192282Sqingli struct rtentry *rt; 1172192282Sqingli struct ifaddr *ifa0, *nifa; 117362587Sitojun 1174192282Sqingli /* 1175192282Sqingli * find another IPv6 address as the gateway for the 1176192282Sqingli * link-local and node-local all-nodes multicast 1177192282Sqingli * address routes 1178192282Sqingli */ 1179194760Srwatson IF_ADDR_LOCK(ifp); 1180192282Sqingli TAILQ_FOREACH_SAFE(ifa0, &ifp->if_addrhead, ifa_link, nifa) { 1181192282Sqingli if ((ifa0->ifa_addr->sa_family != AF_INET6) || 1182192282Sqingli memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr, 1183192282Sqingli &ia->ia_addr.sin6_addr, 1184192282Sqingli sizeof(struct in6_addr)) == 0) 1185192282Sqingli continue; 1186192282Sqingli else 1187192282Sqingli break; 1188192282Sqingli } 1189194760Srwatson if (ifa0 != NULL) 1190194760Srwatson ifa_ref(ifa0); 1191194760Srwatson IF_ADDR_UNLOCK(ifp); 1192192282Sqingli 1193195914Sqingli /* 1194195914Sqingli * Remove the loopback route to the interface address. 1195195914Sqingli * The check for the current setting of "nd6_useloopback" is not needed. 1196195914Sqingli */ 1197195914Sqingli if (!(ia->ia_ifp->if_flags & IFF_LOOPBACK)) { 1198195643Sqingli struct rt_addrinfo info; 1199195643Sqingli struct sockaddr_dl null_sdl; 1200195643Sqingli 1201195643Sqingli bzero(&null_sdl, sizeof(null_sdl)); 1202195643Sqingli null_sdl.sdl_len = sizeof(null_sdl); 1203195643Sqingli null_sdl.sdl_family = AF_LINK; 1204196864Sqingli null_sdl.sdl_type = ia->ia_ifp->if_type; 1205196864Sqingli null_sdl.sdl_index = ia->ia_ifp->if_index; 1206195643Sqingli bzero(&info, sizeof(info)); 1207195643Sqingli info.rti_flags = ia->ia_flags | RTF_HOST | RTF_STATIC; 1208195643Sqingli info.rti_info[RTAX_DST] = (struct sockaddr *)&ia->ia_addr; 1209195643Sqingli info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl; 1210195643Sqingli error = rtrequest1_fib(RTM_DELETE, &info, NULL, 0); 1211195643Sqingli 1212195643Sqingli if (error != 0) 1213195643Sqingli log(LOG_INFO, "in6_purgeaddr: deletion failed\n"); 1214195643Sqingli } 1215195643Sqingli 121678064Sume /* stop DAD processing */ 121778064Sume nd6_dad_stop(ifa); 121862587Sitojun 1219186119Sqingli IF_AFDATA_LOCK(ifp); 1220186119Sqingli lla_lookup(LLTABLE6(ifp), (LLE_DELETE | LLE_IFADDR), 1221186119Sqingli (struct sockaddr *)&ia->ia_addr); 1222186119Sqingli IF_AFDATA_UNLOCK(ifp); 1223192282Sqingli 122478064Sume /* 1225192282Sqingli * initialize for rtmsg generation 1226192282Sqingli */ 1227192282Sqingli bzero(&gateway, sizeof(gateway)); 1228192282Sqingli gateway.sdl_len = sizeof(gateway); 1229192282Sqingli gateway.sdl_family = AF_LINK; 1230192282Sqingli gateway.sdl_nlen = 0; 1231192282Sqingli gateway.sdl_alen = ifp->if_addrlen; 1232192282Sqingli /* */ 1233192282Sqingli bzero(&rt0, sizeof(rt0)); 1234192282Sqingli rt0.rt_gateway = (struct sockaddr *)&gateway; 1235192282Sqingli memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); 1236192282Sqingli memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); 1237192282Sqingli rt_mask(&rt0) = (struct sockaddr *)&mask; 1238192282Sqingli rt_key(&rt0) = (struct sockaddr *)&addr; 1239192282Sqingli rt0.rt_flags = RTF_HOST | RTF_STATIC; 1240192282Sqingli rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0); 1241192282Sqingli 1242192282Sqingli /* 1243170202Sjinmei * leave from multicast groups we have joined for the interface 1244170202Sjinmei */ 1245170202Sjinmei while ((imm = ia->ia6_memberships.lh_first) != NULL) { 1246170202Sjinmei LIST_REMOVE(imm, i6mm_chain); 1247170202Sjinmei in6_leavegroup(imm); 124862587Sitojun } 124962587Sitojun 1250192282Sqingli /* 1251192282Sqingli * remove the link-local all-nodes address 1252192282Sqingli */ 1253192282Sqingli bzero(&mltmask, sizeof(mltmask)); 1254192282Sqingli mltmask.sin6_len = sizeof(struct sockaddr_in6); 1255192282Sqingli mltmask.sin6_family = AF_INET6; 1256192282Sqingli mltmask.sin6_addr = in6mask32; 1257192282Sqingli 1258192282Sqingli bzero(&mltaddr, sizeof(mltaddr)); 1259192282Sqingli mltaddr.sin6_len = sizeof(struct sockaddr_in6); 1260192282Sqingli mltaddr.sin6_family = AF_INET6; 1261192282Sqingli mltaddr.sin6_addr = in6addr_linklocal_allnodes; 1262192282Sqingli 1263192282Sqingli if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 1264192282Sqingli 0) 1265192282Sqingli goto cleanup; 1266192282Sqingli 1267192282Sqingli rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL); 1268192282Sqingli if (rt != NULL && rt->rt_gateway != NULL && 1269192282Sqingli (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 1270192282Sqingli &ia->ia_addr.sin6_addr, 1271192282Sqingli sizeof(ia->ia_addr.sin6_addr)) == 0)) { 1272192282Sqingli /* 1273192282Sqingli * if no more IPv6 address exists on this interface 1274192282Sqingli * then remove the multicast address route 1275192282Sqingli */ 1276192282Sqingli if (ifa0 == NULL) { 1277192282Sqingli memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr, 1278192282Sqingli sizeof(mltaddr.sin6_addr)); 1279192282Sqingli RTFREE_LOCKED(rt); 1280192282Sqingli error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr, 1281192282Sqingli (struct sockaddr *)&ia->ia_addr, 1282192282Sqingli (struct sockaddr *)&mltmask, RTF_UP, 1283192282Sqingli (struct rtentry **)0); 1284192282Sqingli if (error) 1285192282Sqingli log(LOG_INFO, "in6_purgeaddr: link-local all-nodes" 1286192282Sqingli "multicast address deletion error\n"); 1287192282Sqingli } else { 1288192282Sqingli /* 1289192282Sqingli * replace the gateway of the route 1290192282Sqingli */ 1291192282Sqingli struct sockaddr_in6 sa; 1292192282Sqingli 1293192282Sqingli bzero(&sa, sizeof(sa)); 1294192282Sqingli sa.sin6_len = sizeof(struct sockaddr_in6); 1295192282Sqingli sa.sin6_family = AF_INET6; 1296192282Sqingli memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr, 1297192282Sqingli sizeof(sa.sin6_addr)); 1298192282Sqingli in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL); 1299192282Sqingli memcpy(rt->rt_gateway, &sa, sizeof(sa)); 1300192282Sqingli RTFREE_LOCKED(rt); 1301192282Sqingli } 1302192282Sqingli } else { 1303192282Sqingli if (rt != NULL) 1304192282Sqingli RTFREE_LOCKED(rt); 1305192282Sqingli } 1306192282Sqingli 1307192282Sqingli /* 1308192282Sqingli * remove the node-local all-nodes address 1309192282Sqingli */ 1310192282Sqingli mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 1311192282Sqingli if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 1312192282Sqingli 0) 1313192282Sqingli goto cleanup; 1314192282Sqingli 1315192282Sqingli rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL); 1316192282Sqingli if (rt != NULL && rt->rt_gateway != NULL && 1317192282Sqingli (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 1318192282Sqingli &ia->ia_addr.sin6_addr, 1319192282Sqingli sizeof(ia->ia_addr.sin6_addr)) == 0)) { 1320192282Sqingli /* 1321192282Sqingli * if no more IPv6 address exists on this interface 1322192282Sqingli * then remove the multicast address route 1323192282Sqingli */ 1324192282Sqingli if (ifa0 == NULL) { 1325192282Sqingli memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr, 1326192282Sqingli sizeof(mltaddr.sin6_addr)); 1327192282Sqingli 1328192282Sqingli RTFREE_LOCKED(rt); 1329192282Sqingli error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr, 1330192282Sqingli (struct sockaddr *)&ia->ia_addr, 1331192282Sqingli (struct sockaddr *)&mltmask, RTF_UP, 1332192282Sqingli (struct rtentry **)0); 1333192282Sqingli 1334192282Sqingli if (error) 1335192282Sqingli log(LOG_INFO, "in6_purgeaddr: node-local all-nodes" 1336192282Sqingli "multicast address deletion error\n"); 1337192282Sqingli } else { 1338192282Sqingli /* 1339192282Sqingli * replace the gateway of the route 1340192282Sqingli */ 1341192282Sqingli struct sockaddr_in6 sa; 1342192282Sqingli 1343192282Sqingli bzero(&sa, sizeof(sa)); 1344192282Sqingli sa.sin6_len = sizeof(struct sockaddr_in6); 1345192282Sqingli sa.sin6_family = AF_INET6; 1346192282Sqingli memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr, 1347192282Sqingli sizeof(sa.sin6_addr)); 1348192282Sqingli in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL); 1349192282Sqingli memcpy(rt->rt_gateway, &sa, sizeof(sa)); 1350192282Sqingli RTFREE_LOCKED(rt); 1351192282Sqingli } 1352192282Sqingli } else { 1353192282Sqingli if (rt != NULL) 1354192282Sqingli RTFREE_LOCKED(rt); 1355192282Sqingli } 1356192282Sqingli 1357192282Sqinglicleanup: 1358192282Sqingli 1359192282Sqingli plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ 1360192282Sqingli if ((ia->ia_flags & IFA_ROUTE) && plen == 128) { 1361192282Sqingli int error; 1362192282Sqingli struct sockaddr *dstaddr; 1363192282Sqingli 1364192282Sqingli /* 1365192282Sqingli * use the interface address if configuring an 1366192282Sqingli * interface address with a /128 prefix len 1367192282Sqingli */ 1368192282Sqingli if (ia->ia_dstaddr.sin6_family == AF_INET6) 1369192282Sqingli dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 1370192282Sqingli else 1371192282Sqingli dstaddr = (struct sockaddr *)&ia->ia_addr; 1372192282Sqingli 1373192282Sqingli error = rtrequest(RTM_DELETE, 1374192282Sqingli (struct sockaddr *)dstaddr, 1375192282Sqingli (struct sockaddr *)&ia->ia_addr, 1376192282Sqingli (struct sockaddr *)&ia->ia_prefixmask, 1377192282Sqingli ia->ia_flags | RTF_HOST, NULL); 1378192282Sqingli if (error != 0) 1379192282Sqingli return; 1380192282Sqingli ia->ia_flags &= ~IFA_ROUTE; 1381192282Sqingli } 1382194760Srwatson if (ifa0 != NULL) 1383194760Srwatson ifa_free(ifa0); 1384192282Sqingli 138578064Sume in6_unlink_ifa(ia, ifp); 138678064Sume} 138778064Sume 138878064Sumestatic void 1389171259Sdelphijin6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) 139078064Sume{ 139178064Sume int s = splnet(); 139278064Sume 1393191323Srwatson IF_ADDR_LOCK(ifp); 1394191340Srwatson TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); 1395191323Srwatson IF_ADDR_UNLOCK(ifp); 1396194760Srwatson ifa_free(&ia->ia_ifa); /* if_addrhead */ 139762587Sitojun 1398195102Srwatson /* 1399195102Srwatson * Defer the release of what might be the last reference to the 1400195102Srwatson * in6_ifaddr so that it can't be freed before the remainder of the 1401195102Srwatson * cleanup. 1402195102Srwatson */ 1403194971Srwatson IN6_IFADDR_WLOCK(); 1404194907Srwatson TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link); 1405194971Srwatson IN6_IFADDR_WUNLOCK(); 140662587Sitojun 140762587Sitojun /* 1408151915Ssuz * Release the reference to the base prefix. There should be a 1409151915Ssuz * positive reference. 141062587Sitojun */ 1411194907Srwatson if (ia->ia6_ndpr == NULL) { 1412151915Ssuz nd6log((LOG_NOTICE, 1413151915Ssuz "in6_unlink_ifa: autoconf'ed address " 1414194907Srwatson "%p has no prefix\n", ia)); 1415151915Ssuz } else { 1416194907Srwatson ia->ia6_ndpr->ndpr_refcnt--; 1417194907Srwatson ia->ia6_ndpr = NULL; 1418151915Ssuz } 141962587Sitojun 1420151915Ssuz /* 1421151915Ssuz * Also, if the address being removed is autoconf'ed, call 1422151915Ssuz * pfxlist_onlink_check() since the release might affect the status of 1423171260Sdelphij * other (detached) addresses. 1424151915Ssuz */ 1425194907Srwatson if ((ia->ia6_flags & IN6_IFF_AUTOCONF)) { 142678064Sume pfxlist_onlink_check(); 142762587Sitojun } 1428195102Srwatson ifa_free(&ia->ia_ifa); /* in6_ifaddrhead */ 142978064Sume splx(s); 143062587Sitojun} 143162587Sitojun 143278064Sumevoid 1433171259Sdelphijin6_purgeif(struct ifnet *ifp) 143478064Sume{ 143578064Sume struct ifaddr *ifa, *nifa; 143678064Sume 1437191340Srwatson TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { 143878064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 143978064Sume continue; 144078064Sume in6_purgeaddr(ifa); 144178064Sume } 144278064Sume 144378064Sume in6_ifdetach(ifp); 144478064Sume} 144578064Sume 144653541Sshin/* 144753541Sshin * SIOC[GAD]LIFADDR. 144862744Sgrog * SIOCGLIFADDR: get first address. (?) 144953541Sshin * SIOCGLIFADDR with IFLR_PREFIX: 145053541Sshin * get first address that matches the specified prefix. 145153541Sshin * SIOCALIFADDR: add the specified address. 145253541Sshin * SIOCALIFADDR with IFLR_PREFIX: 145353541Sshin * add the specified prefix, filling hostid part from 145453541Sshin * the first link-local address. prefixlen must be <= 64. 145553541Sshin * SIOCDLIFADDR: delete the specified address. 145653541Sshin * SIOCDLIFADDR with IFLR_PREFIX: 145753541Sshin * delete the first address that matches the specified prefix. 145853541Sshin * return values: 145953541Sshin * EINVAL on invalid parameters 146053541Sshin * EADDRNOTAVAIL on prefix match failed/specified address not found 146153541Sshin * other values may be returned from in6_ioctl() 146253541Sshin * 146353541Sshin * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64. 146453541Sshin * this is to accomodate address naming scheme other than RFC2374, 146553541Sshin * in the future. 146653541Sshin * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374 146753541Sshin * address encoding scheme. (see figure on page 8) 146853541Sshin */ 146953541Sshinstatic int 1470171259Sdelphijin6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data, 1471171259Sdelphij struct ifnet *ifp, struct thread *td) 147253541Sshin{ 147353541Sshin struct if_laddrreq *iflr = (struct if_laddrreq *)data; 147453541Sshin struct ifaddr *ifa; 147562587Sitojun struct sockaddr *sa; 147653541Sshin 147753541Sshin /* sanity checks */ 147853541Sshin if (!data || !ifp) { 147953541Sshin panic("invalid argument to in6_lifaddr_ioctl"); 1480120891Sume /* NOTREACHED */ 148153541Sshin } 148253541Sshin 148353541Sshin switch (cmd) { 148453541Sshin case SIOCGLIFADDR: 148553541Sshin /* address must be specified on GET with IFLR_PREFIX */ 148653541Sshin if ((iflr->flags & IFLR_PREFIX) == 0) 148753541Sshin break; 148895023Ssuz /* FALLTHROUGH */ 148953541Sshin case SIOCALIFADDR: 149053541Sshin case SIOCDLIFADDR: 149153541Sshin /* address must be specified on ADD and DELETE */ 149262587Sitojun sa = (struct sockaddr *)&iflr->addr; 149362587Sitojun if (sa->sa_family != AF_INET6) 149453541Sshin return EINVAL; 149562587Sitojun if (sa->sa_len != sizeof(struct sockaddr_in6)) 149653541Sshin return EINVAL; 149753541Sshin /* XXX need improvement */ 149862587Sitojun sa = (struct sockaddr *)&iflr->dstaddr; 149962587Sitojun if (sa->sa_family && sa->sa_family != AF_INET6) 150053541Sshin return EINVAL; 150162587Sitojun if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6)) 150253541Sshin return EINVAL; 150353541Sshin break; 150495023Ssuz default: /* shouldn't happen */ 150562587Sitojun#if 0 150662587Sitojun panic("invalid cmd to in6_lifaddr_ioctl"); 150795023Ssuz /* NOTREACHED */ 150862587Sitojun#else 150953541Sshin return EOPNOTSUPP; 151062587Sitojun#endif 151153541Sshin } 151253541Sshin if (sizeof(struct in6_addr) * 8 < iflr->prefixlen) 151353541Sshin return EINVAL; 151453541Sshin 151553541Sshin switch (cmd) { 151653541Sshin case SIOCALIFADDR: 151753541Sshin { 151853541Sshin struct in6_aliasreq ifra; 151953541Sshin struct in6_addr *hostid = NULL; 152053541Sshin int prefixlen; 152153541Sshin 1522194760Srwatson ifa = NULL; 152353541Sshin if ((iflr->flags & IFLR_PREFIX) != 0) { 152453541Sshin struct sockaddr_in6 *sin6; 152553541Sshin 152653541Sshin /* 152753541Sshin * hostid is to fill in the hostid part of the 152853541Sshin * address. hostid points to the first link-local 152953541Sshin * address attached to the interface. 153053541Sshin */ 153162587Sitojun ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); 153253541Sshin if (!ifa) 153353541Sshin return EADDRNOTAVAIL; 153453541Sshin hostid = IFA_IN6(ifa); 153553541Sshin 1536171260Sdelphij /* prefixlen must be <= 64. */ 153753541Sshin if (64 < iflr->prefixlen) 153853541Sshin return EINVAL; 153953541Sshin prefixlen = iflr->prefixlen; 154053541Sshin 154153541Sshin /* hostid part must be zero. */ 154253541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 1543126552Sume if (sin6->sin6_addr.s6_addr32[2] != 0 || 1544126552Sume sin6->sin6_addr.s6_addr32[3] != 0) { 154553541Sshin return EINVAL; 154653541Sshin } 154753541Sshin } else 154853541Sshin prefixlen = iflr->prefixlen; 154953541Sshin 155053541Sshin /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 155153541Sshin bzero(&ifra, sizeof(ifra)); 1552120891Sume bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name)); 155353541Sshin 155462587Sitojun bcopy(&iflr->addr, &ifra.ifra_addr, 1555120891Sume ((struct sockaddr *)&iflr->addr)->sa_len); 155653541Sshin if (hostid) { 155753541Sshin /* fill in hostid part */ 155853541Sshin ifra.ifra_addr.sin6_addr.s6_addr32[2] = 1559120891Sume hostid->s6_addr32[2]; 156053541Sshin ifra.ifra_addr.sin6_addr.s6_addr32[3] = 1561120891Sume hostid->s6_addr32[3]; 156253541Sshin } 156353541Sshin 1564120891Sume if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */ 156553541Sshin bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 1566120891Sume ((struct sockaddr *)&iflr->dstaddr)->sa_len); 156753541Sshin if (hostid) { 156853541Sshin ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] = 1569120891Sume hostid->s6_addr32[2]; 157053541Sshin ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = 1571120891Sume hostid->s6_addr32[3]; 157253541Sshin } 157353541Sshin } 1574194760Srwatson if (ifa != NULL) 1575194760Srwatson ifa_free(ifa); 157653541Sshin 157753541Sshin ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 1578121168Sume in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); 157953541Sshin 158053541Sshin ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; 158183366Sjulian return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, td); 158253541Sshin } 158353541Sshin case SIOCGLIFADDR: 158453541Sshin case SIOCDLIFADDR: 158553541Sshin { 158653541Sshin struct in6_ifaddr *ia; 158753541Sshin struct in6_addr mask, candidate, match; 158853541Sshin struct sockaddr_in6 *sin6; 158953541Sshin int cmp; 159053541Sshin 159153541Sshin bzero(&mask, sizeof(mask)); 159253541Sshin if (iflr->flags & IFLR_PREFIX) { 159353541Sshin /* lookup a prefix rather than address. */ 1594121168Sume in6_prefixlen2mask(&mask, iflr->prefixlen); 159553541Sshin 159653541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 159753541Sshin bcopy(&sin6->sin6_addr, &match, sizeof(match)); 159853541Sshin match.s6_addr32[0] &= mask.s6_addr32[0]; 159953541Sshin match.s6_addr32[1] &= mask.s6_addr32[1]; 160053541Sshin match.s6_addr32[2] &= mask.s6_addr32[2]; 160153541Sshin match.s6_addr32[3] &= mask.s6_addr32[3]; 160253541Sshin 160353541Sshin /* if you set extra bits, that's wrong */ 160453541Sshin if (bcmp(&match, &sin6->sin6_addr, sizeof(match))) 160553541Sshin return EINVAL; 160653541Sshin 160753541Sshin cmp = 1; 160853541Sshin } else { 160953541Sshin if (cmd == SIOCGLIFADDR) { 161053541Sshin /* on getting an address, take the 1st match */ 161195023Ssuz cmp = 0; /* XXX */ 161253541Sshin } else { 161353541Sshin /* on deleting an address, do exact match */ 1614121168Sume in6_prefixlen2mask(&mask, 128); 161553541Sshin sin6 = (struct sockaddr_in6 *)&iflr->addr; 161653541Sshin bcopy(&sin6->sin6_addr, &match, sizeof(match)); 161753541Sshin 161853541Sshin cmp = 1; 161953541Sshin } 162053541Sshin } 162153541Sshin 1622191323Srwatson IF_ADDR_LOCK(ifp); 1623191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 162453541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 162553541Sshin continue; 162653541Sshin if (!cmp) 162753541Sshin break; 162878064Sume 162978064Sume /* 163078064Sume * XXX: this is adhoc, but is necessary to allow 163178064Sume * a user to specify fe80::/64 (not /10) for a 163278064Sume * link-local address. 163378064Sume */ 1634148385Sume bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate)); 1635148385Sume in6_clearscope(&candidate); 163653541Sshin candidate.s6_addr32[0] &= mask.s6_addr32[0]; 163753541Sshin candidate.s6_addr32[1] &= mask.s6_addr32[1]; 163853541Sshin candidate.s6_addr32[2] &= mask.s6_addr32[2]; 163953541Sshin candidate.s6_addr32[3] &= mask.s6_addr32[3]; 164053541Sshin if (IN6_ARE_ADDR_EQUAL(&candidate, &match)) 164153541Sshin break; 164253541Sshin } 1643191323Srwatson IF_ADDR_UNLOCK(ifp); 164453541Sshin if (!ifa) 164553541Sshin return EADDRNOTAVAIL; 164653541Sshin ia = ifa2ia6(ifa); 164753541Sshin 164853541Sshin if (cmd == SIOCGLIFADDR) { 1649148385Sume int error; 165078064Sume 165153541Sshin /* fill in the if_laddrreq structure */ 165253541Sshin bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len); 1653148385Sume error = sa6_recoverscope( 1654148385Sume (struct sockaddr_in6 *)&iflr->addr); 1655148385Sume if (error != 0) 1656148385Sume return (error); 1657148385Sume 165853541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 165953541Sshin bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 1660120891Sume ia->ia_dstaddr.sin6_len); 1661148385Sume error = sa6_recoverscope( 1662148385Sume (struct sockaddr_in6 *)&iflr->dstaddr); 1663148385Sume if (error != 0) 1664148385Sume return (error); 166553541Sshin } else 166653541Sshin bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 166753541Sshin 166853541Sshin iflr->prefixlen = 1669120891Sume in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 167053541Sshin 167195023Ssuz iflr->flags = ia->ia6_flags; /* XXX */ 167253541Sshin 167353541Sshin return 0; 167453541Sshin } else { 167553541Sshin struct in6_aliasreq ifra; 167653541Sshin 167753541Sshin /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 167853541Sshin bzero(&ifra, sizeof(ifra)); 167953541Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 1680120891Sume sizeof(ifra.ifra_name)); 168153541Sshin 168253541Sshin bcopy(&ia->ia_addr, &ifra.ifra_addr, 1683120891Sume ia->ia_addr.sin6_len); 168453541Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 168553541Sshin bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 1686120891Sume ia->ia_dstaddr.sin6_len); 168762587Sitojun } else { 168862587Sitojun bzero(&ifra.ifra_dstaddr, 168962587Sitojun sizeof(ifra.ifra_dstaddr)); 169053541Sshin } 169153541Sshin bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr, 1692120891Sume ia->ia_prefixmask.sin6_len); 169353541Sshin 169453541Sshin ifra.ifra_flags = ia->ia6_flags; 169553541Sshin return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, 1696120891Sume ifp, td); 169753541Sshin } 169853541Sshin } 169953541Sshin } 170053541Sshin 170195023Ssuz return EOPNOTSUPP; /* just for safety */ 170253541Sshin} 170353541Sshin 170453541Sshin/* 170553541Sshin * Initialize an interface's intetnet6 address 170653541Sshin * and routing table entry. 170753541Sshin */ 170878064Sumestatic int 1709171259Sdelphijin6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, 1710171259Sdelphij struct sockaddr_in6 *sin6, int newhost) 171153541Sshin{ 171278064Sume int error = 0, plen, ifacount = 0; 171353541Sshin int s = splimp(); 171478064Sume struct ifaddr *ifa; 171553541Sshin 171653541Sshin /* 171753541Sshin * Give the interface a chance to initialize 171853541Sshin * if this is its first address, 171953541Sshin * and to validate the address if necessary. 172053541Sshin */ 1721191323Srwatson IF_ADDR_LOCK(ifp); 1722191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 172378064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 172478064Sume continue; 172578064Sume ifacount++; 172678064Sume } 1727191323Srwatson IF_ADDR_UNLOCK(ifp); 172878064Sume 172978064Sume ia->ia_addr = *sin6; 173078064Sume 1731146883Siedowse if (ifacount <= 1 && ifp->if_ioctl) { 1732146883Siedowse error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); 1733146883Siedowse if (error) { 1734146883Siedowse splx(s); 1735146883Siedowse return (error); 1736146883Siedowse } 173753541Sshin } 173878064Sume splx(s); 173953541Sshin 174078064Sume ia->ia_ifa.ifa_metric = ifp->if_metric; 174153541Sshin 174278064Sume /* we could do in(6)_socktrim here, but just omit it at this moment. */ 174378064Sume 174453541Sshin /* 174578064Sume * Special case: 1746124337Sume * If a new destination address is specified for a point-to-point 174778064Sume * interface, install a route to the destination as an interface 1748186119Sqingli * direct route. 1749124337Sume * XXX: the logic below rejects assigning multiple addresses on a p2p 1750159390Sgnn * interface that share the same destination. 175153541Sshin */ 175278064Sume plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ 1753196152Sqingli if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 && 1754196152Sqingli ia->ia_dstaddr.sin6_family == AF_INET6) { 1755159390Sgnn int rtflags = RTF_UP | RTF_HOST; 1756159390Sgnn 1757178888Sjulian error = rtrequest(RTM_ADD, 1758196152Sqingli (struct sockaddr *)&ia->ia_dstaddr, 1759159390Sgnn (struct sockaddr *)&ia->ia_addr, 1760159390Sgnn (struct sockaddr *)&ia->ia_prefixmask, 1761186708Sqingli ia->ia_flags | rtflags, NULL); 1762159390Sgnn if (error != 0) 1763120856Sume return (error); 176478064Sume ia->ia_flags |= IFA_ROUTE; 176553541Sshin } 176653541Sshin 1767195643Sqingli /* 1768195643Sqingli * add a loopback route to self 1769195643Sqingli */ 1770195914Sqingli if (V_nd6_useloopback && !(ifp->if_flags & IFF_LOOPBACK)) { 1771195643Sqingli struct rt_addrinfo info; 1772195643Sqingli struct rtentry *rt = NULL; 1773195643Sqingli static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 1774195643Sqingli 1775195643Sqingli bzero(&info, sizeof(info)); 1776195643Sqingli info.rti_ifp = V_loif; 1777195643Sqingli info.rti_flags = ia->ia_flags | RTF_HOST | RTF_STATIC; 1778195643Sqingli info.rti_info[RTAX_DST] = (struct sockaddr *)&ia->ia_addr; 1779195643Sqingli info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl; 1780195643Sqingli error = rtrequest1_fib(RTM_ADD, &info, &rt, 0); 1781195643Sqingli 1782195643Sqingli if (error == 0 && rt != NULL) { 1783195643Sqingli RT_LOCK(rt); 1784195643Sqingli ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type = 1785196864Sqingli ifp->if_type; 1786195643Sqingli ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index = 1787196864Sqingli ifp->if_index; 1788195643Sqingli RT_REMREF(rt); 1789195643Sqingli RT_UNLOCK(rt); 1790195643Sqingli } else if (error != 0) 1791195643Sqingli log(LOG_INFO, "in6_ifinit: insertion failed\n"); 1792195643Sqingli } 1793195643Sqingli 179495023Ssuz /* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */ 1795186119Sqingli if (newhost) { 1796186119Sqingli struct llentry *ln; 1797192282Sqingli struct rtentry rt; 1798192282Sqingli struct sockaddr_dl gateway; 1799192282Sqingli struct sockaddr_in6 mask, addr; 180053541Sshin 1801186119Sqingli IF_AFDATA_LOCK(ifp); 1802186119Sqingli ia->ia_ifa.ifa_rtrequest = NULL; 1803186119Sqingli 1804186119Sqingli /* XXX QL 1805186119Sqingli * we need to report rt_newaddrmsg 1806186119Sqingli */ 1807186119Sqingli ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | LLE_EXCLUSIVE), 1808186119Sqingli (struct sockaddr *)&ia->ia_addr); 1809186119Sqingli IF_AFDATA_UNLOCK(ifp); 1810186158Skmacy if (ln != NULL) { 1811186119Sqingli ln->la_expire = 0; /* for IPv6 this means permanent */ 1812186119Sqingli ln->ln_state = ND6_LLINFO_REACHABLE; 1813192282Sqingli /* 1814192282Sqingli * initialize for rtmsg generation 1815192282Sqingli */ 1816192282Sqingli bzero(&gateway, sizeof(gateway)); 1817192282Sqingli gateway.sdl_len = sizeof(gateway); 1818192282Sqingli gateway.sdl_family = AF_LINK; 1819192282Sqingli gateway.sdl_nlen = 0; 1820192282Sqingli gateway.sdl_alen = 6; 1821192282Sqingli memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned, sizeof(ln->ll_addr)); 1822192282Sqingli /* */ 1823186119Sqingli LLE_WUNLOCK(ln); 1824186119Sqingli } 1825192282Sqingli 1826192282Sqingli bzero(&rt, sizeof(rt)); 1827192282Sqingli rt.rt_gateway = (struct sockaddr *)&gateway; 1828192282Sqingli memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); 1829192282Sqingli memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); 1830192282Sqingli rt_mask(&rt) = (struct sockaddr *)&mask; 1831192282Sqingli rt_key(&rt) = (struct sockaddr *)&addr; 1832192282Sqingli rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC; 1833192282Sqingli rt_newaddrmsg(RTM_ADD, &ia->ia_ifa, 0, &rt); 1834186119Sqingli } 1835186119Sqingli 1836120856Sume return (error); 183753541Sshin} 183853541Sshin 183953541Sshin/* 184053541Sshin * Find an IPv6 interface link-local address specific to an interface. 1841194760Srwatson * ifaddr is returned referenced. 184253541Sshin */ 184353541Sshinstruct in6_ifaddr * 1844171259Sdelphijin6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags) 184553541Sshin{ 184678064Sume struct ifaddr *ifa; 184753541Sshin 1848191323Srwatson IF_ADDR_LOCK(ifp); 1849191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 185053541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 185153541Sshin continue; 185262587Sitojun if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { 185362587Sitojun if ((((struct in6_ifaddr *)ifa)->ia6_flags & 185462587Sitojun ignoreflags) != 0) 185562587Sitojun continue; 1856194760Srwatson ifa_ref(ifa); 185753541Sshin break; 185862587Sitojun } 185953541Sshin } 1860191323Srwatson IF_ADDR_UNLOCK(ifp); 186153541Sshin 1862120856Sume return ((struct in6_ifaddr *)ifa); 186353541Sshin} 186453541Sshin 186553541Sshin 186653541Sshin/* 186753541Sshin * find the internet address corresponding to a given interface and address. 1868194760Srwatson * ifaddr is returned referenced. 186953541Sshin */ 187053541Sshinstruct in6_ifaddr * 1871171259Sdelphijin6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr) 187253541Sshin{ 187378064Sume struct ifaddr *ifa; 187453541Sshin 1875191337Srwatson IF_ADDR_LOCK(ifp); 1876191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 187753541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 187853541Sshin continue; 1879194760Srwatson if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) { 1880194760Srwatson ifa_ref(ifa); 188153541Sshin break; 1882194760Srwatson } 188353541Sshin } 1884191337Srwatson IF_ADDR_UNLOCK(ifp); 188553541Sshin 1886120856Sume return ((struct in6_ifaddr *)ifa); 188753541Sshin} 188853541Sshin 188953541Sshin/* 1890165118Sbz * Convert IP6 address to printable (loggable) representation. Caller 1891165118Sbz * has to make sure that ip6buf is at least INET6_ADDRSTRLEN long. 189253541Sshin */ 189353541Sshinstatic char digits[] = "0123456789abcdef"; 189453541Sshinchar * 1895165118Sbzip6_sprintf(char *ip6buf, const struct in6_addr *addr) 189653541Sshin{ 189778064Sume int i; 189878064Sume char *cp; 1899126552Sume const u_int16_t *a = (const u_int16_t *)addr; 1900126552Sume const u_int8_t *d; 1901165287Sbz int dcolon = 0, zero = 0; 190253541Sshin 1903165118Sbz cp = ip6buf; 190453541Sshin 190553541Sshin for (i = 0; i < 8; i++) { 190653541Sshin if (dcolon == 1) { 190753541Sshin if (*a == 0) { 190853541Sshin if (i == 7) 190953541Sshin *cp++ = ':'; 191053541Sshin a++; 191153541Sshin continue; 191253541Sshin } else 191353541Sshin dcolon = 2; 191453541Sshin } 191553541Sshin if (*a == 0) { 191653541Sshin if (dcolon == 0 && *(a + 1) == 0) { 191753541Sshin if (i == 0) 191853541Sshin *cp++ = ':'; 191953541Sshin *cp++ = ':'; 192053541Sshin dcolon = 1; 192153541Sshin } else { 192253541Sshin *cp++ = '0'; 192353541Sshin *cp++ = ':'; 192453541Sshin } 192553541Sshin a++; 192653541Sshin continue; 192753541Sshin } 192891346Salfred d = (const u_char *)a; 1929165287Sbz /* Try to eliminate leading zeros in printout like in :0001. */ 1930165287Sbz zero = 1; 1931165287Sbz *cp = digits[*d >> 4]; 1932165287Sbz if (*cp != '0') { 1933165287Sbz zero = 0; 1934165287Sbz cp++; 1935165287Sbz } 1936165287Sbz *cp = digits[*d++ & 0xf]; 1937165287Sbz if (zero == 0 || (*cp != '0')) { 1938165287Sbz zero = 0; 1939165287Sbz cp++; 1940165287Sbz } 1941165287Sbz *cp = digits[*d >> 4]; 1942165287Sbz if (zero == 0 || (*cp != '0')) { 1943165287Sbz zero = 0; 1944165287Sbz cp++; 1945165287Sbz } 194653541Sshin *cp++ = digits[*d & 0xf]; 194753541Sshin *cp++ = ':'; 194853541Sshin a++; 194953541Sshin } 1950165118Sbz *--cp = '\0'; 1951165118Sbz return (ip6buf); 195253541Sshin} 195353541Sshin 195453541Sshinint 1955171259Sdelphijin6_localaddr(struct in6_addr *in6) 195653541Sshin{ 195753541Sshin struct in6_ifaddr *ia; 195853541Sshin 195953541Sshin if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6)) 196053541Sshin return 1; 196153541Sshin 1962194971Srwatson IN6_IFADDR_RLOCK(); 1963194907Srwatson TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { 196453541Sshin if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr, 1965120891Sume &ia->ia_prefixmask.sin6_addr)) { 1966194971Srwatson IN6_IFADDR_RUNLOCK(); 196753541Sshin return 1; 1968120891Sume } 1969120891Sume } 1970194971Srwatson IN6_IFADDR_RUNLOCK(); 197153541Sshin 197253541Sshin return (0); 197353541Sshin} 197453541Sshin 197578064Sumeint 1976171259Sdelphijin6_is_addr_deprecated(struct sockaddr_in6 *sa6) 197778064Sume{ 197878064Sume struct in6_ifaddr *ia; 197978064Sume 1980194971Srwatson IN6_IFADDR_RLOCK(); 1981194907Srwatson TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { 198278064Sume if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 198378064Sume &sa6->sin6_addr) && 1984194971Srwatson (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) { 1985194971Srwatson IN6_IFADDR_RUNLOCK(); 1986120856Sume return (1); /* true */ 1987194971Srwatson } 198878064Sume 198978064Sume /* XXX: do we still have to go thru the rest of the list? */ 199078064Sume } 1991194971Srwatson IN6_IFADDR_RUNLOCK(); 199278064Sume 1993120856Sume return (0); /* false */ 199478064Sume} 199578064Sume 199653541Sshin/* 199753541Sshin * return length of part which dst and src are equal 199853541Sshin * hard coding... 199953541Sshin */ 200053541Sshinint 2001171259Sdelphijin6_matchlen(struct in6_addr *src, struct in6_addr *dst) 200253541Sshin{ 200353541Sshin int match = 0; 200453541Sshin u_char *s = (u_char *)src, *d = (u_char *)dst; 200553541Sshin u_char *lim = s + 16, r; 200653541Sshin 200753541Sshin while (s < lim) 200853541Sshin if ((r = (*d++ ^ *s++)) != 0) { 200953541Sshin while (r < 128) { 201053541Sshin match++; 201153541Sshin r <<= 1; 201253541Sshin } 201353541Sshin break; 201453541Sshin } else 201553541Sshin match += 8; 201653541Sshin return match; 201753541Sshin} 201853541Sshin 201962587Sitojun/* XXX: to be scope conscious */ 202053541Sshinint 2021171259Sdelphijin6_are_prefix_equal(struct in6_addr *p1, struct in6_addr *p2, int len) 202253541Sshin{ 202353541Sshin int bytelen, bitlen; 202453541Sshin 202553541Sshin /* sanity check */ 202653541Sshin if (0 > len || len > 128) { 202753541Sshin log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n", 202853541Sshin len); 2029120856Sume return (0); 203053541Sshin } 203153541Sshin 203253541Sshin bytelen = len / 8; 203353541Sshin bitlen = len % 8; 203453541Sshin 203553541Sshin if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen)) 2036120856Sume return (0); 2037126184Scperciva if (bitlen != 0 && 2038126184Scperciva p1->s6_addr[bytelen] >> (8 - bitlen) != 203953541Sshin p2->s6_addr[bytelen] >> (8 - bitlen)) 2040120856Sume return (0); 204153541Sshin 2042120856Sume return (1); 204353541Sshin} 204453541Sshin 204553541Sshinvoid 2046171259Sdelphijin6_prefixlen2mask(struct in6_addr *maskp, int len) 204753541Sshin{ 204853541Sshin u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 204953541Sshin int bytelen, bitlen, i; 205053541Sshin 205153541Sshin /* sanity check */ 205253541Sshin if (0 > len || len > 128) { 205353541Sshin log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n", 205453541Sshin len); 205553541Sshin return; 205653541Sshin } 205753541Sshin 205853541Sshin bzero(maskp, sizeof(*maskp)); 205953541Sshin bytelen = len / 8; 206053541Sshin bitlen = len % 8; 206153541Sshin for (i = 0; i < bytelen; i++) 206253541Sshin maskp->s6_addr[i] = 0xff; 206353541Sshin if (bitlen) 206453541Sshin maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 206553541Sshin} 206653541Sshin 206753541Sshin/* 206853541Sshin * return the best address out of the same scope. if no address was 206953541Sshin * found, return the first valid address from designated IF. 207053541Sshin */ 207153541Sshinstruct in6_ifaddr * 2072171259Sdelphijin6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) 207353541Sshin{ 207453541Sshin int dst_scope = in6_addrscope(dst), blen = -1, tlen; 207553541Sshin struct ifaddr *ifa; 207653541Sshin struct in6_ifaddr *besta = 0; 207795023Ssuz struct in6_ifaddr *dep[2]; /* last-resort: deprecated */ 207853541Sshin 207953541Sshin dep[0] = dep[1] = NULL; 208053541Sshin 208153541Sshin /* 208253541Sshin * We first look for addresses in the same scope. 208353541Sshin * If there is one, return it. 208453541Sshin * If two or more, return one which matches the dst longest. 208553541Sshin * If none, return one of global addresses assigned other ifs. 208653541Sshin */ 2087191323Srwatson IF_ADDR_LOCK(ifp); 2088191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 208953541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 209053541Sshin continue; 209153541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 209253541Sshin continue; /* XXX: is there any case to allow anycast? */ 209353541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 209453541Sshin continue; /* don't use this interface */ 209553541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 209653541Sshin continue; 209753541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 2098181803Sbz if (V_ip6_use_deprecated) 209953541Sshin dep[0] = (struct in6_ifaddr *)ifa; 210053541Sshin continue; 210153541Sshin } 210253541Sshin 210353541Sshin if (dst_scope == in6_addrscope(IFA_IN6(ifa))) { 210453541Sshin /* 210553541Sshin * call in6_matchlen() as few as possible 210653541Sshin */ 210753541Sshin if (besta) { 210853541Sshin if (blen == -1) 210953541Sshin blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst); 211053541Sshin tlen = in6_matchlen(IFA_IN6(ifa), dst); 211153541Sshin if (tlen > blen) { 211253541Sshin blen = tlen; 211353541Sshin besta = (struct in6_ifaddr *)ifa; 211453541Sshin } 211553541Sshin } else 211653541Sshin besta = (struct in6_ifaddr *)ifa; 211753541Sshin } 211853541Sshin } 2119191323Srwatson if (besta) { 2120194760Srwatson ifa_ref(&besta->ia_ifa); 2121191323Srwatson IF_ADDR_UNLOCK(ifp); 2122120856Sume return (besta); 2123191323Srwatson } 2124194971Srwatson IF_ADDR_UNLOCK(ifp); 212553541Sshin 2126194971Srwatson IN6_IFADDR_RLOCK(); 2127191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 212853541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 212953541Sshin continue; 213053541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 213153541Sshin continue; /* XXX: is there any case to allow anycast? */ 213253541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 213353541Sshin continue; /* don't use this interface */ 213453541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 213553541Sshin continue; 213653541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 2137181803Sbz if (V_ip6_use_deprecated) 213853541Sshin dep[1] = (struct in6_ifaddr *)ifa; 213953541Sshin continue; 214053541Sshin } 214153541Sshin 2142194760Srwatson if (ifa != NULL) 2143194760Srwatson ifa_ref(ifa); 2144194971Srwatson IN6_IFADDR_RUNLOCK(); 214553541Sshin return (struct in6_ifaddr *)ifa; 214653541Sshin } 2147194971Srwatson IN6_IFADDR_RUNLOCK(); 214853541Sshin 214953541Sshin /* use the last-resort values, that are, deprecated addresses */ 215053541Sshin if (dep[0]) 215153541Sshin return dep[0]; 215253541Sshin if (dep[1]) 215353541Sshin return dep[1]; 215453541Sshin 215553541Sshin return NULL; 215653541Sshin} 215753541Sshin 215853541Sshin/* 215953541Sshin * perform DAD when interface becomes IFF_UP. 216053541Sshin */ 216153541Sshinvoid 2162171259Sdelphijin6_if_up(struct ifnet *ifp) 216353541Sshin{ 216453541Sshin struct ifaddr *ifa; 216553541Sshin struct in6_ifaddr *ia; 216653541Sshin 2167191323Srwatson IF_ADDR_LOCK(ifp); 2168191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 216953541Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 217053541Sshin continue; 217153541Sshin ia = (struct in6_ifaddr *)ifa; 2172151539Ssuz if (ia->ia6_flags & IN6_IFF_TENTATIVE) { 2173151539Ssuz /* 2174151539Ssuz * The TENTATIVE flag was likely set by hand 2175151539Ssuz * beforehand, implicitly indicating the need for DAD. 2176151539Ssuz * We may be able to skip the random delay in this 2177151539Ssuz * case, but we impose delays just in case. 2178151539Ssuz */ 2179151539Ssuz nd6_dad_start(ifa, 2180151539Ssuz arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz)); 2181151539Ssuz } 218253541Sshin } 2183191323Srwatson IF_ADDR_UNLOCK(ifp); 2184151539Ssuz 2185151539Ssuz /* 2186151539Ssuz * special cases, like 6to4, are handled in in6_ifattach 2187151539Ssuz */ 2188151539Ssuz in6_ifattach(ifp, NULL); 218953541Sshin} 219053541Sshin 219178064Sumeint 2192171259Sdelphijin6if_do_dad(struct ifnet *ifp) 219378064Sume{ 219478064Sume if ((ifp->if_flags & IFF_LOOPBACK) != 0) 2195120856Sume return (0); 219678064Sume 219778064Sume switch (ifp->if_type) { 219878064Sume#ifdef IFT_DUMMY 219978064Sume case IFT_DUMMY: 220078064Sume#endif 220178064Sume case IFT_FAITH: 220278064Sume /* 220378064Sume * These interfaces do not have the IFF_LOOPBACK flag, 220478064Sume * but loop packets back. We do not have to do DAD on such 220578064Sume * interfaces. We should even omit it, because loop-backed 220678064Sume * NS would confuse the DAD procedure. 220778064Sume */ 2208120856Sume return (0); 220978064Sume default: 221078064Sume /* 221178064Sume * Our DAD routine requires the interface up and running. 221278064Sume * However, some interfaces can be up before the RUNNING 221378064Sume * status. Additionaly, users may try to assign addresses 221478064Sume * before the interface becomes up (or running). 221578064Sume * We simply skip DAD in such a case as a work around. 221678064Sume * XXX: we should rather mark "tentative" on such addresses, 221778064Sume * and do DAD after the interface becomes ready. 221878064Sume */ 2219148887Srwatson if (!((ifp->if_flags & IFF_UP) && 2220148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 2221120856Sume return (0); 222278064Sume 2223120856Sume return (1); 222478064Sume } 222578064Sume} 222678064Sume 222753541Sshin/* 222853541Sshin * Calculate max IPv6 MTU through all the interfaces and store it 222953541Sshin * to in6_maxmtu. 223053541Sshin */ 223153541Sshinvoid 2232171259Sdelphijin6_setmaxmtu(void) 223353541Sshin{ 223453541Sshin unsigned long maxmtu = 0; 223553541Sshin struct ifnet *ifp; 223653541Sshin 2237196481Srwatson IFNET_RLOCK_NOSLEEP(); 2238181887Sjulian for (ifp = TAILQ_FIRST(&V_ifnet); ifp; 2239181888Sjulian ifp = TAILQ_NEXT(ifp, if_list)) { 2240121283Sume /* this function can be called during ifnet initialization */ 2241121283Sume if (!ifp->if_afdata[AF_INET6]) 2242121283Sume continue; 224353541Sshin if ((ifp->if_flags & IFF_LOOPBACK) == 0 && 2244121283Sume IN6_LINKMTU(ifp) > maxmtu) 2245121283Sume maxmtu = IN6_LINKMTU(ifp); 224653541Sshin } 2247196481Srwatson IFNET_RUNLOCK_NOSLEEP(); 2248120891Sume if (maxmtu) /* update only when maxmtu is positive */ 2249181803Sbz V_in6_maxmtu = maxmtu; 225053541Sshin} 225153541Sshin 2252151539Ssuz/* 2253151539Ssuz * Provide the length of interface identifiers to be used for the link attached 2254151539Ssuz * to the given interface. The length should be defined in "IPv6 over 2255151539Ssuz * xxx-link" document. Note that address architecture might also define 2256151539Ssuz * the length for a particular set of address prefixes, regardless of the 2257151539Ssuz * link type. As clarified in rfc2462bis, those two definitions should be 2258151539Ssuz * consistent, and those really are as of August 2004. 2259151539Ssuz */ 2260151539Ssuzint 2261171259Sdelphijin6_if2idlen(struct ifnet *ifp) 2262151539Ssuz{ 2263151539Ssuz switch (ifp->if_type) { 2264151539Ssuz case IFT_ETHER: /* RFC2464 */ 2265151539Ssuz#ifdef IFT_PROPVIRTUAL 2266151539Ssuz case IFT_PROPVIRTUAL: /* XXX: no RFC. treat it as ether */ 2267151539Ssuz#endif 2268151539Ssuz#ifdef IFT_L2VLAN 2269151539Ssuz case IFT_L2VLAN: /* ditto */ 2270151539Ssuz#endif 2271151539Ssuz#ifdef IFT_IEEE80211 2272151539Ssuz case IFT_IEEE80211: /* ditto */ 2273151539Ssuz#endif 2274151539Ssuz#ifdef IFT_MIP 2275151539Ssuz case IFT_MIP: /* ditto */ 2276151539Ssuz#endif 2277151539Ssuz return (64); 2278151539Ssuz case IFT_FDDI: /* RFC2467 */ 2279151539Ssuz return (64); 2280151539Ssuz case IFT_ISO88025: /* RFC2470 (IPv6 over Token Ring) */ 2281151539Ssuz return (64); 2282151539Ssuz case IFT_PPP: /* RFC2472 */ 2283151539Ssuz return (64); 2284151539Ssuz case IFT_ARCNET: /* RFC2497 */ 2285151539Ssuz return (64); 2286151539Ssuz case IFT_FRELAY: /* RFC2590 */ 2287151539Ssuz return (64); 2288151539Ssuz case IFT_IEEE1394: /* RFC3146 */ 2289151539Ssuz return (64); 2290151539Ssuz case IFT_GIF: 2291151539Ssuz return (64); /* draft-ietf-v6ops-mech-v2-07 */ 2292151539Ssuz case IFT_LOOP: 2293151539Ssuz return (64); /* XXX: is this really correct? */ 2294151539Ssuz default: 2295151539Ssuz /* 2296151539Ssuz * Unknown link type: 2297151539Ssuz * It might be controversial to use the today's common constant 2298151539Ssuz * of 64 for these cases unconditionally. For full compliance, 2299151539Ssuz * we should return an error in this case. On the other hand, 2300151539Ssuz * if we simply miss the standard for the link type or a new 2301151539Ssuz * standard is defined for a new link type, the IFID length 2302151539Ssuz * is very likely to be the common constant. As a compromise, 2303151539Ssuz * we always use the constant, but make an explicit notice 2304151539Ssuz * indicating the "unknown" case. 2305151539Ssuz */ 2306151539Ssuz printf("in6_if2idlen: unknown link type (%d)\n", ifp->if_type); 2307151539Ssuz return (64); 2308151539Ssuz } 2309151539Ssuz} 2310151539Ssuz 2311186119Sqingli#include <sys/sysctl.h> 2312186119Sqingli 2313186119Sqinglistruct in6_llentry { 2314186119Sqingli struct llentry base; 2315186119Sqingli struct sockaddr_in6 l3_addr6; 2316186119Sqingli}; 2317186119Sqingli 2318186119Sqinglistatic struct llentry * 2319186119Sqingliin6_lltable_new(const struct sockaddr *l3addr, u_int flags) 2320186119Sqingli{ 2321186119Sqingli struct in6_llentry *lle; 2322186119Sqingli 2323186119Sqingli lle = malloc(sizeof(struct in6_llentry), M_LLTABLE, 2324186119Sqingli M_DONTWAIT | M_ZERO); 2325186119Sqingli if (lle == NULL) /* NB: caller generates msg */ 2326186119Sqingli return NULL; 2327186119Sqingli 2328186119Sqingli callout_init(&lle->base.ln_timer_ch, CALLOUT_MPSAFE); 2329186119Sqingli lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr; 2330186119Sqingli lle->base.lle_refcnt = 1; 2331186119Sqingli LLE_LOCK_INIT(&lle->base); 2332186119Sqingli return &lle->base; 2333186119Sqingli} 2334186119Sqingli 2335186119Sqingli/* 2336186119Sqingli * Deletes an address from the address table. 2337186119Sqingli * This function is called by the timer functions 2338186119Sqingli * such as arptimer() and nd6_llinfo_timer(), and 2339186119Sqingli * the caller does the locking. 2340186119Sqingli */ 2341186119Sqinglistatic void 2342186119Sqingliin6_lltable_free(struct lltable *llt, struct llentry *lle) 2343186119Sqingli{ 2344186150Skmacy LLE_WUNLOCK(lle); 2345186150Skmacy LLE_LOCK_DESTROY(lle); 2346186119Sqingli free(lle, M_LLTABLE); 2347186119Sqingli} 2348186119Sqingli 2349192476Sqinglistatic void 2350192476Sqingliin6_lltable_prefix_free(struct lltable *llt, 2351192476Sqingli const struct sockaddr *prefix, 2352192476Sqingli const struct sockaddr *mask) 2353192476Sqingli{ 2354192476Sqingli const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix; 2355192476Sqingli const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask; 2356192476Sqingli struct llentry *lle, *next; 2357192476Sqingli register int i; 2358192476Sqingli 2359192476Sqingli for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { 2360192476Sqingli LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 2361192476Sqingli if (IN6_ARE_MASKED_ADDR_EQUAL( 2362192476Sqingli &((struct sockaddr_in6 *)L3_ADDR(lle))->sin6_addr, 2363192476Sqingli &pfx->sin6_addr, 2364192476Sqingli &msk->sin6_addr)) { 2365192476Sqingli callout_drain(&lle->la_timer); 2366192476Sqingli LLE_WLOCK(lle); 2367192476Sqingli llentry_free(lle); 2368192476Sqingli } 2369192476Sqingli } 2370192476Sqingli } 2371192476Sqingli} 2372192476Sqingli 2373186119Sqinglistatic int 2374186119Sqingliin6_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr) 2375186119Sqingli{ 2376186119Sqingli struct rtentry *rt; 2377186119Sqingli char ip6buf[INET6_ADDRSTRLEN]; 2378186119Sqingli 2379186119Sqingli KASSERT(l3addr->sa_family == AF_INET6, 2380186119Sqingli ("sin_family %d", l3addr->sa_family)); 2381186119Sqingli 2382186119Sqingli /* XXX rtalloc1 should take a const param */ 2383186119Sqingli rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0); 2384186119Sqingli if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) { 2385186119Sqingli struct ifaddr *ifa; 2386186119Sqingli /* 2387186119Sqingli * Create an ND6 cache for an IPv6 neighbor 2388186119Sqingli * that is not covered by our own prefix. 2389186119Sqingli */ 2390186119Sqingli /* XXX ifaof_ifpforaddr should take a const param */ 2391186119Sqingli ifa = ifaof_ifpforaddr(__DECONST(struct sockaddr *, l3addr), ifp); 2392186119Sqingli if (ifa != NULL) { 2393194760Srwatson ifa_free(ifa); 2394186119Sqingli if (rt != NULL) 2395187946Sbz RTFREE_LOCKED(rt); 2396186119Sqingli return 0; 2397186119Sqingli } 2398186119Sqingli log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", 2399186119Sqingli ip6_sprintf(ip6buf, &((const struct sockaddr_in6 *)l3addr)->sin6_addr)); 2400186119Sqingli if (rt != NULL) 2401187946Sbz RTFREE_LOCKED(rt); 2402186119Sqingli return EINVAL; 2403186119Sqingli } 2404187946Sbz RTFREE_LOCKED(rt); 2405186119Sqingli return 0; 2406186119Sqingli} 2407186119Sqingli 2408186119Sqinglistatic struct llentry * 2409186119Sqingliin6_lltable_lookup(struct lltable *llt, u_int flags, 2410186119Sqingli const struct sockaddr *l3addr) 2411186119Sqingli{ 2412186119Sqingli const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; 2413186119Sqingli struct ifnet *ifp = llt->llt_ifp; 2414186119Sqingli struct llentry *lle; 2415186119Sqingli struct llentries *lleh; 2416186119Sqingli u_int hashkey; 2417186119Sqingli 2418186119Sqingli IF_AFDATA_LOCK_ASSERT(ifp); 2419186119Sqingli KASSERT(l3addr->sa_family == AF_INET6, 2420186119Sqingli ("sin_family %d", l3addr->sa_family)); 2421186119Sqingli 2422186119Sqingli hashkey = sin6->sin6_addr.s6_addr32[3]; 2423186119Sqingli lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; 2424186119Sqingli LIST_FOREACH(lle, lleh, lle_next) { 2425186708Sqingli struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)L3_ADDR(lle); 2426186119Sqingli if (lle->la_flags & LLE_DELETED) 2427186119Sqingli continue; 2428186708Sqingli if (bcmp(&sa6->sin6_addr, &sin6->sin6_addr, 2429186708Sqingli sizeof(struct in6_addr)) == 0) 2430186119Sqingli break; 2431186119Sqingli } 2432186119Sqingli 2433186119Sqingli if (lle == NULL) { 2434186119Sqingli if (!(flags & LLE_CREATE)) 2435186119Sqingli return (NULL); 2436186119Sqingli /* 2437186119Sqingli * A route that covers the given address must have 2438186119Sqingli * been installed 1st because we are doing a resolution, 2439186119Sqingli * verify this. 2440186119Sqingli */ 2441186119Sqingli if (!(flags & LLE_IFADDR) && 2442186119Sqingli in6_lltable_rtcheck(ifp, l3addr) != 0) 2443186119Sqingli return NULL; 2444186119Sqingli 2445186119Sqingli lle = in6_lltable_new(l3addr, flags); 2446186119Sqingli if (lle == NULL) { 2447186119Sqingli log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); 2448186119Sqingli return NULL; 2449186119Sqingli } 2450186119Sqingli lle->la_flags = flags & ~LLE_CREATE; 2451186119Sqingli if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { 2452186119Sqingli bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); 2453186119Sqingli lle->la_flags |= (LLE_VALID | LLE_STATIC); 2454186119Sqingli } 2455186119Sqingli 2456186119Sqingli lle->lle_tbl = llt; 2457186119Sqingli lle->lle_head = lleh; 2458186119Sqingli LIST_INSERT_HEAD(lleh, lle, lle_next); 2459186119Sqingli } else if (flags & LLE_DELETE) { 2460186392Sqingli if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) { 2461186392Sqingli LLE_WLOCK(lle); 2462186392Sqingli lle->la_flags = LLE_DELETED; 2463186392Sqingli LLE_WUNLOCK(lle); 2464186119Sqingli#ifdef DIAGNOSTICS 2465186392Sqingli log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); 2466186119Sqingli#endif 2467186392Sqingli } 2468186119Sqingli lle = (void *)-1; 2469186119Sqingli } 2470186119Sqingli if (LLE_IS_VALID(lle)) { 2471186119Sqingli if (flags & LLE_EXCLUSIVE) 2472186119Sqingli LLE_WLOCK(lle); 2473186119Sqingli else 2474186119Sqingli LLE_RLOCK(lle); 2475186119Sqingli } 2476186119Sqingli return (lle); 2477186119Sqingli} 2478186119Sqingli 2479186119Sqinglistatic int 2480186119Sqingliin6_lltable_dump(struct lltable *llt, struct sysctl_req *wr) 2481186119Sqingli{ 2482186119Sqingli struct ifnet *ifp = llt->llt_ifp; 2483186119Sqingli struct llentry *lle; 2484186119Sqingli /* XXX stack use */ 2485186119Sqingli struct { 2486186119Sqingli struct rt_msghdr rtm; 2487186119Sqingli struct sockaddr_in6 sin6; 2488186119Sqingli /* 2489186119Sqingli * ndp.c assumes that sdl is word aligned 2490186119Sqingli */ 2491186119Sqingli#ifdef __LP64__ 2492186119Sqingli uint32_t pad; 2493186119Sqingli#endif 2494186119Sqingli struct sockaddr_dl sdl; 2495186119Sqingli } ndpc; 2496186119Sqingli int i, error; 2497186119Sqingli 2498196864Sqingli if (ifp->if_flags & IFF_LOOPBACK) 2499196864Sqingli return 0; 2500196864Sqingli 2501196535Srwatson LLTABLE_LOCK_ASSERT(); 2502186119Sqingli 2503186119Sqingli error = 0; 2504186119Sqingli for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { 2505186119Sqingli LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 2506186119Sqingli struct sockaddr_dl *sdl; 2507186119Sqingli 2508186119Sqingli /* skip deleted or invalid entries */ 2509186119Sqingli if ((lle->la_flags & (LLE_DELETED|LLE_VALID)) != LLE_VALID) 2510186119Sqingli continue; 2511186980Sbz /* Skip if jailed and not a valid IP of the prison. */ 2512188144Sjamie if (prison_if(wr->td->td_ucred, L3_ADDR(lle)) != 0) 2513186980Sbz continue; 2514186119Sqingli /* 2515186119Sqingli * produce a msg made of: 2516186119Sqingli * struct rt_msghdr; 2517186119Sqingli * struct sockaddr_in6 (IPv6) 2518186119Sqingli * struct sockaddr_dl; 2519186119Sqingli */ 2520186119Sqingli bzero(&ndpc, sizeof(ndpc)); 2521186119Sqingli ndpc.rtm.rtm_msglen = sizeof(ndpc); 2522187094Sqingli ndpc.rtm.rtm_version = RTM_VERSION; 2523187094Sqingli ndpc.rtm.rtm_type = RTM_GET; 2524187094Sqingli ndpc.rtm.rtm_flags = RTF_UP; 2525187094Sqingli ndpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; 2526186119Sqingli ndpc.sin6.sin6_family = AF_INET6; 2527186119Sqingli ndpc.sin6.sin6_len = sizeof(ndpc.sin6); 2528186119Sqingli bcopy(L3_ADDR(lle), &ndpc.sin6, L3_ADDR_LEN(lle)); 2529186119Sqingli 2530186119Sqingli /* publish */ 2531186119Sqingli if (lle->la_flags & LLE_PUB) 2532186119Sqingli ndpc.rtm.rtm_flags |= RTF_ANNOUNCE; 2533186119Sqingli 2534186119Sqingli sdl = &ndpc.sdl; 2535186119Sqingli sdl->sdl_family = AF_LINK; 2536186119Sqingli sdl->sdl_len = sizeof(*sdl); 2537186119Sqingli sdl->sdl_alen = ifp->if_addrlen; 2538186119Sqingli sdl->sdl_index = ifp->if_index; 2539186119Sqingli sdl->sdl_type = ifp->if_type; 2540186119Sqingli bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); 2541186119Sqingli ndpc.rtm.rtm_rmx.rmx_expire = 2542186119Sqingli lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; 2543186500Sqingli ndpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); 2544186119Sqingli if (lle->la_flags & LLE_STATIC) 2545186119Sqingli ndpc.rtm.rtm_flags |= RTF_STATIC; 2546186119Sqingli ndpc.rtm.rtm_index = ifp->if_index; 2547186119Sqingli error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc)); 2548186119Sqingli if (error) 2549186119Sqingli break; 2550186119Sqingli } 2551186119Sqingli } 2552186119Sqingli return error; 2553186119Sqingli} 2554186119Sqingli 2555121161Sumevoid * 2556171259Sdelphijin6_domifattach(struct ifnet *ifp) 2557121161Sume{ 2558121161Sume struct in6_ifextra *ext; 2559121161Sume 2560121161Sume ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK); 2561121161Sume bzero(ext, sizeof(*ext)); 2562121161Sume 2563121161Sume ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat), 2564121161Sume M_IFADDR, M_WAITOK); 2565121161Sume bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat)); 2566121161Sume 2567121161Sume ext->icmp6_ifstat = 2568121161Sume (struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat), 2569121161Sume M_IFADDR, M_WAITOK); 2570121161Sume bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat)); 2571121161Sume 2572121161Sume ext->nd_ifinfo = nd6_ifattach(ifp); 2573121161Sume ext->scope6_id = scope6_ifattach(ifp); 2574186119Sqingli ext->lltable = lltable_init(ifp, AF_INET6); 2575186119Sqingli if (ext->lltable != NULL) { 2576186119Sqingli ext->lltable->llt_new = in6_lltable_new; 2577186119Sqingli ext->lltable->llt_free = in6_lltable_free; 2578192476Sqingli ext->lltable->llt_prefix_free = in6_lltable_prefix_free; 2579186119Sqingli ext->lltable->llt_rtcheck = in6_lltable_rtcheck; 2580186119Sqingli ext->lltable->llt_lookup = in6_lltable_lookup; 2581186119Sqingli ext->lltable->llt_dump = in6_lltable_dump; 2582186119Sqingli } 2583191672Sbms 2584191672Sbms ext->mld_ifinfo = mld_domifattach(ifp); 2585191672Sbms 2586121161Sume return ext; 2587121161Sume} 2588121161Sume 2589121161Sumevoid 2590171259Sdelphijin6_domifdetach(struct ifnet *ifp, void *aux) 2591121161Sume{ 2592121161Sume struct in6_ifextra *ext = (struct in6_ifextra *)aux; 2593121161Sume 2594191672Sbms mld_domifdetach(ifp); 2595121161Sume scope6_ifdetach(ext->scope6_id); 2596121161Sume nd6_ifdetach(ext->nd_ifinfo); 2597186119Sqingli lltable_free(ext->lltable); 2598121161Sume free(ext->in6_ifstat, M_IFADDR); 2599121161Sume free(ext->icmp6_ifstat, M_IFADDR); 2600121161Sume free(ext, M_IFADDR); 2601121161Sume} 2602121161Sume 260353541Sshin/* 260495023Ssuz * Convert sockaddr_in6 to sockaddr_in. Original sockaddr_in6 must be 260553541Sshin * v4 mapped addr or v4 compat addr 260653541Sshin */ 260753541Sshinvoid 260853541Sshinin6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 260953541Sshin{ 2610171259Sdelphij 261153541Sshin bzero(sin, sizeof(*sin)); 261253541Sshin sin->sin_len = sizeof(struct sockaddr_in); 261353541Sshin sin->sin_family = AF_INET; 261453541Sshin sin->sin_port = sin6->sin6_port; 2615120891Sume sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3]; 261653541Sshin} 261753541Sshin 261853541Sshin/* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */ 261953541Sshinvoid 262053541Sshinin6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 262153541Sshin{ 262253541Sshin bzero(sin6, sizeof(*sin6)); 262353541Sshin sin6->sin6_len = sizeof(struct sockaddr_in6); 262453541Sshin sin6->sin6_family = AF_INET6; 262553541Sshin sin6->sin6_port = sin->sin_port; 262653541Sshin sin6->sin6_addr.s6_addr32[0] = 0; 262753541Sshin sin6->sin6_addr.s6_addr32[1] = 0; 262853541Sshin sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP; 262953541Sshin sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; 263053541Sshin} 263153541Sshin 263253541Sshin/* Convert sockaddr_in6 into sockaddr_in. */ 263353541Sshinvoid 263453541Sshinin6_sin6_2_sin_in_sock(struct sockaddr *nam) 263553541Sshin{ 263653541Sshin struct sockaddr_in *sin_p; 263753541Sshin struct sockaddr_in6 sin6; 263853541Sshin 263953541Sshin /* 264053541Sshin * Save original sockaddr_in6 addr and convert it 264153541Sshin * to sockaddr_in. 264253541Sshin */ 264353541Sshin sin6 = *(struct sockaddr_in6 *)nam; 264453541Sshin sin_p = (struct sockaddr_in *)nam; 264553541Sshin in6_sin6_2_sin(sin_p, &sin6); 264653541Sshin} 264753541Sshin 264853541Sshin/* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */ 264953541Sshinvoid 265053541Sshinin6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam) 265153541Sshin{ 265253541Sshin struct sockaddr_in *sin_p; 265353541Sshin struct sockaddr_in6 *sin6_p; 265453541Sshin 2655184205Sdes sin6_p = malloc(sizeof *sin6_p, M_SONAME, 2656111119Simp M_WAITOK); 265753541Sshin sin_p = (struct sockaddr_in *)*nam; 265853541Sshin in6_sin_2_v4mapsin6(sin_p, sin6_p); 2659184205Sdes free(*nam, M_SONAME); 266053541Sshin *nam = (struct sockaddr *)sin6_p; 266153541Sshin} 2662