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