+
+void
+in6_ifaddr_set_dadprogress(struct in6_ifaddr *ia)
+{
+ struct ifnet* ifp = ia->ia_ifp;
+ uint32_t flags = IN6_IFF_TENTATIVE;
+ uint32_t optdad = nd6_optimistic_dad;
+ struct nd_ifinfo *ndi = NULL;
+
+ ndi = ND_IFINFO(ifp);
+ VERIFY((NULL != ndi) && (TRUE == ndi->initialized));
+ if (!(ndi->flags & ND6_IFF_DAD))
+ return;
+
+ if (optdad) {
+ if ((ifp->if_eflags & IFEF_IPV6_ROUTER) != 0) {
+ optdad = 0;
+ } else {
+ lck_mtx_lock(&ndi->lock);
+ if ((ndi->flags & ND6_IFF_REPLICATED) != 0) {
+ optdad = 0;
+ }
+ lck_mtx_unlock(&ndi->lock);
+ }
+ }
+
+ if (optdad) {
+ 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 {
+ /*
+ * Keeping the behavior for temp and CGA
+ * SLAAC addresses to have a knob for optimistic
+ * DAD.
+ * Other than that if ND6_OPTIMISTIC_DAD_AUTOCONF
+ * is set, we should default to optimistic
+ * DAD.
+ * For now this means SLAAC addresses with interface
+ * identifier derived from modified EUI-64 bit
+ * identifiers.
+ */
+ 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;
+ }
+ } else if ((optdad & ND6_OPTIMISTIC_DAD_MANUAL) &&
+ (ia->ia6_flags & IN6_IFF_OPTIMISTIC)) {
+ /*
+ * rdar://17483438
+ * Bypass tentative for address assignments
+ * not covered above (e.g. manual) upon request
+ */
+ if (!IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr) &&
+ !(ia->ia6_flags & IN6_IFF_AUTOCONF) &&
+ !(ia->ia6_flags & IN6_IFF_DYNAMIC))
+ flags = IN6_IFF_OPTIMISTIC;
+ }
+ }
+
+ ia->ia6_flags &= ~(IN6_IFF_DUPLICATED | IN6_IFF_DADPROGRESS);
+ ia->ia6_flags |= flags;
+
+ nd6log2((LOG_DEBUG, "%s - %s ifp %s ia6_flags 0x%x\n",
+ __func__,
+ ip6_sprintf(&ia->ia_addr.sin6_addr),
+ if_name(ia->ia_ifp),
+ ia->ia6_flags));
+}
+