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
);