]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/ev_dlil.c
configd-453.18.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / ev_dlil.c
1 /*
2 * Copyright (c) 2002-2006, 2009, 2011 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 __private_extern__
193 void
194 interface_detaching(const char *if_name)
195 {
196 CFStringRef key;
197 CFMutableDictionaryRef newDict;
198
199 key = create_interface_key(if_name);
200 newDict = copy_entity(key);
201 CFDictionarySetValue(newDict, kSCPropNetLinkDetaching,
202 kCFBooleanTrue);
203 cache_SCDynamicStoreSetValue(store, key, newDict);
204 CFRelease(newDict);
205 CFRelease(key);
206 return;
207 }
208
209 static void
210 interface_remove(const char *if_name)
211 {
212 CFStringRef key;
213
214 key = create_interface_key(if_name);
215 cache_SCDynamicStoreRemoveValue(store, key);
216 CFRelease(key);
217
218 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
219 key = create_linkquality_key(if_name);
220 cache_SCDynamicStoreRemoveValue(store, key);
221 CFRelease(key);
222 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
223
224 return;
225 }
226
227
228 __private_extern__
229 void
230 link_update_status(const char *if_name, boolean_t attach)
231 {
232 CFBooleanRef active = NULL;
233 struct ifmediareq ifm;
234 int sock;
235
236 sock = dgram_socket(AF_INET);
237 if (sock == -1) {
238 SCLog(TRUE, LOG_NOTICE, CFSTR("link_update_status: socket open failed, %s"), strerror(errno));
239 goto done;
240 }
241 bzero((char *)&ifm, sizeof(ifm));
242 (void) strncpy(ifm.ifm_name, if_name, sizeof(ifm.ifm_name));
243
244 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) == -1) {
245 /* if media status not available for this interface */
246 goto done;
247 }
248
249 if (ifm.ifm_count == 0) {
250 /* no media types */
251 goto done;
252 }
253
254 if (!(ifm.ifm_status & IFM_AVALID)) {
255 /* if active bit not valid */
256 goto done;
257 }
258
259 if (ifm.ifm_status & IFM_ACTIVE) {
260 active = kCFBooleanTrue;
261 } else {
262 active = kCFBooleanFalse;
263 }
264
265 done:
266 interface_update_status(if_name, active, attach);
267 if (sock != -1)
268 close(sock);
269 return;
270 }
271
272
273 __private_extern__
274 void
275 link_add(const char *if_name)
276 {
277 CFStringRef interface;
278 CFStringRef cacheKey;
279 CFDictionaryRef dict;
280 CFMutableDictionaryRef newDict = NULL;
281 CFArrayRef ifList;
282 CFMutableArrayRef newIFList = NULL;
283
284 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
285 cacheKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
286 kSCDynamicStoreDomainState);
287
288 dict = cache_SCDynamicStoreCopyValue(store, cacheKey);
289 if (dict) {
290 if (isA_CFDictionary(dict)) {
291 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
292 ifList = CFDictionaryGetValue(newDict, kSCPropNetInterfaces);
293 if (isA_CFArray(ifList)) {
294 newIFList = CFArrayCreateMutableCopy(NULL, 0, ifList);
295 }
296 }
297 CFRelease(dict);
298 }
299
300 if (!newDict) {
301 newDict = CFDictionaryCreateMutable(NULL,
302 0,
303 &kCFTypeDictionaryKeyCallBacks,
304 &kCFTypeDictionaryValueCallBacks);
305 }
306
307 if (!newIFList) {
308 newIFList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
309 }
310
311 if (CFArrayContainsValue(newIFList,
312 CFRangeMake(0, CFArrayGetCount(newIFList)),
313 interface) == FALSE) {
314 CFArrayAppendValue(newIFList, interface);
315 CFDictionarySetValue(newDict, kSCPropNetInterfaces, newIFList);
316 }
317 cache_SCDynamicStoreSetValue(store, cacheKey, newDict);
318 link_update_status(if_name, TRUE);
319 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
320 link_update_quality_metric(if_name);
321 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
322 CFRelease(cacheKey);
323 CFRelease(interface);
324 if (newDict) CFRelease(newDict);
325 if (newIFList) CFRelease(newIFList);
326
327 return;
328 }
329
330
331 __private_extern__
332 void
333 link_remove(const char *if_name)
334 {
335 CFStringRef interface;
336 CFStringRef cacheKey;
337 CFDictionaryRef dict;
338 CFMutableDictionaryRef newDict = NULL;
339 CFArrayRef ifList;
340 CFMutableArrayRef newIFList = NULL;
341 CFIndex i;
342
343 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
344 cacheKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
345 kSCDynamicStoreDomainState);
346
347 dict = cache_SCDynamicStoreCopyValue(store, cacheKey);
348 if (dict) {
349 if (isA_CFDictionary(dict)) {
350 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
351 ifList = CFDictionaryGetValue(newDict, kSCPropNetInterfaces);
352 if (isA_CFArray(ifList)) {
353 newIFList = CFArrayCreateMutableCopy(NULL, 0, ifList);
354 }
355 }
356 CFRelease(dict);
357 }
358
359 if (!newIFList ||
360 ((i = CFArrayGetFirstIndexOfValue(newIFList,
361 CFRangeMake(0, CFArrayGetCount(newIFList)),
362 interface)) == kCFNotFound)
363 ) {
364 /* we're not tracking this interface */
365 goto done;
366 }
367
368 CFArrayRemoveValueAtIndex(newIFList, i);
369 CFDictionarySetValue(newDict, kSCPropNetInterfaces, newIFList);
370 cache_SCDynamicStoreSetValue(store, cacheKey, newDict);
371
372 interface_remove(if_name);
373
374 done:
375
376 CFRelease(cacheKey);
377 CFRelease(interface);
378 if (newDict) CFRelease(newDict);
379 if (newIFList) CFRelease(newIFList);
380
381 return;
382 }
383
384
385 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
386 #define INVALID_SOCKET_REF -1
387 static
388 int
389 socket_reference_count(const char* if_name) {
390 struct ifreq ifr;
391 int ref = INVALID_SOCKET_REF;
392 int s;
393
394 s = dgram_socket(AF_INET);
395 if (s == -1) {
396 return (ref);
397 }
398
399 bzero((char *)&ifr, sizeof(ifr));
400 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name);
401
402 if (ioctl(s, SIOCGIFGETRTREFCNT, (caddr_t)&ifr) != -1) {
403 ref = ifr.ifr_route_refcnt;
404 } else {
405 ref = INVALID_SOCKET_REF;
406 }
407 close(s);
408 return (ref);
409 }
410
411
412 __private_extern__
413 void
414 interface_update_idle_state(const char *if_name)
415 {
416 CFStringRef if_name_cf;
417 CFStringRef key;
418 int ref;
419
420 /* We will only update the SCDynamicStore if the idle ref count
421 * is still 0 */
422 ref = socket_reference_count(if_name);
423 if (ref != 0) {
424 return;
425 }
426
427 if_name_cf = CFStringCreateWithCString(NULL, if_name,
428 kCFStringEncodingASCII);
429
430 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
431 kSCDynamicStoreDomainState,
432 if_name_cf,
433 kSCEntNetIdleRoute);
434
435 cache_SCDynamicStoreNotifyValue(store, key);
436 CFRelease(key);
437 CFRelease(if_name_cf);
438 return;
439 }
440 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT