2 * Copyright (c) 2001-2017 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 * May 20, 2006 Joe Liu <joe.liu@apple.com>
28 * Allan Nathanson <ajn@apple.com>
29 * - register interface by entryID (and not path)
31 * November 6, 2006 Allan Nathanson <ajn@apple.com>
32 * Dan Markarian <markarian@apple.com>
33 * Dieter Siegmund <dieter@apple.com>
34 * - updated code to name interfaces quicker (without need for
35 * calling IOKitWaitQuiet).
37 * October 3, 2003 Allan Nathanson <ajn@apple.com>
38 * - sort new interfaces by IOKit path (rather than MAC address) to
39 * help facilitate a more predictable interface-->name mapping for
40 * like hardware configurations.
42 * June 23, 2001 Allan Nathanson <ajn@apple.com>
43 * - update to public SystemConfiguration.framework APIs
45 * January 23, 2001 Dieter Siegmund <dieter@apple.com>
51 * - module that receives IOKit Network Interface messages
52 * and names any interface that currently does not have a name
53 * - uses Interface Type and MACAddress as the unique identifying
54 * keys; any interface that doesn't contain both of these properties
55 * is ignored and not processed
56 * - stores the Interface Type, MACAddress, and Unit in permanent storage
57 * to give persistent interface names
65 #include <sys/ioctl.h>
67 #include <sys/sysctl.h>
68 #include <sys/param.h>
69 #include <mach/mach.h>
70 #include <net/ethernet.h>
71 #include <net/if_types.h>
74 #include <CommonCrypto/CommonDigest.h>
76 #include <CoreFoundation/CoreFoundation.h>
78 #define SC_LOG_HANDLE __log_InterfaceNamer()
79 #include <SystemConfiguration/SystemConfiguration.h>
80 #include <SystemConfiguration/SCDPlugin.h>
81 #include <SystemConfiguration/SCPrivate.h>
82 #include <SystemConfiguration/SCValidation.h>
83 #include "plugin_shared.h"
85 #include "InterfaceNamerControlPrefs.h"
86 #endif // !TARGET_OS_IPHONE
88 #include <IOKit/IOKitLib.h>
89 #include <IOKit/IOKitLibPrivate.h>
90 #include <IOKit/IOKitKeysPrivate.h>
91 #include <IOKit/IOBSD.h>
92 #include <IOKit/IOMessage.h>
93 #include <IOKit/network/IONetworkController.h>
94 #include <IOKit/network/IONetworkInterface.h>
95 #include <IOKit/network/IONetworkStack.h>
96 #include <IOKit/usb/USB.h>
98 #ifdef kIONetworkStackUserCommandKey
99 #define USE_REGISTRY_ENTRY_ID
102 #ifndef USE_REGISTRY_ENTRY_ID
103 // from <IOKit/network/IONetworkStack.h>
104 #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand"
106 kRegisterInterfaceWithFixedUnit
= 0,
108 kRegisterAllInterfaces
110 #endif // !USE_REGISTRY_ENTRY_ID
112 #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo"
113 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
114 #define kSCNetworkInterfaceActive "Active"
116 #define MY_PLUGIN_NAME "InterfaceNamer"
117 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
119 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
120 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
122 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
123 #define WAIT_QUIET_TIMEOUT_DEFAULT 60.0
127 * "IONetworkStack" connect object used to "name" an interface.
129 static io_connect_t S_connect
= MACH_PORT_NULL
;
133 * An array of CFDictionary's representing the interfaces
134 * that have been identified and [need to be] named.
136 static CFMutableArrayRef S_dblist
= NULL
;
140 * An array of SCNetworkInterface's representing the
141 * interfaces that have been identified.
143 static CFMutableArrayRef S_iflist
= NULL
;
147 * IOServiceAddMatchingNotification object used to watch for
148 * new network interfaces.
150 static io_iterator_t S_iter
= MACH_PORT_NULL
;
154 * notification object for receiving IOKit notifications of
155 * new devices or state changes.
157 static IONotificationPortRef S_notify
= NULL
;
159 /* S_prev_active_list
160 * An array of CFDictionary's representing the previously
163 static CFMutableArrayRef S_prev_active_list
= NULL
;
167 * IOServiceAddInterestNotification object used to watch for
168 * IOKit matching to quiesce.
170 static io_object_t S_quiet
= MACH_PORT_NULL
;
174 * IOServiceAddMatchingNotification object used to watch for
175 * the availability of the "IONetworkStack" object.
177 static io_iterator_t S_stack
= MACH_PORT_NULL
;
181 * A dictionary containing Information about each network
182 * interface. For now, the key is the BSD name and the
183 * value is a CFNumber noting how long (in milliseconds)
184 * it took for the interface to be recognized/named.
186 static CFMutableDictionaryRef S_state
= NULL
;
190 * CFRunLoopTimer tracking how long we are willing to wait
191 * for IOKit matching to quiesce (IOKitWaitQuiet).
194 * time to wait for the IONetworkStack object to appear before timeout
197 * time to wait for the IOKit to quiesce (after the IONetworkStack is
200 static CFRunLoopTimerRef S_timer
= NULL
;
201 static double S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
202 static double S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
205 * Virtual network interface configuration
206 * S_prefs : SCPreferences to configuration
207 * S_bonds : most recently actived Bond configuration
208 * S_bridges : most recently actived Bridge configuration
209 * S_vlans : most recently actived VLAN configuration
211 static SCPreferencesRef S_prefs
= NULL
;
212 static CFArrayRef S_bonds
= NULL
;
213 static CFArrayRef S_bridges
= NULL
;
214 static CFArrayRef S_vlans
= NULL
;
220 __log_InterfaceNamer()
222 static os_log_t log
= NULL
;
225 log
= os_log_create("com.apple.SystemConfiguration", "InterfaceNamer");
233 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
238 now
= CFAbsoluteTimeGetCurrent();
239 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
240 CFDictionaryAddValue(dict
, key
, val
);
245 #define INTERFACES CFSTR("Interfaces")
246 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
248 static CFComparisonResult
249 if_unit_compare(const void *val1
, const void *val2
, void *context
)
251 CFComparisonResult res
;
257 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
258 CFSTR(kIOInterfaceType
));
259 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
260 CFSTR(kIOInterfaceType
));
261 res
= CFNumberCompare(type1
, type2
, NULL
);
262 if (res
!= kCFCompareEqualTo
) {
265 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
266 CFSTR(kIOInterfaceUnit
));
267 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
268 CFSTR(kIOInterfaceUnit
));
269 return (CFNumberCompare(unit1
, unit2
, NULL
));
273 writeInterfaceList(CFArrayRef if_list
)
276 CFStringRef new_model
;
277 CFStringRef old_model
;
278 SCPreferencesRef prefs
;
280 if (isA_CFArray(if_list
) == NULL
) {
284 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
286 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
290 cur_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
291 if (_SC_CFEqual(cur_list
, if_list
)) {
295 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
296 new_model
= _SC_hw_model(FALSE
);
297 if ((new_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
299 if ((old_model
!= NULL
) && (cur_list
!= NULL
)) {
302 // if interface list was created on other hardware
303 history
= CFStringCreateWithFormat(NULL
, NULL
,
307 SCPreferencesSetValue(prefs
, history
, cur_list
);
310 SC_log(LOG_NOTICE
, "Hardware model changed\n"
311 " created on \"%@\"\n"
317 SCPreferencesSetValue(prefs
, MODEL
, new_model
);
320 SCPreferencesSetValue(prefs
, INTERFACES
, if_list
);
322 if (!SCPreferencesCommitChanges(prefs
)) {
323 if (SCError() != EROFS
) {
324 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
335 static CFPropertyListRef
336 restoreNIPrefsFromBackup(SCPreferencesRef prefs
, CFStringRef current_model
)
338 CFPropertyListRef if_list
;
341 key
= CFStringCreateWithFormat(NULL
, 0, CFSTR("%@:%@"), INTERFACES
, current_model
);
342 if_list
= SCPreferencesGetValue(prefs
, key
);
343 if_list
= isA_CFArray(if_list
);
344 if (if_list
!= NULL
) {
345 /* Write the previously backed up Interface list for this hardware */
346 writeInterfaceList(if_list
);
348 /* Synchronize the prefs */
349 SCPreferencesSynchronize(prefs
);
351 /* Re-fetch the interface list */
352 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
353 if_list
= isA_CFArray(if_list
);
354 if (if_list
!= NULL
) {
355 /* We do not need the old interface list any more */
356 SCPreferencesRemoveValue(prefs
, key
);
357 if (!SCPreferencesCommitChanges(prefs
)) {
358 if (SCError() != EROFS
) {
359 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
370 static CF_RETURNS_RETAINED CFMutableArrayRef
374 CFStringRef old_model
;
375 CFMutableArrayRef plist
= NULL
;
376 SCPreferencesRef prefs
= NULL
;
378 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
380 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
384 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
385 if_list
= isA_CFArray(if_list
);
387 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
388 if (old_model
!= NULL
) {
389 CFStringRef new_model
;
391 new_model
= _SC_hw_model(FALSE
);
392 if (!_SC_CFEqual(old_model
, new_model
)) {
393 /* if interface list was created on other hardware,
394 Restore if a backup interface list is present */
395 if_list
= restoreNIPrefsFromBackup(prefs
, new_model
);
399 if (if_list
!= NULL
) {
401 CFIndex n
= CFArrayGetCount(if_list
);
403 plist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
404 for (i
= 0; i
< n
; i
++) {
405 CFDictionaryRef dict
;
407 dict
= CFArrayGetValueAtIndex(if_list
, i
);
408 if (isA_CFDictionary(dict
) &&
409 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceType
)) &&
410 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
411 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
412 CFArrayAppendValue(plist
, dict
);
423 static CF_RETURNS_RETAINED CFMutableArrayRef
424 previouslyActiveInterfaces()
426 CFMutableArrayRef active
;
430 if (S_dblist
== NULL
) {
434 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
436 n
= CFArrayGetCount(S_dblist
);
437 for (i
= 0; i
< n
; i
++) {
438 CFDictionaryRef if_dict
;
440 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
441 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
442 CFMutableDictionaryRef new_dict
;
444 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
445 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
446 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
447 CFArrayAppendValue(active
, new_dict
);
460 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
),
461 kSCDynamicStoreDomainPlugin
);
462 (void)SCDynamicStoreSetValue(NULL
, key
, S_state
);
468 #if !TARGET_OS_IPHONE
470 updateBondInterfaceConfiguration(SCPreferencesRef prefs
)
472 CFArrayRef interfaces
;
474 interfaces
= SCBondInterfaceCopyAll(prefs
);
475 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
476 CFRelease(interfaces
);
480 if (_SC_CFEqual(S_bonds
, interfaces
)) {
482 if (interfaces
!= NULL
) CFRelease(interfaces
);
486 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
487 S_bonds
= interfaces
;
489 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
490 SC_log(LOG_NOTICE
, "_SCBondInterfaceUpdateConfiguration() failed: %s",
491 SCErrorString(SCError()));
496 #endif // !TARGET_OS_IPHONE
499 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs
)
501 CFArrayRef interfaces
;
503 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
504 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
505 CFRelease(interfaces
);
509 if (_SC_CFEqual(S_bridges
, interfaces
)) {
511 if (interfaces
!= NULL
) CFRelease(interfaces
);
515 if (S_bridges
!= NULL
) CFRelease(S_bridges
);
516 S_bridges
= interfaces
;
518 if (!_SCBridgeInterfaceUpdateConfiguration(prefs
)) {
519 SC_log(LOG_NOTICE
, "_SCBridgeInterfaceUpdateConfiguration() failed: %s",
520 SCErrorString(SCError()));
527 updateVLANInterfaceConfiguration(SCPreferencesRef prefs
)
529 CFArrayRef interfaces
;
531 interfaces
= SCVLANInterfaceCopyAll(prefs
);
532 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
533 CFRelease(interfaces
);
537 if (_SC_CFEqual(S_vlans
, interfaces
)) {
539 if (interfaces
!= NULL
) CFRelease(interfaces
);
543 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
544 S_vlans
= interfaces
;
546 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
547 SC_log(LOG_NOTICE
, "_SCVLANInterfaceUpdateConfiguration() failed: %s",
548 SCErrorString(SCError()));
555 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
556 SCPreferencesNotification notificationType
,
559 os_activity_t activity
;
561 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
565 activity
= os_activity_create("check/update virtual network interface configuration",
567 OS_ACTIVITY_FLAG_DEFAULT
);
568 os_activity_scope(activity
);
571 // if a new interface has been "named"
573 if (S_bonds
!= NULL
) {
577 if (S_bridges
!= NULL
) {
578 CFRelease(S_bridges
);
581 if (S_vlans
!= NULL
) {
587 #if !TARGET_OS_IPHONE
588 updateBondInterfaceConfiguration (prefs
);
589 #endif // !TARGET_OS_IPHONE
590 updateBridgeInterfaceConfiguration(prefs
);
591 updateVLANInterfaceConfiguration (prefs
);
593 // we are finished with current prefs, wait for changes
594 SCPreferencesSynchronize(prefs
);
596 os_release(activity
);
601 #if !TARGET_OS_EMBEDDED
604 updateBTPANInformation(const void *value
, void *context
)
607 CFDictionaryRef dict
= (CFDictionaryRef
)value
;
609 CFDictionaryRef info
;
612 if_name
= CFDictionaryGetValue(dict
, CFSTR(kIOBSDNameKey
));
613 if (!isA_CFString(if_name
)) {
618 info
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceInfo
));
619 if (!isA_CFDictionary(info
)) {
620 // if no SCNetworkInterface info
624 name
= CFDictionaryGetValue(info
, kSCPropUserDefinedName
);
625 if (!isA_CFString(name
) || !CFEqual(name
, CFSTR(BT_PAN_NAME
))) {
626 // if not BT-PAN interface
630 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Name
, if_name
);
632 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
633 if (isA_CFData(addr
)) {
634 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Mac
, addr
);
639 #endif // !TARGET_OS_EMBEDDED
641 static CFDictionaryRef
642 createInterfaceDict(SCNetworkInterfaceRef interface
)
644 CFMutableDictionaryRef new_if
;
647 new_if
= CFDictionaryCreateMutable(NULL
,
649 &kCFTypeDictionaryKeyCallBacks
,
650 &kCFTypeDictionaryValueCallBacks
);
652 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
654 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
658 val
= _SCNetworkInterfaceGetIOPath(interface
);
660 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
663 val
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
665 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceNamePrefix
), val
);
668 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
670 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
673 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
675 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
678 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
680 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
683 val
= SCNetworkInterfaceGetBSDName(interface
);
685 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
688 val
= SCNetworkInterfaceGetInterfaceType(interface
);
690 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
693 CFDictionarySetValue(new_if
,
695 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
697 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
702 static CFDictionaryRef
703 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
710 if (db_list
== NULL
) {
713 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
714 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
715 if (type
== NULL
|| addr
== NULL
) {
719 n
= CFArrayGetCount(db_list
);
720 for (i
= 0; i
< n
; i
++) {
722 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
725 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
726 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
727 if (t
== NULL
|| a
== NULL
)
730 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
740 static CFDictionaryRef
741 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
748 if (db_list
== NULL
) {
751 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
752 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
753 if (type
== NULL
|| unit
== NULL
) {
757 n
= CFArrayGetCount(db_list
);
758 for (i
= 0; i
< n
; i
++) {
759 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
763 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
764 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
765 if (t
== NULL
|| u
== NULL
) {
769 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
779 CFDictionaryRef match_info
;
780 CFStringRef match_type
;
781 CFBooleanRef match_builtin
;
782 CFMutableArrayRef matches
;
783 } matchContext
, *matchContextRef
;
785 static CF_RETURNS_RETAINED CFDictionaryRef
786 thinInterfaceInfo(CFDictionaryRef info
)
791 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
793 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
794 && (vid
== kIOUSBVendorIDAppleComputer
)) {
795 CFMutableDictionaryRef thin
;
797 // if this is an Apple USB device than we trust that
798 // the non-localized name will be correct.
799 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
800 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
801 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
802 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
806 return CFRetain(info
);
810 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
814 match
= _SC_CFEqual(known_info
, match_info
);
816 isA_CFDictionary(known_info
) &&
817 isA_CFDictionary(match_info
)) {
819 // if not an exact match, try thinning
820 known_info
= thinInterfaceInfo(known_info
);
821 match_info
= thinInterfaceInfo(match_info
);
822 match
= _SC_CFEqual(known_info
, match_info
);
823 if (known_info
!= NULL
) CFRelease(known_info
);
824 if (match_info
!= NULL
) CFRelease(match_info
);
831 matchKnown(const void *value
, void *context
)
833 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
834 matchContextRef match_context
= (matchContextRef
)context
;
836 // match interface type
838 CFStringRef known_type
;
840 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
841 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
846 // match SCNetworkInterfaceInfo
848 CFDictionaryRef known_info
;
850 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
851 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
856 // if requested, match [non-]builtin
857 if (match_context
->match_builtin
!= NULL
) {
858 CFBooleanRef known_builtin
;
860 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
861 if (!isA_CFBoolean(known_builtin
)) {
862 known_builtin
= kCFBooleanFalse
;
864 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
869 // if we have a match
870 if (match_context
->matches
== NULL
) {
871 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
873 CFArrayAppendValue(match_context
->matches
, known_dict
);
879 matchUnnamed(const void *value
, void *context
)
881 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
882 matchContextRef match_context
= (matchContextRef
)context
;
884 if (match_context
->matches
== NULL
) {
888 // match interface type
890 CFStringRef known_type
;
892 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
893 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
898 // match SCNetworkInterfaceInfo
900 CFDictionaryRef known_info
;
903 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
904 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
905 if (known_info
!= NULL
) CFRelease(known_info
);
911 // if requested, match [non-]builtin
912 if (match_context
->match_builtin
!= NULL
) {
913 CFBooleanRef known_builtin
;
915 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
917 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
922 // if we have a match
923 CFRelease(match_context
->matches
);
924 match_context
->matches
= NULL
;
930 interfaceExists(CFStringRef prefix
, CFNumberRef unit
)
932 Boolean found
= FALSE
;
933 CFDictionaryRef match_dict
;
934 CFStringRef match_keys
[2];
935 CFTypeRef match_vals
[2];
936 CFDictionaryRef matching
;
940 io_registry_entry_t entry
= MACH_PORT_NULL
;
941 io_iterator_t iterator
= MACH_PORT_NULL
;
943 mach_port_t masterPort
= MACH_PORT_NULL
;
945 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
946 if (kr
!= KERN_SUCCESS
) {
947 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
951 // look for kIONetworkInterface with matching prefix and unit
952 match_keys
[0] = CFSTR(kIOInterfaceNamePrefix
);
953 match_vals
[0] = prefix
;
954 match_keys
[1] = CFSTR(kIOInterfaceUnit
);
955 match_vals
[1] = unit
;
956 match_dict
= CFDictionaryCreate(NULL
,
957 (const void **)match_keys
,
958 (const void **)match_vals
,
960 &kCFTypeDictionaryKeyCallBacks
,
961 &kCFTypeDictionaryValueCallBacks
);
963 match_keys
[0] = CFSTR(kIOProviderClassKey
);
964 match_vals
[0] = CFSTR(kIONetworkInterfaceClass
);
965 match_keys
[1] = CFSTR(kIOPropertyMatchKey
);
966 match_vals
[1] = match_dict
;
967 matching
= CFDictionaryCreate(NULL
,
968 (const void **)match_keys
,
969 (const void **)match_vals
,
970 sizeof(match_keys
)/sizeof(match_keys
[0]),
971 &kCFTypeDictionaryKeyCallBacks
,
972 &kCFTypeDictionaryValueCallBacks
);
973 CFRelease(match_dict
);
975 // note: the "matching" dictionary will be consumed by the following
976 kr
= IOServiceGetMatchingServices(masterPort
, matching
, &iterator
);
977 if ((kr
!= kIOReturnSuccess
) || (iterator
== MACH_PORT_NULL
)) {
982 entry
= IOIteratorNext(iterator
);
983 if (entry
== MACH_PORT_NULL
) {
991 if (masterPort
!= MACH_PORT_NULL
) {
992 mach_port_deallocate(mach_task_self(), masterPort
);
994 if (entry
!= MACH_PORT_NULL
) {
995 IOObjectRelease(entry
);
997 if (iterator
!= MACH_PORT_NULL
) {
998 IOObjectRelease(iterator
);
1005 * lookupMatchingInterface
1007 * Looks at the interfaces that have already been [or need to be] named with
1008 * the goal of allowing a system using a single network interface/adaptor of
1009 * a given type (vendor, model, ...) to not care about the specific adaptor
1010 * that is used (i.e. swapping dongle's is OK). Once a system has had more
1011 * than one interface/adaptor connected at the same time than we assume that
1012 * the network configuration is being setup for multi-homing that should be
1015 * If no matches are found or if more than one match is found, return NULL.
1016 * If a single match is found, return the match.
1018 static CFDictionaryRef
1019 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
1020 CFArrayRef db_list
, // already named
1021 CFArrayRef if_list
, // to be named
1022 CFIndex if_list_index
,
1023 CFBooleanRef builtin
)
1025 CFStringRef if_type
;
1026 CFDictionaryRef match
= NULL
;
1027 matchContext match_context
;
1029 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
1030 if (if_type
== NULL
) {
1034 match_context
.match_type
= if_type
;
1035 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
1036 match_context
.match_builtin
= builtin
;
1037 match_context
.matches
= NULL
;
1039 // check for matches to interfaces that have already been named
1040 // ... and append each match that we find to match_context.matches
1041 if (db_list
!= NULL
) {
1042 CFArrayApplyFunction(db_list
,
1043 CFRangeMake(0, CFArrayGetCount(db_list
)),
1048 // check for matches to interfaces that will be named
1049 // ... and CFRelease match_context.matches if we find another network
1050 // interface of the same type that also needs to be named
1051 if (if_list
!= NULL
) {
1052 CFIndex if_list_count
;
1054 if_list_count
= CFArrayGetCount(if_list
);
1055 if (if_list_index
< if_list_count
) {
1056 CFArrayApplyFunction(if_list
,
1057 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
1063 // check if we have a single match
1064 if (match_context
.matches
!= NULL
) {
1065 if (CFArrayGetCount(match_context
.matches
) == 1) {
1066 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
1068 CFRelease(match_context
.matches
);
1071 if (match
!= NULL
) {
1072 Boolean active
= TRUE
;
1075 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
1076 if (isA_CFString(name
)) {
1080 prefix
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceNamePrefix
));
1081 unit
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceUnit
));
1082 if (isA_CFString(prefix
) && isA_CFNumber(unit
)) {
1083 if (!interfaceExists(prefix
, unit
)) {
1094 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
1099 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
)
1102 CFDictionaryRef if_dict
;
1103 CFStringRef if_name
;
1104 CFNumberRef if_type
;
1105 CFNumberRef if_unit
;
1106 CFIndex n
= CFArrayGetCount(db_list
);
1107 CFComparisonResult res
;
1109 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1110 if (if_name
!= NULL
) {
1111 addTimestamp(S_state
, if_name
);
1114 if_dict
= createInterfaceDict(interface
);
1115 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1116 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1117 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
1122 for (i
= 0; i
< n
; i
++) {
1123 CFNumberRef db_type
;
1124 CFNumberRef db_unit
;
1125 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
1127 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1128 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1129 res
= CFNumberCompare(if_type
, db_type
, NULL
);
1130 if (res
== kCFCompareLessThan
1131 || (res
== kCFCompareEqualTo
1132 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
1133 == kCFCompareLessThan
))) {
1134 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
1140 CFArrayAppendValue(S_dblist
, if_dict
);
1142 #if !TARGET_OS_EMBEDDED
1143 updateBTPANInformation(if_dict
, NULL
);
1144 #endif // !TARGET_OS_EMBEDDED
1151 replaceInterface(SCNetworkInterfaceRef interface
)
1156 if (S_dblist
== NULL
) {
1157 S_dblist
= CFArrayCreateMutable(NULL
, 0,
1158 &kCFTypeArrayCallBacks
);
1160 // remove any dict that has our type/addr
1161 while (lookupInterfaceByAddress(S_dblist
, interface
, &where
) != NULL
) {
1162 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1165 // remove any dict that has the same type/unit
1166 while (lookupInterfaceByUnit(S_dblist
, interface
, &where
) != NULL
) {
1167 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1170 insertInterface(S_dblist
, interface
);
1173 SC_log(LOG_ERR
, "Multiple interfaces updated (n = %d, %@)", n
, interface
);
1180 getHighestUnitForType(CFNumberRef if_type
)
1184 CFNumberRef ret_unit
= NULL
;
1186 if (S_dblist
== NULL
) {
1190 n
= CFArrayGetCount(S_dblist
);
1191 for (i
= 0; i
< n
; i
++) {
1192 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1195 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1196 if (CFEqual(type
, if_type
)) {
1199 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1200 if (ret_unit
== NULL
1201 || (CFNumberCompare(unit
, ret_unit
, NULL
)
1202 == kCFCompareGreaterThan
)) {
1212 * Function: ensureInterfaceHasUnit
1214 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1215 * release the interface and return NULL.
1217 static SCNetworkInterfaceRef
1218 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if
)
1221 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if
) == NULL
) {
1228 #ifdef USE_REGISTRY_ENTRY_ID
1229 static kern_return_t
1230 registerInterfaceWithIORegistryEntryID(io_connect_t connect
,
1236 CFMutableDictionaryRef dict
;
1240 dict
= CFDictionaryCreateMutable(NULL
, 0,
1241 &kCFTypeDictionaryKeyCallBacks
,
1242 &kCFTypeDictionaryValueCallBacks
);
1243 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1244 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1246 data
= CFDataCreate(NULL
, (void *) &entryID
, sizeof(entryID
));
1247 CFDictionarySetValue(dict
, CFSTR(kIORegistryEntryIDKey
), data
);
1249 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1250 kr
= IOConnectSetCFProperties(connect
, dict
);
1255 static SCNetworkInterfaceRef
1256 copyInterfaceForIORegistryEntryID(uint64_t entryID
)
1258 io_registry_entry_t entry
= MACH_PORT_NULL
;
1259 SCNetworkInterfaceRef interface
= NULL
;
1260 io_iterator_t iterator
= MACH_PORT_NULL
;
1262 mach_port_t masterPort
= MACH_PORT_NULL
;
1264 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1265 if (kr
!= KERN_SUCCESS
) {
1266 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1270 kr
= IOServiceGetMatchingServices(masterPort
,
1271 IORegistryEntryIDMatching(entryID
),
1273 if ((kr
!= KERN_SUCCESS
) || (iterator
== MACH_PORT_NULL
)) {
1274 SC_log(LOG_NOTICE
, "IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d",
1281 entry
= IOIteratorNext(iterator
);
1282 if (entry
== MACH_PORT_NULL
) {
1283 SC_log(LOG_NOTICE
, "IORegistryEntryIDMatching(0x%llx) failed", entryID
);
1287 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1290 if (masterPort
!= MACH_PORT_NULL
) {
1291 mach_port_deallocate(mach_task_self(), masterPort
);
1293 if (entry
!= MACH_PORT_NULL
) {
1294 IOObjectRelease(entry
);
1296 if (iterator
!= MACH_PORT_NULL
) {
1297 IOObjectRelease(iterator
);
1302 static SCNetworkInterfaceRef
1303 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID
)
1305 SCNetworkInterfaceRef net_if
;
1307 net_if
= copyInterfaceForIORegistryEntryID(entryID
);
1308 return (ensureInterfaceHasUnit(net_if
));
1311 #else // USE_REGISTRY_ENTRY_ID
1313 * Function: registerInterface
1315 * Register a single interface with the given service path to the
1316 * data link layer (BSD), using the specified unit number.
1318 static kern_return_t
1319 registerInterfaceWithIOServicePath(io_connect_t connect
,
1324 CFMutableDictionaryRef dict
;
1328 dict
= CFDictionaryCreateMutable(NULL
, 0,
1329 &kCFTypeDictionaryKeyCallBacks
,
1330 &kCFTypeDictionaryValueCallBacks
);
1331 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1332 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1334 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1335 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1336 kr
= IOConnectSetCFProperties(connect
, dict
);
1341 static SCNetworkInterfaceRef
1342 copyInterfaceForIOKitPath(CFStringRef if_path
)
1344 io_registry_entry_t entry
= MACH_PORT_NULL
;
1345 SCNetworkInterfaceRef interface
= NULL
;
1347 mach_port_t masterPort
= MACH_PORT_NULL
;
1350 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1351 if (kr
!= KERN_SUCCESS
) {
1352 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1355 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1356 entry
= IORegistryEntryFromPath(masterPort
, path
);
1357 if (entry
== MACH_PORT_NULL
) {
1358 SC_log(LOG_NOTICE
, "IORegistryEntryFromPath(%@) failed", if_path
);
1362 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1365 if (masterPort
!= MACH_PORT_NULL
) {
1366 mach_port_deallocate(mach_task_self(), masterPort
);
1368 if (entry
!= MACH_PORT_NULL
) {
1369 IOObjectRelease(entry
);
1375 static SCNetworkInterfaceRef
1376 copyNamedInterfaceForIOKitPath(CFStringRef if_path
)
1378 SCNetworkInterfaceRef net_if
;
1380 net_if
= copyInterfaceForIOKitPath(if_path
);
1381 return (ensureInterfaceHasUnit(net_if
));
1384 #endif // USE_REGISTRY_ENTRY_ID
1387 displayInterface(SCNetworkInterfaceRef interface
)
1394 name
= SCNetworkInterfaceGetBSDName(interface
);
1395 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1396 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1397 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1399 SC_log(LOG_INFO
, " %s%@%sType: %@, %s%@%sMAC address: %@",
1400 (name
!= NULL
) ? "BSD Name: " : "",
1401 (name
!= NULL
) ? name
: CFSTR(""),
1402 (name
!= NULL
) ? ", " : "",
1404 (unit
!= NULL
) ? "Unit: " : "",
1405 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1406 (unit
!= NULL
) ? ", " : "",
1411 builtinAvailable(SCNetworkInterfaceRef interface
, // new interface
1412 CFNumberRef if_unit
) // desired unit
1415 CFNumberRef if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1418 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1419 for (i
= 0; i
< n
; i
++) {
1420 CFStringRef if_path
;
1421 CFDictionaryRef known_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1422 CFStringRef known_path
;
1423 CFNumberRef known_type
;
1424 CFNumberRef known_unit
;
1426 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceType
));
1427 if (!_SC_CFEqual(if_type
, known_type
)) {
1428 continue; // if not the same interface type
1431 known_unit
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceUnit
));
1432 if (!_SC_CFEqual(if_unit
, known_unit
)) {
1433 continue; // if not the same interface unit
1436 if_path
= _SCNetworkInterfaceGetIOPath(interface
);
1437 known_path
= CFDictionaryGetValue(known_dict
, CFSTR(kIOPathMatchKey
));
1438 if (!_SC_CFEqual(if_path
, known_path
)) {
1439 // if different IORegistry path
1443 // if same type, same unit, same path
1447 // if interface type/unit not found
1452 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
1457 for (i
= 0; i
< last
; i
++) {
1458 SCNetworkInterfaceRef builtin_if
;
1459 CFNumberRef builtin_type
;
1461 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1462 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
1463 if (CFEqual(if_type
, builtin_type
)) {
1464 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1465 n
++; // if built-in interface
1473 #if !TARGET_OS_IPHONE
1475 blockNewInterfaces()
1477 static boolean_t allow
= TRUE
;
1478 static dispatch_once_t once
;
1480 dispatch_once(&once
, ^{
1481 allow
= InterfaceNamerControlPrefsAllowNewInterfaces();
1491 CFArrayRef console_sessions
;
1492 boolean_t locked
= FALSE
;
1493 io_registry_entry_t root
;
1495 root
= IORegistryGetRootEntry(kIOMasterPortDefault
);
1496 console_sessions
= IORegistryEntryCreateCFProperty(root
,
1497 CFSTR(kIOConsoleUsersKey
),
1500 if (isA_CFArray(console_sessions
)) {
1503 n
= CFArrayGetCount(console_sessions
);
1504 for (CFIndex i
= 0; i
< n
; i
++) {
1505 CFBooleanRef isLocked
;
1506 CFBooleanRef isLoginDone
;
1507 CFBooleanRef onConsole
;
1508 CFDictionaryRef session
;
1510 session
= CFArrayGetValueAtIndex(console_sessions
, i
);
1511 if (!isA_CFDictionary(session
)) {
1512 // if not dictionary
1516 if (!CFDictionaryGetValueIfPresent(session
,
1517 CFSTR(kIOConsoleSessionOnConsoleKey
),
1518 (const void **)&onConsole
) ||
1519 !isA_CFBoolean(onConsole
) ||
1520 !CFBooleanGetValue(onConsole
)) {
1521 // if not "on console" session
1526 CFDictionaryGetValueIfPresent(session
,
1527 CFSTR(kIOConsoleSessionLoginDoneKey
),
1528 (const void **)&isLoginDone
) &&
1529 isA_CFBoolean(isLoginDone
) &&
1530 !CFBooleanGetValue(isLoginDone
)) {
1532 SC_log(LOG_INFO
, "multiple sessions, console @ loginwindow");
1537 if (CFDictionaryGetValueIfPresent(session
,
1538 CFSTR(kIOConsoleSessionScreenIsLockedKey
),
1539 (const void **)&isLocked
) &&
1540 isA_CFBoolean(isLocked
) &&
1541 CFBooleanGetValue(isLocked
)) {
1543 SC_log(LOG_INFO
, "console screen locked");
1550 SC_log(LOG_INFO
, "console not locked");
1554 if (console_sessions
!= NULL
) {
1555 CFRelease(console_sessions
);
1557 IOObjectRelease(root
);
1561 #endif // !TARGET_OS_IPHONE
1563 static __inline__ boolean_t
1566 return (S_quiet
== MACH_PORT_NULL
);
1570 nameInterfaces(CFMutableArrayRef if_list
)
1573 CFIndex n
= CFArrayGetCount(if_list
);
1575 for (i
= 0; i
< n
; i
++) {
1577 SCNetworkInterfaceRef interface
;
1578 SCNetworkInterfaceRef new_interface
;
1584 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1585 path
= _SCNetworkInterfaceGetIOPath(interface
);
1586 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1587 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1588 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
1591 CFStringRef if_name
;
1593 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1594 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
1595 SC_log(LOG_INFO
, "Interface already has a unit number");
1596 displayInterface(interface
);
1599 // update the list of interfaces that were previously named
1600 if ((S_prev_active_list
!= NULL
)
1601 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
1602 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1605 replaceInterface(interface
);
1607 CFDictionaryRef dbdict
;
1608 boolean_t is_builtin
;
1612 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
1613 if (dbdict
!= NULL
) {
1614 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1617 SC_log(LOG_INFO
, "Interface assigned unit %@ (from database)", unit
);
1620 if ((dbdict
== NULL
) && !isQuiet()) {
1621 // if new interface, wait until quiet before naming
1622 addTimestamp(S_state
, path
);
1626 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
1628 if (dbdict
== NULL
) {
1629 dbdict
= lookupMatchingInterface(interface
,
1633 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
1635 #if !TARGET_OS_IPHONE
1638 blockNewInterfaces() &&
1639 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
1640 isConsoleLocked()) {
1643 // if new (but matching) interface and console locked, ignore
1644 SC_log(LOG_NOTICE
, "Console locked, network interface* ignored");
1645 SC_log(LOG_INFO
, " path = %@", path
);
1646 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
1648 SC_log(LOG_INFO
, " addr = %@", addr
);
1652 #endif // !TARGET_OS_IPHONE
1654 if (dbdict
!= NULL
) {
1655 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1658 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database)", unit
);
1662 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
1663 // update the list of interfaces that were previously named
1664 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
1665 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
1667 if (where
!= kCFNotFound
) {
1668 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1672 if (dbdict
== NULL
) {
1676 // built-in interface, try to use the reserved slots
1677 next_unit
= builtinCount(if_list
, i
, type
);
1679 // But, before claiming a reserved slot we check to see if the
1680 // slot had previously been used. If so, and if the slot had been
1681 // assigned to the same type of interface, then we will perform a
1682 // replacement (e.g. assume that this was a board swap). But, if
1683 // the new interface is a different type then we assume that the
1684 // built-in configuration has changed and allocate a new unit from
1685 // the non-reserved slots.
1687 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1688 if (!builtinAvailable(interface
, unit
)) {
1689 // if [built-in] unit not available
1690 SC_log(LOG_INFO
, "Interface not assigned [built-in] unit %@", unit
);
1696 #if !TARGET_OS_IPHONE
1699 blockNewInterfaces() &&
1700 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
1701 isConsoleLocked()) {
1704 // if new interface and console locked, ignore
1705 SC_log(LOG_NOTICE
, "Console locked, network interface ignored");
1706 SC_log(LOG_INFO
, " path = %@", path
);
1707 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
1709 SC_log(LOG_INFO
, " addr = %@", addr
);
1713 #endif // !TARGET_OS_IPHONE
1716 // not built-in (or built-in unit not available), allocate from
1717 // the non-reserved slots
1718 next_unit
= builtinCount(if_list
, n
, type
);
1720 unit
= getHighestUnitForType(type
);
1724 CFNumberGetValue(unit
, kCFNumberIntType
, &high_unit
);
1725 if (high_unit
>= next_unit
) {
1726 next_unit
= high_unit
+ 1;
1730 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1733 SC_log(LOG_INFO
, "Interface assigned unit %@ (%s)",
1735 is_builtin
? "built-in" : "next available");
1740 #ifdef USE_REGISTRY_ENTRY_ID
1741 kr
= registerInterfaceWithIORegistryEntryID(S_connect
,
1744 (dbdict
== NULL
) ? kIONetworkStackRegisterInterfaceWithLowestUnit
1745 : kIONetworkStackRegisterInterfaceWithUnit
);
1746 new_interface
= copyNamedInterfaceForIORegistryEntryID(entryID
);
1747 #else // USE_REGISTRY_ENTRY_ID
1748 kr
= registerInterfaceWithIOServicePath(S_connect
,
1751 (dbdict
== NULL
) ? kRegisterInterface
1752 : kRegisterInterfaceWithFixedUnit
);
1753 new_interface
= copyNamedInterfaceForIOKitPath(path
);
1754 #endif // USE_REGISTRY_ENTRY_ID
1755 if (new_interface
== NULL
) {
1756 const char *signature
;
1758 signature
= (dbdict
== NULL
) ? "failed to name new interface"
1759 : "failed to name known interface";
1761 SC_log(LOG_NOTICE
, "%s, kr=0x%x\n"
1771 displayInterface(interface
);
1773 if ((dbdict
!= NULL
) && (retries
++ < 5)) {
1774 usleep(50 * 1000); // sleep 50ms between attempts
1779 CFNumberRef new_unit
;
1782 SC_log(LOG_INFO
, "%s interface named after %d %s\n"
1785 (dbdict
== NULL
) ? "New" : "Known",
1787 (retries
== 1) ? "try" : "tries",
1791 #ifdef SHOW_NAMING_FAILURE
1792 str
= CFStringCreateWithFormat(NULL
,
1794 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
1795 (dbdict
== NULL
) ? "New" : "Known",
1797 (retries
== 1) ? "try" : "tries",
1799 CFUserNotificationDisplayNotice(0,
1800 kCFUserNotificationStopAlertLevel
,
1805 CFSTR("Please report repeated failures."),
1808 #endif // SHOW_NAMING_FAILURE
1811 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
1812 if (!CFEqual(unit
, new_unit
)) {
1813 SC_log(LOG_INFO
, "interface type %@ assigned unit %@ instead of %@",
1814 type
, new_unit
, unit
);
1817 displayInterface(new_interface
);
1819 // update if_list (with the interface name & unit)
1820 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
1821 CFRelease(new_interface
);
1822 interface
= new_interface
; // if_list holds the reference
1824 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
1827 // update the list of [built-in] interfaces that were previously named
1828 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
1829 SC_log(LOG_DEBUG
, " and updated database (new address)");
1830 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1833 replaceInterface(interface
);
1841 #if !TARGET_OS_IPHONE
1845 static Boolean isRecovery
= FALSE
;
1846 static dispatch_once_t once
;
1849 * We check to see if the UserEventAgent daemon is present. If not, then
1850 * we are most likely booted into the Recovery OS with no "SCMonitor"
1851 * [UserEventAgent] plugin.
1853 dispatch_once(&once
, ^{
1854 if ((access("/usr/libexec/UserEventAgent", X_OK
) == -1) && (errno
== ENOENT
)) {
1864 updateNetworkConfiguration(CFArrayRef if_list
)
1866 Boolean do_commit
= FALSE
;
1869 SCPreferencesRef prefs
= NULL
;
1870 SCNetworkSetRef set
= NULL
;
1872 prefs
= SCPreferencesCreate(NULL
, CFSTR("InterfaceNamer:updateNetworkConfiguration"), NULL
);
1874 set
= SCNetworkSetCopyCurrent(prefs
);
1876 SC_log(LOG_INFO
, "No current set");
1880 n
= CFArrayGetCount(if_list
);
1881 for (i
= 0; i
< n
; i
++) {
1882 SCNetworkInterfaceRef interface
;
1884 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1885 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set
, interface
)) {
1886 SC_log(LOG_INFO
, "adding default configuration for %@",
1887 SCNetworkInterfaceGetBSDName(interface
));
1895 ok
= SCPreferencesCommitChanges(prefs
);
1897 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
1901 ok
= SCPreferencesApplyChanges(prefs
);
1903 SC_log(LOG_NOTICE
, "SCPreferencesApplyChanges() failed: %s", SCErrorString(SCError()));
1915 if (prefs
!= NULL
) {
1922 #endif // !TARGET_OS_IPHONE
1925 updatePreConfigured(CFArrayRef interfaces
)
1929 CFMutableArrayRef new_list
= NULL
;
1930 Boolean updated
= FALSE
;
1932 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
1933 for (i
= 0; i
< n
; i
++) {
1934 SCNetworkInterfaceRef interface
;
1936 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1937 if (_SCNetworkInterfaceIsApplePreconfigured(interface
)) {
1938 CFStringRef bsdName
;
1940 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
1941 if (bsdName
== NULL
) {
1945 // add pre-configured interface
1946 if (new_list
== NULL
) {
1947 CFArrayRef cur_list
;
1949 cur_list
= CFDictionaryGetValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
);
1950 if (cur_list
!= NULL
) {
1951 new_list
= CFArrayCreateMutableCopy(NULL
, 0, cur_list
);
1953 new_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1957 if (!CFArrayContainsValue(new_list
, CFRangeMake(0, CFArrayGetCount(new_list
)), bsdName
)) {
1958 CFArrayAppendValue(new_list
, bsdName
);
1964 if (new_list
!= NULL
) {
1966 CFDictionarySetValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
, new_list
);
1970 CFRelease(new_list
);
1979 if (S_connect
== MACH_PORT_NULL
) {
1980 // if we don't have the "IONetworkStack" connect object
1984 if (S_iflist
!= NULL
) {
1987 n
= CFArrayGetCount(S_iflist
);
1989 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
1991 nameInterfaces(S_iflist
);
1995 * Update the list of [Apple] pre-configured interfaces
1997 updatePreConfigured(S_iflist
);
2001 * The registry [matching] has quiesced so let's
2002 * - save the DB with the interfaces that have been named
2003 * - update the VLAN/BOND configuration
2004 * - tell everyone that we've finished (at least for now)
2005 * - log those interfaces which are no longer present
2006 * in the HW config (or have yet to show up).
2008 writeInterfaceList(S_dblist
);
2009 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
2011 #if !TARGET_OS_IPHONE
2012 if (isRecoveryOS()) {
2014 * We are most likely booted into the Recovery OS with no "SCMonitor"
2015 * UserEventAgent plugin running so let's make sure we update the
2016 * network configuration for new interfaces.
2018 updateNetworkConfiguration(S_iflist
);
2020 #endif // !TARGET_OS_IPHONE
2024 if (S_iflist
!= NULL
) {
2025 CFRelease(S_iflist
);
2029 if (S_prev_active_list
!= NULL
) {
2033 n
= CFArrayGetCount(S_prev_active_list
);
2035 SC_log(LOG_INFO
, "Interface%s not [yet] active",
2036 (n
> 1) ? "s" : "");
2038 for (i
= 0; i
< n
; i
++) {
2039 CFDictionaryRef if_dict
;
2044 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
2045 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
2046 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
2047 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
2048 SC_log(LOG_INFO
, " %s%@%sType: %@, Unit: %@",
2049 (name
!= NULL
) ? "BSD Name: " : "",
2050 (name
!= NULL
) ? name
: CFSTR(""),
2051 (name
!= NULL
) ? ", " : "",
2056 CFRelease(S_prev_active_list
);
2057 S_prev_active_list
= NULL
;
2060 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
2062 * if we've named all of the interfaces that
2063 * were used during the previous boot.
2065 addTimestamp(S_state
, CFSTR("*RELEASE*"));
2066 SC_log(LOG_INFO
, "last boot interfaces have been named");
2068 CFRelease(S_prev_active_list
);
2069 S_prev_active_list
= NULL
;
2077 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
2079 os_activity_t activity
;
2082 activity
= os_activity_create("process new network interface",
2083 OS_ACTIVITY_CURRENT
,
2084 OS_ACTIVITY_FLAG_DEFAULT
);
2085 os_activity_scope(activity
);
2087 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
2088 SCNetworkInterfaceRef interface
;
2090 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
2091 if (interface
!= NULL
) {
2092 if (S_iflist
== NULL
) {
2093 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2095 CFArrayAppendValue(S_iflist
, interface
);
2096 CFRelease(interface
);
2098 IOObjectRelease(obj
);
2103 os_release(activity
);
2109 * Function: stackCallback
2111 * Get a reference to the single IONetworkStack object instance in
2112 * the kernel. Naming requests must be sent to this object, which is
2113 * attached as a client to all network interface objects in the system.
2115 * Call IOObjectRelease on the returned object.
2118 stackCallback(void *refcon
, io_iterator_t iter
)
2120 os_activity_t activity
;
2124 activity
= os_activity_create("process IONetworkStack",
2125 OS_ACTIVITY_CURRENT
,
2126 OS_ACTIVITY_FLAG_DEFAULT
);
2127 os_activity_scope(activity
);
2129 stack
= IOIteratorNext(iter
);
2130 if (stack
== MACH_PORT_NULL
) {
2134 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
2135 if (kr
!= KERN_SUCCESS
) {
2136 SC_log(LOG_ERR
, "IOServiceOpen returned 0x%x", kr
);
2140 addTimestamp(S_state
, CFSTR("*STACK*"));
2141 SC_log(LOG_INFO
, "IONetworkStack found");
2143 if (S_stack
!= MACH_PORT_NULL
) {
2144 IOObjectRelease(S_stack
);
2145 S_stack
= MACH_PORT_NULL
;
2148 if ((S_timer
!= NULL
) && CFRunLoopTimerIsValid(S_timer
)) {
2149 // With the IONetworkStack object now available we can
2150 // reset (shorten?) the time we are willing to wait for
2151 // IOKit to quiesce.
2152 CFRunLoopTimerSetNextFireDate(S_timer
,
2153 CFAbsoluteTimeGetCurrent() + S_quiet_timeout
);
2160 if (stack
!= MACH_PORT_NULL
) {
2161 IOObjectRelease(stack
);
2164 os_release(activity
);
2170 quietCallback(void *refcon
,
2171 io_service_t service
,
2172 natural_t messageType
,
2173 void *messageArgument
)
2175 os_activity_t activity
;
2177 if (messageArgument
!= NULL
) {
2182 activity
= os_activity_create("process IOKit quiet",
2183 OS_ACTIVITY_CURRENT
,
2184 OS_ACTIVITY_FLAG_DEFAULT
);
2185 os_activity_scope(activity
);
2187 if (messageType
== kIOMessageServiceBusyStateChange
) {
2188 addTimestamp(S_state
, kInterfaceNamerKey_Quiet
);
2189 SC_log(LOG_INFO
, "IOKit quiet");
2192 if (S_connect
== MACH_PORT_NULL
) {
2193 SC_log(LOG_ERR
, "No network stack object");
2197 if (S_quiet
!= MACH_PORT_NULL
) {
2198 IOObjectRelease(S_quiet
);
2199 S_quiet
= MACH_PORT_NULL
;
2202 if (S_timer
!= NULL
) {
2203 CFRunLoopTimerInvalidate(S_timer
);
2208 // grab (and name) any additional interfaces.
2209 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2211 if (messageType
== kIOMessageServiceBusyStateChange
) {
2212 addTimestamp(S_state
, CFSTR("*QUIET&NAMED*"));
2218 os_release(activity
);
2224 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, int *count
)
2226 kern_return_t kr
= kIOReturnSuccess
;;
2229 while ((kr
== kIOReturnSuccess
) &&
2230 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
2231 uint64_t accumulated_busy_time
;
2232 uint32_t busy_state
;
2235 CFMutableArrayRef newNodes
;
2237 CFMutableStringRef str
= NULL
;
2239 if (nodes
== NULL
) {
2240 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2242 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
2244 assert(newNodes
!= NULL
);
2246 kr
= IORegistryEntryGetName(obj
, name
);
2247 if (kr
!= kIOReturnSuccess
) {
2248 SC_log(LOG_NOTICE
, "IORegistryEntryGetName() returned 0x%x", kr
);
2252 str
= CFStringCreateMutable(NULL
, 0);
2253 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
2255 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
2257 case kIOReturnSuccess
:
2258 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
2259 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
2261 case kIOReturnNotFound
:
2264 SC_log(LOG_NOTICE
, "IORegistryEntryGetLocationInPlane() returned 0x%x", kr
);
2269 CFArrayAppendValue(newNodes
, str
);
2272 kr
= IOServiceGetBusyStateAndTime(obj
, &state
, &busy_state
, &accumulated_busy_time
);
2273 if (kr
!= kIOReturnSuccess
) {
2274 SC_log(LOG_NOTICE
, "IOServiceGetBusyStateAndTime() returned 0x%x", kr
);
2278 #ifdef TEST_SNAPSHOT
2281 #endif // TEST_SNAPSHOT
2283 if (busy_state
!= 0) {
2286 if ((*count
)++ == 0) {
2287 SC_log(LOG_ERR
, "Busy services :");
2290 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
2291 SC_log(LOG_ERR
, " %@ [%s%s%s%d, %lld ms]",
2293 (state
& kIOServiceRegisteredState
) ? "" : "!registered, ",
2294 (state
& kIOServiceMatchedState
) ? "" : "!matched, ",
2295 (state
& kIOServiceInactiveState
) ? "inactive, " : "",
2297 accumulated_busy_time
/ kMillisecondScale
);
2301 kr
= IORegistryIteratorEnterEntry(iterator
);
2302 if (kr
!= kIOReturnSuccess
) {
2303 SC_log(LOG_NOTICE
, "IORegistryIteratorEnterEntry() returned 0x%x", kr
);
2307 iterateRegistryBusy(iterator
, newNodes
, count
);
2309 kr
= IORegistryIteratorExitEntry(iterator
);
2310 if (kr
!= kIOReturnSuccess
) {
2311 SC_log(LOG_NOTICE
, "IORegistryIteratorExitEntry() returned 0x%x", kr
);
2316 CFRelease(newNodes
);
2317 IOObjectRelease(obj
);
2327 io_iterator_t iterator
= MACH_PORT_NULL
;
2330 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
2334 if (kr
!= kIOReturnSuccess
) {
2335 SC_log(LOG_NOTICE
, "IORegistryCreateIterator() returned 0x%x", kr
);
2339 iterateRegistryBusy(iterator
, NULL
, &count
);
2341 SC_log(LOG_ERR
, "w/no busy services");
2344 IOObjectRelease(iterator
);
2348 timerCallback(CFRunLoopTimerRef timer
, void *info
)
2350 os_activity_t activity
;
2352 activity
= os_activity_create("process IOKit timer",
2353 OS_ACTIVITY_CURRENT
,
2354 OS_ACTIVITY_FLAG_DEFAULT
);
2355 os_activity_scope(activity
);
2357 // We've been waiting for IOKit to quiesce and it just
2358 // hasn't happenned. Time to just move on!
2359 addTimestamp(S_state
, kInterfaceNamerKey_Timeout
);
2362 SC_log(LOG_ERR
, "timed out waiting for IOKit to quiesce");
2365 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
2367 addTimestamp(S_state
, CFSTR("*TIMEOUT&NAMED*"));
2370 os_release(activity
);
2376 setup_IOKit(CFBundleRef bundle
)
2380 mach_port_t masterPort
= MACH_PORT_NULL
;
2382 io_object_t root
= MACH_PORT_NULL
;
2384 // read DB of previously named network interfaces
2385 S_dblist
= readInterfaceList();
2386 if (S_dblist
!= NULL
) {
2389 n
= CFArrayGetCount(S_dblist
);
2391 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
2395 // get interfaces that were named during the last boot
2396 S_prev_active_list
= previouslyActiveInterfaces();
2398 // track how long we've waited to see each interface.
2399 S_state
= CFDictionaryCreateMutable(NULL
,
2401 &kCFTypeDictionaryKeyCallBacks
,
2402 &kCFTypeDictionaryValueCallBacks
);
2403 addTimestamp(S_state
, CFSTR("*START*"));
2405 // Creates and returns a notification object for receiving IOKit
2406 // notifications of new devices or state changes.
2407 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
2408 if (kr
!= KERN_SUCCESS
) {
2409 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
2413 S_notify
= IONotificationPortCreate(masterPort
);
2414 if (S_notify
== NULL
) {
2415 SC_log(LOG_ERR
, "IONotificationPortCreate failed");
2419 // watch IOKit matching activity
2420 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
2421 if (root
== MACH_PORT_NULL
) {
2422 SC_log(LOG_ERR
, "IORegistryEntryFromPath failed");
2426 kr
= IOServiceAddInterestNotification(S_notify
,
2430 (void *)S_notify
, // refCon
2431 &S_quiet
); // notification
2432 if (kr
!= KERN_SUCCESS
) {
2433 SC_log(LOG_ERR
, "IOServiceAddInterestNotification returned 0x%x", kr
);
2437 kr
= IOServiceGetBusyState(root
, &busy
);
2438 if (kr
!= KERN_SUCCESS
) {
2439 SC_log(LOG_ERR
, "IOServiceGetBusyState returned 0x%x", kr
);
2443 // add a timer so we don't wait forever for IOKit to quiesce
2444 S_timer
= CFRunLoopTimerCreate(NULL
,
2445 CFAbsoluteTimeGetCurrent() + S_stack_timeout
,
2451 if (S_timer
== NULL
) {
2452 SC_log(LOG_ERR
, "CFRunLoopTimerCreate failed");
2456 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
2458 // watch for the introduction of the IONetworkStack
2459 kr
= IOServiceAddMatchingNotification(S_notify
,
2460 kIOFirstMatchNotification
,
2461 IOServiceMatching("IONetworkStack"),
2463 (void *)S_notify
, // refCon
2464 &S_stack
); // notification
2465 if (kr
!= KERN_SUCCESS
) {
2466 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
2470 // check and see if the stack is already available and arm the
2471 // notification for its introduction.
2472 stackCallback((void *)S_notify
, S_stack
);
2474 // watch for the introduction of new network interfaces
2475 kr
= IOServiceAddMatchingNotification(S_notify
,
2476 kIOFirstMatchNotification
,
2477 IOServiceMatching("IONetworkInterface"),
2478 &interfaceArrivalCallback
,
2479 (void *)S_notify
, // refCon
2480 &S_iter
); // notification
2481 if (kr
!= KERN_SUCCESS
) {
2482 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
2486 // Get the current list of matches and arm the notification for
2487 // future interface arrivals.
2488 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2490 // Check if IOKit has already quiesced.
2491 quietCallback((void *)S_notify
,
2493 kIOMessageServiceBusyStateChange
,
2494 (void *)(uintptr_t)busy
);
2496 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2497 IONotificationPortGetRunLoopSource(S_notify
),
2498 kCFRunLoopDefaultMode
);
2500 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
2502 * Start the wheels turning until we've named all of
2503 * the interfaces that were used during the previous
2504 * boot, until IOKit [matching] has quiesced, or
2505 * until we've waited long enough.
2507 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
2508 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2509 IONotificationPortGetRunLoopSource(S_notify
),
2511 while (S_prev_active_list
!= NULL
) {
2514 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
2516 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
2518 #if !TARGET_OS_EMBEDDED
2519 if (S_dblist
!= NULL
) {
2520 // apply special handling for the BT-PAN interface (if present)
2521 CFArrayApplyFunction(S_dblist
,
2522 CFRangeMake(0, CFArrayGetCount(S_dblist
)),
2523 updateBTPANInformation
,
2526 #endif // !TARGET_OS_EMBEDDED
2531 if (root
!= MACH_PORT_NULL
) {
2532 IOObjectRelease(root
);
2534 if (masterPort
!= MACH_PORT_NULL
) {
2535 mach_port_deallocate(mach_task_self(), masterPort
);
2542 setup_Virtual(CFBundleRef bundle
)
2544 // open a SCPreferences session
2545 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
);
2546 if (S_prefs
== NULL
) {
2547 SC_log(LOG_ERR
, "SCPreferencesCreate() failed: %s",
2548 SCErrorString(SCError()));
2552 // register for change notifications.
2553 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
2554 SC_log(LOG_ERR
, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
2560 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
2561 if (SCError() != kSCStatusNoStoreServer
) {
2562 SC_log(LOG_ERR
, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
2572 exec_InterfaceNamer(void *arg
)
2574 CFBundleRef bundle
= (CFBundleRef
)arg
;
2575 CFDictionaryRef dict
;
2577 pthread_setname_np(MY_PLUGIN_NAME
" thread");
2579 dict
= CFBundleGetInfoDictionary(bundle
);
2580 if (isA_CFDictionary(dict
)) {
2583 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_STACK_TIMEOUT_KEY
));
2585 if (!isA_CFNumber(num
) ||
2586 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_stack_timeout
) ||
2587 (S_stack_timeout
<= 0.0)) {
2588 SC_log(LOG_NOTICE
, WAIT_STACK_TIMEOUT_KEY
" value error");
2589 S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
2593 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
2595 if (!isA_CFNumber(num
) ||
2596 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_quiet_timeout
) ||
2597 (S_quiet_timeout
<= 0.0)) {
2598 SC_log(LOG_NOTICE
, WAIT_QUIET_TIMEOUT_KEY
" value error");
2599 S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
2604 // setup virtual network interface monitoring
2605 if (!setup_Virtual(bundle
)) {
2609 // setup [IOKit] network interface monitoring
2610 if (!setup_IOKit(bundle
)) {
2617 if (S_connect
!= MACH_PORT_NULL
) {
2618 IOServiceClose(S_connect
);
2619 S_connect
= MACH_PORT_NULL
;
2621 if (S_dblist
!= NULL
) {
2622 CFRelease(S_dblist
);
2625 if (S_iter
!= MACH_PORT_NULL
) {
2626 IOObjectRelease(S_iter
);
2627 S_iter
= MACH_PORT_NULL
;
2629 if (S_notify
!= MACH_PORT_NULL
) {
2630 IONotificationPortDestroy(S_notify
);
2632 if (S_quiet
!= MACH_PORT_NULL
) {
2633 IOObjectRelease(S_quiet
);
2634 S_quiet
= MACH_PORT_NULL
;
2636 if (S_stack
!= MACH_PORT_NULL
) {
2637 IOObjectRelease(S_stack
);
2638 S_stack
= MACH_PORT_NULL
;
2640 if (S_state
!= NULL
) {
2644 if (S_timer
!= NULL
) {
2645 CFRunLoopTimerInvalidate(S_timer
);
2659 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
2661 pthread_attr_t tattr
;
2664 CFRetain(bundle
); // released in exec_InterfaceNamer
2666 pthread_attr_init(&tattr
);
2667 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
2668 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
2669 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
2670 pthread_create(&tid
, &tattr
, exec_InterfaceNamer
, bundle
);
2671 pthread_attr_destroy(&tattr
);
2676 //------------------------------------------------------------------------
2680 main(int argc
, char ** argv
)
2685 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2687 bundle
= CFBundleGetMainBundle();
2688 CFRetain(bundle
); // released in exec_InterfaceNamer
2690 (void)exec_InterfaceNamer();
2698 #ifdef TEST_SNAPSHOT
2700 main(int argc
, char ** argv
)
2702 CFStringRef snapshot
;
2705 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2707 snapshot
= captureBusy();
2708 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), snapshot
);
2709 CFRelease(snapshot
);
2714 #endif /* TEST_SNAPSHOT */