version 379.32.1
diff --git a/Makefile b/Makefile
index a52bb1c..e15b89c 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 include $(MAKEFILEPATH)/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-379.27.1"
+MVERS = "mDNSResponder-379.32.1"
 
 DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
 VER = 
diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c
index 75d9b32..51eaf67 100755
--- a/mDNSCore/mDNS.c
+++ b/mDNSCore/mDNS.c
@@ -5507,43 +5507,44 @@
     SendResponses(m);
 }
 
+/*
+ * This function attempts to detect if multiple interfaces are on the same subnet.
+ * It makes this determination based only on the IPv4 Addresses and subnet masks.
+ * IPv6 link local addresses that are configured by default on all interfaces make
+ * it hard to make this determination
+ *
+ * The 'real' fix for this would be to send out multicast packets over one interface
+ * and conclude that multiple interfaces are on the same subnet only if these packets
+ * are seen on other interfaces on the same system
+ */
 mDNSlocal mDNSBool skipSameSubnetRegistration(mDNS *const m, mDNSInterfaceID *regID, mDNSu32 count, mDNSInterfaceID intfid)
 {
     NetworkInterfaceInfo *intf;
     NetworkInterfaceInfo *newIntf;
     mDNSu32 i;
 
-    newIntf = FirstInterfaceForID(m, intfid);
-    if (newIntf == mDNSNULL)
+    for (newIntf = FirstInterfaceForID(m, intfid); newIntf; newIntf = newIntf->next)
     {
-        LogMsg("%s : Could not get Interface for id %d", __func__, intfid);
-        return (mDNSfalse);
-    }
-
-    for ( i = 0; i < count; i++)
-    {
-        intf = FirstInterfaceForID(m, regID[i]);
-        if (intf == mDNSNULL)
+        if ((newIntf->InterfaceID != intfid) ||
+            (newIntf->ip.type     != mDNSAddrType_IPv4))
         {
-            LogMsg("%s : Could not get Interface for id %d", __func__, regID[i]);
-            return (mDNSfalse);
+            continue;
         }
-
-        if ((newIntf->ip.type == mDNSAddrType_IPv4) &&
-            (((intf->ip.ip.v4.NotAnInteger ^ newIntf->ip.ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0))
+        for ( i = 0; i < count; i++)
         {
-            LogSPS("%s : Already registered for the same subnet (IPv4) for interface %s", __func__, intf->ifname);
-            return (mDNStrue);
-        }
-
-        if ( (newIntf->ip.type == mDNSAddrType_IPv6) &&
-             ((((intf->ip.ip.v6.l[0] ^ newIntf->ip.ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
-              (((intf->ip.ip.v6.l[1] ^ newIntf->ip.ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
-              (((intf->ip.ip.v6.l[2] ^ newIntf->ip.ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
-              (((intf->ip.ip.v6.l[3] ^ newIntf->ip.ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0)))
-        {
-            LogSPS("%s : Already registered for the same subnet (IPv6) for interface %s", __func__, intf->ifname);
-            return (mDNStrue);
+            for (intf = FirstInterfaceForID(m, regID[i]); intf; intf = intf->next)
+            {
+                if ((intf->InterfaceID != regID[i]) ||
+                    (intf->ip.type     != mDNSAddrType_IPv4))
+                {
+                    continue;
+                }
+                if ((intf->ip.ip.v4.NotAnInteger & intf->mask.ip.v4.NotAnInteger) == (newIntf->ip.ip.v4.NotAnInteger & newIntf->mask.ip.v4.NotAnInteger))
+                {
+                    LogSPS("%s : Already registered for the same subnet (IPv4) for interface %s", __func__, intf->ifname);
+                    return (mDNStrue);
+                }
+            }
         }
     }
     return (mDNSfalse);
diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c
index d33e100..e48ce48 100644
--- a/mDNSMacOSX/mDNSMacOSX.c
+++ b/mDNSMacOSX/mDNSMacOSX.c
@@ -227,7 +227,15 @@
 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
 mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len);
 
-static ARListElem *D2DRecords = NULL; // List of locally-generated PTR records to records found via D2D
+typedef struct D2DRecordListElem
+{
+    struct D2DRecordListElem *next;
+    AuthRecord               ar;
+    D2DServiceInstance       instanceHandle;
+    D2DTransportType         transportType;
+} D2DRecordListElem;
+
+static D2DRecordListElem *D2DRecords = NULL; // List of records returned with D2DServiceFound events
 
 typedef struct D2DBrowseListElem
 {
@@ -388,8 +396,8 @@
     (void)m;  // unused
     if (result == mStatus_MemFree)
     {
-        ARListElem **ptr = &D2DRecords;
-        ARListElem *tmp;
+        D2DRecordListElem **ptr = &D2DRecords;
+        D2DRecordListElem *tmp;
         while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
         if (!*ptr) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m, rr)); return; }
         LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m, rr));
@@ -400,9 +408,26 @@
     }
 }
 
+mDNSexport void external_connection_release(const domainname *instance)
+{
+    (void) instance;
+    D2DRecordListElem *ptr = D2DRecords;
+
+    for ( ; ptr ; ptr = ptr->next)
+    {
+        if ((ptr->ar.resrec.rrtype == kDNSServiceType_PTR) &&
+             SameDomainName(&ptr->ar.rdatastorage.u.name, instance))
+        {
+            LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d", 
+                ptr->instanceHandle,  ptr->transportType);
+            if (D2DRelease) D2DRelease(ptr->instanceHandle, ptr->transportType);
+        }
+    }
+}
+
 mDNSlocal void xD2DClearCache(const domainname *regType)
 {
-    ARListElem *ptr = D2DRecords;
+    D2DRecordListElem *ptr = D2DRecords;
     for ( ; ptr ; ptr = ptr->next)
     {
         if (SameDomainName(&ptr->ar.namestorage, regType))
@@ -476,15 +501,12 @@
 
 mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
 {
-    (void)transportType; // We don't care about this, yet.
-    (void)instanceHandle; // We don't care about this, yet.
-
     if (result == kD2DSuccess)
     {
         if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
 
         mStatus err;
-        ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(ARListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
+        D2DRecordListElem *ptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
 
         if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
 
@@ -505,6 +527,8 @@
         }
 
         LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar));
+        ptr->instanceHandle = instanceHandle;
+        ptr->transportType = transportType;
         ptr->next = D2DRecords;
         D2DRecords = ptr;
     }
@@ -512,14 +536,14 @@
         LogMsg("xD2DAddToCache: Unexpected result %d", result);
 }
 
-mDNSlocal ARListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
+mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
 {
-    ARListElem *ptr = D2DRecords;
-    ARListElem *arptr;
+    D2DRecordListElem *ptr = D2DRecords;
+    D2DRecordListElem *arptr;
 
     if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
 
-    arptr = mDNSPlatformMemAllocate(sizeof(ARListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
+    arptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
     if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; }
 
     if (xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr->ar) != mStatus_NoError)
@@ -547,7 +571,7 @@
 
     if (result == kD2DSuccess)
     {
-        ARListElem *ptr = xD2DFindInList(m, key, keySize, value, valueSize);
+        D2DRecordListElem *ptr = xD2DFindInList(m, key, keySize, value, valueSize);
         if (ptr)
         {
             LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m, &ptr->ar));
@@ -9349,10 +9373,6 @@
 // with the kDNSServiceFlagsIncludeAWDL flag set.
 mDNSexport mDNSBool   mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
 {
-    // Don't do AWDL specific filtering if AWDL support is not enabled.
-    if (!mDNSStorage.mDNSHandlePeerEvents)
-        return mDNStrue;
-
     if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
         return mDNStrue;
 
diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h
index b17944f..8ff872e 100644
--- a/mDNSShared/dns_sd.h
+++ b/mDNSShared/dns_sd.h
@@ -77,7 +77,7 @@
  */
 
 #ifndef _DNS_SD_H
-#define _DNS_SD_H 3792701
+#define _DNS_SD_H 3793201
 
 #ifdef  __cplusplus
 extern "C" {
@@ -627,9 +627,9 @@
  *   DNSServiceQueryRecord, it restricts the operation to P2P.
  *
  * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceResolve, it is
- *   mapped internally to kDNSServiceInterfaceIndexAny, because resolving
- *   a P2P service may create and/or enable an interface whose index is not
- *   known a priori. The resolve callback will indicate the index of the
+ *   mapped internally to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
+ *   set, because resolving a P2P service may create and/or enable an interface whose 
+ *   index is not known a priori. The resolve callback will indicate the index of the
  *   interface via which the service can be accessed.
  *
  * If applications pass kDNSServiceInterfaceIndexAny to DNSServiceBrowse
@@ -1792,7 +1792,6 @@
     const void                         *rdata
 );
 
-
 /*********************************************************************************************
 *
 *  NAT Port Mapping
diff --git a/mDNSShared/dnssd_clientshim.c b/mDNSShared/dnssd_clientshim.c
index 3a5ed57..fffeeab 100644
--- a/mDNSShared/dnssd_clientshim.c
+++ b/mDNSShared/dnssd_clientshim.c
@@ -794,4 +794,5 @@
     (void)rdata;            // Unused
     return(kDNSServiceErr_Unsupported);
 }
-#endif
+
+#endif  // !MDNS_BUILDINGSTUBLIBRARY
diff --git a/mDNSShared/dnssd_ipc.h b/mDNSShared/dnssd_ipc.h
index 746ac58..bb3b0df 100644
--- a/mDNSShared/dnssd_ipc.h
+++ b/mDNSShared/dnssd_ipc.h
@@ -135,6 +135,7 @@
     port_mapping_request,   // New in Leopard and B4W 2.0
     addrinfo_request,
     send_bpf,               // New in SL
+    release_request,
 
     cancel_request = 63
 } request_op_t;
diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c
index 1c1898a..2514986 100644
--- a/mDNSShared/uds_daemon.c
+++ b/mDNSShared/uds_daemon.c
@@ -3292,6 +3292,54 @@
     return(status);
 }
 
+#if APPLE_OSX_mDNSResponder
+
+mDNSlocal mStatus handle_release_request(request_state *request)
+{
+    mStatus err = 0;
+    char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
+    domainname instance;
+
+    // extract the data from the message
+    DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+
+    if (get_string(&request->msgptr, request->msgend, name, 256) < 0 ||
+        get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+        get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
+    {
+        LogMsg("ERROR: handle_release_request - Couldn't read name/regtype/domain");
+        return(mStatus_BadParamErr);
+    }
+
+    if (!request->msgptr)
+    {
+        LogMsg("%3d: PeerConnectionRelease(unreadable parameters)", request->sd);
+        return(mStatus_BadParamErr);
+    }
+
+    if (build_domainname_from_strings(&instance, name, regtype, domain) < 0)
+    {
+        LogMsg("ERROR: handle_release_request bad “%s” “%s” “%s”", name, regtype, domain);
+        return(mStatus_BadParamErr);
+    }
+
+    LogOperation("%3d: PeerConnectionRelease(%X %##s) START PID[%d](%s)",
+        request->sd, flags, instance.c, get_peer_pid(request->sd, pid_name), pid_name);
+    
+    external_connection_release(&instance);
+    return(err);
+}
+
+#else   // APPLE_OSX_mDNSResponder
+
+mDNSlocal mStatus handle_release_request(request_state *request)
+{
+    (void) request; 
+    return mStatus_UnsupportedErr;
+}
+
+#endif  // APPLE_OSX_mDNSResponder
+
 mDNSlocal mStatus handle_setdomain_request(request_state *request)
 {
     char domainstr[MAX_ESCAPED_DOMAIN_NAME];
@@ -3899,6 +3947,7 @@
         case addrinfo_request:         min_size += sizeof(mDNSu32) + 4 /* v4/v6 */   + 1 /* hostname */;                       break;
         case send_bpf:                     // Same as cancel_request below
         case cancel_request:           min_size = 0;                                                                           break;
+        case release_request:          min_size += sizeof(mDNSu32) + 3 /* type, type, domain */;                               break;
         default: LogMsg("ERROR: validate_message - unsupported req type: %d", req->hdr.op); min_size = -1;                     break;
         }
 
@@ -3956,6 +4005,7 @@
             case update_record_request:        err = handle_update_request      (req);  break;
             case remove_record_request:        err = handle_removerecord_request(req);  break;
             case cancel_request:                     handle_cancel_request      (req);  break;
+            case release_request:              err = handle_release_request     (req);  break;
             default: LogMsg("%3d: ERROR: Unsupported UDS req: %d", req->sd, req->hdr.op);
             }
 
diff --git a/mDNSShared/uds_daemon.h b/mDNSShared/uds_daemon.h
index 3f0d38d..5254946 100644
--- a/mDNSShared/uds_daemon.h
+++ b/mDNSShared/uds_daemon.h
@@ -66,6 +66,7 @@
 extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
 extern void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
 extern void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
+extern void external_connection_release(const domainname *instance);
 #else
 #define external_start_browsing_for_service(A,B,C,D) (void)(A)
 #define external_stop_browsing_for_service(A,B,C,D)  (void)(A)
@@ -73,6 +74,7 @@
 #define external_stop_advertising_service(A,B)       (void)(A)
 #define external_start_resolving_service(A,B,C)      (void)(A)
 #define external_stop_resolving_service(A,B,C)       (void)(A)
+#define external_connection_release(A)               (void)(A)
 #endif // APPLE_OSX_mDNSResponder
 
 extern const char mDNSResponderVersionString_SCCS[];