]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/ev_dlil.c
configd-1061.0.2.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / ev_dlil.c
1 /*
2 * Copyright (c) 2002-2019 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 (oldDict != NULL) {
138 SC_log(LOG_DEBUG, "Update interface link status: %s: <removed>", if_name);
139 }
140 SCDynamicStoreRemoveValue(store, key);
141 }
142
143 CFRelease(key);
144 CFRelease(newDict);
145 if (oldDict != NULL) {
146 CFRelease(oldDict);
147 }
148 return;
149 }
150
151
152 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
153 static CFStringRef
154 create_linkquality_key(CFStringRef interface)
155 {
156 CFStringRef key;
157
158 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
159 kSCDynamicStoreDomainState,
160 interface,
161 kSCEntNetLinkQuality);
162 return (key);
163 }
164
165
166 __private_extern__
167 void
168 interface_update_quality_metric(const char *if_name,
169 int quality)
170 {
171 CFStringRef key;
172 CFStringRef interface;
173 CFMutableDictionaryRef newDict;
174
175 interface = create_interface_cfstring(if_name);
176 key = create_linkquality_key(interface);
177 newDict = copy_entity(key);
178
179 if (quality != IFNET_LQM_THRESH_UNKNOWN) {
180 CFNumberRef linkquality;
181
182 linkquality = CFNumberCreate(NULL, kCFNumberIntType, &quality);
183 CFDictionarySetValue(newDict, kSCPropNetLinkQuality, linkquality);
184 CFRelease(linkquality);
185 } else {
186 CFDictionaryRemoveValue(newDict, kSCPropNetLinkQuality);
187 }
188
189 /* update status */
190 if (CFDictionaryGetCount(newDict) > 0) {
191 SC_log(LOG_DEBUG, "Update interface link quality: %s: %@", if_name, newDict);
192 SCDynamicStoreSetValue(store, key, newDict);
193 } else {
194 SC_log(LOG_DEBUG, "Update interface link quality: %s: <unknown>", if_name);
195 SCDynamicStoreRemoveValue(store, key);
196 }
197
198 CFRelease(interface);
199 CFRelease(key);
200 CFRelease(newDict);
201 return;
202 }
203
204
205 static
206 void
207 link_update_quality_metric(const char *if_name)
208 {
209 struct ifreq ifr;
210 int quality = IFNET_LQM_THRESH_UNKNOWN;
211 int sock;
212
213 sock = dgram_socket(AF_INET);
214 if (sock == -1) {
215 goto done;
216 }
217
218 memset((char *)&ifr, 0, sizeof(ifr));
219 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name);
220
221 if (ioctl(sock, SIOCGIFLINKQUALITYMETRIC, (caddr_t)&ifr) != -1) {
222 quality = ifr.ifr_link_quality_metric;
223 }
224
225 done:
226
227 interface_update_quality_metric(if_name, quality);
228
229 if (sock != -1) {
230 close(sock);
231 }
232 return;
233
234 }
235 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
236
237
238 #ifdef KEV_DL_ISSUES
239 static CFStringRef
240 create_link_issues_key(CFStringRef interface)
241 {
242 CFStringRef key;
243
244 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
245 kSCDynamicStoreDomainState,
246 interface,
247 kSCEntNetLinkIssues);
248 return (key);
249 }
250
251
252 __private_extern__
253 void
254 interface_update_link_issues(const char *if_name,
255 uint64_t timestamp,
256 uint8_t *modid,
257 size_t modid_size,
258 uint8_t *info,
259 size_t info_size)
260 {
261 CFDataRef infoData;
262 CFStringRef interface;
263 CFStringRef key;
264 CFDataRef modidData;
265 CFMutableDictionaryRef newDict;
266 CFDateRef timeStamp;
267
268 interface = create_interface_cfstring(if_name);
269 key = create_link_issues_key(interface);
270
271 newDict = copy_entity(key);
272
273 modidData = CFDataCreate(NULL, modid, modid_size);
274 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesModuleID, modidData);
275 CFRelease(modidData);
276
277 if (info_size != 0) {
278 infoData = CFDataCreate(NULL, info, info_size);
279 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesInfo, infoData);
280 CFRelease(infoData);
281 } else {
282 CFDictionaryRemoveValue(newDict, kSCPropNetLinkIssuesInfo);
283 }
284
285 timeStamp = CFDateCreate(NULL, timestamp);
286 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesTimeStamp, timeStamp);
287 CFRelease(timeStamp);
288
289 SC_log(LOG_DEBUG, "Update interface link issues: %s: %@", if_name, newDict);
290 SCDynamicStoreSetValue(store, key, newDict);
291 CFRelease(interface);
292 CFRelease(newDict);
293 CFRelease(key);
294 return;
295 }
296 #endif /* KEV_DL_ISSUES */
297
298
299 __private_extern__
300 void
301 interface_detaching(const char *if_name)
302 {
303 CFStringRef interface;
304 CFStringRef key;
305 CFMutableDictionaryRef newDict;
306
307 SC_log(LOG_DEBUG, "Detach interface: %s", if_name);
308
309 interface = create_interface_cfstring(if_name);
310 key = create_interface_key(interface);
311 newDict = copy_entity(key);
312 CFDictionarySetValue(newDict, kSCPropNetLinkDetaching,
313 kCFBooleanTrue);
314 SCDynamicStoreSetValue(store, key, newDict);
315 CFRelease(interface);
316 CFRelease(newDict);
317 CFRelease(key);
318 return;
319 }
320
321 static CFStringRef
322 create_nat64_key(CFStringRef interface)
323 {
324 CFStringRef key;
325
326 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
327 kSCDynamicStoreDomainState,
328 interface,
329 kSCEntNetNAT64);
330 return (key);
331 }
332
333
334 static void
335 interface_remove(const char *if_name)
336 {
337 CFStringRef interface;
338 CFStringRef key;
339
340 SC_log(LOG_DEBUG, "Remove interface: %s", if_name);
341
342 interface = create_interface_cfstring(if_name);
343
344 key = create_interface_key(interface);
345 SCDynamicStoreRemoveValue(store, key);
346 CFRelease(key);
347
348 key = create_nat64_key(interface);
349 SCDynamicStoreRemoveValue(store, key);
350 CFRelease(key);
351
352 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
353 key = create_linkquality_key(interface);
354 SCDynamicStoreRemoveValue(store, key);
355 CFRelease(key);
356 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
357
358 #ifdef KEV_DL_ISSUES
359 key = create_link_issues_key(interface);
360 SCDynamicStoreRemoveValue(store, key);
361 CFRelease(key);
362 #endif /* KEV_DL_ISSUES */
363
364 CFRelease(interface);
365 return;
366 }
367
368
369 static void
370 S_link_update_status(const char *if_name, CFStringRef interface, boolean_t attach, boolean_t only_if_different)
371 {
372 CFBooleanRef active = NULL;
373 CFBooleanRef expensive = NULL;
374 struct ifmediareq ifm;
375 int sock;
376
377 sock = dgram_socket(AF_INET);
378 if (sock == -1) {
379 return;
380 }
381
382 /* get "Link" */
383 memset((char *)&ifm, 0, sizeof(ifm));
384 (void) strlcpy(ifm.ifm_name, if_name, sizeof(ifm.ifm_name));
385
386 if (ioctl(sock, SIOCGIFXMEDIA, (caddr_t)&ifm) == -1) {
387 /* if media status not available for this interface */
388 goto update;
389 }
390
391 if (ifm.ifm_count == 0) {
392 /* no media types */
393 goto update;
394 }
395
396 if (!(ifm.ifm_status & IFM_AVALID)) {
397 /* if active bit not valid */
398 goto update;
399 }
400
401 if (ifm.ifm_status & IFM_ACTIVE) {
402 active = kCFBooleanTrue;
403 } else {
404 active = kCFBooleanFalse;
405 }
406
407 update:
408
409 if ((active == NULL) || CFBooleanGetValue(active)) {
410 /*
411 * if link status not available or active (link UP),
412 * set "Expensive"
413 */
414 expensive = interface_update_expensive(if_name);
415 }
416
417 /* update status */
418 interface_update_status(if_name, interface, active, attach, expensive, only_if_different);
419 close(sock);
420 return;
421 }
422
423 __private_extern__
424 void
425 link_update_status(const char *if_name, boolean_t attach, boolean_t only_if_different)
426 {
427 CFStringRef interface;
428
429 interface = create_interface_cfstring(if_name);
430 S_link_update_status(if_name, interface, attach, only_if_different);
431 CFRelease(interface);
432 }
433
434
435 __private_extern__
436 void
437 link_update_status_if_missing(const char * if_name)
438 {
439 CFStringRef interface;
440 CFStringRef key;
441 CFDictionaryRef dict;
442
443 interface = create_interface_cfstring(if_name);
444 key = create_interface_key(interface);
445 dict = SCDynamicStoreCopyValue(store, key);
446 if (dict != NULL) {
447 /* it's already present, don't update */
448 CFRelease(dict);
449 goto done;
450 }
451 S_link_update_status(if_name, interface, FALSE, FALSE);
452 dict = SCDynamicStoreCopyValue(store, key);
453 if (dict != NULL) {
454 /* our action made it appear */
455 messages_add_msg_with_arg("added missing link status", if_name);
456 CFRelease(dict);
457 }
458 done:
459 CFRelease(interface);
460 CFRelease(key);
461 return;
462 }
463
464 __private_extern__
465 CFMutableArrayRef
466 interfaceListCopy(void)
467 {
468 CFStringRef cacheKey;
469 CFDictionaryRef dict;
470 CFMutableArrayRef ret_ifList = NULL;
471
472 cacheKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
473 kSCDynamicStoreDomainState);
474 dict = SCDynamicStoreCopyValue(store, cacheKey);
475 CFRelease(cacheKey);
476 if (dict != NULL) {
477 if (isA_CFDictionary(dict) != NULL) {
478 CFArrayRef ifList;
479
480 ifList = CFDictionaryGetValue(dict, kSCPropNetInterfaces);
481 if (isA_CFArray(ifList) != NULL) {
482 ret_ifList = CFArrayCreateMutableCopy(NULL, 0, ifList);
483 }
484 }
485 CFRelease(dict);
486 }
487 if (ret_ifList == NULL) {
488 ret_ifList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
489 }
490 return (ret_ifList);
491 }
492
493
494 __private_extern__
495 void
496 interfaceListUpdate(CFArrayRef ifList)
497 {
498 CFStringRef cacheKey;
499 CFDictionaryRef dict;
500
501 cacheKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
502 kSCDynamicStoreDomainState);
503 dict = SCDynamicStoreCopyValue(store, cacheKey);
504 if (dict != NULL && isA_CFDictionary(dict) == NULL) {
505 CFRelease(dict);
506 dict = NULL;
507 }
508 if (dict == NULL) {
509 dict = CFDictionaryCreate(NULL,
510 (const void * *)&kSCPropNetInterfaces,
511 (const void * *)&ifList,
512 1,
513 &kCFTypeDictionaryKeyCallBacks,
514 &kCFTypeDictionaryValueCallBacks);
515 SCDynamicStoreSetValue(store, cacheKey, dict);
516 CFRelease(dict);
517
518 }
519 else {
520 CFMutableDictionaryRef newDict;
521
522 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
523 CFRelease(dict);
524 CFDictionarySetValue(newDict, kSCPropNetInterfaces, ifList);
525 SCDynamicStoreSetValue(store, cacheKey, newDict);
526 CFRelease(newDict);
527 }
528 CFRelease(cacheKey);
529 return;
530 }
531
532
533 __private_extern__
534 Boolean
535 interfaceListAddInterface(CFMutableArrayRef ifList, const char * if_name)
536 {
537 Boolean added = FALSE;
538 CFStringRef interface;
539
540 interface = create_interface_cfstring(if_name);
541 if (!CFArrayContainsValue(ifList,
542 CFRangeMake(0, CFArrayGetCount(ifList)),
543 interface)) {
544 /* interface was added, prime the link-specific values */
545 added = TRUE;
546 CFArrayAppendValue(ifList, interface);
547 link_update_status(if_name, TRUE, FALSE);
548 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
549 link_update_quality_metric(if_name);
550 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
551 }
552 else {
553 /* only update the link status if it is different */
554 link_update_status(if_name, FALSE, TRUE);
555 }
556 CFRelease(interface);
557 return (added);
558 }
559
560
561 static Boolean
562 interfaceListRemoveInterface(CFMutableArrayRef ifList, const char * if_name)
563 {
564 CFStringRef interface;
565 CFIndex where;
566
567 interface = create_interface_cfstring(if_name);
568 where = CFArrayGetFirstIndexOfValue(ifList,
569 CFRangeMake(0, CFArrayGetCount(ifList)),
570 interface);
571 CFRelease(interface);
572 if (where != kCFNotFound) {
573 CFArrayRemoveValueAtIndex(ifList, where);
574 interface_remove(if_name);
575 }
576 return (where != kCFNotFound);
577 }
578
579
580 __private_extern__
581 void
582 link_add(const char *if_name)
583 {
584 CFMutableArrayRef ifList;
585
586 ifList = interfaceListCopy();
587 if (interfaceListAddInterface(ifList, if_name)) {
588 /* interface was added, update the global list */
589 messages_add_msg_with_arg("link_add", if_name);
590 interfaceListUpdate(ifList);
591 config_new_interface(if_name);
592 }
593 CFRelease(ifList);
594 return;
595 }
596
597
598 __private_extern__
599 void
600 link_remove(const char *if_name)
601 {
602 CFMutableArrayRef ifList;
603
604 ifList = interfaceListCopy();
605 if (interfaceListRemoveInterface(ifList, if_name)) {
606 /* interface was removed, update the global list */
607 interfaceListUpdate(ifList);
608 }
609 CFRelease(ifList);
610 return;
611 }
612
613
614 __private_extern__
615 void
616 interface_update_delegation(const char *if_name)
617 {
618 CFStringRef interface;
619 CFStringRef key;
620
621 interface = create_interface_cfstring(if_name);
622 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
623 kSCDynamicStoreDomainState,
624 interface,
625 kSCEntNetInterfaceDelegation);
626 SC_log(LOG_DEBUG, "Post interface delegation change: %s", if_name);
627 SCDynamicStoreNotifyValue(store, key);
628 CFRelease(key);
629 CFRelease(interface);
630 return;
631 }
632
633
634 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
635 #define INVALID_SOCKET_REF -1
636 static
637 int
638 socket_reference_count(const char* if_name) {
639 struct ifreq ifr;
640 int ref = INVALID_SOCKET_REF;
641 int s;
642
643 s = dgram_socket(AF_INET);
644 if (s == -1) {
645 return (ref);
646 }
647
648 memset((char *)&ifr, 0, sizeof(ifr));
649 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name);
650
651 if (ioctl(s, SIOCGIFGETRTREFCNT, (caddr_t)&ifr) != -1) {
652 ref = ifr.ifr_route_refcnt;
653 } else {
654 ref = INVALID_SOCKET_REF;
655 }
656 close(s);
657 return (ref);
658 }
659
660
661 __private_extern__
662 void
663 interface_update_idle_state(const char *if_name)
664 {
665 CFStringRef interface;
666 CFStringRef key;
667 int ref;
668
669 /* only update the SCDynamicStore if the idle ref count is still 0 */
670 ref = socket_reference_count(if_name);
671 if (ref != 0) {
672 return;
673 }
674
675 interface = create_interface_cfstring(if_name);
676 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
677 kSCDynamicStoreDomainState,
678 interface,
679 kSCEntNetIdleRoute);
680
681 SC_log(LOG_DEBUG, "Post interface idle: %s", if_name);
682 SCDynamicStoreNotifyValue(store, key);
683 CFRelease(key);
684 CFRelease(interface);
685 return;
686 }
687 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT