2 * Copyright (c) 2002-2006, 2009, 2011, 2013 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
36 #ifndef kSCEntNetIdleRoute
37 #define kSCEntNetIdleRoute CFSTR("IdleRoute")
38 #endif /* kSCEntNetIdleRoute */
41 create_interface_key(const char * if_name
)
43 CFStringRef interface
;
46 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
47 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
48 kSCDynamicStoreDomainState
,
56 static CFMutableDictionaryRef
57 copy_entity(CFStringRef key
)
60 CFMutableDictionaryRef newDict
= NULL
;
62 dict
= cache_SCDynamicStoreCopyValue(store
, key
);
64 if (isA_CFDictionary(dict
) != NULL
) {
65 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
69 if (newDict
== NULL
) {
70 newDict
= CFDictionaryCreateMutable(NULL
,
72 &kCFTypeDictionaryKeyCallBacks
,
73 &kCFTypeDictionaryValueCallBacks
);
80 interface_update_status(const char *if_name
,
81 CFBooleanRef active
, boolean_t attach
,
82 CFBooleanRef expensive
)
84 CFStringRef key
= NULL
;
85 CFMutableDictionaryRef newDict
= NULL
;
87 key
= create_interface_key(if_name
);
88 newDict
= copy_entity(key
);
89 /* if new status available, update cache */
91 CFDictionarySetValue(newDict
, kSCPropNetLinkActive
, active
);
93 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkActive
);
97 /* the interface was attached, remove stale state */
98 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkDetaching
);
101 if ((expensive
!= NULL
) && CFBooleanGetValue(expensive
)) {
102 CFDictionarySetValue(newDict
, kSCPropNetLinkExpensive
, expensive
);
104 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkExpensive
);
108 if (CFDictionaryGetCount(newDict
) > 0) {
109 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
111 cache_SCDynamicStoreRemoveValue(store
, key
);
120 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
122 create_linkquality_key(const char * if_name
)
124 CFStringRef interface
;
127 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
128 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
129 kSCDynamicStoreDomainState
,
131 kSCEntNetLinkQuality
);
132 CFRelease(interface
);
139 interface_update_quality_metric(const char *if_name
,
142 CFStringRef key
= NULL
;
143 CFMutableDictionaryRef newDict
= NULL
;
144 CFNumberRef linkquality
= NULL
;
146 key
= create_linkquality_key(if_name
);
147 newDict
= copy_entity(key
);
149 if (quality
!= IFNET_LQM_THRESH_UNKNOWN
) {
150 linkquality
= CFNumberCreate(NULL
, kCFNumberIntType
, &quality
);
151 CFDictionarySetValue(newDict
, kSCPropNetLinkQuality
, linkquality
);
152 CFRelease(linkquality
);
154 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkQuality
);
158 if (CFDictionaryGetCount(newDict
) > 0) {
159 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
161 cache_SCDynamicStoreRemoveValue(store
, key
);
172 link_update_quality_metric(const char *if_name
)
175 int quality
= IFNET_LQM_THRESH_UNKNOWN
;
178 sock
= dgram_socket(AF_INET
);
180 SCLog(TRUE
, LOG_NOTICE
, CFSTR("socket_get_link_quality: socket open failed, %s"), strerror(errno
));
184 bzero((char *)&ifr
, sizeof(ifr
));
185 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
);
187 if (ioctl(sock
, SIOCGIFLINKQUALITYMETRIC
, (caddr_t
)&ifr
) != -1) {
188 quality
= ifr
.ifr_link_quality_metric
;
192 interface_update_quality_metric(if_name
, quality
);
198 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
203 create_link_issues_key(const char * if_name
)
205 CFStringRef interface
;
208 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
209 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
210 kSCDynamicStoreDomainState
,
212 kSCEntNetLinkIssues
);
213 CFRelease(interface
);
220 interface_update_link_issues(const char *if_name
,
230 CFMutableDictionaryRef newDict
;
233 key
= create_link_issues_key(if_name
);
235 newDict
= copy_entity(key
);
237 modidData
= CFDataCreate(NULL
, modid
, modid_size
);
238 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesModuleID
, modidData
);
239 CFRelease(modidData
);
241 if (info_size
!= 0) {
242 infoData
= CFDataCreate(NULL
, info
, info_size
);
243 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesInfo
, infoData
);
246 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkIssuesInfo
);
249 timeStamp
= CFDateCreate(NULL
, timestamp
);
250 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesTimeStamp
, timeStamp
);
251 CFRelease(timeStamp
);
253 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
258 #endif /* KEV_DL_ISSUES */
263 interface_detaching(const char *if_name
)
266 CFMutableDictionaryRef newDict
;
268 key
= create_interface_key(if_name
);
269 newDict
= copy_entity(key
);
270 CFDictionarySetValue(newDict
, kSCPropNetLinkDetaching
,
272 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
280 interface_remove(const char *if_name
)
284 key
= create_interface_key(if_name
);
285 cache_SCDynamicStoreRemoveValue(store
, key
);
288 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
289 key
= create_linkquality_key(if_name
);
290 cache_SCDynamicStoreRemoveValue(store
, key
);
292 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
295 key
= create_link_issues_key(if_name
);
296 cache_SCDynamicStoreRemoveValue(store
, key
);
298 #endif /* KEV_DL_ISSUES */
306 link_update_status(const char *if_name
, boolean_t attach
)
308 CFBooleanRef active
= NULL
;
309 CFBooleanRef expensive
;
310 struct ifmediareq ifm
;
313 sock
= dgram_socket(AF_INET
);
315 SCLog(TRUE
, LOG_NOTICE
, CFSTR("link_update_status: socket open failed, %s"), strerror(errno
));
320 bzero((char *)&ifm
, sizeof(ifm
));
321 (void) strncpy(ifm
.ifm_name
, if_name
, sizeof(ifm
.ifm_name
));
323 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) == -1) {
324 /* if media status not available for this interface */
328 if (ifm
.ifm_count
== 0) {
333 if (!(ifm
.ifm_status
& IFM_AVALID
)) {
334 /* if active bit not valid */
338 if (ifm
.ifm_status
& IFM_ACTIVE
) {
339 active
= kCFBooleanTrue
;
341 active
= kCFBooleanFalse
;
346 /* get "Expensive" */
347 expensive
= interface_update_expensive(if_name
);
350 interface_update_status(if_name
, active
, attach
, expensive
);
357 link_add(const char *if_name
)
359 CFStringRef interface
;
360 CFStringRef cacheKey
;
361 CFDictionaryRef dict
;
362 CFMutableDictionaryRef newDict
= NULL
;
364 CFMutableArrayRef newIFList
= NULL
;
366 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
367 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
368 kSCDynamicStoreDomainState
);
370 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
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
);
383 newDict
= CFDictionaryCreateMutable(NULL
,
385 &kCFTypeDictionaryKeyCallBacks
,
386 &kCFTypeDictionaryValueCallBacks
);
390 newIFList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
393 if (CFArrayContainsValue(newIFList
,
394 CFRangeMake(0, CFArrayGetCount(newIFList
)),
395 interface
) == FALSE
) {
396 CFArrayAppendValue(newIFList
, interface
);
397 CFDictionarySetValue(newDict
, kSCPropNetInterfaces
, newIFList
);
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 */
405 CFRelease(interface
);
406 if (newDict
) CFRelease(newDict
);
407 if (newIFList
) CFRelease(newIFList
);
414 link_remove(const char *if_name
)
416 CFStringRef interface
;
417 CFStringRef cacheKey
;
418 CFDictionaryRef dict
;
419 CFMutableDictionaryRef newDict
= NULL
;
421 CFMutableArrayRef newIFList
= NULL
;
424 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
425 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
426 kSCDynamicStoreDomainState
);
428 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
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
);
441 ((i
= CFArrayGetFirstIndexOfValue(newIFList
,
442 CFRangeMake(0, CFArrayGetCount(newIFList
)),
443 interface
)) == kCFNotFound
)
445 /* we're not tracking this interface */
449 CFArrayRemoveValueAtIndex(newIFList
, i
);
450 CFDictionarySetValue(newDict
, kSCPropNetInterfaces
, newIFList
);
451 cache_SCDynamicStoreSetValue(store
, cacheKey
, newDict
);
453 interface_remove(if_name
);
458 CFRelease(interface
);
459 if (newDict
) CFRelease(newDict
);
460 if (newIFList
) CFRelease(newIFList
);
465 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
466 #define INVALID_SOCKET_REF -1
469 socket_reference_count(const char* if_name
) {
471 int ref
= INVALID_SOCKET_REF
;
474 s
= dgram_socket(AF_INET
);
479 bzero((char *)&ifr
, sizeof(ifr
));
480 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
);
482 if (ioctl(s
, SIOCGIFGETRTREFCNT
, (caddr_t
)&ifr
) != -1) {
483 ref
= ifr
.ifr_route_refcnt
;
485 ref
= INVALID_SOCKET_REF
;
494 interface_update_idle_state(const char *if_name
)
496 CFStringRef if_name_cf
;
500 /* We will only update the SCDynamicStore if the idle ref count
502 ref
= socket_reference_count(if_name
);
507 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
,
508 kCFStringEncodingASCII
);
510 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
511 kSCDynamicStoreDomainState
,
515 cache_SCDynamicStoreNotifyValue(store
, key
);
517 CFRelease(if_name_cf
);
520 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT