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