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_mutable_dictionary(CFDictionaryRef dict
)
59 CFMutableDictionaryRef newDict
;
61 if (isA_CFDictionary(dict
) != NULL
) {
62 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
65 newDict
= CFDictionaryCreateMutable(NULL
,
67 &kCFTypeDictionaryKeyCallBacks
,
68 &kCFTypeDictionaryValueCallBacks
);
73 static CFMutableDictionaryRef
74 copy_entity(CFStringRef key
)
77 CFMutableDictionaryRef newDict
= NULL
;
79 dict
= cache_SCDynamicStoreCopyValue(store
, key
);
80 newDict
= copy_mutable_dictionary(dict
);
89 interface_update_status(const char *if_name
,
90 CFBooleanRef active
, boolean_t attach
,
91 CFBooleanRef expensive
, boolean_t only_if_different
)
93 CFStringRef key
= NULL
;
94 CFMutableDictionaryRef newDict
;
95 CFDictionaryRef oldDict
;
97 key
= create_interface_key(if_name
);
98 oldDict
= cache_SCDynamicStoreCopyValue(store
, key
);
99 if (oldDict
!= NULL
&& isA_CFDictionary(oldDict
) == NULL
) {
103 newDict
= copy_mutable_dictionary(oldDict
);
105 /* if new status available, update cache */
106 if (active
!= NULL
) {
107 CFDictionarySetValue(newDict
, kSCPropNetLinkActive
, active
);
109 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkActive
);
112 if (attach
== TRUE
) {
113 /* the interface was attached, remove stale state */
114 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkDetaching
);
117 if ((expensive
!= NULL
) && CFBooleanGetValue(expensive
)) {
118 CFDictionarySetValue(newDict
, kSCPropNetLinkExpensive
, expensive
);
120 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkExpensive
);
123 /* update the SCDynamicStore */
124 if (CFDictionaryGetCount(newDict
) > 0) {
126 if (!only_if_different
128 || !CFEqual(oldDict
, newDict
)) {
129 SC_log(LOG_DEBUG
, "Update interface link status: %s: %@", if_name
, newDict
);
130 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
133 /* remove the value */
134 SC_log(LOG_DEBUG
, "Update interface link status: %s: <removed>", if_name
);
135 cache_SCDynamicStoreRemoveValue(store
, key
);
140 if (oldDict
!= NULL
) {
147 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
149 create_linkquality_key(const char * if_name
)
151 CFStringRef interface
;
154 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
155 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
156 kSCDynamicStoreDomainState
,
158 kSCEntNetLinkQuality
);
159 CFRelease(interface
);
166 interface_update_quality_metric(const char *if_name
,
169 CFStringRef key
= NULL
;
170 CFMutableDictionaryRef newDict
= NULL
;
171 CFNumberRef linkquality
= NULL
;
173 key
= create_linkquality_key(if_name
);
174 newDict
= copy_entity(key
);
176 if (quality
!= IFNET_LQM_THRESH_UNKNOWN
) {
177 linkquality
= CFNumberCreate(NULL
, kCFNumberIntType
, &quality
);
178 CFDictionarySetValue(newDict
, kSCPropNetLinkQuality
, linkquality
);
179 CFRelease(linkquality
);
181 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkQuality
);
185 if (CFDictionaryGetCount(newDict
) > 0) {
186 SC_log(LOG_DEBUG
, "Update interface link quality: %s: %@", if_name
, newDict
);
187 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
189 SC_log(LOG_DEBUG
, "Update interface link quality: %s: <removed>", if_name
);
190 cache_SCDynamicStoreRemoveValue(store
, key
);
201 link_update_quality_metric(const char *if_name
)
204 int quality
= IFNET_LQM_THRESH_UNKNOWN
;
207 sock
= dgram_socket(AF_INET
);
212 bzero((char *)&ifr
, sizeof(ifr
));
213 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
);
215 if (ioctl(sock
, SIOCGIFLINKQUALITYMETRIC
, (caddr_t
)&ifr
) != -1) {
216 quality
= ifr
.ifr_link_quality_metric
;
220 interface_update_quality_metric(if_name
, quality
);
226 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
231 create_link_issues_key(const char * if_name
)
233 CFStringRef interface
;
236 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
237 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
238 kSCDynamicStoreDomainState
,
240 kSCEntNetLinkIssues
);
241 CFRelease(interface
);
248 interface_update_link_issues(const char *if_name
,
258 CFMutableDictionaryRef newDict
;
261 key
= create_link_issues_key(if_name
);
263 newDict
= copy_entity(key
);
265 modidData
= CFDataCreate(NULL
, modid
, modid_size
);
266 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesModuleID
, modidData
);
267 CFRelease(modidData
);
269 if (info_size
!= 0) {
270 infoData
= CFDataCreate(NULL
, info
, info_size
);
271 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesInfo
, infoData
);
274 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkIssuesInfo
);
277 timeStamp
= CFDateCreate(NULL
, timestamp
);
278 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesTimeStamp
, timeStamp
);
279 CFRelease(timeStamp
);
281 SC_log(LOG_DEBUG
, "Update interface link issues: %s: %@", if_name
, newDict
);
282 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
287 #endif /* KEV_DL_ISSUES */
292 interface_detaching(const char *if_name
)
295 CFMutableDictionaryRef newDict
;
297 SC_log(LOG_DEBUG
, "Detach interface: %s", if_name
);
299 key
= create_interface_key(if_name
);
300 newDict
= copy_entity(key
);
301 CFDictionarySetValue(newDict
, kSCPropNetLinkDetaching
,
303 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
311 interface_remove(const char *if_name
)
315 SC_log(LOG_DEBUG
, "Remove interface: %s", if_name
);
317 key
= create_interface_key(if_name
);
318 cache_SCDynamicStoreRemoveValue(store
, key
);
321 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
322 key
= create_linkquality_key(if_name
);
323 cache_SCDynamicStoreRemoveValue(store
, key
);
325 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
328 key
= create_link_issues_key(if_name
);
329 cache_SCDynamicStoreRemoveValue(store
, key
);
331 #endif /* KEV_DL_ISSUES */
339 link_update_status(const char *if_name
, boolean_t attach
, boolean_t only_if_different
)
341 CFBooleanRef active
= NULL
;
342 CFBooleanRef expensive
;
343 struct ifmediareq ifm
;
346 sock
= dgram_socket(AF_INET
);
352 bzero((char *)&ifm
, sizeof(ifm
));
353 (void) strncpy(ifm
.ifm_name
, if_name
, sizeof(ifm
.ifm_name
));
355 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) == -1) {
356 /* if media status not available for this interface */
360 if (ifm
.ifm_count
== 0) {
365 if (!(ifm
.ifm_status
& IFM_AVALID
)) {
366 /* if active bit not valid */
370 if (ifm
.ifm_status
& IFM_ACTIVE
) {
371 active
= kCFBooleanTrue
;
373 active
= kCFBooleanFalse
;
378 /* get "Expensive" */
379 expensive
= interface_update_expensive(if_name
);
382 interface_update_status(if_name
, active
, attach
, expensive
, only_if_different
);
390 link_update_status_if_missing(const char * if_name
)
393 CFDictionaryRef dict
;
395 key
= create_interface_key(if_name
);
396 dict
= cache_SCDynamicStoreCopyValue(store
, key
);
398 /* it's already present, don't update */
402 link_update_status(if_name
, FALSE
, FALSE
);
403 dict
= cache_SCDynamicStoreCopyValue(store
, key
);
405 /* our action made it appear */
406 messages_add_msg_with_arg("added missing link status", if_name
);
416 interfaceListCopy(void)
418 CFStringRef cacheKey
;
419 CFDictionaryRef dict
;
420 CFMutableArrayRef ret_ifList
= NULL
;
422 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
423 kSCDynamicStoreDomainState
);
424 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
427 if (isA_CFDictionary(dict
) != NULL
) {
430 ifList
= CFDictionaryGetValue(dict
, kSCPropNetInterfaces
);
431 if (isA_CFArray(ifList
) != NULL
) {
432 ret_ifList
= CFArrayCreateMutableCopy(NULL
, 0, ifList
);
437 if (ret_ifList
== NULL
) {
438 ret_ifList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
446 interfaceListUpdate(CFArrayRef ifList
)
448 CFStringRef cacheKey
;
449 CFDictionaryRef dict
;
451 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
452 kSCDynamicStoreDomainState
);
453 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
454 if (dict
!= NULL
&& isA_CFDictionary(dict
) == NULL
) {
459 dict
= CFDictionaryCreate(NULL
,
460 (const void * *)&kSCPropNetInterfaces
,
461 (const void * *)&ifList
,
463 &kCFTypeDictionaryKeyCallBacks
,
464 &kCFTypeDictionaryValueCallBacks
);
465 cache_SCDynamicStoreSetValue(store
, cacheKey
, dict
);
470 CFMutableDictionaryRef newDict
;
472 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
474 CFDictionarySetValue(newDict
, kSCPropNetInterfaces
, ifList
);
475 cache_SCDynamicStoreSetValue(store
, cacheKey
, newDict
);
485 interfaceListAddInterface(CFMutableArrayRef ifList
, const char * if_name
)
487 Boolean added
= FALSE
;
488 CFStringRef interface
;
490 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
491 if (CFArrayContainsValue(ifList
,
492 CFRangeMake(0, CFArrayGetCount(ifList
)),
493 interface
) == FALSE
) {
494 /* interface was added, prime the link-specific values */
496 CFArrayAppendValue(ifList
, interface
);
497 link_update_status(if_name
, TRUE
, FALSE
);
498 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
499 link_update_quality_metric(if_name
);
500 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
503 /* only update the link status if it is different */
504 link_update_status(if_name
, FALSE
, TRUE
);
506 CFRelease(interface
);
512 interfaceListRemoveInterface(CFMutableArrayRef ifList
, const char * if_name
)
514 CFStringRef interface
;
517 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
518 where
= CFArrayGetFirstIndexOfValue(ifList
,
519 CFRangeMake(0, CFArrayGetCount(ifList
)),
521 CFRelease(interface
);
522 if (where
!= kCFNotFound
) {
523 CFArrayRemoveValueAtIndex(ifList
, where
);
524 interface_remove(if_name
);
526 return (where
!= kCFNotFound
);
532 link_add(const char *if_name
)
534 CFMutableArrayRef ifList
;
536 ifList
= interfaceListCopy();
537 if (interfaceListAddInterface(ifList
, if_name
)) {
538 /* interface was added, update the global list */
539 messages_add_msg_with_arg("link_add", if_name
);
540 interfaceListUpdate(ifList
);
549 link_remove(const char *if_name
)
551 CFMutableArrayRef ifList
;
553 ifList
= interfaceListCopy();
554 if (interfaceListRemoveInterface(ifList
, if_name
)) {
555 /* interface was removed, update the global list */
556 interfaceListUpdate(ifList
);
563 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
564 #define INVALID_SOCKET_REF -1
567 socket_reference_count(const char* if_name
) {
569 int ref
= INVALID_SOCKET_REF
;
572 s
= dgram_socket(AF_INET
);
577 bzero((char *)&ifr
, sizeof(ifr
));
578 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
);
580 if (ioctl(s
, SIOCGIFGETRTREFCNT
, (caddr_t
)&ifr
) != -1) {
581 ref
= ifr
.ifr_route_refcnt
;
583 ref
= INVALID_SOCKET_REF
;
592 interface_update_idle_state(const char *if_name
)
594 CFStringRef if_name_cf
;
598 /* We will only update the SCDynamicStore if the idle ref count
600 ref
= socket_reference_count(if_name
);
605 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
,
606 kCFStringEncodingASCII
);
608 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
609 kSCDynamicStoreDomainState
,
613 SC_log(LOG_DEBUG
, "Post interface idle: %s", if_name
);
614 cache_SCDynamicStoreNotifyValue(store
, key
);
616 CFRelease(if_name_cf
);
619 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT