2 * Copyright (c) 2002-2006, 2009, 2011, 2013, 2015 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 SC_log(LOG_DEBUG
, "Update interface link status: %s: %@", if_name
, newDict
);
110 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
112 SC_log(LOG_DEBUG
, "Update interface link status: %s: <removed>", if_name
);
113 cache_SCDynamicStoreRemoveValue(store
, key
);
122 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
124 create_linkquality_key(const char * if_name
)
126 CFStringRef interface
;
129 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
130 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
131 kSCDynamicStoreDomainState
,
133 kSCEntNetLinkQuality
);
134 CFRelease(interface
);
141 interface_update_quality_metric(const char *if_name
,
144 CFStringRef key
= NULL
;
145 CFMutableDictionaryRef newDict
= NULL
;
146 CFNumberRef linkquality
= NULL
;
148 key
= create_linkquality_key(if_name
);
149 newDict
= copy_entity(key
);
151 if (quality
!= IFNET_LQM_THRESH_UNKNOWN
) {
152 linkquality
= CFNumberCreate(NULL
, kCFNumberIntType
, &quality
);
153 CFDictionarySetValue(newDict
, kSCPropNetLinkQuality
, linkquality
);
154 CFRelease(linkquality
);
156 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkQuality
);
160 if (CFDictionaryGetCount(newDict
) > 0) {
161 SC_log(LOG_DEBUG
, "Update interface link quality: %s: %@", if_name
, newDict
);
162 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
164 SC_log(LOG_DEBUG
, "Update interface link quality: %s: <removed>", if_name
);
165 cache_SCDynamicStoreRemoveValue(store
, key
);
176 link_update_quality_metric(const char *if_name
)
179 int quality
= IFNET_LQM_THRESH_UNKNOWN
;
182 sock
= dgram_socket(AF_INET
);
187 bzero((char *)&ifr
, sizeof(ifr
));
188 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
);
190 if (ioctl(sock
, SIOCGIFLINKQUALITYMETRIC
, (caddr_t
)&ifr
) != -1) {
191 quality
= ifr
.ifr_link_quality_metric
;
195 interface_update_quality_metric(if_name
, quality
);
201 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
206 create_link_issues_key(const char * if_name
)
208 CFStringRef interface
;
211 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
212 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
213 kSCDynamicStoreDomainState
,
215 kSCEntNetLinkIssues
);
216 CFRelease(interface
);
223 interface_update_link_issues(const char *if_name
,
233 CFMutableDictionaryRef newDict
;
236 key
= create_link_issues_key(if_name
);
238 newDict
= copy_entity(key
);
240 modidData
= CFDataCreate(NULL
, modid
, modid_size
);
241 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesModuleID
, modidData
);
242 CFRelease(modidData
);
244 if (info_size
!= 0) {
245 infoData
= CFDataCreate(NULL
, info
, info_size
);
246 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesInfo
, infoData
);
249 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkIssuesInfo
);
252 timeStamp
= CFDateCreate(NULL
, timestamp
);
253 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesTimeStamp
, timeStamp
);
254 CFRelease(timeStamp
);
256 SC_log(LOG_DEBUG
, "Update interface link issues: %s: %@", if_name
, newDict
);
257 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
262 #endif /* KEV_DL_ISSUES */
267 interface_detaching(const char *if_name
)
270 CFMutableDictionaryRef newDict
;
272 SC_log(LOG_DEBUG
, "Detach interface: %s", if_name
);
274 key
= create_interface_key(if_name
);
275 newDict
= copy_entity(key
);
276 CFDictionarySetValue(newDict
, kSCPropNetLinkDetaching
,
278 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
286 interface_remove(const char *if_name
)
290 SC_log(LOG_DEBUG
, "Remove interface: %s", if_name
);
292 key
= create_interface_key(if_name
);
293 cache_SCDynamicStoreRemoveValue(store
, key
);
296 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
297 key
= create_linkquality_key(if_name
);
298 cache_SCDynamicStoreRemoveValue(store
, key
);
300 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
303 key
= create_link_issues_key(if_name
);
304 cache_SCDynamicStoreRemoveValue(store
, key
);
306 #endif /* KEV_DL_ISSUES */
314 link_update_status(const char *if_name
, boolean_t attach
)
316 CFBooleanRef active
= NULL
;
317 CFBooleanRef expensive
;
318 struct ifmediareq ifm
;
321 sock
= dgram_socket(AF_INET
);
327 bzero((char *)&ifm
, sizeof(ifm
));
328 (void) strncpy(ifm
.ifm_name
, if_name
, sizeof(ifm
.ifm_name
));
330 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) == -1) {
331 /* if media status not available for this interface */
335 if (ifm
.ifm_count
== 0) {
340 if (!(ifm
.ifm_status
& IFM_AVALID
)) {
341 /* if active bit not valid */
345 if (ifm
.ifm_status
& IFM_ACTIVE
) {
346 active
= kCFBooleanTrue
;
348 active
= kCFBooleanFalse
;
353 /* get "Expensive" */
354 expensive
= interface_update_expensive(if_name
);
357 interface_update_status(if_name
, active
, attach
, expensive
);
365 interfaceListCopy(void)
367 CFStringRef cacheKey
;
368 CFDictionaryRef dict
;
369 CFMutableArrayRef ret_ifList
= NULL
;
371 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
372 kSCDynamicStoreDomainState
);
373 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
376 if (isA_CFDictionary(dict
) != NULL
) {
379 ifList
= CFDictionaryGetValue(dict
, kSCPropNetInterfaces
);
380 if (isA_CFArray(ifList
) != NULL
) {
381 ret_ifList
= CFArrayCreateMutableCopy(NULL
, 0, ifList
);
386 if (ret_ifList
== NULL
) {
387 ret_ifList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
395 interfaceListUpdate(CFArrayRef ifList
)
397 CFStringRef cacheKey
;
398 CFDictionaryRef dict
;
400 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
401 kSCDynamicStoreDomainState
);
402 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
403 if (dict
!= NULL
&& isA_CFDictionary(dict
) == NULL
) {
408 dict
= CFDictionaryCreate(NULL
,
409 (const void * *)&kSCPropNetInterfaces
,
410 (const void * *)&ifList
,
412 &kCFTypeDictionaryKeyCallBacks
,
413 &kCFTypeDictionaryValueCallBacks
);
414 cache_SCDynamicStoreSetValue(store
, cacheKey
, dict
);
419 CFMutableDictionaryRef newDict
;
421 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
423 CFDictionarySetValue(newDict
, kSCPropNetInterfaces
, ifList
);
424 cache_SCDynamicStoreSetValue(store
, cacheKey
, newDict
);
434 interfaceListAddInterface(CFMutableArrayRef ifList
, const char * if_name
)
436 Boolean added
= FALSE
;
437 CFStringRef interface
;
439 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
440 if (CFArrayContainsValue(ifList
,
441 CFRangeMake(0, CFArrayGetCount(ifList
)),
442 interface
) == FALSE
) {
443 /* interface was added, prime the link-specific values */
445 CFArrayAppendValue(ifList
, interface
);
446 link_update_status(if_name
, TRUE
);
447 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
448 link_update_quality_metric(if_name
);
449 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
451 CFRelease(interface
);
457 interfaceListRemoveInterface(CFMutableArrayRef ifList
, const char * if_name
)
459 CFStringRef interface
;
462 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
463 where
= CFArrayGetFirstIndexOfValue(ifList
,
464 CFRangeMake(0, CFArrayGetCount(ifList
)),
466 CFRelease(interface
);
467 if (where
!= kCFNotFound
) {
468 CFArrayRemoveValueAtIndex(ifList
, where
);
469 interface_remove(if_name
);
471 return (where
!= kCFNotFound
);
477 link_add(const char *if_name
)
479 CFMutableArrayRef ifList
;
481 ifList
= interfaceListCopy();
482 if (interfaceListAddInterface(ifList
, if_name
)) {
483 /* interface was added, update the global list */
484 messages_add_msg_with_arg("link_add", if_name
);
485 interfaceListUpdate(ifList
);
494 link_remove(const char *if_name
)
496 CFMutableArrayRef ifList
;
498 ifList
= interfaceListCopy();
499 if (interfaceListRemoveInterface(ifList
, if_name
)) {
500 /* interface was removed, update the global list */
501 interfaceListUpdate(ifList
);
508 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
509 #define INVALID_SOCKET_REF -1
512 socket_reference_count(const char* if_name
) {
514 int ref
= INVALID_SOCKET_REF
;
517 s
= dgram_socket(AF_INET
);
522 bzero((char *)&ifr
, sizeof(ifr
));
523 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
);
525 if (ioctl(s
, SIOCGIFGETRTREFCNT
, (caddr_t
)&ifr
) != -1) {
526 ref
= ifr
.ifr_route_refcnt
;
528 ref
= INVALID_SOCKET_REF
;
537 interface_update_idle_state(const char *if_name
)
539 CFStringRef if_name_cf
;
543 /* We will only update the SCDynamicStore if the idle ref count
545 ref
= socket_reference_count(if_name
);
550 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
,
551 kCFStringEncodingASCII
);
553 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
554 kSCDynamicStoreDomainState
,
558 SC_log(LOG_DEBUG
, "Post interface idle: %s", if_name
);
559 cache_SCDynamicStoreNotifyValue(store
, key
);
561 CFRelease(if_name_cf
);
564 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT