]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/D2D.c
mDNSResponder-1310.60.4.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / D2D.c
1 /*
2 * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "D2D.h"
18 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
19 #include "DNSCommon.h"
20 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
21 #include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
22 #include "dns_sd_internal.h"
23 #include "uds_daemon.h"
24 #include "BLE.h"
25 #include "mdns_powerlog.h"
26
27 D2DStatus D2DInitialize(CFRunLoopRef runLoop, D2DServiceCallback serviceCallback, void* userData) __attribute__((weak_import));
28 D2DStatus D2DRetain(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
29 D2DStatus D2DStopAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
30 D2DStatus D2DRelease(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
31 D2DStatus D2DStartAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
32 D2DStatus D2DStartBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
33 D2DStatus D2DStopBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
34 void D2DStartResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
35 void D2DStopResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
36 D2DStatus D2DTerminate(void) __attribute__((weak_import));
37
38 #pragma mark - D2D Support
39
40 mDNSexport void D2D_start_advertising_interface(NetworkInterfaceInfo *interface)
41 {
42 // AWDL wants the address and reverse address PTR record communicated
43 // via the D2D interface layer.
44 if (interface->InterfaceID == AWDLInterfaceID)
45 {
46 // only log if we have a valid record to start advertising
47 if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
48 LogInfo("D2D_start_advertising_interface: %s", interface->ifname);
49
50 if (interface->RR_A.resrec.RecordType)
51 external_start_advertising_service(&interface->RR_A.resrec, 0, 0);
52 if (interface->RR_PTR.resrec.RecordType)
53 external_start_advertising_service(&interface->RR_PTR.resrec, 0, 0);
54 }
55 }
56
57 mDNSexport void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface)
58 {
59 if (interface->InterfaceID == AWDLInterfaceID)
60 {
61 // only log if we have a valid record to stop advertising
62 if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
63 LogInfo("D2D_stop_advertising_interface: %s", interface->ifname);
64
65 if (interface->RR_A.resrec.RecordType)
66 external_stop_advertising_service(&interface->RR_A.resrec, 0, 0);
67 if (interface->RR_PTR.resrec.RecordType)
68 external_stop_advertising_service(&interface->RR_PTR.resrec, 0, 0);
69 }
70 }
71
72 // If record would have been advertised to the D2D plugin layer, stop that advertisement.
73 mDNSexport void D2D_stop_advertising_record(AuthRecord *ar)
74 {
75 DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType);
76 if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags))
77 {
78 external_stop_advertising_service(&ar->resrec, flags, 0);
79 }
80 }
81
82 // If record should be advertised to the D2D plugin layer, start that advertisement.
83 mDNSexport void D2D_start_advertising_record(AuthRecord *ar)
84 {
85 DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType);
86 if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags))
87 {
88 external_start_advertising_service(&ar->resrec, flags, 0);
89 }
90 }
91
92 // Name compression items for fake packet version number 1
93 static const mDNSu8 compression_packet_v1 = 0x01;
94
95 static DNSMessage compression_base_msg = { { {{0}}, {{0}}, 2, 0, 0, 0 }, "\x04_tcp\x05local\x00\x00\x0C\x00\x01\x04_udp\xC0\x11\x00\x0C\x00\x01" };
96 static mDNSu8 *const compression_limit = (mDNSu8 *) &compression_base_msg + sizeof(DNSMessage);
97 static mDNSu8 *const compression_lhs = (mDNSu8 *const) compression_base_msg.data + 27;
98
99 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
100
101 typedef struct D2DRecordListElem
102 {
103 struct D2DRecordListElem *next;
104 D2DServiceInstance instanceHandle;
105 D2DTransportType transportType;
106 AuthRecord ar; // must be last in the structure to accomodate extra space
107 // allocated for large records.
108 } D2DRecordListElem;
109
110 static D2DRecordListElem *D2DRecords = NULL; // List of records returned with D2DServiceFound events
111
112 typedef struct D2DBrowseListElem
113 {
114 struct D2DBrowseListElem *next;
115 domainname name;
116 mDNSu16 type;
117 unsigned int refCount;
118 } D2DBrowseListElem;
119
120 D2DBrowseListElem* D2DBrowseList = NULL;
121
122 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
123 {
124 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
125 ptr[1] = (mDNSu8)((val ) & 0xFF);
126 return ptr + sizeof(mDNSu16);
127 }
128
129 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
130 {
131 ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
132 ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
133 ptr[2] = (mDNSu8)((val >> 8) & 0xFF);
134 ptr[3] = (mDNSu8)((val ) & 0xFF);
135 return ptr + sizeof(mDNSu32);
136 }
137
138 mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out)
139 {
140 const mDNSu8 * const start = (const mDNSu8 * const)in;
141 mDNSu8 *ptr = (mDNSu8*)start;
142 while(*ptr)
143 {
144 mDNSu8 c = *ptr;
145 out->c[ptr-start] = *ptr;
146 ptr++;
147 for (; c; c--,ptr++) out->c[ptr-start] = mDNSIsUpperCase(*ptr) ? (*ptr - 'A' + 'a') : *ptr;
148 }
149 out->c[ptr-start] = *ptr;
150 }
151
152 mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname* typeDomain, DNS_TypeValues qtype)
153 {
154 mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain);
155 if (!ptr) return ptr;
156 *ptr = (qtype >> 8) & 0xff;
157 ptr += 1;
158 *ptr = qtype & 0xff;
159 ptr += 1;
160 *ptr = compression_packet_v1;
161 return ptr + 1;
162 }
163
164 mDNSlocal mDNSu8 * DNSNameCompressionBuildRHS(mDNSu8 *start, const ResourceRecord *const resourceRecord)
165 {
166 return putRData(&compression_base_msg, start, compression_limit, resourceRecord);
167 }
168
169 mDNSlocal void PrintHelper(const char *const tag, mDNSu8 *lhs, mDNSu16 lhs_len, mDNSu8 *rhs, mDNSu16 rhs_len)
170 {
171 if (mDNS_LoggingEnabled)
172 {
173 LogDebug("%s: LHS: (%d bytes) %.*H", tag, lhs_len, lhs_len, lhs);
174 if (rhs) LogDebug("%s: RHS: (%d bytes) %.*H", tag, rhs_len, rhs_len, rhs);
175 }
176 }
177
178 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
179 {
180 (void)m; // unused
181 if (result == mStatus_MemFree)
182 {
183 D2DRecordListElem **ptr = &D2DRecords;
184 D2DRecordListElem *tmp;
185 while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
186 if (!*ptr) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m, rr)); return; }
187 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m, rr));
188 tmp = *ptr;
189 *ptr = (*ptr)->next;
190 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
191 mDNSPlatformMemFree(tmp);
192 }
193 }
194
195 mDNSexport void external_connection_release(const domainname *instance)
196 {
197 (void) instance;
198 D2DRecordListElem *ptr = D2DRecords;
199
200 for ( ; ptr ; ptr = ptr->next)
201 {
202 if ((ptr->ar.resrec.rrtype == kDNSServiceType_PTR) &&
203 SameDomainName(&ptr->ar.rdatastorage.u.name, instance))
204 {
205 LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d",
206 ptr->instanceHandle, ptr->transportType);
207 if (D2DRelease) D2DRelease(ptr->instanceHandle, ptr->transportType);
208 }
209 }
210 }
211
212 mDNSlocal void xD2DClearCache(const domainname *regType, DNS_TypeValues qtype)
213 {
214 D2DRecordListElem *ptr = D2DRecords;
215 for ( ; ptr ; ptr = ptr->next)
216 {
217 if ((ptr->ar.resrec.rrtype == qtype) && SameDomainName(&ptr->ar.namestorage, regType))
218 {
219 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar));
220 mDNS_Deregister(&mDNSStorage, &ptr->ar);
221 }
222 }
223 }
224
225 mDNSlocal D2DBrowseListElem ** D2DFindInBrowseList(const domainname *const name, mDNSu16 type)
226 {
227 D2DBrowseListElem **ptr = &D2DBrowseList;
228
229 for ( ; *ptr; ptr = &(*ptr)->next)
230 if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name))
231 break;
232
233 return ptr;
234 }
235
236 mDNSlocal unsigned int D2DBrowseListRefCount(const domainname *const name, mDNSu16 type)
237 {
238 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
239 return *ptr ? (*ptr)->refCount : 0;
240 }
241
242 mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type)
243 {
244 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
245
246 if (!*ptr)
247 {
248 *ptr = (D2DBrowseListElem *) mDNSPlatformMemAllocateClear(sizeof(**ptr));
249 (*ptr)->type = type;
250 AssignDomainName(&(*ptr)->name, name);
251 }
252 (*ptr)->refCount += 1;
253
254 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
255 }
256
257 // Returns true if found in list, false otherwise
258 mDNSlocal bool D2DBrowseListRelease(const domainname *const name, mDNSu16 type)
259 {
260 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
261
262 if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return false; }
263
264 (*ptr)->refCount -= 1;
265
266 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
267
268 if (!(*ptr)->refCount)
269 {
270 D2DBrowseListElem *tmp = *ptr;
271 *ptr = (*ptr)->next;
272 mDNSPlatformMemFree(tmp);
273 }
274 return true;
275 }
276
277 mDNSlocal mStatus xD2DParse(const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, D2DRecordListElem **D2DListp)
278 {
279 mDNS *const m = &mDNSStorage;
280
281 // Sanity check that key array (lhs) has one domain name, followed by the record type and single byte D2D
282 // plugin protocol version number.
283 // Note, we don't have a DNSMessage pointer at this point, so just pass in the lhs value as the lower bound
284 // of the input bytes we are processing. skipDomainName() does not try to follow name compression pointers,
285 // so it is safe to pass it the key byte array since it will stop parsing the DNS name and return a pointer
286 // to the byte after the first name compression pointer it encounters.
287 const mDNSu8 *keyp = skipDomainName((const DNSMessage *const) lhs, lhs, lhs + lhs_len);
288
289 // There should be 3 bytes remaining in a valid key,
290 // two for the DNS record type, and one for the D2D protocol version number.
291 if (keyp == NULL || (keyp + 3 != (lhs + lhs_len)))
292 {
293 LogInfo("xD2DParse: Could not parse DNS name in key");
294 return mStatus_Incompatible;
295 }
296 keyp += 2; // point to D2D compression packet format version byte
297 if (*keyp != compression_packet_v1)
298 {
299 LogInfo("xD2DParse: Invalid D2D packet version: %d", *keyp);
300 return mStatus_Incompatible;
301 }
302
303 if (mDNS_LoggingEnabled)
304 {
305 const int len = (int)(compression_lhs - (mDNSu8*)&compression_base_msg);
306 LogInfo("xD2DParse: Static Bytes: (%d bytes) %.*H", len, len, &compression_base_msg);
307 }
308
309 mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet
310
311 // Check to make sure we're not going to go past the end of the DNSMessage data
312 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
313 if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr;
314
315 // Copy the LHS onto our fake wire packet
316 mDNSPlatformMemCopy(ptr, lhs, lhs_len);
317 ptr += lhs_len - 1;
318
319 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
320 if (*ptr != compression_packet_v1) return mStatus_Incompatible;
321
322 // two bytes of CLASS
323 ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet);
324
325 // four bytes of TTL
326 ptr = putVal32(ptr, 120);
327
328 // Copy the RHS length into the RDLENGTH of our fake wire packet
329 ptr = putVal16(ptr, rhs_len);
330
331 // Copy the RHS onto our fake wire packet
332 mDNSPlatformMemCopy(ptr, rhs, rhs_len);
333 ptr += rhs_len;
334
335 if (mDNS_LoggingEnabled)
336 {
337 const int len = (int)(ptr - compression_lhs);
338 LogInfo("xD2DParse: Our Bytes (%d bytes): %.*H", len, len, compression_lhs);
339 }
340
341 ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec);
342 if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative)
343 {
344 LogMsg("xD2DParse: failed to get large RR");
345 m->rec.r.resrec.RecordType = 0;
346 return mStatus_UnknownErr;
347 }
348 else
349 {
350 LogInfo("xD2DParse: got rr: %s", CRDisplayString(m, &m->rec.r));
351 }
352
353 *D2DListp = (D2DRecordListElem *) mDNSPlatformMemAllocateClear(sizeof(D2DRecordListElem) + (m->rec.r.resrec.rdlength <= sizeof(RDataBody) ? 0 : m->rec.r.resrec.rdlength - sizeof(RDataBody)));
354 if (!*D2DListp) return mStatus_NoMemoryErr;
355
356 AuthRecord *rr = &(*D2DListp)->ar;
357 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL);
358 AssignDomainName(&rr->namestorage, &m->rec.namestorage);
359 rr->resrec.rdlength = m->rec.r.resrec.rdlength;
360 rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
361 mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength);
362 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
363 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
364
365 m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use
366
367 return mStatus_NoError;
368 }
369
370 mDNSexport void xD2DAddToCache(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
371 {
372 mDNS *const m = &mDNSStorage;
373 if (result == kD2DSuccess)
374 {
375 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
376
377 mStatus err;
378 D2DRecordListElem *ptr = NULL;
379
380 err = xD2DParse((const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr);
381 if (err)
382 {
383 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err);
384 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
385 if (ptr)
386 mDNSPlatformMemFree(ptr);
387 return;
388 }
389
390 #if ENABLE_BLE_TRIGGERED_BONJOUR
391 // If the record was created based on a BLE beacon, update the interface index to indicate
392 // this and thus match BLE specific queries.
393 if (transportType == D2DBLETransport)
394 ptr->ar.resrec.InterfaceID = mDNSInterface_BLE;
395 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
396
397 err = mDNS_Register(m, &ptr->ar);
398 if (err)
399 {
400 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err, ARDisplayString(m, &ptr->ar));
401 mDNSPlatformMemFree(ptr);
402 return;
403 }
404
405 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar));
406 ptr->instanceHandle = instanceHandle;
407 ptr->transportType = transportType;
408 ptr->next = D2DRecords;
409 D2DRecords = ptr;
410 }
411 else
412 LogMsg("xD2DAddToCache: Unexpected result %d", result);
413 }
414
415 mDNSlocal D2DRecordListElem * xD2DFindInList(const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
416 {
417 D2DRecordListElem *ptr = D2DRecords;
418 D2DRecordListElem *arptr = NULL;
419
420 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
421
422 mStatus err = xD2DParse((const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr);
423 if (err)
424 {
425 LogMsg("xD2DFindInList: xD2DParse returned error: %d", err);
426 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
427 if (arptr)
428 mDNSPlatformMemFree(arptr);
429 return NULL;
430 }
431
432 while (ptr)
433 {
434 if (IdenticalResourceRecord(&arptr->ar.resrec, &ptr->ar.resrec)) break;
435 ptr = ptr->next;
436 }
437
438 if (!ptr) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(&mDNSStorage, &arptr->ar));
439 mDNSPlatformMemFree(arptr);
440 return ptr;
441 }
442
443 mDNSexport void xD2DRemoveFromCache(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
444 {
445 (void)transportType; // We don't care about this, yet.
446 (void)instanceHandle; // We don't care about this, yet.
447
448 if (result == kD2DSuccess)
449 {
450 D2DRecordListElem *ptr = xD2DFindInList(key, keySize, value, valueSize);
451 if (ptr)
452 {
453 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(&mDNSStorage, &ptr->ar));
454 mDNS_Deregister(&mDNSStorage, &ptr->ar);
455 }
456 }
457 else
458 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result);
459 }
460
461 mDNSlocal void xD2DServiceResolved(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
462 {
463 (void)key;
464 (void)keySize;
465 (void)value;
466 (void)valueSize;
467
468 if (result == kD2DSuccess)
469 {
470 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle);
471 if (D2DRetain) D2DRetain(instanceHandle, transportType);
472 }
473 else LogMsg("xD2DServiceResolved: Unexpected result %d", result);
474 }
475
476 mDNSlocal void xD2DRetainHappened(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
477 {
478 (void)instanceHandle;
479 (void)transportType;
480 (void)key;
481 (void)keySize;
482 (void)value;
483 (void)valueSize;
484
485 if (result == kD2DSuccess) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle);
486 else LogMsg("xD2DRetainHappened: Unexpected result %d", result);
487 }
488
489 mDNSlocal void xD2DReleaseHappened(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
490 {
491 (void)instanceHandle;
492 (void)transportType;
493 (void)key;
494 (void)keySize;
495 (void)value;
496 (void)valueSize;
497
498 if (result == kD2DSuccess) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle);
499 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result);
500 }
501
502 mDNSlocal void xD2DServiceCallback(D2DServiceEvent event, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize, void *userData)
503 {
504 const char *eventString = "unknown";
505
506 KQueueLock();
507
508 if (keySize > 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize);
509 if (valueSize > 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize);
510
511 switch (event)
512 {
513 case D2DServiceFound:
514 eventString = "D2DServiceFound";
515 break;
516 case D2DServiceLost:
517 eventString = "D2DServiceLost";
518 break;
519 case D2DServiceResolved:
520 eventString = "D2DServiceResolved";
521 break;
522 case D2DServiceRetained:
523 eventString = "D2DServiceRetained";
524 break;
525 case D2DServiceReleased:
526 eventString = "D2DServiceReleased";
527 break;
528 default:
529 break;
530 }
531
532 LogInfo("xD2DServiceCallback: event=%s result=%d instanceHandle=%p transportType=%d LHS=%p (%u) RHS=%p (%u) userData=%p", eventString, result, instanceHandle, transportType, key, keySize, value, valueSize, userData);
533 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
534
535 switch (event)
536 {
537 case D2DServiceFound:
538 xD2DAddToCache(result, instanceHandle, transportType, key, keySize, value, valueSize);
539 break;
540 case D2DServiceLost:
541 xD2DRemoveFromCache(result, instanceHandle, transportType, key, keySize, value, valueSize);
542 break;
543 case D2DServiceResolved:
544 xD2DServiceResolved(result, instanceHandle, transportType, key, keySize, value, valueSize);
545 break;
546 case D2DServiceRetained:
547 xD2DRetainHappened(result, instanceHandle, transportType, key, keySize, value, valueSize);
548 break;
549 case D2DServiceReleased:
550 xD2DReleaseHappened(result, instanceHandle, transportType, key, keySize, value, valueSize);
551 break;
552 default:
553 break;
554 }
555
556 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
557 KQueueUnlock("xD2DServiceCallback");
558 }
559
560 // Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
561 // should be called.
562 // When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
563 // will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
564 // If the return value is not D2DTransportMax, excludedTransportType is undefined.
565
566 mDNSlocal D2DTransportType xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID, DNSServiceFlags flags, D2DTransportType * excludedTransportType)
567 {
568 NetworkInterfaceInfoOSX *info;
569
570 // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
571 *excludedTransportType = D2DAWDLTransport;
572
573 // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
574 if ((flags & kDNSServiceFlagsIncludeP2P) && (flags & kDNSServiceFlagsIncludeAWDL))
575 {
576 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
577 *excludedTransportType = D2DTransportMax;
578 return D2DTransportMax;
579 }
580 // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
581 else if (flags & kDNSServiceFlagsIncludeP2P)
582 {
583 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
584 return D2DTransportMax;
585 }
586 // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
587 else if (flags & kDNSServiceFlagsIncludeAWDL)
588 {
589 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
590 return D2DAWDLTransport;
591 }
592
593 if (InterfaceID == mDNSInterface_P2P)
594 {
595 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
596 return D2DTransportMax;
597 }
598
599 // Compare to cached AWDL interface ID.
600 if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
601 {
602 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID);
603 return D2DAWDLTransport;
604 }
605
606 info = IfindexToInterfaceInfoOSX(InterfaceID);
607 if (info == NULL)
608 {
609 LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID);
610 return D2DTransportMax;
611 }
612
613 // Recognize AirDrop specific p2p* interface based on interface name.
614 if (strncmp(info->ifinfo.ifname, "p2p", 3) == 0)
615 {
616 LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID);
617 return D2DWifiPeerToPeerTransport;
618 }
619
620 // Currently there is no way to identify Bluetooth interface by name,
621 // since they use "en*" based name strings.
622
623 LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID);
624 return D2DTransportMax;
625 }
626
627 mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags, pid_t clientPID)
628 {
629 #if ENABLE_BLE_TRIGGERED_BONJOUR
630 // BLE support currently not handled by a D2D plugin
631 if (applyToBLE(InterfaceID, flags))
632 {
633 domainname lower;
634
635 DomainnameToLower(typeDomain, &lower);
636 // pass in the key and keySize
637 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
638 start_BLE_browse(InterfaceID, &lower, qtype, flags, compression_lhs, end - compression_lhs);
639 }
640 else
641 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
642 internal_start_browsing_for_service(InterfaceID, typeDomain, qtype, flags, clientPID);
643 }
644
645 mDNSexport void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags, pid_t clientPID)
646 {
647 domainname lower;
648
649 DomainnameToLower(typeDomain, &lower);
650
651 if (!D2DBrowseListRefCount(&lower, qtype))
652 {
653 D2DTransportType transportType, excludedTransport;
654
655 LogInfo("%s: Starting browse for: %##s %s", __func__, lower.c, DNSTypeName(qtype));
656 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
657 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
658
659 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
660 if (transportType == D2DTransportMax)
661 {
662 D2DTransportType i;
663 for (i = 0; i < D2DTransportMax; i++)
664 {
665 if (i == excludedTransport) continue;
666 if (D2DStartBrowsingForKeyOnTransport)
667 {
668 if (i == D2DAWDLTransport)
669 {
670 mdns_powerlog_awdl_browse_start(typeDomain->c, qtype, clientPID);
671 }
672 D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
673 }
674 }
675 }
676 else
677 {
678 if (D2DStartBrowsingForKeyOnTransport)
679 {
680 if (transportType == D2DAWDLTransport)
681 {
682 mdns_powerlog_awdl_browse_start(typeDomain->c, qtype, clientPID);
683 }
684 D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
685 }
686 }
687 }
688 D2DBrowseListRetain(&lower, qtype);
689 }
690
691 mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags, pid_t clientPID)
692 {
693 #if ENABLE_BLE_TRIGGERED_BONJOUR
694 // BLE support currently not handled by a D2D plugin
695 if (applyToBLE(InterfaceID, flags))
696 {
697 domainname lower;
698
699 // If this is the last instance of this browse, clear any cached records recieved for it.
700 // We are not guaranteed to get a D2DServiceLost event for all key, value pairs cached over BLE.
701 DomainnameToLower(typeDomain, &lower);
702 if (stop_BLE_browse(InterfaceID, &lower, qtype, flags))
703 xD2DClearCache(&lower, qtype);
704 }
705 else
706 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
707 internal_stop_browsing_for_service(InterfaceID, typeDomain, qtype, flags, clientPID);
708 }
709
710 mDNSexport void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags, pid_t clientPID)
711 {
712 domainname lower;
713
714 DomainnameToLower(typeDomain, &lower);
715
716 // If found in list and this is the last reference to this browse, remove the key from the D2D plugins.
717 if (D2DBrowseListRelease(&lower, qtype) && !D2DBrowseListRefCount(&lower, qtype))
718 {
719 D2DTransportType transportType, excludedTransport;
720
721 LogInfo("%s: Stopping browse for: %##s %s", __func__, lower.c, DNSTypeName(qtype));
722 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
723 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
724
725 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
726 if (transportType == D2DTransportMax)
727 {
728 D2DTransportType i;
729 for (i = 0; i < D2DTransportMax; i++)
730 {
731 if (i == excludedTransport) continue;
732 if (D2DStopBrowsingForKeyOnTransport)
733 {
734 D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
735 if (i == D2DAWDLTransport)
736 {
737 mdns_powerlog_awdl_browse_stop(typeDomain->c, qtype, clientPID);
738 }
739 }
740 }
741 }
742 else
743 {
744 if (D2DStopBrowsingForKeyOnTransport)
745 {
746 D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
747 if (transportType == D2DAWDLTransport)
748 {
749 mdns_powerlog_awdl_browse_stop(typeDomain->c, qtype, clientPID);
750 }
751 }
752 }
753
754 // The D2D driver may not generate the D2DServiceLost event for this key after
755 // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
756 // record cache now.
757 xD2DClearCache(&lower, qtype);
758 }
759 }
760
761 mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags, pid_t clientPID)
762 {
763 #if ENABLE_BLE_TRIGGERED_BONJOUR
764 if (applyToBLE(resourceRecord->InterfaceID, flags))
765 {
766 domainname lower;
767
768 DomainnameToLower(resourceRecord->name, &lower);
769 start_BLE_advertise(resourceRecord, &lower, resourceRecord->rrtype, flags);
770 }
771 else
772 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
773 internal_start_advertising_service(resourceRecord, flags, clientPID);
774 }
775
776 mDNSexport void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags, pid_t clientPID)
777 {
778 domainname lower;
779 mDNSu8 *rhs = NULL;
780 mDNSu8 *end = NULL;
781 D2DTransportType transportType, excludedTransport;
782 DomainnameToLower(resourceRecord->name, &lower);
783
784 LogInfo("%s: %s", __func__, RRDisplayString(&mDNSStorage, resourceRecord));
785
786 // For SRV records, update packet filter if p2p interface already exists, otherwise,
787 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
788 if (resourceRecord->rrtype == kDNSType_SRV)
789 mDNSUpdatePacketFilter(NULL);
790
791 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
792 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
793 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
794
795 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
796 if (transportType == D2DTransportMax)
797 {
798 D2DTransportType i;
799 for (i = 0; i < D2DTransportMax; i++)
800 {
801 if (i == excludedTransport) continue;
802 if (D2DStartAdvertisingPairOnTransport)
803 {
804 if (i == D2DAWDLTransport)
805 {
806 mdns_powerlog_awdl_advertise_start(lower.c, resourceRecord->rrtype, clientPID);
807 }
808 D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
809 }
810 }
811 }
812 else
813 {
814 if (D2DStartAdvertisingPairOnTransport)
815 {
816 if (transportType == D2DAWDLTransport)
817 {
818 mdns_powerlog_awdl_advertise_start(lower.c, resourceRecord->rrtype, clientPID);
819 }
820 D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
821 }
822 }
823 }
824
825 mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags, pid_t clientPID)
826 {
827 #if ENABLE_BLE_TRIGGERED_BONJOUR
828 // BLE support currently not handled by a D2D plugin
829 if (applyToBLE(resourceRecord->InterfaceID, flags))
830 {
831 domainname lower;
832
833 DomainnameToLower(resourceRecord->name, &lower);
834 stop_BLE_advertise(&lower, resourceRecord->rrtype, flags);
835 }
836 else
837 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
838 internal_stop_advertising_service(resourceRecord, flags, clientPID);
839 }
840
841 mDNSexport void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags, pid_t clientPID)
842 {
843 domainname lower;
844 mDNSu8 *rhs = NULL;
845 mDNSu8 *end = NULL;
846 D2DTransportType transportType, excludedTransport;
847 DomainnameToLower(resourceRecord->name, &lower);
848
849 LogInfo("%s: %s", __func__, RRDisplayString(&mDNSStorage, resourceRecord));
850
851 // For SRV records, update packet filter if p2p interface already exists, otherwise,
852 // For SRV records, update packet filter to to remove this port from list
853 if (resourceRecord->rrtype == kDNSType_SRV)
854 mDNSUpdatePacketFilter(resourceRecord);
855
856 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
857 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
858 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
859
860 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
861 if (transportType == D2DTransportMax)
862 {
863 D2DTransportType i;
864 for (i = 0; i < D2DTransportMax; i++)
865 {
866 if (i == excludedTransport) continue;
867 if (D2DStopAdvertisingPairOnTransport)
868 {
869 D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
870 if (i == D2DAWDLTransport)
871 {
872 mdns_powerlog_awdl_advertise_stop(lower.c, resourceRecord->rrtype, clientPID);
873 }
874 }
875 }
876 }
877 else
878 {
879 if (D2DStopAdvertisingPairOnTransport)
880 {
881 D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
882 if (transportType == D2DAWDLTransport)
883 {
884 mdns_powerlog_awdl_advertise_stop(lower.c, resourceRecord->rrtype, clientPID);
885 }
886 }
887 }
888 }
889
890 mDNSexport void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags, pid_t clientPID)
891 {
892 domainname lower;
893 mDNSu8 *rhs = NULL;
894 mDNSu8 *end = NULL;
895 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
896 D2DTransportType transportType, excludedTransport;
897 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
898
899 LogInfo("external_start_resolving_service: %##s", fqdn->c);
900 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
901 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
902 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
903
904 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
905 if (transportType == D2DTransportMax)
906 {
907 // Resolving over all the transports, except for excludedTransport if set.
908 D2DTransportType i;
909 for (i = 0; i < D2DTransportMax; i++)
910 {
911 if (i == excludedTransport) continue;
912 if (D2DStartResolvingPairOnTransport)
913 {
914 if (i == D2DAWDLTransport)
915 {
916 mdns_powerlog_awdl_resolve_start(lower.c, kDNSType_PTR, clientPID);
917 }
918 D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
919 }
920 if (i == D2DAWDLTransport)
921 AWDL_used = true;
922 }
923 }
924 else
925 {
926 // Resolving over one specific transport.
927 if (D2DStartResolvingPairOnTransport)
928 {
929 if (transportType == D2DAWDLTransport)
930 {
931 mdns_powerlog_awdl_resolve_start(lower.c, kDNSType_PTR, clientPID);
932 }
933 D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
934 }
935 if (transportType == D2DAWDLTransport)
936 AWDL_used = true;
937 }
938
939 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
940 // We only want these records going to AWDL, so use AWDLInterfaceID as the
941 // interface and don't set any other flags.
942 if (AWDL_used && AWDLInterfaceID)
943 {
944 LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
945 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, 0, clientPID);
946 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0, clientPID);
947 }
948 }
949
950 mDNSexport void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags, pid_t clientPID)
951 {
952 domainname lower;
953 mDNSu8 *rhs = NULL;
954 mDNSu8 *end = NULL;
955 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
956 D2DTransportType transportType, excludedTransport;
957 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
958
959 LogInfo("external_stop_resolving_service: %##s", fqdn->c);
960 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
961 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
962 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
963
964 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
965 if (transportType == D2DTransportMax)
966 {
967 D2DTransportType i;
968 for (i = 0; i < D2DTransportMax; i++)
969 {
970 if (i == excludedTransport) continue;
971 if (D2DStopResolvingPairOnTransport)
972 {
973 D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
974 if (i == D2DAWDLTransport)
975 {
976 mdns_powerlog_awdl_resolve_stop(lower.c, kDNSType_PTR, clientPID);
977 }
978 }
979 if (i == D2DAWDLTransport)
980 AWDL_used = true;
981 }
982 }
983 else
984 {
985 if (D2DStopResolvingPairOnTransport)
986 {
987 D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
988 if (transportType == D2DAWDLTransport)
989 {
990 mdns_powerlog_awdl_resolve_stop(lower.c, kDNSType_PTR, clientPID);
991 }
992 }
993 if (transportType == D2DAWDLTransport)
994 AWDL_used = true;
995 }
996
997 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
998 // We only want these records going to AWDL, so use AWDLInterfaceID as the
999 // interface and don't set any other flags.
1000 if (AWDL_used && AWDLInterfaceID)
1001 {
1002 LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
1003 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, 0, clientPID);
1004 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0, clientPID);
1005 }
1006 }
1007
1008 mDNSexport mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags)
1009 {
1010 // Only call D2D layer routines if request applies to a D2D interface and the domain is "local".
1011 if ( (((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL | kDNSServiceFlagsAutoTrigger)))
1012 || mDNSPlatformInterfaceIsD2D(InterfaceID) || (InterfaceID == mDNSInterface_BLE))
1013 && IsLocalDomain(domain))
1014 {
1015 return mDNStrue;
1016 }
1017 else
1018 return mDNSfalse;
1019 }
1020
1021 // Used to derive the original D2D specific flags specified by the client in the registration
1022 // when we don't have access to the original flag (kDNSServiceFlags*) values.
1023 mDNSexport mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType)
1024 {
1025 mDNSu32 flags = 0;
1026 if ((authRecType == AuthRecordAnyIncludeP2P) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
1027 flags |= kDNSServiceFlagsIncludeP2P;
1028 else if ((authRecType == AuthRecordAnyIncludeAWDL) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
1029 flags |= kDNSServiceFlagsIncludeAWDL;
1030 return flags;
1031 }
1032
1033 void initializeD2DPlugins(mDNS *const m)
1034 {
1035 // We only initialize if mDNSCore successfully initialized.
1036 if (D2DInitialize)
1037 {
1038 D2DStatus ds = D2DInitialize(CFRunLoopGetMain(), xD2DServiceCallback, m);
1039 if (ds != kD2DSuccess)
1040 LogMsg("D2DInitialiize failed: %d", ds);
1041 else
1042 LogMsg("D2DInitialize succeeded");
1043 }
1044 }
1045
1046 void terminateD2DPlugins(void)
1047 {
1048 if (D2DTerminate)
1049 {
1050 D2DStatus ds = D2DTerminate();
1051 if (ds != kD2DSuccess)
1052 LogMsg("D2DTerminate failed: %d", ds);
1053 else
1054 LogMsg("D2DTerminate succeeded");
1055 }
1056 }
1057
1058 #ifdef UNIT_TEST
1059 #pragma mark - Unit test support routines
1060
1061 // These unit test support routines are called from unittests/ framework
1062 // and are not compiled for the mDNSResponder runtime code paths.
1063
1064 void D2D_unitTest(void)
1065 {
1066 }
1067
1068 #endif // UNIT_TEST