+ sdl->sdl_slen = 0;
+ break;
+ }
+ case AF_LINK: {
+ struct sockaddr_dl *sdla = (struct sockaddr_dl *)(void *)sa;
+ struct in6_addr *in6 = &sin6->sin6_addr;
+ caddr_t lla = LLADDR(sdla);
+
+ VERIFY(sa->sa_len <= sizeof *sdl);
+ bcopy(sa, sdl, sa->sa_len);
+
+ sin6->sin6_scope_id = sdla->sdl_index;
+ if (sin6->sin6_scope_id == 0)
+ sin6->sin6_scope_id = ifp->if_index;
+ in6->s6_addr[0] = 0xfe;
+ in6->s6_addr[1] = 0x80;
+ if (sdla->sdl_alen == EUI64_LENGTH)
+ bcopy(lla, &in6->s6_addr[8], EUI64_LENGTH);
+ else {
+ VERIFY(sdla->sdl_alen == ETHER_ADDR_LEN);
+
+ in6->s6_addr[8] = ((uint8_t) lla[0] ^ ND6_EUI64_UBIT);
+ in6->s6_addr[9] = (uint8_t) lla[1];
+ in6->s6_addr[10] = (uint8_t) lla[2];
+ in6->s6_addr[11] = 0xff;
+ in6->s6_addr[12] = 0xfe;
+ in6->s6_addr[13] = (uint8_t) lla[3];
+ in6->s6_addr[14] = (uint8_t) lla[4];
+ in6->s6_addr[15] = (uint8_t) lla[5];
+ }
+
+ break;
+ }
+ default:
+ VERIFY(false);
+ break;
+ }
+}
+
+void
+nd6_alt_node_present(struct ifnet *ifp, struct sockaddr_in6 *sin6,
+ struct sockaddr_dl *sdl, int32_t rssi, int lqm, int npm)
+{
+ struct rtentry *rt;
+ struct llinfo_nd6 *ln;
+ struct if_llreach *lr;
+
+ nd6_cache_lladdr(ifp, &sin6->sin6_addr, LLADDR(sdl), sdl->sdl_alen,
+ ND_NEIGHBOR_ADVERT, 0);
+
+ lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_NOTOWNED);
+ lck_mtx_lock(rnh_lock);
+
+ rt = rtalloc1_scoped_locked((struct sockaddr *)sin6, 1, 0,
+ ifp->if_index);
+ if (rt != NULL) {
+ RT_LOCK(rt);
+ VERIFY(rt->rt_flags & RTF_LLINFO);
+ VERIFY(rt->rt_llinfo);
+
+ ln = rt->rt_llinfo;
+ ln->ln_state = ND6_LLINFO_REACHABLE;
+ ln_setexpire(ln, 0);
+
+ lr = ln->ln_llreach;
+ if (lr) {
+ IFLR_LOCK(lr);
+ lr->lr_rssi = rssi;
+ lr->lr_lqm = (int32_t) lqm;
+ lr->lr_npm = (int32_t) npm;
+ IFLR_UNLOCK(lr);
+ }
+
+ RT_UNLOCK(rt);
+ RT_REMREF(rt);
+ }
+
+ lck_mtx_unlock(rnh_lock);
+
+ if (rt == NULL) {
+ log(LOG_ERR, "%s: failed to add/update host route to %s.\n",
+ __func__, ip6_sprintf(&sin6->sin6_addr));
+ } else {
+ nd6log((LOG_DEBUG, "%s: host route to %s [lr=0x%llx]\n",
+ __func__, ip6_sprintf(&sin6->sin6_addr),
+ (uint64_t)VM_KERNEL_ADDRPERM(lr)));
+ }
+}
+
+void
+nd6_alt_node_absent(struct ifnet *ifp, struct sockaddr_in6 *sin6)
+{
+ struct rtentry *rt;
+
+ nd6log((LOG_DEBUG, "%s: host route to %s\n", __func__,
+ ip6_sprintf(&sin6->sin6_addr)));
+
+ lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_NOTOWNED);
+ lck_mtx_lock(rnh_lock);
+
+ rt = rtalloc1_scoped_locked((struct sockaddr *)sin6, 0, 0,
+ ifp->if_index);
+ if (rt != NULL) {
+ RT_LOCK(rt);
+
+ if (!(rt->rt_flags & (RTF_CLONING|RTF_PRCLONING)) &&
+ (rt->rt_flags & (RTF_HOST|RTF_LLINFO|RTF_WASCLONED)) ==
+ (RTF_HOST|RTF_LLINFO|RTF_WASCLONED)) {
+ rt->rt_flags |= RTF_CONDEMNED;
+ RT_UNLOCK(rt);
+
+ (void) rtrequest_locked(RTM_DELETE, rt_key(rt),
+ (struct sockaddr *)NULL, rt_mask(rt), 0,
+ (struct rtentry **)NULL);
+
+ rtfree_locked(rt);
+ } else {
+ RT_REMREF_LOCKED(rt);
+ RT_UNLOCK(rt);
+ }
+ }
+
+ lck_mtx_unlock(rnh_lock);