in6.c revision 121742
1238106Sdes/* $FreeBSD: head/sys/netinet6/in6.c 121742 2003-10-30 15:29:17Z ume $ */ 2238106Sdes/* $KAME: in6.c,v 1.259 2002/01/21 11:37:50 keiichi Exp $ */ 3238106Sdes 4238106Sdes/* 5238106Sdes * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6238106Sdes * All rights reserved. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 1. Redistributions of source code must retain the above copyright 12238106Sdes * notice, this list of conditions and the following disclaimer. 13238106Sdes * 2. Redistributions in binary form must reproduce the above copyright 14238106Sdes * notice, this list of conditions and the following disclaimer in the 15238106Sdes * documentation and/or other materials provided with the distribution. 16238106Sdes * 3. Neither the name of the project nor the names of its contributors 17238106Sdes * may be used to endorse or promote products derived from this software 18238106Sdes * without specific prior written permission. 19238106Sdes * 20238106Sdes * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21238106Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22238106Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23238106Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24269257Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25269257Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26269257Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27269257Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28269257Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29269257Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30269257Sdes * SUCH DAMAGE. 31269257Sdes */ 32269257Sdes 33269257Sdes/* 34238106Sdes * Copyright (c) 1982, 1986, 1991, 1993 35238106Sdes * The Regents of the University of California. All rights reserved. 36238106Sdes * 37238106Sdes * Redistribution and use in source and binary forms, with or without 38238106Sdes * modification, are permitted provided that the following conditions 39238106Sdes * are met: 40238106Sdes * 1. Redistributions of source code must retain the above copyright 41285206Sdes * notice, this list of conditions and the following disclaimer. 42285206Sdes * 2. Redistributions in binary form must reproduce the above copyright 43238106Sdes * notice, this list of conditions and the following disclaimer in the 44238106Sdes * documentation and/or other materials provided with the distribution. 45238106Sdes * 3. All advertising materials mentioning features or use of this software 46238106Sdes * must display the following acknowledgement: 47238106Sdes * This product includes software developed by the University of 48238106Sdes * California, Berkeley and its contributors. 49285206Sdes * 4. Neither the name of the University nor the names of its contributors 50285206Sdes * may be used to endorse or promote products derived from this software 51285206Sdes * without specific prior written permission. 52285206Sdes * 53238106Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54238106Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55238106Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56238106Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57238106Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58238106Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59238106Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60238106Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61238106Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62238106Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63238106Sdes * SUCH DAMAGE. 64238106Sdes * 65238106Sdes * @(#)in.c 8.2 (Berkeley) 11/15/93 66238106Sdes */ 67238106Sdes 68238106Sdes#include "opt_inet.h" 69238106Sdes#include "opt_inet6.h" 70238106Sdes 71238106Sdes#include <sys/param.h> 72238106Sdes#include <sys/errno.h> 73238106Sdes#include <sys/malloc.h> 74238106Sdes#include <sys/socket.h> 75238106Sdes#include <sys/socketvar.h> 76238106Sdes#include <sys/sockio.h> 77238106Sdes#include <sys/systm.h> 78238106Sdes#include <sys/proc.h> 79238106Sdes#include <sys/time.h> 80238106Sdes#include <sys/kernel.h> 81269257Sdes#include <sys/syslog.h> 82269257Sdes 83269257Sdes#include <net/if.h> 84269257Sdes#include <net/if_types.h> 85238106Sdes#include <net/route.h> 86238106Sdes#include <net/if_dl.h> 87238106Sdes 88238106Sdes#include <netinet/in.h> 89285206Sdes#include <netinet/in_var.h> 90285206Sdes#include <netinet/if_ether.h> 91285206Sdes#include <netinet/in_systm.h> 92238106Sdes#include <netinet/ip.h> 93238106Sdes#include <netinet/in_pcb.h> 94238106Sdes 95238106Sdes#include <netinet/ip6.h> 96238106Sdes#include <netinet6/ip6_var.h> 97238106Sdes#include <netinet6/nd6.h> 98238106Sdes#include <netinet6/mld6_var.h> 99238106Sdes#include <netinet6/ip6_mroute.h> 100238106Sdes#include <netinet6/in6_ifattach.h> 101238106Sdes#include <netinet6/scope6_var.h> 102238106Sdes#include <netinet6/in6_pcb.h> 103238106Sdes 104238106Sdes#include <net/net_osdep.h> 105238106Sdes 106238106SdesMALLOC_DEFINE(M_IPMADDR, "in6_multi", "internet multicast address"); 107238106Sdes 108238106Sdes/* 109238106Sdes * Definitions of some costant IP6 addresses. 110238106Sdes */ 111238106Sdesconst struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 112238106Sdesconst struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 113238106Sdesconst struct in6_addr in6addr_nodelocal_allnodes = 114238106Sdes IN6ADDR_NODELOCAL_ALLNODES_INIT; 115238106Sdesconst struct in6_addr in6addr_linklocal_allnodes = 116238106Sdes IN6ADDR_LINKLOCAL_ALLNODES_INIT; 117238106Sdesconst struct in6_addr in6addr_linklocal_allrouters = 118238106Sdes IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; 119238106Sdes 120238106Sdesconst struct in6_addr in6mask0 = IN6MASK0; 121238106Sdesconst struct in6_addr in6mask32 = IN6MASK32; 122238106Sdesconst struct in6_addr in6mask64 = IN6MASK64; 123238106Sdesconst struct in6_addr in6mask96 = IN6MASK96; 124238106Sdesconst struct in6_addr in6mask128 = IN6MASK128; 125238106Sdes 126238106Sdesconst struct sockaddr_in6 sa6_any = {sizeof(sa6_any), AF_INET6, 127238106Sdes 0, 0, IN6ADDR_ANY_INIT, 0}; 128238106Sdes 129238106Sdesstatic int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, 130238106Sdes struct ifnet *, struct thread *)); 131238106Sdesstatic int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *, 132238106Sdes struct sockaddr_in6 *, int)); 133238106Sdesstatic void in6_unlink_ifa __P((struct in6_ifaddr *, struct ifnet *)); 134238106Sdes 135238106Sdesstruct in6_multihead in6_multihead; /* XXX BSS initialization */ 136238106Sdesint (*faithprefix_p)(struct in6_addr *); 137238106Sdes 138238106Sdes/* 139238106Sdes * Subroutine for in6_ifaddloop() and in6_ifremloop(). 140238106Sdes * This routine does actual work. 141285206Sdes */ 142285206Sdesstatic void 143285206Sdesin6_ifloop_request(int cmd, struct ifaddr *ifa) 144285206Sdes{ 145285206Sdes struct sockaddr_in6 all1_sa; 146285206Sdes struct rtentry *nrt = NULL; 147285206Sdes int e; 148285206Sdes 149285206Sdes bzero(&all1_sa, sizeof(all1_sa)); 150285206Sdes all1_sa.sin6_family = AF_INET6; 151285206Sdes all1_sa.sin6_len = sizeof(struct sockaddr_in6); 152285206Sdes all1_sa.sin6_addr = in6mask128; 153285206Sdes 154285206Sdes /* 155285206Sdes * We specify the address itself as the gateway, and set the 156285206Sdes * RTF_LLINFO flag, so that the corresponding host route would have 157285206Sdes * the flag, and thus applications that assume traditional behavior 158285206Sdes * would be happy. Note that we assume the caller of the function 159285206Sdes * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest, 160285206Sdes * which changes the outgoing interface to the loopback interface. 161285206Sdes */ 162285206Sdes e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr, 163285206Sdes (struct sockaddr *)&all1_sa, RTF_UP|RTF_HOST|RTF_LLINFO, &nrt); 164285206Sdes if (e != 0) { 165285206Sdes /* XXX need more descriptive message */ 166285206Sdes log(LOG_ERR, "in6_ifloop_request: " 167285206Sdes "%s operation failed for %s (errno=%d)\n", 168285206Sdes cmd == RTM_ADD ? "ADD" : "DELETE", 169285206Sdes ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr), 170285206Sdes e); 171285206Sdes } 172285206Sdes 173285206Sdes if (nrt) { 174285206Sdes RT_LOCK(nrt); 175285206Sdes /* 176238106Sdes * Make sure rt_ifa be equal to IFA, the second argument of 177238106Sdes * the function. We need this because when we refer to 178238106Sdes * rt_ifa->ia6_flags in ip6_input, we assume that the rt_ifa 179238106Sdes * points to the address instead of the loopback address. 180238106Sdes */ 181238106Sdes if (cmd == RTM_ADD && ifa != nrt->rt_ifa) { 182238106Sdes IFAFREE(nrt->rt_ifa); 183238106Sdes IFAREF(ifa); 184238106Sdes nrt->rt_ifa = ifa; 185238106Sdes } 186238106Sdes 187238106Sdes /* 188238106Sdes * Report the addition/removal of the address to the routing 189238106Sdes * socket. 190238106Sdes * 191238106Sdes * XXX: since we called rtinit for a p2p interface with a 192238106Sdes * destination, we end up reporting twice in such a case. 193238106Sdes * Should we rather omit the second report? 194238106Sdes */ 195238106Sdes rt_newaddrmsg(cmd, ifa, e, nrt); 196238106Sdes if (cmd == RTM_DELETE) { 197238106Sdes rtfree(nrt); 198238106Sdes } else { 199285206Sdes /* the cmd must be RTM_ADD here */ 200238106Sdes nrt->rt_refcnt--; 201238106Sdes RT_UNLOCK(nrt); 202238106Sdes } 203238106Sdes } 204238106Sdes} 205285206Sdes 206285206Sdes/* 207285206Sdes * Add ownaddr as loopback rtentry. We previously add the route only if 208285206Sdes * necessary (ex. on a p2p link). However, since we now manage addresses 209285206Sdes * separately from prefixes, we should always add the route. We can't 210285206Sdes * rely on the cloning mechanism from the corresponding interface route 211285206Sdes * any more. 212285206Sdes */ 213285206Sdesstatic void 214285206Sdesin6_ifaddloop(struct ifaddr *ifa) 215285206Sdes{ 216285206Sdes struct rtentry *rt; 217285206Sdes int need_loop; 218285206Sdes 219285206Sdes /* If there is no loopback entry, allocate one. */ 220285206Sdes rt = rtalloc1(ifa->ifa_addr, 0, 0); 221285206Sdes need_loop = (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 || 222285206Sdes (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0); 223285206Sdes if (rt) 224285206Sdes rtfree(rt); 225285206Sdes if (need_loop) 226285206Sdes in6_ifloop_request(RTM_ADD, ifa); 227285206Sdes} 228238106Sdes 229238106Sdes/* 230238106Sdes * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(), 231238106Sdes * if it exists. 232238106Sdes */ 233238106Sdesstatic void 234238106Sdesin6_ifremloop(struct ifaddr *ifa) 235238106Sdes{ 236238106Sdes struct in6_ifaddr *ia; 237238106Sdes struct rtentry *rt; 238238106Sdes int ia_count = 0; 239238106Sdes 240238106Sdes /* 241238106Sdes * Some of BSD variants do not remove cloned routes 242238106Sdes * from an interface direct route, when removing the direct route 243238106Sdes * (see comments in net/net_osdep.h). Even for variants that do remove 244238106Sdes * cloned routes, they could fail to remove the cloned routes when 245238106Sdes * we handle multple addresses that share a common prefix. 246238106Sdes * So, we should remove the route corresponding to the deleted address 247238106Sdes * regardless of the result of in6_is_ifloop_auto(). 248238106Sdes */ 249238106Sdes 250238106Sdes /* 251238106Sdes * Delete the entry only if exact one ifa exists. More than one ifa 252238106Sdes * can exist if we assign a same single address to multiple 253238106Sdes * (probably p2p) interfaces. 254238106Sdes * XXX: we should avoid such a configuration in IPv6... 255238106Sdes */ 256238106Sdes for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 257238106Sdes if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) { 258238106Sdes ia_count++; 259238106Sdes if (ia_count > 1) 260238106Sdes break; 261238106Sdes } 262238106Sdes } 263238106Sdes 264238106Sdes if (ia_count == 1) { 265238106Sdes /* 266238106Sdes * Before deleting, check if a corresponding loopbacked host 267238106Sdes * route surely exists. With this check, we can avoid to 268238106Sdes * delete an interface direct route whose destination is same 269238106Sdes * as the address being removed. This can happen when removing 270238106Sdes * a subnet-router anycast address on an interface attahced 271238106Sdes * to a shared medium. 272238106Sdes */ 273238106Sdes rt = rtalloc1(ifa->ifa_addr, 0, 0); 274238106Sdes if (rt != NULL) { 275238106Sdes if ((rt->rt_flags & RTF_HOST) != 0 && 276238106Sdes (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { 277238106Sdes rtfree(rt); 278238106Sdes in6_ifloop_request(RTM_DELETE, ifa); 279238106Sdes } else 280238106Sdes RT_UNLOCK(rt); 281238106Sdes } 282238106Sdes } 283238106Sdes} 284238106Sdes 285238106Sdesint 286238106Sdesin6_mask2len(mask, lim0) 287238106Sdes struct in6_addr *mask; 288238106Sdes u_char *lim0; 289238106Sdes{ 290238106Sdes int x = 0, y; 291238106Sdes u_char *lim = lim0, *p; 292238106Sdes 293238106Sdes /* ignore the scope_id part */ 294238106Sdes if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask)) 295238106Sdes lim = (u_char *)mask + sizeof(*mask); 296238106Sdes for (p = (u_char *)mask; p < lim; x++, p++) { 297238106Sdes if (*p != 0xff) 298238106Sdes break; 299238106Sdes } 300238106Sdes y = 0; 301238106Sdes if (p < lim) { 302238106Sdes for (y = 0; y < 8; y++) { 303238106Sdes if ((*p & (0x80 >> y)) == 0) 304285206Sdes break; 305238106Sdes } 306238106Sdes } 307238106Sdes 308285206Sdes /* 309285206Sdes * when the limit pointer is given, do a stricter check on the 310238106Sdes * remaining bits. 311238106Sdes */ 312238106Sdes if (p < lim) { 313238106Sdes if (y != 0 && (*p & (0x00ff >> y)) != 0) 314238106Sdes return (-1); 315238106Sdes for (p = p + 1; p < lim; p++) 316238106Sdes if (*p != 0) 317238106Sdes return (-1); 318238106Sdes } 319238106Sdes 320285206Sdes return x * 8 + y; 321285206Sdes} 322285206Sdes 323285206Sdes#define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) 324285206Sdes#define ia62ifa(ia6) (&((ia6)->ia_ifa)) 325285206Sdes 326285206Sdesint 327285206Sdesin6_control(so, cmd, data, ifp, td) 328285206Sdes struct socket *so; 329285206Sdes u_long cmd; 330285206Sdes caddr_t data; 331285206Sdes struct ifnet *ifp; 332285206Sdes struct thread *td; 333285206Sdes{ 334285206Sdes struct in6_ifreq *ifr = (struct in6_ifreq *)data; 335285206Sdes struct in6_ifaddr *ia = NULL; 336285206Sdes struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; 337285206Sdes int privileged; 338285206Sdes 339285206Sdes privileged = 0; 340285206Sdes if (td == NULL || !suser(td)) 341285206Sdes privileged++; 342285206Sdes 343238106Sdes switch (cmd) { 344285206Sdes case SIOCGETSGCNT_IN6: 345285206Sdes case SIOCGETMIFCNT_IN6: 346285206Sdes return (mrt6_ioctl(cmd, data)); 347285206Sdes } 348238106Sdes 349285206Sdes switch(cmd) { 350285206Sdes case SIOCAADDRCTL_POLICY: 351238106Sdes case SIOCDADDRCTL_POLICY: 352285206Sdes if (!privileged) 353238106Sdes return (EPERM); 354285206Sdes return (in6_src_ioctl(cmd, data)); 355238106Sdes } 356238106Sdes 357285206Sdes if (ifp == NULL) 358285206Sdes return (EOPNOTSUPP); 359285206Sdes 360285206Sdes switch (cmd) { 361285206Sdes case SIOCSNDFLUSH_IN6: 362285206Sdes case SIOCSPFXFLUSH_IN6: 363238106Sdes case SIOCSRTRFLUSH_IN6: 364238106Sdes case SIOCSDEFIFACE_IN6: 365238106Sdes case SIOCSIFINFO_FLAGS: 366238106Sdes if (!privileged) 367238106Sdes return (EPERM); 368238106Sdes /* FALLTHROUGH */ 369238106Sdes case OSIOCGIFINFO_IN6: 370238106Sdes case SIOCGIFINFO_IN6: 371238106Sdes case SIOCGDRLST_IN6: 372238106Sdes case SIOCGPRLST_IN6: 373238106Sdes case SIOCGNBRINFO_IN6: 374238106Sdes case SIOCGDEFIFACE_IN6: 375238106Sdes return (nd6_ioctl(cmd, data, ifp)); 376238106Sdes } 377238106Sdes 378238106Sdes switch (cmd) { 379238106Sdes case SIOCSIFPREFIX_IN6: 380238106Sdes case SIOCDIFPREFIX_IN6: 381238106Sdes case SIOCAIFPREFIX_IN6: 382238106Sdes case SIOCCIFPREFIX_IN6: 383238106Sdes case SIOCSGIFPREFIX_IN6: 384238106Sdes case SIOCGIFPREFIX_IN6: 385238106Sdes log(LOG_NOTICE, 386238106Sdes "prefix ioctls are now invalidated. " 387238106Sdes "please use ifconfig.\n"); 388238106Sdes return (EOPNOTSUPP); 389238106Sdes } 390238106Sdes 391238106Sdes switch (cmd) { 392238106Sdes case SIOCSSCOPE6: 393238106Sdes if (!privileged) 394238106Sdes return (EPERM); 395238106Sdes return (scope6_set(ifp, 396238106Sdes (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 397238106Sdes case SIOCGSCOPE6: 398238106Sdes return (scope6_get(ifp, 399238106Sdes (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 400238106Sdes case SIOCGSCOPE6DEF: 401285206Sdes return (scope6_get_default((struct scope6_id *) 402238106Sdes ifr->ifr_ifru.ifru_scope_id)); 403238106Sdes } 404238106Sdes 405238106Sdes switch (cmd) { 406238106Sdes case SIOCALIFADDR: 407238106Sdes case SIOCDLIFADDR: 408238106Sdes if (!privileged) 409285206Sdes return (EPERM); 410238106Sdes /* FALLTHROUGH */ 411238106Sdes case SIOCGLIFADDR: 412238106Sdes return in6_lifaddr_ioctl(so, cmd, data, ifp, td); 413238106Sdes } 414285206Sdes 415238106Sdes /* 416238106Sdes * Find address for this interface, if it exists. 417238106Sdes */ 418238106Sdes if (ifra->ifra_addr.sin6_family == AF_INET6) { /* XXX */ 419238106Sdes struct sockaddr_in6 *sa6 = 420238106Sdes (struct sockaddr_in6 *)&ifra->ifra_addr; 421238106Sdes 422238106Sdes if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { 423238106Sdes if (sa6->sin6_addr.s6_addr16[1] == 0) { 424238106Sdes /* link ID is not embedded by the user */ 425238106Sdes sa6->sin6_addr.s6_addr16[1] = 426238106Sdes htons(ifp->if_index); 427238106Sdes } else if (sa6->sin6_addr.s6_addr16[1] != 428238106Sdes htons(ifp->if_index)) { 429238106Sdes return (EINVAL); /* link ID contradicts */ 430238106Sdes } 431238106Sdes if (sa6->sin6_scope_id) { 432238106Sdes if (sa6->sin6_scope_id != 433238106Sdes (u_int32_t)ifp->if_index) 434238106Sdes return (EINVAL); 435238106Sdes sa6->sin6_scope_id = 0; /* XXX: good way? */ 436238106Sdes } 437238106Sdes } 438238106Sdes ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr); 439238106Sdes } 440238106Sdes 441238106Sdes switch (cmd) { 442238106Sdes case SIOCSIFADDR_IN6: 443238106Sdes case SIOCSIFDSTADDR_IN6: 444238106Sdes case SIOCSIFNETMASK_IN6: 445238106Sdes /* 446238106Sdes * Since IPv6 allows a node to assign multiple addresses 447238106Sdes * on a single interface, SIOCSIFxxx ioctls are not suitable 448238106Sdes * and should be unused. 449238106Sdes */ 450238106Sdes /* we decided to obsolete this command (20000704) */ 451238106Sdes return (EINVAL); 452238106Sdes 453238106Sdes case SIOCDIFADDR_IN6: 454238106Sdes /* 455238106Sdes * for IPv4, we look for existing in_ifaddr here to allow 456238106Sdes * "ifconfig if0 delete" to remove first IPv4 address on the 457238106Sdes * interface. For IPv6, as the spec allow multiple interface 458238106Sdes * address from the day one, we consider "remove the first one" 459238106Sdes * semantics to be not preferable. 460238106Sdes */ 461238106Sdes if (ia == NULL) 462238106Sdes return (EADDRNOTAVAIL); 463238106Sdes /* FALLTHROUGH */ 464238106Sdes case SIOCAIFADDR_IN6: 465238106Sdes /* 466238106Sdes * We always require users to specify a valid IPv6 address for 467238106Sdes * the corresponding operation. 468238106Sdes */ 469238106Sdes if (ifra->ifra_addr.sin6_family != AF_INET6 || 470238106Sdes ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) 471238106Sdes return (EAFNOSUPPORT); 472238106Sdes if (!privileged) 473238106Sdes return (EPERM); 474238106Sdes 475238106Sdes break; 476238106Sdes 477238106Sdes case SIOCGIFADDR_IN6: 478238106Sdes /* This interface is basically deprecated. use SIOCGIFCONF. */ 479238106Sdes /* FALLTHROUGH */ 480238106Sdes case SIOCGIFAFLAG_IN6: 481238106Sdes case SIOCGIFNETMASK_IN6: 482238106Sdes case SIOCGIFDSTADDR_IN6: 483238106Sdes case SIOCGIFALIFETIME_IN6: 484238106Sdes /* must think again about its semantics */ 485238106Sdes if (ia == NULL) 486238106Sdes return (EADDRNOTAVAIL); 487238106Sdes break; 488238106Sdes case SIOCSIFALIFETIME_IN6: 489238106Sdes { 490238106Sdes struct in6_addrlifetime *lt; 491238106Sdes 492238106Sdes if (!privileged) 493238106Sdes return (EPERM); 494238106Sdes if (ia == NULL) 495238106Sdes return (EADDRNOTAVAIL); 496238106Sdes /* sanity for overflow - beware unsigned */ 497238106Sdes lt = &ifr->ifr_ifru.ifru_lifetime; 498238106Sdes if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME 499238106Sdes && lt->ia6t_vltime + time_second < time_second) { 500238106Sdes return EINVAL; 501238106Sdes } 502238106Sdes if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME 503238106Sdes && lt->ia6t_pltime + time_second < time_second) { 504238106Sdes return EINVAL; 505238106Sdes } 506238106Sdes break; 507238106Sdes } 508238106Sdes } 509238106Sdes 510238106Sdes switch (cmd) { 511238106Sdes 512238106Sdes case SIOCGIFADDR_IN6: 513238106Sdes ifr->ifr_addr = ia->ia_addr; 514238106Sdes break; 515238106Sdes 516238106Sdes case SIOCGIFDSTADDR_IN6: 517238106Sdes if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 518238106Sdes return (EINVAL); 519238106Sdes /* 520238106Sdes * XXX: should we check if ifa_dstaddr is NULL and return 521238106Sdes * an error? 522238106Sdes */ 523238106Sdes ifr->ifr_dstaddr = ia->ia_dstaddr; 524238106Sdes break; 525238106Sdes 526238106Sdes case SIOCGIFNETMASK_IN6: 527238106Sdes ifr->ifr_addr = ia->ia_prefixmask; 528238106Sdes break; 529238106Sdes 530238106Sdes case SIOCGIFAFLAG_IN6: 531238106Sdes ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags; 532238106Sdes break; 533238106Sdes 534238106Sdes case SIOCGIFSTAT_IN6: 535238106Sdes if (ifp == NULL) 536238106Sdes return EINVAL; 537238106Sdes bzero(&ifr->ifr_ifru.ifru_stat, 538238106Sdes sizeof(ifr->ifr_ifru.ifru_stat)); 539238106Sdes ifr->ifr_ifru.ifru_stat = 540238106Sdes *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat; 541238106Sdes break; 542238106Sdes 543238106Sdes case SIOCGIFSTAT_ICMP6: 544238106Sdes if (ifp == NULL) 545238106Sdes return EINVAL; 546238106Sdes bzero(&ifr->ifr_ifru.ifru_stat, 547238106Sdes sizeof(ifr->ifr_ifru.ifru_icmp6stat)); 548238106Sdes ifr->ifr_ifru.ifru_icmp6stat = 549238106Sdes *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat; 550238106Sdes break; 551238106Sdes 552238106Sdes case SIOCGIFALIFETIME_IN6: 553238106Sdes ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime; 554238106Sdes break; 555238106Sdes 556238106Sdes case SIOCSIFALIFETIME_IN6: 557238106Sdes ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime; 558238106Sdes /* for sanity */ 559238106Sdes if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 560238106Sdes ia->ia6_lifetime.ia6t_expire = 561238106Sdes time_second + ia->ia6_lifetime.ia6t_vltime; 562238106Sdes } else 563238106Sdes ia->ia6_lifetime.ia6t_expire = 0; 564238106Sdes if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 565238106Sdes ia->ia6_lifetime.ia6t_preferred = 566238106Sdes time_second + ia->ia6_lifetime.ia6t_pltime; 567238106Sdes } else 568238106Sdes ia->ia6_lifetime.ia6t_preferred = 0; 569238106Sdes break; 570238106Sdes 571238106Sdes case SIOCAIFADDR_IN6: 572238106Sdes { 573238106Sdes int i, error = 0; 574238106Sdes struct nd_prefix pr0, *pr; 575238106Sdes 576238106Sdes /* 577238106Sdes * first, make or update the interface address structure, 578238106Sdes * and link it to the list. 579238106Sdes */ 580238106Sdes if ((error = in6_update_ifa(ifp, ifra, ia)) != 0) 581238106Sdes return (error); 582238106Sdes 583238106Sdes /* 584238106Sdes * then, make the prefix on-link on the interface. 585238106Sdes * XXX: we'd rather create the prefix before the address, but 586238106Sdes * we need at least one address to install the corresponding 587238106Sdes * interface route, so we configure the address first. 588238106Sdes */ 589238106Sdes 590238106Sdes /* 591238106Sdes * convert mask to prefix length (prefixmask has already 592238106Sdes * been validated in in6_update_ifa(). 593238106Sdes */ 594238106Sdes bzero(&pr0, sizeof(pr0)); 595238106Sdes pr0.ndpr_ifp = ifp; 596238106Sdes pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 597238106Sdes NULL); 598238106Sdes if (pr0.ndpr_plen == 128) { 599238106Sdes break; /* we don't need to install a host route. */ 600238106Sdes } 601238106Sdes pr0.ndpr_prefix = ifra->ifra_addr; 602238106Sdes pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr; 603238106Sdes /* apply the mask for safety. */ 604238106Sdes for (i = 0; i < 4; i++) { 605238106Sdes pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 606238106Sdes ifra->ifra_prefixmask.sin6_addr.s6_addr32[i]; 607238106Sdes } 608238106Sdes /* 609238106Sdes * XXX: since we don't have an API to set prefix (not address) 610238106Sdes * lifetimes, we just use the same lifetimes as addresses. 611238106Sdes * The (temporarily) installed lifetimes can be overridden by 612238106Sdes * later advertised RAs (when accept_rtadv is non 0), which is 613238106Sdes * an intended behavior. 614238106Sdes */ 615238106Sdes pr0.ndpr_raf_onlink = 1; /* should be configurable? */ 616238106Sdes pr0.ndpr_raf_auto = 617238106Sdes ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0); 618238106Sdes pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime; 619238106Sdes pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime; 620238106Sdes 621238106Sdes /* add the prefix if not yet. */ 622238106Sdes if ((pr = nd6_prefix_lookup(&pr0)) == NULL) { 623238106Sdes /* 624238106Sdes * nd6_prelist_add will install the corresponding 625238106Sdes * interface route. 626238106Sdes */ 627238106Sdes if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) 628238106Sdes return (error); 629238106Sdes if (pr == NULL) { 630238106Sdes log(LOG_ERR, "nd6_prelist_add succeeded but " 631238106Sdes "no prefix\n"); 632238106Sdes return (EINVAL); /* XXX panic here? */ 633238106Sdes } 634238106Sdes } 635238106Sdes if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr)) 636238106Sdes == NULL) { 637238106Sdes /* XXX: this should not happen! */ 638238106Sdes log(LOG_ERR, "in6_control: addition succeeded, but" 639238106Sdes " no ifaddr\n"); 640238106Sdes } else { 641238106Sdes if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && 642238106Sdes ia->ia6_ndpr == NULL) { /* new autoconfed addr */ 643238106Sdes ia->ia6_ndpr = pr; 644238106Sdes pr->ndpr_refcnt++; 645238106Sdes 646238106Sdes /* 647238106Sdes * If this is the first autoconf address from 648238106Sdes * the prefix, create a temporary address 649238106Sdes * as well (when specified). 650285206Sdes */ 651238106Sdes if (ip6_use_tempaddr && 652238106Sdes pr->ndpr_refcnt == 1) { 653238106Sdes int e; 654238106Sdes if ((e = in6_tmpifadd(ia, 1)) != 0) { 655238106Sdes log(LOG_NOTICE, "in6_control: " 656238106Sdes "failed to create a " 657238106Sdes "temporary address, " 658238106Sdes "errno=%d\n", 659238106Sdes e); 660238106Sdes } 661238106Sdes } 662238106Sdes } 663238106Sdes 664238106Sdes /* 665238106Sdes * this might affect the status of autoconfigured 666238106Sdes * addresses, that is, this address might make 667238106Sdes * other addresses detached. 668238106Sdes */ 669238106Sdes pfxlist_onlink_check(); 670238106Sdes } 671238106Sdes break; 672238106Sdes } 673238106Sdes 674238106Sdes case SIOCDIFADDR_IN6: 675238106Sdes { 676238106Sdes int i = 0; 677238106Sdes struct nd_prefix pr0, *pr; 678238106Sdes 679238106Sdes /* 680238106Sdes * If the address being deleted is the only one that owns 681238106Sdes * the corresponding prefix, expire the prefix as well. 682238106Sdes * XXX: theoretically, we don't have to worry about such 683238106Sdes * relationship, since we separate the address management 684238106Sdes * and the prefix management. We do this, however, to provide 685238106Sdes * as much backward compatibility as possible in terms of 686238106Sdes * the ioctl operation. 687238106Sdes */ 688238106Sdes bzero(&pr0, sizeof(pr0)); 689238106Sdes pr0.ndpr_ifp = ifp; 690238106Sdes pr0.ndpr_plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, 691238106Sdes NULL); 692238106Sdes if (pr0.ndpr_plen == 128) 693238106Sdes goto purgeaddr; 694238106Sdes pr0.ndpr_prefix = ia->ia_addr; 695238106Sdes pr0.ndpr_mask = ia->ia_prefixmask.sin6_addr; 696238106Sdes for (i = 0; i < 4; i++) { 697285206Sdes pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 698285206Sdes ia->ia_prefixmask.sin6_addr.s6_addr32[i]; 699285206Sdes } 700285206Sdes /* 701238106Sdes * The logic of the following condition is a bit complicated. 702285206Sdes * We expire the prefix when 703285206Sdes * 1. the address obeys autoconfiguration and it is the 704285206Sdes * only owner of the associated prefix, or 705285206Sdes * 2. the address does not obey autoconf and there is no 706285206Sdes * other owner of the prefix. 707285206Sdes */ 708238106Sdes if ((pr = nd6_prefix_lookup(&pr0)) != NULL && 709238106Sdes (((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && 710238106Sdes pr->ndpr_refcnt == 1) || 711238106Sdes ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0 && 712238106Sdes pr->ndpr_refcnt == 0))) { 713285206Sdes pr->ndpr_expire = 1; /* XXX: just for expiration */ 714285206Sdes } 715285206Sdes 716285206Sdes purgeaddr: 717285206Sdes in6_purgeaddr(&ia->ia_ifa); 718285206Sdes break; 719285206Sdes } 720285206Sdes 721285206Sdes default: 722285206Sdes if (ifp == NULL || ifp->if_ioctl == 0) 723238106Sdes return (EOPNOTSUPP); 724269257Sdes return ((*ifp->if_ioctl)(ifp, cmd, data)); 725269257Sdes } 726238106Sdes 727238106Sdes return (0); 728238106Sdes} 729238106Sdes 730238106Sdes/* 731238106Sdes * Update parameters of an IPv6 interface address. 732238106Sdes * If necessary, a new entry is created and linked into address chains. 733238106Sdes * This function is separated from in6_control(). 734238106Sdes * XXX: should this be performed under splnet()? 735238106Sdes */ 736238106Sdesint 737238106Sdesin6_update_ifa(ifp, ifra, ia) 738238106Sdes struct ifnet *ifp; 739238106Sdes struct in6_aliasreq *ifra; 740238106Sdes struct in6_ifaddr *ia; 741238106Sdes{ 742238106Sdes int error = 0, hostIsNew = 0, plen = -1; 743255579Sdes struct in6_ifaddr *oia; 744238106Sdes struct sockaddr_in6 dst6; 745238106Sdes struct in6_addrlifetime *lt; 746238106Sdes 747238106Sdes /* Validate parameters */ 748238106Sdes if (ifp == NULL || ifra == NULL) /* this maybe redundant */ 749238106Sdes return (EINVAL); 750238106Sdes 751238106Sdes /* 752285206Sdes * The destination address for a p2p link must have a family 753238106Sdes * of AF_UNSPEC or AF_INET6. 754238106Sdes */ 755238106Sdes if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && 756238106Sdes ifra->ifra_dstaddr.sin6_family != AF_INET6 && 757238106Sdes ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) 758238106Sdes return (EAFNOSUPPORT); 759238106Sdes /* 760238106Sdes * validate ifra_prefixmask. don't check sin6_family, netmask 761238106Sdes * does not carry fields other than sin6_len. 762238106Sdes */ 763238106Sdes if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6)) 764238106Sdes return (EINVAL); 765238106Sdes /* 766238106Sdes * Because the IPv6 address architecture is classless, we require 767238106Sdes * users to specify a (non 0) prefix length (mask) for a new address. 768238106Sdes * We also require the prefix (when specified) mask is valid, and thus 769238106Sdes * reject a non-consecutive mask. 770238106Sdes */ 771238106Sdes if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0) 772238106Sdes return (EINVAL); 773238106Sdes if (ifra->ifra_prefixmask.sin6_len != 0) { 774238106Sdes plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, 775238106Sdes (u_char *)&ifra->ifra_prefixmask + 776238106Sdes ifra->ifra_prefixmask.sin6_len); 777238106Sdes if (plen <= 0) 778238106Sdes return (EINVAL); 779238106Sdes } else { 780238106Sdes /* 781238106Sdes * In this case, ia must not be NULL. We just use its prefix 782238106Sdes * length. 783238106Sdes */ 784238106Sdes plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 785238106Sdes } 786238106Sdes /* 787238106Sdes * If the destination address on a p2p interface is specified, 788238106Sdes * and the address is a scoped one, validate/set the scope 789238106Sdes * zone identifier. 790238106Sdes */ 791238106Sdes dst6 = ifra->ifra_dstaddr; 792238106Sdes if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 && 793238106Sdes (dst6.sin6_family == AF_INET6)) { 794238106Sdes int scopeid; 795238106Sdes 796238106Sdes if ((error = in6_recoverscope(&dst6, 797238106Sdes &ifra->ifra_dstaddr.sin6_addr, ifp)) != 0) 798238106Sdes return (error); 799238106Sdes if (in6_addr2zoneid(ifp, &dst6.sin6_addr, &scopeid)) 800238106Sdes return (EINVAL); 801238106Sdes if (dst6.sin6_scope_id == 0) /* user omit to specify the ID. */ 802238106Sdes dst6.sin6_scope_id = scopeid; 803238106Sdes else if (dst6.sin6_scope_id != scopeid) 804238106Sdes return (EINVAL); /* scope ID mismatch. */ 805238106Sdes if ((error = in6_embedscope(&dst6.sin6_addr, &dst6, NULL, NULL)) 806238106Sdes != 0) 807238106Sdes return (error); 808269257Sdes dst6.sin6_scope_id = 0; /* XXX */ 809269257Sdes } 810269257Sdes /* 811269257Sdes * The destination address can be specified only for a p2p or a 812269257Sdes * loopback interface. If specified, the corresponding prefix length 813269257Sdes * must be 128. 814238106Sdes */ 815238106Sdes if (ifra->ifra_dstaddr.sin6_family == AF_INET6) { 816238106Sdes if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) { 817238106Sdes /* XXX: noisy message */ 818238106Sdes log(LOG_INFO, "in6_update_ifa: a destination can be " 819238106Sdes "specified for a p2p or a loopback IF only\n"); 820238106Sdes return (EINVAL); 821238106Sdes } 822238106Sdes if (plen != 128) { 823238106Sdes /* 824238106Sdes * The following message seems noisy, but we dare to 825238106Sdes * add it for diagnosis. 826238106Sdes */ 827238106Sdes log(LOG_INFO, "in6_update_ifa: prefixlen must be 128 " 828238106Sdes "when dstaddr is specified\n"); 829238106Sdes return (EINVAL); 830238106Sdes } 831285206Sdes } 832238106Sdes /* lifetime consistency check */ 833238106Sdes lt = &ifra->ifra_lifetime; 834238106Sdes if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME 835238106Sdes && lt->ia6t_vltime + time_second < time_second) { 836285206Sdes return EINVAL; 837238106Sdes } 838238106Sdes if (lt->ia6t_vltime == 0) { 839238106Sdes /* 840238106Sdes * the following log might be noisy, but this is a typical 841238106Sdes * configuration mistake or a tool's bug. 842238106Sdes */ 843238106Sdes log(LOG_INFO, 844238106Sdes "in6_update_ifa: valid lifetime is 0 for %s\n", 845238106Sdes ip6_sprintf(&ifra->ifra_addr.sin6_addr)); 846238106Sdes } 847238106Sdes if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME 848238106Sdes && lt->ia6t_pltime + time_second < time_second) { 849238106Sdes return EINVAL; 850238106Sdes } 851269257Sdes 852269257Sdes /* 853238106Sdes * If this is a new address, allocate a new ifaddr and link it 854238106Sdes * into chains. 855238106Sdes */ 856238106Sdes if (ia == NULL) { 857269257Sdes hostIsNew = 1; 858238106Sdes /* 859238106Sdes * When in6_update_ifa() is called in a process of a received 860238106Sdes * RA, it is called under an interrupt context. So, we should 861238106Sdes * call malloc with M_NOWAIT. 862238106Sdes */ 863238106Sdes ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR, 864238106Sdes M_NOWAIT); 865238106Sdes if (ia == NULL) 866238106Sdes return (ENOBUFS); 867238106Sdes bzero((caddr_t)ia, sizeof(*ia)); 868238106Sdes /* Initialize the address and masks */ 869238106Sdes IFA_LOCK_INIT(&ia->ia_ifa); 870238106Sdes ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 871238106Sdes ia->ia_addr.sin6_family = AF_INET6; 872238106Sdes ia->ia_addr.sin6_len = sizeof(ia->ia_addr); 873285206Sdes if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { 874285206Sdes /* 875238106Sdes * XXX: some functions expect that ifa_dstaddr is not 876238106Sdes * NULL for p2p interfaces. 877285206Sdes */ 878285206Sdes ia->ia_ifa.ifa_dstaddr = 879238106Sdes (struct sockaddr *)&ia->ia_dstaddr; 880238106Sdes } else { 881238106Sdes ia->ia_ifa.ifa_dstaddr = NULL; 882238106Sdes } 883238106Sdes ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; 884269257Sdes 885238106Sdes ia->ia_ifp = ifp; 886238106Sdes if ((oia = in6_ifaddr) != NULL) { 887238106Sdes for ( ; oia->ia_next; oia = oia->ia_next) 888238106Sdes continue; 889238106Sdes oia->ia_next = ia; 890285206Sdes } else 891285206Sdes in6_ifaddr = ia; 892238106Sdes 893238106Sdes ia->ia_ifa.ifa_refcnt = 1; 894285206Sdes TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); 895285206Sdes } 896238106Sdes 897238106Sdes /* set prefix mask */ 898238106Sdes if (ifra->ifra_prefixmask.sin6_len) { 899238106Sdes /* 900238106Sdes * We prohibit changing the prefix length of an existing 901269257Sdes * address, because 902238106Sdes * + such an operation should be rare in IPv6, and 903238106Sdes * + the operation would confuse prefix management. 904238106Sdes */ 905238106Sdes if (ia->ia_prefixmask.sin6_len && 906238106Sdes in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) { 907285206Sdes log(LOG_INFO, "in6_update_ifa: the prefix length of an" 908285206Sdes " existing (%s) address should not be changed\n", 909238106Sdes ip6_sprintf(&ia->ia_addr.sin6_addr)); 910238106Sdes error = EINVAL; 911285206Sdes goto unlink; 912285206Sdes } 913285206Sdes ia->ia_prefixmask = ifra->ifra_prefixmask; 914285206Sdes } 915285206Sdes 916285206Sdes /* 917238106Sdes * If a new destination address is specified, scrub the old one and 918285206Sdes * install the new destination. Note that the interface must be 919285206Sdes * p2p or loopback (see the check above.) 920285206Sdes */ 921285206Sdes if (dst6.sin6_family == AF_INET6 && 922285206Sdes !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) { 923285206Sdes int e; 924285206Sdes 925285206Sdes if ((ia->ia_flags & IFA_ROUTE) != 0 && 926285206Sdes (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) { 927285206Sdes log(LOG_ERR, "in6_update_ifa: failed to remove " 928285206Sdes "a route to the old destination: %s\n", 929285206Sdes ip6_sprintf(&ia->ia_addr.sin6_addr)); 930285206Sdes /* proceed anyway... */ 931285206Sdes } else 932285206Sdes ia->ia_flags &= ~IFA_ROUTE; 933285206Sdes ia->ia_dstaddr = dst6; 934285206Sdes } 935285206Sdes 936285206Sdes /* reset the interface and routing table appropriately. */ 937285206Sdes if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) 938238106Sdes goto unlink; 939238106Sdes 940238106Sdes /* 941285206Sdes * Beyond this point, we should call in6_purgeaddr upon an error, 942285206Sdes * not just go to unlink. 943238106Sdes */ 944269257Sdes 945238106Sdes if ((ifp->if_flags & IFF_MULTICAST) != 0) { 946238106Sdes struct sockaddr_in6 mltaddr, mltmask; 947238106Sdes struct in6_multi *in6m; 948238106Sdes 949238106Sdes if (hostIsNew) { 950285206Sdes /* join solicited multicast addr for new host id */ 951285206Sdes struct in6_addr llsol; 952238106Sdes 953238106Sdes bzero(&llsol, sizeof(struct in6_addr)); 954285206Sdes llsol.s6_addr16[0] = htons(0xff02); 955285206Sdes llsol.s6_addr16[1] = htons(ifp->if_index); 956238106Sdes llsol.s6_addr32[1] = 0; 957238106Sdes llsol.s6_addr32[2] = htonl(1); 958285206Sdes llsol.s6_addr32[3] = 959285206Sdes ifra->ifra_addr.sin6_addr.s6_addr32[3]; 960285206Sdes llsol.s6_addr8[12] = 0xff; 961285206Sdes (void)in6_addmulti(&llsol, ifp, &error); 962285206Sdes if (error != 0) { 963285206Sdes log(LOG_WARNING, 964238106Sdes "in6_update_ifa: addmulti failed for " 965285206Sdes "%s on %s (errno=%d)\n", 966285206Sdes ip6_sprintf(&llsol), if_name(ifp), 967285206Sdes error); 968285206Sdes in6_purgeaddr((struct ifaddr *)ia); 969285206Sdes return (error); 970285206Sdes } 971285206Sdes } 972285206Sdes 973285206Sdes bzero(&mltmask, sizeof(mltmask)); 974285206Sdes mltmask.sin6_len = sizeof(struct sockaddr_in6); 975285206Sdes mltmask.sin6_family = AF_INET6; 976285206Sdes mltmask.sin6_addr = in6mask32; 977285206Sdes 978238106Sdes /* 979238106Sdes * join link-local all-nodes address 980238106Sdes */ 981238106Sdes bzero(&mltaddr, sizeof(mltaddr)); 982238106Sdes mltaddr.sin6_len = sizeof(struct sockaddr_in6); 983238106Sdes mltaddr.sin6_family = AF_INET6; 984238106Sdes mltaddr.sin6_addr = in6addr_linklocal_allnodes; 985238106Sdes mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 986238106Sdes 987238106Sdes IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 988238106Sdes if (in6m == NULL) { 989238106Sdes rtrequest(RTM_ADD, 990238106Sdes (struct sockaddr *)&mltaddr, 991238106Sdes (struct sockaddr *)&ia->ia_addr, 992238106Sdes (struct sockaddr *)&mltmask, 993238106Sdes RTF_UP|RTF_CLONING, /* xxx */ 994238106Sdes (struct rtentry **)0); 995238106Sdes (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); 996238106Sdes if (error != 0) { 997238106Sdes log(LOG_WARNING, 998238106Sdes "in6_update_ifa: addmulti failed for " 999238106Sdes "%s on %s (errno=%d)\n", 1000238106Sdes ip6_sprintf(&mltaddr.sin6_addr), 1001238106Sdes if_name(ifp), error); 1002238106Sdes } 1003238106Sdes } 1004238106Sdes 1005238106Sdes /* 1006238106Sdes * join node information group address 1007238106Sdes */ 1008238106Sdes#define hostnamelen strlen(hostname) 1009238106Sdes if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr) 1010238106Sdes == 0) { 1011238106Sdes IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 1012238106Sdes if (in6m == NULL && ia != NULL) { 1013238106Sdes (void)in6_addmulti(&mltaddr.sin6_addr, 1014238106Sdes ifp, &error); 1015238106Sdes if (error != 0) { 1016238106Sdes log(LOG_WARNING, "in6_update_ifa: " 1017238106Sdes "addmulti failed for " 1018238106Sdes "%s on %s (errno=%d)\n", 1019269257Sdes ip6_sprintf(&mltaddr.sin6_addr), 1020269257Sdes if_name(ifp), error); 1021269257Sdes } 1022238106Sdes } 1023238106Sdes } 1024238106Sdes#undef hostnamelen 1025269257Sdes 1026269257Sdes /* 1027269257Sdes * join node-local all-nodes address, on loopback. 1028269257Sdes * XXX: since "node-local" is obsoleted by interface-local, 1029269257Sdes * we have to join the group on every interface with 1030238106Sdes * some interface-boundary restriction. 1031238106Sdes */ 1032269257Sdes if (ifp->if_flags & IFF_LOOPBACK) { 1033238106Sdes struct in6_ifaddr *ia_loop; 1034238106Sdes 1035238106Sdes struct in6_addr loop6 = in6addr_loopback; 1036238106Sdes ia_loop = in6ifa_ifpwithaddr(ifp, &loop6); 1037238106Sdes 1038238106Sdes mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 1039238106Sdes 1040238106Sdes IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 1041238106Sdes if (in6m == NULL && ia_loop != NULL) { 1042238106Sdes rtrequest(RTM_ADD, 1043238106Sdes (struct sockaddr *)&mltaddr, 1044238106Sdes (struct sockaddr *)&ia_loop->ia_addr, 1045238106Sdes (struct sockaddr *)&mltmask, 1046238106Sdes RTF_UP, 1047238106Sdes (struct rtentry **)0); 1048238106Sdes (void)in6_addmulti(&mltaddr.sin6_addr, ifp, 1049238106Sdes &error); 1050238106Sdes if (error != 0) { 1051238106Sdes log(LOG_WARNING, "in6_update_ifa: " 1052238106Sdes "addmulti failed for %s on %s " 1053238106Sdes "(errno=%d)\n", 1054238106Sdes ip6_sprintf(&mltaddr.sin6_addr), 1055238106Sdes if_name(ifp), error); 1056238106Sdes } 1057238106Sdes } 1058238106Sdes } 1059238106Sdes } 1060238106Sdes 1061238106Sdes ia->ia6_flags = ifra->ifra_flags; 1062238106Sdes ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/ 1063238106Sdes ia->ia6_flags &= ~IN6_IFF_NODAD; /* Mobile IPv6 */ 1064238106Sdes 1065238106Sdes ia->ia6_lifetime = ifra->ifra_lifetime; 1066238106Sdes /* for sanity */ 1067238106Sdes if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 1068238106Sdes ia->ia6_lifetime.ia6t_expire = 1069238106Sdes time_second + ia->ia6_lifetime.ia6t_vltime; 1070238106Sdes } else 1071238106Sdes ia->ia6_lifetime.ia6t_expire = 0; 1072238106Sdes if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 1073238106Sdes ia->ia6_lifetime.ia6t_preferred = 1074238106Sdes time_second + ia->ia6_lifetime.ia6t_pltime; 1075238106Sdes } else 1076238106Sdes ia->ia6_lifetime.ia6t_preferred = 0; 1077238106Sdes 1078238106Sdes /* 1079238106Sdes * Perform DAD, if needed. 1080238106Sdes * XXX It may be of use, if we can administratively 1081238106Sdes * disable DAD. 1082238106Sdes */ 1083238106Sdes if (in6if_do_dad(ifp) && (ifra->ifra_flags & IN6_IFF_NODAD) == 0) { 1084238106Sdes ia->ia6_flags |= IN6_IFF_TENTATIVE; 1085269257Sdes nd6_dad_start((struct ifaddr *)ia, NULL); 1086238106Sdes } 1087238106Sdes 1088238106Sdes return (error); 1089238106Sdes 1090238106Sdes unlink: 1091238106Sdes /* 1092238106Sdes * XXX: if a change of an existing address failed, keep the entry 1093269257Sdes * anyway. 1094238106Sdes */ 1095238106Sdes if (hostIsNew) 1096238106Sdes in6_unlink_ifa(ia, ifp); 1097238106Sdes return (error); 1098238106Sdes} 1099269257Sdes 1100238106Sdesvoid 1101238106Sdesin6_purgeaddr(ifa) 1102238106Sdes struct ifaddr *ifa; 1103269257Sdes{ 1104238106Sdes struct ifnet *ifp = ifa->ifa_ifp; 1105238106Sdes struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; 1106238106Sdes 1107238106Sdes /* stop DAD processing */ 1108238106Sdes nd6_dad_stop(ifa); 1109238106Sdes 1110238106Sdes /* 1111238106Sdes * delete route to the destination of the address being purged. 1112238106Sdes * The interface must be p2p or loopback in this case. 1113238106Sdes */ 1114238106Sdes if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) { 1115238106Sdes int e; 1116238106Sdes 1117269257Sdes if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) 1118238106Sdes != 0) { 1119238106Sdes log(LOG_ERR, "in6_purgeaddr: failed to remove " 1120238106Sdes "a route to the p2p destination: %s on %s, " 1121238106Sdes "errno=%d\n", 1122238106Sdes ip6_sprintf(&ia->ia_addr.sin6_addr), if_name(ifp), 1123269257Sdes e); 1124238106Sdes /* proceed anyway... */ 1125238106Sdes } else 1126238106Sdes ia->ia_flags &= ~IFA_ROUTE; 1127238106Sdes } 1128238106Sdes 1129238106Sdes /* Remove ownaddr's loopback rtentry, if it exists. */ 1130238106Sdes in6_ifremloop(&(ia->ia_ifa)); 1131238106Sdes 1132269257Sdes if (ifp->if_flags & IFF_MULTICAST) { 1133238106Sdes /* 1134238106Sdes * delete solicited multicast addr for deleting host id 1135238106Sdes */ 1136238106Sdes struct in6_multi *in6m; 1137238106Sdes struct in6_addr llsol; 1138238106Sdes bzero(&llsol, sizeof(struct in6_addr)); 1139238106Sdes llsol.s6_addr16[0] = htons(0xff02); 1140238106Sdes llsol.s6_addr16[1] = htons(ifp->if_index); 1141238106Sdes llsol.s6_addr32[1] = 0; 1142238106Sdes llsol.s6_addr32[2] = htonl(1); 1143238106Sdes llsol.s6_addr32[3] = 1144238106Sdes ia->ia_addr.sin6_addr.s6_addr32[3]; 1145238106Sdes llsol.s6_addr8[12] = 0xff; 1146238106Sdes 1147238106Sdes IN6_LOOKUP_MULTI(llsol, ifp, in6m); 1148238106Sdes if (in6m) 1149238106Sdes in6_delmulti(in6m); 1150238106Sdes } 1151238106Sdes 1152238106Sdes in6_unlink_ifa(ia, ifp); 1153238106Sdes} 1154238106Sdes 1155238106Sdesstatic void 1156238106Sdesin6_unlink_ifa(ia, ifp) 1157238106Sdes struct in6_ifaddr *ia; 1158238106Sdes struct ifnet *ifp; 1159238106Sdes{ 1160238106Sdes int plen, iilen; 1161238106Sdes struct in6_ifaddr *oia; 1162238106Sdes int s = splnet(); 1163238106Sdes 1164238106Sdes TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); 1165238106Sdes 1166238106Sdes oia = ia; 1167238106Sdes if (oia == (ia = in6_ifaddr)) 1168238106Sdes in6_ifaddr = ia->ia_next; 1169238106Sdes else { 1170238106Sdes while (ia->ia_next && (ia->ia_next != oia)) 1171238106Sdes ia = ia->ia_next; 1172238106Sdes if (ia->ia_next) 1173238106Sdes ia->ia_next = oia->ia_next; 1174238106Sdes else { 1175238106Sdes /* search failed */ 1176238106Sdes printf("Couldn't unlink in6_ifaddr from in6_ifaddr\n"); 1177238106Sdes } 1178238106Sdes } 1179238106Sdes 1180238106Sdes if (oia->ia6_ifpr) { /* check for safety */ 1181238106Sdes plen = in6_mask2len(&oia->ia_prefixmask.sin6_addr, NULL); 1182285206Sdes iilen = (sizeof(oia->ia_prefixmask.sin6_addr) << 3) - plen; 1183238106Sdes in6_prefix_remove_ifid(iilen, oia); 1184285206Sdes } 1185285206Sdes 1186285206Sdes /* 1187285206Sdes * When an autoconfigured address is being removed, release the 1188285206Sdes * reference to the base prefix. Also, since the release might 1189238106Sdes * affect the status of other (detached) addresses, call 1190238106Sdes * pfxlist_onlink_check(). 1191238106Sdes */ 1192238106Sdes if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) { 1193238106Sdes if (oia->ia6_ndpr == NULL) { 1194238106Sdes log(LOG_NOTICE, "in6_unlink_ifa: autoconf'ed address " 1195238106Sdes "%p has no prefix\n", oia); 1196238106Sdes } else { 1197238106Sdes oia->ia6_ndpr->ndpr_refcnt--; 1198238106Sdes oia->ia6_flags &= ~IN6_IFF_AUTOCONF; 1199238106Sdes oia->ia6_ndpr = NULL; 1200238106Sdes } 1201238106Sdes 1202238106Sdes pfxlist_onlink_check(); 1203238106Sdes } 1204269257Sdes 1205238106Sdes /* 1206238106Sdes * release another refcnt for the link from in6_ifaddr. 1207238106Sdes * Note that we should decrement the refcnt at least once for all *BSD. 1208238106Sdes */ 1209238106Sdes IFAFREE(&oia->ia_ifa); 1210238106Sdes 1211238106Sdes splx(s); 1212238106Sdes} 1213238106Sdes 1214238106Sdesvoid 1215238106Sdesin6_purgeif(ifp) 1216238106Sdes struct ifnet *ifp; 1217238106Sdes{ 1218238106Sdes struct ifaddr *ifa, *nifa; 1219238106Sdes 1220238106Sdes for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa) { 1221238106Sdes nifa = TAILQ_NEXT(ifa, ifa_list); 1222238106Sdes if (ifa->ifa_addr->sa_family != AF_INET6) 1223238106Sdes continue; 1224238106Sdes in6_purgeaddr(ifa); 1225238106Sdes } 1226238106Sdes 1227238106Sdes in6_ifdetach(ifp); 1228238106Sdes} 1229238106Sdes 1230238106Sdes/* 1231238106Sdes * SIOC[GAD]LIFADDR. 1232269257Sdes * SIOCGLIFADDR: get first address. (?) 1233238106Sdes * SIOCGLIFADDR with IFLR_PREFIX: 1234269257Sdes * get first address that matches the specified prefix. 1235238106Sdes * SIOCALIFADDR: add the specified address. 1236238106Sdes * SIOCALIFADDR with IFLR_PREFIX: 1237238106Sdes * add the specified prefix, filling hostid part from 1238238106Sdes * the first link-local address. prefixlen must be <= 64. 1239238106Sdes * SIOCDLIFADDR: delete the specified address. 1240238106Sdes * SIOCDLIFADDR with IFLR_PREFIX: 1241238106Sdes * delete the first address that matches the specified prefix. 1242238106Sdes * return values: 1243238106Sdes * EINVAL on invalid parameters 1244238106Sdes * EADDRNOTAVAIL on prefix match failed/specified address not found 1245238106Sdes * other values may be returned from in6_ioctl() 1246238106Sdes * 1247238106Sdes * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64. 1248238106Sdes * this is to accomodate address naming scheme other than RFC2374, 1249238106Sdes * in the future. 1250238106Sdes * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374 1251238106Sdes * address encoding scheme. (see figure on page 8) 1252238106Sdes */ 1253238106Sdesstatic int 1254238106Sdesin6_lifaddr_ioctl(so, cmd, data, ifp, td) 1255238106Sdes struct socket *so; 1256238106Sdes u_long cmd; 1257238106Sdes caddr_t data; 1258238106Sdes struct ifnet *ifp; 1259238106Sdes struct thread *td; 1260238106Sdes{ 1261238106Sdes struct if_laddrreq *iflr = (struct if_laddrreq *)data; 1262238106Sdes struct ifaddr *ifa; 1263238106Sdes struct sockaddr *sa; 1264238106Sdes 1265238106Sdes /* sanity checks */ 1266238106Sdes if (!data || !ifp) { 1267238106Sdes panic("invalid argument to in6_lifaddr_ioctl"); 1268238106Sdes /* NOTREACHED */ 1269238106Sdes } 1270238106Sdes 1271238106Sdes switch (cmd) { 1272238106Sdes case SIOCGLIFADDR: 1273238106Sdes /* address must be specified on GET with IFLR_PREFIX */ 1274238106Sdes if ((iflr->flags & IFLR_PREFIX) == 0) 1275238106Sdes break; 1276238106Sdes /* FALLTHROUGH */ 1277238106Sdes case SIOCALIFADDR: 1278238106Sdes case SIOCDLIFADDR: 1279238106Sdes /* address must be specified on ADD and DELETE */ 1280238106Sdes sa = (struct sockaddr *)&iflr->addr; 1281238106Sdes if (sa->sa_family != AF_INET6) 1282238106Sdes return EINVAL; 1283238106Sdes if (sa->sa_len != sizeof(struct sockaddr_in6)) 1284238106Sdes return EINVAL; 1285238106Sdes /* XXX need improvement */ 1286238106Sdes sa = (struct sockaddr *)&iflr->dstaddr; 1287238106Sdes if (sa->sa_family && sa->sa_family != AF_INET6) 1288238106Sdes return EINVAL; 1289238106Sdes if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6)) 1290238106Sdes return EINVAL; 1291238106Sdes break; 1292238106Sdes default: /* shouldn't happen */ 1293238106Sdes#if 0 1294238106Sdes panic("invalid cmd to in6_lifaddr_ioctl"); 1295238106Sdes /* NOTREACHED */ 1296238106Sdes#else 1297238106Sdes return EOPNOTSUPP; 1298238106Sdes#endif 1299238106Sdes } 1300238106Sdes if (sizeof(struct in6_addr) * 8 < iflr->prefixlen) 1301238106Sdes return EINVAL; 1302238106Sdes 1303238106Sdes switch (cmd) { 1304238106Sdes case SIOCALIFADDR: 1305238106Sdes { 1306238106Sdes struct in6_aliasreq ifra; 1307238106Sdes struct in6_addr *hostid = NULL; 1308238106Sdes int prefixlen; 1309238106Sdes 1310238106Sdes if ((iflr->flags & IFLR_PREFIX) != 0) { 1311238106Sdes struct sockaddr_in6 *sin6; 1312238106Sdes 1313238106Sdes /* 1314238106Sdes * hostid is to fill in the hostid part of the 1315238106Sdes * address. hostid points to the first link-local 1316238106Sdes * address attached to the interface. 1317238106Sdes */ 1318238106Sdes ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); 1319238106Sdes if (!ifa) 1320238106Sdes return EADDRNOTAVAIL; 1321238106Sdes hostid = IFA_IN6(ifa); 1322238106Sdes 1323238106Sdes /* prefixlen must be <= 64. */ 1324238106Sdes if (64 < iflr->prefixlen) 1325238106Sdes return EINVAL; 1326238106Sdes prefixlen = iflr->prefixlen; 1327238106Sdes 1328238106Sdes /* hostid part must be zero. */ 1329238106Sdes sin6 = (struct sockaddr_in6 *)&iflr->addr; 1330238106Sdes if (sin6->sin6_addr.s6_addr32[2] != 0 1331238106Sdes || sin6->sin6_addr.s6_addr32[3] != 0) { 1332238106Sdes return EINVAL; 1333238106Sdes } 1334238106Sdes } else 1335238106Sdes prefixlen = iflr->prefixlen; 1336238106Sdes 1337238106Sdes /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 1338238106Sdes bzero(&ifra, sizeof(ifra)); 1339238106Sdes bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name)); 1340238106Sdes 1341238106Sdes bcopy(&iflr->addr, &ifra.ifra_addr, 1342238106Sdes ((struct sockaddr *)&iflr->addr)->sa_len); 1343238106Sdes if (hostid) { 1344238106Sdes /* fill in hostid part */ 1345238106Sdes ifra.ifra_addr.sin6_addr.s6_addr32[2] = 1346238106Sdes hostid->s6_addr32[2]; 1347238106Sdes ifra.ifra_addr.sin6_addr.s6_addr32[3] = 1348238106Sdes hostid->s6_addr32[3]; 1349238106Sdes } 1350238106Sdes 1351238106Sdes if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */ 1352238106Sdes bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 1353238106Sdes ((struct sockaddr *)&iflr->dstaddr)->sa_len); 1354238106Sdes if (hostid) { 1355238106Sdes ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] = 1356238106Sdes hostid->s6_addr32[2]; 1357238106Sdes ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = 1358238106Sdes hostid->s6_addr32[3]; 1359238106Sdes } 1360238106Sdes } 1361238106Sdes 1362238106Sdes ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 1363238106Sdes in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); 1364238106Sdes 1365238106Sdes ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; 1366238106Sdes return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, td); 1367238106Sdes } 1368238106Sdes case SIOCGLIFADDR: 1369238106Sdes case SIOCDLIFADDR: 1370238106Sdes { 1371238106Sdes struct in6_ifaddr *ia; 1372238106Sdes struct in6_addr mask, candidate, match; 1373238106Sdes struct sockaddr_in6 *sin6; 1374238106Sdes int cmp; 1375238106Sdes 1376238106Sdes bzero(&mask, sizeof(mask)); 1377238106Sdes if (iflr->flags & IFLR_PREFIX) { 1378238106Sdes /* lookup a prefix rather than address. */ 1379238106Sdes in6_prefixlen2mask(&mask, iflr->prefixlen); 1380238106Sdes 1381238106Sdes sin6 = (struct sockaddr_in6 *)&iflr->addr; 1382238106Sdes bcopy(&sin6->sin6_addr, &match, sizeof(match)); 1383238106Sdes match.s6_addr32[0] &= mask.s6_addr32[0]; 1384238106Sdes match.s6_addr32[1] &= mask.s6_addr32[1]; 1385238106Sdes match.s6_addr32[2] &= mask.s6_addr32[2]; 1386238106Sdes match.s6_addr32[3] &= mask.s6_addr32[3]; 1387238106Sdes 1388238106Sdes /* if you set extra bits, that's wrong */ 1389238106Sdes if (bcmp(&match, &sin6->sin6_addr, sizeof(match))) 1390238106Sdes return EINVAL; 1391238106Sdes 1392238106Sdes cmp = 1; 1393238106Sdes } else { 1394238106Sdes if (cmd == SIOCGLIFADDR) { 1395285206Sdes /* on getting an address, take the 1st match */ 1396285206Sdes cmp = 0; /* XXX */ 1397285206Sdes } else { 1398238106Sdes /* on deleting an address, do exact match */ 1399238106Sdes in6_prefixlen2mask(&mask, 128); 1400249141Sdes sin6 = (struct sockaddr_in6 *)&iflr->addr; 1401249141Sdes bcopy(&sin6->sin6_addr, &match, sizeof(match)); 1402249141Sdes 1403249141Sdes cmp = 1; 1404249141Sdes } 1405249141Sdes } 1406249141Sdes 1407249141Sdes TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 1408249141Sdes if (ifa->ifa_addr->sa_family != AF_INET6) 1409249141Sdes continue; 1410249141Sdes if (!cmp) 1411249141Sdes break; 1412249141Sdes 1413249141Sdes bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate)); 1414249141Sdes /* 1415249141Sdes * XXX: this is adhoc, but is necessary to allow 1416249141Sdes * a user to specify fe80::/64 (not /10) for a 1417249141Sdes * link-local address. 1418249141Sdes */ 1419249141Sdes if (IN6_IS_ADDR_LINKLOCAL(&candidate)) 1420249141Sdes candidate.s6_addr16[1] = 0; 1421249141Sdes candidate.s6_addr32[0] &= mask.s6_addr32[0]; 1422249141Sdes candidate.s6_addr32[1] &= mask.s6_addr32[1]; 1423249141Sdes candidate.s6_addr32[2] &= mask.s6_addr32[2]; 1424249141Sdes candidate.s6_addr32[3] &= mask.s6_addr32[3]; 1425249141Sdes if (IN6_ARE_ADDR_EQUAL(&candidate, &match)) 1426249141Sdes break; 1427249141Sdes } 1428249141Sdes if (!ifa) 1429249141Sdes return EADDRNOTAVAIL; 1430249141Sdes ia = ifa2ia6(ifa); 1431249141Sdes 1432249141Sdes if (cmd == SIOCGLIFADDR) { 1433249141Sdes struct sockaddr_in6 *s6; 1434249141Sdes 1435249141Sdes /* fill in the if_laddrreq structure */ 1436249141Sdes bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len); 1437249141Sdes s6 = (struct sockaddr_in6 *)&iflr->addr; 1438249141Sdes if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { 1439285206Sdes s6->sin6_addr.s6_addr16[1] = 0; 1440249141Sdes if (in6_addr2zoneid(ifp, &s6->sin6_addr, 1441249141Sdes &s6->sin6_scope_id)) 1442249141Sdes return (EINVAL);/* XXX */ 1443249141Sdes } 1444249141Sdes if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 1445249141Sdes bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 1446249141Sdes ia->ia_dstaddr.sin6_len); 1447249141Sdes s6 = (struct sockaddr_in6 *)&iflr->dstaddr; 1448249141Sdes if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { 1449249141Sdes s6->sin6_addr.s6_addr16[1] = 0; 1450249141Sdes if (in6_addr2zoneid(ifp, 1451249141Sdes &s6->sin6_addr, &s6->sin6_scope_id)) 1452249141Sdes return (EINVAL); /* EINVAL */ 1453249141Sdes } 1454249141Sdes } else 1455249141Sdes bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 1456249141Sdes 1457249141Sdes iflr->prefixlen = 1458249141Sdes in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); 1459249141Sdes 1460249141Sdes iflr->flags = ia->ia6_flags; /* XXX */ 1461249141Sdes 1462249141Sdes return 0; 1463285206Sdes } else { 1464285206Sdes struct in6_aliasreq ifra; 1465285206Sdes 1466249141Sdes /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 1467249141Sdes bzero(&ifra, sizeof(ifra)); 1468285206Sdes bcopy(iflr->iflr_name, ifra.ifra_name, 1469285206Sdes sizeof(ifra.ifra_name)); 1470285206Sdes 1471285206Sdes bcopy(&ia->ia_addr, &ifra.ifra_addr, 1472285206Sdes ia->ia_addr.sin6_len); 1473285206Sdes if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 1474285206Sdes bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 1475285206Sdes ia->ia_dstaddr.sin6_len); 1476285206Sdes } else { 1477285206Sdes bzero(&ifra.ifra_dstaddr, 1478285206Sdes sizeof(ifra.ifra_dstaddr)); 1479285206Sdes } 1480285206Sdes bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr, 1481285206Sdes ia->ia_prefixmask.sin6_len); 1482285206Sdes 1483285206Sdes ifra.ifra_flags = ia->ia6_flags; 1484285206Sdes return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, 1485285206Sdes ifp, td); 1486285206Sdes } 1487285206Sdes } 1488285206Sdes } 1489285206Sdes 1490285206Sdes return EOPNOTSUPP; /* just for safety */ 1491285206Sdes} 1492285206Sdes 1493285206Sdes/* 1494285206Sdes * Initialize an interface's intetnet6 address 1495285206Sdes * and routing table entry. 1496285206Sdes */ 1497285206Sdesstatic int 1498285206Sdesin6_ifinit(ifp, ia, sin6, newhost) 1499285206Sdes struct ifnet *ifp; 1500285206Sdes struct in6_ifaddr *ia; 1501285206Sdes struct sockaddr_in6 *sin6; 1502285206Sdes int newhost; 1503285206Sdes{ 1504285206Sdes int error = 0, plen, ifacount = 0; 1505285206Sdes int s = splimp(); 1506285206Sdes struct ifaddr *ifa; 1507285206Sdes 1508285206Sdes /* 1509285206Sdes * Give the interface a chance to initialize 1510285206Sdes * if this is its first address, 1511285206Sdes * and to validate the address if necessary. 1512285206Sdes */ 1513285206Sdes TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 1514285206Sdes if (ifa->ifa_addr == NULL) 1515285206Sdes continue; /* just for safety */ 1516285206Sdes if (ifa->ifa_addr->sa_family != AF_INET6) 1517285206Sdes continue; 1518285206Sdes ifacount++; 1519285206Sdes } 1520285206Sdes 1521285206Sdes ia->ia_addr = *sin6; 1522285206Sdes 1523285206Sdes if (ifacount <= 1 && ifp->if_ioctl && 1524285206Sdes (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { 1525285206Sdes splx(s); 1526285206Sdes return (error); 1527285206Sdes } 1528285206Sdes splx(s); 1529285206Sdes 1530285206Sdes ia->ia_ifa.ifa_metric = ifp->if_metric; 1531285206Sdes 1532285206Sdes /* we could do in(6)_socktrim here, but just omit it at this moment. */ 1533285206Sdes 1534285206Sdes /* 1535285206Sdes * Special case: 1536285206Sdes * If the destination address is specified for a point-to-point 1537285206Sdes * interface, install a route to the destination as an interface 1538285206Sdes * direct route. 1539285206Sdes */ 1540285206Sdes plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ 1541285206Sdes if (plen == 128 && ia->ia_dstaddr.sin6_family == AF_INET6) { 1542285206Sdes if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, 1543285206Sdes RTF_UP | RTF_HOST)) != 0) 1544238106Sdes return (error); 1545238106Sdes ia->ia_flags |= IFA_ROUTE; 1546238106Sdes } 1547238106Sdes if (plen < 128) { 1548238106Sdes /* 1549238106Sdes * The RTF_CLONING flag is necessary for in6_is_ifloop_auto(). 1550238106Sdes */ 1551238106Sdes ia->ia_ifa.ifa_flags |= RTF_CLONING; 1552238106Sdes } 1553238106Sdes 1554238106Sdes /* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */ 1555238106Sdes if (newhost) { 1556238106Sdes /* set the rtrequest function to create llinfo */ 1557238106Sdes ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; 1558238106Sdes in6_ifaddloop(&(ia->ia_ifa)); 1559238106Sdes } 1560238106Sdes 1561238106Sdes return (error); 1562238106Sdes} 1563238106Sdes 1564238106Sdes/* 1565238106Sdes * Add an address to the list of IP6 multicast addresses for a 1566238106Sdes * given interface. 1567238106Sdes */ 1568238106Sdesstruct in6_multi * 1569238106Sdesin6_addmulti(maddr6, ifp, errorp) 1570255579Sdes struct in6_addr *maddr6; 1571238106Sdes struct ifnet *ifp; 1572238106Sdes int *errorp; 1573238106Sdes{ 1574238106Sdes struct in6_multi *in6m; 1575238106Sdes struct sockaddr_in6 sin6; 1576238106Sdes struct ifmultiaddr *ifma; 1577238106Sdes int s = splnet(); 1578269257Sdes 1579238106Sdes *errorp = 0; 1580285206Sdes 1581238106Sdes /* 1582238106Sdes * Call generic routine to add membership or increment 1583238106Sdes * refcount. It wants addresses in the form of a sockaddr, 1584238106Sdes * so we build one here (being careful to zero the unused bytes). 1585238106Sdes */ 1586238106Sdes bzero(&sin6, sizeof sin6); 1587238106Sdes sin6.sin6_family = AF_INET6; 1588238106Sdes sin6.sin6_len = sizeof sin6; 1589238106Sdes sin6.sin6_addr = *maddr6; 1590238106Sdes *errorp = if_addmulti(ifp, (struct sockaddr *)&sin6, &ifma); 1591238106Sdes if (*errorp) { 1592238106Sdes splx(s); 1593238106Sdes return 0; 1594238106Sdes } 1595238106Sdes 1596238106Sdes /* 1597238106Sdes * If ifma->ifma_protospec is null, then if_addmulti() created 1598238106Sdes * a new record. Otherwise, we are done. 1599238106Sdes */ 1600238106Sdes if (ifma->ifma_protospec != 0) 1601238106Sdes return ifma->ifma_protospec; 1602238106Sdes 1603238106Sdes /* XXX - if_addmulti uses M_WAITOK. Can this really be called 1604238106Sdes at interrupt time? If so, need to fix if_addmulti. XXX */ 1605238106Sdes in6m = (struct in6_multi *)malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT); 1606238106Sdes if (in6m == NULL) { 1607238106Sdes splx(s); 1608238106Sdes return (NULL); 1609238106Sdes } 1610238106Sdes 1611238106Sdes bzero(in6m, sizeof *in6m); 1612238106Sdes in6m->in6m_addr = *maddr6; 1613238106Sdes in6m->in6m_ifp = ifp; 1614238106Sdes in6m->in6m_ifma = ifma; 1615238106Sdes ifma->ifma_protospec = in6m; 1616238106Sdes LIST_INSERT_HEAD(&in6_multihead, in6m, in6m_entry); 1617238106Sdes 1618238106Sdes /* 1619238106Sdes * Let MLD6 know that we have joined a new IPv6 multicast 1620238106Sdes * group. 1621238106Sdes */ 1622238106Sdes mld6_start_listening(in6m); 1623238106Sdes splx(s); 1624238106Sdes return (in6m); 1625238106Sdes} 1626238106Sdes 1627238106Sdes/* 1628238106Sdes * Delete a multicast address record. 1629238106Sdes */ 1630238106Sdesvoid 1631238106Sdesin6_delmulti(in6m) 1632238106Sdes struct in6_multi *in6m; 1633238106Sdes{ 1634238106Sdes struct ifmultiaddr *ifma = in6m->in6m_ifma; 1635238106Sdes int s = splnet(); 1636238106Sdes 1637238106Sdes if (ifma->ifma_refcount == 1) { 1638238106Sdes /* 1639238106Sdes * No remaining claims to this record; let MLD6 know 1640238106Sdes * that we are leaving the multicast group. 1641238106Sdes */ 1642238106Sdes mld6_stop_listening(in6m); 1643238106Sdes ifma->ifma_protospec = 0; 1644238106Sdes LIST_REMOVE(in6m, in6m_entry); 1645238106Sdes free(in6m, M_IPMADDR); 1646238106Sdes } 1647238106Sdes /* XXX - should be separate API for when we have an ifma? */ 1648238106Sdes if_delmulti(ifma->ifma_ifp, ifma->ifma_addr); 1649238106Sdes splx(s); 1650238106Sdes} 1651249141Sdes 1652238106Sdes/* 1653238106Sdes * Find an IPv6 interface link-local address specific to an interface. 1654238106Sdes */ 1655238106Sdesstruct in6_ifaddr * 1656238106Sdesin6ifa_ifpforlinklocal(ifp, ignoreflags) 1657238106Sdes struct ifnet *ifp; 1658238106Sdes int ignoreflags; 1659238106Sdes{ 1660238106Sdes struct ifaddr *ifa; 1661238106Sdes 1662238106Sdes TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 1663238106Sdes if (ifa->ifa_addr == NULL) 1664238106Sdes continue; /* just for safety */ 1665238106Sdes if (ifa->ifa_addr->sa_family != AF_INET6) 1666238106Sdes continue; 1667238106Sdes if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { 1668238106Sdes if ((((struct in6_ifaddr *)ifa)->ia6_flags & 1669238106Sdes ignoreflags) != 0) 1670238106Sdes continue; 1671238106Sdes break; 1672238106Sdes } 1673238106Sdes } 1674238106Sdes 1675238106Sdes return ((struct in6_ifaddr *)ifa); 1676238106Sdes} 1677238106Sdes 1678238106Sdes 1679238106Sdes/* 1680238106Sdes * find the internet address corresponding to a given interface and address. 1681238106Sdes */ 1682238106Sdesstruct in6_ifaddr * 1683238106Sdesin6ifa_ifpwithaddr(ifp, addr) 1684238106Sdes struct ifnet *ifp; 1685238106Sdes struct in6_addr *addr; 1686238106Sdes{ 1687238106Sdes struct ifaddr *ifa; 1688238106Sdes 1689238106Sdes TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 1690238106Sdes if (ifa->ifa_addr == NULL) 1691238106Sdes continue; /* just for safety */ 1692238106Sdes if (ifa->ifa_addr->sa_family != AF_INET6) 1693238106Sdes continue; 1694238106Sdes if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) 1695238106Sdes break; 1696238106Sdes } 1697238106Sdes 1698238106Sdes return ((struct in6_ifaddr *)ifa); 1699238106Sdes} 1700238106Sdes 1701238106Sdes/* 1702238106Sdes * Convert IP6 address to printable (loggable) representation. 1703238106Sdes */ 1704238106Sdesstatic char digits[] = "0123456789abcdef"; 1705238106Sdesstatic int ip6round = 0; 1706238106Sdeschar * 1707238106Sdesip6_sprintf(addr) 1708238106Sdes const struct in6_addr *addr; 1709238106Sdes{ 1710238106Sdes static char ip6buf[8][48]; 1711238106Sdes int i; 1712238106Sdes char *cp; 1713238106Sdes const u_short *a = (const u_short *)addr; 1714238106Sdes const u_char *d; 1715238106Sdes int dcolon = 0; 1716238106Sdes 1717238106Sdes ip6round = (ip6round + 1) & 7; 1718238106Sdes cp = ip6buf[ip6round]; 1719238106Sdes 1720238106Sdes for (i = 0; i < 8; i++) { 1721238106Sdes if (dcolon == 1) { 1722238106Sdes if (*a == 0) { 1723238106Sdes if (i == 7) 1724238106Sdes *cp++ = ':'; 1725238106Sdes a++; 1726238106Sdes continue; 1727238106Sdes } else 1728238106Sdes dcolon = 2; 1729238106Sdes } 1730238106Sdes if (*a == 0) { 1731238106Sdes if (dcolon == 0 && *(a + 1) == 0) { 1732238106Sdes if (i == 0) 1733238106Sdes *cp++ = ':'; 1734238106Sdes *cp++ = ':'; 1735238106Sdes dcolon = 1; 1736238106Sdes } else { 1737238106Sdes *cp++ = '0'; 1738238106Sdes *cp++ = ':'; 1739238106Sdes } 1740238106Sdes a++; 1741238106Sdes continue; 1742238106Sdes } 1743238106Sdes d = (const u_char *)a; 1744238106Sdes *cp++ = digits[*d >> 4]; 1745238106Sdes *cp++ = digits[*d++ & 0xf]; 1746238106Sdes *cp++ = digits[*d >> 4]; 1747238106Sdes *cp++ = digits[*d & 0xf]; 1748238106Sdes *cp++ = ':'; 1749238106Sdes a++; 1750238106Sdes } 1751238106Sdes *--cp = 0; 1752238106Sdes return (ip6buf[ip6round]); 1753238106Sdes} 1754238106Sdes 1755238106Sdesint 1756238106Sdesin6_localaddr(in6) 1757238106Sdes struct in6_addr *in6; 1758238106Sdes{ 1759238106Sdes struct in6_ifaddr *ia; 1760238106Sdes 1761269257Sdes if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6)) 1762238106Sdes return 1; 1763238106Sdes 1764238106Sdes for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 1765238106Sdes if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr, 1766238106Sdes &ia->ia_prefixmask.sin6_addr)) { 1767238106Sdes return 1; 1768238106Sdes } 1769238106Sdes } 1770238106Sdes 1771238106Sdes return (0); 1772238106Sdes} 1773238106Sdes 1774238106Sdesint 1775238106Sdesin6_is_addr_deprecated(sa6) 1776238106Sdes struct sockaddr_in6 *sa6; 1777238106Sdes{ 1778238106Sdes struct in6_ifaddr *ia; 1779238106Sdes 1780238106Sdes for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 1781238106Sdes if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 1782238106Sdes &sa6->sin6_addr) && 1783238106Sdes (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) 1784238106Sdes return (1); /* true */ 1785238106Sdes 1786238106Sdes /* XXX: do we still have to go thru the rest of the list? */ 1787238106Sdes } 1788269257Sdes 1789238106Sdes return (0); /* false */ 1790238106Sdes} 1791238106Sdes 1792238106Sdes/* 1793238106Sdes * return length of part which dst and src are equal 1794238106Sdes * hard coding... 1795238106Sdes */ 1796238106Sdesint 1797238106Sdesin6_matchlen(src, dst) 1798238106Sdesstruct in6_addr *src, *dst; 1799238106Sdes{ 1800238106Sdes int match = 0; 1801238106Sdes u_char *s = (u_char *)src, *d = (u_char *)dst; 1802238106Sdes u_char *lim = s + 16, r; 1803238106Sdes 1804238106Sdes while (s < lim) 1805238106Sdes if ((r = (*d++ ^ *s++)) != 0) { 1806269257Sdes while (r < 128) { 1807238106Sdes match++; 1808238106Sdes r <<= 1; 1809238106Sdes } 1810238106Sdes break; 1811238106Sdes } else 1812238106Sdes match += 8; 1813238106Sdes return match; 1814238106Sdes} 1815238106Sdes 1816269257Sdes/* XXX: to be scope conscious */ 1817269257Sdesint 1818269257Sdesin6_are_prefix_equal(p1, p2, len) 1819238106Sdes struct in6_addr *p1, *p2; 1820238106Sdes int len; 1821238106Sdes{ 1822238106Sdes int bytelen, bitlen; 1823238106Sdes 1824238106Sdes /* sanity check */ 1825238106Sdes if (0 > len || len > 128) { 1826238106Sdes log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n", 1827269257Sdes len); 1828269257Sdes return (0); 1829269257Sdes } 1830238106Sdes 1831238106Sdes bytelen = len / 8; 1832238106Sdes bitlen = len % 8; 1833238106Sdes 1834238106Sdes if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen)) 1835238106Sdes return (0); 1836238106Sdes if (p1->s6_addr[bytelen] >> (8 - bitlen) != 1837238106Sdes p2->s6_addr[bytelen] >> (8 - bitlen)) 1838238106Sdes return (0); 1839238106Sdes 1840238106Sdes return (1); 1841238106Sdes} 1842238106Sdes 1843238106Sdesvoid 1844238106Sdesin6_prefixlen2mask(maskp, len) 1845238106Sdes struct in6_addr *maskp; 1846269257Sdes int len; 1847238106Sdes{ 1848238106Sdes u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 1849238106Sdes int bytelen, bitlen, i; 1850238106Sdes 1851238106Sdes /* sanity check */ 1852238106Sdes if (0 > len || len > 128) { 1853238106Sdes log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n", 1854238106Sdes len); 1855269257Sdes return; 1856269257Sdes } 1857269257Sdes 1858269257Sdes bzero(maskp, sizeof(*maskp)); 1859269257Sdes bytelen = len / 8; 1860269257Sdes bitlen = len % 8; 1861269257Sdes for (i = 0; i < bytelen; i++) 1862269257Sdes maskp->s6_addr[i] = 0xff; 1863269257Sdes if (bitlen) 1864269257Sdes maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 1865269257Sdes} 1866269257Sdes 1867269257Sdes/* 1868269257Sdes * return the best address out of the same scope 1869269257Sdes */ 1870269257Sdesstruct in6_ifaddr * 1871269257Sdesin6_ifawithscope(oifp, dst) 1872269257Sdes struct ifnet *oifp; 1873269257Sdes struct in6_addr *dst; 1874269257Sdes{ 1875269257Sdes int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0; 1876269257Sdes int blen = -1; 1877269257Sdes struct ifaddr *ifa; 1878269257Sdes struct ifnet *ifp; 1879269257Sdes struct in6_ifaddr *ifa_best = NULL; 1880269257Sdes u_int32_t dstzone, odstzone; 1881269257Sdes 1882269257Sdes if (oifp == NULL) { 1883269257Sdes return (NULL); 1884269257Sdes } 1885269257Sdes 1886269257Sdes if (in6_addr2zoneid(oifp, dst, &odstzone)) 1887269257Sdes return (NULL); 1888269257Sdes 1889269257Sdes /* 1890269257Sdes * We search for all addresses on all interfaces from the beginning. 1891269257Sdes * Comparing an interface with the outgoing interface will be done 1892238106Sdes * only at the final stage of tiebreaking. 1893238106Sdes */ 1894238106Sdes IFNET_RLOCK(); 1895238106Sdes for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) 1896238106Sdes { 1897238106Sdes /* 1898238106Sdes * We can never take an address that breaks the scope zone 1899238106Sdes * of the destination. 1900238106Sdes */ 1901238106Sdes if (in6_addr2zoneid(ifp, dst, &dstzone) || dstzone != odstzone) 1902238106Sdes continue; 1903238106Sdes 1904238106Sdes TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 1905238106Sdes { 1906238106Sdes int tlen = -1, dscopecmp, bscopecmp, matchcmp; 1907238106Sdes 1908238106Sdes if (ifa->ifa_addr->sa_family != AF_INET6) 1909238106Sdes continue; 1910238106Sdes 1911238106Sdes src_scope = in6_addrscope(IFA_IN6(ifa)); 1912238106Sdes 1913269257Sdes /* 1914238106Sdes * Don't use an address before completing DAD 1915285206Sdes * nor a duplicated address. 1916285206Sdes */ 1917285206Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & 1918285206Sdes IN6_IFF_NOTREADY) 1919238106Sdes continue; 1920238106Sdes 1921238106Sdes /* XXX: is there any case to allow anycasts? */ 1922238106Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & 1923238106Sdes IN6_IFF_ANYCAST) 1924238106Sdes continue; 1925238106Sdes 1926238106Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & 1927238106Sdes IN6_IFF_DETACHED) 1928238106Sdes continue; 1929238106Sdes 1930238106Sdes /* 1931238106Sdes * If this is the first address we find, 1932238106Sdes * keep it anyway. 1933238106Sdes */ 1934238106Sdes if (ifa_best == NULL) 1935238106Sdes goto replace; 1936269257Sdes 1937269257Sdes /* 1938238106Sdes * ifa_best is never NULL beyond this line except 1939238106Sdes * within the block labeled "replace". 1940238106Sdes */ 1941238106Sdes 1942238106Sdes /* 1943238106Sdes * If ifa_best has a smaller scope than dst and 1944238106Sdes * the current address has a larger one than 1945238106Sdes * (or equal to) dst, always replace ifa_best. 1946238106Sdes * Also, if the current address has a smaller scope 1947238106Sdes * than dst, ignore it unless ifa_best also has a 1948238106Sdes * smaller scope. 1949238106Sdes * Consequently, after the two if-clause below, 1950238106Sdes * the followings must be satisfied: 1951238106Sdes * (scope(src) < scope(dst) && 1952238106Sdes * scope(best) < scope(dst)) 1953238106Sdes * OR 1954238106Sdes * (scope(best) >= scope(dst) && 1955238106Sdes * scope(src) >= scope(dst)) 1956238106Sdes */ 1957238106Sdes if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 && 1958238106Sdes IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0) 1959238106Sdes goto replace; /* (A) */ 1960238106Sdes if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 && 1961238106Sdes IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0) 1962238106Sdes continue; /* (B) */ 1963238106Sdes 1964238106Sdes /* 1965238106Sdes * A deprecated address SHOULD NOT be used in new 1966238106Sdes * communications if an alternate (non-deprecated) 1967238106Sdes * address is available and has sufficient scope. 1968238106Sdes * RFC 2462, Section 5.5.4. 1969238106Sdes */ 1970238106Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & 1971238106Sdes IN6_IFF_DEPRECATED) { 1972238106Sdes /* 1973238106Sdes * Ignore any deprecated addresses if 1974238106Sdes * specified by configuration. 1975238106Sdes */ 1976238106Sdes if (!ip6_use_deprecated) 1977238106Sdes continue; 1978238106Sdes 1979238106Sdes /* 1980238106Sdes * If we have already found a non-deprecated 1981238106Sdes * candidate, just ignore deprecated addresses. 1982269257Sdes */ 1983269257Sdes if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) 1984238106Sdes == 0) 1985269257Sdes continue; 1986269257Sdes } 1987238106Sdes 1988238106Sdes /* 1989238106Sdes * A non-deprecated address is always preferred 1990238106Sdes * to a deprecated one regardless of scopes and 1991238106Sdes * address matching (Note invariants ensured by the 1992238106Sdes * conditions (A) and (B) above.) 1993238106Sdes */ 1994238106Sdes if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) && 1995238106Sdes (((struct in6_ifaddr *)ifa)->ia6_flags & 1996238106Sdes IN6_IFF_DEPRECATED) == 0) 1997238106Sdes goto replace; 1998238106Sdes 1999238106Sdes /* 2000238106Sdes * When we use temporary addresses described in 2001238106Sdes * RFC 3041, we prefer temporary addresses to 2002238106Sdes * public autoconf addresses. Again, note the 2003238106Sdes * invariants from (A) and (B). Also note that we 2004238106Sdes * don't have any preference between static addresses 2005238106Sdes * and autoconf addresses (despite of whether or not 2006238106Sdes * the latter is temporary or public.) 2007238106Sdes */ 2008238106Sdes if (ip6_use_tempaddr) { 2009238106Sdes struct in6_ifaddr *ifat; 2010238106Sdes 2011238106Sdes ifat = (struct in6_ifaddr *)ifa; 2012238106Sdes if ((ifa_best->ia6_flags & 2013238106Sdes (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) 2014238106Sdes == IN6_IFF_AUTOCONF && 2015269257Sdes (ifat->ia6_flags & 2016269257Sdes (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) 2017238106Sdes == (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) { 2018238106Sdes goto replace; 2019238106Sdes } 2020238106Sdes if ((ifa_best->ia6_flags & 2021269257Sdes (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) 2022269257Sdes == (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY) && 2023238106Sdes (ifat->ia6_flags & 2024238106Sdes (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) 2025238106Sdes == IN6_IFF_AUTOCONF) { 2026238106Sdes continue; 2027238106Sdes } 2028238106Sdes } 2029238106Sdes 2030238106Sdes /* 2031238106Sdes * At this point, we have two cases: 2032238106Sdes * 1. we are looking at a non-deprecated address, 2033238106Sdes * and ifa_best is also non-deprecated. 2034238106Sdes * 2. we are looking at a deprecated address, 2035238106Sdes * and ifa_best is also deprecated. 2036238106Sdes * Also, we do not have to consider a case where 2037238106Sdes * the scope of if_best is larger(smaller) than dst and 2038238106Sdes * the scope of the current address is smaller(larger) 2039238106Sdes * than dst. Such a case has already been covered. 2040269257Sdes * Tiebreaking is done according to the following 2041285206Sdes * items: 2042285206Sdes * - the scope comparison between the address and 2043285206Sdes * dst (dscopecmp) 2044238106Sdes * - the scope comparison between the address and 2045238106Sdes * ifa_best (bscopecmp) 2046238106Sdes * - if the address match dst longer than ifa_best 2047238106Sdes * (matchcmp) 2048238106Sdes * - if the address is on the outgoing I/F (outI/F) 2049238106Sdes * 2050238106Sdes * Roughly speaking, the selection policy is 2051238106Sdes * - the most important item is scope. The same scope 2052238106Sdes * is best. Then search for a larger scope. 2053238106Sdes * Smaller scopes are the last resort. 2054238106Sdes * - A deprecated address is chosen only when we have 2055285206Sdes * no address that has an enough scope, but is 2056285206Sdes * prefered to any addresses of smaller scopes 2057238106Sdes * (this must be already done above.) 2058238106Sdes * - addresses on the outgoing I/F are preferred to 2059238106Sdes * ones on other interfaces if none of above 2060238106Sdes * tiebreaks. In the table below, the column "bI" 2061238106Sdes * means if the best_ifa is on the outgoing 2062238106Sdes * interface, and the column "sI" means if the ifa 2063285206Sdes * is on the outgoing interface. 2064285206Sdes * - If there is no other reasons to choose one, 2065285206Sdes * longest address match against dst is considered. 2066285206Sdes * 2067238106Sdes * The precise decision table is as follows: 2068238106Sdes * dscopecmp bscopecmp match bI oI | replace? 2069238106Sdes * N/A equal N/A Y N | No (1) 2070285206Sdes * N/A equal N/A N Y | Yes (2) 2071238106Sdes * N/A equal larger N/A | Yes (3) 2072238106Sdes * N/A equal !larger N/A | No (4) 2073285206Sdes * larger larger N/A N/A | No (5) 2074238106Sdes * larger smaller N/A N/A | Yes (6) 2075238106Sdes * smaller larger N/A N/A | Yes (7) 2076238106Sdes * smaller smaller N/A N/A | No (8) 2077238106Sdes * equal smaller N/A N/A | Yes (9) 2078238106Sdes * equal larger (already done at A above) 2079285206Sdes */ 2080285206Sdes dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope); 2081238106Sdes bscopecmp = IN6_ARE_SCOPE_CMP(src_scope, best_scope); 2082285206Sdes 2083238106Sdes if (bscopecmp == 0) { 2084238106Sdes struct ifnet *bifp = ifa_best->ia_ifp; 2085238106Sdes 2086238106Sdes if (bifp == oifp && ifp != oifp) /* (1) */ 2087238106Sdes continue; 2088238106Sdes if (bifp != oifp && ifp == oifp) /* (2) */ 2089238106Sdes goto replace; 2090238106Sdes 2091238106Sdes /* 2092238106Sdes * Both bifp and ifp are on the outgoing 2093285206Sdes * interface, or both two are on a different 2094238106Sdes * interface from the outgoing I/F. 2095238106Sdes * now we need address matching against dst 2096238106Sdes * for tiebreaking. 2097238106Sdes */ 2098238106Sdes tlen = in6_matchlen(IFA_IN6(ifa), dst); 2099238106Sdes matchcmp = tlen - blen; 2100238106Sdes if (matchcmp > 0) /* (3) */ 2101238106Sdes goto replace; 2102238106Sdes continue; /* (4) */ 2103238106Sdes } 2104238106Sdes if (dscopecmp > 0) { 2105238106Sdes if (bscopecmp > 0) /* (5) */ 2106238106Sdes continue; 2107238106Sdes goto replace; /* (6) */ 2108238106Sdes } 2109238106Sdes if (dscopecmp < 0) { 2110238106Sdes if (bscopecmp > 0) /* (7) */ 2111238106Sdes goto replace; 2112238106Sdes continue; /* (8) */ 2113238106Sdes } 2114238106Sdes 2115238106Sdes /* now dscopecmp must be 0 */ 2116238106Sdes if (bscopecmp < 0) 2117238106Sdes goto replace; /* (9) */ 2118238106Sdes 2119238106Sdes replace: 2120238106Sdes ifa_best = (struct in6_ifaddr *)ifa; 2121238106Sdes blen = tlen >= 0 ? tlen : 2122238106Sdes in6_matchlen(IFA_IN6(ifa), dst); 2123238106Sdes best_scope = in6_addrscope(&ifa_best->ia_addr.sin6_addr); 2124238106Sdes } 2125238106Sdes } 2126238106Sdes IFNET_RUNLOCK(); 2127238106Sdes 2128238106Sdes /* count statistics for future improvements */ 2129238106Sdes if (ifa_best == NULL) 2130238106Sdes ip6stat.ip6s_sources_none++; 2131238106Sdes else { 2132238106Sdes if (oifp == ifa_best->ia_ifp) 2133238106Sdes ip6stat.ip6s_sources_sameif[best_scope]++; 2134238106Sdes else 2135238106Sdes ip6stat.ip6s_sources_otherif[best_scope]++; 2136238106Sdes 2137238106Sdes if (best_scope == dst_scope) 2138238106Sdes ip6stat.ip6s_sources_samescope[best_scope]++; 2139238106Sdes else 2140238106Sdes ip6stat.ip6s_sources_otherscope[best_scope]++; 2141238106Sdes 2142238106Sdes if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) != 0) 2143238106Sdes ip6stat.ip6s_sources_deprecated[best_scope]++; 2144238106Sdes } 2145238106Sdes 2146285206Sdes return (ifa_best); 2147285206Sdes} 2148238106Sdes 2149238106Sdes/* 2150285206Sdes * return the best address out of the same scope. if no address was 2151285206Sdes * found, return the first valid address from designated IF. 2152285206Sdes */ 2153285206Sdesstruct in6_ifaddr * 2154285206Sdesin6_ifawithifp(ifp, dst) 2155285206Sdes struct ifnet *ifp; 2156285206Sdes struct in6_addr *dst; 2157285206Sdes{ 2158285206Sdes int dst_scope = in6_addrscope(dst), blen = -1, tlen; 2159285206Sdes struct ifaddr *ifa; 2160285206Sdes struct in6_ifaddr *besta = 0; 2161285206Sdes struct in6_ifaddr *dep[2]; /* last-resort: deprecated */ 2162285206Sdes 2163238106Sdes dep[0] = dep[1] = NULL; 2164238106Sdes 2165238106Sdes /* 2166238106Sdes * We first look for addresses in the same scope. 2167238106Sdes * If there is one, return it. 2168238106Sdes * If two or more, return one which matches the dst longest. 2169238106Sdes * If none, return one of global addresses assigned other ifs. 2170238106Sdes */ 2171238106Sdes TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 2172285206Sdes if (ifa->ifa_addr->sa_family != AF_INET6) 2173285206Sdes continue; 2174285206Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 2175238106Sdes continue; /* XXX: is there any case to allow anycast? */ 2176285206Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 2177285206Sdes continue; /* don't use this interface */ 2178285206Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 2179285206Sdes continue; 2180285206Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 2181285206Sdes if (ip6_use_deprecated) 2182285206Sdes dep[0] = (struct in6_ifaddr *)ifa; 2183285206Sdes continue; 2184285206Sdes } 2185285206Sdes 2186285206Sdes if (dst_scope == in6_addrscope(IFA_IN6(ifa))) { 2187285206Sdes /* 2188285206Sdes * call in6_matchlen() as few as possible 2189285206Sdes */ 2190238106Sdes if (besta) { 2191238106Sdes if (blen == -1) 2192238106Sdes blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst); 2193238106Sdes tlen = in6_matchlen(IFA_IN6(ifa), dst); 2194238106Sdes if (tlen > blen) { 2195238106Sdes blen = tlen; 2196238106Sdes besta = (struct in6_ifaddr *)ifa; 2197238106Sdes } 2198238106Sdes } else 2199238106Sdes besta = (struct in6_ifaddr *)ifa; 2200238106Sdes } 2201238106Sdes } 2202269257Sdes if (besta) 2203238106Sdes return (besta); 2204238106Sdes 2205238106Sdes TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 2206285206Sdes if (ifa->ifa_addr->sa_family != AF_INET6) 2207285206Sdes continue; 2208285206Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) 2209285206Sdes continue; /* XXX: is there any case to allow anycast? */ 2210285206Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) 2211285206Sdes continue; /* don't use this interface */ 2212285206Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) 2213238106Sdes continue; 2214238106Sdes if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { 2215269257Sdes if (ip6_use_deprecated) 2216238106Sdes dep[1] = (struct in6_ifaddr *)ifa; 2217238106Sdes continue; 2218238106Sdes } 2219238106Sdes 2220238106Sdes return (struct in6_ifaddr *)ifa; 2221238106Sdes } 2222238106Sdes 2223238106Sdes /* use the last-resort values, that are, deprecated addresses */ 2224238106Sdes if (dep[0]) 2225238106Sdes return dep[0]; 2226269257Sdes if (dep[1]) 2227269257Sdes return dep[1]; 2228269257Sdes 2229238106Sdes return NULL; 2230238106Sdes} 2231238106Sdes 2232238106Sdes/* 2233269257Sdes * perform DAD when interface becomes IFF_UP. 2234269257Sdes */ 2235269257Sdesvoid 2236269257Sdesin6_if_up(ifp) 2237269257Sdes struct ifnet *ifp; 2238269257Sdes{ 2239269257Sdes struct ifaddr *ifa; 2240269257Sdes struct in6_ifaddr *ia; 2241269257Sdes int dad_delay; /* delay ticks before DAD output */ 2242269257Sdes 2243269257Sdes /* 2244269257Sdes * special cases, like 6to4, are handled in in6_ifattach 2245238106Sdes */ 2246238106Sdes in6_ifattach(ifp, NULL); 2247238106Sdes 2248238106Sdes dad_delay = 0; 2249269257Sdes TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 2250238106Sdes if (ifa->ifa_addr->sa_family != AF_INET6) 2251238106Sdes continue; 2252238106Sdes ia = (struct in6_ifaddr *)ifa; 2253238106Sdes if (ia->ia6_flags & IN6_IFF_TENTATIVE) 2254238106Sdes nd6_dad_start(ifa, &dad_delay); 2255238106Sdes } 2256238106Sdes} 2257238106Sdes 2258238106Sdesint 2259238106Sdesin6if_do_dad(ifp) 2260238106Sdes struct ifnet *ifp; 2261238106Sdes{ 2262238106Sdes if ((ifp->if_flags & IFF_LOOPBACK) != 0) 2263238106Sdes return (0); 2264238106Sdes 2265238106Sdes switch (ifp->if_type) { 2266238106Sdes#ifdef IFT_DUMMY 2267238106Sdes case IFT_DUMMY: 2268238106Sdes#endif 2269238106Sdes case IFT_FAITH: 2270238106Sdes /* 2271238106Sdes * These interfaces do not have the IFF_LOOPBACK flag, 2272238106Sdes * but loop packets back. We do not have to do DAD on such 2273238106Sdes * interfaces. We should even omit it, because loop-backed 2274238106Sdes * NS would confuse the DAD procedure. 2275238106Sdes */ 2276238106Sdes return (0); 2277238106Sdes default: 2278238106Sdes /* 2279238106Sdes * Our DAD routine requires the interface up and running. 2280238106Sdes * However, some interfaces can be up before the RUNNING 2281238106Sdes * status. Additionaly, users may try to assign addresses 2282238106Sdes * before the interface becomes up (or running). 2283238106Sdes * We simply skip DAD in such a case as a work around. 2284238106Sdes * XXX: we should rather mark "tentative" on such addresses, 2285238106Sdes * and do DAD after the interface becomes ready. 2286238106Sdes */ 2287238106Sdes if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != 2288238106Sdes (IFF_UP|IFF_RUNNING)) 2289238106Sdes return (0); 2290238106Sdes 2291238106Sdes return (1); 2292238106Sdes } 2293238106Sdes} 2294238106Sdes 2295238106Sdes/* 2296238106Sdes * Calculate max IPv6 MTU through all the interfaces and store it 2297238106Sdes * to in6_maxmtu. 2298238106Sdes */ 2299238106Sdesvoid 2300238106Sdesin6_setmaxmtu() 2301238106Sdes{ 2302238106Sdes unsigned long maxmtu = 0; 2303238106Sdes struct ifnet *ifp; 2304238106Sdes 2305238106Sdes IFNET_RLOCK(); 2306238106Sdes for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { 2307238106Sdes /* this function can be called during ifnet initialization */ 2308238106Sdes if (!ifp->if_afdata[AF_INET6]) 2309238106Sdes continue; 2310238106Sdes if ((ifp->if_flags & IFF_LOOPBACK) == 0 && 2311238106Sdes IN6_LINKMTU(ifp) > maxmtu) 2312238106Sdes maxmtu = IN6_LINKMTU(ifp); 2313238106Sdes } 2314238106Sdes IFNET_RUNLOCK(); 2315238106Sdes if (maxmtu) /* update only when maxmtu is positive */ 2316238106Sdes in6_maxmtu = maxmtu; 2317238106Sdes} 2318238106Sdes 2319238106Sdesvoid * 2320238106Sdesin6_domifattach(ifp) 2321238106Sdes struct ifnet *ifp; 2322238106Sdes{ 2323238106Sdes struct in6_ifextra *ext; 2324238106Sdes 2325238106Sdes ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK); 2326238106Sdes bzero(ext, sizeof(*ext)); 2327238106Sdes 2328238106Sdes ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat), 2329238106Sdes M_IFADDR, M_WAITOK); 2330238106Sdes bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat)); 2331238106Sdes 2332238106Sdes ext->icmp6_ifstat = 2333238106Sdes (struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat), 2334238106Sdes M_IFADDR, M_WAITOK); 2335238106Sdes bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat)); 2336238106Sdes 2337238106Sdes ext->nd_ifinfo = nd6_ifattach(ifp); 2338269257Sdes ext->scope6_id = scope6_ifattach(ifp); 2339269257Sdes return ext; 2340269257Sdes} 2341269257Sdes 2342269257Sdesvoid 2343269257Sdesin6_domifdetach(ifp, aux) 2344269257Sdes struct ifnet *ifp; 2345269257Sdes void *aux; 2346269257Sdes{ 2347269257Sdes struct in6_ifextra *ext = (struct in6_ifextra *)aux; 2348238106Sdes 2349238106Sdes scope6_ifdetach(ext->scope6_id); 2350238106Sdes nd6_ifdetach(ext->nd_ifinfo); 2351238106Sdes free(ext->in6_ifstat, M_IFADDR); 2352238106Sdes free(ext->icmp6_ifstat, M_IFADDR); 2353238106Sdes free(ext, M_IFADDR); 2354238106Sdes} 2355238106Sdes 2356238106Sdes/* 2357238106Sdes * Convert sockaddr_in6 to sockaddr_in. Original sockaddr_in6 must be 2358238106Sdes * v4 mapped addr or v4 compat addr 2359238106Sdes */ 2360238106Sdesvoid 2361238106Sdesin6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 2362238106Sdes{ 2363238106Sdes bzero(sin, sizeof(*sin)); 2364238106Sdes sin->sin_len = sizeof(struct sockaddr_in); 2365238106Sdes sin->sin_family = AF_INET; 2366238106Sdes sin->sin_port = sin6->sin6_port; 2367238106Sdes sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3]; 2368238106Sdes} 2369238106Sdes 2370238106Sdes/* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */ 2371238106Sdesvoid 2372238106Sdesin6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 2373238106Sdes{ 2374238106Sdes bzero(sin6, sizeof(*sin6)); 2375238106Sdes sin6->sin6_len = sizeof(struct sockaddr_in6); 2376238106Sdes sin6->sin6_family = AF_INET6; 2377238106Sdes sin6->sin6_port = sin->sin_port; 2378238106Sdes sin6->sin6_addr.s6_addr32[0] = 0; 2379238106Sdes sin6->sin6_addr.s6_addr32[1] = 0; 2380238106Sdes sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP; 2381238106Sdes sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; 2382238106Sdes} 2383238106Sdes 2384238106Sdes/* Convert sockaddr_in6 into sockaddr_in. */ 2385238106Sdesvoid 2386238106Sdesin6_sin6_2_sin_in_sock(struct sockaddr *nam) 2387238106Sdes{ 2388238106Sdes struct sockaddr_in *sin_p; 2389238106Sdes struct sockaddr_in6 sin6; 2390238106Sdes 2391238106Sdes /* 2392238106Sdes * Save original sockaddr_in6 addr and convert it 2393238106Sdes * to sockaddr_in. 2394238106Sdes */ 2395238106Sdes sin6 = *(struct sockaddr_in6 *)nam; 2396238106Sdes sin_p = (struct sockaddr_in *)nam; 2397238106Sdes in6_sin6_2_sin(sin_p, &sin6); 2398238106Sdes} 2399238106Sdes 2400238106Sdes/* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */ 2401238106Sdesvoid 2402238106Sdesin6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam) 2403238106Sdes{ 2404249141Sdes struct sockaddr_in *sin_p; 2405249141Sdes struct sockaddr_in6 *sin6_p; 2406285206Sdes 2407285206Sdes MALLOC(sin6_p, struct sockaddr_in6 *, sizeof *sin6_p, M_SONAME, 2408238106Sdes M_WAITOK); 2409238106Sdes sin_p = (struct sockaddr_in *)*nam; 2410238106Sdes in6_sin_2_v4mapsin6(sin_p, sin6_p); 2411238106Sdes FREE(*nam, M_SONAME); 2412238106Sdes *nam = (struct sockaddr *)sin6_p; 2413238106Sdes} 2414238106Sdes