2 * Copyright (c) 2002-2006, 2009, 2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * August 5, 2002 Allan Nathanson <ajn@apple.com>
28 * - split code out from eventmon.c
35 #ifndef kSCEntNetIdleRoute
36 #define kSCEntNetIdleRoute CFSTR("IdleRoute")
37 #endif /* kSCEntNetIdleRoute */
40 create_interface_key(const char * if_name
)
42 CFStringRef interface
;
45 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
46 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
47 kSCDynamicStoreDomainState
,
55 static CFMutableDictionaryRef
56 copy_entity(CFStringRef key
)
59 CFMutableDictionaryRef newDict
= NULL
;
61 dict
= cache_SCDynamicStoreCopyValue(store
, key
);
63 if (isA_CFDictionary(dict
) != NULL
) {
64 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
68 if (newDict
== NULL
) {
69 newDict
= CFDictionaryCreateMutable(NULL
,
71 &kCFTypeDictionaryKeyCallBacks
,
72 &kCFTypeDictionaryValueCallBacks
);
79 interface_update_status(const char *if_name
, CFBooleanRef active
,
82 CFStringRef key
= NULL
;
83 CFMutableDictionaryRef newDict
= NULL
;
85 key
= create_interface_key(if_name
);
86 newDict
= copy_entity(key
);
87 /* if new status available, update cache */
89 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkActive
);
91 CFDictionarySetValue(newDict
, kSCPropNetLinkActive
, active
);
94 /* the interface was attached, remove stale state */
95 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkDetaching
);
99 if (CFDictionaryGetCount(newDict
) > 0) {
100 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
102 cache_SCDynamicStoreRemoveValue(store
, key
);
111 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
113 create_linkquality_key(const char * if_name
)
115 CFStringRef interface
;
118 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
119 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
120 kSCDynamicStoreDomainState
,
122 kSCEntNetLinkQuality
);
123 CFRelease(interface
);
130 interface_update_quality_metric(const char *if_name
,
133 CFStringRef key
= NULL
;
134 CFMutableDictionaryRef newDict
= NULL
;
135 CFNumberRef linkquality
= NULL
;
137 key
= create_linkquality_key(if_name
);
138 newDict
= copy_entity(key
);
140 if (quality
!= IFNET_LQM_THRESH_UNKNOWN
) {
141 linkquality
= CFNumberCreate(NULL
, kCFNumberIntType
, &quality
);
142 CFDictionarySetValue(newDict
, kSCPropNetLinkQuality
, linkquality
);
143 CFRelease(linkquality
);
145 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkQuality
);
149 if (CFDictionaryGetCount(newDict
) > 0) {
150 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
152 cache_SCDynamicStoreRemoveValue(store
, key
);
163 link_update_quality_metric(const char *if_name
)
166 int quality
= IFNET_LQM_THRESH_UNKNOWN
;
169 sock
= dgram_socket(AF_INET
);
171 SCLog(TRUE
, LOG_NOTICE
, CFSTR("socket_get_link_quality: socket open failed, %s"), strerror(errno
));
175 bzero((char *)&ifr
, sizeof(ifr
));
176 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
);
178 if (ioctl(sock
, SIOCGIFLINKQUALITYMETRIC
, (caddr_t
)&ifr
) != -1) {
179 quality
= ifr
.ifr_link_quality_metric
;
183 interface_update_quality_metric(if_name
, quality
);
189 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
194 interface_detaching(const char *if_name
)
197 CFMutableDictionaryRef newDict
;
199 key
= create_interface_key(if_name
);
200 newDict
= copy_entity(key
);
201 CFDictionarySetValue(newDict
, kSCPropNetLinkDetaching
,
203 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
210 interface_remove(const char *if_name
)
214 key
= create_interface_key(if_name
);
215 cache_SCDynamicStoreRemoveValue(store
, key
);
218 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
219 key
= create_linkquality_key(if_name
);
220 cache_SCDynamicStoreRemoveValue(store
, key
);
222 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
230 link_update_status(const char *if_name
, boolean_t attach
)
232 CFBooleanRef active
= NULL
;
233 struct ifmediareq ifm
;
236 sock
= dgram_socket(AF_INET
);
238 SCLog(TRUE
, LOG_NOTICE
, CFSTR("link_update_status: socket open failed, %s"), strerror(errno
));
241 bzero((char *)&ifm
, sizeof(ifm
));
242 (void) strncpy(ifm
.ifm_name
, if_name
, sizeof(ifm
.ifm_name
));
244 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) == -1) {
245 /* if media status not available for this interface */
249 if (ifm
.ifm_count
== 0) {
254 if (!(ifm
.ifm_status
& IFM_AVALID
)) {
255 /* if active bit not valid */
259 if (ifm
.ifm_status
& IFM_ACTIVE
) {
260 active
= kCFBooleanTrue
;
262 active
= kCFBooleanFalse
;
266 interface_update_status(if_name
, active
, attach
);
275 link_add(const char *if_name
)
277 CFStringRef interface
;
278 CFStringRef cacheKey
;
279 CFDictionaryRef dict
;
280 CFMutableDictionaryRef newDict
= NULL
;
282 CFMutableArrayRef newIFList
= NULL
;
284 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
285 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
286 kSCDynamicStoreDomainState
);
288 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
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
);
301 newDict
= CFDictionaryCreateMutable(NULL
,
303 &kCFTypeDictionaryKeyCallBacks
,
304 &kCFTypeDictionaryValueCallBacks
);
308 newIFList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
311 if (CFArrayContainsValue(newIFList
,
312 CFRangeMake(0, CFArrayGetCount(newIFList
)),
313 interface
) == FALSE
) {
314 CFArrayAppendValue(newIFList
, interface
);
315 CFDictionarySetValue(newDict
, kSCPropNetInterfaces
, newIFList
);
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 */
323 CFRelease(interface
);
324 if (newDict
) CFRelease(newDict
);
325 if (newIFList
) CFRelease(newIFList
);
333 link_remove(const char *if_name
)
335 CFStringRef interface
;
336 CFStringRef cacheKey
;
337 CFDictionaryRef dict
;
338 CFMutableDictionaryRef newDict
= NULL
;
340 CFMutableArrayRef newIFList
= NULL
;
343 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
344 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
345 kSCDynamicStoreDomainState
);
347 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
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
);
360 ((i
= CFArrayGetFirstIndexOfValue(newIFList
,
361 CFRangeMake(0, CFArrayGetCount(newIFList
)),
362 interface
)) == kCFNotFound
)
364 /* we're not tracking this interface */
368 CFArrayRemoveValueAtIndex(newIFList
, i
);
369 CFDictionarySetValue(newDict
, kSCPropNetInterfaces
, newIFList
);
370 cache_SCDynamicStoreSetValue(store
, cacheKey
, newDict
);
372 interface_remove(if_name
);
377 CFRelease(interface
);
378 if (newDict
) CFRelease(newDict
);
379 if (newIFList
) CFRelease(newIFList
);
385 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
386 #define INVALID_SOCKET_REF -1
389 socket_reference_count(const char* if_name
) {
391 int ref
= INVALID_SOCKET_REF
;
394 s
= dgram_socket(AF_INET
);
399 bzero((char *)&ifr
, sizeof(ifr
));
400 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
);
402 if (ioctl(s
, SIOCGIFGETRTREFCNT
, (caddr_t
)&ifr
) != -1) {
403 ref
= ifr
.ifr_route_refcnt
;
405 ref
= INVALID_SOCKET_REF
;
414 interface_update_idle_state(const char *if_name
)
416 CFStringRef if_name_cf
;
420 /* We will only update the SCDynamicStore if the idle ref count
422 ref
= socket_reference_count(if_name
);
427 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
,
428 kCFStringEncodingASCII
);
430 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
431 kSCDynamicStoreDomainState
,
435 cache_SCDynamicStoreNotifyValue(store
, key
);
437 CFRelease(if_name_cf
);
440 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT