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