]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/ev_dlil.c
configd-699.30.1.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / ev_dlil.c
1 /*
2 * Copyright (c) 2002-2006, 2009, 2011, 2013 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 cache_SCDynamicStoreSetValue(store, key, newDict);
110 } else {
111 cache_SCDynamicStoreRemoveValue(store, key);
112 }
113
114 CFRelease(key);
115 CFRelease(newDict);
116 return;
117 }
118
119
120 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
121 static CFStringRef
122 create_linkquality_key(const char * if_name)
123 {
124 CFStringRef interface;
125 CFStringRef key;
126
127 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
128 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
129 kSCDynamicStoreDomainState,
130 interface,
131 kSCEntNetLinkQuality);
132 CFRelease(interface);
133 return (key);
134 }
135
136
137 __private_extern__
138 void
139 interface_update_quality_metric(const char *if_name,
140 int quality)
141 {
142 CFStringRef key = NULL;
143 CFMutableDictionaryRef newDict = NULL;
144 CFNumberRef linkquality = NULL;
145
146 key = create_linkquality_key(if_name);
147 newDict = copy_entity(key);
148
149 if (quality != IFNET_LQM_THRESH_UNKNOWN) {
150 linkquality = CFNumberCreate(NULL, kCFNumberIntType, &quality);
151 CFDictionarySetValue(newDict, kSCPropNetLinkQuality, linkquality);
152 CFRelease(linkquality);
153 } else {
154 CFDictionaryRemoveValue(newDict, kSCPropNetLinkQuality);
155 }
156
157 /* update status */
158 if (CFDictionaryGetCount(newDict) > 0) {
159 cache_SCDynamicStoreSetValue(store, key, newDict);
160 } else {
161 cache_SCDynamicStoreRemoveValue(store, key);
162 }
163
164 CFRelease(key);
165 CFRelease(newDict);
166 return;
167 }
168
169
170 static
171 void
172 link_update_quality_metric(const char *if_name)
173 {
174 struct ifreq ifr;
175 int quality = IFNET_LQM_THRESH_UNKNOWN;
176 int sock;
177
178 sock = dgram_socket(AF_INET);
179 if (sock == -1) {
180 SCLog(TRUE, LOG_NOTICE, CFSTR("socket_get_link_quality: socket open failed, %s"), strerror(errno));
181 goto done;
182 }
183
184 bzero((char *)&ifr, sizeof(ifr));
185 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name);
186
187 if (ioctl(sock, SIOCGIFLINKQUALITYMETRIC, (caddr_t)&ifr) != -1) {
188 quality = ifr.ifr_link_quality_metric;
189 }
190
191 done:
192 interface_update_quality_metric(if_name, quality);
193 if (sock != -1)
194 close(sock);
195 return;
196
197 }
198 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
199
200
201 #ifdef KEV_DL_ISSUES
202 static CFStringRef
203 create_link_issues_key(const char * if_name)
204 {
205 CFStringRef interface;
206 CFStringRef key;
207
208 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
209 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
210 kSCDynamicStoreDomainState,
211 interface,
212 kSCEntNetLinkIssues);
213 CFRelease(interface);
214 return (key);
215 }
216
217
218 __private_extern__
219 void
220 interface_update_link_issues(const char *if_name,
221 uint64_t timestamp,
222 uint8_t *modid,
223 size_t modid_size,
224 uint8_t *info,
225 size_t info_size)
226 {
227 CFDataRef infoData;
228 CFStringRef key;
229 CFDataRef modidData;
230 CFMutableDictionaryRef newDict;
231 CFDateRef timeStamp;
232
233 key = create_link_issues_key(if_name);
234
235 newDict = copy_entity(key);
236
237 modidData = CFDataCreate(NULL, modid, modid_size);
238 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesModuleID, modidData);
239 CFRelease(modidData);
240
241 if (info_size != 0) {
242 infoData = CFDataCreate(NULL, info, info_size);
243 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesInfo, infoData);
244 CFRelease(infoData);
245 } else {
246 CFDictionaryRemoveValue(newDict, kSCPropNetLinkIssuesInfo);
247 }
248
249 timeStamp = CFDateCreate(NULL, timestamp);
250 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesTimeStamp, timeStamp);
251 CFRelease(timeStamp);
252
253 cache_SCDynamicStoreSetValue(store, key, newDict);
254 CFRelease(newDict);
255 CFRelease(key);
256 return;
257 }
258 #endif /* KEV_DL_ISSUES */
259
260
261 __private_extern__
262 void
263 interface_detaching(const char *if_name)
264 {
265 CFStringRef key;
266 CFMutableDictionaryRef newDict;
267
268 key = create_interface_key(if_name);
269 newDict = copy_entity(key);
270 CFDictionarySetValue(newDict, kSCPropNetLinkDetaching,
271 kCFBooleanTrue);
272 cache_SCDynamicStoreSetValue(store, key, newDict);
273 CFRelease(newDict);
274 CFRelease(key);
275 return;
276 }
277
278
279 static void
280 interface_remove(const char *if_name)
281 {
282 CFStringRef key;
283
284 key = create_interface_key(if_name);
285 cache_SCDynamicStoreRemoveValue(store, key);
286 CFRelease(key);
287
288 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
289 key = create_linkquality_key(if_name);
290 cache_SCDynamicStoreRemoveValue(store, key);
291 CFRelease(key);
292 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
293
294 #ifdef KEV_DL_ISSUES
295 key = create_link_issues_key(if_name);
296 cache_SCDynamicStoreRemoveValue(store, key);
297 CFRelease(key);
298 #endif /* KEV_DL_ISSUES */
299
300 return;
301 }
302
303
304 __private_extern__
305 void
306 link_update_status(const char *if_name, boolean_t attach)
307 {
308 CFBooleanRef active = NULL;
309 CFBooleanRef expensive;
310 struct ifmediareq ifm;
311 int sock;
312
313 sock = dgram_socket(AF_INET);
314 if (sock == -1) {
315 SCLog(TRUE, LOG_NOTICE, CFSTR("link_update_status: socket open failed, %s"), strerror(errno));
316 return;
317 }
318
319 /* get "Link" */
320 bzero((char *)&ifm, sizeof(ifm));
321 (void) strncpy(ifm.ifm_name, if_name, sizeof(ifm.ifm_name));
322
323 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) == -1) {
324 /* if media status not available for this interface */
325 goto update;
326 }
327
328 if (ifm.ifm_count == 0) {
329 /* no media types */
330 goto update;
331 }
332
333 if (!(ifm.ifm_status & IFM_AVALID)) {
334 /* if active bit not valid */
335 goto update;
336 }
337
338 if (ifm.ifm_status & IFM_ACTIVE) {
339 active = kCFBooleanTrue;
340 } else {
341 active = kCFBooleanFalse;
342 }
343
344 update:
345
346 /* get "Expensive" */
347 expensive = interface_update_expensive(if_name);
348
349 /* update status */
350 interface_update_status(if_name, active, attach, expensive);
351 close(sock);
352 return;
353 }
354
355 __private_extern__
356 void
357 link_add(const char *if_name)
358 {
359 CFStringRef interface;
360 CFStringRef cacheKey;
361 CFDictionaryRef dict;
362 CFMutableDictionaryRef newDict = NULL;
363 CFArrayRef ifList;
364 CFMutableArrayRef newIFList = NULL;
365
366 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
367 cacheKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
368 kSCDynamicStoreDomainState);
369
370 dict = cache_SCDynamicStoreCopyValue(store, cacheKey);
371 if (dict) {
372 if (isA_CFDictionary(dict)) {
373 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
374 ifList = CFDictionaryGetValue(newDict, kSCPropNetInterfaces);
375 if (isA_CFArray(ifList)) {
376 newIFList = CFArrayCreateMutableCopy(NULL, 0, ifList);
377 }
378 }
379 CFRelease(dict);
380 }
381
382 if (!newDict) {
383 newDict = CFDictionaryCreateMutable(NULL,
384 0,
385 &kCFTypeDictionaryKeyCallBacks,
386 &kCFTypeDictionaryValueCallBacks);
387 }
388
389 if (!newIFList) {
390 newIFList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
391 }
392
393 if (CFArrayContainsValue(newIFList,
394 CFRangeMake(0, CFArrayGetCount(newIFList)),
395 interface) == FALSE) {
396 CFArrayAppendValue(newIFList, interface);
397 CFDictionarySetValue(newDict, kSCPropNetInterfaces, newIFList);
398 }
399 cache_SCDynamicStoreSetValue(store, cacheKey, newDict);
400 link_update_status(if_name, TRUE);
401 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
402 link_update_quality_metric(if_name);
403 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
404 CFRelease(cacheKey);
405 CFRelease(interface);
406 if (newDict) CFRelease(newDict);
407 if (newIFList) CFRelease(newIFList);
408 return;
409 }
410
411
412 __private_extern__
413 void
414 link_remove(const char *if_name)
415 {
416 CFStringRef interface;
417 CFStringRef cacheKey;
418 CFDictionaryRef dict;
419 CFMutableDictionaryRef newDict = NULL;
420 CFArrayRef ifList;
421 CFMutableArrayRef newIFList = NULL;
422 CFIndex i;
423
424 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
425 cacheKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
426 kSCDynamicStoreDomainState);
427
428 dict = cache_SCDynamicStoreCopyValue(store, cacheKey);
429 if (dict) {
430 if (isA_CFDictionary(dict)) {
431 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
432 ifList = CFDictionaryGetValue(newDict, kSCPropNetInterfaces);
433 if (isA_CFArray(ifList)) {
434 newIFList = CFArrayCreateMutableCopy(NULL, 0, ifList);
435 }
436 }
437 CFRelease(dict);
438 }
439
440 if (!newIFList ||
441 ((i = CFArrayGetFirstIndexOfValue(newIFList,
442 CFRangeMake(0, CFArrayGetCount(newIFList)),
443 interface)) == kCFNotFound)
444 ) {
445 /* we're not tracking this interface */
446 goto done;
447 }
448
449 CFArrayRemoveValueAtIndex(newIFList, i);
450 CFDictionarySetValue(newDict, kSCPropNetInterfaces, newIFList);
451 cache_SCDynamicStoreSetValue(store, cacheKey, newDict);
452
453 interface_remove(if_name);
454
455 done:
456
457 CFRelease(cacheKey);
458 CFRelease(interface);
459 if (newDict) CFRelease(newDict);
460 if (newIFList) CFRelease(newIFList);
461 return;
462 }
463
464
465 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
466 #define INVALID_SOCKET_REF -1
467 static
468 int
469 socket_reference_count(const char* if_name) {
470 struct ifreq ifr;
471 int ref = INVALID_SOCKET_REF;
472 int s;
473
474 s = dgram_socket(AF_INET);
475 if (s == -1) {
476 return (ref);
477 }
478
479 bzero((char *)&ifr, sizeof(ifr));
480 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name);
481
482 if (ioctl(s, SIOCGIFGETRTREFCNT, (caddr_t)&ifr) != -1) {
483 ref = ifr.ifr_route_refcnt;
484 } else {
485 ref = INVALID_SOCKET_REF;
486 }
487 close(s);
488 return (ref);
489 }
490
491
492 __private_extern__
493 void
494 interface_update_idle_state(const char *if_name)
495 {
496 CFStringRef if_name_cf;
497 CFStringRef key;
498 int ref;
499
500 /* We will only update the SCDynamicStore if the idle ref count
501 * is still 0 */
502 ref = socket_reference_count(if_name);
503 if (ref != 0) {
504 return;
505 }
506
507 if_name_cf = CFStringCreateWithCString(NULL, if_name,
508 kCFStringEncodingASCII);
509
510 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
511 kSCDynamicStoreDomainState,
512 if_name_cf,
513 kSCEntNetIdleRoute);
514
515 cache_SCDynamicStoreNotifyValue(store, key);
516 CFRelease(key);
517 CFRelease(if_name_cf);
518 return;
519 }
520 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT