2 * Copyright (c) 2002-2016 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
);
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 if (oldDict
!= NULL
) {
135 SC_log(LOG_DEBUG
, "Update interface link status: %s: <removed>", if_name
);
137 cache_SCDynamicStoreRemoveValue(store
, key
);
142 if (oldDict
!= NULL
) {
149 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
151 create_linkquality_key(const char * if_name
)
153 CFStringRef interface
;
156 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
157 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
158 kSCDynamicStoreDomainState
,
160 kSCEntNetLinkQuality
);
161 CFRelease(interface
);
168 interface_update_quality_metric(const char *if_name
,
171 CFStringRef key
= NULL
;
172 CFMutableDictionaryRef newDict
= NULL
;
173 CFNumberRef linkquality
= NULL
;
175 key
= create_linkquality_key(if_name
);
176 newDict
= copy_entity(key
);
178 if (quality
!= IFNET_LQM_THRESH_UNKNOWN
) {
179 linkquality
= CFNumberCreate(NULL
, kCFNumberIntType
, &quality
);
180 CFDictionarySetValue(newDict
, kSCPropNetLinkQuality
, linkquality
);
181 CFRelease(linkquality
);
183 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkQuality
);
187 if (CFDictionaryGetCount(newDict
) > 0) {
188 SC_log(LOG_DEBUG
, "Update interface link quality: %s: %@", if_name
, newDict
);
189 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
191 SC_log(LOG_DEBUG
, "Update interface link quality: %s: <unknown>", if_name
);
192 cache_SCDynamicStoreRemoveValue(store
, key
);
203 link_update_quality_metric(const char *if_name
)
206 int quality
= IFNET_LQM_THRESH_UNKNOWN
;
209 sock
= dgram_socket(AF_INET
);
214 bzero((char *)&ifr
, sizeof(ifr
));
215 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
);
217 if (ioctl(sock
, SIOCGIFLINKQUALITYMETRIC
, (caddr_t
)&ifr
) != -1) {
218 quality
= ifr
.ifr_link_quality_metric
;
222 interface_update_quality_metric(if_name
, quality
);
228 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
233 create_link_issues_key(const char * if_name
)
235 CFStringRef interface
;
238 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
239 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
240 kSCDynamicStoreDomainState
,
242 kSCEntNetLinkIssues
);
243 CFRelease(interface
);
250 interface_update_link_issues(const char *if_name
,
260 CFMutableDictionaryRef newDict
;
263 key
= create_link_issues_key(if_name
);
265 newDict
= copy_entity(key
);
267 modidData
= CFDataCreate(NULL
, modid
, modid_size
);
268 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesModuleID
, modidData
);
269 CFRelease(modidData
);
271 if (info_size
!= 0) {
272 infoData
= CFDataCreate(NULL
, info
, info_size
);
273 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesInfo
, infoData
);
276 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkIssuesInfo
);
279 timeStamp
= CFDateCreate(NULL
, timestamp
);
280 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesTimeStamp
, timeStamp
);
281 CFRelease(timeStamp
);
283 SC_log(LOG_DEBUG
, "Update interface link issues: %s: %@", if_name
, newDict
);
284 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
289 #endif /* KEV_DL_ISSUES */
294 interface_detaching(const char *if_name
)
297 CFMutableDictionaryRef newDict
;
299 SC_log(LOG_DEBUG
, "Detach interface: %s", if_name
);
301 key
= create_interface_key(if_name
);
302 newDict
= copy_entity(key
);
303 CFDictionarySetValue(newDict
, kSCPropNetLinkDetaching
,
305 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
313 interface_remove(const char *if_name
)
317 SC_log(LOG_DEBUG
, "Remove interface: %s", if_name
);
319 key
= create_interface_key(if_name
);
320 cache_SCDynamicStoreRemoveValue(store
, key
);
323 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
324 key
= create_linkquality_key(if_name
);
325 cache_SCDynamicStoreRemoveValue(store
, key
);
327 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
330 key
= create_link_issues_key(if_name
);
331 cache_SCDynamicStoreRemoveValue(store
, key
);
333 #endif /* KEV_DL_ISSUES */
341 link_update_status(const char *if_name
, boolean_t attach
, boolean_t only_if_different
)
343 CFBooleanRef active
= NULL
;
344 CFBooleanRef expensive
;
345 struct ifmediareq ifm
;
348 sock
= dgram_socket(AF_INET
);
354 bzero((char *)&ifm
, sizeof(ifm
));
355 (void) strlcpy(ifm
.ifm_name
, if_name
, sizeof(ifm
.ifm_name
));
357 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) == -1) {
358 /* if media status not available for this interface */
362 if (ifm
.ifm_count
== 0) {
367 if (!(ifm
.ifm_status
& IFM_AVALID
)) {
368 /* if active bit not valid */
372 if (ifm
.ifm_status
& IFM_ACTIVE
) {
373 active
= kCFBooleanTrue
;
375 active
= kCFBooleanFalse
;
380 /* get "Expensive" */
381 expensive
= interface_update_expensive(if_name
);
384 interface_update_status(if_name
, active
, attach
, expensive
, only_if_different
);
392 link_update_status_if_missing(const char * if_name
)
395 CFDictionaryRef dict
;
397 key
= create_interface_key(if_name
);
398 dict
= cache_SCDynamicStoreCopyValue(store
, key
);
400 /* it's already present, don't update */
404 link_update_status(if_name
, FALSE
, FALSE
);
405 dict
= cache_SCDynamicStoreCopyValue(store
, key
);
407 /* our action made it appear */
408 messages_add_msg_with_arg("added missing link status", if_name
);
418 interfaceListCopy(void)
420 CFStringRef cacheKey
;
421 CFDictionaryRef dict
;
422 CFMutableArrayRef ret_ifList
= NULL
;
424 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
425 kSCDynamicStoreDomainState
);
426 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
429 if (isA_CFDictionary(dict
) != NULL
) {
432 ifList
= CFDictionaryGetValue(dict
, kSCPropNetInterfaces
);
433 if (isA_CFArray(ifList
) != NULL
) {
434 ret_ifList
= CFArrayCreateMutableCopy(NULL
, 0, ifList
);
439 if (ret_ifList
== NULL
) {
440 ret_ifList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
448 interfaceListUpdate(CFArrayRef ifList
)
450 CFStringRef cacheKey
;
451 CFDictionaryRef dict
;
453 cacheKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
454 kSCDynamicStoreDomainState
);
455 dict
= cache_SCDynamicStoreCopyValue(store
, cacheKey
);
456 if (dict
!= NULL
&& isA_CFDictionary(dict
) == NULL
) {
461 dict
= CFDictionaryCreate(NULL
,
462 (const void * *)&kSCPropNetInterfaces
,
463 (const void * *)&ifList
,
465 &kCFTypeDictionaryKeyCallBacks
,
466 &kCFTypeDictionaryValueCallBacks
);
467 cache_SCDynamicStoreSetValue(store
, cacheKey
, dict
);
472 CFMutableDictionaryRef newDict
;
474 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
476 CFDictionarySetValue(newDict
, kSCPropNetInterfaces
, ifList
);
477 cache_SCDynamicStoreSetValue(store
, cacheKey
, newDict
);
487 interfaceListAddInterface(CFMutableArrayRef ifList
, const char * if_name
)
489 Boolean added
= FALSE
;
490 CFStringRef interface
;
492 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
493 if (!CFArrayContainsValue(ifList
,
494 CFRangeMake(0, CFArrayGetCount(ifList
)),
496 /* interface was added, prime the link-specific values */
498 CFArrayAppendValue(ifList
, interface
);
499 link_update_status(if_name
, TRUE
, FALSE
);
500 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
501 link_update_quality_metric(if_name
);
502 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
505 /* only update the link status if it is different */
506 link_update_status(if_name
, FALSE
, TRUE
);
508 CFRelease(interface
);
514 interfaceListRemoveInterface(CFMutableArrayRef ifList
, const char * if_name
)
516 CFStringRef interface
;
519 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
520 where
= CFArrayGetFirstIndexOfValue(ifList
,
521 CFRangeMake(0, CFArrayGetCount(ifList
)),
523 CFRelease(interface
);
524 if (where
!= kCFNotFound
) {
525 CFArrayRemoveValueAtIndex(ifList
, where
);
526 interface_remove(if_name
);
528 return (where
!= kCFNotFound
);
534 link_add(const char *if_name
)
536 CFMutableArrayRef ifList
;
538 ifList
= interfaceListCopy();
539 if (interfaceListAddInterface(ifList
, if_name
)) {
540 /* interface was added, update the global list */
541 messages_add_msg_with_arg("link_add", if_name
);
542 interfaceListUpdate(ifList
);
543 config_new_interface(if_name
);
552 link_remove(const char *if_name
)
554 CFMutableArrayRef ifList
;
556 ifList
= interfaceListCopy();
557 if (interfaceListRemoveInterface(ifList
, if_name
)) {
558 /* interface was removed, update the global list */
559 interfaceListUpdate(ifList
);
566 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
567 #define INVALID_SOCKET_REF -1
570 socket_reference_count(const char* if_name
) {
572 int ref
= INVALID_SOCKET_REF
;
575 s
= dgram_socket(AF_INET
);
580 bzero((char *)&ifr
, sizeof(ifr
));
581 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
);
583 if (ioctl(s
, SIOCGIFGETRTREFCNT
, (caddr_t
)&ifr
) != -1) {
584 ref
= ifr
.ifr_route_refcnt
;
586 ref
= INVALID_SOCKET_REF
;
595 interface_update_idle_state(const char *if_name
)
597 CFStringRef if_name_cf
;
601 /* We will only update the SCDynamicStore if the idle ref count
603 ref
= socket_reference_count(if_name
);
608 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
,
609 kCFStringEncodingASCII
);
611 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
612 kSCDynamicStoreDomainState
,
616 SC_log(LOG_DEBUG
, "Post interface idle: %s", if_name
);
617 cache_SCDynamicStoreNotifyValue(store
, key
);
619 CFRelease(if_name_cf
);
622 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT