+extern int in6_get_hw_ifid(struct ifnet *, struct in6_addr *);
+
+static int nd6_llreach_base = (LL_BASE_REACHABLE / 1000); /* seconds */
+
+SYSCTL_DECL(_net_inet6_icmp6);
+
+SYSCTL_INT(_net_inet6_icmp6, OID_AUTO, nd6_llreach_base,
+ CTLFLAG_RW | CTLFLAG_LOCKED, &nd6_llreach_base, LL_BASE_REACHABLE,
+ "default ND6 link-layer reachability max lifetime (in seconds)");
+
+#define SIN6(s) ((struct sockaddr_in6 *)s)
+
+/*
+ * Obtain a link-layer source cache entry for the sender.
+ *
+ * NOTE: This is currently only for ND6/Ethernet.
+ */
+void
+nd6_llreach_alloc(struct rtentry *rt, struct ifnet *ifp, void *addr,
+ unsigned int alen, boolean_t solicited)
+{
+ struct llinfo_nd6 *ln = rt->rt_llinfo;
+
+ if (nd6_llreach_base != 0 &&
+ ln->ln_expire != 0 && rt->rt_ifp != lo_ifp &&
+ ifp->if_addrlen == IF_LLREACH_MAXLEN && /* Ethernet */
+ alen == ifp->if_addrlen) {
+ struct if_llreach *lr;
+ const char *why = NULL, *type = "";
+
+ /* Become a regular mutex, just in case */
+ RT_CONVERT_LOCK(rt);
+
+ if ((lr = ln->ln_llreach) != NULL) {
+ type = (solicited ? "ND6 advertisement" :
+ "ND6 unsolicited announcement");
+ /*
+ * If target has changed, create a new record;
+ * otherwise keep existing record.
+ */
+ IFLR_LOCK(lr);
+ if (bcmp(addr, lr->lr_key.addr, alen) != 0) {
+ IFLR_UNLOCK(lr);
+ /* Purge any link-layer info caching */
+ VERIFY(rt->rt_llinfo_purge != NULL);
+ rt->rt_llinfo_purge(rt);
+ lr = NULL;
+ why = " for different target HW address; "
+ "using new llreach record";
+ } else {
+ lr->lr_probes = 0; /* reset probe count */
+ IFLR_UNLOCK(lr);
+ if (solicited) {
+ why = " for same target HW address; "
+ "keeping existing llreach record";
+ }
+ }
+ }
+
+ if (lr == NULL) {
+ lr = ln->ln_llreach = ifnet_llreach_alloc(ifp,
+ ETHERTYPE_IPV6, addr, alen, nd6_llreach_base);
+ if (lr != NULL) {
+ lr->lr_probes = 0; /* reset probe count */
+ if (why == NULL)
+ why = "creating new llreach record";
+ }
+ }
+
+ if (nd6_debug && lr != NULL && why != NULL) {
+ char tmp[MAX_IPv6_STR_LEN];
+
+ nd6log((LOG_DEBUG, "%s%d: %s%s for %s\n", ifp->if_name,
+ ifp->if_unit, type, why, inet_ntop(AF_INET6,
+ &SIN6(rt_key(rt))->sin6_addr, tmp, sizeof (tmp))));
+ }
+ }
+}
+
+void
+nd6_llreach_use(struct llinfo_nd6 *ln)
+{
+ if (ln->ln_llreach != NULL)
+ ln->ln_lastused = net_uptime();
+}
+