Annotation of sys/netinet6/in6.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: in6.c,v 1.72 2006/11/17 01:11:23 itojun Exp $ */
! 2: /* $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun Exp $ */
! 3:
! 4: /*
! 5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the project nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: */
! 32:
! 33: /*
! 34: * Copyright (c) 1982, 1986, 1991, 1993
! 35: * The Regents of the University of California. All rights reserved.
! 36: *
! 37: * Redistribution and use in source and binary forms, with or without
! 38: * modification, are permitted provided that the following conditions
! 39: * are met:
! 40: * 1. Redistributions of source code must retain the above copyright
! 41: * notice, this list of conditions and the following disclaimer.
! 42: * 2. Redistributions in binary form must reproduce the above copyright
! 43: * notice, this list of conditions and the following disclaimer in the
! 44: * documentation and/or other materials provided with the distribution.
! 45: * 3. Neither the name of the University nor the names of its contributors
! 46: * may be used to endorse or promote products derived from this software
! 47: * without specific prior written permission.
! 48: *
! 49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 59: * SUCH DAMAGE.
! 60: *
! 61: * @(#)in.c 8.2 (Berkeley) 11/15/93
! 62: */
! 63:
! 64: #include <sys/param.h>
! 65: #include <sys/ioctl.h>
! 66: #include <sys/errno.h>
! 67: #include <sys/malloc.h>
! 68: #include <sys/socket.h>
! 69: #include <sys/socketvar.h>
! 70: #include <sys/sockio.h>
! 71: #include <sys/systm.h>
! 72: #include <sys/proc.h>
! 73: #include <sys/time.h>
! 74: #include <sys/kernel.h>
! 75: #include <sys/syslog.h>
! 76:
! 77: #include <net/if.h>
! 78: #include <net/if_types.h>
! 79: #include <net/route.h>
! 80: #include <net/if_dl.h>
! 81:
! 82: #include <netinet/in.h>
! 83: #include <netinet/in_var.h>
! 84: #include <netinet/if_ether.h>
! 85:
! 86: #include <netinet/ip6.h>
! 87: #include <netinet6/ip6_var.h>
! 88: #include <netinet6/nd6.h>
! 89: #include <netinet6/mld6_var.h>
! 90: #ifdef MROUTING
! 91: #include <netinet6/ip6_mroute.h>
! 92: #endif
! 93: #include <netinet6/in6_ifattach.h>
! 94:
! 95: /* backward compatibility for a while... */
! 96: #define COMPAT_IN6IFIOCTL
! 97:
! 98: /*
! 99: * Definitions of some constant IP6 addresses.
! 100: */
! 101: const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
! 102: const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
! 103: const struct in6_addr in6addr_intfacelocal_allnodes =
! 104: IN6ADDR_INTFACELOCAL_ALLNODES_INIT;
! 105: const struct in6_addr in6addr_linklocal_allnodes =
! 106: IN6ADDR_LINKLOCAL_ALLNODES_INIT;
! 107: const struct in6_addr in6addr_linklocal_allrouters =
! 108: IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
! 109:
! 110: const struct in6_addr in6mask0 = IN6MASK0;
! 111: const struct in6_addr in6mask32 = IN6MASK32;
! 112: const struct in6_addr in6mask64 = IN6MASK64;
! 113: const struct in6_addr in6mask96 = IN6MASK96;
! 114: const struct in6_addr in6mask128 = IN6MASK128;
! 115:
! 116: static int in6_lifaddr_ioctl(struct socket *, u_long, caddr_t,
! 117: struct ifnet *, struct proc *);
! 118: static int in6_ifinit(struct ifnet *, struct in6_ifaddr *,
! 119: struct sockaddr_in6 *, int);
! 120: static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
! 121:
! 122: const struct sockaddr_in6 sa6_any = {sizeof(sa6_any), AF_INET6,
! 123: 0, 0, IN6ADDR_ANY_INIT, 0};
! 124:
! 125: /*
! 126: * This structure is used to keep track of in6_multi chains which belong to
! 127: * deleted interface addresses.
! 128: */
! 129: static LIST_HEAD(, multi6_kludge) in6_mk; /* XXX BSS initialization */
! 130:
! 131: struct multi6_kludge {
! 132: LIST_ENTRY(multi6_kludge) mk_entry;
! 133: struct ifnet *mk_ifp;
! 134: struct in6_multihead mk_head;
! 135: };
! 136:
! 137: /*
! 138: * Subroutine for in6_ifaddloop() and in6_ifremloop().
! 139: * This routine does actual work.
! 140: */
! 141: static void
! 142: in6_ifloop_request(int cmd, struct ifaddr *ifa)
! 143: {
! 144: struct sockaddr_in6 lo_sa;
! 145: struct sockaddr_in6 all1_sa;
! 146: struct rtentry *nrt = NULL;
! 147: int e;
! 148:
! 149: bzero(&lo_sa, sizeof(lo_sa));
! 150: bzero(&all1_sa, sizeof(all1_sa));
! 151: lo_sa.sin6_family = all1_sa.sin6_family = AF_INET6;
! 152: lo_sa.sin6_len = all1_sa.sin6_len = sizeof(struct sockaddr_in6);
! 153: lo_sa.sin6_addr = in6addr_loopback;
! 154: all1_sa.sin6_addr = in6mask128;
! 155:
! 156: /*
! 157: * We specify the address itself as the gateway, and set the
! 158: * RTF_LLINFO flag, so that the corresponding host route would have
! 159: * the flag, and thus applications that assume traditional behavior
! 160: * would be happy. Note that we assume the caller of the function
! 161: * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest,
! 162: * which changes the outgoing interface to the loopback interface.
! 163: * XXX only table 0 for now
! 164: */
! 165: e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr,
! 166: (struct sockaddr *)&all1_sa, RTF_UP|RTF_HOST|RTF_LLINFO, &nrt, 0);
! 167: if (e != 0) {
! 168: log(LOG_ERR, "in6_ifloop_request: "
! 169: "%s operation failed for %s (errno=%d)\n",
! 170: cmd == RTM_ADD ? "ADD" : "DELETE",
! 171: ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr),
! 172: e);
! 173: }
! 174:
! 175: /*
! 176: * Make sure rt_ifa be equal to IFA, the second argument of the
! 177: * function.
! 178: * We need this because when we refer to rt_ifa->ia6_flags in
! 179: * ip6_input, we assume that the rt_ifa points to the address instead
! 180: * of the loopback address.
! 181: */
! 182: if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) {
! 183: IFAFREE(nrt->rt_ifa);
! 184: ifa->ifa_refcnt++;
! 185: nrt->rt_ifa = ifa;
! 186: }
! 187:
! 188: /*
! 189: * Report the addition/removal of the address to the routing socket.
! 190: * XXX: since we called rtinit for a p2p interface with a destination,
! 191: * we end up reporting twice in such a case. Should we rather
! 192: * omit the second report?
! 193: */
! 194: if (nrt) {
! 195: rt_newaddrmsg(cmd, ifa, e, nrt);
! 196: if (cmd == RTM_DELETE) {
! 197: if (nrt->rt_refcnt <= 0) {
! 198: /* XXX: we should free the entry ourselves. */
! 199: nrt->rt_refcnt++;
! 200: rtfree(nrt);
! 201: }
! 202: } else {
! 203: /* the cmd must be RTM_ADD here */
! 204: nrt->rt_refcnt--;
! 205: }
! 206: }
! 207: }
! 208:
! 209: /*
! 210: * Add ownaddr as loopback rtentry. We previously add the route only if
! 211: * necessary (ex. on a p2p link). However, since we now manage addresses
! 212: * separately from prefixes, we should always add the route. We can't
! 213: * rely on the cloning mechanism from the corresponding interface route
! 214: * any more.
! 215: */
! 216: void
! 217: in6_ifaddloop(struct ifaddr *ifa)
! 218: {
! 219: struct rtentry *rt;
! 220:
! 221: /* If there is no loopback entry, allocate one. */
! 222: rt = rtalloc1(ifa->ifa_addr, 0, 0);
! 223: if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
! 224: (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
! 225: in6_ifloop_request(RTM_ADD, ifa);
! 226: if (rt)
! 227: rt->rt_refcnt--;
! 228: }
! 229:
! 230: /*
! 231: * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
! 232: * if it exists.
! 233: */
! 234: void
! 235: in6_ifremloop(struct ifaddr *ifa)
! 236: {
! 237: struct in6_ifaddr *ia;
! 238: struct rtentry *rt;
! 239: int ia_count = 0;
! 240:
! 241: /*
! 242: * Some of BSD variants do not remove cloned routes
! 243: * from an interface direct route, when removing the direct route
! 244: * (see comments in net/net_osdep.h). Even for variants that do remove
! 245: * cloned routes, they could fail to remove the cloned routes when
! 246: * we handle multple addresses that share a common prefix.
! 247: * So, we should remove the route corresponding to the deleted address.
! 248: */
! 249:
! 250: /*
! 251: * Delete the entry only if exact one ifa exists. More than one ifa
! 252: * can exist if we assign a same single address to multiple
! 253: * (probably p2p) interfaces.
! 254: * XXX: we should avoid such a configuration in IPv6...
! 255: */
! 256: for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
! 257: if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) {
! 258: ia_count++;
! 259: if (ia_count > 1)
! 260: break;
! 261: }
! 262: }
! 263:
! 264: if (ia_count == 1) {
! 265: /*
! 266: * Before deleting, check if a corresponding loopbacked host
! 267: * route surely exists. With this check, we can avoid to
! 268: * delete an interface direct route whose destination is same
! 269: * as the address being removed. This can happen when removing
! 270: * a subnet-router anycast address on an interface attahced
! 271: * to a shared medium.
! 272: */
! 273: rt = rtalloc1(ifa->ifa_addr, 0, 0);
! 274: if (rt != NULL && (rt->rt_flags & RTF_HOST) != 0 &&
! 275: (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
! 276: rt->rt_refcnt--;
! 277: in6_ifloop_request(RTM_DELETE, ifa);
! 278: }
! 279: }
! 280: }
! 281:
! 282: int
! 283: in6_mask2len(mask, lim0)
! 284: struct in6_addr *mask;
! 285: u_char *lim0;
! 286: {
! 287: int x = 0, y;
! 288: u_char *lim = lim0, *p;
! 289:
! 290: /* ignore the scope_id part */
! 291: if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask))
! 292: lim = (u_char *)mask + sizeof(*mask);
! 293: for (p = (u_char *)mask; p < lim; x++, p++) {
! 294: if (*p != 0xff)
! 295: break;
! 296: }
! 297: y = 0;
! 298: if (p < lim) {
! 299: for (y = 0; y < 8; y++) {
! 300: if ((*p & (0x80 >> y)) == 0)
! 301: break;
! 302: }
! 303: }
! 304:
! 305: /*
! 306: * when the limit pointer is given, do a stricter check on the
! 307: * remaining bits.
! 308: */
! 309: if (p < lim) {
! 310: if (y != 0 && (*p & (0x00ff >> y)) != 0)
! 311: return (-1);
! 312: for (p = p + 1; p < lim; p++)
! 313: if (*p != 0)
! 314: return (-1);
! 315: }
! 316:
! 317: return x * 8 + y;
! 318: }
! 319:
! 320: #define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa))
! 321: #define ia62ifa(ia6) (&((ia6)->ia_ifa))
! 322:
! 323: int
! 324: in6_control(so, cmd, data, ifp, p)
! 325: struct socket *so;
! 326: u_long cmd;
! 327: caddr_t data;
! 328: struct ifnet *ifp;
! 329: struct proc *p;
! 330: {
! 331: struct in6_ifreq *ifr = (struct in6_ifreq *)data;
! 332: struct in6_ifaddr *ia = NULL;
! 333: struct in6_aliasreq *ifra = (struct in6_aliasreq *)data;
! 334: struct sockaddr_in6 *sa6;
! 335: int privileged;
! 336:
! 337: privileged = 0;
! 338: if ((so->so_state & SS_PRIV) != 0)
! 339: privileged++;
! 340:
! 341: #ifdef MROUTING
! 342: switch (cmd) {
! 343: case SIOCGETSGCNT_IN6:
! 344: case SIOCGETMIFCNT_IN6:
! 345: return (mrt6_ioctl(cmd, data));
! 346: }
! 347: #endif
! 348:
! 349: if (ifp == NULL)
! 350: return (EOPNOTSUPP);
! 351:
! 352: switch (cmd) {
! 353: case SIOCSNDFLUSH_IN6:
! 354: case SIOCSPFXFLUSH_IN6:
! 355: case SIOCSRTRFLUSH_IN6:
! 356: case SIOCSDEFIFACE_IN6:
! 357: case SIOCSIFINFO_FLAGS:
! 358: if (!privileged)
! 359: return (EPERM);
! 360: /* FALLTHROUGH */
! 361: case OSIOCGIFINFO_IN6:
! 362: case SIOCGIFINFO_IN6:
! 363: case SIOCGDRLST_IN6:
! 364: case SIOCGPRLST_IN6:
! 365: case SIOCGNBRINFO_IN6:
! 366: case SIOCGDEFIFACE_IN6:
! 367: return (nd6_ioctl(cmd, data, ifp));
! 368: }
! 369:
! 370: switch (cmd) {
! 371: case SIOCSIFPREFIX_IN6:
! 372: case SIOCDIFPREFIX_IN6:
! 373: case SIOCAIFPREFIX_IN6:
! 374: case SIOCCIFPREFIX_IN6:
! 375: case SIOCSGIFPREFIX_IN6:
! 376: case SIOCGIFPREFIX_IN6:
! 377: log(LOG_NOTICE,
! 378: "prefix ioctls are now invalidated. "
! 379: "please use ifconfig.\n");
! 380: return (EOPNOTSUPP);
! 381: }
! 382:
! 383: switch (cmd) {
! 384: case SIOCALIFADDR:
! 385: case SIOCDLIFADDR:
! 386: if (!privileged)
! 387: return (EPERM);
! 388: /* FALLTHROUGH */
! 389: case SIOCGLIFADDR:
! 390: return in6_lifaddr_ioctl(so, cmd, data, ifp, p);
! 391: }
! 392:
! 393: /*
! 394: * Find address for this interface, if it exists.
! 395: *
! 396: * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation
! 397: * only, and used the first interface address as the target of other
! 398: * operations (without checking ifra_addr). This was because netinet
! 399: * code/API assumed at most 1 interface address per interface.
! 400: * Since IPv6 allows a node to assign multiple addresses
! 401: * on a single interface, we almost always look and check the
! 402: * presence of ifra_addr, and reject invalid ones here.
! 403: * It also decreases duplicated code among SIOC*_IN6 operations.
! 404: */
! 405: switch (cmd) {
! 406: case SIOCAIFADDR_IN6:
! 407: case SIOCSIFPHYADDR_IN6:
! 408: sa6 = &ifra->ifra_addr;
! 409: break;
! 410: case SIOCSIFADDR_IN6:
! 411: case SIOCGIFADDR_IN6:
! 412: case SIOCSIFDSTADDR_IN6:
! 413: case SIOCSIFNETMASK_IN6:
! 414: case SIOCGIFDSTADDR_IN6:
! 415: case SIOCGIFNETMASK_IN6:
! 416: case SIOCDIFADDR_IN6:
! 417: case SIOCGIFPSRCADDR_IN6:
! 418: case SIOCGIFPDSTADDR_IN6:
! 419: case SIOCGIFAFLAG_IN6:
! 420: case SIOCSNDFLUSH_IN6:
! 421: case SIOCSPFXFLUSH_IN6:
! 422: case SIOCSRTRFLUSH_IN6:
! 423: case SIOCGIFALIFETIME_IN6:
! 424: case SIOCSIFALIFETIME_IN6:
! 425: case SIOCGIFSTAT_IN6:
! 426: case SIOCGIFSTAT_ICMP6:
! 427: sa6 = &ifr->ifr_addr;
! 428: break;
! 429: default:
! 430: sa6 = NULL;
! 431: break;
! 432: }
! 433: if (sa6 && sa6->sin6_family == AF_INET6) {
! 434: if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
! 435: if (sa6->sin6_addr.s6_addr16[1] == 0) {
! 436: /* link ID is not embedded by the user */
! 437: sa6->sin6_addr.s6_addr16[1] =
! 438: htons(ifp->if_index);
! 439: } else if (sa6->sin6_addr.s6_addr16[1] !=
! 440: htons(ifp->if_index)) {
! 441: return (EINVAL); /* link ID contradicts */
! 442: }
! 443: if (sa6->sin6_scope_id) {
! 444: if (sa6->sin6_scope_id !=
! 445: (u_int32_t)ifp->if_index)
! 446: return (EINVAL);
! 447: sa6->sin6_scope_id = 0; /* XXX: good way? */
! 448: }
! 449: }
! 450: ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
! 451: } else
! 452: ia = NULL;
! 453:
! 454: switch (cmd) {
! 455: case SIOCSIFADDR_IN6:
! 456: case SIOCSIFDSTADDR_IN6:
! 457: case SIOCSIFNETMASK_IN6:
! 458: /*
! 459: * Since IPv6 allows a node to assign multiple addresses
! 460: * on a single interface, SIOCSIFxxx ioctls are deprecated.
! 461: */
! 462: return (EINVAL);
! 463:
! 464: case SIOCDIFADDR_IN6:
! 465: /*
! 466: * for IPv4, we look for existing in_ifaddr here to allow
! 467: * "ifconfig if0 delete" to remove the first IPv4 address on
! 468: * the interface. For IPv6, as the spec allows multiple
! 469: * interface address from the day one, we consider "remove the
! 470: * first one" semantics to be not preferable.
! 471: */
! 472: if (ia == NULL)
! 473: return (EADDRNOTAVAIL);
! 474: /* FALLTHROUGH */
! 475: case SIOCAIFADDR_IN6:
! 476: /*
! 477: * We always require users to specify a valid IPv6 address for
! 478: * the corresponding operation.
! 479: */
! 480: if (ifra->ifra_addr.sin6_family != AF_INET6 ||
! 481: ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6))
! 482: return (EAFNOSUPPORT);
! 483: if (!privileged)
! 484: return (EPERM);
! 485:
! 486: break;
! 487:
! 488: case SIOCGIFADDR_IN6:
! 489: /* This interface is basically deprecated. use SIOCGIFCONF. */
! 490: /* FALLTHROUGH */
! 491: case SIOCGIFAFLAG_IN6:
! 492: case SIOCGIFNETMASK_IN6:
! 493: case SIOCGIFDSTADDR_IN6:
! 494: case SIOCGIFALIFETIME_IN6:
! 495: /* must think again about its semantics */
! 496: if (ia == NULL)
! 497: return (EADDRNOTAVAIL);
! 498: break;
! 499: case SIOCSIFALIFETIME_IN6:
! 500: {
! 501: struct in6_addrlifetime *lt;
! 502:
! 503: if (!privileged)
! 504: return (EPERM);
! 505: if (ia == NULL)
! 506: return (EADDRNOTAVAIL);
! 507: /* sanity for overflow - beware unsigned */
! 508: lt = &ifr->ifr_ifru.ifru_lifetime;
! 509: if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
! 510: && lt->ia6t_vltime + time_second < time_second) {
! 511: return EINVAL;
! 512: }
! 513: if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
! 514: && lt->ia6t_pltime + time_second < time_second) {
! 515: return EINVAL;
! 516: }
! 517: break;
! 518: }
! 519: }
! 520:
! 521: switch (cmd) {
! 522:
! 523: case SIOCGIFADDR_IN6:
! 524: ifr->ifr_addr = ia->ia_addr;
! 525: break;
! 526:
! 527: case SIOCGIFDSTADDR_IN6:
! 528: if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
! 529: return (EINVAL);
! 530: /*
! 531: * XXX: should we check if ifa_dstaddr is NULL and return
! 532: * an error?
! 533: */
! 534: ifr->ifr_dstaddr = ia->ia_dstaddr;
! 535: break;
! 536:
! 537: case SIOCGIFNETMASK_IN6:
! 538: ifr->ifr_addr = ia->ia_prefixmask;
! 539: break;
! 540:
! 541: case SIOCGIFAFLAG_IN6:
! 542: ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags;
! 543: break;
! 544:
! 545: case SIOCGIFSTAT_IN6:
! 546: if (ifp == NULL)
! 547: return EINVAL;
! 548: bzero(&ifr->ifr_ifru.ifru_stat,
! 549: sizeof(ifr->ifr_ifru.ifru_stat));
! 550: ifr->ifr_ifru.ifru_stat =
! 551: *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat;
! 552: break;
! 553:
! 554: case SIOCGIFSTAT_ICMP6:
! 555: if (ifp == NULL)
! 556: return EINVAL;
! 557: bzero(&ifr->ifr_ifru.ifru_icmp6stat,
! 558: sizeof(ifr->ifr_ifru.ifru_icmp6stat));
! 559: ifr->ifr_ifru.ifru_icmp6stat =
! 560: *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat;
! 561: break;
! 562:
! 563: case SIOCGIFALIFETIME_IN6:
! 564: ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
! 565: if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
! 566: time_t maxexpire;
! 567: struct in6_addrlifetime *retlt =
! 568: &ifr->ifr_ifru.ifru_lifetime;
! 569:
! 570: /*
! 571: * XXX: adjust expiration time assuming time_t is
! 572: * signed.
! 573: */
! 574: maxexpire = (-1) &
! 575: ~(1 << ((sizeof(maxexpire) * 8) - 1));
! 576: if (ia->ia6_lifetime.ia6t_vltime <
! 577: maxexpire - ia->ia6_updatetime) {
! 578: retlt->ia6t_expire = ia->ia6_updatetime +
! 579: ia->ia6_lifetime.ia6t_vltime;
! 580: } else
! 581: retlt->ia6t_expire = maxexpire;
! 582: }
! 583: if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
! 584: time_t maxexpire;
! 585: struct in6_addrlifetime *retlt =
! 586: &ifr->ifr_ifru.ifru_lifetime;
! 587:
! 588: /*
! 589: * XXX: adjust expiration time assuming time_t is
! 590: * signed.
! 591: */
! 592: maxexpire = (-1) &
! 593: ~(1 << ((sizeof(maxexpire) * 8) - 1));
! 594: if (ia->ia6_lifetime.ia6t_pltime <
! 595: maxexpire - ia->ia6_updatetime) {
! 596: retlt->ia6t_preferred = ia->ia6_updatetime +
! 597: ia->ia6_lifetime.ia6t_pltime;
! 598: } else
! 599: retlt->ia6t_preferred = maxexpire;
! 600: }
! 601: break;
! 602:
! 603: case SIOCSIFALIFETIME_IN6:
! 604: ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime;
! 605: /* for sanity */
! 606: if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
! 607: ia->ia6_lifetime.ia6t_expire =
! 608: time_second + ia->ia6_lifetime.ia6t_vltime;
! 609: } else
! 610: ia->ia6_lifetime.ia6t_expire = 0;
! 611: if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
! 612: ia->ia6_lifetime.ia6t_preferred =
! 613: time_second + ia->ia6_lifetime.ia6t_pltime;
! 614: } else
! 615: ia->ia6_lifetime.ia6t_preferred = 0;
! 616: break;
! 617:
! 618: case SIOCAIFADDR_IN6:
! 619: {
! 620: int i, error = 0;
! 621: struct nd_prefix pr0, *pr;
! 622:
! 623: /* reject read-only flags */
! 624: if ((ifra->ifra_flags & IN6_IFF_DUPLICATED) != 0 ||
! 625: (ifra->ifra_flags & IN6_IFF_DETACHED) != 0 ||
! 626: (ifra->ifra_flags & IN6_IFF_NODAD) != 0 ||
! 627: (ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0) {
! 628: return (EINVAL);
! 629: }
! 630: /*
! 631: * first, make or update the interface address structure,
! 632: * and link it to the list.
! 633: */
! 634: if ((error = in6_update_ifa(ifp, ifra, ia)) != 0)
! 635: return (error);
! 636: if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
! 637: == NULL) {
! 638: /*
! 639: * this can happen when the user specify the 0 valid
! 640: * lifetime.
! 641: */
! 642: break;
! 643: }
! 644:
! 645: /*
! 646: * then, make the prefix on-link on the interface.
! 647: * XXX: we'd rather create the prefix before the address, but
! 648: * we need at least one address to install the corresponding
! 649: * interface route, so we configure the address first.
! 650: */
! 651:
! 652: /*
! 653: * convert mask to prefix length (prefixmask has already
! 654: * been validated in in6_update_ifa().
! 655: */
! 656: bzero(&pr0, sizeof(pr0));
! 657: pr0.ndpr_ifp = ifp;
! 658: pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
! 659: NULL);
! 660: if (pr0.ndpr_plen == 128) {
! 661: break; /* we don't need to install a host route. */
! 662: }
! 663: pr0.ndpr_prefix = ifra->ifra_addr;
! 664: pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr;
! 665: /* apply the mask for safety. */
! 666: for (i = 0; i < 4; i++) {
! 667: pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
! 668: ifra->ifra_prefixmask.sin6_addr.s6_addr32[i];
! 669: }
! 670: /*
! 671: * XXX: since we don't have an API to set prefix (not address)
! 672: * lifetimes, we just use the same lifetimes as addresses.
! 673: * The (temporarily) installed lifetimes can be overridden by
! 674: * later advertised RAs (when accept_rtadv is non 0), which is
! 675: * an intended behavior.
! 676: */
! 677: pr0.ndpr_raf_onlink = 1; /* should be configurable? */
! 678: pr0.ndpr_raf_auto =
! 679: ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0);
! 680: pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime;
! 681: pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime;
! 682:
! 683: /* add the prefix if not yet. */
! 684: if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
! 685: /*
! 686: * nd6_prelist_add will install the corresponding
! 687: * interface route.
! 688: */
! 689: if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0)
! 690: return (error);
! 691: if (pr == NULL) {
! 692: log(LOG_ERR, "nd6_prelist_add succeeded but "
! 693: "no prefix\n");
! 694: return (EINVAL); /* XXX panic here? */
! 695: }
! 696: }
! 697:
! 698: /* relate the address to the prefix */
! 699: if (ia->ia6_ndpr == NULL) {
! 700: ia->ia6_ndpr = pr;
! 701: pr->ndpr_refcnt++;
! 702: }
! 703:
! 704: /*
! 705: * this might affect the status of autoconfigured addresses,
! 706: * that is, this address might make other addresses detached.
! 707: */
! 708: pfxlist_onlink_check();
! 709:
! 710: dohooks(ifp->if_addrhooks, 0);
! 711: break;
! 712: }
! 713:
! 714: case SIOCDIFADDR_IN6:
! 715: {
! 716: int i = 0, purgeprefix = 0;
! 717: struct nd_prefix pr0, *pr = NULL;
! 718:
! 719: /*
! 720: * If the address being deleted is the only one that owns
! 721: * the corresponding prefix, expire the prefix as well.
! 722: * XXX: theoretically, we don't have to worry about such
! 723: * relationship, since we separate the address management
! 724: * and the prefix management. We do this, however, to provide
! 725: * as much backward compatibility as possible in terms of
! 726: * the ioctl operation.
! 727: */
! 728: bzero(&pr0, sizeof(pr0));
! 729: pr0.ndpr_ifp = ifp;
! 730: pr0.ndpr_plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr,
! 731: NULL);
! 732: if (pr0.ndpr_plen == 128)
! 733: goto purgeaddr;
! 734: pr0.ndpr_prefix = ia->ia_addr;
! 735: pr0.ndpr_mask = ia->ia_prefixmask.sin6_addr;
! 736: for (i = 0; i < 4; i++) {
! 737: pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
! 738: ia->ia_prefixmask.sin6_addr.s6_addr32[i];
! 739: }
! 740: if ((pr = nd6_prefix_lookup(&pr0)) != NULL &&
! 741: pr == ia->ia6_ndpr) {
! 742: pr->ndpr_refcnt--;
! 743: if (pr->ndpr_refcnt == 0)
! 744: purgeprefix = 1;
! 745: }
! 746:
! 747: purgeaddr:
! 748: in6_purgeaddr(&ia->ia_ifa);
! 749: if (pr && purgeprefix)
! 750: prelist_remove(pr);
! 751: dohooks(ifp->if_addrhooks, 0);
! 752: break;
! 753: }
! 754:
! 755: default:
! 756: if (ifp == NULL || ifp->if_ioctl == 0)
! 757: return (EOPNOTSUPP);
! 758: return ((*ifp->if_ioctl)(ifp, cmd, data));
! 759: }
! 760:
! 761: return (0);
! 762: }
! 763:
! 764: /*
! 765: * Update parameters of an IPv6 interface address.
! 766: * If necessary, a new entry is created and linked into address chains.
! 767: * This function is separated from in6_control().
! 768: * XXX: should this be performed under splnet()?
! 769: */
! 770: int
! 771: in6_update_ifa(ifp, ifra, ia)
! 772: struct ifnet *ifp;
! 773: struct in6_aliasreq *ifra;
! 774: struct in6_ifaddr *ia;
! 775: {
! 776: int error = 0, hostIsNew = 0, plen = -1;
! 777: struct in6_ifaddr *oia;
! 778: struct sockaddr_in6 dst6;
! 779: struct in6_addrlifetime *lt;
! 780: struct in6_multi_mship *imm;
! 781: struct rtentry *rt;
! 782:
! 783: /* Validate parameters */
! 784: if (ifp == NULL || ifra == NULL) /* this maybe redundant */
! 785: return (EINVAL);
! 786:
! 787: /*
! 788: * The destination address for a p2p link must have a family
! 789: * of AF_UNSPEC or AF_INET6.
! 790: */
! 791: if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
! 792: ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
! 793: ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
! 794: return (EAFNOSUPPORT);
! 795: /*
! 796: * validate ifra_prefixmask. don't check sin6_family, netmask
! 797: * does not carry fields other than sin6_len.
! 798: */
! 799: if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6))
! 800: return (EINVAL);
! 801: /*
! 802: * Because the IPv6 address architecture is classless, we require
! 803: * users to specify a (non 0) prefix length (mask) for a new address.
! 804: * We also require the prefix (when specified) mask is valid, and thus
! 805: * reject a non-consecutive mask.
! 806: */
! 807: if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0)
! 808: return (EINVAL);
! 809: if (ifra->ifra_prefixmask.sin6_len != 0) {
! 810: plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
! 811: (u_char *)&ifra->ifra_prefixmask +
! 812: ifra->ifra_prefixmask.sin6_len);
! 813: if (plen <= 0)
! 814: return (EINVAL);
! 815: } else {
! 816: /*
! 817: * In this case, ia must not be NULL. We just use its prefix
! 818: * length.
! 819: */
! 820: plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
! 821: }
! 822: /*
! 823: * If the destination address on a p2p interface is specified,
! 824: * and the address is a scoped one, validate/set the scope
! 825: * zone identifier.
! 826: */
! 827: dst6 = ifra->ifra_dstaddr;
! 828: if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 &&
! 829: (dst6.sin6_family == AF_INET6)) {
! 830: /* link-local index check: should be a separate function? */
! 831: if (IN6_IS_ADDR_LINKLOCAL(&dst6.sin6_addr)) {
! 832: if (dst6.sin6_addr.s6_addr16[1] == 0) {
! 833: /*
! 834: * interface ID is not embedded by
! 835: * the user
! 836: */
! 837: dst6.sin6_addr.s6_addr16[1] =
! 838: htons(ifp->if_index);
! 839: } else if (dst6.sin6_addr.s6_addr16[1] !=
! 840: htons(ifp->if_index)) {
! 841: return (EINVAL); /* ifid contradicts */
! 842: }
! 843: }
! 844: }
! 845: /*
! 846: * The destination address can be specified only for a p2p or a
! 847: * loopback interface. If specified, the corresponding prefix length
! 848: * must be 128.
! 849: */
! 850: if (ifra->ifra_dstaddr.sin6_family == AF_INET6) {
! 851: #ifdef FORCE_P2PPLEN
! 852: int i;
! 853: #endif
! 854:
! 855: if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) {
! 856: /* XXX: noisy message */
! 857: nd6log((LOG_INFO, "in6_update_ifa: a destination can "
! 858: "be specified for a p2p or a loopback IF only\n"));
! 859: return (EINVAL);
! 860: }
! 861: if (plen != 128) {
! 862: nd6log((LOG_INFO, "in6_update_ifa: prefixlen should "
! 863: "be 128 when dstaddr is specified\n"));
! 864: #ifdef FORCE_P2PPLEN
! 865: /*
! 866: * To be compatible with old configurations,
! 867: * such as ifconfig gif0 inet6 2001::1 2001::2
! 868: * prefixlen 126, we override the specified
! 869: * prefixmask as if the prefix length was 128.
! 870: */
! 871: ifra->ifra_prefixmask.sin6_len =
! 872: sizeof(struct sockaddr_in6);
! 873: for (i = 0; i < 4; i++)
! 874: ifra->ifra_prefixmask.sin6_addr.s6_addr32[i] =
! 875: 0xffffffff;
! 876: plen = 128;
! 877: #else
! 878: return (EINVAL);
! 879: #endif
! 880: }
! 881: }
! 882: /* lifetime consistency check */
! 883: lt = &ifra->ifra_lifetime;
! 884: if (lt->ia6t_pltime > lt->ia6t_vltime)
! 885: return (EINVAL);
! 886: if (lt->ia6t_vltime == 0) {
! 887: /*
! 888: * the following log might be noisy, but this is a typical
! 889: * configuration mistake or a tool's bug.
! 890: */
! 891: nd6log((LOG_INFO,
! 892: "in6_update_ifa: valid lifetime is 0 for %s\n",
! 893: ip6_sprintf(&ifra->ifra_addr.sin6_addr)));
! 894:
! 895: if (ia == NULL)
! 896: return (0); /* there's nothing to do */
! 897: }
! 898:
! 899: /*
! 900: * If this is a new address, allocate a new ifaddr and link it
! 901: * into chains.
! 902: */
! 903: if (ia == NULL) {
! 904: hostIsNew = 1;
! 905: /*
! 906: * When in6_update_ifa() is called in a process of a received
! 907: * RA, it is called under an interrupt context. So, we should
! 908: * call malloc with M_NOWAIT.
! 909: */
! 910: ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR,
! 911: M_NOWAIT);
! 912: if (ia == NULL)
! 913: return (ENOBUFS);
! 914: bzero((caddr_t)ia, sizeof(*ia));
! 915: LIST_INIT(&ia->ia6_memberships);
! 916: /* Initialize the address and masks, and put time stamp */
! 917: ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
! 918: ia->ia_addr.sin6_family = AF_INET6;
! 919: ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
! 920: ia->ia6_createtime = ia->ia6_updatetime = time_second;
! 921: if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) {
! 922: /*
! 923: * XXX: some functions expect that ifa_dstaddr is not
! 924: * NULL for p2p interfaces.
! 925: */
! 926: ia->ia_ifa.ifa_dstaddr =
! 927: (struct sockaddr *)&ia->ia_dstaddr;
! 928: } else {
! 929: ia->ia_ifa.ifa_dstaddr = NULL;
! 930: }
! 931: ia->ia_ifa.ifa_netmask =
! 932: (struct sockaddr *)&ia->ia_prefixmask;
! 933:
! 934: ia->ia_ifp = ifp;
! 935: if ((oia = in6_ifaddr) != NULL) {
! 936: for ( ; oia->ia_next; oia = oia->ia_next)
! 937: continue;
! 938: oia->ia_next = ia;
! 939: } else
! 940: in6_ifaddr = ia;
! 941: TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa,
! 942: ifa_list);
! 943: }
! 944:
! 945: /* set prefix mask */
! 946: if (ifra->ifra_prefixmask.sin6_len) {
! 947: /*
! 948: * We prohibit changing the prefix length of an existing
! 949: * address, because
! 950: * + such an operation should be rare in IPv6, and
! 951: * + the operation would confuse prefix management.
! 952: */
! 953: if (ia->ia_prefixmask.sin6_len &&
! 954: in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) {
! 955: nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an"
! 956: " existing (%s) address should not be changed\n",
! 957: ip6_sprintf(&ia->ia_addr.sin6_addr)));
! 958: error = EINVAL;
! 959: goto unlink;
! 960: }
! 961: ia->ia_prefixmask = ifra->ifra_prefixmask;
! 962: }
! 963:
! 964: /*
! 965: * If a new destination address is specified, scrub the old one and
! 966: * install the new destination. Note that the interface must be
! 967: * p2p or loopback (see the check above.)
! 968: */
! 969: if (dst6.sin6_family == AF_INET6 &&
! 970: !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) {
! 971: int e;
! 972:
! 973: if ((ia->ia_flags & IFA_ROUTE) != 0 &&
! 974: (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) {
! 975: nd6log((LOG_ERR, "in6_update_ifa: failed to remove "
! 976: "a route to the old destination: %s\n",
! 977: ip6_sprintf(&ia->ia_addr.sin6_addr)));
! 978: /* proceed anyway... */
! 979: } else
! 980: ia->ia_flags &= ~IFA_ROUTE;
! 981: ia->ia_dstaddr = dst6;
! 982: }
! 983:
! 984: /*
! 985: * Set lifetimes. We do not refer to ia6t_expire and ia6t_preferred
! 986: * to see if the address is deprecated or invalidated, but initialize
! 987: * these members for applications.
! 988: */
! 989: ia->ia6_lifetime = ifra->ifra_lifetime;
! 990: if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
! 991: ia->ia6_lifetime.ia6t_expire =
! 992: time_second + ia->ia6_lifetime.ia6t_vltime;
! 993: } else
! 994: ia->ia6_lifetime.ia6t_expire = 0;
! 995: if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
! 996: ia->ia6_lifetime.ia6t_preferred =
! 997: time_second + ia->ia6_lifetime.ia6t_pltime;
! 998: } else
! 999: ia->ia6_lifetime.ia6t_preferred = 0;
! 1000:
! 1001: /* reset the interface and routing table appropriately. */
! 1002: if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0)
! 1003: goto unlink;
! 1004:
! 1005: /*
! 1006: * configure address flags.
! 1007: */
! 1008: ia->ia6_flags = ifra->ifra_flags;
! 1009: /*
! 1010: * backward compatibility - if IN6_IFF_DEPRECATED is set from the
! 1011: * userland, make it deprecated.
! 1012: */
! 1013: if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) {
! 1014: ia->ia6_lifetime.ia6t_pltime = 0;
! 1015: ia->ia6_lifetime.ia6t_preferred = time_second;
! 1016: }
! 1017: /*
! 1018: * Make the address tentative before joining multicast addresses,
! 1019: * so that corresponding MLD responses would not have a tentative
! 1020: * source address.
! 1021: */
! 1022: ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /* safety */
! 1023: if (hostIsNew && in6if_do_dad(ifp))
! 1024: ia->ia6_flags |= IN6_IFF_TENTATIVE;
! 1025:
! 1026: /*
! 1027: * We are done if we have simply modified an existing address.
! 1028: */
! 1029: if (!hostIsNew)
! 1030: return (error);
! 1031:
! 1032: /*
! 1033: * Beyond this point, we should call in6_purgeaddr upon an error,
! 1034: * not just go to unlink.
! 1035: */
! 1036:
! 1037: /* join necessary multiast groups */
! 1038: if ((ifp->if_flags & IFF_MULTICAST) != 0) {
! 1039: struct sockaddr_in6 mltaddr, mltmask;
! 1040:
! 1041: /* join solicited multicast addr for new host id */
! 1042: struct sockaddr_in6 llsol;
! 1043:
! 1044: bzero(&llsol, sizeof(llsol));
! 1045: llsol.sin6_family = AF_INET6;
! 1046: llsol.sin6_len = sizeof(llsol);
! 1047: llsol.sin6_addr.s6_addr16[0] = htons(0xff02);
! 1048: llsol.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
! 1049: llsol.sin6_addr.s6_addr32[1] = 0;
! 1050: llsol.sin6_addr.s6_addr32[2] = htonl(1);
! 1051: llsol.sin6_addr.s6_addr32[3] =
! 1052: ifra->ifra_addr.sin6_addr.s6_addr32[3];
! 1053: llsol.sin6_addr.s6_addr8[12] = 0xff;
! 1054: imm = in6_joingroup(ifp, &llsol.sin6_addr, &error);
! 1055: if (!imm) {
! 1056: nd6log((LOG_ERR, "in6_update_ifa: "
! 1057: "addmulti failed for %s on %s (errno=%d)\n",
! 1058: ip6_sprintf(&llsol.sin6_addr),
! 1059: ifp->if_xname, error));
! 1060: goto cleanup;
! 1061: }
! 1062: LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
! 1063:
! 1064: bzero(&mltmask, sizeof(mltmask));
! 1065: mltmask.sin6_len = sizeof(struct sockaddr_in6);
! 1066: mltmask.sin6_family = AF_INET6;
! 1067: mltmask.sin6_addr = in6mask32;
! 1068:
! 1069: /*
! 1070: * join link-local all-nodes address
! 1071: */
! 1072: bzero(&mltaddr, sizeof(mltaddr));
! 1073: mltaddr.sin6_len = sizeof(struct sockaddr_in6);
! 1074: mltaddr.sin6_family = AF_INET6;
! 1075: mltaddr.sin6_addr = in6addr_linklocal_allnodes;
! 1076: mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
! 1077: mltaddr.sin6_scope_id = 0;
! 1078:
! 1079: /*
! 1080: * XXX: do we really need this automatic routes?
! 1081: * We should probably reconsider this stuff. Most applications
! 1082: * actually do not need the routes, since they usually specify
! 1083: * the outgoing interface.
! 1084: */
! 1085: rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0);
! 1086: if (rt) {
! 1087: /*
! 1088: * 32bit came from "mltmask"
! 1089: */
! 1090: if (memcmp(&mltaddr.sin6_addr,
! 1091: &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
! 1092: 32 / 8)) {
! 1093: RTFREE(rt);
! 1094: rt = NULL;
! 1095: }
! 1096: }
! 1097: if (!rt) {
! 1098: struct rt_addrinfo info;
! 1099:
! 1100: bzero(&info, sizeof(info));
! 1101: info.rti_info[RTAX_DST] = (struct sockaddr *)&mltaddr;
! 1102: info.rti_info[RTAX_GATEWAY] =
! 1103: (struct sockaddr *)&ia->ia_addr;
! 1104: info.rti_info[RTAX_NETMASK] =
! 1105: (struct sockaddr *)&mltmask;
! 1106: info.rti_info[RTAX_IFA] =
! 1107: (struct sockaddr *)&ia->ia_addr;
! 1108: /* XXX: we need RTF_CLONING to fake nd6_rtrequest */
! 1109: info.rti_flags = RTF_UP | RTF_CLONING;
! 1110: error = rtrequest1(RTM_ADD, &info, NULL, 0);
! 1111: if (error)
! 1112: goto cleanup;
! 1113: } else {
! 1114: RTFREE(rt);
! 1115: }
! 1116: imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);
! 1117: if (!imm) {
! 1118: nd6log((LOG_WARNING,
! 1119: "in6_update_ifa: addmulti failed for "
! 1120: "%s on %s (errno=%d)\n",
! 1121: ip6_sprintf(&mltaddr.sin6_addr),
! 1122: ifp->if_xname, error));
! 1123: goto cleanup;
! 1124: }
! 1125: LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
! 1126:
! 1127: /*
! 1128: * join node information group address
! 1129: */
! 1130: if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr) == 0) {
! 1131: imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);
! 1132: if (!imm) {
! 1133: nd6log((LOG_WARNING, "in6_update_ifa: "
! 1134: "addmulti failed for %s on %s (errno=%d)\n",
! 1135: ip6_sprintf(&mltaddr.sin6_addr),
! 1136: ifp->if_xname, error));
! 1137: /* XXX not very fatal, go on... */
! 1138: } else {
! 1139: LIST_INSERT_HEAD(&ia->ia6_memberships,
! 1140: imm, i6mm_chain);
! 1141: }
! 1142: }
! 1143:
! 1144: /*
! 1145: * join interface-local all-nodes address.
! 1146: * (ff01::1%ifN, and ff01::%ifN/32)
! 1147: */
! 1148: bzero(&mltaddr.sin6_addr, sizeof(mltaddr.sin6_addr));
! 1149: mltaddr.sin6_len = sizeof(struct sockaddr_in6);
! 1150: mltaddr.sin6_family = AF_INET6;
! 1151: mltaddr.sin6_addr = in6addr_intfacelocal_allnodes;
! 1152: mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
! 1153: mltaddr.sin6_scope_id = 0;
! 1154:
! 1155: /* XXX: again, do we really need the route? */
! 1156: rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0);
! 1157: if (rt) {
! 1158: /* 32bit came from "mltmask" */
! 1159: if (memcmp(&mltaddr.sin6_addr,
! 1160: &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
! 1161: 32 / 8)) {
! 1162: RTFREE(rt);
! 1163: rt = NULL;
! 1164: }
! 1165: }
! 1166: if (!rt) {
! 1167: struct rt_addrinfo info;
! 1168:
! 1169: bzero(&info, sizeof(info));
! 1170: info.rti_info[RTAX_DST] = (struct sockaddr *)&mltaddr;
! 1171: info.rti_info[RTAX_GATEWAY] =
! 1172: (struct sockaddr *)&ia->ia_addr;
! 1173: info.rti_info[RTAX_NETMASK] =
! 1174: (struct sockaddr *)&mltmask;
! 1175: info.rti_info[RTAX_IFA] =
! 1176: (struct sockaddr *)&ia->ia_addr;
! 1177: info.rti_flags = RTF_UP | RTF_CLONING;
! 1178: error = rtrequest1(RTM_ADD, &info, NULL, 0);
! 1179: if (error)
! 1180: goto cleanup;
! 1181: } else {
! 1182: RTFREE(rt);
! 1183: }
! 1184: imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);
! 1185: if (!imm) {
! 1186: nd6log((LOG_WARNING, "in6_update_ifa: "
! 1187: "addmulti failed for %s on %s (errno=%d)\n",
! 1188: ip6_sprintf(&mltaddr.sin6_addr),
! 1189: ifp->if_xname, error));
! 1190: goto cleanup;
! 1191: }
! 1192: LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
! 1193: }
! 1194:
! 1195: /*
! 1196: * Perform DAD, if needed.
! 1197: * XXX It may be of use, if we can administratively
! 1198: * disable DAD.
! 1199: */
! 1200: if (hostIsNew && in6if_do_dad(ifp) &&
! 1201: (ifra->ifra_flags & IN6_IFF_NODAD) == 0)
! 1202: {
! 1203: nd6_dad_start((struct ifaddr *)ia, NULL);
! 1204: }
! 1205:
! 1206: return (error);
! 1207:
! 1208: unlink:
! 1209: /*
! 1210: * XXX: if a change of an existing address failed, keep the entry
! 1211: * anyway.
! 1212: */
! 1213: if (hostIsNew)
! 1214: in6_unlink_ifa(ia, ifp);
! 1215: return (error);
! 1216:
! 1217: cleanup:
! 1218: in6_purgeaddr(&ia->ia_ifa);
! 1219: return error;
! 1220: }
! 1221:
! 1222: void
! 1223: in6_purgeaddr(ifa)
! 1224: struct ifaddr *ifa;
! 1225: {
! 1226: struct ifnet *ifp = ifa->ifa_ifp;
! 1227: struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
! 1228: struct in6_multi_mship *imm;
! 1229:
! 1230: /* stop DAD processing */
! 1231: nd6_dad_stop(ifa);
! 1232:
! 1233: /*
! 1234: * delete route to the destination of the address being purged.
! 1235: * The interface must be p2p or loopback in this case.
! 1236: */
! 1237: if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) {
! 1238: int e;
! 1239:
! 1240: if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST))
! 1241: != 0) {
! 1242: log(LOG_ERR, "in6_purgeaddr: failed to remove "
! 1243: "a route to the p2p destination: %s on %s, "
! 1244: "errno=%d\n",
! 1245: ip6_sprintf(&ia->ia_addr.sin6_addr), ifp->if_xname,
! 1246: e);
! 1247: /* proceed anyway... */
! 1248: } else
! 1249: ia->ia_flags &= ~IFA_ROUTE;
! 1250: }
! 1251:
! 1252: /* Remove ownaddr's loopback rtentry, if it exists. */
! 1253: in6_ifremloop(&(ia->ia_ifa));
! 1254:
! 1255: /*
! 1256: * leave from multicast groups we have joined for the interface
! 1257: */
! 1258: while (!LIST_EMPTY(&ia->ia6_memberships)) {
! 1259: imm = LIST_FIRST(&ia->ia6_memberships);
! 1260: LIST_REMOVE(imm, i6mm_chain);
! 1261: in6_leavegroup(imm);
! 1262: }
! 1263:
! 1264: in6_unlink_ifa(ia, ifp);
! 1265: }
! 1266:
! 1267: static void
! 1268: in6_unlink_ifa(ia, ifp)
! 1269: struct in6_ifaddr *ia;
! 1270: struct ifnet *ifp;
! 1271: {
! 1272: struct in6_ifaddr *oia;
! 1273: int s = splnet();
! 1274:
! 1275: TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
! 1276:
! 1277: oia = ia;
! 1278: if (oia == (ia = in6_ifaddr))
! 1279: in6_ifaddr = ia->ia_next;
! 1280: else {
! 1281: while (ia->ia_next && (ia->ia_next != oia))
! 1282: ia = ia->ia_next;
! 1283: if (ia->ia_next)
! 1284: ia->ia_next = oia->ia_next;
! 1285: else {
! 1286: /* search failed */
! 1287: printf("Couldn't unlink in6_ifaddr from in6_ifaddr\n");
! 1288: }
! 1289: }
! 1290:
! 1291: if (!LIST_EMPTY(&oia->ia6_multiaddrs)) {
! 1292: in6_savemkludge(oia);
! 1293: }
! 1294:
! 1295: /*
! 1296: * When an autoconfigured address is being removed, release the
! 1297: * reference to the base prefix. Also, since the release might
! 1298: * affect the status of other (detached) addresses, call
! 1299: * pfxlist_onlink_check().
! 1300: */
! 1301: if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) {
! 1302: if (oia->ia6_ndpr == NULL) {
! 1303: log(LOG_NOTICE, "in6_unlink_ifa: autoconf'ed address "
! 1304: "%p has no prefix\n", oia);
! 1305: } else {
! 1306: oia->ia6_ndpr->ndpr_refcnt--;
! 1307: oia->ia6_flags &= ~IN6_IFF_AUTOCONF;
! 1308: oia->ia6_ndpr = NULL;
! 1309: }
! 1310:
! 1311: pfxlist_onlink_check();
! 1312: }
! 1313:
! 1314: /*
! 1315: * release another refcnt for the link from in6_ifaddr.
! 1316: * Note that we should decrement the refcnt at least once for all *BSD.
! 1317: */
! 1318: IFAFREE(&oia->ia_ifa);
! 1319:
! 1320: splx(s);
! 1321: }
! 1322:
! 1323: void
! 1324: in6_purgeif(ifp)
! 1325: struct ifnet *ifp;
! 1326: {
! 1327: struct ifaddr *ifa, *nifa;
! 1328:
! 1329: for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa)
! 1330: {
! 1331: nifa = TAILQ_NEXT(ifa, ifa_list);
! 1332: if (ifa->ifa_addr->sa_family != AF_INET6)
! 1333: continue;
! 1334: in6_purgeaddr(ifa);
! 1335: }
! 1336:
! 1337: in6_ifdetach(ifp);
! 1338: }
! 1339:
! 1340: /*
! 1341: * SIOC[GAD]LIFADDR.
! 1342: * SIOCGLIFADDR: get first address. (?)
! 1343: * SIOCGLIFADDR with IFLR_PREFIX:
! 1344: * get first address that matches the specified prefix.
! 1345: * SIOCALIFADDR: add the specified address.
! 1346: * SIOCALIFADDR with IFLR_PREFIX:
! 1347: * add the specified prefix, filling hostid part from
! 1348: * the first link-local address. prefixlen must be <= 64.
! 1349: * SIOCDLIFADDR: delete the specified address.
! 1350: * SIOCDLIFADDR with IFLR_PREFIX:
! 1351: * delete the first address that matches the specified prefix.
! 1352: * return values:
! 1353: * EINVAL on invalid parameters
! 1354: * EADDRNOTAVAIL on prefix match failed/specified address not found
! 1355: * other values may be returned from in6_ioctl()
! 1356: *
! 1357: * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64.
! 1358: * this is to accommodate address naming scheme other than RFC2374,
! 1359: * in the future.
! 1360: * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374
! 1361: * address encoding scheme. (see figure on page 8)
! 1362: */
! 1363: static int
! 1364: in6_lifaddr_ioctl(so, cmd, data, ifp, p)
! 1365: struct socket *so;
! 1366: u_long cmd;
! 1367: caddr_t data;
! 1368: struct ifnet *ifp;
! 1369: struct proc *p;
! 1370: {
! 1371: struct if_laddrreq *iflr = (struct if_laddrreq *)data;
! 1372: struct ifaddr *ifa;
! 1373: struct sockaddr *sa;
! 1374:
! 1375: /* sanity checks */
! 1376: if (!data || !ifp) {
! 1377: panic("invalid argument to in6_lifaddr_ioctl");
! 1378: /* NOTREACHED */
! 1379: }
! 1380:
! 1381: switch (cmd) {
! 1382: case SIOCGLIFADDR:
! 1383: /* address must be specified on GET with IFLR_PREFIX */
! 1384: if ((iflr->flags & IFLR_PREFIX) == 0)
! 1385: break;
! 1386: /* FALLTHROUGH */
! 1387: case SIOCALIFADDR:
! 1388: case SIOCDLIFADDR:
! 1389: /* address must be specified on ADD and DELETE */
! 1390: sa = (struct sockaddr *)&iflr->addr;
! 1391: if (sa->sa_family != AF_INET6)
! 1392: return EINVAL;
! 1393: if (sa->sa_len != sizeof(struct sockaddr_in6))
! 1394: return EINVAL;
! 1395: /* XXX need improvement */
! 1396: sa = (struct sockaddr *)&iflr->dstaddr;
! 1397: if (sa->sa_family && sa->sa_family != AF_INET6)
! 1398: return EINVAL;
! 1399: if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6))
! 1400: return EINVAL;
! 1401: break;
! 1402: default: /* shouldn't happen */
! 1403: #if 0
! 1404: panic("invalid cmd to in6_lifaddr_ioctl");
! 1405: /* NOTREACHED */
! 1406: #else
! 1407: return EOPNOTSUPP;
! 1408: #endif
! 1409: }
! 1410: if (sizeof(struct in6_addr) * 8 < iflr->prefixlen)
! 1411: return EINVAL;
! 1412:
! 1413: switch (cmd) {
! 1414: case SIOCALIFADDR:
! 1415: {
! 1416: struct in6_aliasreq ifra;
! 1417: struct in6_addr *hostid = NULL;
! 1418: int prefixlen;
! 1419:
! 1420: if ((iflr->flags & IFLR_PREFIX) != 0) {
! 1421: struct sockaddr_in6 *sin6;
! 1422:
! 1423: /*
! 1424: * hostid is to fill in the hostid part of the
! 1425: * address. hostid points to the first link-local
! 1426: * address attached to the interface.
! 1427: */
! 1428: ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);
! 1429: if (!ifa)
! 1430: return EADDRNOTAVAIL;
! 1431: hostid = IFA_IN6(ifa);
! 1432:
! 1433: /* prefixlen must be <= 64. */
! 1434: if (64 < iflr->prefixlen)
! 1435: return EINVAL;
! 1436: prefixlen = iflr->prefixlen;
! 1437:
! 1438: /* hostid part must be zero. */
! 1439: sin6 = (struct sockaddr_in6 *)&iflr->addr;
! 1440: if (sin6->sin6_addr.s6_addr32[2] != 0
! 1441: || sin6->sin6_addr.s6_addr32[3] != 0) {
! 1442: return EINVAL;
! 1443: }
! 1444: } else
! 1445: prefixlen = iflr->prefixlen;
! 1446:
! 1447: /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
! 1448: bzero(&ifra, sizeof(ifra));
! 1449: bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name));
! 1450:
! 1451: bcopy(&iflr->addr, &ifra.ifra_addr,
! 1452: ((struct sockaddr *)&iflr->addr)->sa_len);
! 1453: if (hostid) {
! 1454: /* fill in hostid part */
! 1455: ifra.ifra_addr.sin6_addr.s6_addr32[2] =
! 1456: hostid->s6_addr32[2];
! 1457: ifra.ifra_addr.sin6_addr.s6_addr32[3] =
! 1458: hostid->s6_addr32[3];
! 1459: }
! 1460:
! 1461: if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /*XXX*/
! 1462: bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
! 1463: ((struct sockaddr *)&iflr->dstaddr)->sa_len);
! 1464: if (hostid) {
! 1465: ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] =
! 1466: hostid->s6_addr32[2];
! 1467: ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] =
! 1468: hostid->s6_addr32[3];
! 1469: }
! 1470: }
! 1471:
! 1472: ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
! 1473: in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
! 1474:
! 1475: ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX;
! 1476: return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, p);
! 1477: }
! 1478: case SIOCGLIFADDR:
! 1479: case SIOCDLIFADDR:
! 1480: {
! 1481: struct in6_ifaddr *ia;
! 1482: struct in6_addr mask, candidate, match;
! 1483: struct sockaddr_in6 *sin6;
! 1484: int cmp;
! 1485:
! 1486: bzero(&mask, sizeof(mask));
! 1487: if (iflr->flags & IFLR_PREFIX) {
! 1488: /* lookup a prefix rather than address. */
! 1489: in6_prefixlen2mask(&mask, iflr->prefixlen);
! 1490:
! 1491: sin6 = (struct sockaddr_in6 *)&iflr->addr;
! 1492: bcopy(&sin6->sin6_addr, &match, sizeof(match));
! 1493: match.s6_addr32[0] &= mask.s6_addr32[0];
! 1494: match.s6_addr32[1] &= mask.s6_addr32[1];
! 1495: match.s6_addr32[2] &= mask.s6_addr32[2];
! 1496: match.s6_addr32[3] &= mask.s6_addr32[3];
! 1497:
! 1498: /* if you set extra bits, that's wrong */
! 1499: if (bcmp(&match, &sin6->sin6_addr, sizeof(match)))
! 1500: return EINVAL;
! 1501:
! 1502: cmp = 1;
! 1503: } else {
! 1504: if (cmd == SIOCGLIFADDR) {
! 1505: /* on getting an address, take the 1st match */
! 1506: cmp = 0; /* XXX */
! 1507: } else {
! 1508: /* on deleting an address, do exact match */
! 1509: in6_prefixlen2mask(&mask, 128);
! 1510: sin6 = (struct sockaddr_in6 *)&iflr->addr;
! 1511: bcopy(&sin6->sin6_addr, &match, sizeof(match));
! 1512:
! 1513: cmp = 1;
! 1514: }
! 1515: }
! 1516:
! 1517: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 1518: if (ifa->ifa_addr->sa_family != AF_INET6)
! 1519: continue;
! 1520: if (!cmp)
! 1521: break;
! 1522:
! 1523: bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));
! 1524: candidate.s6_addr32[0] &= mask.s6_addr32[0];
! 1525: candidate.s6_addr32[1] &= mask.s6_addr32[1];
! 1526: candidate.s6_addr32[2] &= mask.s6_addr32[2];
! 1527: candidate.s6_addr32[3] &= mask.s6_addr32[3];
! 1528: if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
! 1529: break;
! 1530: }
! 1531: if (!ifa)
! 1532: return EADDRNOTAVAIL;
! 1533: ia = ifa2ia6(ifa);
! 1534:
! 1535: if (cmd == SIOCGLIFADDR) {
! 1536: /* fill in the if_laddrreq structure */
! 1537: bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
! 1538: if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
! 1539: bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
! 1540: ia->ia_dstaddr.sin6_len);
! 1541: } else
! 1542: bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
! 1543:
! 1544: iflr->prefixlen =
! 1545: in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
! 1546:
! 1547: iflr->flags = ia->ia6_flags; /*XXX*/
! 1548:
! 1549: return 0;
! 1550: } else {
! 1551: struct in6_aliasreq ifra;
! 1552:
! 1553: /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
! 1554: bzero(&ifra, sizeof(ifra));
! 1555: bcopy(iflr->iflr_name, ifra.ifra_name,
! 1556: sizeof(ifra.ifra_name));
! 1557:
! 1558: bcopy(&ia->ia_addr, &ifra.ifra_addr,
! 1559: ia->ia_addr.sin6_len);
! 1560: if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
! 1561: bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
! 1562: ia->ia_dstaddr.sin6_len);
! 1563: } else {
! 1564: bzero(&ifra.ifra_dstaddr,
! 1565: sizeof(ifra.ifra_dstaddr));
! 1566: }
! 1567: bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr,
! 1568: ia->ia_prefixmask.sin6_len);
! 1569:
! 1570: ifra.ifra_flags = ia->ia6_flags;
! 1571: return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
! 1572: ifp, p);
! 1573: }
! 1574: }
! 1575: }
! 1576:
! 1577: return EOPNOTSUPP; /* just for safety */
! 1578: }
! 1579:
! 1580: /*
! 1581: * Initialize an interface's intetnet6 address
! 1582: * and routing table entry.
! 1583: */
! 1584: static int
! 1585: in6_ifinit(ifp, ia, sin6, newhost)
! 1586: struct ifnet *ifp;
! 1587: struct in6_ifaddr *ia;
! 1588: struct sockaddr_in6 *sin6;
! 1589: int newhost;
! 1590: {
! 1591: int error = 0, plen, ifacount = 0;
! 1592: int s = splnet();
! 1593: struct ifaddr *ifa;
! 1594:
! 1595: /*
! 1596: * Give the interface a chance to initialize
! 1597: * if this is its first address (or it is a CARP interface)
! 1598: * and to validate the address if necessary.
! 1599: */
! 1600: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 1601: if (ifa->ifa_addr == NULL)
! 1602: continue; /* just for safety */
! 1603: if (ifa->ifa_addr->sa_family != AF_INET6)
! 1604: continue;
! 1605: ifacount++;
! 1606: }
! 1607:
! 1608: ia->ia_addr = *sin6;
! 1609:
! 1610: if ((ifacount <= 1 || ifp->if_type == IFT_CARP) && ifp->if_ioctl &&
! 1611: (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
! 1612: splx(s);
! 1613: return (error);
! 1614: }
! 1615: splx(s);
! 1616:
! 1617: ia->ia_ifa.ifa_metric = ifp->if_metric;
! 1618:
! 1619: /* we could do in(6)_socktrim here, but just omit it at this moment. */
! 1620:
! 1621: /*
! 1622: * Special case:
! 1623: * If the destination address is specified for a point-to-point
! 1624: * interface, install a route to the destination as an interface
! 1625: * direct route.
! 1626: */
! 1627: plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
! 1628: if (plen == 128 && ia->ia_dstaddr.sin6_family == AF_INET6) {
! 1629: if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD,
! 1630: RTF_UP | RTF_HOST)) != 0)
! 1631: return (error);
! 1632: ia->ia_flags |= IFA_ROUTE;
! 1633: }
! 1634:
! 1635: /* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
! 1636: if (newhost) {
! 1637: /* set the rtrequest function to create llinfo */
! 1638: ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
! 1639: in6_ifaddloop(&(ia->ia_ifa));
! 1640: }
! 1641:
! 1642: if (ifp->if_flags & IFF_MULTICAST)
! 1643: in6_restoremkludge(ia, ifp);
! 1644:
! 1645: return (error);
! 1646: }
! 1647:
! 1648: /*
! 1649: * Multicast address kludge:
! 1650: * If there were any multicast addresses attached to this interface address,
! 1651: * either move them to another address on this interface, or save them until
! 1652: * such time as this interface is reconfigured for IPv6.
! 1653: */
! 1654: void
! 1655: in6_savemkludge(oia)
! 1656: struct in6_ifaddr *oia;
! 1657: {
! 1658: struct in6_ifaddr *ia;
! 1659: struct in6_multi *in6m, *next;
! 1660:
! 1661: IFP_TO_IA6(oia->ia_ifp, ia);
! 1662: if (ia) { /* there is another address */
! 1663: for (in6m = LIST_FIRST(&oia->ia6_multiaddrs);
! 1664: in6m != LIST_END(&oia->ia6_multiaddrs); in6m = next) {
! 1665: next = LIST_NEXT(in6m, in6m_entry);
! 1666: IFAFREE(&in6m->in6m_ia->ia_ifa);
! 1667: ia->ia_ifa.ifa_refcnt++;
! 1668: in6m->in6m_ia = ia;
! 1669: LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
! 1670: }
! 1671: } else { /* last address on this if deleted, save */
! 1672: struct multi6_kludge *mk;
! 1673:
! 1674: LIST_FOREACH(mk, &in6_mk, mk_entry) {
! 1675: if (mk->mk_ifp == oia->ia_ifp)
! 1676: break;
! 1677: }
! 1678: if (mk == NULL) /* this should not happen! */
! 1679: panic("in6_savemkludge: no kludge space");
! 1680:
! 1681: for (in6m = LIST_FIRST(&oia->ia6_multiaddrs);
! 1682: in6m != LIST_END(&oia->ia6_multiaddrs); in6m = next) {
! 1683: next = LIST_NEXT(in6m, in6m_entry);
! 1684: IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */
! 1685: in6m->in6m_ia = NULL;
! 1686: LIST_INSERT_HEAD(&mk->mk_head, in6m, in6m_entry);
! 1687: }
! 1688: }
! 1689: }
! 1690:
! 1691: /*
! 1692: * Continuation of multicast address hack:
! 1693: * If there was a multicast group list previously saved for this interface,
! 1694: * then we re-attach it to the first address configured on the i/f.
! 1695: */
! 1696: void
! 1697: in6_restoremkludge(ia, ifp)
! 1698: struct in6_ifaddr *ia;
! 1699: struct ifnet *ifp;
! 1700: {
! 1701: struct multi6_kludge *mk;
! 1702:
! 1703: LIST_FOREACH(mk, &in6_mk, mk_entry) {
! 1704: if (mk->mk_ifp == ifp) {
! 1705: struct in6_multi *in6m, *next;
! 1706:
! 1707: for (in6m = LIST_FIRST(&mk->mk_head);
! 1708: in6m != LIST_END(&mk->mk_head);
! 1709: in6m = next) {
! 1710: next = LIST_NEXT(in6m, in6m_entry);
! 1711: in6m->in6m_ia = ia;
! 1712: ia->ia_ifa.ifa_refcnt++;
! 1713: LIST_INSERT_HEAD(&ia->ia6_multiaddrs,
! 1714: in6m, in6m_entry);
! 1715: }
! 1716: LIST_INIT(&mk->mk_head);
! 1717: break;
! 1718: }
! 1719: }
! 1720: }
! 1721:
! 1722: /*
! 1723: * Allocate space for the kludge at interface initialization time.
! 1724: * Formerly, we dynamically allocated the space in in6_savemkludge() with
! 1725: * malloc(M_WAITOK). However, it was wrong since the function could be called
! 1726: * under an interrupt context (software timer on address lifetime expiration).
! 1727: * Also, we cannot just give up allocating the strucutre, since the group
! 1728: * membership structure is very complex and we need to keep it anyway.
! 1729: * Of course, this function MUST NOT be called under an interrupt context.
! 1730: * Specifically, it is expected to be called only from in6_ifattach(), though
! 1731: * it is a global function.
! 1732: */
! 1733: void
! 1734: in6_createmkludge(ifp)
! 1735: struct ifnet *ifp;
! 1736: {
! 1737: struct multi6_kludge *mk;
! 1738:
! 1739: LIST_FOREACH(mk, &in6_mk, mk_entry) {
! 1740: /* If we've already had one, do not allocate. */
! 1741: if (mk->mk_ifp == ifp)
! 1742: return;
! 1743: }
! 1744:
! 1745: mk = malloc(sizeof(*mk), M_IPMADDR, M_WAITOK);
! 1746:
! 1747: bzero(mk, sizeof(*mk));
! 1748: LIST_INIT(&mk->mk_head);
! 1749: mk->mk_ifp = ifp;
! 1750: LIST_INSERT_HEAD(&in6_mk, mk, mk_entry);
! 1751: }
! 1752:
! 1753: void
! 1754: in6_purgemkludge(ifp)
! 1755: struct ifnet *ifp;
! 1756: {
! 1757: struct multi6_kludge *mk;
! 1758: struct in6_multi *in6m;
! 1759:
! 1760: LIST_FOREACH(mk, &in6_mk, mk_entry) {
! 1761: if (mk->mk_ifp != ifp)
! 1762: continue;
! 1763:
! 1764: /* leave from all multicast groups joined */
! 1765: while ((in6m = LIST_FIRST(&mk->mk_head)) != NULL)
! 1766: in6_delmulti(in6m);
! 1767: LIST_REMOVE(mk, mk_entry);
! 1768: free(mk, M_IPMADDR);
! 1769: break;
! 1770: }
! 1771: }
! 1772:
! 1773: /*
! 1774: * Add an address to the list of IP6 multicast addresses for a
! 1775: * given interface.
! 1776: */
! 1777: struct in6_multi *
! 1778: in6_addmulti(maddr6, ifp, errorp)
! 1779: struct in6_addr *maddr6;
! 1780: struct ifnet *ifp;
! 1781: int *errorp;
! 1782: {
! 1783: struct in6_ifaddr *ia;
! 1784: struct in6_ifreq ifr;
! 1785: struct in6_multi *in6m;
! 1786: int s = splsoftnet();
! 1787:
! 1788: *errorp = 0;
! 1789: /*
! 1790: * See if address already in list.
! 1791: */
! 1792: IN6_LOOKUP_MULTI(*maddr6, ifp, in6m);
! 1793: if (in6m != NULL) {
! 1794: /*
! 1795: * Found it; just increment the refrence count.
! 1796: */
! 1797: in6m->in6m_refcount++;
! 1798: } else {
! 1799: /*
! 1800: * New address; allocate a new multicast record
! 1801: * and link it into the interface's multicast list.
! 1802: */
! 1803: in6m = (struct in6_multi *)
! 1804: malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT);
! 1805: if (in6m == NULL) {
! 1806: splx(s);
! 1807: *errorp = ENOBUFS;
! 1808: return (NULL);
! 1809: }
! 1810: in6m->in6m_addr = *maddr6;
! 1811: in6m->in6m_ifp = ifp;
! 1812: in6m->in6m_refcount = 1;
! 1813: IFP_TO_IA6(ifp, ia);
! 1814: if (ia == NULL) {
! 1815: free(in6m, M_IPMADDR);
! 1816: splx(s);
! 1817: *errorp = EADDRNOTAVAIL; /* appropriate? */
! 1818: return (NULL);
! 1819: }
! 1820: in6m->in6m_ia = ia;
! 1821: ia->ia_ifa.ifa_refcnt++; /* gain a reference */
! 1822: LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
! 1823:
! 1824: /*
! 1825: * Ask the network driver to update its multicast reception
! 1826: * filter appropriately for the new address.
! 1827: */
! 1828: bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
! 1829: ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
! 1830: ifr.ifr_addr.sin6_family = AF_INET6;
! 1831: ifr.ifr_addr.sin6_addr = *maddr6;
! 1832: if (ifp->if_ioctl == NULL)
! 1833: *errorp = ENXIO; /* XXX: appropriate? */
! 1834: else
! 1835: *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI,
! 1836: (caddr_t)&ifr);
! 1837: if (*errorp) {
! 1838: LIST_REMOVE(in6m, in6m_entry);
! 1839: free(in6m, M_IPMADDR);
! 1840: IFAFREE(&ia->ia_ifa);
! 1841: splx(s);
! 1842: return (NULL);
! 1843: }
! 1844: /*
! 1845: * Let MLD6 know that we have joined a new IP6 multicast
! 1846: * group.
! 1847: */
! 1848: mld6_start_listening(in6m);
! 1849: }
! 1850: splx(s);
! 1851: return (in6m);
! 1852: }
! 1853:
! 1854: /*
! 1855: * Delete a multicast address record.
! 1856: */
! 1857: void
! 1858: in6_delmulti(in6m)
! 1859: struct in6_multi *in6m;
! 1860: {
! 1861: struct in6_ifreq ifr;
! 1862: int s = splsoftnet();
! 1863:
! 1864: if (--in6m->in6m_refcount == 0) {
! 1865: /*
! 1866: * No remaining claims to this record; let MLD6 know
! 1867: * that we are leaving the multicast group.
! 1868: */
! 1869: mld6_stop_listening(in6m);
! 1870:
! 1871: /*
! 1872: * Unlink from list.
! 1873: */
! 1874: LIST_REMOVE(in6m, in6m_entry);
! 1875: if (in6m->in6m_ia) {
! 1876: IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */
! 1877: }
! 1878:
! 1879: /*
! 1880: * Notify the network driver to update its multicast
! 1881: * reception filter.
! 1882: */
! 1883: bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
! 1884: ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
! 1885: ifr.ifr_addr.sin6_family = AF_INET6;
! 1886: ifr.ifr_addr.sin6_addr = in6m->in6m_addr;
! 1887: (*in6m->in6m_ifp->if_ioctl)(in6m->in6m_ifp,
! 1888: SIOCDELMULTI, (caddr_t)&ifr);
! 1889: free(in6m, M_IPMADDR);
! 1890: }
! 1891: splx(s);
! 1892: }
! 1893:
! 1894: struct in6_multi_mship *
! 1895: in6_joingroup(ifp, addr, errorp)
! 1896: struct ifnet *ifp;
! 1897: struct in6_addr *addr;
! 1898: int *errorp;
! 1899: {
! 1900: struct in6_multi_mship *imm;
! 1901:
! 1902: imm = malloc(sizeof(*imm), M_IPMADDR, M_NOWAIT);
! 1903: if (!imm) {
! 1904: *errorp = ENOBUFS;
! 1905: return NULL;
! 1906: }
! 1907: imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp);
! 1908: if (!imm->i6mm_maddr) {
! 1909: /* *errorp is alrady set */
! 1910: free(imm, M_IPMADDR);
! 1911: return NULL;
! 1912: }
! 1913: return imm;
! 1914: }
! 1915:
! 1916: int
! 1917: in6_leavegroup(imm)
! 1918: struct in6_multi_mship *imm;
! 1919: {
! 1920:
! 1921: if (imm->i6mm_maddr)
! 1922: in6_delmulti(imm->i6mm_maddr);
! 1923: free(imm, M_IPMADDR);
! 1924: return 0;
! 1925: }
! 1926:
! 1927: /*
! 1928: * Find an IPv6 interface link-local address specific to an interface.
! 1929: */
! 1930: struct in6_ifaddr *
! 1931: in6ifa_ifpforlinklocal(ifp, ignoreflags)
! 1932: struct ifnet *ifp;
! 1933: int ignoreflags;
! 1934: {
! 1935: struct ifaddr *ifa;
! 1936:
! 1937: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 1938: if (ifa->ifa_addr == NULL)
! 1939: continue; /* just for safety */
! 1940: if (ifa->ifa_addr->sa_family != AF_INET6)
! 1941: continue;
! 1942: if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
! 1943: if ((((struct in6_ifaddr *)ifa)->ia6_flags &
! 1944: ignoreflags) != 0)
! 1945: continue;
! 1946: break;
! 1947: }
! 1948: }
! 1949:
! 1950: return ((struct in6_ifaddr *)ifa);
! 1951: }
! 1952:
! 1953:
! 1954: /*
! 1955: * find the internet address corresponding to a given interface and address.
! 1956: */
! 1957: struct in6_ifaddr *
! 1958: in6ifa_ifpwithaddr(ifp, addr)
! 1959: struct ifnet *ifp;
! 1960: struct in6_addr *addr;
! 1961: {
! 1962: struct ifaddr *ifa;
! 1963:
! 1964: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 1965: if (ifa->ifa_addr == NULL)
! 1966: continue; /* just for safety */
! 1967: if (ifa->ifa_addr->sa_family != AF_INET6)
! 1968: continue;
! 1969: if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
! 1970: break;
! 1971: }
! 1972:
! 1973: return ((struct in6_ifaddr *)ifa);
! 1974: }
! 1975:
! 1976: /*
! 1977: * Convert IP6 address to printable (loggable) representation.
! 1978: */
! 1979: static char digits[] = "0123456789abcdef";
! 1980: static int ip6round = 0;
! 1981: char *
! 1982: ip6_sprintf(addr)
! 1983: struct in6_addr *addr;
! 1984: {
! 1985: static char ip6buf[8][48];
! 1986: int i;
! 1987: char *cp;
! 1988: u_short *a = (u_short *)addr;
! 1989: u_char *d;
! 1990: int dcolon = 0;
! 1991:
! 1992: ip6round = (ip6round + 1) & 7;
! 1993: cp = ip6buf[ip6round];
! 1994:
! 1995: for (i = 0; i < 8; i++) {
! 1996: if (dcolon == 1) {
! 1997: if (*a == 0) {
! 1998: if (i == 7)
! 1999: *cp++ = ':';
! 2000: a++;
! 2001: continue;
! 2002: } else
! 2003: dcolon = 2;
! 2004: }
! 2005: if (*a == 0) {
! 2006: if (dcolon == 0 && *(a + 1) == 0) {
! 2007: if (i == 0)
! 2008: *cp++ = ':';
! 2009: *cp++ = ':';
! 2010: dcolon = 1;
! 2011: } else {
! 2012: *cp++ = '0';
! 2013: *cp++ = ':';
! 2014: }
! 2015: a++;
! 2016: continue;
! 2017: }
! 2018: d = (u_char *)a;
! 2019: *cp++ = digits[*d >> 4];
! 2020: *cp++ = digits[*d++ & 0xf];
! 2021: *cp++ = digits[*d >> 4];
! 2022: *cp++ = digits[*d & 0xf];
! 2023: *cp++ = ':';
! 2024: a++;
! 2025: }
! 2026: *--cp = 0;
! 2027: return (ip6buf[ip6round]);
! 2028: }
! 2029:
! 2030: /*
! 2031: * Get a scope of the address. Node-local, link-local, site-local or global.
! 2032: */
! 2033: int
! 2034: in6_addrscope (addr)
! 2035: struct in6_addr *addr;
! 2036: {
! 2037: int scope;
! 2038:
! 2039: if (addr->s6_addr8[0] == 0xfe) {
! 2040: scope = addr->s6_addr8[1] & 0xc0;
! 2041:
! 2042: switch (scope) {
! 2043: case 0x80:
! 2044: return IPV6_ADDR_SCOPE_LINKLOCAL;
! 2045: break;
! 2046: case 0xc0:
! 2047: return IPV6_ADDR_SCOPE_SITELOCAL;
! 2048: break;
! 2049: default:
! 2050: return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
! 2051: break;
! 2052: }
! 2053: }
! 2054:
! 2055:
! 2056: if (addr->s6_addr8[0] == 0xff) {
! 2057: scope = addr->s6_addr8[1] & 0x0f;
! 2058:
! 2059: /*
! 2060: * due to other scope such as reserved,
! 2061: * return scope doesn't work.
! 2062: */
! 2063: switch (scope) {
! 2064: case IPV6_ADDR_SCOPE_INTFACELOCAL:
! 2065: return IPV6_ADDR_SCOPE_INTFACELOCAL;
! 2066: break;
! 2067: case IPV6_ADDR_SCOPE_LINKLOCAL:
! 2068: return IPV6_ADDR_SCOPE_LINKLOCAL;
! 2069: break;
! 2070: case IPV6_ADDR_SCOPE_SITELOCAL:
! 2071: return IPV6_ADDR_SCOPE_SITELOCAL;
! 2072: break;
! 2073: default:
! 2074: return IPV6_ADDR_SCOPE_GLOBAL;
! 2075: break;
! 2076: }
! 2077: }
! 2078:
! 2079: if (bcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) {
! 2080: if (addr->s6_addr8[15] == 1) /* loopback */
! 2081: return IPV6_ADDR_SCOPE_INTFACELOCAL;
! 2082: if (addr->s6_addr8[15] == 0) /* unspecified */
! 2083: return IPV6_ADDR_SCOPE_LINKLOCAL;
! 2084: }
! 2085:
! 2086: return IPV6_ADDR_SCOPE_GLOBAL;
! 2087: }
! 2088:
! 2089: int
! 2090: in6_addr2scopeid(ifp, addr)
! 2091: struct ifnet *ifp; /* must not be NULL */
! 2092: struct in6_addr *addr; /* must not be NULL */
! 2093: {
! 2094: int scope = in6_addrscope(addr);
! 2095:
! 2096: switch(scope) {
! 2097: case IPV6_ADDR_SCOPE_INTFACELOCAL:
! 2098: case IPV6_ADDR_SCOPE_LINKLOCAL:
! 2099: /* XXX: we do not distinguish between a link and an I/F. */
! 2100: return (ifp->if_index);
! 2101:
! 2102: case IPV6_ADDR_SCOPE_SITELOCAL:
! 2103: return (0); /* XXX: invalid. */
! 2104:
! 2105: default:
! 2106: return (0); /* XXX: treat as global. */
! 2107: }
! 2108: }
! 2109:
! 2110: int
! 2111: in6_is_addr_deprecated(sa6)
! 2112: struct sockaddr_in6 *sa6;
! 2113: {
! 2114: struct in6_ifaddr *ia;
! 2115:
! 2116: for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
! 2117: if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
! 2118: &sa6->sin6_addr) &&
! 2119: (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0)
! 2120: return (1); /* true */
! 2121:
! 2122: /* XXX: do we still have to go thru the rest of the list? */
! 2123: }
! 2124:
! 2125: return (0); /* false */
! 2126: }
! 2127:
! 2128: /*
! 2129: * return length of part which dst and src are equal
! 2130: * hard coding...
! 2131: */
! 2132: int
! 2133: in6_matchlen(src, dst)
! 2134: struct in6_addr *src, *dst;
! 2135: {
! 2136: int match = 0;
! 2137: u_char *s = (u_char *)src, *d = (u_char *)dst;
! 2138: u_char *lim = s + 16, r;
! 2139:
! 2140: while (s < lim)
! 2141: if ((r = (*d++ ^ *s++)) != 0) {
! 2142: while (r < 128) {
! 2143: match++;
! 2144: r <<= 1;
! 2145: }
! 2146: break;
! 2147: } else
! 2148: match += 8;
! 2149: return match;
! 2150: }
! 2151:
! 2152: int
! 2153: in6_are_prefix_equal(p1, p2, len)
! 2154: struct in6_addr *p1, *p2;
! 2155: int len;
! 2156: {
! 2157: int bytelen, bitlen;
! 2158:
! 2159: /* sanity check */
! 2160: if (0 > len || len > 128) {
! 2161: log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n",
! 2162: len);
! 2163: return (0);
! 2164: }
! 2165:
! 2166: bytelen = len / 8;
! 2167: bitlen = len % 8;
! 2168:
! 2169: if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen))
! 2170: return (0);
! 2171: /* len == 128 is ok because bitlen == 0 then */
! 2172: if (bitlen != 0 &&
! 2173: p1->s6_addr[bytelen] >> (8 - bitlen) !=
! 2174: p2->s6_addr[bytelen] >> (8 - bitlen))
! 2175: return (0);
! 2176:
! 2177: return (1);
! 2178: }
! 2179:
! 2180: void
! 2181: in6_prefixlen2mask(maskp, len)
! 2182: struct in6_addr *maskp;
! 2183: int len;
! 2184: {
! 2185: u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
! 2186: int bytelen, bitlen, i;
! 2187:
! 2188: /* sanity check */
! 2189: if (0 > len || len > 128) {
! 2190: log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n",
! 2191: len);
! 2192: return;
! 2193: }
! 2194:
! 2195: bzero(maskp, sizeof(*maskp));
! 2196: bytelen = len / 8;
! 2197: bitlen = len % 8;
! 2198: for (i = 0; i < bytelen; i++)
! 2199: maskp->s6_addr[i] = 0xff;
! 2200: /* len == 128 is ok because bitlen == 0 then */
! 2201: if (bitlen)
! 2202: maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
! 2203: }
! 2204:
! 2205: /*
! 2206: * return the best address out of the same scope
! 2207: */
! 2208: struct in6_ifaddr *
! 2209: in6_ifawithscope(oifp, dst)
! 2210: struct ifnet *oifp;
! 2211: struct in6_addr *dst;
! 2212: {
! 2213: int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0;
! 2214: int blen = -1;
! 2215: struct ifaddr *ifa;
! 2216: struct ifnet *ifp;
! 2217: struct in6_ifaddr *ifa_best = NULL;
! 2218:
! 2219: if (oifp == NULL) {
! 2220: printf("in6_ifawithscope: output interface is not specified\n");
! 2221: return (NULL);
! 2222: }
! 2223:
! 2224: /*
! 2225: * We search for all addresses on all interfaces from the beginning.
! 2226: * Comparing an interface with the outgoing interface will be done
! 2227: * only at the final stage of tiebreaking.
! 2228: */
! 2229: for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
! 2230: {
! 2231: /*
! 2232: * We can never take an address that breaks the scope zone
! 2233: * of the destination.
! 2234: */
! 2235: if (in6_addr2scopeid(ifp, dst) != in6_addr2scopeid(oifp, dst))
! 2236: continue;
! 2237:
! 2238: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 2239: int tlen = -1, dscopecmp, bscopecmp, matchcmp;
! 2240:
! 2241: if (ifa->ifa_addr->sa_family != AF_INET6)
! 2242: continue;
! 2243:
! 2244: src_scope = in6_addrscope(IFA_IN6(ifa));
! 2245:
! 2246: #ifdef ADDRSELECT_DEBUG /* should be removed after stabilization */
! 2247: dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope);
! 2248: printf("in6_ifawithscope: dst=%s bestaddr=%s, "
! 2249: "newaddr=%s, scope=%x, dcmp=%d, bcmp=%d, "
! 2250: "matchlen=%d, flgs=%x\n",
! 2251: ip6_sprintf(dst),
! 2252: ifa_best ? ip6_sprintf(&ifa_best->ia_addr.sin6_addr) : "none",
! 2253: ip6_sprintf(IFA_IN6(ifa)), src_scope,
! 2254: dscopecmp,
! 2255: ifa_best ? IN6_ARE_SCOPE_CMP(src_scope, best_scope) : -1,
! 2256: in6_matchlen(IFA_IN6(ifa), dst),
! 2257: ((struct in6_ifaddr *)ifa)->ia6_flags);
! 2258: #endif
! 2259:
! 2260: /*
! 2261: * Don't use an address before completing DAD
! 2262: * nor a duplicated address.
! 2263: */
! 2264: if (((struct in6_ifaddr *)ifa)->ia6_flags &
! 2265: IN6_IFF_NOTREADY)
! 2266: continue;
! 2267:
! 2268: /* XXX: is there any case to allow anycasts? */
! 2269: if (((struct in6_ifaddr *)ifa)->ia6_flags &
! 2270: IN6_IFF_ANYCAST)
! 2271: continue;
! 2272:
! 2273: if (((struct in6_ifaddr *)ifa)->ia6_flags &
! 2274: IN6_IFF_DETACHED)
! 2275: continue;
! 2276:
! 2277: /*
! 2278: * If this is the first address we find,
! 2279: * keep it anyway.
! 2280: */
! 2281: if (ifa_best == NULL)
! 2282: goto replace;
! 2283:
! 2284: /*
! 2285: * ifa_best is never NULL beyond this line except
! 2286: * within the block labeled "replace".
! 2287: */
! 2288:
! 2289: /*
! 2290: * If ifa_best has a smaller scope than dst and
! 2291: * the current address has a larger one than
! 2292: * (or equal to) dst, always replace ifa_best.
! 2293: * Also, if the current address has a smaller scope
! 2294: * than dst, ignore it unless ifa_best also has a
! 2295: * smaller scope.
! 2296: */
! 2297: if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 &&
! 2298: IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0)
! 2299: goto replace;
! 2300: if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 &&
! 2301: IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0)
! 2302: continue;
! 2303:
! 2304: /*
! 2305: * A deprecated address SHOULD NOT be used in new
! 2306: * communications if an alternate (non-deprecated)
! 2307: * address is available and has sufficient scope.
! 2308: * RFC 2462, Section 5.5.4.
! 2309: */
! 2310: if (((struct in6_ifaddr *)ifa)->ia6_flags &
! 2311: IN6_IFF_DEPRECATED) {
! 2312: /*
! 2313: * Ignore any deprecated addresses if
! 2314: * specified by configuration.
! 2315: */
! 2316: if (!ip6_use_deprecated)
! 2317: continue;
! 2318:
! 2319: /*
! 2320: * If we have already found a non-deprecated
! 2321: * candidate, just ignore deprecated addresses.
! 2322: */
! 2323: if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED)
! 2324: == 0)
! 2325: continue;
! 2326: }
! 2327:
! 2328: /*
! 2329: * A non-deprecated address is always preferred
! 2330: * to a deprecated one regardless of scopes and
! 2331: * address matching.
! 2332: */
! 2333: if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) &&
! 2334: (((struct in6_ifaddr *)ifa)->ia6_flags &
! 2335: IN6_IFF_DEPRECATED) == 0)
! 2336: goto replace;
! 2337:
! 2338: /*
! 2339: * At this point, we have two cases:
! 2340: * 1. we are looking at a non-deprecated address,
! 2341: * and ifa_best is also non-deprecated.
! 2342: * 2. we are looking at a deprecated address,
! 2343: * and ifa_best is also deprecated.
! 2344: * Also, we do not have to consider a case where
! 2345: * the scope of if_best is larger(smaller) than dst and
! 2346: * the scope of the current address is smaller(larger)
! 2347: * than dst. Such a case has already been covered.
! 2348: * Tiebreaking is done according to the following
! 2349: * items:
! 2350: * - the scope comparison between the address and
! 2351: * dst (dscopecmp)
! 2352: * - the scope comparison between the address and
! 2353: * ifa_best (bscopecmp)
! 2354: * - if the address match dst longer than ifa_best
! 2355: * (matchcmp)
! 2356: * - if the address is on the outgoing I/F (outI/F)
! 2357: *
! 2358: * Roughly speaking, the selection policy is
! 2359: * - the most important item is scope. The same scope
! 2360: * is best. Then search for a larger scope.
! 2361: * Smaller scopes are the last resort.
! 2362: * - A deprecated address is chosen only when we have
! 2363: * no address that has an enough scope, but is
! 2364: * prefered to any addresses of smaller scopes.
! 2365: * - Longest address match against dst is considered
! 2366: * only for addresses that has the same scope of dst.
! 2367: * - If there is no other reasons to choose one,
! 2368: * addresses on the outgoing I/F are preferred.
! 2369: *
! 2370: * The precise decision table is as follows:
! 2371: * dscopecmp bscopecmp matchcmp outI/F | replace?
! 2372: * !equal equal N/A Yes | Yes (1)
! 2373: * !equal equal N/A No | No (2)
! 2374: * larger larger N/A N/A | No (3)
! 2375: * larger smaller N/A N/A | Yes (4)
! 2376: * smaller larger N/A N/A | Yes (5)
! 2377: * smaller smaller N/A N/A | No (6)
! 2378: * equal smaller N/A N/A | Yes (7)
! 2379: * equal larger (already done)
! 2380: * equal equal larger N/A | Yes (8)
! 2381: * equal equal smaller N/A | No (9)
! 2382: * equal equal equal Yes | Yes (a)
! 2383: * eaual eqaul equal No | No (b)
! 2384: */
! 2385: dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope);
! 2386: bscopecmp = IN6_ARE_SCOPE_CMP(src_scope, best_scope);
! 2387:
! 2388: if (dscopecmp && bscopecmp == 0) {
! 2389: if (oifp == ifp) /* (1) */
! 2390: goto replace;
! 2391: continue; /* (2) */
! 2392: }
! 2393: if (dscopecmp > 0) {
! 2394: if (bscopecmp > 0) /* (3) */
! 2395: continue;
! 2396: goto replace; /* (4) */
! 2397: }
! 2398: if (dscopecmp < 0) {
! 2399: if (bscopecmp > 0) /* (5) */
! 2400: goto replace;
! 2401: continue; /* (6) */
! 2402: }
! 2403:
! 2404: /* now dscopecmp must be 0 */
! 2405: if (bscopecmp < 0)
! 2406: goto replace; /* (7) */
! 2407:
! 2408: /*
! 2409: * At last both dscopecmp and bscopecmp must be 0.
! 2410: * We need address matching against dst for
! 2411: * tiebreaking.
! 2412: */
! 2413: tlen = in6_matchlen(IFA_IN6(ifa), dst);
! 2414: matchcmp = tlen - blen;
! 2415: if (matchcmp > 0) /* (8) */
! 2416: goto replace;
! 2417: if (matchcmp < 0) /* (9) */
! 2418: continue;
! 2419: if (oifp == ifp) /* (a) */
! 2420: goto replace;
! 2421: continue; /* (b) */
! 2422:
! 2423: replace:
! 2424: ifa_best = (struct in6_ifaddr *)ifa;
! 2425: blen = tlen >= 0 ? tlen :
! 2426: in6_matchlen(IFA_IN6(ifa), dst);
! 2427: best_scope = in6_addrscope(&ifa_best->ia_addr.sin6_addr);
! 2428: }
! 2429: }
! 2430:
! 2431: /* count statistics for future improvements */
! 2432: if (ifa_best == NULL)
! 2433: ip6stat.ip6s_sources_none++;
! 2434: else {
! 2435: if (oifp == ifa_best->ia_ifp)
! 2436: ip6stat.ip6s_sources_sameif[best_scope]++;
! 2437: else
! 2438: ip6stat.ip6s_sources_otherif[best_scope]++;
! 2439:
! 2440: if (best_scope == dst_scope)
! 2441: ip6stat.ip6s_sources_samescope[best_scope]++;
! 2442: else
! 2443: ip6stat.ip6s_sources_otherscope[best_scope]++;
! 2444:
! 2445: if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) != 0)
! 2446: ip6stat.ip6s_sources_deprecated[best_scope]++;
! 2447: }
! 2448:
! 2449: return (ifa_best);
! 2450: }
! 2451:
! 2452: /*
! 2453: * return the best address out of the same scope. if no address was
! 2454: * found, return the first valid address from designated IF.
! 2455: */
! 2456: struct in6_ifaddr *
! 2457: in6_ifawithifp(ifp, dst)
! 2458: struct ifnet *ifp;
! 2459: struct in6_addr *dst;
! 2460: {
! 2461: int dst_scope = in6_addrscope(dst), blen = -1, tlen;
! 2462: struct ifaddr *ifa;
! 2463: struct in6_ifaddr *besta = 0;
! 2464: struct in6_ifaddr *dep[2]; /*last-resort: deprecated*/
! 2465:
! 2466: dep[0] = dep[1] = NULL;
! 2467:
! 2468: /*
! 2469: * We first look for addresses in the same scope.
! 2470: * If there is one, return it.
! 2471: * If two or more, return one which matches the dst longest.
! 2472: * If none, return one of global addresses assigned other ifs.
! 2473: */
! 2474: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 2475: if (ifa->ifa_addr->sa_family != AF_INET6)
! 2476: continue;
! 2477: if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
! 2478: continue; /* XXX: is there any case to allow anycast? */
! 2479: if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
! 2480: continue; /* don't use this interface */
! 2481: if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
! 2482: continue;
! 2483: if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
! 2484: if (ip6_use_deprecated)
! 2485: dep[0] = (struct in6_ifaddr *)ifa;
! 2486: continue;
! 2487: }
! 2488:
! 2489: if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
! 2490: /*
! 2491: * call in6_matchlen() as few as possible
! 2492: */
! 2493: if (besta) {
! 2494: if (blen == -1)
! 2495: blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
! 2496: tlen = in6_matchlen(IFA_IN6(ifa), dst);
! 2497: if (tlen > blen) {
! 2498: blen = tlen;
! 2499: besta = (struct in6_ifaddr *)ifa;
! 2500: }
! 2501: } else
! 2502: besta = (struct in6_ifaddr *)ifa;
! 2503: }
! 2504: }
! 2505: if (besta)
! 2506: return (besta);
! 2507:
! 2508: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 2509: if (ifa->ifa_addr->sa_family != AF_INET6)
! 2510: continue;
! 2511: if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
! 2512: continue; /* XXX: is there any case to allow anycast? */
! 2513: if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
! 2514: continue; /* don't use this interface */
! 2515: if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
! 2516: continue;
! 2517: if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
! 2518: if (ip6_use_deprecated)
! 2519: dep[1] = (struct in6_ifaddr *)ifa;
! 2520: continue;
! 2521: }
! 2522:
! 2523: return (struct in6_ifaddr *)ifa;
! 2524: }
! 2525:
! 2526: /* use the last-resort values, that are, deprecated addresses */
! 2527: if (dep[0])
! 2528: return dep[0];
! 2529: if (dep[1])
! 2530: return dep[1];
! 2531:
! 2532: return NULL;
! 2533: }
! 2534:
! 2535: /*
! 2536: * perform DAD when interface becomes IFF_UP.
! 2537: */
! 2538: void
! 2539: in6_if_up(ifp)
! 2540: struct ifnet *ifp;
! 2541: {
! 2542: struct ifaddr *ifa;
! 2543: struct in6_ifaddr *ia;
! 2544: int dad_delay; /* delay ticks before DAD output */
! 2545:
! 2546: /*
! 2547: * special cases, like 6to4, are handled in in6_ifattach
! 2548: */
! 2549: in6_ifattach(ifp, NULL);
! 2550:
! 2551: dad_delay = 0;
! 2552: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 2553: if (ifa->ifa_addr->sa_family != AF_INET6)
! 2554: continue;
! 2555: ia = (struct in6_ifaddr *)ifa;
! 2556: if (ia->ia6_flags & IN6_IFF_TENTATIVE)
! 2557: nd6_dad_start(ifa, &dad_delay);
! 2558: }
! 2559: }
! 2560:
! 2561: int
! 2562: in6if_do_dad(ifp)
! 2563: struct ifnet *ifp;
! 2564: {
! 2565: if ((ifp->if_flags & IFF_LOOPBACK) != 0)
! 2566: return (0);
! 2567:
! 2568: switch (ifp->if_type) {
! 2569: case IFT_FAITH:
! 2570: /*
! 2571: * These interfaces do not have the IFF_LOOPBACK flag,
! 2572: * but loop packets back. We do not have to do DAD on such
! 2573: * interfaces. We should even omit it, because loop-backed
! 2574: * NS would confuse the DAD procedure.
! 2575: */
! 2576: return (0);
! 2577: default:
! 2578: /*
! 2579: * Our DAD routine requires the interface up and running.
! 2580: * However, some interfaces can be up before the RUNNING
! 2581: * status. Additionaly, users may try to assign addresses
! 2582: * before the interface becomes up (or running).
! 2583: * We simply skip DAD in such a case as a work around.
! 2584: * XXX: we should rather mark "tentative" on such addresses,
! 2585: * and do DAD after the interface becomes ready.
! 2586: */
! 2587: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) !=
! 2588: (IFF_UP|IFF_RUNNING))
! 2589: return (0);
! 2590:
! 2591: return (1);
! 2592: }
! 2593: }
! 2594:
! 2595: /*
! 2596: * Calculate max IPv6 MTU through all the interfaces and store it
! 2597: * to in6_maxmtu.
! 2598: */
! 2599: void
! 2600: in6_setmaxmtu()
! 2601: {
! 2602: unsigned long maxmtu = 0;
! 2603: struct ifnet *ifp;
! 2604:
! 2605: for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
! 2606: {
! 2607: /* this function can be called during ifnet initialization */
! 2608: if (!ifp->if_afdata[AF_INET6])
! 2609: continue;
! 2610: if ((ifp->if_flags & IFF_LOOPBACK) == 0 &&
! 2611: IN6_LINKMTU(ifp) > maxmtu)
! 2612: maxmtu = IN6_LINKMTU(ifp);
! 2613: }
! 2614: if (maxmtu) /* update only when maxmtu is positive */
! 2615: in6_maxmtu = maxmtu;
! 2616: }
! 2617:
! 2618: void *
! 2619: in6_domifattach(ifp)
! 2620: struct ifnet *ifp;
! 2621: {
! 2622: struct in6_ifextra *ext;
! 2623:
! 2624: ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK);
! 2625: bzero(ext, sizeof(*ext));
! 2626:
! 2627: ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat),
! 2628: M_IFADDR, M_WAITOK);
! 2629: bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat));
! 2630:
! 2631: ext->icmp6_ifstat =
! 2632: (struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat),
! 2633: M_IFADDR, M_WAITOK);
! 2634: bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat));
! 2635:
! 2636: ext->nd_ifinfo = nd6_ifattach(ifp);
! 2637: return ext;
! 2638: }
! 2639:
! 2640: void
! 2641: in6_domifdetach(ifp, aux)
! 2642: struct ifnet *ifp;
! 2643: void *aux;
! 2644: {
! 2645: struct in6_ifextra *ext = (struct in6_ifextra *)aux;
! 2646:
! 2647: nd6_ifdetach(ext->nd_ifinfo);
! 2648: free(ext->in6_ifstat, M_IFADDR);
! 2649: free(ext->icmp6_ifstat, M_IFADDR);
! 2650: free(ext, M_IFADDR);
! 2651: }
CVSweb