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