2 * Copyright (c) 2001-2008 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 * November 6, 2006 Allan Nathanson <ajn@apple.com>
28 * Dan Markarian <markarian@apple.com>
29 * Dieter Siegmund <dieter@apple.com>
30 * - updated code to name interfaces quicker (without need for
31 * calling IOKitWaitQuiet).
33 * October 3, 2003 Allan Nathanson <ajn@apple.com>
34 * - sort new interfaces by IOKit path (rather than MAC address) to
35 * help facilitate a more predictable interface-->name mapping for
36 * like hardware configurations.
38 * June 23, 2001 Allan Nathanson <ajn@apple.com>
39 * - update to public SystemConfiguration.framework APIs
41 * January 23, 2001 Dieter Siegmund <dieter@apple.com>
47 * - module that receives IOKit Network Interface messages
48 * and names any interface that currently does not have a name
49 * - uses Interface Type and MACAddress as the unique identifying
50 * keys; any interface that doesn't contain both of these properties
51 * is ignored and not processed
52 * - stores the Interface Type, MACAddress, and Unit in permanent storage
53 * to give persistent interface names
61 #include <sys/ioctl.h>
62 #include <sys/socket.h>
63 #include <sys/sockio.h>
65 #include <sys/param.h>
66 #include <mach/mach.h>
67 #include <net/ethernet.h>
69 #include <net/if_types.h>
71 #include <CoreFoundation/CoreFoundation.h>
73 #include <SystemConfiguration/SystemConfiguration.h>
74 #include <SystemConfiguration/SCDPlugin.h>
75 #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
76 #include <SystemConfiguration/SCValidation.h>
78 #include <IOKit/IOKitLib.h>
79 #include <IOKit/IOKitLibPrivate.h>
80 #include <IOKit/IOBSD.h>
81 #include <IOKit/IOMessage.h>
82 #include <IOKit/network/IONetworkController.h>
83 #include <IOKit/network/IONetworkInterface.h>
84 #include <IOKit/usb/USB.h>
86 #define kIONetworkStackUserCommand "IONetworkStackUserCommand"
87 #define kRegisterInterface 1
89 #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo"
90 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
91 #define kSCNetworkInterfaceActive "Active"
93 #define MY_PLUGIN_NAME "InterfaceNamer"
94 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
96 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
97 #define WAIT_QUIET_TIMEOUT_DEFAULT 60.0
101 * "IONetworkStack" connect object used to "name" an interface.
103 static io_connect_t S_connect
= MACH_PORT_NULL
;
107 * An array of CFDictionary's representing the interfaces
108 * that have been identified and [need to be] named.
110 static CFMutableArrayRef S_dblist
= NULL
;
114 * A boolean that enables additional logging.
116 static boolean_t S_debug
= FALSE
;
120 * An array of SCNetworkInterface's representing the
121 * interfaces that have been identified.
123 static CFMutableArrayRef S_iflist
= NULL
;
127 * IOServiceAddMatchingNotification object used to watch for
128 * new network interfaces.
130 static io_iterator_t S_iter
= MACH_PORT_NULL
;
134 * notification object for receiving IOKit notifications of
135 * new devices or state changes.
137 static IONotificationPortRef S_notify
= NULL
;
139 /* S_prev_active_list
140 * An array of CFDictionary's representing the previously
143 static CFMutableArrayRef S_prev_active_list
= NULL
;
147 * IOServiceAddInterestNotification object used to watch for
148 * IOKit matching to quiesce.
150 static io_object_t S_quiet
= MACH_PORT_NULL
;
154 * IOServiceAddMatchingNotification object used to watch for
155 * the availability of the "IONetworkStack" object.
157 static io_iterator_t S_stack
= MACH_PORT_NULL
;
161 * A dictionary containing Information about each network
162 * interface. For now, the key is the BSD name and the
163 * value is a CFNumber noting how long (in milliseconds)
164 * it took for the interface to be recognized/named.
166 static CFMutableDictionaryRef S_state
= NULL
;
170 * CFRunLoopTimer tracking how long we are willing to wait
171 * for IOKit matching to quiesce (IOKitWaitQuiet).
173 static CFRunLoopTimerRef S_timer
= NULL
;
175 #if !TARGET_OS_IPHONE
177 * Virtual network interface configuration
178 * S_prefs : SCPreferences to configuration
179 * S_bonds : most recently actived Bond configuration
180 * S_vlans : most recently actived VLAN configuration
182 static SCPreferencesRef S_prefs
= NULL
;
183 static CFArrayRef S_bonds
= NULL
;
184 static CFArrayRef S_vlans
= NULL
;
185 #endif /* !TARGET_OS_IPHONE */
188 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
193 now
= CFAbsoluteTimeGetCurrent();
194 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
195 CFDictionaryAddValue(dict
, key
, val
);
200 static CFComparisonResult
201 if_unit_compare(const void *val1
, const void *val2
, void *context
)
203 CFComparisonResult res
;
209 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
210 CFSTR(kIOInterfaceType
));
211 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
212 CFSTR(kIOInterfaceType
));
213 res
= CFNumberCompare(type1
, type2
, NULL
);
214 if (res
!= kCFCompareEqualTo
) {
217 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
218 CFSTR(kIOInterfaceUnit
));
219 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
220 CFSTR(kIOInterfaceUnit
));
221 return (CFNumberCompare(unit1
, unit2
, NULL
));
225 read_file(char * filename
, size_t * data_length
)
233 if (stat(filename
, &sb
) == -1)
243 fd
= open(filename
, O_RDONLY
);
247 if (read(fd
, data
, len
) != len
) {
249 CFSTR(MY_PLUGIN_NAME
": read %s failed, %s"),
250 filename
, strerror(errno
));
263 static CFPropertyListRef
264 readPropertyList(char * filename
)
268 CFDataRef data
= NULL
;
269 CFPropertyListRef plist
= NULL
;
270 CFStringRef errorString
= NULL
;
272 buf
= read_file(filename
, &bufsize
);
276 data
= CFDataCreate(NULL
, buf
, bufsize
);
281 plist
= CFPropertyListCreateFromXMLData(NULL
, data
,
282 kCFPropertyListMutableContainers
,
285 if (errorString
!= NULL
) {
287 CFSTR(MY_PLUGIN_NAME
": %@"),
289 CFRelease(errorString
);
300 #define INTERFACES CFSTR("Interfaces")
301 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
302 #define OLD_NETWORK_INTERFACES_FILE "/var/db/NetworkInterfaces.xml"
305 writeInterfaceList(CFArrayRef if_list
)
308 SCPreferencesRef prefs
;
310 if (isA_CFArray(if_list
) == NULL
) {
314 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
317 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate failed, %s"),
318 SCErrorString(SCError()));
322 cur_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
323 if (_SC_CFEqual(cur_list
, if_list
)) {
327 if (!SCPreferencesSetValue(prefs
, INTERFACES
, if_list
)) {
329 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetValue failed, %s"),
330 SCErrorString(SCError()));
334 if (!SCPreferencesCommitChanges(prefs
)) {
335 SCLog((SCError() != EROFS
), LOG_ERR
,
336 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCommitChanges failed, %s"),
337 SCErrorString(SCError()));
347 static CFMutableArrayRef
351 CFMutableArrayRef plist
= NULL
;
352 SCPreferencesRef prefs
= NULL
;
354 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
357 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate failed, %s"),
358 SCErrorString(SCError()));
362 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
363 if (!isA_CFArray(if_list
)) {
364 if_list
= (CFArrayRef
)readPropertyList(OLD_NETWORK_INTERFACES_FILE
);
365 if (if_list
== NULL
) {
368 if (!isA_CFArray(if_list
)) {
373 writeInterfaceList(if_list
);
374 (void)unlink(OLD_NETWORK_INTERFACES_FILE
);
378 if (if_list
!= NULL
) {
380 CFIndex n
= CFArrayGetCount(if_list
);
382 plist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
383 for (i
= 0; i
< n
; i
++) {
384 CFDictionaryRef dict
;
386 dict
= CFArrayGetValueAtIndex(if_list
, i
);
387 if (isA_CFDictionary(dict
) &&
388 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceType
)) &&
389 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
390 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
391 CFArrayAppendValue(plist
, dict
);
401 static CFMutableArrayRef
402 previouslyActiveInterfaces()
404 CFMutableArrayRef active
;
408 if (S_dblist
== NULL
) {
412 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
414 n
= CFArrayGetCount(S_dblist
);
415 for (i
= 0; i
< n
; i
++) {
416 CFDictionaryRef if_dict
;
418 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
419 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
420 CFMutableDictionaryRef new_dict
;
422 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
423 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
424 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
425 CFArrayAppendValue(active
, new_dict
);
437 SCDynamicStoreRef store
;
439 store
= SCDynamicStoreCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
, NULL
);
444 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
),
445 kSCDynamicStoreDomainPlugin
);
446 (void)SCDynamicStoreSetValue(store
, key
, S_state
);
453 #if !TARGET_OS_IPHONE
455 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
456 SCPreferencesNotification notificationType
,
459 CFArrayRef interfaces
;
461 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
466 // if a new interface has been "named"
468 if (S_bonds
!= NULL
) {
472 if (S_vlans
!= NULL
) {
478 // update Bond configuration
480 interfaces
= SCBondInterfaceCopyAll(prefs
);
481 if ((S_bonds
== NULL
) && (interfaces
== NULL
)) {
485 if ((S_bonds
!= NULL
) && (interfaces
!= NULL
) && CFEqual(S_bonds
, interfaces
)) {
487 CFRelease(interfaces
);
490 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
491 S_bonds
= interfaces
;
493 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
495 CFSTR(MY_PLUGIN_NAME
": _SCBondInterfaceUpdateConfiguration failed, %s"),
496 SCErrorString(SCError()));
501 // update VLAN configuration
503 interfaces
= SCVLANInterfaceCopyAll(prefs
);
504 if ((S_vlans
== NULL
) && (interfaces
== NULL
)) {
508 if ((S_vlans
!= NULL
) && (interfaces
!= NULL
) && CFEqual(S_vlans
, interfaces
)) {
510 CFRelease(interfaces
);
513 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
514 S_vlans
= interfaces
;
516 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
518 CFSTR(MY_PLUGIN_NAME
": _SCVLANInterfaceUpdateConfiguration failed, %s"),
519 SCErrorString(SCError()));
524 // we are finished with current prefs, wait for changes
526 SCPreferencesSynchronize(prefs
);
529 #endif /* !TARGET_OS_IPHONE */
531 static CFDictionaryRef
532 createInterfaceDict(SCNetworkInterfaceRef interface
)
534 CFMutableDictionaryRef new_if
;
537 new_if
= CFDictionaryCreateMutable(NULL
,
539 &kCFTypeDictionaryKeyCallBacks
,
540 &kCFTypeDictionaryValueCallBacks
);
542 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
544 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
548 val
= _SCNetworkInterfaceGetIOPath(interface
);
550 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
553 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
555 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
558 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
560 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
563 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
565 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
568 val
= SCNetworkInterfaceGetBSDName(interface
);
570 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
573 val
= SCNetworkInterfaceGetInterfaceType(interface
);
575 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
578 CFDictionarySetValue(new_if
,
580 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
582 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
587 static CFDictionaryRef
588 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
595 if (db_list
== NULL
) {
598 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
599 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
600 if (type
== NULL
|| addr
== NULL
) {
604 n
= CFArrayGetCount(db_list
);
605 for (i
= 0; i
< n
; i
++) {
607 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
610 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
611 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
612 if (t
== NULL
|| a
== NULL
)
615 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
625 static CFDictionaryRef
626 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
633 if (db_list
== NULL
) {
636 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
637 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
638 if (type
== NULL
|| unit
== NULL
) {
642 n
= CFArrayGetCount(db_list
);
643 for (i
= 0; i
< n
; i
++) {
644 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
648 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
649 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
650 if (t
== NULL
|| u
== NULL
) {
654 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
664 CFDictionaryRef match_info
;
665 CFStringRef match_type
;
666 CFBooleanRef match_builtin
;
667 CFMutableArrayRef matches
;
668 } matchContext
, *matchContextRef
;
670 static CFDictionaryRef
671 thinInterfaceInfo(CFDictionaryRef info
)
676 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
678 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
679 && (vid
== kIOUSBVendorIDAppleComputer
)) {
680 CFMutableDictionaryRef thin
;
682 // if this is an Apple USB device than we trust that
683 // the non-localized name will be correct.
684 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
685 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
686 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
687 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
691 return CFRetain(info
);
695 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
699 match
= _SC_CFEqual(known_info
, match_info
);
701 isA_CFDictionary(known_info
) &&
702 isA_CFDictionary(match_info
)) {
704 // if not an exact match, try thinning
705 known_info
= thinInterfaceInfo(known_info
);
706 match_info
= thinInterfaceInfo(match_info
);
707 match
= _SC_CFEqual(known_info
, match_info
);
708 CFRelease(known_info
);
709 CFRelease(match_info
);
716 matchKnown(const void *value
, void *context
)
718 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
719 matchContextRef match_context
= (matchContextRef
)context
;
721 // match interface type
723 CFStringRef known_type
;
725 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
726 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
731 // match SCNetworkInterfaceInfo
733 CFDictionaryRef known_info
;
735 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
736 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
741 // if requested, match [non-]builtin
742 if (match_context
->match_builtin
!= NULL
) {
743 CFBooleanRef known_builtin
;
745 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
746 if (!isA_CFBoolean(known_builtin
)) {
747 known_builtin
= kCFBooleanFalse
;
749 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
754 // if we have a match
755 if (match_context
->matches
== NULL
) {
756 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
758 CFArrayAppendValue(match_context
->matches
, known_dict
);
764 matchUnnamed(const void *value
, void *context
)
766 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
767 matchContextRef match_context
= (matchContextRef
)context
;
769 if (match_context
->matches
== NULL
) {
773 // match interface type
775 CFStringRef known_type
;
777 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
778 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
783 // match SCNetworkInterfaceInfo
785 CFDictionaryRef known_info
;
788 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
789 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
790 if (known_info
!= NULL
) CFRelease(known_info
);
796 // if requested, match [non-]builtin
797 if (match_context
->match_builtin
!= NULL
) {
798 CFBooleanRef known_builtin
;
800 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
802 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
807 // if we have a match
808 CFRelease(match_context
->matches
);
809 match_context
->matches
= NULL
;
815 * lookupMatchingInterface
817 * Looks at the interfaces that have already been [or need to be] named with
818 * the goal of allowing a system using a single network interface/adaptor of
819 * a given type (vendor, model, ...) to not care about the specific adaptor
820 * that is used (i.e. swapping dongle's is OK). Once a system has had more
821 * than one interface/adaptor connected at the same time than we assume that
822 * the network configuration is being setup for multi-homing that should be
825 * If no matches are found or if more than one match is found, return NULL.
826 * If a single match is found, return the match.
828 static CFDictionaryRef
829 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
830 CFArrayRef db_list
, // already named
831 CFArrayRef if_list
, // to be named
832 CFIndex if_list_index
,
833 CFBooleanRef builtin
)
836 CFDictionaryRef match
= NULL
;
837 matchContext match_context
;
839 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
840 if (if_type
== NULL
) {
844 match_context
.match_type
= if_type
;
845 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
846 match_context
.match_builtin
= builtin
;
847 match_context
.matches
= NULL
;
849 // check for matches to already named interfaces
850 // ... and appends each match that we find to match_context.matches
851 if (db_list
!= NULL
) {
852 CFArrayApplyFunction(db_list
,
853 CFRangeMake(0, CFArrayGetCount(db_list
)),
858 // check for matches to to be named interfaces
859 // ... and CFReleases match_context.matches if we find another network
860 // interface of the same type that also needs to be named
861 if (if_list
!= NULL
) {
862 CFIndex if_list_count
;
864 if_list_count
= CFArrayGetCount(if_list
);
865 if (if_list_index
< if_list_count
) {
866 CFArrayApplyFunction(if_list
,
867 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
873 // check if we have a single match
874 if (match_context
.matches
!= NULL
) {
875 if (CFArrayGetCount(match_context
.matches
) == 1) {
876 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
878 CFRelease(match_context
.matches
);
882 Boolean active
= TRUE
;
885 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
886 if (isA_CFString(name
)) {
889 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
893 (void)_SC_cfstring_to_cstring(name
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
);
894 if (ioctl(sock
, SIOCGIFFLAGS
, &ifr
) == -1) {
895 // if interface name not currently in-use
907 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
912 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
)
915 CFDictionaryRef if_dict
;
919 CFIndex n
= CFArrayGetCount(db_list
);
920 CFComparisonResult res
;
922 if_name
= SCNetworkInterfaceGetBSDName(interface
);
923 if (if_name
!= NULL
) {
924 addTimestamp(S_state
, if_name
);
927 if_dict
= createInterfaceDict(interface
);
928 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
929 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
930 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
935 for (i
= 0; i
< n
; i
++) {
938 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
940 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
941 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
942 res
= CFNumberCompare(if_type
, db_type
, NULL
);
943 if (res
== kCFCompareLessThan
944 || (res
== kCFCompareEqualTo
945 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
946 == kCFCompareLessThan
))) {
947 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
953 CFArrayAppendValue(S_dblist
, if_dict
);
959 replaceInterface(SCNetworkInterfaceRef interface
)
963 if (S_dblist
== NULL
) {
964 S_dblist
= CFArrayCreateMutable(NULL
, 0,
965 &kCFTypeArrayCallBacks
);
967 // remove any dict that has our type/addr
968 if (lookupInterfaceByAddress(S_dblist
, interface
, &where
) != NULL
) {
969 CFArrayRemoveValueAtIndex(S_dblist
, where
);
971 // remove any dict that has the same type/unit
972 if (lookupInterfaceByUnit(S_dblist
, interface
, &where
) != NULL
) {
973 CFArrayRemoveValueAtIndex(S_dblist
, where
);
975 insertInterface(S_dblist
, interface
);
980 getHighestUnitForType(CFNumberRef if_type
)
984 CFNumberRef ret_unit
= NULL
;
986 if (S_dblist
== NULL
) {
990 n
= CFArrayGetCount(S_dblist
);
991 for (i
= 0; i
< n
; i
++) {
992 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
995 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
996 if (CFEqual(type
, if_type
)) {
999 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1000 if (ret_unit
== NULL
1001 || (CFNumberCompare(unit
, ret_unit
, NULL
)
1002 == kCFCompareGreaterThan
)) {
1012 * Function: registerInterface
1014 * Register a single interface with the given service path to the
1015 * data link layer (BSD), using the specified unit number.
1017 static kern_return_t
1018 registerInterface(io_connect_t connect
,
1022 static const int command
= kRegisterInterface
;
1023 CFMutableDictionaryRef dict
;
1027 dict
= CFDictionaryCreateMutable(NULL
, 0,
1028 &kCFTypeDictionaryKeyCallBacks
,
1029 &kCFTypeDictionaryValueCallBacks
);
1030 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1031 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommand
), num
);
1033 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1034 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1035 kr
= IOConnectSetCFProperties(connect
, dict
);
1040 static SCNetworkInterfaceRef
1041 lookupIOKitPath(CFStringRef if_path
)
1043 io_registry_entry_t entry
= MACH_PORT_NULL
;
1044 SCNetworkInterfaceRef interface
= NULL
;
1046 mach_port_t masterPort
= MACH_PORT_NULL
;
1049 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1050 if (kr
!= KERN_SUCCESS
) {
1051 SCLog(TRUE
, LOG_ERR
,
1052 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x\n"),
1056 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1057 entry
= IORegistryEntryFromPath(masterPort
, path
);
1058 if (entry
== MACH_PORT_NULL
) {
1059 SCLog(TRUE
, LOG_ERR
,
1060 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryFromPath(%@) failed"),
1065 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1068 if (masterPort
!= MACH_PORT_NULL
) {
1069 mach_port_deallocate(mach_task_self(), masterPort
);
1071 if (entry
!= MACH_PORT_NULL
) {
1072 IOObjectRelease(entry
);
1079 displayInterface(SCNetworkInterfaceRef interface
)
1086 name
= SCNetworkInterfaceGetBSDName(interface
);
1087 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1088 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1089 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1091 SCLog(TRUE
, LOG_INFO
,
1092 CFSTR(MY_PLUGIN_NAME
": %s%@%sType: %@, %s%@%sMAC address: %@"),
1093 (name
!= NULL
) ? "BSD Name: " : "",
1094 (name
!= NULL
) ? name
: CFSTR(""),
1095 (name
!= NULL
) ? ", " : "",
1097 (unit
!= NULL
) ? "Unit: " : "",
1098 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1099 (unit
!= NULL
) ? ", " : "",
1104 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
1109 for (i
= 0; i
< last
; i
++) {
1110 SCNetworkInterfaceRef builtin_if
;
1111 CFNumberRef builtin_type
;
1113 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1114 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
1115 if (CFEqual(if_type
, builtin_type
)) {
1116 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1117 n
++; // if built-in interface
1125 static __inline__ boolean_t
1128 return (S_quiet
== MACH_PORT_NULL
);
1132 nameInterfaces(CFMutableArrayRef if_list
)
1135 CFIndex n
= CFArrayGetCount(if_list
);
1137 for (i
= 0; i
< n
; i
++) {
1138 SCNetworkInterfaceRef interface
;
1144 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1145 path
= _SCNetworkInterfaceGetIOPath(interface
);
1146 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1147 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1151 CFStringRef if_name
;
1153 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1154 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
1155 SCLog(TRUE
, LOG_INFO
,
1156 CFSTR(MY_PLUGIN_NAME
": Interface already has a unit number"));
1157 displayInterface(interface
);
1161 // update the list of interfaces that were previously named
1162 if ((S_prev_active_list
!= NULL
)
1163 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
1164 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1167 CFDictionaryRef dbdict
;
1168 boolean_t is_builtin
;
1171 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
1172 if (dbdict
!= NULL
) {
1173 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1176 SCLog(S_debug
, LOG_INFO
,
1177 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (from database)"),
1181 if ((dbdict
== NULL
) && !isQuiet()) {
1182 // if new interface, wait until quiet before naming
1183 addTimestamp(S_state
, path
);
1187 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
1189 if (dbdict
== NULL
) {
1190 dbdict
= lookupMatchingInterface(interface
,
1194 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
1195 if (dbdict
!= NULL
) {
1196 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1199 SCLog(S_debug
, LOG_INFO
,
1200 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (updating database)"),
1205 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
1206 // update the list of interfaces that were previously named
1207 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
1208 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
1210 if (where
!= kCFNotFound
) {
1211 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1215 if (dbdict
== NULL
) {
1219 // built-in interface, use the reserved slots
1220 next_unit
= builtinCount(if_list
, i
, type
);
1222 // not built-in, skip over the reserved slots
1223 next_unit
= builtinCount(if_list
, n
, type
);
1225 unit
= getHighestUnitForType(type
);
1229 CFNumberGetValue(unit
, kCFNumberIntType
, &high_unit
);
1230 if (high_unit
>= next_unit
) {
1231 next_unit
= high_unit
+ 1;
1235 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1237 SCLog(S_debug
, LOG_INFO
,
1238 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (%s)"),
1240 is_builtin
? "built-in" : "next available");
1243 kr
= registerInterface(S_connect
, path
, unit
);
1244 if (kr
!= KERN_SUCCESS
) {
1245 SCLog(TRUE
, LOG_ERR
,
1246 CFSTR(MY_PLUGIN_NAME
": failed to name the interface, kr=0x%x\n"
1247 MY_PLUGIN_NAME
": path = %@\n"
1248 MY_PLUGIN_NAME
": unit = %@"),
1253 displayInterface(interface
);
1256 SCNetworkInterfaceRef new_interface
;
1258 new_interface
= lookupIOKitPath(path
);
1259 if (new_interface
!= NULL
) {
1260 CFNumberRef new_unit
;
1262 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
1263 if (CFEqual(unit
, new_unit
) == FALSE
) {
1264 SCLog(S_debug
, LOG_INFO
,
1265 CFSTR(MY_PLUGIN_NAME
1266 ": interface type %@ assigned "
1267 "unit %@ instead of %@"),
1268 type
, new_unit
, unit
);
1271 displayInterface(new_interface
);
1274 // update if_list (with the interface name & unit)
1275 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
1276 CFRelease(new_interface
);
1277 interface
= new_interface
; // if_list holds the reference
1279 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
1282 // update the list of [built-in] interfaces that were previously named
1283 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
1284 SCLog(S_debug
, LOG_INFO
,
1285 CFSTR(MY_PLUGIN_NAME
": and updated database (new address)"));
1286 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1296 replaceInterface(interface
);
1304 if (S_connect
== MACH_PORT_NULL
) {
1305 // if we don't have the "IONetworkStack" connect object
1309 if (S_iflist
!= NULL
) {
1312 n
= CFArrayGetCount(S_iflist
);
1314 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
1316 nameInterfaces(S_iflist
);
1321 * The registry [matching] has quiesced so let's
1322 * - save the DB with the interfaces that have been named
1323 * - update the VLAN/BOND configuration
1324 * - tell everyone that we've finished (at least for now)
1325 * - log those interfaces which are no longer present
1326 * in the HW config (or have yet to show up).
1328 writeInterfaceList(S_dblist
);
1329 #if !TARGET_OS_IPHONE
1330 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
1331 #endif /* !TARGET_OS_IPHONE */
1334 if (S_iflist
!= NULL
) {
1335 CFRelease(S_iflist
);
1339 if (S_prev_active_list
!= NULL
) {
1344 n
= CFArrayGetCount(S_prev_active_list
);
1346 SCLog(TRUE
, LOG_INFO
,
1347 CFSTR(MY_PLUGIN_NAME
": Interface%s not [yet] active"),
1348 (n
> 1) ? "s" : "");
1350 for (i
= 0; i
< n
; i
++) {
1351 CFDictionaryRef if_dict
;
1356 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
1357 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
1358 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
1359 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
1360 SCLog(TRUE
, LOG_INFO
,
1361 CFSTR(MY_PLUGIN_NAME
": %s%@%sType: %@, Unit: %@"),
1362 (name
!= NULL
) ? "BSD Name: " : "",
1363 (name
!= NULL
) ? name
: CFSTR(""),
1364 (name
!= NULL
) ? ", " : "",
1369 CFRelease(S_prev_active_list
);
1370 S_prev_active_list
= NULL
;
1373 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
1375 * if we've named all of the interfaces that
1376 * were used during the previous boot.
1378 addTimestamp(S_state
, CFSTR("*RELEASE*"));
1379 SCLog(S_debug
, LOG_INFO
,
1380 CFSTR(MY_PLUGIN_NAME
": last boot interfaces have been named"));
1382 CFRelease(S_prev_active_list
);
1383 S_prev_active_list
= NULL
;
1390 static CFComparisonResult
1391 compareMacAddress(const void *val1
, const void *val2
, void *context
)
1393 CFDataRef mac1
= (CFDataRef
)val1
;
1394 CFDataRef mac2
= (CFDataRef
)val2
;
1397 CFComparisonResult res
;
1399 n1
= CFDataGetLength(mac1
);
1400 n2
= CFDataGetLength(mac2
);
1402 res
= kCFCompareLessThan
;
1403 } else if (n2
> n1
) {
1404 res
= kCFCompareGreaterThan
;
1406 res
= bcmp(CFDataGetBytePtr(mac1
), CFDataGetBytePtr(mac2
), n1
);
1412 #ifndef kIOPlatformUUIDKey
1413 #define kIOPlatformUUIDKey "IOPlatformUUID"
1416 updatePlatformUUID()
1419 CFMutableArrayRef addrs
= NULL
;
1423 io_registry_entry_t platform
;
1425 platform
= IORegistryEntryFromPath(kIOMasterPortDefault
, kIODeviceTreePlane
":/");
1426 if (platform
== MACH_PORT_NULL
) {
1430 guid
= IORegistryEntryCreateCFProperty(platform
, CFSTR(kIOPlatformUUIDKey
), NULL
, 0);
1432 // if GUID already defined
1436 addrs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1437 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1438 for (i
= 0; i
< n
; i
++) {
1439 CFBooleanRef builtin
;
1440 CFDictionaryRef dict
;
1443 dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1444 type
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceType
));
1445 if (!isA_CFString(type
) || !CFEqual(type
, kSCNetworkInterfaceTypeEthernet
)) {
1448 builtin
= CFDictionaryGetValue(dict
, CFSTR(kIOBuiltin
));
1449 if (!isA_CFBoolean(builtin
) || !CFBooleanGetValue(builtin
)) {
1452 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
1453 if (!isA_CFData(addr
) || (CFDataGetLength(addr
) != ETHER_ADDR_LEN
)) {
1456 CFArrayAppendValue(addrs
, addr
);
1459 if (CFArrayGetCount(addrs
) == 0) {
1460 // if no ethernet interfaces, look for wireless
1461 for (i
= 0; i
< n
; i
++) {
1462 CFDictionaryRef dict
;
1465 dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1466 type
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceType
));
1467 if (!isA_CFString(type
) || !CFEqual(type
, kSCNetworkInterfaceTypeIEEE80211
)) {
1470 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
1471 if (!isA_CFData(addr
) || (CFDataGetLength(addr
) != ETHER_ADDR_LEN
)) {
1474 CFArrayAppendValue(addrs
, addr
);
1478 n
= CFArrayGetCount(addrs
);
1481 SCLog(TRUE
, LOG_ERR
,
1482 CFSTR(MY_PLUGIN_NAME
": no network interfaces, could not update platform UUID"));
1485 // sort by MAC address
1486 CFArraySortValues(addrs
, CFRangeMake(0, n
), compareMacAddress
, NULL
);
1490 CFUUIDBytes bytes
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1491 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1496 addr
= CFArrayGetValueAtIndex(addrs
, 0);
1497 bcopy(CFDataGetBytePtr(addr
),
1498 (void *)&bytes
+ sizeof(bytes
) - ETHER_ADDR_LEN
,
1500 uuid
= CFUUIDCreateFromUUIDBytes(NULL
, bytes
);
1501 guid
= CFUUIDCreateString(NULL
, uuid
);
1504 SCLog(TRUE
, LOG_INFO
,
1505 CFSTR(MY_PLUGIN_NAME
": setting platform UUID = %@"),
1507 kr
= IORegistryEntrySetCFProperty(platform
, CFSTR(kIOPlatformUUIDKey
), guid
);
1508 if (kr
!= KERN_SUCCESS
) {
1509 SCLog(TRUE
, LOG_ERR
,
1510 CFSTR(MY_PLUGIN_NAME
": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"),
1514 addTimestamp(S_state
, CFSTR("*PLATFORM-UUID*"));
1522 if (addrs
!= NULL
) CFRelease(addrs
);
1523 if (platform
!= MACH_PORT_NULL
) IOObjectRelease(platform
);
1524 if (guid
!= NULL
) CFRelease(guid
);
1529 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
1533 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
1534 SCNetworkInterfaceRef interface
;
1536 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
1537 if (interface
!= NULL
) {
1538 if (S_iflist
== NULL
) {
1539 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1541 CFArrayAppendValue(S_iflist
, interface
);
1542 CFRelease(interface
);
1544 IOObjectRelease(obj
);
1552 * Function: stackCallback
1554 * Get a reference to the single IONetworkStack object instance in
1555 * the kernel. Naming requests must be sent to this object, which is
1556 * attached as a client to all network interface objects in the system.
1558 * Call IOObjectRelease on the returned object.
1561 stackCallback(void *refcon
, io_iterator_t iter
)
1566 stack
= IOIteratorNext(iter
);
1567 if (stack
== MACH_PORT_NULL
) {
1571 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
1572 if (kr
!= KERN_SUCCESS
) {
1573 SCLog(TRUE
, LOG_ERR
,
1574 CFSTR(MY_PLUGIN_NAME
": IOServiceOpen returned 0x%x"),
1579 addTimestamp(S_state
, CFSTR("*STACK*"));
1580 SCLog(S_debug
, LOG_INFO
,
1581 CFSTR(MY_PLUGIN_NAME
": IONetworkStack found"));
1583 if (S_stack
!= MACH_PORT_NULL
) {
1584 IOObjectRelease(S_stack
);
1585 S_stack
= MACH_PORT_NULL
;
1591 if (stack
!= MACH_PORT_NULL
) {
1592 IOObjectRelease(stack
);
1599 quietCallback(void *refcon
,
1600 io_service_t service
,
1601 natural_t messageType
,
1602 void *messageArgument
)
1604 if (messageArgument
!= NULL
) {
1609 if (messageType
== kIOMessageServiceBusyStateChange
) {
1610 addTimestamp(S_state
, CFSTR("*QUIET*"));
1611 SCLog(S_debug
, LOG_INFO
,
1612 CFSTR(MY_PLUGIN_NAME
": IOKit quiet"));
1615 if (S_connect
== MACH_PORT_NULL
) {
1616 SCLog(TRUE
, LOG_ERR
,
1617 CFSTR(MY_PLUGIN_NAME
": No network stack object"));
1621 if (S_quiet
!= MACH_PORT_NULL
) {
1622 IOObjectRelease(S_quiet
);
1623 S_quiet
= MACH_PORT_NULL
;
1626 if (S_timer
!= NULL
) {
1627 CFRunLoopTimerInvalidate(S_timer
);
1632 // grab (and name) any additional interfaces.
1633 interfaceArrivalCallback((void *)S_notify
, S_iter
);
1635 updatePlatformUUID();
1641 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, int *count
)
1643 kern_return_t kr
= kIOReturnSuccess
;;
1646 while ((kr
== kIOReturnSuccess
) &&
1647 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
1651 CFMutableArrayRef newNodes
;
1652 CFMutableStringRef str
= NULL
;
1654 if (nodes
== NULL
) {
1655 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1657 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
1660 kr
= IORegistryEntryGetName(obj
, name
);
1661 if (kr
!= kIOReturnSuccess
) {
1662 SCLog(TRUE
, LOG_ERR
,
1663 CFSTR(MY_PLUGIN_NAME
": reportBusy IORegistryEntryGetName returned 0x%x"),
1668 str
= CFStringCreateMutable(NULL
, 0);
1669 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
1671 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
1673 case kIOReturnSuccess
:
1674 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
1675 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
1677 case kIOReturnNotFound
:
1680 SCLog(TRUE
, LOG_ERR
,
1681 CFSTR(MY_PLUGIN_NAME
": reportBusy IORegistryEntryGetLocationInPlane returned 0x%x"),
1687 CFArrayAppendValue(newNodes
, str
);
1690 kr
= IOServiceGetBusyState(obj
, &busy
);
1691 if (kr
!= kIOReturnSuccess
) {
1692 SCLog(TRUE
, LOG_ERR
,
1693 CFSTR(MY_PLUGIN_NAME
": reportBusy IOServiceGetBusyState returned 0x%x"),
1701 if ((*count
)++ == 0) {
1702 SCLog(TRUE
, LOG_WARNING
, CFSTR(MY_PLUGIN_NAME
": Busy services :"));
1705 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
1706 SCLog(TRUE
, LOG_WARNING
, CFSTR(MY_PLUGIN_NAME
": %@ [%d]"), path
, busy
);
1710 kr
= IORegistryIteratorEnterEntry(iterator
);
1711 if (kr
!= kIOReturnSuccess
) {
1712 SCLog(TRUE
, LOG_ERR
,
1713 CFSTR(MY_PLUGIN_NAME
": reportBusy IORegistryIteratorEnterEntry returned 0x%x"),
1718 iterateRegistryBusy(iterator
, newNodes
, count
);
1720 kr
= IORegistryIteratorExitEntry(iterator
);
1721 if (kr
!= kIOReturnSuccess
) {
1722 SCLog(TRUE
, LOG_ERR
,
1723 CFSTR(MY_PLUGIN_NAME
": reportBusy IORegistryIteratorExitEntry returned 0x%x"),
1729 CFRelease(newNodes
);
1730 IOObjectRelease(obj
);
1740 io_iterator_t iterator
= MACH_PORT_NULL
;
1743 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
1747 if (kr
!= kIOReturnSuccess
) {
1748 SCLog(TRUE
, LOG_ERR
,
1749 CFSTR(MY_PLUGIN_NAME
": reportBusy IORegistryCreateIterator returned 0x%x"),
1754 iterateRegistryBusy(iterator
, NULL
, &count
);
1755 SCLog((count
== 0), LOG_WARNING
,
1756 CFSTR(MY_PLUGIN_NAME
": w/no busy services"));
1757 IOObjectRelease(iterator
);
1762 timerCallback(CFRunLoopTimerRef timer
, void *info
)
1765 * We've been waiting for IOKit to quiesce and it just
1766 * hasn't happenned. Time to just move on!
1768 addTimestamp(S_state
, CFSTR("*TIMEOUT*"));
1769 SCLog(TRUE
, LOG_ERR
,
1770 CFSTR(MY_PLUGIN_NAME
": timed out waiting for IOKit to quiesce"));
1773 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
1778 setup_IOKit(CFBundleRef bundle
)
1781 CFDictionaryRef dict
;
1783 mach_port_t masterPort
= MACH_PORT_NULL
;
1785 io_object_t root
= MACH_PORT_NULL
;
1786 double timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
1788 // read DB of previously named network interfaces
1789 S_dblist
= readInterfaceList();
1790 if (S_dblist
!= NULL
) {
1793 n
= CFArrayGetCount(S_dblist
);
1795 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
1799 // get interfaces that were named during the last boot
1800 S_prev_active_list
= previouslyActiveInterfaces();
1802 // track how long we've waited to see each interface.
1803 S_state
= CFDictionaryCreateMutable(NULL
,
1805 &kCFTypeDictionaryKeyCallBacks
,
1806 &kCFTypeDictionaryValueCallBacks
);
1807 addTimestamp(S_state
, CFSTR("*START*"));
1809 // Creates and returns a notification object for receiving IOKit
1810 // notifications of new devices or state changes.
1811 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1812 if (kr
!= KERN_SUCCESS
) {
1813 SCLog(TRUE
, LOG_ERR
,
1814 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x"),
1819 S_notify
= IONotificationPortCreate(masterPort
);
1820 if (S_notify
== NULL
) {
1821 SCLog(TRUE
, LOG_ERR
,
1822 CFSTR(MY_PLUGIN_NAME
": IONotificationPortCreate failed"));
1826 // watch IOKit matching activity
1827 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
1828 if (root
== MACH_PORT_NULL
) {
1829 SCLog(TRUE
, LOG_ERR
,
1830 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryFromPath failed"));
1834 kr
= IOServiceAddInterestNotification(S_notify
,
1838 (void *)S_notify
, // refCon
1839 &S_quiet
); // notification
1840 if (kr
!= KERN_SUCCESS
) {
1841 SCLog(TRUE
, LOG_ERR
,
1842 CFSTR(MY_PLUGIN_NAME
": IOServiceAddInterestNotification returned 0x%x"),
1847 kr
= IOServiceGetBusyState(root
, &busy
);
1848 if (kr
!= KERN_SUCCESS
) {
1849 SCLog(TRUE
, LOG_ERR
,
1850 CFSTR(MY_PLUGIN_NAME
": IOServiceGetBusyState returned 0x%x"),
1855 // add a timer so we don't wait forever for IOKit to quiesce
1856 dict
= CFBundleGetInfoDictionary(bundle
);
1857 if (isA_CFDictionary(dict
)) {
1860 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
1862 if (!isA_CFNumber(num
) ||
1863 !CFNumberGetValue(num
, kCFNumberDoubleType
, &timeout
) ||
1865 SCLog(TRUE
, LOG_ERR
,
1866 CFSTR(MY_PLUGIN_NAME
": " WAIT_QUIET_TIMEOUT_KEY
" value error"));
1867 timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
1871 S_timer
= CFRunLoopTimerCreate(NULL
,
1872 CFAbsoluteTimeGetCurrent() + timeout
,
1878 if (S_timer
== NULL
) {
1879 SCLog(TRUE
, LOG_ERR
,
1880 CFSTR(MY_PLUGIN_NAME
": CFRunLoopTimerCreate failed"));
1884 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
1886 // watch for the introduction of the IONetworkStack
1887 kr
= IOServiceAddMatchingNotification(S_notify
,
1888 kIOFirstMatchNotification
,
1889 IOServiceMatching("IONetworkStack"),
1891 (void *)S_notify
, // refCon
1892 &S_stack
); // notification
1893 if (kr
!= KERN_SUCCESS
) {
1894 SCLog(TRUE
, LOG_ERR
,
1895 CFSTR(MY_PLUGIN_NAME
": IOServiceAddMatchingNotification returned 0x%x"),
1900 // check and see if the stack is already available and arm the
1901 // notification for its introduction.
1902 stackCallback((void *)S_notify
, S_stack
);
1904 // watch for the introduction of new network interfaces
1905 kr
= IOServiceAddMatchingNotification(S_notify
,
1906 kIOFirstMatchNotification
,
1907 IOServiceMatching("IONetworkInterface"),
1908 &interfaceArrivalCallback
,
1909 (void *)S_notify
, // refCon
1910 &S_iter
); // notification
1911 if (kr
!= KERN_SUCCESS
) {
1912 SCLog(TRUE
, LOG_ERR
,
1913 CFSTR(MY_PLUGIN_NAME
": IOServiceAddMatchingNotification returned 0x%x"),
1918 // Get the current list of matches and arm the notification for
1919 // future interface arrivals.
1920 interfaceArrivalCallback((void *)S_notify
, S_iter
);
1922 // Check if IOKit has already quiesced.
1923 quietCallback((void *)S_notify
,
1925 kIOMessageServiceBusyStateChange
,
1926 (void *)(uintptr_t)busy
);
1928 CFRunLoopAddSource(CFRunLoopGetCurrent(),
1929 IONotificationPortGetRunLoopSource(S_notify
),
1930 kCFRunLoopDefaultMode
);
1932 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
1934 * Start the wheels turning until we've named all of
1935 * the interfaces that were used during the previous
1936 * boot, until IOKit [matching] has quiesced, or
1937 * until we've waited long enough.
1939 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
1940 CFRunLoopAddSource(CFRunLoopGetCurrent(),
1941 IONotificationPortGetRunLoopSource(S_notify
),
1943 while (S_prev_active_list
!= NULL
) {
1946 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
1948 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
1953 if (root
!= MACH_PORT_NULL
) {
1954 IOObjectRelease(root
);
1956 if (masterPort
!= MACH_PORT_NULL
) {
1957 mach_port_deallocate(mach_task_self(), masterPort
);
1963 #if !TARGET_OS_IPHONE
1965 setup_Virtual(CFBundleRef bundle
)
1967 // open a SCPreferences session
1968 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
);
1969 if (S_prefs
== NULL
) {
1970 SCLog(TRUE
, LOG_ERR
,
1971 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate() failed: %s"),
1972 SCErrorString(SCError()));
1976 // register for change notifications.
1977 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
1978 SCLog(TRUE
, LOG_ERR
,
1979 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetCallBack() failed: %s"),
1980 SCErrorString(SCError()));
1986 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
1987 if (SCError() != kSCStatusNoStoreServer
) {
1988 SCLog(TRUE
, LOG_ERR
,
1989 CFSTR(MY_PLUGIN_NAME
": SCPreferencesScheduleWithRunLoop() failed: %s"),
1990 SCErrorString(SCError()));
1998 #endif /* !TARGET_OS_IPHONE */
2002 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
2004 if (bundleVerbose
) {
2008 #if !TARGET_OS_IPHONE
2009 // setup virtual network interface monitoring
2010 if (!setup_Virtual(bundle
)) {
2013 #endif /* !TARGET_OS_IPHONE */
2015 // setup [IOKit] network interface monitoring
2016 if (!setup_IOKit(bundle
)) {
2023 if (S_connect
!= MACH_PORT_NULL
) {
2024 IOServiceClose(S_connect
);
2025 S_connect
= MACH_PORT_NULL
;
2027 if (S_dblist
!= NULL
) {
2028 CFRelease(S_dblist
);
2031 if (S_iter
!= MACH_PORT_NULL
) {
2032 IOObjectRelease(S_iter
);
2033 S_iter
= MACH_PORT_NULL
;
2035 if (S_notify
!= MACH_PORT_NULL
) {
2036 IONotificationPortDestroy(S_notify
);
2038 if (S_quiet
!= MACH_PORT_NULL
) {
2039 IOObjectRelease(S_quiet
);
2040 S_quiet
= MACH_PORT_NULL
;
2042 if (S_stack
!= MACH_PORT_NULL
) {
2043 IOObjectRelease(S_stack
);
2044 S_stack
= MACH_PORT_NULL
;
2046 if (S_state
!= NULL
) {
2050 if (S_timer
!= NULL
) {
2051 CFRunLoopTimerInvalidate(S_timer
);
2059 //------------------------------------------------------------------------
2063 main(int argc
, char ** argv
)
2066 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2068 load_InterfaceNamer(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);
2076 #ifdef TEST_PLATFORM_UUID
2078 main(int argc
, char ** argv
)
2080 CFArrayRef interfaces
;
2083 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2085 S_dblist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2086 interfaces
= SCNetworkInterfaceCopyAll();
2087 if (interfaces
!= NULL
) {
2091 n
= CFArrayGetCount(interfaces
);
2092 for (i
= 0; i
< n
; i
++) {
2093 CFDictionaryRef dict
;
2094 SCNetworkInterfaceRef interface
;
2096 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2097 dict
= createInterfaceDict(interface
);
2098 CFArrayAppendValue(S_dblist
, dict
);
2101 CFRelease(interfaces
);
2103 updatePlatformUUID();
2104 CFRelease(S_dblist
);
2108 #endif /* TEST_PLATFORM_UUID */