2  * Copyright (c) 2002-2020 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 create_interface_cfstring(const char * if_name
) 
  38         CFStringRef     interface
; 
  40         interface 
= CFStringCreateWithCString(NULL
, if_name
, 
  41                                               kCFStringEncodingUTF8
); 
  46 create_interface_key(CFStringRef interface
) 
  50         key       
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, 
  51                                                                   kSCDynamicStoreDomainState
, 
  58 static CFMutableDictionaryRef
 
  59 copy_mutable_dictionary(CFDictionaryRef dict
) 
  61         CFMutableDictionaryRef  newDict
; 
  63         if (isA_CFDictionary(dict
) != NULL
) { 
  64                 newDict 
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
); 
  67                 newDict 
= CFDictionaryCreateMutable(NULL
, 
  69                                                     &kCFTypeDictionaryKeyCallBacks
, 
  70                                                     &kCFTypeDictionaryValueCallBacks
); 
  75 static CFMutableDictionaryRef
 
  76 copy_entity(CFStringRef key
) 
  79         CFMutableDictionaryRef  newDict         
= NULL
; 
  81         dict 
= SCDynamicStoreCopyValue(store
, key
); 
  82         newDict 
= copy_mutable_dictionary(dict
); 
  91 interface_update_status(const char *if_name
, 
  92                         CFStringRef interface
, 
  93                         CFBooleanRef active
, boolean_t attach
, 
  94                         CFBooleanRef expensive
, boolean_t only_if_different
) 
  96         CFStringRef             key             
= NULL
; 
  97         CFMutableDictionaryRef  newDict
; 
  98         CFDictionaryRef         oldDict
; 
 100         key 
= create_interface_key(interface
); 
 101         oldDict 
= SCDynamicStoreCopyValue(store
, key
); 
 102         if (oldDict 
!= NULL 
&& isA_CFDictionary(oldDict
) == NULL
) { 
 106         newDict 
= copy_mutable_dictionary(oldDict
); 
 108         /* if new status available, update cache */ 
 109         if (active 
!= NULL
) { 
 110                 CFDictionarySetValue(newDict
, kSCPropNetLinkActive
, active
); 
 112                 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkActive
); 
 116                 /* the interface was attached, remove stale state */ 
 117                 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkDetaching
); 
 120         if ((expensive 
!= NULL
) && CFBooleanGetValue(expensive
)) { 
 121                 CFDictionarySetValue(newDict
, kSCPropNetLinkExpensive
, expensive
); 
 123                 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkExpensive
); 
 126         /* update the SCDynamicStore */ 
 127         if (CFDictionaryGetCount(newDict
) > 0) { 
 129                 if (!only_if_different
 
 131                     || !CFEqual(oldDict
, newDict
)) { 
 132                         SC_log(LOG_DEBUG
, "Update interface link status: %s: %@", if_name
, newDict
); 
 133                         SCDynamicStoreSetValue(store
, key
, newDict
); 
 136                 /* remove the value */ 
 137                 if (!only_if_different
 
 138                     || oldDict 
!= NULL
) { 
 139                         SC_log(LOG_DEBUG
, "Update interface link status: %s: <removed>", if_name
); 
 140                         SCDynamicStoreRemoveValue(store
, key
); 
 146         if (oldDict 
!= NULL
) { 
 153 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED 
 155 create_linkquality_key(CFStringRef interface
) 
 159         key 
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, 
 160                                                             kSCDynamicStoreDomainState
, 
 162                                                             kSCEntNetLinkQuality
); 
 169 interface_update_quality_metric(const char *if_name
, 
 173         CFStringRef             interface
; 
 174         CFMutableDictionaryRef  newDict
; 
 176         interface 
= create_interface_cfstring(if_name
); 
 177         key 
= create_linkquality_key(interface
); 
 178         newDict 
= copy_entity(key
); 
 180         if (quality 
!= IFNET_LQM_THRESH_UNKNOWN
) { 
 181                 CFNumberRef     linkquality
; 
 183                 linkquality 
= CFNumberCreate(NULL
, kCFNumberIntType
, &quality
); 
 184                 CFDictionarySetValue(newDict
, kSCPropNetLinkQuality
, linkquality
); 
 185                 CFRelease(linkquality
); 
 187                 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkQuality
); 
 191         if (CFDictionaryGetCount(newDict
) > 0) { 
 192                 SC_log(LOG_DEBUG
, "Update interface link quality: %s: %@", if_name
, newDict
); 
 193                 SCDynamicStoreSetValue(store
, key
, newDict
); 
 195                 SC_log(LOG_DEBUG
, "Update interface link quality: %s: <unknown>", if_name
); 
 196                 SCDynamicStoreRemoveValue(store
, key
); 
 199         CFRelease(interface
); 
 208 link_update_quality_metric(const char *if_name
) 
 211         int             quality 
= IFNET_LQM_THRESH_UNKNOWN
; 
 214         sock 
= dgram_socket(AF_INET
); 
 219         memset((char *)&ifr
, 0, sizeof(ifr
)); 
 220         snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
); 
 222         if (ioctl(sock
, SIOCGIFLINKQUALITYMETRIC
, (caddr_t
)&ifr
) != -1) { 
 223                 quality 
= ifr
.ifr_link_quality_metric
; 
 228         interface_update_quality_metric(if_name
, quality
); 
 236 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */ 
 241 create_link_issues_key(CFStringRef interface
) 
 245         key 
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, 
 246                                                             kSCDynamicStoreDomainState
, 
 248                                                             kSCEntNetLinkIssues
); 
 255 interface_update_link_issues(const char         *if_name
, 
 263         CFStringRef             interface
; 
 266         CFMutableDictionaryRef  newDict
; 
 269         interface 
= create_interface_cfstring(if_name
); 
 270         key 
= create_link_issues_key(interface
); 
 272         newDict 
= copy_entity(key
); 
 274         modidData 
= CFDataCreate(NULL
, modid
, modid_size
); 
 275         CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesModuleID
, modidData
); 
 276         CFRelease(modidData
); 
 278         if (info_size 
!= 0) { 
 279                 infoData 
= CFDataCreate(NULL
, info
, info_size
); 
 280                 CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesInfo
, infoData
); 
 283                 CFDictionaryRemoveValue(newDict
, kSCPropNetLinkIssuesInfo
); 
 286         timeStamp 
= CFDateCreate(NULL
, timestamp
); 
 287         CFDictionarySetValue(newDict
, kSCPropNetLinkIssuesTimeStamp
, timeStamp
); 
 288         CFRelease(timeStamp
); 
 290         SC_log(LOG_DEBUG
, "Update interface link issues: %s: %@", if_name
, newDict
); 
 291         SCDynamicStoreSetValue(store
, key
, newDict
); 
 292         CFRelease(interface
); 
 297 #endif  /* KEV_DL_ISSUES */ 
 302 interface_detaching(const char *if_name
) 
 304         CFStringRef             interface
; 
 306         CFMutableDictionaryRef  newDict
; 
 308         SC_log(LOG_DEBUG
, "Detach interface: %s", if_name
); 
 310         interface 
= create_interface_cfstring(if_name
); 
 311         key 
= create_interface_key(interface
); 
 312         newDict 
= copy_entity(key
); 
 313         CFDictionarySetValue(newDict
, kSCPropNetLinkDetaching
, 
 315         SCDynamicStoreSetValue(store
, key
, newDict
); 
 316         CFRelease(interface
); 
 323 create_nat64_key(CFStringRef interface
) 
 327         key 
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, 
 328                                                             kSCDynamicStoreDomainState
, 
 336 interface_remove(const char *if_name
) 
 338         CFStringRef             interface
; 
 341         SC_log(LOG_DEBUG
, "Remove interface: %s", if_name
); 
 343         interface 
= create_interface_cfstring(if_name
); 
 345         key 
= create_interface_key(interface
); 
 346         SCDynamicStoreRemoveValue(store
, key
); 
 349         key 
= create_nat64_key(interface
); 
 350         SCDynamicStoreRemoveValue(store
, key
); 
 353 #ifdef  KEV_DL_LINK_QUALITY_METRIC_CHANGED 
 354         key 
= create_linkquality_key(interface
); 
 355         SCDynamicStoreRemoveValue(store
, key
); 
 357 #endif  /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */ 
 360         key 
= create_link_issues_key(interface
); 
 361         SCDynamicStoreRemoveValue(store
, key
); 
 363 #endif  /* KEV_DL_ISSUES */ 
 365         CFRelease(interface
); 
 371 S_link_update_status(const char *if_name
, CFStringRef interface
, boolean_t attach
, boolean_t only_if_different
) 
 373         CFBooleanRef            active          
= NULL
; 
 374         CFBooleanRef            expensive       
= NULL
; 
 375         struct ifmediareq       ifm
; 
 378         sock 
= dgram_socket(AF_INET
); 
 384         memset((char *)&ifm
, 0, sizeof(ifm
)); 
 385         (void) strlcpy(ifm
.ifm_name
, if_name
, sizeof(ifm
.ifm_name
)); 
 387         if (ioctl(sock
, SIOCGIFXMEDIA
, (caddr_t
)&ifm
) == -1) { 
 388                 /* if media status not available for this interface */ 
 392         if (ifm
.ifm_count 
== 0) { 
 397         if (!(ifm
.ifm_status 
& IFM_AVALID
)) { 
 398                 /* if active bit not valid */ 
 402         if (ifm
.ifm_status 
& IFM_ACTIVE
) { 
 403                 active 
= kCFBooleanTrue
; 
 405                 active 
= kCFBooleanFalse
; 
 410         if ((active 
== NULL
) || CFBooleanGetValue(active
)) { 
 412                  * if link status not available or active (link UP), 
 415                 expensive 
= interface_update_expensive(if_name
); 
 419         interface_update_status(if_name
, interface
, active
, attach
, expensive
, only_if_different
); 
 426 link_update_status(const char *if_name
, boolean_t attach
, boolean_t only_if_different
) 
 428         CFStringRef     interface
; 
 430         interface 
= create_interface_cfstring(if_name
); 
 431         S_link_update_status(if_name
, interface
, attach
, only_if_different
); 
 432         CFRelease(interface
); 
 438 link_update_status_if_missing(const char * if_name
) 
 440         CFStringRef     interface
; 
 442         CFDictionaryRef dict
; 
 444         interface 
= create_interface_cfstring(if_name
); 
 445         key 
= create_interface_key(interface
); 
 446         dict 
= SCDynamicStoreCopyValue(store
, key
); 
 448                 /* it's already present, don't update */ 
 452         S_link_update_status(if_name
, interface
, FALSE
, FALSE
); 
 453         dict 
= SCDynamicStoreCopyValue(store
, key
); 
 455                 /* our action made it appear */ 
 456                 messages_add_msg_with_arg("added missing link status", if_name
); 
 460         CFRelease(interface
); 
 467 interfaceListCopy(void) 
 469         CFStringRef             cacheKey
; 
 470         CFDictionaryRef         dict
; 
 471         CFMutableArrayRef       ret_ifList 
= NULL
; 
 473         cacheKey 
= SCDynamicStoreKeyCreateNetworkInterface(NULL
, 
 474                                                            kSCDynamicStoreDomainState
); 
 475         dict 
= SCDynamicStoreCopyValue(store
, cacheKey
); 
 478                 if (isA_CFDictionary(dict
) != NULL
) { 
 481                         ifList 
= CFDictionaryGetValue(dict
, kSCPropNetInterfaces
); 
 482                         if (isA_CFArray(ifList
) != NULL
) { 
 483                                 ret_ifList 
= CFArrayCreateMutableCopy(NULL
, 0, ifList
); 
 488         if (ret_ifList 
== NULL
) { 
 489                 ret_ifList 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 497 interfaceListUpdate(CFArrayRef ifList
) 
 499         CFStringRef     cacheKey
; 
 500         CFDictionaryRef dict
; 
 502         cacheKey 
= SCDynamicStoreKeyCreateNetworkInterface(NULL
, 
 503                                                            kSCDynamicStoreDomainState
); 
 504         dict 
= SCDynamicStoreCopyValue(store
, cacheKey
); 
 505         if (dict 
!= NULL 
&& isA_CFDictionary(dict
) == NULL
) { 
 510                 dict 
= CFDictionaryCreate(NULL
, 
 511                                           (const void * *)&kSCPropNetInterfaces
, 
 512                                           (const void * *)&ifList
, 
 514                                           &kCFTypeDictionaryKeyCallBacks
, 
 515                                           &kCFTypeDictionaryValueCallBacks
); 
 516                 SCDynamicStoreSetValue(store
, cacheKey
, dict
); 
 521                 CFMutableDictionaryRef  newDict
; 
 523                 newDict 
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
); 
 525                 CFDictionarySetValue(newDict
, kSCPropNetInterfaces
, ifList
); 
 526                 SCDynamicStoreSetValue(store
, cacheKey
, newDict
); 
 536 interfaceListAddInterface(CFMutableArrayRef ifList
, const char * if_name
) 
 538         Boolean         added 
= FALSE
; 
 539         CFStringRef     interface
; 
 541         interface 
= create_interface_cfstring(if_name
); 
 542         if (!CFArrayContainsValue(ifList
, 
 543                                   CFRangeMake(0, CFArrayGetCount(ifList
)), 
 545                 /* interface was added, prime the link-specific values */ 
 547                 CFArrayAppendValue(ifList
, interface
); 
 548                 link_update_status(if_name
, TRUE
, FALSE
); 
 549 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED 
 550                 link_update_quality_metric(if_name
); 
 551 #endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */ 
 554                 /* only update the link status if it is different */ 
 555                 link_update_status(if_name
, FALSE
, TRUE
); 
 557         CFRelease(interface
); 
 563 interfaceListRemoveInterface(CFMutableArrayRef ifList
, const char * if_name
) 
 565         CFStringRef     interface
; 
 568         interface 
= create_interface_cfstring(if_name
); 
 569         where 
= CFArrayGetFirstIndexOfValue(ifList
, 
 570                                             CFRangeMake(0, CFArrayGetCount(ifList
)), 
 572         CFRelease(interface
); 
 573         if (where 
!= kCFNotFound
) { 
 574                 CFArrayRemoveValueAtIndex(ifList
, where
); 
 575                 interface_remove(if_name
); 
 577         return (where 
!= kCFNotFound
); 
 583 link_add(const char *if_name
) 
 585         CFMutableArrayRef       ifList
; 
 587         ifList 
= interfaceListCopy(); 
 588         if (interfaceListAddInterface(ifList
, if_name
)) { 
 589                 /* interface was added, update the global list */ 
 590                 messages_add_msg_with_arg("link_add", if_name
); 
 591                 interfaceListUpdate(ifList
); 
 592                 config_new_interface(if_name
); 
 601 link_remove(const char *if_name
) 
 603         CFMutableArrayRef       ifList
; 
 605         ifList 
= interfaceListCopy(); 
 606         if (interfaceListRemoveInterface(ifList
, if_name
)) { 
 607                 /* interface was removed, update the global list */ 
 608                 interfaceListUpdate(ifList
); 
 617 interface_update_delegation(const char *if_name
) 
 619         CFStringRef             interface
; 
 622         interface 
= create_interface_cfstring(if_name
); 
 623         key 
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, 
 624                                                             kSCDynamicStoreDomainState
, 
 626                                                             kSCEntNetInterfaceDelegation
); 
 627         SC_log(LOG_DEBUG
, "Post interface delegation change: %s", if_name
); 
 628         SCDynamicStoreNotifyValue(store
, key
); 
 630         CFRelease(interface
); 
 635 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT 
 636 #define INVALID_SOCKET_REF      -1 
 639 socket_reference_count(const char* if_name
) { 
 641         int             ref 
= INVALID_SOCKET_REF
; 
 644         s 
= dgram_socket(AF_INET
); 
 649         memset((char *)&ifr
, 0, sizeof(ifr
)); 
 650         snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", if_name
); 
 652         if (ioctl(s
, SIOCGIFGETRTREFCNT
, (caddr_t
)&ifr
) != -1) { 
 653                 ref 
= ifr
.ifr_route_refcnt
; 
 655                 ref 
= INVALID_SOCKET_REF
; 
 664 interface_update_idle_state(const char *if_name
) 
 666         CFStringRef             interface
; 
 670         /* only update the SCDynamicStore if the idle ref count is still 0 */ 
 671         ref 
= socket_reference_count(if_name
); 
 676         interface 
= create_interface_cfstring(if_name
); 
 677         key 
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, 
 678                                                             kSCDynamicStoreDomainState
, 
 682         SC_log(LOG_DEBUG
, "Post interface idle: %s", if_name
); 
 683         SCDynamicStoreNotifyValue(store
, key
); 
 685         CFRelease(interface
); 
 688 #endif  // KEV_DL_IF_IDLE_ROUTE_REFCNT