- log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "
- "NS in/out=%d/%d, NA in=%d inx=%d\n",
- if_name(ifp), ip6_sprintf(&ia->ia_addr.sin6_addr),
- dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount,
- dp->dad_na_ixcount);
- hwdupposs = dp->dad_na_ixcount;
+ nd6log((LOG_ERR, "%s: NS in/out/loopback=%d/%d, NA in=%d\n",
+ __func__, dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_ns_lcount,
+ dp->dad_na_icount));
+ candisable = FALSE;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr) &&
+ !(ia->ia6_flags & IN6_IFF_SECURED)) {
+ struct in6_addr in6;
+ struct ifaddr *llifa = NULL;
+ struct sockaddr_dl *sdl = NULL;
+ uint8_t *lladdr = dp->dad_lladdr;
+ uint8_t lladdrlen = dp->dad_lladdrlen;
+
+ /*
+ * To avoid over-reaction, we only apply this logic when we are
+ * very sure that hardware addresses are supposed to be unique.
+ */
+ switch (ifp->if_type) {
+ case IFT_BRIDGE:
+ case IFT_ETHER:
+ case IFT_FDDI:
+ case IFT_ATM:
+ case IFT_IEEE1394:
+#ifdef IFT_IEEE80211
+ case IFT_IEEE80211:
+#endif
+ /*
+ * Check if our hardware address matches the
+ * link layer information received in the
+ * NS/NA
+ */
+ llifa = ifp->if_lladdr;
+ IFA_LOCK(llifa);
+ sdl = (struct sockaddr_dl *)(void *)
+ llifa->ifa_addr;
+ if (lladdrlen == sdl->sdl_alen &&
+ bcmp(lladdr, LLADDR(sdl), lladdrlen) == 0) {
+ candisable = TRUE;
+ }
+ IFA_UNLOCK(llifa);
+
+ in6 = ia->ia_addr.sin6_addr;
+ if (in6_iid_from_hw(ifp, &in6) != 0) {
+ break;
+ }
+
+ /* Refine decision about whether IPv6 can be disabled */
+ if (candisable &&
+ !IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &in6)) {
+ /*
+ * Apply this logic only to the embedded MAC
+ * address form of link-local IPv6 address.
+ */
+ candisable = FALSE;
+ } else if (lladdr == NULL &&
+ IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &in6)) {
+ /*
+ * We received a NA with no target link-layer
+ * address option. This means that someone else
+ * has our address. Mark it as a hardware
+ * duplicate so we disable IPv6 later on.
+ */
+ candisable = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ }