]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/ev_dlil.c
configd-1109.40.9.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / ev_dlil.c
1 /*
2 * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * August 5, 2002 Allan Nathanson <ajn@apple.com>
28 * - split code out from eventmon.c
29 */
30
31 #include "eventmon.h"
32 #include "ev_dlil.h"
33 #include "ev_extra.h"
34
35 static CFStringRef
36 create_interface_cfstring(const char * if_name)
37 {
38 CFStringRef interface;
39
40 interface = CFStringCreateWithCString(NULL, if_name,
41 kCFStringEncodingUTF8);
42 return (interface);
43 }
44
45 static CFStringRef
46 create_interface_key(CFStringRef interface)
47 {
48 CFStringRef key;
49
50 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
51 kSCDynamicStoreDomainState,
52 interface,
53 kSCEntNetLink);
54 return (key);
55 }
56
57
58 static CFMutableDictionaryRef
59 copy_mutable_dictionary(CFDictionaryRef dict)
60 {
61 CFMutableDictionaryRef newDict;
62
63 if (isA_CFDictionary(dict) != NULL) {
64 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
65 }
66 else {
67 newDict = CFDictionaryCreateMutable(NULL,
68 0,
69 &kCFTypeDictionaryKeyCallBacks,
70 &kCFTypeDictionaryValueCallBacks);
71 }
72 return (newDict);
73 }
74
75 static CFMutableDictionaryRef
76 copy_entity(CFStringRef key)
77 {
78 CFDictionaryRef dict;
79 CFMutableDictionaryRef newDict = NULL;
80
81 dict = SCDynamicStoreCopyValue(store, key);
82 newDict = copy_mutable_dictionary(dict);
83 if (dict != NULL) {
84 CFRelease(dict);
85 }
86 return (newDict);
87 }
88
89
90 static void
91 interface_update_status(const char *if_name,
92 CFStringRef interface,
93 CFBooleanRef active, boolean_t attach,
94 CFBooleanRef expensive, boolean_t only_if_different)
95 {
96 CFStringRef key = NULL;
97 CFMutableDictionaryRef newDict;
98 CFDictionaryRef oldDict;
99
100 key = create_interface_key(interface);
101 oldDict = SCDynamicStoreCopyValue(store, key);
102 if (oldDict != NULL && isA_CFDictionary(oldDict) == NULL) {
103 CFRelease(oldDict);
104 oldDict = NULL;
105 }
106 newDict = copy_mutable_dictionary(oldDict);
107
108 /* if new status available, update cache */
109 if (active != NULL) {
110 CFDictionarySetValue(newDict, kSCPropNetLinkActive, active);
111 } else {
112 CFDictionaryRemoveValue(newDict, kSCPropNetLinkActive);
113 }
114
115 if (attach) {
116 /* the interface was attached, remove stale state */
117 CFDictionaryRemoveValue(newDict, kSCPropNetLinkDetaching);
118 }
119
120 if ((expensive != NULL) && CFBooleanGetValue(expensive)) {
121 CFDictionarySetValue(newDict, kSCPropNetLinkExpensive, expensive);
122 } else {
123 CFDictionaryRemoveValue(newDict, kSCPropNetLinkExpensive);
124 }
125
126 /* update the SCDynamicStore */
127 if (CFDictionaryGetCount(newDict) > 0) {
128 /* set the value */
129 if (!only_if_different
130 || oldDict == NULL
131 || !CFEqual(oldDict, newDict)) {
132 SC_log(LOG_DEBUG, "Update interface link status: %s: %@", if_name, newDict);
133 SCDynamicStoreSetValue(store, key, newDict);
134 }
135 } else {
136 /* remove the value */
137 if (!only_if_different
138 || oldDict != NULL) {
139 SC_log(LOG_DEBUG, "Update interface link status: %s: <removed>", if_name);
140 SCDynamicStoreRemoveValue(store, key);
141 }
142 }
143
144 CFRelease(key);
145 CFRelease(newDict);
146 if (oldDict != NULL) {
147 CFRelease(oldDict);
148 }
149 return;
150 }
151
152
153 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
154 static CFStringRef
155 create_linkquality_key(CFStringRef interface)
156 {
157 CFStringRef key;
158
159 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
160 kSCDynamicStoreDomainState,
161 interface,
162 kSCEntNetLinkQuality);
163 return (key);
164 }
165
166
167 __private_extern__
168 void
169 interface_update_quality_metric(const char *if_name,
170 int quality)
171 {
172 CFStringRef key;
173 CFStringRef interface;
174 CFMutableDictionaryRef newDict;
175
176 interface = create_interface_cfstring(if_name);
177 key = create_linkquality_key(interface);
178 newDict = copy_entity(key);
179
180 if (quality != IFNET_LQM_THRESH_UNKNOWN) {
181 CFNumberRef linkquality;
182
183 linkquality = CFNumberCreate(NULL, kCFNumberIntType, &quality);
184 CFDictionarySetValue(newDict, kSCPropNetLinkQuality, linkquality);
185 CFRelease(linkquality);
186 } else {
187 CFDictionaryRemoveValue(newDict, kSCPropNetLinkQuality);
188 }
189
190 /* update status */
191 if (CFDictionaryGetCount(newDict) > 0) {
192 SC_log(LOG_DEBUG, "Update interface link quality: %s: %@", if_name, newDict);
193 SCDynamicStoreSetValue(store, key, newDict);
194 } else {
195 SC_log(LOG_DEBUG, "Update interface link quality: %s: <unknown>", if_name);
196 SCDynamicStoreRemoveValue(store, key);
197 }
198
199 CFRelease(interface);
200 CFRelease(key);
201 CFRelease(newDict);
202 return;
203 }
204
205
206 static
207 void
208 link_update_quality_metric(const char *if_name)
209 {
210 struct ifreq ifr;
211 int quality = IFNET_LQM_THRESH_UNKNOWN;
212 int sock;
213
214 sock = dgram_socket(AF_INET);
215 if (sock == -1) {
216 goto done;
217 }
218
219 memset((char *)&ifr, 0, sizeof(ifr));
220 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name);
221
222 if (ioctl(sock, SIOCGIFLINKQUALITYMETRIC, (caddr_t)&ifr) != -1) {
223 quality = ifr.ifr_link_quality_metric;
224 }
225
226 done:
227
228 interface_update_quality_metric(if_name, quality);
229
230 if (sock != -1) {
231 close(sock);
232 }
233 return;
234
235 }
236 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
237
238
239 #ifdef KEV_DL_ISSUES
240 static CFStringRef
241 create_link_issues_key(CFStringRef interface)
242 {
243 CFStringRef key;
244
245 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
246 kSCDynamicStoreDomainState,
247 interface,
248 kSCEntNetLinkIssues);
249 return (key);
250 }
251
252
253 __private_extern__
254 void
255 interface_update_link_issues(const char *if_name,
256 uint64_t timestamp,
257 uint8_t *modid,
258 size_t modid_size,
259 uint8_t *info,
260 size_t info_size)
261 {
262 CFDataRef infoData;
263 CFStringRef interface;
264 CFStringRef key;
265 CFDataRef modidData;
266 CFMutableDictionaryRef newDict;
267 CFDateRef timeStamp;
268
269 interface = create_interface_cfstring(if_name);
270 key = create_link_issues_key(interface);
271
272 newDict = copy_entity(key);
273
274 modidData = CFDataCreate(NULL, modid, modid_size);
275 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesModuleID, modidData);
276 CFRelease(modidData);
277
278 if (info_size != 0) {
279 infoData = CFDataCreate(NULL, info, info_size);
280 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesInfo, infoData);
281 CFRelease(infoData);
282 } else {
283 CFDictionaryRemoveValue(newDict, kSCPropNetLinkIssuesInfo);
284 }
285
286 timeStamp = CFDateCreate(NULL, timestamp);
287 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesTimeStamp, timeStamp);
288 CFRelease(timeStamp);
289
290 SC_log(LOG_DEBUG, "Update interface link issues: %s: %@", if_name, newDict);
291 SCDynamicStoreSetValue(store, key, newDict);
292 CFRelease(interface);
293 CFRelease(newDict);
294 CFRelease(key);
295 return;
296 }
297 #endif /* KEV_DL_ISSUES */
298
299
300 __private_extern__
301 void
302 interface_detaching(const char *if_name)
303 {
304 CFStringRef interface;
305 CFStringRef key;
306 CFMutableDictionaryRef newDict;
307
308 SC_log(LOG_DEBUG, "Detach interface: %s", if_name);
309
310 interface = create_interface_cfstring(if_name);
311 key = create_interface_key(interface);
312 newDict = copy_entity(key);
313 CFDictionarySetValue(newDict, kSCPropNetLinkDetaching,
314 kCFBooleanTrue);
315 SCDynamicStoreSetValue(store, key, newDict);
316 CFRelease(interface);
317 CFRelease(newDict);
318 CFRelease(key);
319 return;
320 }
321
322 static CFStringRef
323 create_nat64_key(CFStringRef interface)
324 {
325 CFStringRef key;
326
327 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
328 kSCDynamicStoreDomainState,
329 interface,
330 kSCEntNetNAT64);
331 return (key);
332 }
333
334
335 static void
336 interface_remove(const char *if_name)
337 {
338 CFStringRef interface;
339 CFStringRef key;
340
341 SC_log(LOG_DEBUG, "Remove interface: %s", if_name);
342
343 interface = create_interface_cfstring(if_name);
344
345 key = create_interface_key(interface);
346 SCDynamicStoreRemoveValue(store, key);
347 CFRelease(key);
348
349 key = create_nat64_key(interface);
350 SCDynamicStoreRemoveValue(store, key);
351 CFRelease(key);
352
353 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
354 key = create_linkquality_key(interface);
355 SCDynamicStoreRemoveValue(store, key);
356 CFRelease(key);
357 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
358
359 #ifdef KEV_DL_ISSUES
360 key = create_link_issues_key(interface);
361 SCDynamicStoreRemoveValue(store, key);
362 CFRelease(key);
363 #endif /* KEV_DL_ISSUES */
364
365 CFRelease(interface);
366 return;
367 }
368
369
370 static void
371 S_link_update_status(const char *if_name, CFStringRef interface, boolean_t attach, boolean_t only_if_different)
372 {
373 CFBooleanRef active = NULL;
374 CFBooleanRef expensive = NULL;
375 struct ifmediareq ifm;
376 int sock;
377
378 sock = dgram_socket(AF_INET);
379 if (sock == -1) {
380 return;
381 }
382
383 /* get "Link" */
384 memset((char *)&ifm, 0, sizeof(ifm));
385 (void) strlcpy(ifm.ifm_name, if_name, sizeof(ifm.ifm_name));
386
387 if (ioctl(sock, SIOCGIFXMEDIA, (caddr_t)&ifm) == -1) {
388 /* if media status not available for this interface */
389 goto update;
390 }
391
392 if (ifm.ifm_count == 0) {
393 /* no media types */
394 goto update;
395 }
396
397 if (!(ifm.ifm_status & IFM_AVALID)) {
398 /* if active bit not valid */
399 goto update;
400 }
401
402 if (ifm.ifm_status & IFM_ACTIVE) {
403 active = kCFBooleanTrue;
404 } else {
405 active = kCFBooleanFalse;
406 }
407
408 update:
409
410 if ((active == NULL) || CFBooleanGetValue(active)) {
411 /*
412 * if link status not available or active (link UP),
413 * set "Expensive"
414 */
415 expensive = interface_update_expensive(if_name);
416 }
417
418 /* update status */
419 interface_update_status(if_name, interface, active, attach, expensive, only_if_different);
420 close(sock);
421 return;
422 }
423
424 __private_extern__
425 void
426 link_update_status(const char *if_name, boolean_t attach, boolean_t only_if_different)
427 {
428 CFStringRef interface;
429
430 interface = create_interface_cfstring(if_name);
431 S_link_update_status(if_name, interface, attach, only_if_different);
432 CFRelease(interface);
433 }
434
435
436 __private_extern__
437 void
438 link_update_status_if_missing(const char * if_name)
439 {
440 CFStringRef interface;
441 CFStringRef key;
442 CFDictionaryRef dict;
443
444 interface = create_interface_cfstring(if_name);
445 key = create_interface_key(interface);
446 dict = SCDynamicStoreCopyValue(store, key);
447 if (dict != NULL) {
448 /* it's already present, don't update */
449 CFRelease(dict);
450 goto done;
451 }
452 S_link_update_status(if_name, interface, FALSE, FALSE);
453 dict = SCDynamicStoreCopyValue(store, key);
454 if (dict != NULL) {
455 /* our action made it appear */
456 messages_add_msg_with_arg("added missing link status", if_name);
457 CFRelease(dict);
458 }
459 done:
460 CFRelease(interface);
461 CFRelease(key);
462 return;
463 }
464
465 __private_extern__
466 CFMutableArrayRef
467 interfaceListCopy(void)
468 {
469 CFStringRef cacheKey;
470 CFDictionaryRef dict;
471 CFMutableArrayRef ret_ifList = NULL;
472
473 cacheKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
474 kSCDynamicStoreDomainState);
475 dict = SCDynamicStoreCopyValue(store, cacheKey);
476 CFRelease(cacheKey);
477 if (dict != NULL) {
478 if (isA_CFDictionary(dict) != NULL) {
479 CFArrayRef ifList;
480
481 ifList = CFDictionaryGetValue(dict, kSCPropNetInterfaces);
482 if (isA_CFArray(ifList) != NULL) {
483 ret_ifList = CFArrayCreateMutableCopy(NULL, 0, ifList);
484 }
485 }
486 CFRelease(dict);
487 }
488 if (ret_ifList == NULL) {
489 ret_ifList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
490 }
491 return (ret_ifList);
492 }
493
494
495 __private_extern__
496 void
497 interfaceListUpdate(CFArrayRef ifList)
498 {
499 CFStringRef cacheKey;
500 CFDictionaryRef dict;
501
502 cacheKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
503 kSCDynamicStoreDomainState);
504 dict = SCDynamicStoreCopyValue(store, cacheKey);
505 if (dict != NULL && isA_CFDictionary(dict) == NULL) {
506 CFRelease(dict);
507 dict = NULL;
508 }
509 if (dict == NULL) {
510 dict = CFDictionaryCreate(NULL,
511 (const void * *)&kSCPropNetInterfaces,
512 (const void * *)&ifList,
513 1,
514 &kCFTypeDictionaryKeyCallBacks,
515 &kCFTypeDictionaryValueCallBacks);
516 SCDynamicStoreSetValue(store, cacheKey, dict);
517 CFRelease(dict);
518
519 }
520 else {
521 CFMutableDictionaryRef newDict;
522
523 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
524 CFRelease(dict);
525 CFDictionarySetValue(newDict, kSCPropNetInterfaces, ifList);
526 SCDynamicStoreSetValue(store, cacheKey, newDict);
527 CFRelease(newDict);
528 }
529 CFRelease(cacheKey);
530 return;
531 }
532
533
534 __private_extern__
535 Boolean
536 interfaceListAddInterface(CFMutableArrayRef ifList, const char * if_name)
537 {
538 Boolean added = FALSE;
539 CFStringRef interface;
540
541 interface = create_interface_cfstring(if_name);
542 if (!CFArrayContainsValue(ifList,
543 CFRangeMake(0, CFArrayGetCount(ifList)),
544 interface)) {
545 /* interface was added, prime the link-specific values */
546 added = TRUE;
547 CFArrayAppendValue(ifList, interface);
548 link_update_status(if_name, TRUE, FALSE);
549 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
550 link_update_quality_metric(if_name);
551 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
552 }
553 else {
554 /* only update the link status if it is different */
555 link_update_status(if_name, FALSE, TRUE);
556 }
557 CFRelease(interface);
558 return (added);
559 }
560
561
562 static Boolean
563 interfaceListRemoveInterface(CFMutableArrayRef ifList, const char * if_name)
564 {
565 CFStringRef interface;
566 CFIndex where;
567
568 interface = create_interface_cfstring(if_name);
569 where = CFArrayGetFirstIndexOfValue(ifList,
570 CFRangeMake(0, CFArrayGetCount(ifList)),
571 interface);
572 CFRelease(interface);
573 if (where != kCFNotFound) {
574 CFArrayRemoveValueAtIndex(ifList, where);
575 interface_remove(if_name);
576 }
577 return (where != kCFNotFound);
578 }
579
580
581 __private_extern__
582 void
583 link_add(const char *if_name)
584 {
585 CFMutableArrayRef ifList;
586
587 ifList = interfaceListCopy();
588 if (interfaceListAddInterface(ifList, if_name)) {
589 /* interface was added, update the global list */
590 messages_add_msg_with_arg("link_add", if_name);
591 interfaceListUpdate(ifList);
592 config_new_interface(if_name);
593 }
594 CFRelease(ifList);
595 return;
596 }
597
598
599 __private_extern__
600 void
601 link_remove(const char *if_name)
602 {
603 CFMutableArrayRef ifList;
604
605 ifList = interfaceListCopy();
606 if (interfaceListRemoveInterface(ifList, if_name)) {
607 /* interface was removed, update the global list */
608 interfaceListUpdate(ifList);
609 }
610 CFRelease(ifList);
611 return;
612 }
613
614
615 __private_extern__
616 void
617 interface_update_delegation(const char *if_name)
618 {
619 CFStringRef interface;
620 CFStringRef key;
621
622 interface = create_interface_cfstring(if_name);
623 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
624 kSCDynamicStoreDomainState,
625 interface,
626 kSCEntNetInterfaceDelegation);
627 SC_log(LOG_DEBUG, "Post interface delegation change: %s", if_name);
628 SCDynamicStoreNotifyValue(store, key);
629 CFRelease(key);
630 CFRelease(interface);
631 return;
632 }
633
634
635 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
636 #define INVALID_SOCKET_REF -1
637 static
638 int
639 socket_reference_count(const char* if_name) {
640 struct ifreq ifr;
641 int ref = INVALID_SOCKET_REF;
642 int s;
643
644 s = dgram_socket(AF_INET);
645 if (s == -1) {
646 return (ref);
647 }
648
649 memset((char *)&ifr, 0, sizeof(ifr));
650 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name);
651
652 if (ioctl(s, SIOCGIFGETRTREFCNT, (caddr_t)&ifr) != -1) {
653 ref = ifr.ifr_route_refcnt;
654 } else {
655 ref = INVALID_SOCKET_REF;
656 }
657 close(s);
658 return (ref);
659 }
660
661
662 __private_extern__
663 void
664 interface_update_idle_state(const char *if_name)
665 {
666 CFStringRef interface;
667 CFStringRef key;
668 int ref;
669
670 /* only update the SCDynamicStore if the idle ref count is still 0 */
671 ref = socket_reference_count(if_name);
672 if (ref != 0) {
673 return;
674 }
675
676 interface = create_interface_cfstring(if_name);
677 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
678 kSCDynamicStoreDomainState,
679 interface,
680 kSCEntNetIdleRoute);
681
682 SC_log(LOG_DEBUG, "Post interface idle: %s", if_name);
683 SCDynamicStoreNotifyValue(store, key);
684 CFRelease(key);
685 CFRelease(interface);
686 return;
687 }
688 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT