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 #include <SystemConfiguration/SystemConfiguration.h>
79 #include <SystemConfiguration/SCDPlugin.h>
80 #include <SystemConfiguration/SCPrivate.h>
81 #include <SystemConfiguration/SCValidation.h>
82 #include "plugin_shared.h"
84 #include "InterfaceNamerControlPrefs.h"
85 #endif // !TARGET_OS_IPHONE
87 #include <IOKit/IOKitLib.h>
88 #include <IOKit/IOKitLibPrivate.h>
89 #include <IOKit/IOKitKeysPrivate.h>
90 #include <IOKit/IOBSD.h>
91 #include <IOKit/IOMessage.h>
92 #include <IOKit/network/IONetworkController.h>
93 #include <IOKit/network/IONetworkInterface.h>
94 #include <IOKit/network/IONetworkStack.h>
95 #include <IOKit/usb/USB.h>
97 #ifdef kIONetworkStackUserCommandKey
98 #define USE_REGISTRY_ENTRY_ID
101 #ifndef USE_REGISTRY_ENTRY_ID
102 // from <IOKit/network/IONetworkStack.h>
103 #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand"
105 kRegisterInterfaceWithFixedUnit
= 0,
107 kRegisterAllInterfaces
109 #endif // !USE_REGISTRY_ENTRY_ID
111 #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo"
112 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
113 #define kSCNetworkInterfaceActive "Active"
115 #define MY_PLUGIN_NAME "InterfaceNamer"
116 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
118 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
119 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
121 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
122 #define WAIT_QUIET_TIMEOUT_DEFAULT 240.0
126 * "IONetworkStack" connect object used to "name" an interface.
128 static io_connect_t S_connect
= MACH_PORT_NULL
;
132 * An array of CFDictionary's representing the interfaces
133 * that have been identified and [need to be] named.
135 static CFMutableArrayRef S_dblist
= NULL
;
139 * An array of SCNetworkInterface's representing the
140 * interfaces that have been identified.
142 static CFMutableArrayRef S_iflist
= NULL
;
146 * IOServiceAddMatchingNotification object used to watch for
147 * new network interfaces.
149 static io_iterator_t S_iter
= MACH_PORT_NULL
;
153 * notification object for receiving IOKit notifications of
154 * new devices or state changes.
156 static IONotificationPortRef S_notify
= NULL
;
160 * An array of CFData(WatchedInfo) objects representing those
161 * pre-configured interfaces that have been connected to the
164 static CFMutableArrayRef S_preconfigured
= NULL
;
166 /* S_prev_active_list
167 * An array of CFDictionary's representing the previously
170 static CFMutableArrayRef S_prev_active_list
= NULL
;
174 * IOServiceAddInterestNotification object used to watch for
175 * IOKit matching to quiesce.
177 static io_object_t S_quiet
= MACH_PORT_NULL
;
181 * IOServiceAddMatchingNotification object used to watch for
182 * the availability of the "IONetworkStack" object.
184 static io_iterator_t S_stack
= MACH_PORT_NULL
;
188 * A dictionary containing Information about each network
189 * interface. For now, the key is the BSD name and the
190 * value is a CFNumber noting how long (in milliseconds)
191 * it took for the interface to be recognized/named.
193 static CFMutableDictionaryRef S_state
= NULL
;
197 * CFRunLoopTimer tracking how long we are willing to wait
198 * for IOKit matching to quiesce (IOKitWaitQuiet).
201 * time to wait for the IONetworkStack object to appear before timeout
204 * time to wait for the IOKit to quiesce (after the IONetworkStack is
207 static CFRunLoopTimerRef S_timer
= NULL
;
208 static double S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
209 static double S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
212 * Virtual network interface configuration
213 * S_prefs : SCPreferences to configuration
214 * S_bonds : most recently actived Bond configuration
215 * S_bridges : most recently actived Bridge configuration
216 * S_vlans : most recently actived VLAN configuration
218 static SCPreferencesRef S_prefs
= NULL
;
219 static CFArrayRef S_bonds
= NULL
;
220 static CFArrayRef S_bridges
= NULL
;
221 static CFArrayRef S_vlans
= NULL
;
228 __log_InterfaceNamer()
230 static os_log_t log
= NULL
;
233 log
= os_log_create("com.apple.SystemConfiguration", "InterfaceNamer");
241 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
246 now
= CFAbsoluteTimeGetCurrent();
247 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
248 CFDictionaryAddValue(dict
, key
, val
);
253 #define INTERFACES CFSTR("Interfaces")
254 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
256 static CFComparisonResult
257 if_unit_compare(const void *val1
, const void *val2
, void *context
)
259 #pragma unused(context)
260 CFComparisonResult res
;
266 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
267 CFSTR(kIOInterfaceType
));
268 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
269 CFSTR(kIOInterfaceType
));
270 res
= CFNumberCompare(type1
, type2
, NULL
);
271 if (res
!= kCFCompareEqualTo
) {
274 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
275 CFSTR(kIOInterfaceUnit
));
276 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
277 CFSTR(kIOInterfaceUnit
));
278 return (CFNumberCompare(unit1
, unit2
, NULL
));
282 writeInterfaceList(CFArrayRef if_list
)
285 CFStringRef new_model
;
286 CFStringRef old_model
;
287 SCPreferencesRef prefs
;
289 if (isA_CFArray(if_list
) == NULL
) {
293 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
295 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
299 cur_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
300 if (_SC_CFEqual(cur_list
, if_list
)) {
304 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
305 new_model
= _SC_hw_model(FALSE
);
306 if ((new_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
308 if ((old_model
!= NULL
) && (cur_list
!= NULL
)) {
311 // if interface list was created on other hardware
312 history
= CFStringCreateWithFormat(NULL
, NULL
,
316 SCPreferencesSetValue(prefs
, history
, cur_list
);
319 SC_log(LOG_NOTICE
, "Hardware model changed\n"
320 " created on \"%@\"\n"
326 SCPreferencesSetValue(prefs
, MODEL
, new_model
);
329 SCPreferencesSetValue(prefs
, INTERFACES
, if_list
);
331 if (!SCPreferencesCommitChanges(prefs
)) {
332 if (SCError() != EROFS
) {
333 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
344 static CFPropertyListRef
345 restoreNIPrefsFromBackup(SCPreferencesRef prefs
, CFStringRef current_model
)
347 CFPropertyListRef if_list
;
350 key
= CFStringCreateWithFormat(NULL
, 0, CFSTR("%@:%@"), INTERFACES
, current_model
);
351 if_list
= SCPreferencesGetValue(prefs
, key
);
352 if_list
= isA_CFArray(if_list
);
353 if (if_list
!= NULL
) {
354 /* Write the previously backed up Interface list for this hardware */
355 writeInterfaceList(if_list
);
357 /* Synchronize the prefs */
358 SCPreferencesSynchronize(prefs
);
360 /* Re-fetch the interface list */
361 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
362 if_list
= isA_CFArray(if_list
);
363 if (if_list
!= NULL
) {
364 /* We do not need the old interface list any more */
365 SCPreferencesRemoveValue(prefs
, key
);
366 if (!SCPreferencesCommitChanges(prefs
)) {
367 if (SCError() != EROFS
) {
368 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
379 static CF_RETURNS_RETAINED CFMutableArrayRef
383 CFStringRef old_model
;
384 CFMutableArrayRef plist
= NULL
;
385 SCPreferencesRef prefs
= NULL
;
387 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
389 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
393 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
394 if_list
= isA_CFArray(if_list
);
396 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
397 if (old_model
!= NULL
) {
398 CFStringRef new_model
;
400 new_model
= _SC_hw_model(FALSE
);
401 if (!_SC_CFEqual(old_model
, new_model
)) {
402 /* if interface list was created on other hardware,
403 Restore if a backup interface list is present */
404 if_list
= restoreNIPrefsFromBackup(prefs
, new_model
);
408 if (if_list
!= NULL
) {
410 CFIndex n
= CFArrayGetCount(if_list
);
412 plist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
413 for (i
= 0; i
< n
; i
++) {
414 CFDictionaryRef dict
;
416 dict
= CFArrayGetValueAtIndex(if_list
, i
);
417 if (isA_CFDictionary(dict
) &&
418 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceType
)) &&
419 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
420 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
421 CFArrayAppendValue(plist
, dict
);
432 static CF_RETURNS_RETAINED CFMutableArrayRef
433 previouslyActiveInterfaces()
435 CFMutableArrayRef active
;
439 if (S_dblist
== NULL
) {
443 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
445 n
= CFArrayGetCount(S_dblist
);
446 for (i
= 0; i
< n
; i
++) {
447 CFDictionaryRef if_dict
;
449 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
450 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
451 CFMutableDictionaryRef new_dict
;
453 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
454 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
455 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
456 CFArrayAppendValue(active
, new_dict
);
465 updateInterfaces(void);
472 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
),
473 kSCDynamicStoreDomainPlugin
);
474 (void)SCDynamicStoreSetValue(NULL
, key
, S_state
);
480 #if !TARGET_OS_IPHONE
482 updateBondInterfaceConfiguration(SCPreferencesRef prefs
)
484 CFArrayRef interfaces
;
486 interfaces
= SCBondInterfaceCopyAll(prefs
);
487 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
488 CFRelease(interfaces
);
492 if (_SC_CFEqual(S_bonds
, interfaces
)) {
494 if (interfaces
!= NULL
) CFRelease(interfaces
);
498 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
499 S_bonds
= interfaces
;
501 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
502 SC_log(LOG_NOTICE
, "_SCBondInterfaceUpdateConfiguration() failed: %s",
503 SCErrorString(SCError()));
508 #endif // !TARGET_OS_IPHONE
511 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs
)
513 CFArrayRef interfaces
;
515 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
516 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
517 CFRelease(interfaces
);
521 if (_SC_CFEqual(S_bridges
, interfaces
)) {
523 if (interfaces
!= NULL
) CFRelease(interfaces
);
527 if (S_bridges
!= NULL
) CFRelease(S_bridges
);
528 S_bridges
= interfaces
;
530 if (!_SCBridgeInterfaceUpdateConfiguration(prefs
)) {
531 SC_log(LOG_NOTICE
, "_SCBridgeInterfaceUpdateConfiguration() failed: %s",
532 SCErrorString(SCError()));
539 updateVLANInterfaceConfiguration(SCPreferencesRef prefs
)
541 CFArrayRef interfaces
;
543 interfaces
= SCVLANInterfaceCopyAll(prefs
);
544 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
545 CFRelease(interfaces
);
549 if (_SC_CFEqual(S_vlans
, interfaces
)) {
551 if (interfaces
!= NULL
) CFRelease(interfaces
);
555 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
556 S_vlans
= interfaces
;
558 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
559 SC_log(LOG_NOTICE
, "_SCVLANInterfaceUpdateConfiguration() failed: %s",
560 SCErrorString(SCError()));
567 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
568 SCPreferencesNotification notificationType
,
572 os_activity_t activity
;
574 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
578 activity
= os_activity_create("check/update virtual network interface configuration",
580 OS_ACTIVITY_FLAG_DEFAULT
);
581 os_activity_scope(activity
);
584 // if a new interface has been "named"
586 if (S_bonds
!= NULL
) {
590 if (S_bridges
!= NULL
) {
591 CFRelease(S_bridges
);
594 if (S_vlans
!= NULL
) {
600 #if !TARGET_OS_IPHONE
601 updateBondInterfaceConfiguration (prefs
);
602 #endif // !TARGET_OS_IPHONE
603 updateBridgeInterfaceConfiguration(prefs
);
604 updateVLANInterfaceConfiguration (prefs
);
606 // we are finished with current prefs, wait for changes
607 SCPreferencesSynchronize(prefs
);
609 os_release(activity
);
614 #if !TARGET_OS_EMBEDDED
617 updateBTPANInformation(const void *value
, void *context
)
619 #pragma unused(context)
621 CFDictionaryRef dict
= (CFDictionaryRef
)value
;
623 CFDictionaryRef info
;
626 if_name
= CFDictionaryGetValue(dict
, CFSTR(kIOBSDNameKey
));
627 if (!isA_CFString(if_name
)) {
632 info
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceInfo
));
633 if (!isA_CFDictionary(info
)) {
634 // if no SCNetworkInterface info
638 name
= CFDictionaryGetValue(info
, kSCPropUserDefinedName
);
639 if (!isA_CFString(name
) || !CFEqual(name
, CFSTR(BT_PAN_NAME
))) {
640 // if not BT-PAN interface
644 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Name
, if_name
);
646 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
647 if (isA_CFData(addr
)) {
648 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Mac
, addr
);
653 #endif // !TARGET_OS_EMBEDDED
655 static CFDictionaryRef
656 createInterfaceDict(SCNetworkInterfaceRef interface
)
658 CFMutableDictionaryRef new_if
;
661 new_if
= CFDictionaryCreateMutable(NULL
,
663 &kCFTypeDictionaryKeyCallBacks
,
664 &kCFTypeDictionaryValueCallBacks
);
666 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
668 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
672 val
= _SCNetworkInterfaceGetIOPath(interface
);
674 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
677 val
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
679 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceNamePrefix
), val
);
682 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
684 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
687 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
689 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
692 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
694 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
697 val
= SCNetworkInterfaceGetBSDName(interface
);
699 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
702 val
= SCNetworkInterfaceGetInterfaceType(interface
);
704 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
707 CFDictionarySetValue(new_if
,
709 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
711 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
716 static CFDictionaryRef
717 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
724 if (db_list
== NULL
) {
727 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
728 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
729 if (type
== NULL
|| addr
== NULL
) {
733 n
= CFArrayGetCount(db_list
);
734 for (i
= 0; i
< n
; i
++) {
736 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
739 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
740 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
741 if (t
== NULL
|| a
== NULL
)
744 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
754 static CFDictionaryRef
755 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
762 if (db_list
== NULL
) {
765 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
766 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
767 if (type
== NULL
|| unit
== NULL
) {
771 n
= CFArrayGetCount(db_list
);
772 for (i
= 0; i
< n
; i
++) {
773 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
777 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
778 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
779 if (t
== NULL
|| u
== NULL
) {
783 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
793 CFDictionaryRef match_info
;
794 CFStringRef match_type
;
795 CFBooleanRef match_builtin
;
796 CFMutableArrayRef matches
;
797 } matchContext
, *matchContextRef
;
799 static CF_RETURNS_RETAINED CFDictionaryRef
800 thinInterfaceInfo(CFDictionaryRef info
)
805 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
807 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
808 && (vid
== kIOUSBVendorIDAppleComputer
)) {
809 CFMutableDictionaryRef thin
;
811 // if this is an Apple USB device than we trust that
812 // the non-localized name will be correct.
813 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
814 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
815 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
816 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
820 return CFRetain(info
);
824 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
828 match
= _SC_CFEqual(known_info
, match_info
);
830 isA_CFDictionary(known_info
) &&
831 isA_CFDictionary(match_info
)) {
833 // if not an exact match, try thinning
834 known_info
= thinInterfaceInfo(known_info
);
835 match_info
= thinInterfaceInfo(match_info
);
836 match
= _SC_CFEqual(known_info
, match_info
);
837 if (known_info
!= NULL
) CFRelease(known_info
);
838 if (match_info
!= NULL
) CFRelease(match_info
);
845 matchKnown(const void *value
, void *context
)
847 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
848 matchContextRef match_context
= (matchContextRef
)context
;
850 // match interface type
852 CFStringRef known_type
;
854 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
855 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
860 // match SCNetworkInterfaceInfo
862 CFDictionaryRef known_info
;
864 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
865 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
870 // if requested, match [non-]builtin
871 if (match_context
->match_builtin
!= NULL
) {
872 CFBooleanRef known_builtin
;
874 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
875 if (!isA_CFBoolean(known_builtin
)) {
876 known_builtin
= kCFBooleanFalse
;
878 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
883 // if we have a match
884 if (match_context
->matches
== NULL
) {
885 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
887 CFArrayAppendValue(match_context
->matches
, known_dict
);
893 matchUnnamed(const void *value
, void *context
)
895 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
896 matchContextRef match_context
= (matchContextRef
)context
;
898 if (match_context
->matches
== NULL
) {
902 // match interface type
904 CFStringRef known_type
;
906 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
907 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
912 // match SCNetworkInterfaceInfo
914 CFDictionaryRef known_info
;
917 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
918 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
919 if (known_info
!= NULL
) CFRelease(known_info
);
925 // if requested, match [non-]builtin
926 if (match_context
->match_builtin
!= NULL
) {
927 CFBooleanRef known_builtin
;
929 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
931 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
936 // if we have a match
937 CFRelease(match_context
->matches
);
938 match_context
->matches
= NULL
;
944 interfaceExists(CFStringRef prefix
, CFNumberRef unit
)
946 Boolean found
= FALSE
;
947 CFDictionaryRef match_dict
;
948 CFStringRef match_keys
[2];
949 CFTypeRef match_vals
[2];
950 CFDictionaryRef matching
;
954 io_registry_entry_t entry
= MACH_PORT_NULL
;
955 io_iterator_t iterator
= MACH_PORT_NULL
;
957 mach_port_t masterPort
= MACH_PORT_NULL
;
959 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
960 if (kr
!= KERN_SUCCESS
) {
961 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
965 // look for kIONetworkInterface with matching prefix and unit
966 match_keys
[0] = CFSTR(kIOInterfaceNamePrefix
);
967 match_vals
[0] = prefix
;
968 match_keys
[1] = CFSTR(kIOInterfaceUnit
);
969 match_vals
[1] = unit
;
970 match_dict
= CFDictionaryCreate(NULL
,
971 (const void **)match_keys
,
972 (const void **)match_vals
,
974 &kCFTypeDictionaryKeyCallBacks
,
975 &kCFTypeDictionaryValueCallBacks
);
977 match_keys
[0] = CFSTR(kIOProviderClassKey
);
978 match_vals
[0] = CFSTR(kIONetworkInterfaceClass
);
979 match_keys
[1] = CFSTR(kIOPropertyMatchKey
);
980 match_vals
[1] = match_dict
;
981 matching
= CFDictionaryCreate(NULL
,
982 (const void **)match_keys
,
983 (const void **)match_vals
,
984 sizeof(match_keys
)/sizeof(match_keys
[0]),
985 &kCFTypeDictionaryKeyCallBacks
,
986 &kCFTypeDictionaryValueCallBacks
);
987 CFRelease(match_dict
);
989 // note: the "matching" dictionary will be consumed by the following
990 kr
= IOServiceGetMatchingServices(masterPort
, matching
, &iterator
);
991 if ((kr
!= kIOReturnSuccess
) || (iterator
== MACH_PORT_NULL
)) {
996 entry
= IOIteratorNext(iterator
);
997 if (entry
== MACH_PORT_NULL
) {
1005 if (masterPort
!= MACH_PORT_NULL
) {
1006 mach_port_deallocate(mach_task_self(), masterPort
);
1008 if (entry
!= MACH_PORT_NULL
) {
1009 IOObjectRelease(entry
);
1011 if (iterator
!= MACH_PORT_NULL
) {
1012 IOObjectRelease(iterator
);
1019 * lookupMatchingInterface
1021 * Looks at the interfaces that have already been [or need to be] named with
1022 * the goal of allowing a system using a single network interface/adaptor of
1023 * a given type (vendor, model, ...) to not care about the specific adaptor
1024 * that is used (i.e. swapping dongle's is OK). Once a system has had more
1025 * than one interface/adaptor connected at the same time than we assume that
1026 * the network configuration is being setup for multi-homing that should be
1029 * If no matches are found or if more than one match is found, return NULL.
1030 * If a single match is found, return the match.
1032 static CFDictionaryRef
1033 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
1034 CFArrayRef db_list
, // already named
1035 CFArrayRef if_list
, // to be named
1036 CFIndex if_list_index
,
1037 CFBooleanRef builtin
)
1039 CFStringRef if_type
;
1040 CFDictionaryRef match
= NULL
;
1041 matchContext match_context
;
1043 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
1044 if (if_type
== NULL
) {
1048 match_context
.match_type
= if_type
;
1049 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
1050 match_context
.match_builtin
= builtin
;
1051 match_context
.matches
= NULL
;
1053 // check for matches to interfaces that have already been named
1054 // ... and append each match that we find to match_context.matches
1055 if (db_list
!= NULL
) {
1056 CFArrayApplyFunction(db_list
,
1057 CFRangeMake(0, CFArrayGetCount(db_list
)),
1062 // check for matches to interfaces that will be named
1063 // ... and CFRelease match_context.matches if we find another network
1064 // interface of the same type that also needs to be named
1065 if (if_list
!= NULL
) {
1066 CFIndex if_list_count
;
1068 if_list_count
= CFArrayGetCount(if_list
);
1069 if (if_list_index
< if_list_count
) {
1070 CFArrayApplyFunction(if_list
,
1071 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
1077 // check if we have a single match
1078 if (match_context
.matches
!= NULL
) {
1079 if (CFArrayGetCount(match_context
.matches
) == 1) {
1080 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
1082 CFRelease(match_context
.matches
);
1085 if (match
!= NULL
) {
1086 Boolean active
= TRUE
;
1089 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
1090 if (isA_CFString(name
)) {
1094 prefix
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceNamePrefix
));
1095 unit
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceUnit
));
1096 if (isA_CFString(prefix
) && isA_CFNumber(unit
)) {
1097 if (!interfaceExists(prefix
, unit
)) {
1108 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
1113 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
)
1116 CFDictionaryRef if_dict
;
1117 CFStringRef if_name
;
1118 CFNumberRef if_type
;
1119 CFNumberRef if_unit
;
1120 CFIndex n
= CFArrayGetCount(db_list
);
1121 CFComparisonResult res
;
1123 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1124 if (if_name
!= NULL
) {
1125 addTimestamp(S_state
, if_name
);
1128 if_dict
= createInterfaceDict(interface
);
1129 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1130 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1131 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
1136 for (i
= 0; i
< n
; i
++) {
1137 CFNumberRef db_type
;
1138 CFNumberRef db_unit
;
1139 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
1141 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1142 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1143 res
= CFNumberCompare(if_type
, db_type
, NULL
);
1144 if (res
== kCFCompareLessThan
1145 || (res
== kCFCompareEqualTo
1146 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
1147 == kCFCompareLessThan
))) {
1148 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
1154 CFArrayAppendValue(S_dblist
, if_dict
);
1156 #if !TARGET_OS_EMBEDDED
1157 updateBTPANInformation(if_dict
, NULL
);
1158 #endif // !TARGET_OS_EMBEDDED
1165 replaceInterface(SCNetworkInterfaceRef interface
)
1170 if (S_dblist
== NULL
) {
1171 S_dblist
= CFArrayCreateMutable(NULL
, 0,
1172 &kCFTypeArrayCallBacks
);
1174 // remove any dict that has our type/addr
1175 while (lookupInterfaceByAddress(S_dblist
, interface
, &where
) != NULL
) {
1176 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1179 // remove any dict that has the same type/unit
1180 while (lookupInterfaceByUnit(S_dblist
, interface
, &where
) != NULL
) {
1181 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1184 insertInterface(S_dblist
, interface
);
1187 SC_log(LOG_ERR
, "Multiple interfaces updated (n = %d, %@)", n
, interface
);
1194 getHighestUnitForType(CFNumberRef if_type
)
1198 CFNumberRef ret_unit
= NULL
;
1200 if (S_dblist
== NULL
) {
1204 n
= CFArrayGetCount(S_dblist
);
1205 for (i
= 0; i
< n
; i
++) {
1206 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1209 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1210 if (CFEqual(type
, if_type
)) {
1213 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1214 if (ret_unit
== NULL
1215 || (CFNumberCompare(unit
, ret_unit
, NULL
)
1216 == kCFCompareGreaterThan
)) {
1226 * Function: ensureInterfaceHasUnit
1228 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1229 * release the interface and return NULL.
1231 static SCNetworkInterfaceRef
1232 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if
)
1235 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if
) == NULL
) {
1242 #ifdef USE_REGISTRY_ENTRY_ID
1243 static kern_return_t
1244 registerInterfaceWithIORegistryEntryID(io_connect_t connect
,
1250 CFMutableDictionaryRef dict
;
1254 dict
= CFDictionaryCreateMutable(NULL
, 0,
1255 &kCFTypeDictionaryKeyCallBacks
,
1256 &kCFTypeDictionaryValueCallBacks
);
1257 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1258 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1260 data
= CFDataCreate(NULL
, (void *) &entryID
, sizeof(entryID
));
1261 CFDictionarySetValue(dict
, CFSTR(kIORegistryEntryIDKey
), data
);
1263 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1264 kr
= IOConnectSetCFProperties(connect
, dict
);
1269 static SCNetworkInterfaceRef
1270 copyInterfaceForIORegistryEntryID(uint64_t entryID
)
1272 io_registry_entry_t entry
= MACH_PORT_NULL
;
1273 SCNetworkInterfaceRef interface
= NULL
;
1274 io_iterator_t iterator
= MACH_PORT_NULL
;
1276 mach_port_t masterPort
= MACH_PORT_NULL
;
1278 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1279 if (kr
!= KERN_SUCCESS
) {
1280 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1284 kr
= IOServiceGetMatchingServices(masterPort
,
1285 IORegistryEntryIDMatching(entryID
),
1287 if ((kr
!= KERN_SUCCESS
) || (iterator
== MACH_PORT_NULL
)) {
1288 SC_log(LOG_NOTICE
, "IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d",
1295 entry
= IOIteratorNext(iterator
);
1296 if (entry
== MACH_PORT_NULL
) {
1297 SC_log(LOG_NOTICE
, "IORegistryEntryIDMatching(0x%llx) failed", entryID
);
1301 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1304 if (masterPort
!= MACH_PORT_NULL
) {
1305 mach_port_deallocate(mach_task_self(), masterPort
);
1307 if (entry
!= MACH_PORT_NULL
) {
1308 IOObjectRelease(entry
);
1310 if (iterator
!= MACH_PORT_NULL
) {
1311 IOObjectRelease(iterator
);
1316 static SCNetworkInterfaceRef
1317 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID
)
1319 SCNetworkInterfaceRef net_if
;
1321 net_if
= copyInterfaceForIORegistryEntryID(entryID
);
1322 return (ensureInterfaceHasUnit(net_if
));
1325 #else // USE_REGISTRY_ENTRY_ID
1327 * Function: registerInterface
1329 * Register a single interface with the given service path to the
1330 * data link layer (BSD), using the specified unit number.
1332 static kern_return_t
1333 registerInterfaceWithIOServicePath(io_connect_t connect
,
1338 CFMutableDictionaryRef dict
;
1342 dict
= CFDictionaryCreateMutable(NULL
, 0,
1343 &kCFTypeDictionaryKeyCallBacks
,
1344 &kCFTypeDictionaryValueCallBacks
);
1345 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1346 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1348 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1349 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1350 kr
= IOConnectSetCFProperties(connect
, dict
);
1355 static SCNetworkInterfaceRef
1356 copyInterfaceForIOKitPath(CFStringRef if_path
)
1358 io_registry_entry_t entry
= MACH_PORT_NULL
;
1359 SCNetworkInterfaceRef interface
= NULL
;
1361 mach_port_t masterPort
= MACH_PORT_NULL
;
1364 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1365 if (kr
!= KERN_SUCCESS
) {
1366 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1369 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1370 entry
= IORegistryEntryFromPath(masterPort
, path
);
1371 if (entry
== MACH_PORT_NULL
) {
1372 SC_log(LOG_NOTICE
, "IORegistryEntryFromPath(%@) failed", if_path
);
1376 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1379 if (masterPort
!= MACH_PORT_NULL
) {
1380 mach_port_deallocate(mach_task_self(), masterPort
);
1382 if (entry
!= MACH_PORT_NULL
) {
1383 IOObjectRelease(entry
);
1389 static SCNetworkInterfaceRef
1390 copyNamedInterfaceForIOKitPath(CFStringRef if_path
)
1392 SCNetworkInterfaceRef net_if
;
1394 net_if
= copyInterfaceForIOKitPath(if_path
);
1395 return (ensureInterfaceHasUnit(net_if
));
1398 #endif // USE_REGISTRY_ENTRY_ID
1401 displayInterface(SCNetworkInterfaceRef interface
)
1408 name
= SCNetworkInterfaceGetBSDName(interface
);
1409 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1410 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1411 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1413 SC_log(LOG_INFO
, " %s%@%sType: %@, %s%@%sMAC address: %@",
1414 (name
!= NULL
) ? "BSD Name: " : "",
1415 (name
!= NULL
) ? name
: CFSTR(""),
1416 (name
!= NULL
) ? ", " : "",
1418 (unit
!= NULL
) ? "Unit: " : "",
1419 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1420 (unit
!= NULL
) ? ", " : "",
1425 builtinAvailable(SCNetworkInterfaceRef interface
, // new interface
1426 CFNumberRef if_unit
) // desired unit
1429 CFNumberRef if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1432 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1433 for (i
= 0; i
< n
; i
++) {
1434 CFStringRef if_path
;
1435 CFDictionaryRef known_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1436 CFStringRef known_path
;
1437 CFNumberRef known_type
;
1438 CFNumberRef known_unit
;
1440 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceType
));
1441 if (!_SC_CFEqual(if_type
, known_type
)) {
1442 continue; // if not the same interface type
1445 known_unit
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceUnit
));
1446 if (!_SC_CFEqual(if_unit
, known_unit
)) {
1447 continue; // if not the same interface unit
1450 if_path
= _SCNetworkInterfaceGetIOPath(interface
);
1451 known_path
= CFDictionaryGetValue(known_dict
, CFSTR(kIOPathMatchKey
));
1452 if (!_SC_CFEqual(if_path
, known_path
)) {
1453 // if different IORegistry path
1457 // if same type, same unit, same path
1461 // if interface type/unit not found
1466 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
1471 for (i
= 0; i
< last
; i
++) {
1472 SCNetworkInterfaceRef builtin_if
;
1473 CFNumberRef builtin_type
;
1475 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1476 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
1477 if (CFEqual(if_type
, builtin_type
)) {
1478 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1479 n
++; // if built-in interface
1489 #pragma mark Interface monitoring (e.g. watch for "detach")
1492 typedef struct WatchedInfo
*WatchedInfoRef
;
1494 typedef void (*InterfaceUpdateCallBack
) (
1496 natural_t messageType
,
1497 void *messageArgument
1501 SCNetworkInterfaceRef interface
;
1502 io_service_t interface_node
;
1503 io_object_t notification
;
1504 InterfaceUpdateCallBack callback
;
1508 watcherRelease(CFDataRef watched
);
1511 updateWatchedInterface(void *refCon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
1513 #pragma unused(service)
1514 #pragma unused(messageArgument)
1515 switch (messageType
) {
1516 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
1517 CFDataRef watched
= (CFDataRef
)refCon
;
1518 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1521 watchedInfo
->callback(watched
, messageType
, messageArgument
);
1522 watcherRelease(watched
);
1535 watcherCreate(SCNetworkInterfaceRef interface
, InterfaceUpdateCallBack callback
)
1538 io_service_t interface_node
;
1540 CFDictionaryRef matching
;
1541 CFMutableDataRef watched
;
1542 WatchedInfo
*watchedInfo
;
1544 // get the IORegistry node
1545 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
1546 matching
= IORegistryEntryIDMatching(entryID
);
1547 interface_node
= IOServiceGetMatchingService(kIOMasterPortDefault
, matching
);
1548 if (interface_node
== MACH_PORT_NULL
) {
1549 // interface no longer present
1553 // create [locked] interface watcher
1554 watched
= CFDataCreateMutable(NULL
, sizeof(WatchedInfo
));
1555 CFDataSetLength(watched
, sizeof(WatchedInfo
));
1556 watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1557 bzero(watchedInfo
, sizeof(*watchedInfo
));
1560 watchedInfo
->interface
= CFRetain(interface
);
1562 // ... and the interface node
1563 watchedInfo
->interface_node
= interface_node
;
1565 // ... and set the callback
1566 watchedInfo
->callback
= callback
;
1568 kr
= IOServiceAddInterestNotification(S_notify
, // IONotificationPortRef
1569 watchedInfo
->interface_node
, // io_service_t
1570 kIOGeneralInterest
, // interestType
1571 updateWatchedInterface
, // IOServiceInterestCallback
1572 (void *)watched
, // refCon
1573 &watchedInfo
->notification
); // notification
1574 if (kr
!= KERN_SUCCESS
) {
1576 "IOServiceAddInterestNotification() failed, kr = 0x%x",
1578 watcherRelease(watched
);
1587 watcherRelease(CFDataRef watched
)
1589 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1592 if (watchedInfo
->notification
!= IO_OBJECT_NULL
) {
1593 IOObjectRelease(watchedInfo
->notification
);
1594 watchedInfo
->notification
= IO_OBJECT_NULL
;
1597 // release interface node
1598 if (watchedInfo
->interface_node
!= IO_OBJECT_NULL
) {
1599 IOObjectRelease(watchedInfo
->interface_node
);
1600 watchedInfo
->interface_node
= IO_OBJECT_NULL
;
1603 // release interface
1604 if (watchedInfo
->interface
!= NULL
) {
1605 CFRelease(watchedInfo
->interface
);
1606 watchedInfo
->interface
= NULL
;
1614 #pragma mark Locked device support [macOS]
1617 #if !TARGET_OS_IPHONE
1619 blockNewInterfaces()
1621 static boolean_t allow
= TRUE
;
1622 static dispatch_once_t once
;
1624 dispatch_once(&once
, ^{
1625 allow
= InterfaceNamerControlPrefsAllowNewInterfaces();
1635 CFArrayRef console_sessions
;
1636 boolean_t locked
= FALSE
;
1637 io_registry_entry_t root
;
1639 root
= IORegistryGetRootEntry(kIOMasterPortDefault
);
1640 console_sessions
= IORegistryEntryCreateCFProperty(root
,
1641 CFSTR(kIOConsoleUsersKey
),
1644 if (isA_CFArray(console_sessions
)) {
1647 n
= CFArrayGetCount(console_sessions
);
1648 for (CFIndex i
= 0; i
< n
; i
++) {
1649 CFBooleanRef isLocked
;
1650 CFBooleanRef isLoginDone
;
1651 CFBooleanRef onConsole
;
1652 CFDictionaryRef session
;
1654 session
= CFArrayGetValueAtIndex(console_sessions
, i
);
1655 if (!isA_CFDictionary(session
)) {
1656 // if not dictionary
1660 if (!CFDictionaryGetValueIfPresent(session
,
1661 CFSTR(kIOConsoleSessionOnConsoleKey
),
1662 (const void **)&onConsole
) ||
1663 !isA_CFBoolean(onConsole
) ||
1664 !CFBooleanGetValue(onConsole
)) {
1665 // if not "on console" session
1670 CFDictionaryGetValueIfPresent(session
,
1671 CFSTR(kIOConsoleSessionLoginDoneKey
),
1672 (const void **)&isLoginDone
) &&
1673 isA_CFBoolean(isLoginDone
) &&
1674 !CFBooleanGetValue(isLoginDone
)) {
1676 SC_log(LOG_INFO
, "multiple sessions, console @ loginwindow");
1681 if (CFDictionaryGetValueIfPresent(session
,
1682 CFSTR(kIOConsoleSessionScreenIsLockedKey
),
1683 (const void **)&isLocked
) &&
1684 isA_CFBoolean(isLocked
) &&
1685 CFBooleanGetValue(isLocked
)) {
1687 SC_log(LOG_INFO
, "console screen locked");
1694 SC_log(LOG_INFO
, "console not locked");
1698 if (console_sessions
!= NULL
) {
1699 CFRelease(console_sessions
);
1701 IOObjectRelease(root
);
1705 #endif // !TARGET_OS_IPHONE
1709 #pragma mark Interface naming
1712 static __inline__ boolean_t
1715 return (S_quiet
== MACH_PORT_NULL
);
1719 nameInterfaces(CFMutableArrayRef if_list
)
1722 CFIndex n
= CFArrayGetCount(if_list
);
1724 for (i
= 0; i
< n
; i
++) {
1726 SCNetworkInterfaceRef interface
;
1727 SCNetworkInterfaceRef new_interface
;
1733 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1734 path
= _SCNetworkInterfaceGetIOPath(interface
);
1735 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1736 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1737 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
1740 CFStringRef if_name
;
1742 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1743 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
1744 SC_log(LOG_INFO
, "Interface already has a unit number");
1745 displayInterface(interface
);
1748 // update the list of interfaces that were previously named
1749 if ((S_prev_active_list
!= NULL
)
1750 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
1751 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1754 replaceInterface(interface
);
1756 CFDictionaryRef dbdict
;
1757 boolean_t is_builtin
;
1761 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
1762 if (dbdict
!= NULL
) {
1763 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1766 SC_log(LOG_INFO
, "Interface assigned unit %@ (from database)", unit
);
1769 if ((dbdict
== NULL
) && !isQuiet()) {
1770 // if new interface, wait until quiet before naming
1771 addTimestamp(S_state
, path
);
1775 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
1777 if (dbdict
== NULL
) {
1778 dbdict
= lookupMatchingInterface(interface
,
1782 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
1784 #if !TARGET_OS_IPHONE
1787 blockNewInterfaces() &&
1788 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
1789 isConsoleLocked()) {
1792 // if new (but matching) interface and console locked, ignore
1793 SC_log(LOG_NOTICE
, "Console locked, network interface* ignored");
1794 SC_log(LOG_INFO
, " path = %@", path
);
1795 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
1797 SC_log(LOG_INFO
, " addr = %@", addr
);
1801 #endif // !TARGET_OS_IPHONE
1803 if (dbdict
!= NULL
) {
1804 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1807 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database)", unit
);
1811 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
1812 // update the list of interfaces that were previously named
1813 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
1814 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
1816 if (where
!= kCFNotFound
) {
1817 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1821 if (dbdict
== NULL
) {
1825 // built-in interface, try to use the reserved slots
1826 next_unit
= builtinCount(if_list
, i
, type
);
1828 // But, before claiming a reserved slot we check to see if the
1829 // slot had previously been used. If so, and if the slot had been
1830 // assigned to the same type of interface, then we will perform a
1831 // replacement (e.g. assume that this was a board swap). But, if
1832 // the new interface is a different type then we assume that the
1833 // built-in configuration has changed and allocate a new unit from
1834 // the non-reserved slots.
1836 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1837 if (!builtinAvailable(interface
, unit
)) {
1838 // if [built-in] unit not available
1839 SC_log(LOG_INFO
, "Interface not assigned [built-in] unit %@", unit
);
1845 #if !TARGET_OS_IPHONE
1848 blockNewInterfaces() &&
1849 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
1850 isConsoleLocked()) {
1853 // if new interface and console locked, ignore
1854 SC_log(LOG_NOTICE
, "Console locked, network interface ignored");
1855 SC_log(LOG_INFO
, " path = %@", path
);
1856 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
1858 SC_log(LOG_INFO
, " addr = %@", addr
);
1862 #endif // !TARGET_OS_IPHONE
1865 // not built-in (or built-in unit not available), allocate from
1866 // the non-reserved slots
1867 next_unit
= builtinCount(if_list
, n
, type
);
1869 unit
= getHighestUnitForType(type
);
1873 CFNumberGetValue(unit
, kCFNumberIntType
, &high_unit
);
1874 if (high_unit
>= next_unit
) {
1875 next_unit
= high_unit
+ 1;
1879 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1882 SC_log(LOG_INFO
, "Interface assigned unit %@ (%s)",
1884 is_builtin
? "built-in" : "next available");
1889 #ifdef USE_REGISTRY_ENTRY_ID
1890 kr
= registerInterfaceWithIORegistryEntryID(S_connect
,
1893 (dbdict
== NULL
) ? kIONetworkStackRegisterInterfaceWithLowestUnit
1894 : kIONetworkStackRegisterInterfaceWithUnit
);
1895 new_interface
= copyNamedInterfaceForIORegistryEntryID(entryID
);
1896 #else // USE_REGISTRY_ENTRY_ID
1897 kr
= registerInterfaceWithIOServicePath(S_connect
,
1900 (dbdict
== NULL
) ? kRegisterInterface
1901 : kRegisterInterfaceWithFixedUnit
);
1902 new_interface
= copyNamedInterfaceForIOKitPath(path
);
1903 #endif // USE_REGISTRY_ENTRY_ID
1904 if (new_interface
== NULL
) {
1905 const char *signature
;
1907 signature
= (dbdict
== NULL
) ? "failed to name new interface"
1908 : "failed to name known interface";
1910 SC_log(LOG_NOTICE
, "%s, kr=0x%x\n"
1920 displayInterface(interface
);
1922 if ((dbdict
!= NULL
) && (retries
++ < 5)) {
1923 usleep(50 * 1000); // sleep 50ms between attempts
1928 CFNumberRef new_unit
;
1931 SC_log(LOG_INFO
, "%s interface named after %d %s\n"
1934 (dbdict
== NULL
) ? "New" : "Known",
1936 (retries
== 1) ? "try" : "tries",
1940 #ifdef SHOW_NAMING_FAILURE
1941 str
= CFStringCreateWithFormat(NULL
,
1943 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
1944 (dbdict
== NULL
) ? "New" : "Known",
1946 (retries
== 1) ? "try" : "tries",
1948 CFUserNotificationDisplayNotice(0,
1949 kCFUserNotificationStopAlertLevel
,
1954 CFSTR("Please report repeated failures."),
1957 #endif // SHOW_NAMING_FAILURE
1960 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
1961 if (!CFEqual(unit
, new_unit
)) {
1962 SC_log(LOG_INFO
, "interface type %@ assigned unit %@ instead of %@",
1963 type
, new_unit
, unit
);
1966 displayInterface(new_interface
);
1968 // update if_list (with the interface name & unit)
1969 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
1970 CFRelease(new_interface
);
1971 interface
= new_interface
; // if_list holds the reference
1973 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
1976 // update the list of [built-in] interfaces that were previously named
1977 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
1978 SC_log(LOG_DEBUG
, " and updated database (new address)");
1979 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1982 replaceInterface(interface
);
1990 #if !TARGET_OS_IPHONE
1994 static Boolean isRecovery
= FALSE
;
1995 static dispatch_once_t once
;
1998 * We check to see if the UserEventAgent daemon is present. If not, then
1999 * we are most likely booted into the Recovery OS with no "SCMonitor"
2000 * [UserEventAgent] plugin.
2002 dispatch_once(&once
, ^{
2003 if ((access("/usr/libexec/UserEventAgent", X_OK
) == -1) && (errno
== ENOENT
)) {
2013 updateNetworkConfiguration(CFArrayRef if_list
)
2015 Boolean do_commit
= FALSE
;
2018 SCPreferencesRef prefs
= NULL
;
2019 SCNetworkSetRef set
= NULL
;
2021 prefs
= SCPreferencesCreate(NULL
, CFSTR("InterfaceNamer:updateNetworkConfiguration"), NULL
);
2023 set
= SCNetworkSetCopyCurrent(prefs
);
2025 SC_log(LOG_INFO
, "No current set, adding default");
2026 set
= _SCNetworkSetCreateDefault(prefs
);
2028 SC_log(LOG_NOTICE
, "_SCNetworkSetCreateDefault() failed: %s", SCErrorString(SCError()));
2033 n
= (if_list
!= NULL
) ? CFArrayGetCount(if_list
) : 0;
2034 for (i
= 0; i
< n
; i
++) {
2035 SCNetworkInterfaceRef interface
;
2037 interface
= CFArrayGetValueAtIndex(if_list
, i
);
2038 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set
, interface
)) {
2039 SC_log(LOG_INFO
, "adding default configuration for %@",
2040 SCNetworkInterfaceGetBSDName(interface
));
2048 ok
= SCPreferencesCommitChanges(prefs
);
2050 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
2054 ok
= SCPreferencesApplyChanges(prefs
);
2056 SC_log(LOG_NOTICE
, "SCPreferencesApplyChanges() failed: %s", SCErrorString(SCError()));
2068 if (prefs
!= NULL
) {
2075 #endif // !TARGET_OS_IPHONE
2078 sharePreconfigured()
2082 n
= (S_preconfigured
!= NULL
) ? CFArrayGetCount(S_preconfigured
) : 0;
2084 CFMutableArrayRef preconfigured
;
2086 preconfigured
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2088 for (CFIndex i
= 0; i
< n
; i
++) {
2089 CFStringRef bsdName
;
2090 CFDataRef watched
= CFArrayGetValueAtIndex(S_preconfigured
, i
);
2091 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2093 bsdName
= SCNetworkInterfaceGetBSDName(watchedInfo
->interface
);
2094 CFArrayAppendValue(preconfigured
, bsdName
);
2097 CFDictionarySetValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
, preconfigured
);
2098 CFRelease(preconfigured
);
2100 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
);
2109 preconfiguredInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2111 Boolean updated
= FALSE
;
2112 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2114 #pragma unused(messageArgument)
2115 switch (messageType
) {
2116 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2117 SC_log(LOG_INFO
, "[pre-configured] interface removed: %@",
2118 SCNetworkInterfaceGetBSDName(watchedInfo
->interface
));
2120 if (S_preconfigured
!= NULL
) {
2122 CFIndex n
= CFArrayGetCount(S_preconfigured
);
2124 i
= CFArrayGetFirstIndexOfValue(S_preconfigured
, CFRangeMake(0, n
), watched
);
2125 if (i
!= kCFNotFound
) {
2126 CFArrayRemoveValueAtIndex(S_preconfigured
, i
);
2127 if (CFArrayGetCount(S_preconfigured
) == 0) {
2128 CFRelease(S_preconfigured
);
2129 S_preconfigured
= NULL
;
2143 sharePreconfigured();
2150 updatePreConfiguredInterfaces(CFArrayRef interfaces
)
2153 Boolean updated
= FALSE
;
2155 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
2156 for (CFIndex i
= 0; i
< n
; i
++) {
2157 SCNetworkInterfaceRef interface
;
2159 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2160 if (_SCNetworkInterfaceIsApplePreconfigured(interface
)) {
2163 watched
= watcherCreate(interface
, preconfiguredInterfaceUpdated
);
2164 if (watched
!= NULL
) {
2165 SC_log(LOG_INFO
, "watching [pre-configured] interface: %@",
2166 SCNetworkInterfaceGetBSDName(interface
));
2168 if (S_preconfigured
== NULL
) {
2169 S_preconfigured
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2171 CFArrayAppendValue(S_preconfigured
, watched
);
2178 sharePreconfigured();
2187 if (S_connect
== MACH_PORT_NULL
) {
2188 // if we don't have the "IONetworkStack" connect object
2192 if (S_iflist
!= NULL
) {
2195 n
= CFArrayGetCount(S_iflist
);
2197 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
2199 nameInterfaces(S_iflist
);
2203 * Update the list of [Apple] pre-configured interfaces
2205 updatePreConfiguredInterfaces(S_iflist
);
2209 * The registry [matching] has quiesced so let's
2210 * - save the DB with the interfaces that have been named
2211 * - update the VLAN/BOND configuration
2212 * - tell everyone that we've finished (at least for now)
2213 * - log those interfaces which are no longer present
2214 * in the HW config (or have yet to show up).
2216 writeInterfaceList(S_dblist
);
2217 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
2219 #if !TARGET_OS_IPHONE
2220 if (isRecoveryOS()) {
2222 * We are most likely booted into the Recovery OS with no "SCMonitor"
2223 * UserEventAgent plugin running so let's make sure we update the
2224 * network configuration for new interfaces.
2226 updateNetworkConfiguration(S_iflist
);
2228 #endif // !TARGET_OS_IPHONE
2232 if (S_iflist
!= NULL
) {
2233 CFRelease(S_iflist
);
2237 if (S_prev_active_list
!= NULL
) {
2241 n
= CFArrayGetCount(S_prev_active_list
);
2243 SC_log(LOG_INFO
, "Interface%s not [yet] active",
2244 (n
> 1) ? "s" : "");
2246 for (i
= 0; i
< n
; i
++) {
2247 CFDictionaryRef if_dict
;
2252 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
2253 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
2254 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
2255 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
2256 SC_log(LOG_INFO
, " %s%@%sType: %@, Unit: %@",
2257 (name
!= NULL
) ? "BSD Name: " : "",
2258 (name
!= NULL
) ? name
: CFSTR(""),
2259 (name
!= NULL
) ? ", " : "",
2264 CFRelease(S_prev_active_list
);
2265 S_prev_active_list
= NULL
;
2268 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
2270 * if we've named all of the interfaces that
2271 * were used during the previous boot.
2273 addTimestamp(S_state
, CFSTR("*RELEASE*"));
2274 SC_log(LOG_INFO
, "last boot interfaces have been named");
2276 CFRelease(S_prev_active_list
);
2277 S_prev_active_list
= NULL
;
2285 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
2287 #pragma unused(refcon)
2288 os_activity_t activity
;
2291 activity
= os_activity_create("process new network interface",
2292 OS_ACTIVITY_CURRENT
,
2293 OS_ACTIVITY_FLAG_DEFAULT
);
2294 os_activity_scope(activity
);
2296 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
2297 SCNetworkInterfaceRef interface
;
2299 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
2300 if (interface
!= NULL
) {
2301 if (S_iflist
== NULL
) {
2302 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2304 CFArrayAppendValue(S_iflist
, interface
);
2305 CFRelease(interface
);
2307 IOObjectRelease(obj
);
2312 os_release(activity
);
2318 * Function: stackCallback
2320 * Get a reference to the single IONetworkStack object instance in
2321 * the kernel. Naming requests must be sent to this object, which is
2322 * attached as a client to all network interface objects in the system.
2324 * Call IOObjectRelease on the returned object.
2327 stackCallback(void *refcon
, io_iterator_t iter
)
2329 #pragma unused(refcon)
2330 os_activity_t activity
;
2334 activity
= os_activity_create("process IONetworkStack",
2335 OS_ACTIVITY_CURRENT
,
2336 OS_ACTIVITY_FLAG_DEFAULT
);
2337 os_activity_scope(activity
);
2339 stack
= IOIteratorNext(iter
);
2340 if (stack
== MACH_PORT_NULL
) {
2344 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
2345 if (kr
!= KERN_SUCCESS
) {
2346 SC_log(LOG_ERR
, "IOServiceOpen returned 0x%x", kr
);
2350 addTimestamp(S_state
, CFSTR("*STACK*"));
2351 SC_log(LOG_INFO
, "IONetworkStack found");
2353 if (S_stack
!= MACH_PORT_NULL
) {
2354 IOObjectRelease(S_stack
);
2355 S_stack
= MACH_PORT_NULL
;
2358 if ((S_timer
!= NULL
) && CFRunLoopTimerIsValid(S_timer
)) {
2359 // With the IONetworkStack object now available we can
2360 // reset (shorten?) the time we are willing to wait for
2361 // IOKit to quiesce.
2362 CFRunLoopTimerSetNextFireDate(S_timer
,
2363 CFAbsoluteTimeGetCurrent() + S_quiet_timeout
);
2370 if (stack
!= MACH_PORT_NULL
) {
2371 IOObjectRelease(stack
);
2374 os_release(activity
);
2380 quietCallback(void *refcon
,
2381 io_service_t service
,
2382 natural_t messageType
,
2383 void *messageArgument
)
2385 #pragma unused(refcon)
2386 #pragma unused(service)
2387 os_activity_t activity
;
2389 if (messageArgument
!= NULL
) {
2394 activity
= os_activity_create("process IOKit quiet",
2395 OS_ACTIVITY_CURRENT
,
2396 OS_ACTIVITY_FLAG_DEFAULT
);
2397 os_activity_scope(activity
);
2399 if (messageType
== kIOMessageServiceBusyStateChange
) {
2400 addTimestamp(S_state
, kInterfaceNamerKey_Quiet
);
2401 SC_log(LOG_INFO
, "IOKit quiet");
2404 if (S_connect
== MACH_PORT_NULL
) {
2405 SC_log(LOG_ERR
, "No network stack object");
2409 if (S_quiet
!= MACH_PORT_NULL
) {
2410 IOObjectRelease(S_quiet
);
2411 S_quiet
= MACH_PORT_NULL
;
2414 if (S_timer
!= NULL
) {
2415 CFRunLoopTimerInvalidate(S_timer
);
2420 // grab (and name) any additional interfaces.
2421 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2423 if (messageType
== kIOMessageServiceBusyStateChange
) {
2424 addTimestamp(S_state
, CFSTR("*QUIET&NAMED*"));
2430 os_release(activity
);
2436 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, int *count
)
2438 kern_return_t kr
= kIOReturnSuccess
;;
2441 while ((kr
== kIOReturnSuccess
) &&
2442 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
2443 uint64_t accumulated_busy_time
;
2444 uint32_t busy_state
;
2447 CFMutableArrayRef newNodes
;
2449 CFMutableStringRef str
= NULL
;
2451 if (nodes
== NULL
) {
2452 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2454 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
2456 assert(newNodes
!= NULL
);
2458 kr
= IORegistryEntryGetName(obj
, name
);
2459 if (kr
!= kIOReturnSuccess
) {
2460 SC_log(LOG_NOTICE
, "IORegistryEntryGetName() returned 0x%x", kr
);
2464 str
= CFStringCreateMutable(NULL
, 0);
2465 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
2467 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
2469 case kIOReturnSuccess
:
2470 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
2471 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
2473 case kIOReturnNotFound
:
2476 SC_log(LOG_NOTICE
, "IORegistryEntryGetLocationInPlane() returned 0x%x", kr
);
2481 CFArrayAppendValue(newNodes
, str
);
2484 kr
= IOServiceGetBusyStateAndTime(obj
, &state
, &busy_state
, &accumulated_busy_time
);
2485 if (kr
!= kIOReturnSuccess
) {
2486 SC_log(LOG_NOTICE
, "IOServiceGetBusyStateAndTime() returned 0x%x", kr
);
2490 #ifdef TEST_SNAPSHOT
2493 #endif // TEST_SNAPSHOT
2495 if (busy_state
!= 0) {
2498 if ((*count
)++ == 0) {
2499 SC_log(LOG_ERR
, "Busy services :");
2502 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
2503 SC_log(LOG_ERR
, " %@ [%s%s%s%d, %lld ms]",
2505 (state
& kIOServiceRegisteredState
) ? "" : "!registered, ",
2506 (state
& kIOServiceMatchedState
) ? "" : "!matched, ",
2507 (state
& kIOServiceInactiveState
) ? "inactive, " : "",
2509 accumulated_busy_time
/ kMillisecondScale
);
2513 kr
= IORegistryIteratorEnterEntry(iterator
);
2514 if (kr
!= kIOReturnSuccess
) {
2515 SC_log(LOG_NOTICE
, "IORegistryIteratorEnterEntry() returned 0x%x", kr
);
2519 iterateRegistryBusy(iterator
, newNodes
, count
);
2521 kr
= IORegistryIteratorExitEntry(iterator
);
2522 if (kr
!= kIOReturnSuccess
) {
2523 SC_log(LOG_NOTICE
, "IORegistryIteratorExitEntry() returned 0x%x", kr
);
2528 CFRelease(newNodes
);
2529 IOObjectRelease(obj
);
2539 io_iterator_t iterator
= MACH_PORT_NULL
;
2542 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
2546 if (kr
!= kIOReturnSuccess
) {
2547 SC_log(LOG_NOTICE
, "IORegistryCreateIterator() returned 0x%x", kr
);
2551 iterateRegistryBusy(iterator
, NULL
, &count
);
2553 SC_log(LOG_ERR
, "w/no busy services");
2556 IOObjectRelease(iterator
);
2560 timerCallback(CFRunLoopTimerRef timer
, void *info
)
2562 #pragma unused(timer)
2563 #pragma unused(info)
2564 os_activity_t activity
;
2566 activity
= os_activity_create("process IOKit timer",
2567 OS_ACTIVITY_CURRENT
,
2568 OS_ACTIVITY_FLAG_DEFAULT
);
2569 os_activity_scope(activity
);
2571 // We've been waiting for IOKit to quiesce and it just
2572 // hasn't happenned. Time to just move on!
2573 addTimestamp(S_state
, kInterfaceNamerKey_Timeout
);
2576 SC_log(LOG_ERR
, "timed out waiting for IOKit to quiesce");
2579 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
2581 addTimestamp(S_state
, CFSTR("*TIMEOUT&NAMED*"));
2584 os_release(activity
);
2590 setup_IOKit(CFBundleRef bundle
)
2592 #pragma unused(bundle)
2595 mach_port_t masterPort
= MACH_PORT_NULL
;
2597 io_object_t root
= MACH_PORT_NULL
;
2599 // read DB of previously named network interfaces
2600 S_dblist
= readInterfaceList();
2601 if (S_dblist
!= NULL
) {
2604 n
= CFArrayGetCount(S_dblist
);
2606 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
2610 // get interfaces that were named during the last boot
2611 S_prev_active_list
= previouslyActiveInterfaces();
2613 // track how long we've waited to see each interface.
2614 S_state
= CFDictionaryCreateMutable(NULL
,
2616 &kCFTypeDictionaryKeyCallBacks
,
2617 &kCFTypeDictionaryValueCallBacks
);
2618 addTimestamp(S_state
, CFSTR("*START*"));
2620 // Creates and returns a notification object for receiving IOKit
2621 // notifications of new devices or state changes.
2622 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
2623 if (kr
!= KERN_SUCCESS
) {
2624 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
2628 S_notify
= IONotificationPortCreate(masterPort
);
2629 if (S_notify
== NULL
) {
2630 SC_log(LOG_ERR
, "IONotificationPortCreate failed");
2634 // watch IOKit matching activity
2635 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
2636 if (root
== MACH_PORT_NULL
) {
2637 SC_log(LOG_ERR
, "IORegistryEntryFromPath failed");
2641 kr
= IOServiceAddInterestNotification(S_notify
,
2645 (void *)S_notify
, // refCon
2646 &S_quiet
); // notification
2647 if (kr
!= KERN_SUCCESS
) {
2648 SC_log(LOG_ERR
, "IOServiceAddInterestNotification returned 0x%x", kr
);
2652 kr
= IOServiceGetBusyState(root
, &busy
);
2653 if (kr
!= KERN_SUCCESS
) {
2654 SC_log(LOG_ERR
, "IOServiceGetBusyState returned 0x%x", kr
);
2658 // add a timer so we don't wait forever for IOKit to quiesce
2659 S_timer
= CFRunLoopTimerCreate(NULL
,
2660 CFAbsoluteTimeGetCurrent() + S_stack_timeout
,
2666 if (S_timer
== NULL
) {
2667 SC_log(LOG_ERR
, "CFRunLoopTimerCreate failed");
2671 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
2673 // watch for the introduction of the IONetworkStack
2674 kr
= IOServiceAddMatchingNotification(S_notify
,
2675 kIOFirstMatchNotification
,
2676 IOServiceMatching("IONetworkStack"),
2678 (void *)S_notify
, // refCon
2679 &S_stack
); // notification
2680 if (kr
!= KERN_SUCCESS
) {
2681 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
2685 // check and see if the stack is already available and arm the
2686 // notification for its introduction.
2687 stackCallback((void *)S_notify
, S_stack
);
2689 // watch for the introduction of new network interfaces
2690 kr
= IOServiceAddMatchingNotification(S_notify
,
2691 kIOFirstMatchNotification
,
2692 IOServiceMatching("IONetworkInterface"),
2693 &interfaceArrivalCallback
,
2694 (void *)S_notify
, // refCon
2695 &S_iter
); // notification
2696 if (kr
!= KERN_SUCCESS
) {
2697 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
2701 // Get the current list of matches and arm the notification for
2702 // future interface arrivals.
2703 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2705 // Check if IOKit has already quiesced.
2706 quietCallback((void *)S_notify
,
2708 kIOMessageServiceBusyStateChange
,
2709 (void *)(uintptr_t)busy
);
2711 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2712 IONotificationPortGetRunLoopSource(S_notify
),
2713 kCFRunLoopDefaultMode
);
2715 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
2717 * Start the wheels turning until we've named all of
2718 * the interfaces that were used during the previous
2719 * boot, until IOKit [matching] has quiesced, or
2720 * until we've waited long enough.
2722 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
2723 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2724 IONotificationPortGetRunLoopSource(S_notify
),
2726 while (S_prev_active_list
!= NULL
) {
2729 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
2731 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
2733 #if !TARGET_OS_EMBEDDED
2734 if (S_dblist
!= NULL
) {
2735 // apply special handling for the BT-PAN interface (if present)
2736 CFArrayApplyFunction(S_dblist
,
2737 CFRangeMake(0, CFArrayGetCount(S_dblist
)),
2738 updateBTPANInformation
,
2741 #endif // !TARGET_OS_EMBEDDED
2746 if (root
!= MACH_PORT_NULL
) {
2747 IOObjectRelease(root
);
2749 if (masterPort
!= MACH_PORT_NULL
) {
2750 mach_port_deallocate(mach_task_self(), masterPort
);
2757 setup_Virtual(CFBundleRef bundle
)
2759 #pragma unused(bundle)
2760 // open a SCPreferences session
2761 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
);
2762 if (S_prefs
== NULL
) {
2763 SC_log(LOG_ERR
, "SCPreferencesCreate() failed: %s",
2764 SCErrorString(SCError()));
2768 // register for change notifications.
2769 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
2770 SC_log(LOG_ERR
, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
2776 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
2777 if (SCError() != kSCStatusNoStoreServer
) {
2778 SC_log(LOG_ERR
, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
2788 exec_InterfaceNamer(void *arg
)
2790 CFBundleRef bundle
= (CFBundleRef
)arg
;
2791 CFDictionaryRef dict
;
2793 pthread_setname_np(MY_PLUGIN_NAME
" thread");
2795 dict
= CFBundleGetInfoDictionary(bundle
);
2796 if (isA_CFDictionary(dict
)) {
2799 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_STACK_TIMEOUT_KEY
));
2801 if (!isA_CFNumber(num
) ||
2802 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_stack_timeout
) ||
2803 (S_stack_timeout
<= 0.0)) {
2804 SC_log(LOG_NOTICE
, WAIT_STACK_TIMEOUT_KEY
" value error");
2805 S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
2809 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
2811 if (!isA_CFNumber(num
) ||
2812 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_quiet_timeout
) ||
2813 (S_quiet_timeout
<= 0.0)) {
2814 SC_log(LOG_NOTICE
, WAIT_QUIET_TIMEOUT_KEY
" value error");
2815 S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
2820 // setup virtual network interface monitoring
2821 if (!setup_Virtual(bundle
)) {
2825 // setup [IOKit] network interface monitoring
2826 if (!setup_IOKit(bundle
)) {
2833 if (S_connect
!= MACH_PORT_NULL
) {
2834 IOServiceClose(S_connect
);
2835 S_connect
= MACH_PORT_NULL
;
2837 if (S_dblist
!= NULL
) {
2838 CFRelease(S_dblist
);
2841 if (S_iter
!= MACH_PORT_NULL
) {
2842 IOObjectRelease(S_iter
);
2843 S_iter
= MACH_PORT_NULL
;
2845 if (S_notify
!= MACH_PORT_NULL
) {
2846 IONotificationPortDestroy(S_notify
);
2848 if (S_quiet
!= MACH_PORT_NULL
) {
2849 IOObjectRelease(S_quiet
);
2850 S_quiet
= MACH_PORT_NULL
;
2852 if (S_stack
!= MACH_PORT_NULL
) {
2853 IOObjectRelease(S_stack
);
2854 S_stack
= MACH_PORT_NULL
;
2856 if (S_state
!= NULL
) {
2860 if (S_timer
!= NULL
) {
2861 CFRunLoopTimerInvalidate(S_timer
);
2875 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
2877 #pragma unused(bundleVerbose)
2878 pthread_attr_t tattr
;
2881 CFRetain(bundle
); // released in exec_InterfaceNamer
2883 pthread_attr_init(&tattr
);
2884 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
2885 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
2886 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
2887 pthread_create(&tid
, &tattr
, exec_InterfaceNamer
, bundle
);
2888 pthread_attr_destroy(&tattr
);
2893 //------------------------------------------------------------------------
2897 main(int argc
, char ** argv
)
2902 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2904 bundle
= CFBundleGetMainBundle();
2905 CFRetain(bundle
); // released in exec_InterfaceNamer
2907 (void)exec_InterfaceNamer();
2915 #ifdef TEST_SNAPSHOT
2917 main(int argc
, char ** argv
)
2919 CFStringRef snapshot
;
2922 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2924 snapshot
= captureBusy();
2925 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), snapshot
);
2926 CFRelease(snapshot
);
2931 #endif /* TEST_SNAPSHOT */