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