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