2  * Copyright (c) 2002-2003 Apple Computer, 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  * October 21, 2000             Allan Nathanson <ajn@apple.com> 
  33 #define KERNEL_PRIVATE 
  34 #include <sys/ioctl.h> 
  36 #include <sys/socket.h> 
  37 #include <net/ethernet.h> 
  39 #include <net/if_vlan_var.h> 
  40 #include <net/if_media.h> 
  41 #include <net/if_types.h> 
  43 #include <SystemConfiguration/SystemConfiguration.h> 
  44 #include <SystemConfiguration/SCPrivate.h>              // for SCLog() 
  45 #include <SystemConfiguration/SCValidation.h> 
  47 #include <IOKit/IOKitLib.h> 
  48 #include <IOKit/network/IONetworkInterface.h> 
  49 #include <IOKit/network/IONetworkController.h> 
  50 #include "dy_framework.h" 
  53 static const struct ifmedia_description ifm_subtype_shared_descriptions
[] = 
  54     IFM_SUBTYPE_SHARED_DESCRIPTIONS
; 
  56 static const struct ifmedia_description ifm_subtype_ethernet_descriptions
[] = 
  57     IFM_SUBTYPE_ETHERNET_DESCRIPTIONS
; 
  59 static const struct ifmedia_description ifm_shared_option_descriptions
[] = 
  60     IFM_SHARED_OPTION_DESCRIPTIONS
; 
  62 static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions
[] = 
  63     IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS
; 
  66 static CFDictionaryRef
 
  67 __createMediaDictionary(int media_options
, Boolean filter
) 
  69         CFMutableDictionaryRef  dict    
= NULL
; 
  71         CFMutableArrayRef       options 
= NULL
; 
  74         if (IFM_TYPE(media_options
) != IFM_ETHER
) { 
  78         if (filter 
&& (IFM_SUBTYPE(media_options
) == IFM_NONE
)) { 
  79                 return NULL
;    /* filter */ 
  82         dict 
= CFDictionaryCreateMutable(NULL
, 
  84                                          &kCFTypeDictionaryKeyCallBacks
, 
  85                                          &kCFTypeDictionaryValueCallBacks
); 
  90         for (i 
= 0; !val 
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) { 
  91                 if (IFM_SUBTYPE(media_options
) == ifm_subtype_shared_descriptions
[i
].ifmt_word
) { 
  92                         val 
= CFStringCreateWithCString(NULL
, 
  93                                                         ifm_subtype_shared_descriptions
[i
].ifmt_string
, 
  94                                                         kCFStringEncodingASCII
); 
  99         for (i 
= 0; !val 
&& ifm_subtype_ethernet_descriptions
[i
].ifmt_string
; i
++) { 
 100                 if (IFM_SUBTYPE(media_options
) == ifm_subtype_ethernet_descriptions
[i
].ifmt_word
) { 
 101                         val 
= CFStringCreateWithCString(NULL
, 
 102                                                         ifm_subtype_ethernet_descriptions
[i
].ifmt_string
, 
 103                                                         kCFStringEncodingASCII
); 
 109                 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaSubType
, val
); 
 115         options 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 117         while (IFM_OPTIONS(media_options
) != 0) { 
 118                 if (filter 
&& (IFM_OPTIONS(media_options
) & IFM_LOOP
)) { 
 119                         media_options 
&= ~IFM_LOOP
;     /* filter */ 
 124                 for (i 
= 0; !val 
&& ifm_shared_option_descriptions
[i
].ifmt_string
; i
++) { 
 125                         if (IFM_OPTIONS(media_options
) & ifm_shared_option_descriptions
[i
].ifmt_word
) { 
 126                                 val 
= CFStringCreateWithCString(NULL
, 
 127                                                                 ifm_shared_option_descriptions
[i
].ifmt_string
, 
 128                                                                 kCFStringEncodingASCII
); 
 129                                 media_options 
&= ~ifm_shared_option_descriptions
[i
].ifmt_word
; 
 134                 for (i 
= 0; !val 
&& ifm_subtype_ethernet_option_descriptions
[i
].ifmt_string
; i
++) { 
 135                         if (IFM_OPTIONS(media_options
) & ifm_subtype_ethernet_option_descriptions
[i
].ifmt_word
) { 
 136                                 val 
= CFStringCreateWithCString(NULL
, 
 137                                                                 ifm_subtype_ethernet_option_descriptions
[i
].ifmt_string
, 
 138                                                                 kCFStringEncodingASCII
); 
 139                                 media_options 
&= ~ifm_shared_option_descriptions
[i
].ifmt_word
; 
 145                         CFArrayAppendValue(options
, val
); 
 150         CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaOptions
, options
); 
 158 __createMediaOptions(CFDictionaryRef media_options
) 
 162         int             ifm_new 
= IFM_ETHER
; 
 170         val 
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaSubType
); 
 171         if (!isA_CFString(val
)) { 
 175         str 
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
); 
 181         for (i 
= 0; !match 
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) { 
 182                 if (strcasecmp(str
, ifm_subtype_shared_descriptions
[i
].ifmt_string
) == 0) { 
 183                         ifm_new 
|= ifm_subtype_shared_descriptions
[i
].ifmt_word
; 
 189         for (i 
= 0; !match 
&& ifm_subtype_ethernet_descriptions
[i
].ifmt_string
; i
++) { 
 190                 if (strcasecmp(str
, ifm_subtype_ethernet_descriptions
[i
].ifmt_string
) == 0) { 
 191                         ifm_new 
|= ifm_subtype_ethernet_descriptions
[i
].ifmt_word
; 
 197         CFAllocatorDeallocate(NULL
, str
); 
 200                 return -1;      /* if no subtype */ 
 205         options 
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaOptions
); 
 206         if (!isA_CFArray(options
)) { 
 210         n 
= CFArrayGetCount(options
); 
 211         for (i 
= 0; i 
< n
; i
++) { 
 214                 val 
= CFArrayGetValueAtIndex(options
, i
); 
 215                 if (!isA_CFString(val
)) { 
 219                 str 
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
); 
 226                 for (j 
= 0; !match 
&& ifm_shared_option_descriptions
[j
].ifmt_string
; j
++) { 
 227                         if (strcasecmp(str
, ifm_shared_option_descriptions
[j
].ifmt_string
) == 0) { 
 228                                 ifm_new 
|= ifm_shared_option_descriptions
[j
].ifmt_word
; 
 234                 for (j 
= 0; !match 
&& ifm_subtype_ethernet_option_descriptions
[j
].ifmt_string
; j
++) { 
 235                         if (strcasecmp(str
, ifm_subtype_ethernet_option_descriptions
[j
].ifmt_string
) == 0) { 
 236                                 ifm_new 
|= ifm_subtype_ethernet_option_descriptions
[j
].ifmt_word
; 
 242                 CFAllocatorDeallocate(NULL
, str
); 
 245                         return -1;      /* if no option */ 
 254 NetworkInterfaceCopyMediaOptions(CFStringRef            interface
, 
 255                                  CFDictionaryRef        
*current
, 
 256                                  CFDictionaryRef        
*active
, 
 257                                  CFArrayRef             
*available
, 
 261         struct ifmediareq       ifm
; 
 262         int                     *media_list     
= NULL
; 
 266         bzero((void *)&ifm
, sizeof(ifm
)); 
 268         if (_SC_cfstring_to_cstring(interface
, ifm
.ifm_name
, sizeof(ifm
.ifm_name
), kCFStringEncodingASCII
) == NULL
) { 
 269                 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert inteface name")); 
 273         sock 
= socket(AF_INET
, SOCK_DGRAM
, 0); 
 275                 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
)); 
 279         if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) < 0) { 
 280 //              SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno)); 
 284         if (ifm
.ifm_count 
> 0) { 
 285                 media_list 
= (int *)CFAllocatorAllocate(NULL
, ifm
.ifm_count 
* sizeof(int), 0); 
 286                 ifm
.ifm_ulist 
= media_list
; 
 287                 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) < 0) { 
 288                         SCLog(TRUE
, LOG_DEBUG
, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno
)); 
 293         if (active
)     *active    
= NULL
; 
 294         if (current
)    *current   
= NULL
; 
 296                 CFMutableArrayRef       media_options
; 
 298                 media_options 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 299                 for (i 
= 0; i 
< ifm
.ifm_count
; i
++) { 
 300                         CFDictionaryRef options
; 
 302                         options 
= __createMediaDictionary(media_list
[i
], filter
); 
 307                         if (active  
&& (*active 
== NULL
)  && (ifm
.ifm_active 
== media_list
[i
])) { 
 308                                 *active  
= CFRetain(options
); 
 311                         if (current 
&& (*current 
== NULL
) && (ifm
.ifm_current 
== media_list
[i
])) { 
 312                                 *current 
= CFRetain(options
); 
 315                         if (!CFArrayContainsValue(media_options
, CFRangeMake(0, CFArrayGetCount(media_options
)), options
)) { 
 316                                 CFArrayAppendValue(media_options
, options
); 
 321                 *available 
= (CFArrayRef
)media_options
; 
 324         if (active  
&& (*active 
== NULL
)) { 
 325                 *active 
= __createMediaDictionary(ifm
.ifm_active
, FALSE
); 
 328         if (current 
&& (*current 
== NULL
)) { 
 329                 if (active 
&& (ifm
.ifm_active 
== ifm
.ifm_current
)) { 
 330                         if (*active
)    *current 
= CFRetain(active
); 
 332                         *current 
= __createMediaDictionary(ifm
.ifm_current
, FALSE
); 
 340         if (sock 
>= 0)  (void)close(sock
); 
 341         if (media_list
) CFAllocatorDeallocate(NULL
, media_list
); 
 348 NetworkInterfaceCopyMediaSubTypes(CFArrayRef    available
) 
 352         CFMutableArrayRef       subTypes
; 
 354         if (!isA_CFArray(available
)) { 
 358         subTypes 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 360         n 
= CFArrayGetCount(available
); 
 361         for (i 
= 0; i 
< n
; i
++) { 
 362                 CFDictionaryRef options
; 
 365                 options 
= CFArrayGetValueAtIndex(available
, i
); 
 366                 if (!isA_CFDictionary(options
)) { 
 370                 subType 
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
); 
 371                 if (!isA_CFString(subType
)) { 
 375                 if (!CFArrayContainsValue(subTypes
, CFRangeMake(0, CFArrayGetCount(subTypes
)), subType
)) { 
 376                         CFArrayAppendValue(subTypes
, subType
); 
 380         if (CFArrayGetCount(subTypes
) == 0) { 
 390 NetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef      available
, 
 395         CFMutableArrayRef       subTypeOptions
; 
 397         if (!isA_CFArray(available
)) { 
 401         subTypeOptions 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 403         n 
= CFArrayGetCount(available
); 
 404         for (i 
= 0; i 
< n
; i
++) { 
 405                 CFDictionaryRef options
; 
 406                 CFArrayRef      mediaOptions
; 
 407                 CFStringRef     mediaSubType
; 
 409                 options 
= CFArrayGetValueAtIndex(available
, i
); 
 410                 if (!isA_CFDictionary(options
)) { 
 414                 mediaSubType 
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
); 
 415                 if (!isA_CFString(mediaSubType
) || !CFEqual(subType
, mediaSubType
)) { 
 419                 mediaOptions 
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaOptions
); 
 420                 if (!isA_CFArray(mediaOptions
)) { 
 424                 if (!CFArrayContainsValue(subTypeOptions
, CFRangeMake(0, CFArrayGetCount(subTypeOptions
)), mediaOptions
)) { 
 425                         CFArrayAppendValue(subTypeOptions
, mediaOptions
); 
 429         if (CFArrayGetCount(subTypeOptions
) == 0) { 
 430                 CFRelease(subTypeOptions
); 
 431                 subTypeOptions 
= NULL
; 
 434         return subTypeOptions
; 
 439 __getMTULimits(char     ifr_name
[IFNAMSIZ
], 
 444         io_iterator_t           io_iter         
= 0; 
 445         io_registry_entry_t     io_interface    
= 0; 
 446         io_registry_entry_t     io_controller   
= 0; 
 448         static mach_port_t      masterPort      
= MACH_PORT_NULL
; 
 449         CFMutableDictionaryRef  matchingDict
; 
 451         /* look for a matching interface in the IORegistry */ 
 453         if (masterPort 
== MACH_PORT_NULL
) { 
 454                 kr 
= IOMasterPort(MACH_PORT_NULL
, &masterPort
); 
 455                 if (kr 
!= KERN_SUCCESS
) { 
 460         matchingDict 
= IOBSDNameMatching(masterPort
, 0, ifr_name
); 
 462                 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */ 
 463                 kr 
= IOServiceGetMatchingServices(masterPort
, matchingDict
, &io_iter
); 
 464                 if ((kr 
== KERN_SUCCESS
) && io_iter
) { 
 465                     /* should only have a single match */ 
 466                     io_interface 
= IOIteratorNext(io_iter
); 
 468                 if (io_iter
)    IOObjectRelease(io_iter
); 
 475                  * found an interface, get the interface type 
 477                 num 
= IORegistryEntryCreateCFProperty(io_interface
, CFSTR(kIOInterfaceType
), NULL
, kNilOptions
); 
 479                         if (isA_CFNumber(num
)) { 
 480                                 CFNumberGetValue(num
, kCFNumberIntType
, &ifType
); 
 486                  * ...and the property we are REALLY interested is in the controller, 
 487                  * which is the parent of the interface object. 
 489                 (void)IORegistryEntryGetParentEntry(io_interface
, kIOServicePlane
, &io_controller
); 
 490                 IOObjectRelease(io_interface
); 
 492                 /* if no matching interface */ 
 499                 num 
= IORegistryEntryCreateCFProperty(io_controller
, CFSTR(kIOMaxPacketSize
), NULL
, kNilOptions
); 
 501                         if (isA_CFNumber(num
)) { 
 505                                  * Get the value and subtract the FCS bytes and Ethernet header 
 506                                  * sizes from the maximum frame size reported by the controller 
 507                                  * to get the MTU size. The 14 byte media header can be found 
 508                                  * in the registry, but not the size for the trailing FCS bytes. 
 510                                 CFNumberGetValue(num
, kCFNumberIntType
, &value
); 
 512                                 if (ifType 
== IFT_ETHER
) { 
 513                                         value 
-= (ETHER_HDR_LEN 
+ ETHER_CRC_LEN
); 
 516                                 if (mtu_min
)    *mtu_min 
= IF_MINMTU
; 
 517                                 if (mtu_max
)    *mtu_max 
= value
; 
 522                 IOObjectRelease(io_controller
); 
 530 NetworkInterfaceCopyMTU(CFStringRef     interface
, 
 539         bzero((void *)&ifr
, sizeof(ifr
)); 
 540         if (_SC_cfstring_to_cstring(interface
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
) == NULL
) { 
 541                 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert interface name")); 
 545         sock 
= socket(AF_INET
, SOCK_DGRAM
, 0); 
 547                 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
)); 
 551         if (ioctl(sock
, SIOCGIFMTU
, (caddr_t
)&ifr
) < 0) { 
 552 //              SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMTU) failed: %s"), strerror(errno)); 
 556         if (mtu_cur
)    *mtu_cur 
= ifr
.ifr_mtu
; 
 557         if (mtu_min
)    *mtu_min 
= ifr
.ifr_mtu
; 
 558         if (mtu_max
)    *mtu_max 
= ifr
.ifr_mtu
; 
 560         /* get valid MTU range */ 
 562         if (mtu_min 
!= NULL 
|| mtu_max 
!= NULL
) { 
 563                 if (ioctl(sock
, SIOCGIFDEVMTU
, (caddr_t
)&ifr
) == 0) { 
 564                         struct ifdevmtu 
*       devmtu_p
; 
 566                         devmtu_p 
= &ifr
.ifr_devmtu
; 
 567                         if (mtu_min 
!= NULL
) { 
 568                                 *mtu_min 
= (devmtu_p
->ifdm_min 
> IF_MINMTU
) 
 569                                         ? devmtu_p
->ifdm_min 
: IF_MINMTU
; 
 571                         if (mtu_max 
!= NULL
) { 
 572                                 *mtu_max 
= devmtu_p
->ifdm_max
; 
 576                         (void)__getMTULimits(ifr
.ifr_name
, mtu_min
, mtu_max
); 
 584         if (sock 
>= 0)  (void)close(sock
);