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
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 create_link_issues_key(const char * if_name
)
196 CFStringRef interface
;
199 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
200 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
201 kSCDynamicStoreDomainState
,
203 kSCEntNetLinkIssues
);
204 CFRelease(interface
);
211 interface_update_link_issues(const char *if_name
,
221 CFMutableDictionaryRef newDict
;
224 key
= create_link_issues_key(if_name
);
226 newDict
= copy_entity(key
);
228 modidData
= CFDataCreate(NULL
, modid
, modid_size
);
229 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesModuleID
, modidData
);
230 CFRelease(modidData
);
232 if (info_size
!= 0) {
233 infoData
= CFDataCreate(NULL
, info
, info_size
);
234 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesInfo
, infoData
);
237 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkIssuesInfo
);
240 timeStamp
= CFDateCreate(NULL
, timestamp
);
241 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesTimeStamp
, timeStamp
);
242 CFRelease(timeStamp
);
244 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
249 #endif /* KEV_DL_ISSUES */
254 interface_detaching(const char *if_name
)
257 CFMutableDictionaryRef newDict
;
259 key
= create_interface_key(if_name
);
260 newDict
= copy_entity(key
);
261 CFDictionarySetValue(newDict
, kSCPropNetLinkDetaching
,
263 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
271 interface_remove(const char *if_name
)
275 key
= create_interface_key(if_name
);
276 cache_SCDynamicStoreRemoveValue(store
, key
);
279 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
280 key
= create_linkquality_key(if_name
);
281 cache_SCDynamicStoreRemoveValue(store
, key
);
283 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
286 key
= create_link_issues_key(if_name
);
287 cache_SCDynamicStoreRemoveValue(store
, key
);
289 #endif /* KEV_DL_ISSUES */
297 link_update_status(const char *if_name
, boolean_t attach
)
299 CFBooleanRef active
= NULL
;
300 struct ifmediareq ifm
;
303 sock
= dgram_socket(AF_INET
);
305 SCLog(TRUE
, LOG_NOTICE
, CFSTR("link_update_status: socket open failed, %s"), strerror(errno
));
308 bzero((char *)&ifm
, sizeof(ifm
));
309 (void) strncpy(ifm
.ifm_name
, if_name
, sizeof(ifm
.ifm_name
));
311 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) == -1) {
312 /* if media status not available for this interface */
316 if (ifm
.ifm_count
== 0) {
321 if (!(ifm
.ifm_status
& IFM_AVALID
)) {
322 /* if active bit not valid */
326 if (ifm
.ifm_status
& IFM_ACTIVE
) {
327 active
= kCFBooleanTrue
;
329 active
= kCFBooleanFalse
;
333 interface_update_status(if_name
, active
, attach
);
341 link_add(const char *if_name
)
343 CFStringRef interface
;
344 CFStringRef cacheKey
;
345 CFDictionaryRef dict
;
346 CFMutableDictionaryRef newDict
= NULL
;
348 CFMutableArrayRef newIFList
= NULL
;
350 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
351 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
352 kSCDynamicStoreDomainState
);
354 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
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
);
367 newDict
= CFDictionaryCreateMutable(NULL
,
369 &kCFTypeDictionaryKeyCallBacks
,
370 &kCFTypeDictionaryValueCallBacks
);
374 newIFList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
377 if (CFArrayContainsValue(newIFList
,
378 CFRangeMake(0, CFArrayGetCount(newIFList
)),
379 interface
) == FALSE
) {
380 CFArrayAppendValue(newIFList
, interface
);
381 CFDictionarySetValue(newDict
, kSCPropNetInterfaces
, newIFList
);
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 */
389 CFRelease(interface
);
390 if (newDict
) CFRelease(newDict
);
391 if (newIFList
) CFRelease(newIFList
);
399 link_remove(const char *if_name
)
401 CFStringRef interface
;
402 CFStringRef cacheKey
;
403 CFDictionaryRef dict
;
404 CFMutableDictionaryRef newDict
= NULL
;
406 CFMutableArrayRef newIFList
= NULL
;
409 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
410 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
411 kSCDynamicStoreDomainState
);
413 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
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
);
426 ((i
= CFArrayGetFirstIndexOfValue(newIFList
,
427 CFRangeMake(0, CFArrayGetCount(newIFList
)),
428 interface
)) == kCFNotFound
)
430 /* we're not tracking this interface */
434 CFArrayRemoveValueAtIndex(newIFList
, i
);
435 CFDictionarySetValue(newDict
, kSCPropNetInterfaces
, newIFList
);
436 cache_SCDynamicStoreSetValue(store
, cacheKey
, newDict
);
438 interface_remove(if_name
);
443 CFRelease(interface
);
444 if (newDict
) CFRelease(newDict
);
445 if (newIFList
) CFRelease(newIFList
);
451 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
452 #define INVALID_SOCKET_REF -1
455 socket_reference_count(const char* if_name
) {
457 int ref
= INVALID_SOCKET_REF
;
460 s
= dgram_socket(AF_INET
);
465 bzero((char *)&ifr
, sizeof(ifr
));
466 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
);
468 if (ioctl(s
, SIOCGIFGETRTREFCNT
, (caddr_t
)&ifr
) != -1) {
469 ref
= ifr
.ifr_route_refcnt
;
471 ref
= INVALID_SOCKET_REF
;
480 interface_update_idle_state(const char *if_name
)
482 CFStringRef if_name_cf
;
486 /* We will only update the SCDynamicStore if the idle ref count
488 ref
= socket_reference_count(if_name
);
493 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
,
494 kCFStringEncodingASCII
);
496 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
497 kSCDynamicStoreDomainState
,
501 cache_SCDynamicStoreNotifyValue(store
, key
);
503 CFRelease(if_name_cf
);
506 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT