2  * Copyright (c) 2001-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 3, 2003              Allan Nathanson <ajn@apple.com> 
  28  * - sort new interfaces by IOKit path (rather than MAC address) to 
  29  *   help facilitate a more predictable interface-->name mapping for 
  30  *   like hardware configurations. 
  32  * June 23, 2001                Allan Nathanson <ajn@apple.com> 
  33  * - update to public SystemConfiguration.framework APIs 
  35  * January 23, 2001             Dieter Siegmund <dieter@apple.com> 
  41  * - module that receives IOKit Network Interface messages 
  42  *   and names any interface that currently does not have a name 
  43  * - uses Interface Type and MACAddress as the unique identifying 
  44  *   keys; any interface that doesn't contain both of these properties 
  45  *   is ignored and not processed 
  46  * - stores the Interface Type, MACAddress, and Unit in permanent storage 
  47  *   to give persistent interface names 
  55 #include <sys/sockio.h> 
  57 #include <sys/param.h> 
  58 #include <mach/mach.h> 
  59 #include <net/if_types.h> 
  61 #include <CoreFoundation/CoreFoundation.h> 
  63 #include <SystemConfiguration/SystemConfiguration.h> 
  64 #include <SystemConfiguration/SCDPlugin.h> 
  65 #include <SystemConfiguration/SCPrivate.h>      // for SCLog(), SCPrint() 
  66 #include <SystemConfiguration/SCValidation.h> 
  68 #include <SystemConfiguration/BondConfiguration.h> 
  69 #include <SystemConfiguration/BondConfigurationPrivate.h> 
  71 #include <SystemConfiguration/VLANConfiguration.h> 
  72 #include <SystemConfiguration/VLANConfigurationPrivate.h> 
  74 #include <IOKit/IOKitLib.h> 
  75 #include <IOKit/IOBSD.h> 
  76 #include <IOKit/network/IONetworkController.h> 
  77 #include <IOKit/network/IONetworkInterface.h> 
  80 #define kIOBuiltin                      "IOBuiltin" 
  84 #define kIOLocation                     "IOLocation" 
  87 #define kIONetworkStackUserCommand      "IONetworkStackUserCommand" 
  88 #define kIORegisterOne                  1 
  90 #define MY_PLUGIN_NAME                  "InterfaceNamer" 
  92 static boolean_t                        S_debug 
= FALSE
; 
  93 static CFMutableArrayRef                S_dblist 
= NULL
; 
  94 static io_connect_t                     S_connect 
= MACH_PORT_NULL
; 
  95 static io_iterator_t                    S_iter 
= MACH_PORT_NULL
; 
  96 static IONotificationPortRef            S_notify 
= NULL
; 
  99 writeInterfaceList(CFArrayRef ilist
); 
 102 displayInterface(CFDictionaryRef if_dict
); 
 104 static CFDictionaryRef
 
 105 lookupIOKitPath(CFStringRef if_path
); 
 107 static __inline__ CFComparisonResult
 
 108 compareMacAddress(CFDataRef addr1
, CFDataRef addr2
) 
 115     len1 
= CFDataGetLength(addr1
); 
 116     len2 
= CFDataGetLength(addr2
); 
 120             return (kCFCompareEqualTo
); 
 121         return (memcmp(CFDataGetBytePtr(addr1
), 
 122                        CFDataGetBytePtr(addr2
), 
 128     res 
= memcmp(CFDataGetBytePtr(addr1
), 
 129                  CFDataGetBytePtr(addr2
), 
 132         return (len1 
- len2
); 
 137 static CFComparisonResult
 
 138 if_unit_compare(const void *val1
, const void *val2
, void *context
) 
 140     CFComparisonResult  res
; 
 146     type1 
= CFDictionaryGetValue((CFDictionaryRef
)val1
, 
 147                                  CFSTR(kIOInterfaceType
)); 
 148     type2 
= CFDictionaryGetValue((CFDictionaryRef
)val2
, 
 149                                  CFSTR(kIOInterfaceType
)); 
 150     res 
= CFNumberCompare(type1
, type2
, NULL
); 
 151     if (res 
!= kCFCompareEqualTo
) { 
 154     unit1 
= CFDictionaryGetValue((CFDictionaryRef
)val1
, 
 155                                  CFSTR(kIOInterfaceUnit
)); 
 156     unit2 
= CFDictionaryGetValue((CFDictionaryRef
)val2
, 
 157                                  CFSTR(kIOInterfaceUnit
)); 
 158     return (CFNumberCompare(unit1
, unit2
, NULL
)); 
 162 split_path(CFStringRef path
) 
 164         CFArrayRef              components
; 
 165         CFMutableStringRef      nPath
; 
 167         // turn '@'s into '/'s 
 168         nPath 
= CFStringCreateMutableCopy(NULL
, 0, path
); 
 169         (void) CFStringFindAndReplace(nPath
, 
 172                                       CFRangeMake(0, CFStringGetLength(nPath
)), 
 175         // split path into components to be compared 
 176         components 
= CFStringCreateArrayBySeparatingStrings(NULL
, nPath
, CFSTR("/")); 
 183 static CFComparisonResult
 
 184 if_path_compare(const void *val1
, const void *val2
, void *context
) 
 186     CFBooleanRef        builtin
; 
 187     Boolean             builtin_val1    
= FALSE
; 
 188     Boolean             builtin_val2    
= FALSE
; 
 189     CFArrayRef          elements1       
= NULL
; 
 190     CFArrayRef          elements2       
= NULL
; 
 196     CFComparisonResult  res
; 
 200     /* sort by interface type */ 
 202     type1 
= CFDictionaryGetValue((CFDictionaryRef
)val1
, CFSTR(kIOInterfaceType
)); 
 203     type2 
= CFDictionaryGetValue((CFDictionaryRef
)val2
, CFSTR(kIOInterfaceType
)); 
 204     res 
= CFNumberCompare(type1
, type2
, NULL
); 
 205     if (res 
!= kCFCompareEqualTo
) { 
 209     /* built-in interfaces sort first */ 
 210     builtin 
= CFDictionaryGetValue((CFDictionaryRef
)val1
, CFSTR(kIOBuiltin
)); 
 211     if (isA_CFBoolean(builtin
) != NULL
) { 
 212         builtin_val1 
= CFBooleanGetValue(builtin
); 
 214     builtin 
= CFDictionaryGetValue((CFDictionaryRef
)val2
, CFSTR(kIOBuiltin
)); 
 215     if (isA_CFBoolean(builtin
) != NULL
) { 
 216         builtin_val2 
= CFBooleanGetValue(builtin
); 
 218     if (builtin_val1 
!= builtin_val2
) { 
 220             res 
= kCFCompareLessThan
; 
 222             res 
= kCFCompareGreaterThan
; 
 227     /* ... and then sort built-in interfaces by "location" */ 
 229         CFStringRef     location1
; 
 230         CFStringRef     location2
; 
 232         location1 
= CFDictionaryGetValue((CFDictionaryRef
)val1
, CFSTR(kIOLocation
)); 
 233         location2 
= CFDictionaryGetValue((CFDictionaryRef
)val2
, CFSTR(kIOLocation
)); 
 234         if (location1 
!= location2
) { 
 235             if (isA_CFString(location1
)) { 
 236                 if (isA_CFString(location2
)) { 
 237                     res 
= CFStringCompare(location1
, location2
, 0); 
 239                     res 
= kCFCompareLessThan
; 
 242                 res 
= kCFCompareGreaterThan
; 
 245             if (res 
!= kCFCompareEqualTo
) { 
 251     /* ... and then sort by IOPathMatch */ 
 253     path 
= CFDictionaryGetValue((CFDictionaryRef
)val1
, CFSTR(kIOPathMatchKey
)); 
 254     if (isA_CFString(path
)) { 
 255         elements1 
= split_path(path
); 
 256         n1 
= CFArrayGetCount(elements1
); 
 261     path 
= CFDictionaryGetValue((CFDictionaryRef
)val2
, CFSTR(kIOPathMatchKey
)); 
 262     if (isA_CFString(path
)) { 
 263         elements2 
= split_path(path
); 
 264         n2 
= CFArrayGetCount(elements2
); 
 269     n 
= (n1 
<= n2
) ? n1 
: n2
; 
 270     for (i 
= 0; i 
< n
; i
++) { 
 279         e1 
= CFArrayGetValueAtIndex(elements1
, i
); 
 280         e2 
= CFArrayGetValueAtIndex(elements2
, i
); 
 282         str 
= _SC_cfstring_to_cstring(e1
, NULL
, 0, kCFStringEncodingASCII
); 
 284         q1 
= strtoq(str
, &end
, 16); 
 285         isNum 
= ((*str 
!= '\0') && (*end 
== '\0') && (errno 
== 0)); 
 286         CFAllocatorDeallocate(NULL
, str
); 
 289             // if e1 is a valid numeric string 
 290             str 
= _SC_cfstring_to_cstring(e2
, NULL
, 0, kCFStringEncodingASCII
); 
 292             q2 
= strtoq(str
, &end
, 16); 
 293             isNum 
= ((*str 
!= '\0') && (*end 
== '\0') && (errno 
== 0)); 
 294             CFAllocatorDeallocate(NULL
, str
); 
 297                 // if e2 is also a valid numeric string 
 300                     res 
= kCFCompareEqualTo
; 
 302                 } else if (q1 
< q2
) { 
 303                     res 
= kCFCompareLessThan
; 
 305                     res 
= kCFCompareGreaterThan
; 
 311         res 
= CFStringCompare(e1
, e2
, 0); 
 312         if (res 
!= kCFCompareEqualTo
) { 
 317     if (res 
== kCFCompareEqualTo
) { 
 319             res 
= kCFCompareLessThan
; 
 320         } else if (n1 
< n2
) { 
 321             res 
= kCFCompareGreaterThan
; 
 326     if ( elements1 
) CFRelease( elements1 
); 
 327     if ( elements2 
) CFRelease( elements2 
); 
 333 addCFStringProperty( CFMutableDictionaryRef dict
, 
 335                      const char *           string 
) 
 337     boolean_t    ret 
= false; 
 338     CFStringRef  valObj
, keyObj
; 
 340     if ( (string 
== 0) || (key 
== 0) || (dict 
== 0) ) 
 343     keyObj 
= CFStringCreateWithCString(NULL
, 
 345                                        kCFStringEncodingASCII 
); 
 347     valObj 
= CFStringCreateWithCString(NULL
, 
 349                                        kCFStringEncodingASCII 
); 
 351     if (valObj 
&& keyObj
) { 
 352         CFDictionarySetValue( dict
, keyObj
, valObj 
); 
 356     if ( keyObj 
) CFRelease( keyObj 
); 
 357     if ( valObj 
) CFRelease( valObj 
); 
 363 addCFNumberProperty( CFMutableDictionaryRef dict
, 
 365                      unsigned int           number 
) 
 367     boolean_t    ret 
= false; 
 371     if ( (key 
== 0) || (dict 
== 0) ) 
 374     numObj 
= CFNumberCreate(NULL
, 
 378     keyObj 
= CFStringCreateWithCString(NULL
, 
 380                                        kCFStringEncodingASCII 
); 
 382     if ( numObj 
&& keyObj 
) 
 384             CFDictionarySetValue( dict
, keyObj
, numObj 
); 
 388     if ( numObj 
) CFRelease( numObj 
); 
 389     if ( keyObj 
) CFRelease( keyObj 
); 
 395 read_file(char * filename
, size_t * data_length
) 
 403     if (stat(filename
, &sb
) < 0) 
 413     fd 
= open(filename
, O_RDONLY
); 
 417     if (read(fd
, data
, len
) != len
) { 
 418         SCLog(TRUE
, LOG_INFO
, 
 419               CFSTR(MY_PLUGIN_NAME 
": read %s failed, %s"), 
 420               filename
, strerror(errno
)); 
 432 static CFPropertyListRef
 
 433 readPropertyList(char * filename
) 
 437     CFDataRef           data 
= NULL
; 
 438     CFPropertyListRef   plist 
= NULL
; 
 439     CFStringRef         errorString 
= NULL
; 
 441     buf 
= read_file(filename
, &bufsize
); 
 445     data 
= CFDataCreate(NULL
, buf
, bufsize
); 
 450     plist 
= CFPropertyListCreateFromXMLData(NULL
, data
, 
 451                                             kCFPropertyListMutableContainers
, 
 455             SCLog(TRUE
, LOG_INFO
, 
 456                   CFSTR(MY_PLUGIN_NAME 
":%@"), 
 458             CFRelease(errorString
); 
 469 #define IFNAMER_ID                      CFSTR("com.apple.SystemConfiguration.InterfaceNamer") 
 470 #define INTERFACES                      CFSTR("Interfaces") 
 471 #define NETWORK_INTERFACES_PREFS        CFSTR("NetworkInterfaces.plist") 
 472 #define OLD_NETWORK_INTERFACES_FILE     "/var/db/NetworkInterfaces.xml" 
 474 static CFMutableArrayRef
 
 478     CFMutableArrayRef   plist 
= NULL
; 
 479     SCPreferencesRef    prefs 
= NULL
; 
 481     prefs 
= SCPreferencesCreate(NULL
, IFNAMER_ID
, NETWORK_INTERFACES_PREFS
); 
 483         SCLog(TRUE
, LOG_INFO
, 
 484               CFSTR(MY_PLUGIN_NAME 
": SCPreferencesCreate failed, %s"), 
 485               SCErrorString(SCError())); 
 489     ilist 
= SCPreferencesGetValue(prefs
, INTERFACES
); 
 490     if (isA_CFArray(ilist
)) { 
 491         plist 
= CFArrayCreateMutableCopy(NULL
, 0, ilist
); 
 493         plist 
= (CFMutableArrayRef
)readPropertyList(OLD_NETWORK_INTERFACES_FILE
); 
 497         if (isA_CFArray(plist
) == NULL
) { 
 501         writeInterfaceList(plist
); 
 502         (void)unlink(OLD_NETWORK_INTERFACES_FILE
); 
 513 writeInterfaceList(CFArrayRef ilist
) 
 515     SCPreferencesRef    prefs
; 
 517     if (isA_CFArray(ilist
) == NULL
) { 
 521     prefs 
= SCPreferencesCreate(NULL
, IFNAMER_ID
, NETWORK_INTERFACES_PREFS
); 
 523         SCLog(TRUE
, LOG_INFO
, 
 524               CFSTR(MY_PLUGIN_NAME 
": SCPreferencesCreate failed, %s"), 
 525               SCErrorString(SCError())); 
 529     if (!SCPreferencesSetValue(prefs
, INTERFACES
, ilist
)) { 
 530         SCLog(TRUE
, LOG_INFO
, 
 531               CFSTR(MY_PLUGIN_NAME 
": SCPreferencesSetValue failed, %s"), 
 532               SCErrorString(SCError())); 
 536     if (!SCPreferencesCommitChanges(prefs
)) { 
 537         SCLog(TRUE
, LOG_INFO
, 
 538               CFSTR(MY_PLUGIN_NAME 
": SCPreferencesCommitChanges failed, %s"), 
 539               SCErrorString(SCError())); 
 550 updateBondConfiguration(void) 
 552     BondPreferencesRef  prefs
; 
 554     prefs 
= BondPreferencesCreate(NULL
); 
 556         SCLog(TRUE
, LOG_INFO
, 
 557               CFSTR(MY_PLUGIN_NAME 
": BondPreferencesCreate failed, %s"), 
 558               SCErrorString(SCError())); 
 562     if (!_BondPreferencesUpdateConfiguration(prefs
)) { 
 563         SCLog(TRUE
, LOG_INFO
, 
 564               CFSTR(MY_PLUGIN_NAME 
": _BondPreferencesUpdateConfiguration failed, %s"), 
 565               SCErrorString(SCError())); 
 576 updateVLANConfiguration(void) 
 578     VLANPreferencesRef  prefs
; 
 580     prefs 
= VLANPreferencesCreate(NULL
); 
 582         SCLog(TRUE
, LOG_INFO
, 
 583               CFSTR(MY_PLUGIN_NAME 
": VLANPreferencesCreate failed, %s"), 
 584               SCErrorString(SCError())); 
 588     if (!_VLANPreferencesUpdateConfiguration(prefs
)) { 
 589         SCLog(TRUE
, LOG_INFO
, 
 590               CFSTR(MY_PLUGIN_NAME 
": _VLANPreferencesUpdateConfiguration failed, %s"), 
 591               SCErrorString(SCError())); 
 601 #define INDEX_BAD       (-1) 
 603 static CFDictionaryRef
 
 604 lookupInterfaceByType(CFArrayRef list
, CFDictionaryRef if_dict
, int * where
) 
 617     addr 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOMACAddress
)); 
 618     type 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
)); 
 619     if (type 
== NULL 
|| addr 
== NULL
) { 
 623     n 
= CFArrayGetCount(list
); 
 624     for (i 
= 0; i 
< n
; i
++) { 
 625         CFDictionaryRef dict 
= CFArrayGetValueAtIndex(list
, i
); 
 629         a 
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
)); 
 630         t 
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
)); 
 631         if (a 
== NULL 
|| t 
== NULL
) 
 634         if (CFNumberCompare(type
, t
, NULL
) == kCFCompareEqualTo
 
 635             && compareMacAddress(addr
, a
) == kCFCompareEqualTo
) { 
 645 static CFDictionaryRef
 
 646 lookupInterfaceByUnit(CFArrayRef list
, CFDictionaryRef if_dict
, int * where
) 
 659     type 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
)); 
 660     unit 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
)); 
 661     if (type 
== NULL 
|| unit 
== NULL
) { 
 665     n 
= CFArrayGetCount(list
); 
 666     for (i 
= 0; i 
< n
; i
++) { 
 667         CFDictionaryRef dict 
= CFArrayGetValueAtIndex(list
, i
); 
 671         t 
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
)); 
 672         u 
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
)); 
 673         if (t 
== NULL 
|| u 
== NULL
) { 
 677         if (CFNumberCompare(type
, t
, NULL
) == kCFCompareEqualTo
 
 678             && CFNumberCompare(unit
, u
, NULL
) == kCFCompareEqualTo
) { 
 687 #define kAirPortDriverPath      CFSTR("AirPort") 
 688 #define kIO80211InterfacePath   CFSTR("IO80211Interface") 
 689 #define APPLE_WIRELESS_80211    CFSTR("AppleWireless80211") 
 691 static __inline__ boolean_t
 
 692 pathIsAirPort(CFStringRef path
) 
 696     r 
= CFStringFind(path
, kIO80211InterfacePath
, 0); 
 697     if (r
.location 
!= kCFNotFound
) { 
 701     r 
= CFStringFind(path
, kAirPortDriverPath
, 0); 
 702     if (r
.location 
!= kCFNotFound
) { 
 706     r 
= CFStringFind(path
, APPLE_WIRELESS_80211
, 0); 
 707     if (r
.location 
!= kCFNotFound
) { 
 714 static CFDictionaryRef
 
 715 lookupAirPortInterface(CFArrayRef list
, int * where
) 
 726     n 
= CFArrayGetCount(list
); 
 727     for (i 
= 0; i 
< n
; i
++) { 
 728         CFDictionaryRef dict 
= CFArrayGetValueAtIndex(list
, i
); 
 731         path 
= CFDictionaryGetValue(dict
, CFSTR(kIOPathMatchKey
)); 
 735         if (pathIsAirPort(path
) == TRUE
) { 
 745 insertInterface(CFMutableArrayRef list
, CFDictionaryRef if_dict
) 
 750     CFIndex             n       
= CFArrayGetCount(list
); 
 751     CFComparisonResult  res
; 
 753     if_type 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
)); 
 754     if_unit 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
)); 
 755     for (i 
= 0; i 
< n
; i
++) { 
 756         CFDictionaryRef dict 
= CFArrayGetValueAtIndex(list
, i
); 
 760         type 
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
)); 
 761         unit 
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
)); 
 762         res 
= CFNumberCompare(if_type
, type
, NULL
); 
 763         if (res 
== kCFCompareLessThan
 
 764             || (res 
== kCFCompareEqualTo
 
 765                 && (CFNumberCompare(if_unit
, unit
, NULL
) 
 766                     == kCFCompareLessThan
))) { 
 767             CFArrayInsertValueAtIndex(list
, i
, if_dict
); 
 771     CFArrayAppendValue(S_dblist
, if_dict
); 
 776 replaceInterface(CFDictionaryRef if_dict
) 
 780     if (S_dblist 
== NULL
) { 
 781         S_dblist 
= CFArrayCreateMutable(NULL
, 0, 
 782                                         &kCFTypeArrayCallBacks
); 
 784     /* remove any dict that has our type/addr */ 
 785     if (lookupInterfaceByType(S_dblist
, if_dict
, &where
) != NULL
) { 
 786         CFArrayRemoveValueAtIndex(S_dblist
, where
); 
 788     /* remove any dict that has the same type/unit */ 
 789     if (lookupInterfaceByUnit(S_dblist
, if_dict
, &where
) != NULL
) { 
 790         CFArrayRemoveValueAtIndex(S_dblist
, where
); 
 792     insertInterface(S_dblist
, if_dict
); 
 797 getHighestUnitForType(CFNumberRef if_type
) 
 801     CFNumberRef         ret_unit 
= NULL
; 
 803     if (S_dblist 
== NULL
) 
 806     n 
= CFArrayGetCount(S_dblist
); 
 807     for (i 
= 0; i 
< n
; i
++) { 
 808         CFDictionaryRef dict 
= CFArrayGetValueAtIndex(S_dblist
, i
); 
 812         type 
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
)); 
 813         if (CFEqual(type
, if_type
)) { 
 814             unit 
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
)); 
 816                 || (CFNumberCompare(unit
, ret_unit
, NULL
) 
 817                     == kCFCompareGreaterThan
)) { 
 825 //------------------------------------------------------------------------ 
 826 // Register a single interface with the given service path to the 
 827 // data link layer (BSD), using the specified unit number. 
 830 registerInterface(io_connect_t connect
, 
 834     CFMutableDictionaryRef      dict
; 
 835     kern_return_t               kr 
= kIOReturnNoMemory
; 
 837     dict 
= CFDictionaryCreateMutable(NULL
, 0, 
 838                                      &kCFTypeDictionaryKeyCallBacks
, 
 839                                      &kCFTypeDictionaryValueCallBacks
); 
 841         || addCFNumberProperty(dict
, kIONetworkStackUserCommand
, 
 842                                kIORegisterOne
) == FALSE
) 
 845         CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
); 
 846         CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
); 
 847         kr 
= IOConnectSetCFProperties(connect
, dict
); 
 849     if (dict
) CFRelease( dict 
); 
 854  * Note: this function blocks all other plug-ins until it completes 
 857 waitForQuiet(mach_port_t masterPort
) 
 860     kern_return_t   wait_ret
; 
 865     // kIOReturnTimeout if the wait timed out. 
 866     // kIOReturnSuccess on success. 
 867     wait_ret 
= IOKitWaitQuiet(masterPort
, &t
); 
 872  * Function: createNetworkStackObject 
 874  *   Get a reference to the single IONetworkStack object instance in 
 875  *   the kernel. Naming requests must be sent to this object, which is 
 876  *   attached as a client to all network interface objects in the system. 
 878  *   Call IOObjectRelease on the returned object. 
 881 createNetworkStackObject(mach_port_t masterPort
) 
 883     io_iterator_t       iter 
= MACH_PORT_NULL
; 
 885     io_object_t         stack 
= MACH_PORT_NULL
; 
 887     kr 
= IOServiceGetMatchingServices(masterPort
, 
 888                                       IOServiceMatching("IONetworkStack"), 
 890     if (iter 
!= MACH_PORT_NULL
) { 
 891         if (kr 
== KERN_SUCCESS
) { 
 892             stack 
= IOIteratorNext(iter
); 
 894         IOObjectRelease(iter
); 
 900 printMacAddress(CFDataRef data
) 
 903     CFIndex     n 
= CFDataGetLength(data
); 
 905     for (i 
= 0; i 
< n
; i
++) { 
 906         if (i 
!= 0) SCPrint(TRUE
, stdout
, CFSTR(":")); 
 907         SCPrint(TRUE
, stdout
, CFSTR("%02x"), CFDataGetBytePtr(data
)[i
]); 
 913  * Function: getMacAddress 
 916  *   Given an interface object if_obj, return its associated mac address. 
 917  *   The mac address is stored in the parent, the network controller object. 
 920  *   The CFDataRef containing the bytes of the mac address. 
 923 getMacAddress(io_object_t if_obj
) 
 925     CFMutableDictionaryRef      dict 
= NULL
; 
 926     CFDataRef                   data 
= NULL
; 
 928     io_object_t                 parent_obj 
= MACH_PORT_NULL
; 
 930     /* get the parent node */ 
 931     kr 
= IORegistryEntryGetParentEntry(if_obj
, kIOServicePlane
, &parent_obj
); 
 932     if (kr 
!= KERN_SUCCESS
) { 
 933         SCLog(TRUE
, LOG_INFO
, 
 935                     ": IORegistryEntryGetParentEntry returned 0x%x"), 
 940     /* get the dictionary associated with the node */ 
 941     kr 
= IORegistryEntryCreateCFProperties(parent_obj
, 
 945     if (kr 
!= KERN_SUCCESS
) { 
 946         SCLog(TRUE
, LOG_INFO
, 
 948                     ": IORegistryEntryCreateCFProperties returned 0x%x"), 
 952     data 
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
)); 
 961         IOObjectRelease(parent_obj
); 
 965 static CFDictionaryRef
 
 966 getInterface(io_object_t if_obj
) 
 968     CFBooleanRef                        builtin
; 
 970     CFDataRef                           mac_address 
= NULL
; 
 971     CFStringRef                         location
; 
 972     CFMutableDictionaryRef              new_if 
= NULL
; 
 974     CFMutableDictionaryRef              reginfo_if 
= NULL
; 
 975     CFDictionaryRef                     ret_dict 
= NULL
; 
 980     kr 
= IORegistryEntryGetPath(if_obj
, kIOServicePlane
, path
); 
 981     if (kr 
!= KERN_SUCCESS
) { 
 982         SCLog(TRUE
, LOG_INFO
, 
 984                     ": IORegistryEntryGetPath returned 0x%x"), 
 988     kr 
= IORegistryEntryCreateCFProperties(if_obj
, 
 992     if (kr 
!= KERN_SUCCESS
) { 
 993         SCLog(TRUE
, LOG_INFO
, 
 995                     ": IORegistryEntryCreateCFProperties returned 0x%x"), 
 999     type 
= isA_CFNumber(CFDictionaryGetValue(reginfo_if
, 
1000                                              CFSTR(kIOInterfaceType
))); 
1004     mac_address 
= getMacAddress(if_obj
); 
1005     if (mac_address 
== NULL
) { 
1008     builtin 
= isA_CFBoolean(CFDictionaryGetValue(reginfo_if
, 
1009                                                  CFSTR(kIOBuiltin
))); 
1010     if ((builtin 
== NULL
) || !CFBooleanGetValue(builtin
)) { 
1011         builtin 
= isA_CFBoolean(CFDictionaryGetValue(reginfo_if
, 
1012                                                  CFSTR(kIOPrimaryInterface
))); 
1014     location 
= isA_CFString(CFDictionaryGetValue(reginfo_if
, 
1015                                                  CFSTR(kIOLocation
))); 
1017     new_if 
= CFDictionaryCreateMutable(NULL
, 0, 
1018                                        &kCFTypeDictionaryKeyCallBacks
, 
1019                                        &kCFTypeDictionaryValueCallBacks
); 
1020     if (new_if 
== NULL
) { 
1023     CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), type
); 
1024     CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), mac_address
); 
1026         CFDictionarySetValue(new_if
, CFSTR(kIOBuiltin
), builtin
); 
1029         CFDictionarySetValue(new_if
, CFSTR(kIOLocation
), location
); 
1031     addCFStringProperty(new_if
, kIOPathMatchKey
, path
); 
1033     unit 
= isA_CFNumber(CFDictionaryGetValue(reginfo_if
, 
1034                                              CFSTR(kIOInterfaceUnit
))); 
1036         CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), unit
); 
1038     string 
= isA_CFString(CFDictionaryGetValue(reginfo_if
, CFSTR(kIOBSDNameKey
))); 
1040         CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), string
); 
1050         CFRelease(reginfo_if
); 
1053         CFRelease(mac_address
); 
1058 static CFDictionaryRef
 
1059 lookupIOKitPath(CFStringRef if_path
) 
1061     CFDictionaryRef             dict 
= NULL
; 
1062     io_registry_entry_t         entry 
= MACH_PORT_NULL
; 
1064     mach_port_t                 masterPort 
= MACH_PORT_NULL
; 
1067     kr 
= IOMasterPort(bootstrap_port
, &masterPort
); 
1068     if (kr 
!= KERN_SUCCESS
) { 
1069         SCLog(TRUE
, LOG_INFO
, 
1070               CFSTR(MY_PLUGIN_NAME 
": IOMasterPort returned 0x%x\n"), 
1074     _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
); 
1075     entry 
= IORegistryEntryFromPath(masterPort
, path
); 
1076     if (entry 
== MACH_PORT_NULL
) { 
1077         SCLog(TRUE
, LOG_INFO
, 
1078               CFSTR(MY_PLUGIN_NAME 
": IORegistryEntryFromPath(%@) failed"), 
1082     dict 
= getInterface(entry
); 
1085     if (masterPort 
!= MACH_PORT_NULL
) { 
1086         mach_port_deallocate(mach_task_self(), masterPort
); 
1088     if (entry 
!= MACH_PORT_NULL
) { 
1089         IOObjectRelease(entry
); 
1096 displayInterface(CFDictionaryRef if_dict
) 
1102     name 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
)); 
1104         SCPrint(TRUE
, stdout
, CFSTR("BSD Name: %@\n"), name
); 
1107     unit 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
)); 
1109         SCPrint(TRUE
, stdout
, CFSTR("Unit: %@\n"), unit
); 
1112     type 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
)); 
1113     SCPrint(TRUE
, stdout
, CFSTR("Type: %@\n"), type
); 
1115     SCPrint(TRUE
, stdout
, CFSTR("MAC address: ")); 
1116     printMacAddress(CFDictionaryGetValue(if_dict
, CFSTR(kIOMACAddress
))); 
1117     SCPrint(TRUE
, stdout
, CFSTR("\n")); 
1121 sort_interfaces_by_unit(CFMutableArrayRef if_list
) 
1123     int         count 
= CFArrayGetCount(if_list
); 
1124     CFRange     range 
= CFRangeMake(0, count
); 
1128     CFArraySortValues(if_list
, range
, if_unit_compare
, NULL
); 
1133 sort_interfaces_by_path(CFMutableArrayRef if_list
) 
1135     int         count 
= CFArrayGetCount(if_list
); 
1136     CFRange     range 
= CFRangeMake(0, count
); 
1140     CFArraySortValues(if_list
, range
, if_path_compare
, NULL
); 
1145 name_interfaces(CFArrayRef if_list
) 
1148     CFIndex     n 
= CFArrayGetCount(if_list
); 
1149     CFIndex     i_builtin 
= 0; 
1150     CFIndex     n_builtin 
= 0; 
1153         SCPrint(TRUE
, stdout
, CFSTR("\n")); 
1155     for (i 
= 0; i 
< n
; i
++) { 
1156         CFBooleanRef    builtin
; 
1157         CFDictionaryRef if_dict
; 
1159         if_dict 
= CFArrayGetValueAtIndex(if_list
, i
); 
1160         builtin 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBuiltin
)); 
1161         if (builtin 
&& CFBooleanGetValue(builtin
)) { 
1162             n_builtin
++;        // reserve unit number for built-in interface 
1166     for (i 
= 0; i 
< n
; i
++) { 
1167         CFDictionaryRef if_dict
; 
1173                 SCPrint(TRUE
, stdout
, CFSTR("\n")); 
1176         if_dict 
= CFArrayGetValueAtIndex(if_list
, i
); 
1177         unit 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
)); 
1178         type 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
)); 
1181                 SCPrint(TRUE
, stdout
, CFSTR("Interface already has a unit number\n")); 
1182                 displayInterface(if_dict
); 
1184             replaceInterface(if_dict
); 
1187             CFDictionaryRef             dbdict 
= NULL
; 
1188             kern_return_t               kr 
= KERN_SUCCESS
; 
1190             CFNumberRef                 unit 
= NULL
; 
1192             path 
= CFDictionaryGetValue(if_dict
, CFSTR(kIOPathMatchKey
)); 
1193             dbdict 
= lookupInterfaceByType(S_dblist
, if_dict
, NULL
); 
1195                 && pathIsAirPort(path
) == TRUE
) { 
1196                 dbdict 
= lookupAirPortInterface(S_dblist
, NULL
); 
1198             if (dbdict 
!= NULL
) { 
1199                 unit 
= CFDictionaryGetValue(dbdict
, 
1200                                             CFSTR(kIOInterfaceUnit
)); 
1205                 boolean_t       is_builtin 
= FALSE
; 
1208                 CFNumberGetValue(type
, 
1209                                  kCFNumberIntType
, &if_type
); 
1210                 if (if_type 
== IFT_ETHER
) { /* ethernet */ 
1211                     CFBooleanRef        builtin
; 
1213                     builtin 
= CFDictionaryGetValue(if_dict
, 
1215                     if (builtin 
&& CFBooleanGetValue(builtin
)) { 
1217                         next_unit 
= i_builtin
++; 
1220 #if defined(__ppc__) 
1221                         /* skip over slots reserved for built-in ethernet interface(s) */ 
1222                         next_unit 
= n_builtin
; 
1226                 if (is_builtin 
== FALSE
) { 
1227                     unit 
= getHighestUnitForType(type
); 
1231                         CFNumberGetValue(unit
, 
1232                                          kCFNumberIntType
, &high_unit
); 
1233                         if (high_unit 
>= next_unit
) { 
1234                             next_unit 
= high_unit 
+ 1; 
1238                 unit 
= CFNumberCreate(NULL
, 
1239                                       kCFNumberIntType
, &next_unit
); 
1242                 SCPrint(TRUE
, stdout
, CFSTR("Interface assigned unit %@ %s\n"), unit
, 
1243                         dbdict 
? "(from database)" : "(next available)"); 
1245             kr 
= registerInterface(S_connect
, path
, unit
); 
1246             if (kr 
!= KERN_SUCCESS
) { 
1247                 SCLog(TRUE
, LOG_INFO
, 
1248                       CFSTR(MY_PLUGIN_NAME
 
1249                             ": failed to name the interface 0x%x"), 
1252                     displayInterface(if_dict
); 
1256                 CFDictionaryRef new_dict
; 
1258                 path 
= CFDictionaryGetValue(if_dict
, 
1259                                             CFSTR(kIOPathMatchKey
)); 
1260                 new_dict 
= lookupIOKitPath(path
); 
1261                 if (new_dict 
!= NULL
) { 
1262                     CFNumberRef         new_unit
; 
1264                     new_unit 
= CFDictionaryGetValue(new_dict
, 
1265                                                     CFSTR(kIOInterfaceUnit
)); 
1266                     if (CFEqual(unit
, new_unit
) == FALSE
) { 
1267                         SCLog(TRUE
, LOG_INFO
, 
1268                               CFSTR(MY_PLUGIN_NAME
 
1269                                     ": interface type %@ assigned " 
1270                                     "unit %@ instead of %@"), 
1271                               type
, new_unit
, unit
); 
1274                         displayInterface(new_dict
); 
1276                     replaceInterface(new_dict
); 
1277                     CFRelease(new_dict
); 
1283     writeInterfaceList(S_dblist
); 
1288 interfaceArrivalCallback( void * refcon
, io_iterator_t iter 
) 
1290     CFMutableArrayRef   if_list 
= NULL
; 
1294     while ((obj 
= IOIteratorNext(iter
))) { 
1295         CFDictionaryRef dict
; 
1297         dict 
= getInterface(obj
); 
1299             if (if_list 
== NULL
) { 
1300                 if_list 
= CFArrayCreateMutable(NULL
, 0, 
1301                                                &kCFTypeArrayCallBacks
); 
1304                 CFArrayAppendValue(if_list
, dict
); 
1307         IOObjectRelease(obj
); 
1310         sort_interfaces_by_path(if_list
); 
1311         name_interfaces(if_list
); 
1312         updateBondConfiguration(); 
1313         updateVLANConfiguration(); 
1322 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
) 
1325     mach_port_t         masterPort 
= MACH_PORT_NULL
; 
1326     io_object_t         stack 
= MACH_PORT_NULL
; 
1328     if (bundleVerbose
) { 
1332     kr 
= IOMasterPort(bootstrap_port
, &masterPort
); 
1333     if (kr 
!= KERN_SUCCESS
) { 
1334         SCLog(TRUE
, LOG_INFO
, 
1335               CFSTR(MY_PLUGIN_NAME 
": IOMasterPort returned 0x%x"), 
1340     /* synchronize with any drivers that might be loading at boot time */ 
1341     waitForQuiet(masterPort
); 
1343     stack 
= createNetworkStackObject(masterPort
); 
1344     if (stack 
== MACH_PORT_NULL
) { 
1345         SCLog(TRUE
, LOG_INFO
, 
1346               CFSTR(MY_PLUGIN_NAME 
": No network stack object")); 
1349     kr 
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
); 
1350     if (kr 
!= KERN_SUCCESS
) { 
1351         SCPrint(TRUE
, stdout
, CFSTR(MY_PLUGIN_NAME 
": IOServiceOpen returned 0x%x\n"), kr
); 
1355     // Creates and returns a notification object for receiving IOKit 
1356     // notifications of new devices or state changes. 
1358     S_notify 
= IONotificationPortCreate(masterPort
); 
1359     if (S_notify 
== NULL
) { 
1360         SCLog(TRUE
, LOG_INFO
, 
1361               CFSTR(MY_PLUGIN_NAME 
": IONotificationPortCreate failed")); 
1364     kr 
= IOServiceAddMatchingNotification(S_notify
, 
1365                                           kIOFirstMatchNotification
, 
1366                                           IOServiceMatching("IONetworkInterface"), 
1367                                           &interfaceArrivalCallback
, 
1368                                           (void *) S_notify
, /* refCon */ 
1369                                           &S_iter 
);         /* notification */ 
1371     if (kr 
!= KERN_SUCCESS
) { 
1372         SCLog(TRUE
, LOG_INFO
, 
1373               CFSTR(MY_PLUGIN_NAME
 
1374                     ": IOServiceAddMatchingNotification returned 0x%x"), 
1379     S_dblist 
= readInterfaceList(); 
1381         sort_interfaces_by_unit(S_dblist
); 
1383     // Get the current list of matches and arms the notification for 
1384     // future interface arrivals. 
1386     interfaceArrivalCallback((void *) S_notify
, S_iter
); 
1388     CFRunLoopAddSource(CFRunLoopGetCurrent(), 
1389                        IONotificationPortGetRunLoopSource(S_notify
), 
1390                        kCFRunLoopDefaultMode
); 
1391     if (stack 
!= MACH_PORT_NULL
) { 
1392         IOObjectRelease(stack
); 
1394     if (masterPort 
!= MACH_PORT_NULL
) { 
1395         mach_port_deallocate(mach_task_self(), masterPort
); 
1399     if (stack 
!= MACH_PORT_NULL
) { 
1400         IOObjectRelease(stack
); 
1402     if (masterPort 
!= MACH_PORT_NULL
) { 
1403         mach_port_deallocate(mach_task_self(), masterPort
); 
1405     if (S_connect 
!= MACH_PORT_NULL
) { 
1406         IOServiceClose(S_connect
); 
1407         S_connect 
= MACH_PORT_NULL
; 
1409     if (S_iter 
!= MACH_PORT_NULL
) { 
1410         IOObjectRelease(S_iter
); 
1411         S_iter 
= MACH_PORT_NULL
; 
1413     if (S_notify 
!= MACH_PORT_NULL
) { 
1414         IONotificationPortDestroy(S_notify
); 
1419 //------------------------------------------------------------------------ 
1423 main(int argc
, char ** argv
) 
1425     load_InterfaceNamer(CFBundleGetMainBundle(), 
1426          (argc 
> 1) ? TRUE 
: FALSE
);