X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/39236c6e673c41db228275375ab7fdb0f837b292..3903760236c30e3b5ace7a4eefac3a269d68957c:/bsd/netinet6/in6.c diff --git a/bsd/netinet6/in6.c b/bsd/netinet6/in6.c index 261fdc420..f5e206f03 100644 --- a/bsd/netinet6/in6.c +++ b/bsd/netinet6/in6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2013 Apple Inc. All rights reserved. + * Copyright (c) 2003-2016 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -134,7 +134,6 @@ #include #include #include -#include #include #include #include @@ -142,6 +141,8 @@ #include +#include + #if PF #include #endif /* PF */ @@ -172,8 +173,6 @@ const struct sockaddr_in6 sa6_any = { sizeof (sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 }; -static int in6ctl_lifaddr(struct ifnet *, u_long, struct if_laddrreq *, - boolean_t); static int in6ctl_associd(struct socket *, u_long, caddr_t); static int in6ctl_connid(struct socket *, u_long, caddr_t); static int in6ctl_conninfo(struct socket *, u_long, caddr_t); @@ -198,30 +197,27 @@ static void in6_ifaddr_detached(struct ifaddr *); static void in6_ifaddr_free(struct ifaddr *); static void in6_ifaddr_trace(struct ifaddr *, int); #if defined(__LP64__) -static void in6_llstartreq_32_to_64(struct in6_llstartreq_32 *, - struct in6_llstartreq_64 *); +static void in6_cgareq_32_to_64(struct in6_cgareq_32 *, + struct in6_cgareq_64 *); #else -static void in6_llstartreq_64_to_32(struct in6_llstartreq_64 *, - struct in6_llstartreq_32 *); +static void in6_cgareq_64_to_32(struct in6_cgareq_64 *, + struct in6_cgareq_32 *); #endif static struct in6_aliasreq *in6_aliasreq_to_native(void *, int, struct in6_aliasreq *); -static struct in6_llstartreq *in6_llstartreq_to_native(void *, int, - struct in6_llstartreq *); +static struct in6_cgareq *in6_cgareq_to_native(void *, int, + struct in6_cgareq *); static int in6_to_kamescope(struct sockaddr_in6 *, struct ifnet *); - -static void in6_ifaddr_set_dadprogress(struct in6_ifaddr *); - static int in6_getassocids(struct socket *, uint32_t *, user_addr_t); -static int in6_getconnids(struct socket *, associd_t, uint32_t *, user_addr_t); -static int in6_getconninfo(struct socket *, connid_t, uint32_t *, +static int in6_getconnids(struct socket *, sae_associd_t, uint32_t *, + user_addr_t); +static int in6_getconninfo(struct socket *, sae_connid_t, uint32_t *, uint32_t *, int32_t *, user_addr_t, socklen_t *, user_addr_t, socklen_t *, uint32_t *, user_addr_t, uint32_t *); static void in6_if_up_dad_start(struct ifnet *); extern lck_mtx_t *nd6_mutex; -extern int in6_init2done; #define IN6IFA_TRACE_HIST_SIZE 32 /* size of trace history */ @@ -433,9 +429,7 @@ in6_ifremloop(struct ifaddr *ifa) int -in6_mask2len(mask, lim0) - struct in6_addr *mask; - u_char *lim0; +in6_mask2len(struct in6_addr *mask, u_char *lim0) { int x = 0, y; u_char *lim = lim0, *p; @@ -471,9 +465,7 @@ in6_mask2len(mask, lim0) } void -in6_len2mask(mask, len) - struct in6_addr *mask; - int len; +in6_len2mask(struct in6_addr *mask, int len) { int i; @@ -516,41 +508,41 @@ in6_aliasreq_32_to_64(struct in6_aliasreq_32 *src, struct in6_aliasreq_64 *dst) #if defined(__LP64__) void -in6_llstartreq_32_to_64(struct in6_llstartreq_32 *src, - struct in6_llstartreq_64 *dst) +in6_cgareq_32_to_64(struct in6_cgareq_32 *src, + struct in6_cgareq_64 *dst) { bzero(dst, sizeof (*dst)); - bcopy(src->llsr_name, dst->llsr_name, sizeof (dst->llsr_name)); - dst->llsr_flags = src->llsr_flags; - bcopy(src->llsr_cgaprep.cga_modifier.octets, - dst->llsr_cgaprep.cga_modifier.octets, - sizeof (dst->llsr_cgaprep.cga_modifier.octets)); - dst->llsr_cgaprep.cga_security_level = - src->llsr_cgaprep.cga_security_level; - dst->llsr_lifetime.ia6t_expire = src->llsr_lifetime.ia6t_expire; - dst->llsr_lifetime.ia6t_preferred = src->llsr_lifetime.ia6t_preferred; - dst->llsr_lifetime.ia6t_vltime = src->llsr_lifetime.ia6t_vltime; - dst->llsr_lifetime.ia6t_pltime = src->llsr_lifetime.ia6t_pltime; + bcopy(src->cgar_name, dst->cgar_name, sizeof (dst->cgar_name)); + dst->cgar_flags = src->cgar_flags; + bcopy(src->cgar_cgaprep.cga_modifier.octets, + dst->cgar_cgaprep.cga_modifier.octets, + sizeof (dst->cgar_cgaprep.cga_modifier.octets)); + dst->cgar_cgaprep.cga_security_level = + src->cgar_cgaprep.cga_security_level; + dst->cgar_lifetime.ia6t_expire = src->cgar_lifetime.ia6t_expire; + dst->cgar_lifetime.ia6t_preferred = src->cgar_lifetime.ia6t_preferred; + dst->cgar_lifetime.ia6t_vltime = src->cgar_lifetime.ia6t_vltime; + dst->cgar_lifetime.ia6t_pltime = src->cgar_lifetime.ia6t_pltime; } #endif #if !defined(__LP64__) void -in6_llstartreq_64_to_32(struct in6_llstartreq_64 *src, - struct in6_llstartreq_32 *dst) +in6_cgareq_64_to_32(struct in6_cgareq_64 *src, + struct in6_cgareq_32 *dst) { bzero(dst, sizeof (*dst)); - bcopy(src->llsr_name, dst->llsr_name, sizeof (dst->llsr_name)); - dst->llsr_flags = src->llsr_flags; - bcopy(src->llsr_cgaprep.cga_modifier.octets, - dst->llsr_cgaprep.cga_modifier.octets, - sizeof (dst->llsr_cgaprep.cga_modifier.octets)); - dst->llsr_cgaprep.cga_security_level = - src->llsr_cgaprep.cga_security_level; - dst->llsr_lifetime.ia6t_expire = src->llsr_lifetime.ia6t_expire; - dst->llsr_lifetime.ia6t_preferred = src->llsr_lifetime.ia6t_preferred; - dst->llsr_lifetime.ia6t_vltime = src->llsr_lifetime.ia6t_vltime; - dst->llsr_lifetime.ia6t_pltime = src->llsr_lifetime.ia6t_pltime; + bcopy(src->cgar_name, dst->cgar_name, sizeof (dst->cgar_name)); + dst->cgar_flags = src->cgar_flags; + bcopy(src->cgar_cgaprep.cga_modifier.octets, + dst->cgar_cgaprep.cga_modifier.octets, + sizeof (dst->cgar_cgaprep.cga_modifier.octets)); + dst->cgar_cgaprep.cga_security_level = + src->cgar_cgaprep.cga_security_level; + dst->cgar_lifetime.ia6t_expire = src->cgar_lifetime.ia6t_expire; + dst->cgar_lifetime.ia6t_preferred = src->cgar_lifetime.ia6t_preferred; + dst->cgar_lifetime.ia6t_vltime = src->cgar_lifetime.ia6t_vltime; + dst->cgar_lifetime.ia6t_pltime = src->cgar_lifetime.ia6t_pltime; } #endif @@ -573,19 +565,19 @@ in6_aliasreq_to_native(void *data, int data_is_64, struct in6_aliasreq *dst) return (dst); } -static struct in6_llstartreq * -in6_llstartreq_to_native(void *data, int is64, struct in6_llstartreq *dst) +static struct in6_cgareq * +in6_cgareq_to_native(void *data, int is64, struct in6_cgareq *dst) { #if defined(__LP64__) if (is64) bcopy(data, dst, sizeof (*dst)); else - in6_llstartreq_32_to_64((struct in6_llstartreq_32 *)data, - (struct in6_llstartreq_64 *)dst); + in6_cgareq_32_to_64((struct in6_cgareq_32 *)data, + (struct in6_cgareq_64 *)dst); #else if (is64) - in6_llstartreq_64_to_32((struct in6_llstartreq_64 *)data, - (struct in6_llstartreq_32 *)dst); + in6_cgareq_64_to_32((struct in6_cgareq_64 *)data, + (struct in6_cgareq_32 *)dst); else bcopy(data, dst, sizeof (*dst)); #endif /* __LP64__ */ @@ -736,8 +728,7 @@ in6ctl_llstart(struct ifnet *ifp, u_long cmd, caddr_t data) * be done here. They are currently done in in6_ifattach_aux() * for the interfaces that need it. */ - if ((ifp->if_eflags & IFEF_NOAUTOIPV6LL) != 0 && - ifra->ifra_addr.sin6_family == AF_INET6 && + if (ifra->ifra_addr.sin6_family == AF_INET6 && /* Only check ifra_dstaddr if valid */ (ifra->ifra_dstaddr.sin6_len == 0 || ifra->ifra_dstaddr.sin6_family == AF_INET6)) { @@ -762,6 +753,7 @@ static __attribute__((noinline)) int in6ctl_llstop(struct ifnet *ifp) { struct in6_ifaddr *ia; + struct nd_prefix pr0, *pr; VERIFY(ifp != NULL); @@ -794,36 +786,56 @@ in6ctl_llstop(struct ifnet *ifp) ia = ia->ia_next; } lck_rw_done(&in6_ifaddr_rwlock); + + /* Delete the link local prefix */ + bzero(&pr0, sizeof(pr0)); + pr0.ndpr_plen = 64; + pr0.ndpr_ifp = ifp; + pr0.ndpr_prefix.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_ULL; + in6_setscope(&pr0.ndpr_prefix.sin6_addr, ifp, NULL); + pr = nd6_prefix_lookup(&pr0, ND6_PREFIX_EXPIRY_UNSPEC); + if (pr) { + lck_mtx_lock(nd6_mutex); + NDPR_LOCK(pr); + prelist_remove(pr); + NDPR_UNLOCK(pr); + NDPR_REMREF(pr); /* Drop the reference from lookup */ + lck_mtx_unlock(nd6_mutex); + } + return (0); } +/* + * This routine configures secure link local address + */ static __attribute__((noinline)) int in6ctl_cgastart(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct in6_llstartreq llsr; + struct in6_cgareq llcgasr; int is64, error = 0; VERIFY(ifp != NULL); switch (cmd) { - case SIOCLL_CGASTART_32: /* struct in6_llstartreq_32 */ - case SIOCLL_CGASTART_64: /* struct in6_llstartreq_64 */ + case SIOCLL_CGASTART_32: /* struct in6_cgareq_32 */ + case SIOCLL_CGASTART_64: /* struct in6_cgareq_64 */ is64 = (cmd == SIOCLL_CGASTART_64); /* - * Convert user llstartreq to the kernel form, when appropriate. + * Convert user cgareq to the kernel form, when appropriate. * This allows the conversion between different data models * to be centralized, so that it can be passed around to other * routines that are expecting the kernel form. */ - in6_llstartreq_to_native(data, is64, &llsr); + in6_cgareq_to_native(data, is64, &llcgasr); /* * NOTE: All the interface specific DLIL attachements * should be done here. They are currently done in - * in6_ifattach_llstartreq() for the interfaces that + * in6_ifattach_cgareq() for the interfaces that * need it. */ - error = in6_ifattach_llstartreq(ifp, &llsr); + error = in6_ifattach_llcgareq(ifp, &llcgasr); if (error == 0) in6_if_up_dad_start(ifp); break; @@ -1090,14 +1102,6 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, * ioctls which don't require ifp, may require socket. */ switch (cmd) { -#if MROUTING - case SIOCGETSGCNT_IN6: /* struct sioc_sg_req6 */ - case SIOCGETMIFCNT_IN6_32: /* struct sioc_mif_req6_32 */ - case SIOCGETMIFCNT_IN6_64: /* struct sioc_mif_req6_64 */ - return (mrt6_ioctl(cmd, data)); - /* NOTREACHED */ -#endif /* MROUTING */ - case SIOCAADDRCTL_POLICY: /* struct in6_addrpolicy */ case SIOCDADDRCTL_POLICY: /* struct in6_addrpolicy */ if (!privileged) @@ -1137,64 +1141,85 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, if (ifp == NULL) return (ENXIO); + /* + * Unlock the socket since ifnet_ioctl() may be invoked by + * one of the ioctl handlers below. Socket will be re-locked + * prior to returning. + */ + if (so != NULL) { + socket_unlock(so, 0); + so_unlocked = TRUE; + } + /* * ioctls which require ifp but not interface address. */ switch (cmd) { case SIOCAUTOCONF_START: /* struct in6_ifreq */ - if (!privileged) - return (EPERM); - return (in6_autoconf(ifp, TRUE)); - /* NOTREACHED */ + if (!privileged) { + error = EPERM; + goto done; + } + error = in6_autoconf(ifp, TRUE); + goto done; case SIOCAUTOCONF_STOP: /* struct in6_ifreq */ - if (!privileged) - return (EPERM); - return (in6_autoconf(ifp, FALSE)); - /* NOTREACHED */ + if (!privileged) { + error = EPERM; + goto done; + } + error = in6_autoconf(ifp, FALSE); + goto done; case SIOCLL_START_32: /* struct in6_aliasreq_32 */ case SIOCLL_START_64: /* struct in6_aliasreq_64 */ - if (!privileged) - return (EPERM); - return (in6ctl_llstart(ifp, cmd, data)); - /* NOTREACHED */ + if (!privileged) { + error = EPERM; + goto done; + } + error = in6ctl_llstart(ifp, cmd, data); + goto done; case SIOCLL_STOP: /* struct in6_ifreq */ - if (!privileged) - return (EPERM); - return (in6ctl_llstop(ifp)); - /* NOTREACHED */ + if (!privileged) { + error = EPERM; + goto done; + } + error = in6ctl_llstop(ifp); + goto done; case SIOCSETROUTERMODE_IN6: /* struct in6_ifreq */ - if (!privileged) - return (EPERM); - + if (!privileged) { + error = EPERM; + goto done; + } bcopy(&((struct in6_ifreq *)(void *)data)->ifr_intval, &intval, sizeof (intval)); - return (in6_setrouter(ifp, intval)); - /* NOTREACHED */ + error = in6_setrouter(ifp, intval); + goto done; case SIOCPROTOATTACH_IN6_32: /* struct in6_aliasreq_32 */ case SIOCPROTOATTACH_IN6_64: /* struct in6_aliasreq_64 */ - if (!privileged) - return (EPERM); - return (in6_domifattach(ifp)); - /* NOTREACHED */ + if (!privileged) { + error = EPERM; + goto done; + } + error = in6_domifattach(ifp); + goto done; case SIOCPROTODETACH_IN6: /* struct in6_ifreq */ - if (!privileged) - return (EPERM); - + if (!privileged) { + error = EPERM; + goto done; + } /* Cleanup interface routes and addresses */ in6_purgeif(ifp); if ((error = proto_unplumb(PF_INET6, ifp))) log(LOG_ERR, "SIOCPROTODETACH_IN6: %s error=%d\n", if_name(ifp), error); - return (error); - /* NOTREACHED */ + goto done; case SIOCSNDFLUSH_IN6: /* struct in6_ifreq */ case SIOCSPFXFLUSH_IN6: /* struct in6_ifreq */ @@ -1202,8 +1227,12 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, case SIOCSDEFIFACE_IN6_32: /* struct in6_ndifreq_32 */ case SIOCSDEFIFACE_IN6_64: /* struct in6_ndifreq_64 */ case SIOCSIFINFO_FLAGS: /* struct in6_ndireq */ - if (!privileged) - return (EPERM); + case SIOCGIFCGAPREP_IN6: /* struct in6_ifreq */ + case SIOCSIFCGAPREP_IN6: /* struct in6_ifreq */ + if (!privileged) { + error = EPERM; + goto done; + } /* FALLTHRU */ case OSIOCGIFINFO_IN6: /* struct in6_ondireq */ case SIOCGIFINFO_IN6: /* struct in6_ondireq */ @@ -1215,8 +1244,8 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, case SIOCGNBRINFO_IN6_64: /* struct in6_nbrinfo_64 */ case SIOCGDEFIFACE_IN6_32: /* struct in6_ndifreq_32 */ case SIOCGDEFIFACE_IN6_64: /* struct in6_ndifreq_64 */ - return (nd6_ioctl(cmd, data, ifp)); - /* NOTREACHED */ + error = nd6_ioctl(cmd, data, ifp); + goto done; case SIOCSIFPREFIX_IN6: /* struct in6_prefixreq (deprecated) */ case SIOCDIFPREFIX_IN6: /* struct in6_prefixreq (deprecated) */ @@ -1227,41 +1256,27 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, log(LOG_NOTICE, "prefix ioctls are now invalidated. " "please use ifconfig.\n"); - return (EOPNOTSUPP); - /* NOTREACHED */ + error = EOPNOTSUPP; + goto done; case SIOCSSCOPE6: /* struct in6_ifreq (deprecated) */ case SIOCGSCOPE6: /* struct in6_ifreq (deprecated) */ case SIOCGSCOPE6DEF: /* struct in6_ifreq (deprecated) */ - return (EOPNOTSUPP); - /* NOTREACHED */ - - case SIOCALIFADDR: /* struct if_laddrreq */ - case SIOCDLIFADDR: /* struct if_laddrreq */ - if (!privileged) - return (EPERM); - /* FALLTHRU */ - case SIOCGLIFADDR: { /* struct if_laddrreq */ - struct if_laddrreq iflr; - - bcopy(data, &iflr, sizeof (iflr)); - error = in6ctl_lifaddr(ifp, cmd, &iflr, p64); - bcopy(&iflr, data, sizeof (iflr)); - return (error); - /* NOTREACHED */ - } - - case SIOCLL_CGASTART_32: /* struct in6_llstartreq_32 */ - case SIOCLL_CGASTART_64: /* struct in6_llstartreq_64 */ + error = EOPNOTSUPP; + goto done; + + case SIOCLL_CGASTART_32: /* struct in6_cgareq_32 */ + case SIOCLL_CGASTART_64: /* struct in6_cgareq_64 */ if (!privileged) - return (EPERM); - return (in6ctl_cgastart(ifp, cmd, data)); - /* NOTREACHED */ + error = EPERM; + else + error = in6ctl_cgastart(ifp, cmd, data); + goto done; case SIOCGIFSTAT_IN6: /* struct in6_ifreq */ case SIOCGIFSTAT_ICMP6: /* struct in6_ifreq */ - return (in6ctl_gifstat(ifp, cmd, ifr)); - /* NOTREACHED */ + error = in6ctl_gifstat(ifp, cmd, ifr); + goto done; } /* @@ -1276,13 +1291,15 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, * on a single interface, SIOCSIFxxx ioctls are deprecated. */ /* we decided to obsolete this command (20000704) */ - return (EOPNOTSUPP); - /* NOTREACHED */ + error = EOPNOTSUPP; + goto done; case SIOCAIFADDR_IN6_32: /* struct in6_aliasreq_32 */ case SIOCAIFADDR_IN6_64: /* struct in6_aliasreq_64 */ - if (!privileged) - return (EPERM); + if (!privileged) { + error = EPERM; + goto done; + } /* * Convert user ifra to the kernel form, when appropriate. * This allows the conversion between different data models @@ -1297,8 +1314,10 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, case SIOCDIFADDR_IN6: /* struct in6_ifreq */ case SIOCSIFALIFETIME_IN6: /* struct in6_ifreq */ - if (!privileged) - return (EPERM); + if (!privileged) { + error = EPERM; + goto done; + } /* FALLTHRU */ case SIOCGIFADDR_IN6: /* struct in6_ifreq */ case SIOCGIFDSTADDR_IN6: /* struct in6_ifreq */ @@ -1331,12 +1350,15 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, htons(ifp->if_index); } else if (sa6->sin6_addr.s6_addr16[1] != htons(ifp->if_index)) { - return (EINVAL); /* link ID contradicts */ + error = EINVAL; /* link ID contradicts */ + goto done; } if (sa6->sin6_scope_id) { if (sa6->sin6_scope_id != - (u_int32_t)ifp->if_index) - return (EINVAL); + (u_int32_t)ifp->if_index) { + error = EINVAL; + goto done; + } sa6->sin6_scope_id = 0; /* XXX: good way? */ } } @@ -1354,8 +1376,10 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, */ switch (cmd) { case SIOCDIFADDR_IN6: /* struct in6_ifreq */ - if (ia == NULL) - return (EADDRNOTAVAIL); + if (ia == NULL) { + error = EADDRNOTAVAIL; + goto done; + } /* FALLTHROUGH */ case SIOCAIFADDR_IN6_32: /* struct in6_aliasreq_32 */ case SIOCAIFADDR_IN6_64: /* struct in6_aliasreq_64 */ @@ -1373,16 +1397,6 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, break; } - /* - * Unlock the socket since ifnet_ioctl() may be invoked by - * one of the ioctl handlers below. Socket will be re-locked - * prior to returning. - */ - if (so != NULL) { - socket_unlock(so, 0); - so_unlocked = TRUE; - } - /* * And finally process address-related ioctls. */ @@ -1516,8 +1530,8 @@ in6ctl_aifaddr(struct ifnet *ifp, struct in6_aliasreq *ifra) pr0.ndpr_stateflags |= NDPRF_STATIC; lck_mtx_init(&pr0.ndpr_lock, ifa_mtx_grp, ifa_mtx_attr); - /* add the prefix if there's one. */ - if ((pr = nd6_prefix_lookup(&pr0)) == NULL) { + /* add the prefix if there's none. */ + if ((pr = nd6_prefix_lookup(&pr0, ND6_PREFIX_EXPIRY_NEVER)) == NULL) { /* * nd6_prelist_add will install the corresponding interface * route. @@ -1538,7 +1552,7 @@ in6ctl_aifaddr(struct ifnet *ifp, struct in6_aliasreq *ifra) /* if this is a new autoconfed addr */ addtmp = FALSE; - if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && ia->ia6_ndpr == NULL) { + if (ia->ia6_ndpr == NULL) { NDPR_LOCK(pr); ++pr->ndpr_addrcnt; VERIFY(pr->ndpr_addrcnt != 0); @@ -1549,7 +1563,11 @@ in6ctl_aifaddr(struct ifnet *ifp, struct in6_aliasreq *ifra) * If this is the first autoconf address from the prefix, * create a temporary address as well (when specified). */ - addtmp = (ip6_use_tempaddr && pr->ndpr_addrcnt == 1); + if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && + ip6_use_tempaddr && + pr->ndpr_addrcnt == 1) { + addtmp = true; + } NDPR_UNLOCK(pr); } @@ -1614,21 +1632,11 @@ in6ctl_difaddr(struct ifnet *ifp, struct in6_ifaddr *ia) ia->ia_prefixmask.sin6_addr.s6_addr32[i]; } IFA_UNLOCK(&ia->ia_ifa); - /* - * The logic of the following condition is a bit complicated. - * We expire the prefix when - * 1. the address obeys autoconfiguration and it is the - * only owner of the associated prefix, or - * 2. the address does not obey autoconf and there is no - * other owner of the prefix. - */ - if ((pr = nd6_prefix_lookup(&pr0)) != NULL) { + + if ((pr = nd6_prefix_lookup(&pr0, ND6_PREFIX_EXPIRY_UNSPEC)) != NULL) { IFA_LOCK(&ia->ia_ifa); NDPR_LOCK(pr); - if (((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && - pr->ndpr_addrcnt == 1) || - ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0 && - pr->ndpr_addrcnt == 0)) { + if (pr->ndpr_addrcnt == 1) { /* XXX: just for expiration */ pr->ndpr_expire = 1; } @@ -1722,9 +1730,8 @@ in6_setrouter(struct ifnet *ifp, int enable) return (ENODEV); if (enable) { - struct nd_ifinfo *ndi; + struct nd_ifinfo *ndi = NULL; - lck_rw_lock_shared(nd_if_rwlock); ndi = ND_IFINFO(ifp); if (ndi != NULL && ndi->initialized) { lck_mtx_lock(&ndi->lock); @@ -1732,14 +1739,10 @@ in6_setrouter(struct ifnet *ifp, int enable) /* No proxy if we are an advertising router */ ndi->flags &= ~ND6_IFF_PROXY_PREFIXES; lck_mtx_unlock(&ndi->lock); - lck_rw_done(nd_if_rwlock); (void) nd6_if_prproxy(ifp, FALSE); } else { lck_mtx_unlock(&ndi->lock); - lck_rw_done(nd_if_rwlock); } - } else { - lck_rw_done(nd_if_rwlock); } } @@ -1797,12 +1800,19 @@ in6_ifaupdate_aux(struct in6_ifaddr *ia, struct ifnet *ifp, int ifaupflags) struct in6_multi *in6m_sol; struct in6_multi_mship *imm; struct rtentry *rt; - int delay, error; + int delay, error = 0; VERIFY(ifp != NULL && ia != NULL); ifa = &ia->ia_ifa; in6m_sol = NULL; + nd6log2((LOG_DEBUG, "%s - %s ifp %s ia6_flags 0x%x ifaupflags 0x%x\n", + __func__, + ip6_sprintf(&ia->ia_addr.sin6_addr), + if_name(ia->ia_ifp), + ia->ia6_flags, + ifaupflags)); + /* * Mark the address as tentative before joining multicast addresses, * so that corresponding MLD responses would not have a tentative @@ -1812,6 +1822,15 @@ in6_ifaupdate_aux(struct in6_ifaddr *ia, struct ifnet *ifp, int ifaupflags) if (in6if_do_dad(ifp)) in6_ifaddr_set_dadprogress(ia); + /* + * Do not delay sending neighbor solicitations when using optimistic + * duplicate address detection, c.f. RFC 4429. + */ + if (ia->ia6_flags & IN6_IFF_OPTIMISTIC) + ifaupflags &= ~IN6_IFAUPDATE_DADDELAY; + else + ifaupflags |= IN6_IFAUPDATE_DADDELAY; + /* Join necessary multicast groups */ if ((ifp->if_flags & IFF_MULTICAST) != 0) { @@ -1986,15 +2005,6 @@ in6_ifaupdate_aux(struct in6_ifaddr *ia, struct ifnet *ifp, int ifaupflags) } #undef MLTMASK_LEN - /* - * Make sure to initialize ND6 information. this is to workaround - * issues with interfaces with IPv6 addresses, which have never brought - * up. We are assuming that it is safe to nd6_ifattach multiple times. - * NOTE: this is how stf0 gets initialized - */ - if ((error = nd6_ifattach(ifp)) != 0) - goto unwind; - /* Ensure nd6_service() is scheduled as soon as it's convenient */ ++nd6_sched_timeout_want; @@ -2011,7 +2021,13 @@ in6_ifaupdate_aux(struct in6_ifaddr *ia, struct ifnet *ifp, int ifaupflags) IFA_UNLOCK(ifa); delayptr = NULL; - if ((ifaupflags & IN6_IFAUPDATE_DADDELAY)) { + /* + * Avoid the DAD delay if the caller wants us to skip it. + * This is not compliant with RFC 2461, but it's only being + * used for signalling and not for actual DAD. + */ + if ((ifaupflags & IN6_IFAUPDATE_DADDELAY) && + !(ia->ia6_flags & IN6_IFF_SWIFTDAD)) { /* * We need to impose a delay before sending an NS * for DAD. Check if we also needed a delay for the @@ -2286,13 +2302,6 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, int ifaupflags, ia->ia6_lifetime.ia6ti_preferred = timenow; } - /* - * Do not delay sending neighbor solicitations when using optimistic - * duplicate address detection, c.f. RFC 4429. - */ - if ((ia->ia6_flags & IN6_IFF_OPTIMISTIC) == 0) - ifaupflags |= IN6_IFAUPDATE_DADDELAY; - /* * Update flag or prefix length */ @@ -2383,7 +2392,7 @@ in6_purgeaddr(struct ifaddr *ifa) /* in6_unlink_ifa() will need exclusive access */ in6_unlink_ifa(ia, ifp); - in6_post_msg(ifp, KEV_INET6_ADDR_DELETED, ia); + in6_post_msg(ifp, KEV_INET6_ADDR_DELETED, ia, NULL); (void) ifnet_notify_address(ifp, AF_INET6); } @@ -2425,21 +2434,33 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) } /* - * When an autoconfigured address is being removed, release the - * reference to the base prefix. Also, since the release might - * affect the status of other (detached) addresses, call + * When IPv6 address is being removed, release the + * reference to the base prefix. + * Also, since the release might, affect the status + * of other (detached) addresses, call * pfxlist_onlink_check(). */ ifa = &oia->ia_ifa; IFA_LOCK(ifa); - if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) { - if (oia->ia6_ndpr == NULL) { - log(LOG_NOTICE, "in6_unlink_ifa: autoconf'ed address " + /* + * Only log the below message for addresses other than + * link local. + * Only one LLA (auto-configured or statically) is allowed + * on an interface. + * LLA prefix, while added to the prefix list, is not + * reference countedi (as it is the only one). + * The prefix also never expires on its own as LLAs + * have infinite lifetime. + * + * For now quiece down the log message for LLAs. + */ + if (!IN6_IS_ADDR_LINKLOCAL(&oia->ia_addr.sin6_addr)) { + if (oia->ia6_ndpr == NULL) + log(LOG_NOTICE, "in6_unlink_ifa: IPv6 address " "0x%llx has no prefix\n", (uint64_t)VM_KERNEL_ADDRPERM(oia)); - } else { + else { struct nd_prefix *pr = oia->ia6_ndpr; - oia->ia6_flags &= ~IN6_IFF_AUTOCONF; oia->ia6_ndpr = NULL; NDPR_LOCK(pr); @@ -2448,16 +2469,15 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) NDPR_UNLOCK(pr); NDPR_REMREF(pr); /* release addr reference */ } - IFA_UNLOCK(ifa); - lck_rw_done(&in6_ifaddr_rwlock); + } + IFA_UNLOCK(ifa); + lck_rw_done(&in6_ifaddr_rwlock); + + if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) { lck_mtx_lock(nd6_mutex); pfxlist_onlink_check(); lck_mtx_unlock(nd6_mutex); - } else { - IFA_UNLOCK(ifa); - lck_rw_done(&in6_ifaddr_rwlock); } - /* * release another refcnt for the link from in6_ifaddrs. * Do this only if it's not already unlinked in the event that we lost @@ -2508,341 +2528,6 @@ in6_purgeif(struct ifnet *ifp) in6_ifdetach(ifp); } -/* - * SIOC[GAD]LIFADDR. - * SIOCGLIFADDR: get first address. (?) - * SIOCGLIFADDR with IFLR_PREFIX: - * get first address that matches the specified prefix. - * SIOCALIFADDR: add the specified address. - * SIOCALIFADDR with IFLR_PREFIX: - * add the specified prefix, filling hostaddr part from - * the first link-local address. prefixlen must be <= 64. - * SIOCDLIFADDR: delete the specified address. - * SIOCDLIFADDR with IFLR_PREFIX: - * delete the first address that matches the specified prefix. - * return values: - * EINVAL on invalid parameters - * EADDRNOTAVAIL on prefix match failed/specified address not found - * other values may be returned from in6_ioctl() - * - * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64. - * this is to accomodate address naming scheme other than RFC2374, - * in the future. - * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374 - * address encoding scheme. (see figure on page 8) - */ -static __attribute__((noinline)) int -in6ctl_lifaddr(struct ifnet *ifp, u_long cmd, struct if_laddrreq *iflr, - boolean_t p64) -{ - struct in6_aliasreq ifra; - struct ifaddr *ifa; - struct sockaddr *sa; - - VERIFY(ifp != NULL); - - switch (cmd) { - case SIOCGLIFADDR: - /* address must be specified on GET with IFLR_PREFIX */ - if (!(iflr->flags & IFLR_PREFIX)) - break; - /* FALLTHROUGH */ - case SIOCALIFADDR: - case SIOCDLIFADDR: - /* address must be specified on ADD and DELETE */ - sa = (struct sockaddr *)&iflr->addr; - if (sa->sa_family != AF_INET6) - return (EINVAL); - if (sa->sa_len != sizeof (struct sockaddr_in6)) - return (EINVAL); - /* XXX need improvement */ - sa = (struct sockaddr *)&iflr->dstaddr; - if (sa->sa_family && sa->sa_family != AF_INET6) - return (EINVAL); - if (sa->sa_len && sa->sa_len != sizeof (struct sockaddr_in6)) - return (EINVAL); - break; - default: - /* shouldn't happen */ - VERIFY(0); - /* NOTREACHED */ - } - if (sizeof (struct in6_addr) * 8 < iflr->prefixlen) - return (EINVAL); - - switch (cmd) { - case SIOCALIFADDR: { - struct in6_addr hostaddr; - int prefixlen; - int hostid_found = 0; - - if ((iflr->flags & IFLR_PREFIX) != 0) { - struct sockaddr_in6 *sin6; - - /* - * hostaddr is to fill in the hostaddr part of the - * address. hostaddr points to the first link-local - * address attached to the interface. - */ - ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); - if (!ifa) - return (EADDRNOTAVAIL); - IFA_LOCK_SPIN(ifa); - hostaddr = *IFA_IN6(ifa); - IFA_UNLOCK(ifa); - hostid_found = 1; - IFA_REMREF(ifa); - ifa = NULL; - - /* prefixlen must be <= 64. */ - if (64 < iflr->prefixlen) - return (EINVAL); - prefixlen = iflr->prefixlen; - - /* hostid part must be zero. */ - sin6 = (struct sockaddr_in6 *)&iflr->addr; - if (sin6->sin6_addr.s6_addr32[2] != 0 || - sin6->sin6_addr.s6_addr32[3] != 0) { - return (EINVAL); - } - } else { - prefixlen = iflr->prefixlen; - } - /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ - bzero(&ifra, sizeof (ifra)); - bcopy(iflr->iflr_name, ifra.ifra_name, sizeof (ifra.ifra_name)); - - bcopy(&iflr->addr, &ifra.ifra_addr, - ((struct sockaddr *)&iflr->addr)->sa_len); - if (hostid_found) { - /* fill in hostaddr part */ - ifra.ifra_addr.sin6_addr.s6_addr32[2] = - hostaddr.s6_addr32[2]; - ifra.ifra_addr.sin6_addr.s6_addr32[3] = - hostaddr.s6_addr32[3]; - } - - if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */ - bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, - ((struct sockaddr *)&iflr->dstaddr)->sa_len); - if (hostid_found) { - ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] = - hostaddr.s6_addr32[2]; - ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = - hostaddr.s6_addr32[3]; - } - } - - ifra.ifra_prefixmask.sin6_len = sizeof (struct sockaddr_in6); - in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); - - ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; - if (!p64) { -#if defined(__LP64__) - struct in6_aliasreq_32 ifra_32; - /* - * Use 32-bit ioctl and structure for 32-bit process. - */ - in6_aliasreq_64_to_32((struct in6_aliasreq_64 *)&ifra, - &ifra_32); - return (in6_control(NULL, SIOCAIFADDR_IN6_32, - (caddr_t)&ifra_32, ifp, kernproc)); -#else - return (in6_control(NULL, SIOCAIFADDR_IN6, - (caddr_t)&ifra, ifp, kernproc)); -#endif /* __LP64__ */ - } else { -#if defined(__LP64__) - return (in6_control(NULL, SIOCAIFADDR_IN6, - (caddr_t)&ifra, ifp, kernproc)); -#else - struct in6_aliasreq_64 ifra_64; - /* - * Use 64-bit ioctl and structure for 64-bit process. - */ - in6_aliasreq_32_to_64((struct in6_aliasreq_32 *)&ifra, - &ifra_64); - return (in6_control(NULL, SIOCAIFADDR_IN6_64, - (caddr_t)&ifra_64, ifp, kernproc)); -#endif /* __LP64__ */ - } - /* NOTREACHED */ - } - - case SIOCGLIFADDR: - case SIOCDLIFADDR: { - struct in6_ifaddr *ia; - struct in6_addr mask, candidate, match; - struct sockaddr_in6 *sin6; - int cmp; - - bzero(&mask, sizeof (mask)); - if (iflr->flags & IFLR_PREFIX) { - /* lookup a prefix rather than address. */ - in6_prefixlen2mask(&mask, iflr->prefixlen); - - sin6 = (struct sockaddr_in6 *)&iflr->addr; - bcopy(&sin6->sin6_addr, &match, sizeof (match)); - match.s6_addr32[0] &= mask.s6_addr32[0]; - match.s6_addr32[1] &= mask.s6_addr32[1]; - match.s6_addr32[2] &= mask.s6_addr32[2]; - match.s6_addr32[3] &= mask.s6_addr32[3]; - - /* if you set extra bits, that's wrong */ - if (bcmp(&match, &sin6->sin6_addr, sizeof (match))) - return (EINVAL); - - cmp = 1; - } else { - if (cmd == SIOCGLIFADDR) { - /* on getting an address, take the 1st match */ - cmp = 0; /* XXX */ - } else { - /* on deleting an address, do exact match */ - in6_prefixlen2mask(&mask, 128); - sin6 = (struct sockaddr_in6 *)&iflr->addr; - bcopy(&sin6->sin6_addr, &match, sizeof (match)); - - cmp = 1; - } - } - - ifnet_lock_shared(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { - IFA_LOCK(ifa); - if (ifa->ifa_addr->sa_family != AF_INET6) { - IFA_UNLOCK(ifa); - continue; - } - if (!cmp) { - IFA_UNLOCK(ifa); - break; - } - - bcopy(IFA_IN6(ifa), &candidate, sizeof (candidate)); - IFA_UNLOCK(ifa); - /* - * XXX: this is adhoc, but is necessary to allow - * a user to specify fe80::/64 (not /10) for a - * link-local address. - */ - if (IN6_IS_ADDR_LINKLOCAL(&candidate)) - candidate.s6_addr16[1] = 0; - candidate.s6_addr32[0] &= mask.s6_addr32[0]; - candidate.s6_addr32[1] &= mask.s6_addr32[1]; - candidate.s6_addr32[2] &= mask.s6_addr32[2]; - candidate.s6_addr32[3] &= mask.s6_addr32[3]; - if (IN6_ARE_ADDR_EQUAL(&candidate, &match)) - break; - } - if (ifa != NULL) - IFA_ADDREF(ifa); - ifnet_lock_done(ifp); - if (!ifa) - return (EADDRNOTAVAIL); - ia = ifa2ia6(ifa); - - if (cmd == SIOCGLIFADDR) { - struct sockaddr_in6 *s6; - - IFA_LOCK(ifa); - /* fill in the if_laddrreq structure */ - bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len); - s6 = (struct sockaddr_in6 *)&iflr->addr; - if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { - s6->sin6_addr.s6_addr16[1] = 0; - s6->sin6_scope_id = - in6_addr2scopeid(ifp, &s6->sin6_addr); - } - if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { - bcopy(&ia->ia_dstaddr, &iflr->dstaddr, - ia->ia_dstaddr.sin6_len); - s6 = (struct sockaddr_in6 *)&iflr->dstaddr; - if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { - s6->sin6_addr.s6_addr16[1] = 0; - s6->sin6_scope_id = - in6_addr2scopeid(ifp, - &s6->sin6_addr); - } - } else - bzero(&iflr->dstaddr, sizeof (iflr->dstaddr)); - - iflr->prefixlen = - in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); - - iflr->flags = ia->ia6_flags; /* XXX */ - IFA_UNLOCK(ifa); - IFA_REMREF(ifa); - return (0); - } else { - /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ - bzero(&ifra, sizeof (ifra)); - bcopy(iflr->iflr_name, ifra.ifra_name, - sizeof (ifra.ifra_name)); - - IFA_LOCK(ifa); - bcopy(&ia->ia_addr, &ifra.ifra_addr, - ia->ia_addr.sin6_len); - if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { - bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, - ia->ia_dstaddr.sin6_len); - } else { - bzero(&ifra.ifra_dstaddr, - sizeof (ifra.ifra_dstaddr)); - } - bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr, - ia->ia_prefixmask.sin6_len); - - ifra.ifra_flags = ia->ia6_flags; - IFA_UNLOCK(ifa); - IFA_REMREF(ifa); - if (!p64) { -#if defined(__LP64__) - struct in6_aliasreq_32 ifra_32; - /* - * Use 32-bit structure for 32-bit process. - * SIOCDIFADDR_IN6 is encoded with in6_ifreq, - * so it stays the same since the size does - * not change. The data part of the ioctl, - * however, is of a different structure, i.e. - * in6_aliasreq. - */ - in6_aliasreq_64_to_32( - (struct in6_aliasreq_64 *)&ifra, &ifra_32); - return (in6_control(NULL, SIOCDIFADDR_IN6, - (caddr_t)&ifra_32, ifp, kernproc)); -#else - return (in6_control(NULL, SIOCDIFADDR_IN6, - (caddr_t)&ifra, ifp, kernproc)); -#endif /* __LP64__ */ - } else { -#if defined(__LP64__) - return (in6_control(NULL, SIOCDIFADDR_IN6, - (caddr_t)&ifra, ifp, kernproc)); -#else - struct in6_aliasreq_64 ifra_64; - /* - * Use 64-bit structure for 64-bit process. - * SIOCDIFADDR_IN6 is encoded with in6_ifreq, - * so it stays the same since the size does - * not change. The data part of the ioctl, - * however, is of a different structure, i.e. - * in6_aliasreq. - */ - in6_aliasreq_32_to_64( - (struct in6_aliasreq_32 *)&ifra, &ifra_64); - return (in6_control(NULL, SIOCDIFADDR_IN6, - (caddr_t)&ifra_64, ifp, kernproc)); -#endif /* __LP64__ */ - } - /* NOTREACHED */ - } - } - } - - return (EOPNOTSUPP); /* just for safety */ -} - /* * Initialize an interface's internet6 address and routing table entry. */ @@ -2917,9 +2602,7 @@ in6_purgeaddrs(struct ifnet *ifp) * Find an IPv6 interface link-local address specific to an interface. */ struct in6_ifaddr * -in6ifa_ifpforlinklocal(ifp, ignoreflags) - struct ifnet *ifp; - int ignoreflags; +in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags) { struct ifaddr *ifa; @@ -2952,9 +2635,7 @@ in6ifa_ifpforlinklocal(ifp, ignoreflags) * find the internet address corresponding to a given interface and address. */ struct in6_ifaddr * -in6ifa_ifpwithaddr(ifp, addr) - struct ifnet *ifp; - struct in6_addr *addr; +in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr) { struct ifaddr *ifa; @@ -3180,36 +2861,12 @@ in6_localaddr(struct in6_addr *in6) return (0); } -int -in6_is_addr_deprecated(struct sockaddr_in6 *sa6) -{ - struct in6_ifaddr *ia; - - lck_rw_lock_shared(&in6_ifaddr_rwlock); - for (ia = in6_ifaddrs; ia; ia = ia->ia_next) { - IFA_LOCK_SPIN(&ia->ia_ifa); - if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, - &sa6->sin6_addr) && - (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) { - IFA_UNLOCK(&ia->ia_ifa); - lck_rw_done(&in6_ifaddr_rwlock); - return (1); /* true */ - } - /* XXX: do we still have to go thru the rest of the list? */ - IFA_UNLOCK(&ia->ia_ifa); - } - - lck_rw_done(&in6_ifaddr_rwlock); - return (0); /* false */ -} - /* * return length of part which dst and src are equal * hard coding... */ int -in6_matchlen(src, dst) -struct in6_addr *src, *dst; +in6_matchlen(struct in6_addr *src, struct in6_addr *dst) { int match = 0; u_char *s = (u_char *)src, *d = (u_char *)dst; @@ -3229,9 +2886,7 @@ struct in6_addr *src, *dst; /* XXX: to be scope conscious */ int -in6_are_prefix_equal(p1, p2, len) - struct in6_addr *p1, *p2; - int len; +in6_are_prefix_equal(struct in6_addr *p1, struct in6_addr *p2, int len) { int bytelen, bitlen; @@ -3255,9 +2910,7 @@ in6_are_prefix_equal(p1, p2, len) } void -in6_prefixlen2mask(maskp, len) - struct in6_addr *maskp; - int len; +in6_prefixlen2mask(struct in6_addr *maskp, int len) { u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; int bytelen, bitlen, i; @@ -3727,6 +3380,12 @@ static void in6_if_up_dad_start(struct ifnet *ifp) { struct ifaddr *ifa; + struct nd_ifinfo *ndi = NULL; + + ndi = ND_IFINFO(ifp); + VERIFY((NULL != ndi) && (TRUE == ndi->initialized)); + if (!(ndi->flags & ND6_IFF_DAD)) + return; /* start DAD on all the interface addresses */ ifnet_lock_exclusive(ifp); @@ -3754,9 +3413,16 @@ int in6if_do_dad( struct ifnet *ifp) { + struct nd_ifinfo *ndi = NULL; + if ((ifp->if_flags & IFF_LOOPBACK) != 0) return (0); + ndi = ND_IFINFO(ifp); + VERIFY((NULL != ndi) && (TRUE == ndi->initialized)); + if (!(ndi->flags & ND6_IFF_DAD)) + return (0); + /* * If we are using the alternative neighbor discovery * interface on this interface, then skip DAD. @@ -3765,7 +3431,8 @@ in6if_do_dad( * for now, even when not marked as using the alternative * interface. This is for historical reasons. */ - if (ifp->if_eflags & (IFEF_IPV6_ND6ALT|IFEF_LOCALNET_PRIVATE)) + if (ifp->if_eflags & + (IFEF_IPV6_ND6ALT|IFEF_LOCALNET_PRIVATE|IFEF_DIRECTLINK)) return (0); switch (ifp->if_type) { @@ -3810,9 +3477,8 @@ in6_setmaxmtu(void) ifnet_head_lock_shared(); TAILQ_FOREACH(ifp, &ifnet_head, if_list) { - struct nd_ifinfo *ndi; + struct nd_ifinfo *ndi = NULL; - lck_rw_lock_shared(nd_if_rwlock); if ((ndi = ND_IFINFO(ifp)) != NULL && !ndi->initialized) ndi = NULL; if (ndi != NULL) @@ -3822,7 +3488,6 @@ in6_setmaxmtu(void) maxmtu = IN6_LINKMTU(ifp); if (ndi != NULL) lck_mtx_unlock(&ndi->lock); - lck_rw_done(nd_if_rwlock); } ifnet_head_done(); if (maxmtu) /* update only when maxmtu is positive */ @@ -3970,7 +3635,8 @@ in6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam) * are large enough to span 68 years. */ void -in6_post_msg(struct ifnet *ifp, u_int32_t event_code, struct in6_ifaddr *ifa) +in6_post_msg(struct ifnet *ifp, u_int32_t event_code, struct in6_ifaddr *ifa, + uint8_t *mac) { struct kev_msg ev_msg; struct kev_in6_data in6_event_data; @@ -4000,17 +3666,21 @@ in6_post_msg(struct ifnet *ifp, u_int32_t event_code, struct in6_ifaddr *ifa) IFA_UNLOCK(&ifa->ia_ifa); if (ifp != NULL) { - (void) strncpy(&in6_event_data.link_data.if_name[0], + (void) strlcpy(&in6_event_data.link_data.if_name[0], ifp->if_name, IFNAMSIZ); in6_event_data.link_data.if_family = ifp->if_family; in6_event_data.link_data.if_unit = (u_int32_t)ifp->if_unit; } + if (mac != NULL) + memcpy(&in6_event_data.ia_mac, mac, + sizeof(in6_event_data.ia_mac)); + ev_msg.dv[0].data_ptr = &in6_event_data; ev_msg.dv[0].data_length = sizeof (in6_event_data); ev_msg.dv[1].data_length = 0; - kev_post_msg(&ev_msg); + dlil_post_complete_msg(NULL, &ev_msg); } /* @@ -4167,40 +3837,6 @@ in6_ifaddr_trace(struct ifaddr *ifa, int refhold) ctrace_record(&tr[idx]); } -static void -in6_ifaddr_set_dadprogress(struct in6_ifaddr *ia) -{ - uint32_t flags = IN6_IFF_TENTATIVE; - uint32_t optdad = nd6_optimistic_dad; - - if (optdad && (ia->ia_ifp->if_eflags & IFEF_IPV6_ROUTER) == 0) { - if ((optdad & ND6_OPTIMISTIC_DAD_LINKLOCAL) && - IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) - flags = IN6_IFF_OPTIMISTIC; - else if ((optdad & ND6_OPTIMISTIC_DAD_AUTOCONF) && - (ia->ia6_flags & IN6_IFF_AUTOCONF)) { - if (ia->ia6_flags & IN6_IFF_TEMPORARY) { - if (optdad & ND6_OPTIMISTIC_DAD_TEMPORARY) - flags = IN6_IFF_OPTIMISTIC; - } else if (ia->ia6_flags & IN6_IFF_SECURED) { - if (optdad & ND6_OPTIMISTIC_DAD_SECURED) - flags = IN6_IFF_OPTIMISTIC; - } - } else if ((optdad & ND6_OPTIMISTIC_DAD_DYNAMIC) && - (ia->ia6_flags & IN6_IFF_DYNAMIC)) { - if (ia->ia6_flags & IN6_IFF_TEMPORARY) { - if (optdad & ND6_OPTIMISTIC_DAD_TEMPORARY) - flags = IN6_IFF_OPTIMISTIC; - } else { - flags = IN6_IFF_OPTIMISTIC; - } - } - } - - ia->ia6_flags &= ~(IN6_IFF_DUPLICATED | IN6_IFF_DADPROGRESS); - ia->ia6_flags |= flags; -} - /* * Handle SIOCGASSOCIDS ioctl for PF_INET6 domain. */ @@ -4208,13 +3844,13 @@ static int in6_getassocids(struct socket *so, uint32_t *cnt, user_addr_t aidp) { struct in6pcb *in6p = sotoin6pcb(so); - associd_t aid; + sae_associd_t aid; if (in6p == NULL || in6p->inp_state == INPCB_STATE_DEAD) return (EINVAL); /* IN6PCB has no concept of association */ - aid = ASSOCID_ANY; + aid = SAE_ASSOCID_ANY; *cnt = 0; /* just asking how many there are? */ @@ -4228,16 +3864,16 @@ in6_getassocids(struct socket *so, uint32_t *cnt, user_addr_t aidp) * Handle SIOCGCONNIDS ioctl for PF_INET6 domain. */ static int -in6_getconnids(struct socket *so, associd_t aid, uint32_t *cnt, +in6_getconnids(struct socket *so, sae_associd_t aid, uint32_t *cnt, user_addr_t cidp) { struct in6pcb *in6p = sotoin6pcb(so); - connid_t cid; + sae_connid_t cid; if (in6p == NULL || in6p->inp_state == INPCB_STATE_DEAD) return (EINVAL); - if (aid != ASSOCID_ANY && aid != ASSOCID_ALL) + if (aid != SAE_ASSOCID_ANY && aid != SAE_ASSOCID_ALL) return (EINVAL); /* if connected, return 1 connection count */ @@ -4248,7 +3884,7 @@ in6_getconnids(struct socket *so, associd_t aid, uint32_t *cnt, return (0); /* if IN6PCB is connected, assign it connid 1 */ - cid = ((*cnt != 0) ? 1 : CONNID_ANY); + cid = ((*cnt != 0) ? 1 : SAE_CONNID_ANY); return (copyout(&cid, cidp, sizeof (cid))); } @@ -4257,7 +3893,7 @@ in6_getconnids(struct socket *so, associd_t aid, uint32_t *cnt, * Handle SIOCGCONNINFO ioctl for PF_INET6 domain. */ static int -in6_getconninfo(struct socket *so, connid_t cid, uint32_t *flags, +in6_getconninfo(struct socket *so, sae_connid_t cid, uint32_t *flags, uint32_t *ifindex, int32_t *soerror, user_addr_t src, socklen_t *src_len, user_addr_t dst, socklen_t *dst_len, uint32_t *aux_type, user_addr_t aux_data, uint32_t *aux_len) @@ -4278,7 +3914,7 @@ in6_getconninfo(struct socket *so, connid_t cid, uint32_t *flags, goto out; } - if (cid != CONNID_ANY && cid != CONNID_ALL && cid != 1) { + if (cid != SAE_CONNID_ANY && cid != SAE_CONNID_ALL && cid != 1) { error = EINVAL; goto out; } @@ -4302,7 +3938,7 @@ in6_getconninfo(struct socket *so, connid_t cid, uint32_t *flags, /* source address and port */ sin6.sin6_port = in6p->in6p_lport; - bcopy(&in6p->in6p_laddr, &sin6.sin6_addr, sizeof (struct in6_addr)); + in6_recoverscope(&sin6, &in6p->in6p_laddr, NULL); if (*src_len == 0) { *src_len = sin6.sin6_len; } else { @@ -4317,7 +3953,7 @@ in6_getconninfo(struct socket *so, connid_t cid, uint32_t *flags, /* destination address and port */ sin6.sin6_port = in6p->in6p_fport; - bcopy(&in6p->in6p_faddr, &sin6.sin6_addr, sizeof (struct in6_addr)); + in6_recoverscope(&sin6, &in6p->in6p_faddr, NULL); if (*dst_len == 0) { *dst_len = sin6.sin6_len; } else { @@ -4377,9 +4013,6 @@ in6ioctl_cassert(void) case 0: /* bsd/netinet6/in6_var.h */ - case SIOCGETSGCNT_IN6: - case SIOCGETMIFCNT_IN6_32: - case SIOCGETMIFCNT_IN6_64: case SIOCAADDRCTL_POLICY: case SIOCDADDRCTL_POLICY: case SIOCDRADD_IN6_32: