2 * Copyright (c) 2001-2018 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
60 #include <TargetConditionals.h>
69 #endif // TARGET_OS_IPHONE
70 #include <sys/ioctl.h>
72 #include <sys/sysctl.h>
73 #include <sys/param.h>
74 #include <mach/mach.h>
75 #include <net/ethernet.h>
76 #include <net/if_types.h>
79 #include <CommonCrypto/CommonDigest.h>
81 #include <CoreFoundation/CoreFoundation.h>
83 #include <SystemConfiguration/SystemConfiguration.h>
84 #include <SystemConfiguration/SCDPlugin.h>
85 #include <SystemConfiguration/SCPrivate.h>
86 #include <SystemConfiguration/SCValidation.h>
87 #include "SCNetworkConfigurationInternal.h"
88 #include "plugin_shared.h"
90 #include "InterfaceNamerControlPrefs.h"
91 #endif // !TARGET_OS_IPHONE
93 #include <IOKit/IOKitLib.h>
94 #include <IOKit/IOKitLibPrivate.h>
95 #include <IOKit/IOKitKeysPrivate.h>
96 #include <IOKit/IOBSD.h>
97 #include <IOKit/IOMessage.h>
98 #include <IOKit/network/IONetworkController.h>
99 #include <IOKit/network/IONetworkInterface.h>
100 #include <IOKit/network/IONetworkStack.h>
101 #include <IOKit/usb/USB.h>
103 #ifdef kIONetworkStackUserCommandKey
104 #define USE_REGISTRY_ENTRY_ID
107 #ifndef USE_REGISTRY_ENTRY_ID
108 // from <IOKit/network/IONetworkStack.h>
109 #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand"
111 kRegisterInterfaceWithFixedUnit
= 0,
113 kRegisterAllInterfaces
115 #endif // !USE_REGISTRY_ENTRY_ID
117 #define kSCNetworkInterfaceActive "Active"
118 #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo"
119 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
120 #define kSCNetworkInterfaceMatchingMACs "MatchingMACs"
122 #define MY_PLUGIN_NAME "InterfaceNamer"
123 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
125 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
126 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
128 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
129 #define WAIT_QUIET_TIMEOUT_DEFAULT 240.0
133 * "IONetworkStack" connect object used to "name" an interface.
135 static io_connect_t S_connect
= MACH_PORT_NULL
;
139 * An array of CFDictionary's representing the interfaces
140 * that have been identified and [need to be] named.
142 static CFMutableArrayRef S_dblist
= NULL
;
146 * An array of SCNetworkInterface's representing the
147 * interfaces that have been identified.
149 static CFMutableArrayRef S_iflist
= NULL
;
153 * IOServiceAddMatchingNotification object used to watch for
154 * new network interfaces.
156 static io_iterator_t S_iter
= MACH_PORT_NULL
;
158 #if !TARGET_OS_IPHONE
161 * An array of CFData(WatchedInfo) objects representing those
162 * interfaces that have been connected to the system while
165 static CFMutableArrayRef S_locked
= NULL
;
166 #endif // !TARGET_OS_IPHONE
170 * notification object for receiving IOKit notifications of
171 * new devices or state changes.
173 static IONotificationPortRef S_notify
= NULL
;
177 * An array of CFData(WatchedInfo) objects representing those
178 * pre-configured interfaces that have been connected to the
181 static CFMutableArrayRef S_preconfigured
= NULL
;
183 /* S_prev_active_list
184 * An array of CFDictionary's representing the previously
187 static CFMutableArrayRef S_prev_active_list
= NULL
;
191 * IOServiceAddInterestNotification object used to watch for
192 * IOKit matching to quiesce.
194 static io_object_t S_quiet
= MACH_PORT_NULL
;
198 * IOServiceAddMatchingNotification object used to watch for
199 * the availability of the "IONetworkStack" object.
201 static io_iterator_t S_stack
= MACH_PORT_NULL
;
205 * A dictionary containing Information about each network
206 * interface. For now, the key is the BSD name and the
207 * value is a CFNumber noting how long (in milliseconds)
208 * it took for the interface to be recognized/named.
210 static CFMutableDictionaryRef S_state
= NULL
;
214 * S_trustedHostAttached
216 * Note: this global must only be updated on trustRequired_queue()
218 static Boolean S_trustedHostAttached
= FALSE
;
222 * An array of CFData(WatchedInfo) objects representing those
223 * interfaces that require [lockdownd] trust.
225 static CFMutableArrayRef S_trustRequired
= NULL
;
226 #endif // TARGET_OS_IPHONE
230 * CFRunLoopTimer tracking how long we are willing to wait
231 * for IOKit matching to quiesce (IOKitWaitQuiet).
234 * time to wait for the IONetworkStack object to appear before timeout
237 * time to wait for the IOKit to quiesce (after the IONetworkStack is
240 static CFRunLoopTimerRef S_timer
= NULL
;
241 static double S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
242 static double S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
245 * Virtual network interface configuration
246 * S_prefs : SCPreferences to configuration
247 * S_bonds : most recently actived Bond configuration
248 * S_bridges : most recently actived Bridge configuration
249 * S_vlans : most recently actived VLAN configuration
251 static SCPreferencesRef S_prefs
= NULL
;
252 static CFArrayRef S_bonds
= NULL
;
253 static CFArrayRef S_bridges
= NULL
;
254 static CFArrayRef S_vlans
= NULL
;
261 __log_InterfaceNamer(void)
263 static os_log_t log
= NULL
;
266 log
= os_log_create("com.apple.SystemConfiguration", "InterfaceNamer");
274 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
279 now
= CFAbsoluteTimeGetCurrent();
280 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
281 CFDictionaryAddValue(dict
, key
, val
);
286 #define INTERFACES CFSTR("Interfaces")
287 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
289 static CFComparisonResult
290 if_unit_compare(const void *val1
, const void *val2
, void *context
)
292 #pragma unused(context)
293 CFComparisonResult res
;
299 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
300 CFSTR(kIOInterfaceType
));
301 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
302 CFSTR(kIOInterfaceType
));
303 res
= CFNumberCompare(type1
, type2
, NULL
);
304 if (res
!= kCFCompareEqualTo
) {
307 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
308 CFSTR(kIOInterfaceUnit
));
309 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
310 CFSTR(kIOInterfaceUnit
));
311 return (CFNumberCompare(unit1
, unit2
, NULL
));
315 writeInterfaceList(CFArrayRef if_list
)
318 CFStringRef new_model
;
319 CFStringRef old_model
;
320 SCPreferencesRef prefs
;
322 if (isA_CFArray(if_list
) == NULL
) {
326 prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":writeInterfaceList"), NETWORK_INTERFACES_PREFS
);
328 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
332 cur_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
333 if (_SC_CFEqual(cur_list
, if_list
)) {
337 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
338 new_model
= _SC_hw_model(FALSE
);
339 if ((new_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
341 if ((old_model
!= NULL
) && (cur_list
!= NULL
)) {
344 // if interface list was created on other hardware
345 history
= CFStringCreateWithFormat(NULL
, NULL
,
349 SCPreferencesSetValue(prefs
, history
, cur_list
);
352 SC_log(LOG_NOTICE
, "Hardware model changed\n"
353 " created on \"%@\"\n"
359 SCPreferencesSetValue(prefs
, MODEL
, new_model
);
362 SCPreferencesSetValue(prefs
, INTERFACES
, if_list
);
364 if (!SCPreferencesCommitChanges(prefs
)) {
365 if (SCError() != EROFS
) {
366 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
377 static CFPropertyListRef
378 restoreNIPrefsFromBackup(SCPreferencesRef prefs
, CFStringRef current_model
)
380 CFPropertyListRef if_list
;
383 key
= CFStringCreateWithFormat(NULL
, 0, CFSTR("%@:%@"), INTERFACES
, current_model
);
384 if_list
= SCPreferencesGetValue(prefs
, key
);
385 if_list
= isA_CFArray(if_list
);
386 if (if_list
!= NULL
) {
387 /* Write the previously backed up Interface list for this hardware */
388 writeInterfaceList(if_list
);
390 /* Synchronize the prefs */
391 SCPreferencesSynchronize(prefs
);
393 /* Re-fetch the interface list */
394 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
395 if_list
= isA_CFArray(if_list
);
396 if (if_list
!= NULL
) {
397 /* We do not need the old interface list any more */
398 SCPreferencesRemoveValue(prefs
, key
);
399 if (!SCPreferencesCommitChanges(prefs
)) {
400 if (SCError() != EROFS
) {
401 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
412 static CF_RETURNS_RETAINED CFMutableArrayRef
416 CFStringRef old_model
;
417 CFMutableArrayRef plist
= NULL
;
418 SCPreferencesRef prefs
= NULL
;
420 prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":readInterfaceList"), NETWORK_INTERFACES_PREFS
);
422 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
426 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
427 if_list
= isA_CFArray(if_list
);
429 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
430 if (old_model
!= NULL
) {
431 CFStringRef new_model
;
433 new_model
= _SC_hw_model(FALSE
);
434 if (!_SC_CFEqual(old_model
, new_model
)) {
435 /* if interface list was created on other hardware,
436 Restore if a backup interface list is present */
437 if_list
= restoreNIPrefsFromBackup(prefs
, new_model
);
441 if (if_list
!= NULL
) {
443 CFIndex n
= CFArrayGetCount(if_list
);
445 plist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
446 for (i
= 0; i
< n
; i
++) {
447 CFDictionaryRef dict
;
449 dict
= CFArrayGetValueAtIndex(if_list
, i
);
450 if (isA_CFDictionary(dict
) &&
451 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceType
)) &&
452 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
453 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
454 CFArrayAppendValue(plist
, dict
);
465 static CF_RETURNS_RETAINED CFMutableArrayRef
466 previouslyActiveInterfaces()
468 CFMutableArrayRef active
;
472 if (S_dblist
== NULL
) {
476 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
478 n
= CFArrayGetCount(S_dblist
);
479 for (i
= 0; i
< n
; i
++) {
480 CFDictionaryRef if_dict
;
482 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
483 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
484 CFMutableDictionaryRef new_dict
;
486 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
487 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
488 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
489 CFArrayAppendValue(active
, new_dict
);
498 updateInterfaces(void);
505 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
), kSCDynamicStoreDomainPlugin
);
506 (void)SCDynamicStoreSetValue(NULL
, key
, S_state
);
512 #if !TARGET_OS_IPHONE
514 updateBondInterfaceConfiguration(SCPreferencesRef prefs
)
516 CFArrayRef interfaces
;
518 interfaces
= SCBondInterfaceCopyAll(prefs
);
519 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
520 CFRelease(interfaces
);
524 if (_SC_CFEqual(S_bonds
, interfaces
)) {
526 if (interfaces
!= NULL
) CFRelease(interfaces
);
530 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
531 S_bonds
= interfaces
;
533 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
534 SC_log(LOG_NOTICE
, "_SCBondInterfaceUpdateConfiguration() failed: %s",
535 SCErrorString(SCError()));
540 #endif // !TARGET_OS_IPHONE
543 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs
)
545 CFArrayRef interfaces
;
547 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
548 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
549 CFRelease(interfaces
);
553 if (_SC_CFEqual(S_bridges
, interfaces
)) {
555 if (interfaces
!= NULL
) CFRelease(interfaces
);
559 if (S_bridges
!= NULL
) CFRelease(S_bridges
);
560 S_bridges
= interfaces
;
562 if (!_SCBridgeInterfaceUpdateConfiguration(prefs
)) {
563 SC_log(LOG_NOTICE
, "_SCBridgeInterfaceUpdateConfiguration() failed: %s",
564 SCErrorString(SCError()));
571 updateVLANInterfaceConfiguration(SCPreferencesRef prefs
)
573 CFArrayRef interfaces
;
575 interfaces
= SCVLANInterfaceCopyAll(prefs
);
576 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
577 CFRelease(interfaces
);
581 if (_SC_CFEqual(S_vlans
, interfaces
)) {
583 if (interfaces
!= NULL
) CFRelease(interfaces
);
587 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
588 S_vlans
= interfaces
;
590 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
591 SC_log(LOG_NOTICE
, "_SCVLANInterfaceUpdateConfiguration() failed: %s",
592 SCErrorString(SCError()));
599 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
600 SCPreferencesNotification notificationType
,
604 os_activity_t activity
;
606 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
610 activity
= os_activity_create("check/update virtual network interface configuration",
612 OS_ACTIVITY_FLAG_DEFAULT
);
613 os_activity_scope(activity
);
616 // if a new interface has been "named"
618 if (S_bonds
!= NULL
) {
622 if (S_bridges
!= NULL
) {
623 CFRelease(S_bridges
);
626 if (S_vlans
!= NULL
) {
632 #if !TARGET_OS_IPHONE
633 updateBondInterfaceConfiguration (prefs
);
634 #endif // !TARGET_OS_IPHONE
635 updateBridgeInterfaceConfiguration(prefs
);
636 updateVLANInterfaceConfiguration (prefs
);
638 // we are finished with current prefs, wait for changes
639 SCPreferencesSynchronize(prefs
);
641 os_release(activity
);
649 updateBTPANInformation(const void *value
, void *context
)
651 #pragma unused(context)
653 CFDictionaryRef dict
= (CFDictionaryRef
)value
;
655 CFDictionaryRef info
;
658 if_name
= CFDictionaryGetValue(dict
, CFSTR(kIOBSDNameKey
));
659 if (!isA_CFString(if_name
)) {
664 info
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceInfo
));
665 if (!isA_CFDictionary(info
)) {
666 // if no SCNetworkInterface info
670 name
= CFDictionaryGetValue(info
, kSCPropUserDefinedName
);
671 if (!isA_CFString(name
) || !CFEqual(name
, CFSTR(BT_PAN_NAME
))) {
672 // if not BT-PAN interface
676 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Name
, if_name
);
678 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
679 if (isA_CFData(addr
)) {
680 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Mac
, addr
);
685 #endif // TARGET_OS_OSX
687 static CFDictionaryRef
688 createInterfaceDict(SCNetworkInterfaceRef interface
, CFArrayRef matchingMACs
)
690 CFMutableDictionaryRef new_if
;
693 new_if
= CFDictionaryCreateMutable(NULL
,
695 &kCFTypeDictionaryKeyCallBacks
,
696 &kCFTypeDictionaryValueCallBacks
);
698 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
700 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
704 val
= _SCNetworkInterfaceGetIOPath(interface
);
706 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
709 val
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
711 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceNamePrefix
), val
);
714 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
716 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
719 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
721 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
724 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
726 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
729 val
= SCNetworkInterfaceGetBSDName(interface
);
731 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
734 val
= SCNetworkInterfaceGetInterfaceType(interface
);
736 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
739 CFDictionarySetValue(new_if
,
741 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
743 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
745 if (matchingMACs
!= NULL
) {
746 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceMatchingMACs
), matchingMACs
);
752 static CFDictionaryRef
753 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
760 if (db_list
== NULL
) {
763 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
764 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
765 if (type
== NULL
|| addr
== NULL
) {
769 n
= CFArrayGetCount(db_list
);
770 for (i
= 0; i
< n
; i
++) {
772 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
775 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
776 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
777 if (t
== NULL
|| a
== NULL
)
780 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
790 static CFDictionaryRef
791 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
798 if (db_list
== NULL
) {
801 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
802 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
803 if (type
== NULL
|| unit
== NULL
) {
807 n
= CFArrayGetCount(db_list
);
808 for (i
= 0; i
< n
; i
++) {
809 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
813 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
814 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
815 if (t
== NULL
|| u
== NULL
) {
819 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
829 CFDictionaryRef match_info
;
830 CFStringRef match_type
;
831 CFBooleanRef match_builtin
;
832 CFMutableArrayRef matches
;
833 } matchContext
, *matchContextRef
;
835 static CF_RETURNS_RETAINED CFDictionaryRef
836 thinInterfaceInfo(CFDictionaryRef info
)
841 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
843 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
844 && (vid
== kIOUSBVendorIDAppleComputer
)) {
845 CFMutableDictionaryRef thin
;
847 // if this is an Apple USB device than we trust that
848 // the non-localized name will be correct.
849 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
850 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
851 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
852 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
856 return CFRetain(info
);
860 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
864 match
= _SC_CFEqual(known_info
, match_info
);
866 isA_CFDictionary(known_info
) &&
867 isA_CFDictionary(match_info
)) {
869 // if not an exact match, try thinning
870 known_info
= thinInterfaceInfo(known_info
);
871 match_info
= thinInterfaceInfo(match_info
);
872 match
= _SC_CFEqual(known_info
, match_info
);
873 if (known_info
!= NULL
) CFRelease(known_info
);
874 if (match_info
!= NULL
) CFRelease(match_info
);
881 matchKnown(const void *value
, void *context
)
883 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
884 matchContextRef match_context
= (matchContextRef
)context
;
886 // match interface type
888 CFStringRef known_type
;
890 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
891 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
896 // match SCNetworkInterfaceInfo
898 CFDictionaryRef known_info
;
900 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
901 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
906 // if requested, match [non-]builtin
907 if (match_context
->match_builtin
!= NULL
) {
908 CFBooleanRef known_builtin
;
910 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
911 if (!isA_CFBoolean(known_builtin
)) {
912 known_builtin
= kCFBooleanFalse
;
914 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
919 // if we have a match
920 if (match_context
->matches
== NULL
) {
921 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
923 CFArrayAppendValue(match_context
->matches
, known_dict
);
929 matchUnnamed(const void *value
, void *context
)
931 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
932 matchContextRef match_context
= (matchContextRef
)context
;
934 if (match_context
->matches
== NULL
) {
938 // match interface type
940 CFStringRef known_type
;
942 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
943 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
948 // match SCNetworkInterfaceInfo
950 CFDictionaryRef known_info
;
953 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
954 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
955 if (known_info
!= NULL
) CFRelease(known_info
);
961 // if requested, match [non-]builtin
962 if (match_context
->match_builtin
!= NULL
) {
963 CFBooleanRef known_builtin
;
965 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
967 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
972 // if we have a match
973 CFRelease(match_context
->matches
);
974 match_context
->matches
= NULL
;
980 interfaceExists(CFStringRef prefix
, CFNumberRef unit
)
982 Boolean found
= FALSE
;
983 CFDictionaryRef match_dict
;
984 CFStringRef match_keys
[2];
985 CFTypeRef match_vals
[2];
986 CFDictionaryRef matching
;
990 io_registry_entry_t entry
= MACH_PORT_NULL
;
991 io_iterator_t iterator
= MACH_PORT_NULL
;
993 mach_port_t masterPort
= MACH_PORT_NULL
;
995 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
996 if (kr
!= KERN_SUCCESS
) {
997 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1001 // look for kIONetworkInterface with matching prefix and unit
1002 match_keys
[0] = CFSTR(kIOInterfaceNamePrefix
);
1003 match_vals
[0] = prefix
;
1004 match_keys
[1] = CFSTR(kIOInterfaceUnit
);
1005 match_vals
[1] = unit
;
1006 match_dict
= CFDictionaryCreate(NULL
,
1007 (const void **)match_keys
,
1008 (const void **)match_vals
,
1010 &kCFTypeDictionaryKeyCallBacks
,
1011 &kCFTypeDictionaryValueCallBacks
);
1013 match_keys
[0] = CFSTR(kIOProviderClassKey
);
1014 match_vals
[0] = CFSTR(kIONetworkInterfaceClass
);
1015 match_keys
[1] = CFSTR(kIOPropertyMatchKey
);
1016 match_vals
[1] = match_dict
;
1017 matching
= CFDictionaryCreate(NULL
,
1018 (const void **)match_keys
,
1019 (const void **)match_vals
,
1020 sizeof(match_keys
)/sizeof(match_keys
[0]),
1021 &kCFTypeDictionaryKeyCallBacks
,
1022 &kCFTypeDictionaryValueCallBacks
);
1023 CFRelease(match_dict
);
1025 // note: the "matching" dictionary will be consumed by the following
1026 kr
= IOServiceGetMatchingServices(masterPort
, matching
, &iterator
);
1027 if ((kr
!= kIOReturnSuccess
) || (iterator
== MACH_PORT_NULL
)) {
1032 entry
= IOIteratorNext(iterator
);
1033 if (entry
== MACH_PORT_NULL
) {
1041 if (masterPort
!= MACH_PORT_NULL
) {
1042 mach_port_deallocate(mach_task_self(), masterPort
);
1044 if (entry
!= MACH_PORT_NULL
) {
1045 IOObjectRelease(entry
);
1047 if (iterator
!= MACH_PORT_NULL
) {
1048 IOObjectRelease(iterator
);
1055 * lookupMatchingInterface
1057 * Looks at the interfaces that have already been [or need to be] named with
1058 * the goal of allowing a system using a single network interface/adaptor of
1059 * a given type (vendor, model, ...) to not care about the specific adaptor
1060 * that is used (i.e. swapping dongle's is OK). Once a system has had more
1061 * than one interface/adaptor connected at the same time than we assume that
1062 * the network configuration is being setup for multi-homing that should be
1065 * If no matches are found or if more than one match is found, return NULL.
1066 * If a single match is found, return the match.
1068 static CFDictionaryRef
1069 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
1070 CFArrayRef db_list
, // already named
1071 CFArrayRef if_list
, // to be named
1072 CFIndex if_list_index
,
1073 CFBooleanRef builtin
)
1075 CFStringRef if_type
;
1076 CFDictionaryRef match
= NULL
;
1077 matchContext match_context
;
1079 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
1080 if (if_type
== NULL
) {
1084 match_context
.match_type
= if_type
;
1085 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
1086 match_context
.match_builtin
= builtin
;
1087 match_context
.matches
= NULL
;
1089 // check for matches to interfaces that have already been named
1090 // ... and append each match that we find to match_context.matches
1091 if (db_list
!= NULL
) {
1092 CFArrayApplyFunction(db_list
,
1093 CFRangeMake(0, CFArrayGetCount(db_list
)),
1098 // check for matches to interfaces that will be named
1099 // ... and CFRelease match_context.matches if we find another network
1100 // interface of the same type that also needs to be named
1101 if (if_list
!= NULL
) {
1102 CFIndex if_list_count
;
1104 if_list_count
= CFArrayGetCount(if_list
);
1105 if (if_list_index
< if_list_count
) {
1106 CFArrayApplyFunction(if_list
,
1107 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
1113 // check if we have a single match
1114 if (match_context
.matches
!= NULL
) {
1115 if (CFArrayGetCount(match_context
.matches
) == 1) {
1116 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
1118 CFRelease(match_context
.matches
);
1121 if (match
!= NULL
) {
1122 Boolean active
= TRUE
;
1125 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
1126 if (isA_CFString(name
)) {
1130 prefix
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceNamePrefix
));
1131 unit
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceUnit
));
1132 if (isA_CFString(prefix
) && isA_CFNumber(unit
)) {
1133 if (!interfaceExists(prefix
, unit
)) {
1144 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
1149 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
, CFDictionaryRef db_dict_match
)
1152 CFDictionaryRef if_dict
;
1153 CFStringRef if_name
;
1154 CFNumberRef if_type
;
1155 CFNumberRef if_unit
;
1156 CFArrayRef matchingMACs
= NULL
;
1157 CFIndex n
= CFArrayGetCount(db_list
);
1158 CFComparisonResult res
;
1160 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1161 if (if_name
!= NULL
) {
1162 addTimestamp(S_state
, if_name
);
1165 if (!_SCNetworkInterfaceIsBuiltin(interface
) && (db_dict_match
!= NULL
)) {
1169 matchingMACs
= CFDictionaryGetValue(db_dict_match
, CFSTR(kSCNetworkInterfaceMatchingMACs
));
1170 if (matchingMACs
!= NULL
) {
1171 CFRetain(matchingMACs
);
1174 addr_old
= CFDictionaryGetValue(db_dict_match
, CFSTR(kIOMACAddress
));
1175 addr_cur
= _SCNetworkInterfaceGetHardwareAddress(interface
);
1176 if ((addr_old
!= NULL
) && (addr_cur
!= NULL
) && !CFEqual(addr_old
, addr_cur
)) {
1177 CFMutableArrayRef matching_new
;
1179 // if MAC address changed, add previous MAC to history
1180 if (matchingMACs
!= NULL
) {
1181 matching_new
= CFArrayCreateMutableCopy(NULL
, 0, matchingMACs
);
1182 CFRelease(matchingMACs
);
1184 // remove duplicates of the now current MAC from history
1185 i
= CFArrayGetFirstIndexOfValue(matching_new
, CFRangeMake(0, CFArrayGetCount(matching_new
)), addr_cur
);
1186 if (i
!= kCFNotFound
) {
1187 CFArrayRemoveValueAtIndex(matching_new
, i
);
1190 // remove duplicates of the previous MAC from history before re-inserting
1191 i
= CFArrayGetFirstIndexOfValue(matching_new
, CFRangeMake(0, CFArrayGetCount(matching_new
)), addr_old
);
1192 if (i
!= kCFNotFound
) {
1193 CFArrayRemoveValueAtIndex(matching_new
, i
);
1196 matching_new
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1198 CFArrayInsertValueAtIndex(matching_new
, 0, addr_old
);
1200 // limit history size
1201 #define MATCHING_HISTORY_MAXLEN 32
1202 for (i
= CFArrayGetCount(matching_new
); i
> MATCHING_HISTORY_MAXLEN
; i
--) {
1203 CFArrayRemoveValueAtIndex(matching_new
, i
- 1);
1206 matchingMACs
= matching_new
;
1210 if_dict
= createInterfaceDict(interface
, matchingMACs
);
1211 if (matchingMACs
!= NULL
) {
1212 CFRelease(matchingMACs
);
1215 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1216 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1217 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
1222 for (i
= 0; i
< n
; i
++) {
1223 CFNumberRef db_type
;
1224 CFNumberRef db_unit
;
1225 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
1227 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1228 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1229 res
= CFNumberCompare(if_type
, db_type
, NULL
);
1230 if (res
== kCFCompareLessThan
1231 || (res
== kCFCompareEqualTo
1232 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
1233 == kCFCompareLessThan
))) {
1234 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
1240 CFArrayAppendValue(S_dblist
, if_dict
);
1243 updateBTPANInformation(if_dict
, NULL
);
1244 #endif // TARGET_OS_OSX
1251 replaceInterface(SCNetworkInterfaceRef interface
)
1253 CFDictionaryRef db_dict
;
1254 CFDictionaryRef db_dict_match
= NULL
;
1258 if (S_dblist
== NULL
) {
1259 S_dblist
= CFArrayCreateMutable(NULL
, 0,
1260 &kCFTypeArrayCallBacks
);
1263 // remove any dict that has our type/addr
1265 db_dict
= lookupInterfaceByAddress(S_dblist
, interface
, &where
);
1266 if (db_dict
== NULL
) {
1269 if (db_dict_match
== NULL
) {
1270 db_dict_match
= CFRetain(db_dict
);
1272 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1276 // remove any dict that has the same type/unit
1278 db_dict
= lookupInterfaceByUnit(S_dblist
, interface
, &where
);
1279 if (db_dict
== NULL
) {
1282 if (db_dict_match
== NULL
) {
1283 db_dict_match
= CFRetain(db_dict
);
1285 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1289 insertInterface(S_dblist
, interface
, db_dict_match
);
1290 if (db_dict_match
!= NULL
) {
1291 CFRelease(db_dict_match
);
1295 SC_log(LOG_ERR
, "Multiple interfaces updated (n = %d, %@)", n
, interface
);
1302 getHighestUnitForType(CFNumberRef if_type
)
1306 CFNumberRef ret_unit
= NULL
;
1308 if (S_dblist
== NULL
) {
1312 n
= CFArrayGetCount(S_dblist
);
1313 for (i
= 0; i
< n
; i
++) {
1314 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1317 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1318 if (CFEqual(type
, if_type
)) {
1321 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1322 if (ret_unit
== NULL
1323 || (CFNumberCompare(unit
, ret_unit
, NULL
)
1324 == kCFCompareGreaterThan
)) {
1334 * Function: ensureInterfaceHasUnit
1336 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1337 * release the interface and return NULL.
1339 static SCNetworkInterfaceRef
1340 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if
)
1343 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if
) == NULL
) {
1350 #ifdef USE_REGISTRY_ENTRY_ID
1351 static kern_return_t
1352 registerInterfaceWithIORegistryEntryID(io_connect_t connect
,
1358 CFMutableDictionaryRef dict
;
1362 dict
= CFDictionaryCreateMutable(NULL
, 0,
1363 &kCFTypeDictionaryKeyCallBacks
,
1364 &kCFTypeDictionaryValueCallBacks
);
1365 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1366 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1368 data
= CFDataCreate(NULL
, (void *) &entryID
, sizeof(entryID
));
1369 CFDictionarySetValue(dict
, CFSTR(kIORegistryEntryIDKey
), data
);
1371 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1372 kr
= IOConnectSetCFProperties(connect
, dict
);
1377 static SCNetworkInterfaceRef
1378 copyInterfaceForIORegistryEntryID(uint64_t entryID
)
1380 io_registry_entry_t entry
= MACH_PORT_NULL
;
1381 SCNetworkInterfaceRef interface
= NULL
;
1382 io_iterator_t iterator
= MACH_PORT_NULL
;
1384 mach_port_t masterPort
= MACH_PORT_NULL
;
1386 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1387 if (kr
!= KERN_SUCCESS
) {
1388 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1392 kr
= IOServiceGetMatchingServices(masterPort
,
1393 IORegistryEntryIDMatching(entryID
),
1395 if ((kr
!= KERN_SUCCESS
) || (iterator
== MACH_PORT_NULL
)) {
1396 SC_log(LOG_NOTICE
, "IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d",
1403 entry
= IOIteratorNext(iterator
);
1404 if (entry
== MACH_PORT_NULL
) {
1405 SC_log(LOG_NOTICE
, "IORegistryEntryIDMatching(0x%llx) failed", entryID
);
1409 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1412 if (masterPort
!= MACH_PORT_NULL
) {
1413 mach_port_deallocate(mach_task_self(), masterPort
);
1415 if (entry
!= MACH_PORT_NULL
) {
1416 IOObjectRelease(entry
);
1418 if (iterator
!= MACH_PORT_NULL
) {
1419 IOObjectRelease(iterator
);
1424 static SCNetworkInterfaceRef
1425 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID
)
1427 SCNetworkInterfaceRef net_if
;
1429 net_if
= copyInterfaceForIORegistryEntryID(entryID
);
1430 return (ensureInterfaceHasUnit(net_if
));
1433 #else // USE_REGISTRY_ENTRY_ID
1435 * Function: registerInterface
1437 * Register a single interface with the given service path to the
1438 * data link layer (BSD), using the specified unit number.
1440 static kern_return_t
1441 registerInterfaceWithIOServicePath(io_connect_t connect
,
1446 CFMutableDictionaryRef dict
;
1450 dict
= CFDictionaryCreateMutable(NULL
, 0,
1451 &kCFTypeDictionaryKeyCallBacks
,
1452 &kCFTypeDictionaryValueCallBacks
);
1453 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1454 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1456 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1457 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1458 kr
= IOConnectSetCFProperties(connect
, dict
);
1463 static SCNetworkInterfaceRef
1464 copyInterfaceForIOKitPath(CFStringRef if_path
)
1466 io_registry_entry_t entry
= MACH_PORT_NULL
;
1467 SCNetworkInterfaceRef interface
= NULL
;
1469 mach_port_t masterPort
= MACH_PORT_NULL
;
1472 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1473 if (kr
!= KERN_SUCCESS
) {
1474 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1477 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1478 entry
= IORegistryEntryFromPath(masterPort
, path
);
1479 if (entry
== MACH_PORT_NULL
) {
1480 SC_log(LOG_NOTICE
, "IORegistryEntryFromPath(%@) failed", if_path
);
1484 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1487 if (masterPort
!= MACH_PORT_NULL
) {
1488 mach_port_deallocate(mach_task_self(), masterPort
);
1490 if (entry
!= MACH_PORT_NULL
) {
1491 IOObjectRelease(entry
);
1497 static SCNetworkInterfaceRef
1498 copyNamedInterfaceForIOKitPath(CFStringRef if_path
)
1500 SCNetworkInterfaceRef net_if
;
1502 net_if
= copyInterfaceForIOKitPath(if_path
);
1503 return (ensureInterfaceHasUnit(net_if
));
1506 #endif // USE_REGISTRY_ENTRY_ID
1509 displayInterface(SCNetworkInterfaceRef interface
)
1516 name
= SCNetworkInterfaceGetBSDName(interface
);
1517 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1518 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1519 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1521 SC_log(LOG_INFO
, " %s%@%sType: %@, %s%@%sMAC address: %@",
1522 (name
!= NULL
) ? "BSD Name: " : "",
1523 (name
!= NULL
) ? name
: CFSTR(""),
1524 (name
!= NULL
) ? ", " : "",
1526 (unit
!= NULL
) ? "Unit: " : "",
1527 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1528 (unit
!= NULL
) ? ", " : "",
1529 (addr
!= NULL
) ? addr
: CFSTR("?"));
1533 builtinAvailable(SCNetworkInterfaceRef interface
, // new interface
1534 CFNumberRef if_unit
) // desired unit
1537 CFNumberRef if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1540 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1541 for (i
= 0; i
< n
; i
++) {
1542 CFStringRef if_path
;
1543 CFDictionaryRef known_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1544 CFStringRef known_path
;
1545 CFNumberRef known_type
;
1546 CFNumberRef known_unit
;
1548 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceType
));
1549 if (!_SC_CFEqual(if_type
, known_type
)) {
1550 continue; // if not the same interface type
1553 known_unit
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceUnit
));
1554 if (!_SC_CFEqual(if_unit
, known_unit
)) {
1555 continue; // if not the same interface unit
1558 if_path
= _SCNetworkInterfaceGetIOPath(interface
);
1559 known_path
= CFDictionaryGetValue(known_dict
, CFSTR(kIOPathMatchKey
));
1560 if (!_SC_CFEqual(if_path
, known_path
)) {
1561 // if different IORegistry path
1565 // if same type, same unit, same path
1569 // if interface type/unit not found
1574 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
1579 for (i
= 0; i
< last
; i
++) {
1580 SCNetworkInterfaceRef builtin_if
;
1581 CFNumberRef builtin_type
;
1583 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1584 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
1585 if (CFEqual(if_type
, builtin_type
)) {
1586 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1587 n
++; // if built-in interface
1597 #pragma mark Interface monitoring (e.g. watch for "detach")
1600 typedef struct WatchedInfo
*WatchedInfoRef
;
1602 typedef void (*InterfaceUpdateCallBack
) (
1604 natural_t messageType
,
1605 void *messageArgument
1609 SCNetworkInterfaceRef interface
;
1610 io_service_t interface_node
;
1611 io_object_t notification
;
1612 InterfaceUpdateCallBack callback
;
1616 watcherRelease(CFDataRef watched
);
1619 updateWatchedInterface(void *refCon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
1621 #pragma unused(service)
1622 #pragma unused(messageArgument)
1623 switch (messageType
) {
1624 case kIOMessageServiceIsTerminated
: { // if [watched] interface yanked
1625 CFDataRef watched
= (CFDataRef
)refCon
;
1626 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1629 watchedInfo
->callback(watched
, messageType
, messageArgument
);
1630 watcherRelease(watched
);
1643 watcherCreate(SCNetworkInterfaceRef interface
, InterfaceUpdateCallBack callback
)
1646 io_service_t interface_node
;
1648 CFDictionaryRef matching
;
1649 CFMutableDataRef watched
;
1650 WatchedInfo
*watchedInfo
;
1652 // get the IORegistry node
1653 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
1654 matching
= IORegistryEntryIDMatching(entryID
);
1655 interface_node
= IOServiceGetMatchingService(kIOMasterPortDefault
, matching
);
1656 if (interface_node
== MACH_PORT_NULL
) {
1657 // interface no longer present
1661 // create [locked/trusted] interface watcher
1662 watched
= CFDataCreateMutable(NULL
, sizeof(WatchedInfo
));
1663 CFDataSetLength(watched
, sizeof(WatchedInfo
));
1664 watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1665 bzero(watchedInfo
, sizeof(*watchedInfo
));
1668 watchedInfo
->interface
= CFRetain(interface
);
1670 // ... and the interface node
1671 watchedInfo
->interface_node
= interface_node
;
1673 // ... and set the callback
1674 watchedInfo
->callback
= callback
;
1676 kr
= IOServiceAddInterestNotification(S_notify
, // IONotificationPortRef
1677 watchedInfo
->interface_node
, // io_service_t
1678 kIOGeneralInterest
, // interestType
1679 updateWatchedInterface
, // IOServiceInterestCallback
1680 (void *)watched
, // refCon
1681 &watchedInfo
->notification
); // notification
1682 if (kr
!= KERN_SUCCESS
) {
1684 "IOServiceAddInterestNotification() failed, kr = 0x%x",
1686 watcherRelease(watched
);
1695 watcherRelease(CFDataRef watched
)
1697 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1700 if (watchedInfo
->notification
!= IO_OBJECT_NULL
) {
1701 IOObjectRelease(watchedInfo
->notification
);
1702 watchedInfo
->notification
= IO_OBJECT_NULL
;
1705 // release interface node
1706 if (watchedInfo
->interface_node
!= IO_OBJECT_NULL
) {
1707 IOObjectRelease(watchedInfo
->interface_node
);
1708 watchedInfo
->interface_node
= IO_OBJECT_NULL
;
1711 // release interface
1712 if (watchedInfo
->interface
!= NULL
) {
1713 CFRelease(watchedInfo
->interface
);
1714 watchedInfo
->interface
= NULL
;
1722 #pragma mark Locked device support [macOS]
1725 #if !TARGET_OS_IPHONE
1731 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
1733 CFMutableArrayRef locked
;
1735 locked
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1737 for (CFIndex i
= 0; i
< n
; i
++) {
1742 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
1743 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1745 name
= SCNetworkInterfaceGetLocalizedDisplayName(watchedInfo
->interface
);
1746 addr
= SCNetworkInterfaceGetHardwareAddressString(watchedInfo
->interface
);
1747 path
= _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
);
1748 str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@: %@: %@"),
1749 (name
!= NULL
) ? name
: CFSTR("?"),
1750 (addr
!= NULL
) ? addr
: CFSTR("?"),
1752 CFArrayAppendValue(locked
, str
);
1756 CFDictionarySetValue(S_state
, kInterfaceNamerKey_LockedInterfaces
, locked
);
1759 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_LockedInterfaces
);
1768 blockNewInterfaces()
1770 static boolean_t allow
= TRUE
;
1771 static dispatch_once_t once
;
1773 dispatch_once(&once
, ^{
1774 allow
= InterfaceNamerControlPrefsAllowNewInterfaces();
1783 CFArrayRef console_sessions
;
1784 boolean_t locked
= FALSE
;
1785 io_registry_entry_t root
;
1787 root
= IORegistryGetRootEntry(kIOMasterPortDefault
);
1788 console_sessions
= IORegistryEntryCreateCFProperty(root
,
1789 CFSTR(kIOConsoleUsersKey
),
1792 if (isA_CFArray(console_sessions
)) {
1795 n
= CFArrayGetCount(console_sessions
);
1796 for (CFIndex i
= 0; i
< n
; i
++) {
1797 CFBooleanRef isLocked
;
1798 CFBooleanRef isLoginDone
;
1799 CFBooleanRef onConsole
;
1800 CFDictionaryRef session
;
1802 session
= CFArrayGetValueAtIndex(console_sessions
, i
);
1803 if (!isA_CFDictionary(session
)) {
1804 // if not dictionary
1808 if (!CFDictionaryGetValueIfPresent(session
,
1809 CFSTR(kIOConsoleSessionOnConsoleKey
),
1810 (const void **)&onConsole
) ||
1811 !isA_CFBoolean(onConsole
) ||
1812 !CFBooleanGetValue(onConsole
)) {
1813 // if not "on console" session
1818 CFDictionaryGetValueIfPresent(session
,
1819 CFSTR(kIOConsoleSessionLoginDoneKey
),
1820 (const void **)&isLoginDone
) &&
1821 isA_CFBoolean(isLoginDone
) &&
1822 !CFBooleanGetValue(isLoginDone
)) {
1824 SC_log(LOG_INFO
, "multiple sessions, console @ loginwindow");
1829 if (CFDictionaryGetValueIfPresent(session
,
1830 CFSTR(kIOConsoleSessionScreenIsLockedKey
),
1831 (const void **)&isLocked
) &&
1832 isA_CFBoolean(isLocked
) &&
1833 CFBooleanGetValue(isLocked
)) {
1835 SC_log(LOG_INFO
, "console screen locked");
1842 SC_log(LOG_INFO
, "console not locked");
1846 if (console_sessions
!= NULL
) {
1847 CFRelease(console_sessions
);
1849 IOObjectRelease(root
);
1854 //#define ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
1855 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
1857 static CFUserNotificationRef userNotification
;
1858 static CFRunLoopSourceRef userRls
;
1861 lockedNotification_remove(void)
1863 if (userRls
!= NULL
) {
1864 CFRunLoopSourceInvalidate(userRls
);
1868 if (userNotification
!= NULL
) {
1871 status
= CFUserNotificationCancel(userNotification
);
1874 "CFUserNotificationCancel() failed, status=%d",
1877 CFRelease(userNotification
);
1878 userNotification
= NULL
;
1884 #define MY_ICON_PATH "/System/Library/PreferencePanes/Network.prefPane/Contents/Resources/Network.icns"
1887 lockedNotification_reply(CFUserNotificationRef userNotification
, CFOptionFlags response_flags
)
1889 #pragma unused(userNotification)
1891 os_activity_t activity
;
1894 activity
= os_activity_create("process locked interface notification",
1895 OS_ACTIVITY_CURRENT
,
1896 OS_ACTIVITY_FLAG_DEFAULT
);
1897 os_activity_scope(activity
);
1899 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
1900 for (CFIndex i
= 0; i
< n
; i
++) {
1901 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
1902 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1904 // process user response
1905 switch (response_flags
& 0x3) {
1906 case kCFUserNotificationDefaultResponse
: {
1907 // if OK'd, [re-]process new interfaces
1909 SC_log(LOG_INFO
, "Reprocessing %ld [locked] interface%s", n
, n
== 1 ? "" : "s");
1911 if (S_iflist
== NULL
) {
1912 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1916 // add the interface to those newly discovered
1917 CFArrayAppendValue(S_iflist
, watchedInfo
->interface
);
1921 // if cancelled, ignore [remaining] new interfaces
1922 SC_log(LOG_INFO
, "[locked] interface ignored");
1923 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
1929 watcherRelease(watched
);
1932 if (S_locked
!= NULL
) {
1933 CFRelease(S_locked
);
1937 lockedNotification_remove();
1939 if (S_iflist
!= NULL
) {
1943 os_release(activity
);
1949 lockedNotification_add(void)
1952 CFMutableDictionaryRef dict
;
1954 CFMutableArrayRef message
;
1956 CFURLRef url
= NULL
;
1958 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
1960 // no locked interfaces, no notification needed
1964 dict
= CFDictionaryCreateMutable(NULL
,
1966 &kCFTypeDictionaryKeyCallBacks
,
1967 &kCFTypeDictionaryValueCallBacks
);
1969 // set localization URL
1970 bundle
= _SC_CFBundleGet();
1971 if (bundle
!= NULL
) {
1972 url
= CFBundleCopyBundleURL(bundle
);
1976 CFDictionarySetValue(dict
, kCFUserNotificationLocalizationURLKey
, url
);
1979 SC_log(LOG_ERR
, "can't find bundle");
1984 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
1985 (const UInt8
*)MY_ICON_PATH
,
1986 sizeof(MY_ICON_PATH
) - 1,
1989 CFDictionarySetValue(dict
, kCFUserNotificationIconURLKey
, url
);
1994 CFDictionarySetValue(dict
,
1995 kCFUserNotificationAlertHeaderKey
,
1996 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_HEADER")
1997 : CFSTR("LOCKED_MULTIPLE_INTERFACES_HEADER"));
2000 message
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2001 CFArrayAppendValue(message
,
2002 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_MESSAGE")
2003 : CFSTR("LOCKED_MULTIPLE_INTERFACES_MESSAGE"));
2004 for (CFIndex i
= 0; i
< n
; i
++) {
2007 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
2008 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2010 name
= SCNetworkInterfaceGetLocalizedDisplayName(watchedInfo
->interface
);
2011 str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("\r\t%@"), name
);
2012 CFArrayAppendValue(message
, str
);
2015 CFDictionarySetValue(dict
, kCFUserNotificationAlertMessageKey
, message
);
2019 CFDictionarySetValue(dict
,
2020 kCFUserNotificationDefaultButtonTitleKey
,
2021 CFSTR("LOCKED_INTERFACES_IGNORE"));
2022 CFDictionarySetValue(dict
,
2023 kCFUserNotificationAlternateButtonTitleKey
,
2024 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_ADD")
2025 : CFSTR("LOCKED_MULTIPLE_INTERFACES_ADD"));
2027 // create and post notification
2028 userNotification
= CFUserNotificationCreate(NULL
,
2030 kCFUserNotificationNoteAlertLevel
,
2033 if (userNotification
== NULL
) {
2034 SC_log(LOG_ERR
, "CFUserNotificationCreate() failed: %d", (int)error
);
2038 // establish callback
2039 userRls
= CFUserNotificationCreateRunLoopSource(NULL
,
2041 lockedNotification_reply
,
2043 if (userRls
== NULL
) {
2044 SC_log(LOG_ERR
, "CFUserNotificationCreateRunLoopSource() failed");
2045 CFRelease(userNotification
);
2046 userNotification
= NULL
;
2049 CFRunLoopAddSource(CFRunLoopGetCurrent(), userRls
, kCFRunLoopDefaultMode
);
2053 if (dict
!= NULL
) CFRelease(dict
);
2058 lockedNotification_update(void)
2060 // if present, remove current notification
2061 lockedNotification_remove();
2063 // post notification (if needed)
2064 lockedNotification_add();
2069 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2072 lockedInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2074 #pragma unused(messageArgument)
2075 Boolean updated
= FALSE
;
2076 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2078 switch (messageType
) {
2079 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2080 SC_log(LOG_INFO
, "[locked] interface removed");
2081 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
2083 if (S_locked
!= NULL
) {
2085 CFIndex n
= CFArrayGetCount(S_locked
);
2087 i
= CFArrayGetFirstIndexOfValue(S_locked
, CFRangeMake(0, n
), watched
);
2088 if (i
!= kCFNotFound
) {
2089 CFArrayRemoveValueAtIndex(S_locked
, i
);
2090 if (CFArrayGetCount(S_locked
) == 0) {
2091 CFRelease(S_locked
);
2106 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2107 // update user notification after interface removed
2108 lockedNotification_update();
2109 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2111 // post info about interfaces not added because the console is locked
2119 watchLockedInterface(SCNetworkInterfaceRef interface
)
2121 Boolean updated
= FALSE
;
2124 watched
= watcherCreate(interface
, lockedInterfaceUpdated
);
2125 if (watched
!= NULL
) {
2126 SC_log(LOG_INFO
, "watching [locked] interface");
2127 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(interface
));
2129 if (S_locked
== NULL
) {
2130 S_locked
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2132 CFArrayAppendValue(S_locked
, watched
);
2137 // post info about interfaces not added because the console is locked
2140 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2141 // post/update user notification with new interface
2142 lockedNotification_update();
2143 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2148 #endif // !TARGET_OS_IPHONE
2152 #pragma mark Trust required support [iOS]
2155 #if TARGET_OS_IPHONE
2159 CFMutableArrayRef excluded
= NULL
;
2162 n
= (S_trustRequired
!= NULL
) ? CFArrayGetCount(S_trustRequired
) : 0;
2163 if ((n
> 0) && !S_trustedHostAttached
) {
2164 // if we have interfaces that require not [yet] granted "trust".
2166 excluded
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2168 for (CFIndex i
= 0; i
< n
; i
++) {
2169 CFStringRef bsdName
;
2170 CFDataRef watched
= CFArrayGetValueAtIndex(S_trustRequired
, i
);
2171 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2173 bsdName
= SCNetworkInterfaceGetBSDName(watchedInfo
->interface
);
2174 if (bsdName
== NULL
) {
2175 SC_log(LOG_NOTICE
, "[trust required] excluded interface w/no BSD name");
2176 SC_log(LOG_NOTICE
, " interface = %@", watchedInfo
->interface
);
2179 CFArrayAppendValue(excluded
, bsdName
);
2183 if (excluded
!= NULL
) {
2184 CFDictionarySetValue(S_state
, kInterfaceNamerKey_ExcludedInterfaces
, excluded
);
2185 CFRelease(excluded
);
2187 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_ExcludedInterfaces
);
2195 static dispatch_queue_t
2196 trustRequired_queue()
2198 static dispatch_once_t once
;
2199 static dispatch_queue_t q
;
2201 dispatch_once(&once
, ^{
2202 q
= dispatch_queue_create("Trust Required queue", NULL
);
2209 // runs on "Trust Required" dispatch queue
2211 trustRequiredNotification_update(CFRunLoopRef rl
, CFStringRef reason
)
2213 Boolean curTrusted
= FALSE
;
2214 CFBooleanRef trusted
;
2216 trusted
= lockdown_copy_trustedHostAttached();
2217 if (trusted
!= NULL
) {
2218 curTrusted
= isA_CFBoolean(trusted
) && CFBooleanGetValue(trusted
);
2222 SC_log(LOG_INFO
, "%@, trusted = %s", reason
, curTrusted
? "Yes" : "No");
2224 if (S_trustedHostAttached
!= curTrusted
) {
2225 S_trustedHostAttached
= curTrusted
;
2226 CFRunLoopPerformBlock(rl
, kCFRunLoopDefaultMode
, ^{
2229 CFRunLoopWakeUp(rl
);
2236 trustRequiredInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2238 #pragma unused(messageArgument)
2239 Boolean updated
= FALSE
;
2240 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2242 switch (messageType
) {
2243 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2244 SC_log(LOG_INFO
, "[trust required] interface removed");
2245 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
2247 if (S_trustRequired
!= NULL
) {
2249 CFIndex n
= CFArrayGetCount(S_trustRequired
);
2251 i
= CFArrayGetFirstIndexOfValue(S_trustRequired
, CFRangeMake(0, n
), watched
);
2252 if (i
!= kCFNotFound
) {
2253 CFArrayRemoveValueAtIndex(S_trustRequired
, i
);
2254 if (CFArrayGetCount(S_trustRequired
) == 0) {
2255 CFRelease(S_trustRequired
);
2256 S_trustRequired
= NULL
;
2270 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2273 dispatch_async(trustRequired_queue(), ^{
2274 trustRequiredNotification_update(rl
, CFSTR("TrustRequired interface removed"));
2283 watchTrustedStatus(CFStringRef notification
, CFStringRef reason
)
2286 int notify_token
= -1;
2288 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2290 key
= CFStringGetCStringPtr(notification
, kCFStringEncodingUTF8
);
2291 assert(key
!= NULL
);
2295 ret
= notify_register_dispatch(key
,
2297 trustRequired_queue(),
2299 #pragma unused(token)
2300 trustRequiredNotification_update(rl
, reason
);
2302 if (ret
!= NOTIFY_STATUS_OK
) {
2303 SC_log(LOG_ERR
, "notify_register_dispatch(%@) failed: %u", notification
, ret
);
2312 updateTrustRequiredInterfaces(CFArrayRef interfaces
)
2315 Boolean updated
= FALSE
;
2317 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
2318 for (CFIndex i
= 0; i
< n
; i
++) {
2319 SCNetworkInterfaceRef interface
;
2321 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2322 if (_SCNetworkInterfaceIsTrustRequired(interface
)) {
2325 watched
= watcherCreate(interface
, trustRequiredInterfaceUpdated
);
2326 if (watched
!= NULL
) {
2327 SC_log(LOG_INFO
, "watching [trust required] interface: %@",
2328 SCNetworkInterfaceGetBSDName(interface
));
2330 if (S_trustRequired
== NULL
) {
2331 S_trustRequired
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2333 CFArrayAppendValue(S_trustRequired
, watched
);
2340 static dispatch_once_t once
;
2341 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2343 dispatch_once(&once
, ^{
2344 // watch for "Trusted host attached"
2345 watchTrustedStatus(kLockdownNotificationTrustedHostAttached
,
2346 CFSTR("Trusted Host attached"));
2348 // watch for "Host detached"
2349 watchTrustedStatus(kLockdownNotificationHostDetached
,
2350 CFSTR("Host detached"));
2354 dispatch_async(trustRequired_queue(), ^{
2355 trustRequiredNotification_update(rl
, CFSTR("TrustRequired interface added"));
2362 #endif // TARGET_OS_IPHONE
2366 #pragma mark Interface naming
2369 static __inline__ boolean_t
2372 return (S_quiet
== MACH_PORT_NULL
);
2376 wasPreviouslyUsedInterface(CFDictionaryRef dbdict
, SCNetworkInterfaceRef interface
)
2378 CFArrayRef matchingMACs
;
2380 matchingMACs
= CFDictionaryGetValue(dbdict
, CFSTR(kSCNetworkInterfaceMatchingMACs
));
2381 if (matchingMACs
!= NULL
) {
2384 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
2386 if (CFArrayContainsValue(matchingMACs
,
2387 CFRangeMake(0, CFArrayGetCount(matchingMACs
)),
2398 nameInterfaces(CFMutableArrayRef if_list
)
2401 CFIndex n
= CFArrayGetCount(if_list
);
2403 for (i
= 0; i
< n
; i
++) {
2405 SCNetworkInterfaceRef interface
;
2406 SCNetworkInterfaceRef new_interface
;
2412 interface
= CFArrayGetValueAtIndex(if_list
, i
);
2413 path
= _SCNetworkInterfaceGetIOPath(interface
);
2414 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
2415 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
2416 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
2419 CFStringRef if_name
;
2421 if_name
= SCNetworkInterfaceGetBSDName(interface
);
2422 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
2423 SC_log(LOG_INFO
, "Interface already has a unit number");
2424 displayInterface(interface
);
2427 // update the list of interfaces that were previously named
2428 if ((S_prev_active_list
!= NULL
)
2429 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
2430 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
2433 replaceInterface(interface
);
2435 CFDictionaryRef dbdict
;
2436 boolean_t is_builtin
;
2440 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
2441 if (dbdict
!= NULL
) {
2442 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2445 SC_log(LOG_INFO
, "Interface assigned unit %@ (from database)", unit
);
2448 if ((dbdict
== NULL
) && !isQuiet()) {
2449 // if new interface, wait until quiet before naming
2450 addTimestamp(S_state
, path
);
2454 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
2456 if (dbdict
== NULL
) {
2457 dbdict
= lookupMatchingInterface(interface
,
2461 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
2463 if ((dbdict
!= NULL
) && wasPreviouslyUsedInterface(dbdict
, interface
)) {
2464 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2467 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database w/previously used interface)", unit
);
2470 #if !TARGET_OS_IPHONE
2471 if ((unit
== NULL
) &&
2474 blockNewInterfaces() &&
2475 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
2476 isConsoleLocked()) {
2479 // if new (but matching) interface and console locked, ignore
2480 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
2481 SC_log(LOG_NOTICE
, "Console locked, network interface* ignored");
2482 SC_log(LOG_INFO
, " path = %@, addr = %@",
2484 (addr
!= NULL
) ? addr
: CFSTR("?"));
2485 watchLockedInterface(interface
);
2488 #endif // !TARGET_OS_IPHONE
2490 if ((unit
== NULL
) && (dbdict
!= NULL
)) {
2491 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2494 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database w/new interface)", unit
);
2498 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
2499 // update the list of interfaces that were previously named
2500 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
2501 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
2503 if (where
!= kCFNotFound
) {
2504 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
2508 if (dbdict
== NULL
) {
2512 // built-in interface, try to use the reserved slots
2513 next_unit
= builtinCount(if_list
, i
, type
);
2515 // But, before claiming a reserved slot we check to see if the
2516 // slot had previously been used. If so, and if the slot had been
2517 // assigned to the same type of interface, then we will perform a
2518 // replacement (e.g. assume that this was a board swap). But, if
2519 // the new interface is a different type then we assume that the
2520 // built-in configuration has changed and allocate a new unit from
2521 // the non-reserved slots.
2523 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
2524 if (!builtinAvailable(interface
, unit
)) {
2525 // if [built-in] unit not available
2526 SC_log(LOG_INFO
, "Interface not assigned [built-in] unit %@", unit
);
2532 #if !TARGET_OS_IPHONE
2535 blockNewInterfaces() &&
2536 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
2537 isConsoleLocked()) {
2540 // if new interface and console locked, ignore
2541 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
2542 SC_log(LOG_NOTICE
, "Console locked, network interface ignored");
2543 SC_log(LOG_INFO
, " path = %@, addr = %@",
2545 (addr
!= NULL
) ? addr
: CFSTR("?"));
2546 watchLockedInterface(interface
);
2549 #endif // !TARGET_OS_IPHONE
2552 // not built-in (or built-in unit not available), allocate from
2553 // the non-reserved slots
2554 next_unit
= builtinCount(if_list
, n
, type
);
2556 unit
= getHighestUnitForType(type
);
2560 CFNumberGetValue(unit
, kCFNumberIntType
, &high_unit
);
2561 if (high_unit
>= next_unit
) {
2562 next_unit
= high_unit
+ 1;
2566 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
2569 SC_log(LOG_INFO
, "Interface assigned unit %@ (%s)",
2571 is_builtin
? "built-in" : "next available");
2576 #ifdef USE_REGISTRY_ENTRY_ID
2577 kr
= registerInterfaceWithIORegistryEntryID(S_connect
,
2580 (dbdict
== NULL
) ? kIONetworkStackRegisterInterfaceWithLowestUnit
2581 : kIONetworkStackRegisterInterfaceWithUnit
);
2582 new_interface
= copyNamedInterfaceForIORegistryEntryID(entryID
);
2583 #else // USE_REGISTRY_ENTRY_ID
2584 kr
= registerInterfaceWithIOServicePath(S_connect
,
2587 (dbdict
== NULL
) ? kRegisterInterface
2588 : kRegisterInterfaceWithFixedUnit
);
2589 new_interface
= copyNamedInterfaceForIOKitPath(path
);
2590 #endif // USE_REGISTRY_ENTRY_ID
2591 if (new_interface
== NULL
) {
2592 const char *signature
;
2594 signature
= (dbdict
== NULL
) ? "failed to name new interface"
2595 : "failed to name known interface";
2597 SC_log(LOG_NOTICE
, "%s, kr=0x%x\n"
2607 displayInterface(interface
);
2609 if ((dbdict
!= NULL
) && (retries
++ < 5)) {
2610 usleep(50 * 1000); // sleep 50ms between attempts
2615 CFNumberRef new_unit
;
2618 SC_log(LOG_INFO
, "%s interface named after %d %s\n"
2621 (dbdict
== NULL
) ? "New" : "Known",
2623 (retries
== 1) ? "try" : "tries",
2627 #ifdef SHOW_NAMING_FAILURE
2628 str
= CFStringCreateWithFormat(NULL
,
2630 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
2631 (dbdict
== NULL
) ? "New" : "Known",
2633 (retries
== 1) ? "try" : "tries",
2635 CFUserNotificationDisplayNotice(0,
2636 kCFUserNotificationStopAlertLevel
,
2641 CFSTR("Please report repeated failures."),
2644 #endif // SHOW_NAMING_FAILURE
2647 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
2648 if (!CFEqual(unit
, new_unit
)) {
2649 SC_log(LOG_INFO
, "interface type %@ assigned unit %@ instead of %@",
2650 type
, new_unit
, unit
);
2653 displayInterface(new_interface
);
2655 // update if_list (with the interface name & unit)
2656 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
2657 CFRelease(new_interface
);
2658 interface
= new_interface
; // if_list holds the reference
2660 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
2663 // update the list of [built-in] interfaces that were previously named
2664 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
2665 SC_log(LOG_DEBUG
, " and updated database (new address)");
2666 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
2669 replaceInterface(interface
);
2677 #if !TARGET_OS_IPHONE
2681 static Boolean isRecovery
= FALSE
;
2682 static dispatch_once_t once
;
2685 * We check to see if the UserEventAgent daemon is present. If not, then
2686 * we are most likely booted into the Recovery OS with no "SCMonitor"
2687 * [UserEventAgent] plugin.
2689 dispatch_once(&once
, ^{
2690 if ((access("/usr/libexec/UserEventAgent", X_OK
) == -1) && (errno
== ENOENT
)) {
2700 updateNetworkConfiguration(CFArrayRef if_list
)
2702 Boolean do_commit
= FALSE
;
2705 SCPreferencesRef prefs
= NULL
;
2706 SCNetworkSetRef set
= NULL
;
2708 prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":updateNetworkConfiguration"), NULL
);
2709 if (prefs
== NULL
) {
2710 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
2714 set
= SCNetworkSetCopyCurrent(prefs
);
2716 SC_log(LOG_INFO
, "No current set, adding default");
2717 set
= _SCNetworkSetCreateDefault(prefs
);
2719 SC_log(LOG_NOTICE
, "_SCNetworkSetCreateDefault() failed: %s", SCErrorString(SCError()));
2724 n
= (if_list
!= NULL
) ? CFArrayGetCount(if_list
) : 0;
2725 for (i
= 0; i
< n
; i
++) {
2726 SCNetworkInterfaceRef interface
;
2728 interface
= CFArrayGetValueAtIndex(if_list
, i
);
2729 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set
, interface
)) {
2730 SC_log(LOG_INFO
, "adding default configuration for %@",
2731 SCNetworkInterfaceGetBSDName(interface
));
2739 ok
= SCPreferencesCommitChanges(prefs
);
2741 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
2745 ok
= SCPreferencesApplyChanges(prefs
);
2747 SC_log(LOG_NOTICE
, "SCPreferencesApplyChanges() failed: %s", SCErrorString(SCError()));
2759 if (prefs
!= NULL
) {
2766 #endif // !TARGET_OS_IPHONE
2769 sharePreconfigured()
2773 n
= (S_preconfigured
!= NULL
) ? CFArrayGetCount(S_preconfigured
) : 0;
2775 CFMutableArrayRef preconfigured
;
2777 preconfigured
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2779 for (CFIndex i
= 0; i
< n
; i
++) {
2780 CFStringRef bsdName
;
2781 CFDataRef watched
= CFArrayGetValueAtIndex(S_preconfigured
, i
);
2782 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2784 bsdName
= SCNetworkInterfaceGetBSDName(watchedInfo
->interface
);
2785 CFArrayAppendValue(preconfigured
, bsdName
);
2788 CFDictionarySetValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
, preconfigured
);
2789 CFRelease(preconfigured
);
2791 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
);
2800 preconfiguredInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2802 Boolean updated
= FALSE
;
2803 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2805 #pragma unused(messageArgument)
2806 switch (messageType
) {
2807 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2808 SC_log(LOG_INFO
, "[pre-configured] interface removed: %@",
2809 SCNetworkInterfaceGetBSDName(watchedInfo
->interface
));
2811 if (S_preconfigured
!= NULL
) {
2813 CFIndex n
= CFArrayGetCount(S_preconfigured
);
2815 i
= CFArrayGetFirstIndexOfValue(S_preconfigured
, CFRangeMake(0, n
), watched
);
2816 if (i
!= kCFNotFound
) {
2817 CFArrayRemoveValueAtIndex(S_preconfigured
, i
);
2818 if (CFArrayGetCount(S_preconfigured
) == 0) {
2819 CFRelease(S_preconfigured
);
2820 S_preconfigured
= NULL
;
2834 sharePreconfigured();
2841 updatePreConfiguredInterfaces(CFArrayRef interfaces
)
2844 Boolean updated
= FALSE
;
2846 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
2847 for (CFIndex i
= 0; i
< n
; i
++) {
2848 SCNetworkInterfaceRef interface
;
2850 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2851 if (_SCNetworkInterfaceIsApplePreconfigured(interface
)) {
2854 watched
= watcherCreate(interface
, preconfiguredInterfaceUpdated
);
2855 if (watched
!= NULL
) {
2856 SC_log(LOG_INFO
, "watching [pre-configured] interface: %@",
2857 SCNetworkInterfaceGetBSDName(interface
));
2859 if (S_preconfigured
== NULL
) {
2860 S_preconfigured
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2862 CFArrayAppendValue(S_preconfigured
, watched
);
2869 sharePreconfigured();
2878 if (S_connect
== MACH_PORT_NULL
) {
2879 // if we don't have the "IONetworkStack" connect object
2883 if (S_iflist
!= NULL
) {
2886 n
= CFArrayGetCount(S_iflist
);
2888 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
2890 nameInterfaces(S_iflist
);
2894 * Update the list of [Apple] pre-configured interfaces
2896 updatePreConfiguredInterfaces(S_iflist
);
2898 #if TARGET_OS_IPHONE
2900 * Update the list of "trust required" interfaces
2902 updateTrustRequiredInterfaces(S_iflist
);
2903 #endif // TARGET_OS_IPHONE
2907 * The registry [matching] has quiesced so let's
2908 * - save the DB with the interfaces that have been named
2909 * - update the VLAN/BOND configuration
2910 * - tell everyone that we've finished (at least for now)
2911 * - log those interfaces which are no longer present
2912 * in the HW config (or have yet to show up).
2914 writeInterfaceList(S_dblist
);
2915 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
2917 #if !TARGET_OS_IPHONE
2918 if (isRecoveryOS()) {
2920 * We are most likely booted into the Recovery OS with no "SCMonitor"
2921 * UserEventAgent plugin running so let's make sure we update the
2922 * network configuration for new interfaces.
2924 updateNetworkConfiguration(S_iflist
);
2926 #endif // !TARGET_OS_IPHONE
2930 if (S_iflist
!= NULL
) {
2931 CFRelease(S_iflist
);
2935 if (S_prev_active_list
!= NULL
) {
2939 n
= CFArrayGetCount(S_prev_active_list
);
2941 SC_log(LOG_INFO
, "Interface%s not [yet] active",
2942 (n
> 1) ? "s" : "");
2944 for (i
= 0; i
< n
; i
++) {
2945 CFDictionaryRef if_dict
;
2950 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
2951 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
2952 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
2953 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
2954 SC_log(LOG_INFO
, " %s%@%sType: %@, Unit: %@",
2955 (name
!= NULL
) ? "BSD Name: " : "",
2956 (name
!= NULL
) ? name
: CFSTR(""),
2957 (name
!= NULL
) ? ", " : "",
2962 CFRelease(S_prev_active_list
);
2963 S_prev_active_list
= NULL
;
2966 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
2968 * if we've named all of the interfaces that
2969 * were used during the previous boot.
2971 addTimestamp(S_state
, CFSTR("*RELEASE*"));
2972 SC_log(LOG_INFO
, "last boot interfaces have been named");
2974 CFRelease(S_prev_active_list
);
2975 S_prev_active_list
= NULL
;
2983 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
2985 #pragma unused(refcon)
2986 os_activity_t activity
;
2989 activity
= os_activity_create("process new network interface",
2990 OS_ACTIVITY_CURRENT
,
2991 OS_ACTIVITY_FLAG_DEFAULT
);
2992 os_activity_scope(activity
);
2994 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
2995 SCNetworkInterfaceRef interface
;
2997 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
2998 if (interface
!= NULL
) {
2999 if (S_iflist
== NULL
) {
3000 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3002 CFArrayAppendValue(S_iflist
, interface
);
3003 CFRelease(interface
);
3005 IOObjectRelease(obj
);
3010 os_release(activity
);
3016 * Function: stackCallback
3018 * Get a reference to the single IONetworkStack object instance in
3019 * the kernel. Naming requests must be sent to this object, which is
3020 * attached as a client to all network interface objects in the system.
3022 * Call IOObjectRelease on the returned object.
3025 stackCallback(void *refcon
, io_iterator_t iter
)
3027 #pragma unused(refcon)
3028 os_activity_t activity
;
3032 activity
= os_activity_create("process IONetworkStack",
3033 OS_ACTIVITY_CURRENT
,
3034 OS_ACTIVITY_FLAG_DEFAULT
);
3035 os_activity_scope(activity
);
3037 stack
= IOIteratorNext(iter
);
3038 if (stack
== MACH_PORT_NULL
) {
3042 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
3043 if (kr
!= KERN_SUCCESS
) {
3044 SC_log(LOG_ERR
, "IOServiceOpen returned 0x%x", kr
);
3048 addTimestamp(S_state
, CFSTR("*STACK*"));
3049 SC_log(LOG_INFO
, "IONetworkStack found");
3051 if (S_stack
!= MACH_PORT_NULL
) {
3052 IOObjectRelease(S_stack
);
3053 S_stack
= MACH_PORT_NULL
;
3056 if ((S_timer
!= NULL
) && CFRunLoopTimerIsValid(S_timer
)) {
3057 // With the IONetworkStack object now available we can
3058 // reset (shorten?) the time we are willing to wait for
3059 // IOKit to quiesce.
3060 CFRunLoopTimerSetNextFireDate(S_timer
,
3061 CFAbsoluteTimeGetCurrent() + S_quiet_timeout
);
3068 if (stack
!= MACH_PORT_NULL
) {
3069 IOObjectRelease(stack
);
3072 os_release(activity
);
3078 quietCallback(void *refcon
,
3079 io_service_t service
,
3080 natural_t messageType
,
3081 void *messageArgument
)
3083 #pragma unused(refcon)
3084 #pragma unused(service)
3085 os_activity_t activity
;
3087 if (messageArgument
!= NULL
) {
3092 activity
= os_activity_create("process IOKit quiet",
3093 OS_ACTIVITY_CURRENT
,
3094 OS_ACTIVITY_FLAG_DEFAULT
);
3095 os_activity_scope(activity
);
3097 if (messageType
== kIOMessageServiceBusyStateChange
) {
3098 addTimestamp(S_state
, kInterfaceNamerKey_Quiet
);
3099 SC_log(LOG_INFO
, "IOKit quiet");
3102 if (S_connect
== MACH_PORT_NULL
) {
3103 SC_log(LOG_ERR
, "No network stack object");
3107 if (S_quiet
!= MACH_PORT_NULL
) {
3108 IOObjectRelease(S_quiet
);
3109 S_quiet
= MACH_PORT_NULL
;
3112 if (S_timer
!= NULL
) {
3113 CFRunLoopTimerInvalidate(S_timer
);
3118 // grab (and name) any additional interfaces.
3119 interfaceArrivalCallback((void *)S_notify
, S_iter
);
3121 if (messageType
== kIOMessageServiceBusyStateChange
) {
3122 addTimestamp(S_state
, CFSTR("*QUIET&NAMED*"));
3128 os_release(activity
);
3134 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, int *count
)
3136 kern_return_t kr
= kIOReturnSuccess
;;
3139 while ((kr
== kIOReturnSuccess
) &&
3140 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
3141 uint64_t accumulated_busy_time
;
3142 uint32_t busy_state
;
3145 CFMutableArrayRef newNodes
;
3147 CFMutableStringRef str
= NULL
;
3149 if (nodes
== NULL
) {
3150 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3152 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
3154 assert(newNodes
!= NULL
);
3156 kr
= IORegistryEntryGetName(obj
, name
);
3157 if (kr
!= kIOReturnSuccess
) {
3158 SC_log(LOG_NOTICE
, "IORegistryEntryGetName() returned 0x%x", kr
);
3162 str
= CFStringCreateMutable(NULL
, 0);
3163 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
3165 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
3167 case kIOReturnSuccess
:
3168 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
3169 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
3171 case kIOReturnNotFound
:
3174 SC_log(LOG_NOTICE
, "IORegistryEntryGetLocationInPlane() returned 0x%x", kr
);
3179 CFArrayAppendValue(newNodes
, str
);
3182 kr
= IOServiceGetBusyStateAndTime(obj
, &state
, &busy_state
, &accumulated_busy_time
);
3183 if (kr
!= kIOReturnSuccess
) {
3184 SC_log(LOG_NOTICE
, "IOServiceGetBusyStateAndTime() returned 0x%x", kr
);
3188 #ifdef TEST_SNAPSHOT
3191 #endif // TEST_SNAPSHOT
3193 if (busy_state
!= 0) {
3196 if ((*count
)++ == 0) {
3197 SC_log(LOG_ERR
, "Busy services :");
3200 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
3201 SC_log(LOG_ERR
, " %@ [%s%s%s%d, %lld ms]",
3203 (state
& kIOServiceRegisteredState
) ? "" : "!registered, ",
3204 (state
& kIOServiceMatchedState
) ? "" : "!matched, ",
3205 (state
& kIOServiceInactiveState
) ? "inactive, " : "",
3207 accumulated_busy_time
/ kMillisecondScale
);
3211 kr
= IORegistryIteratorEnterEntry(iterator
);
3212 if (kr
!= kIOReturnSuccess
) {
3213 SC_log(LOG_NOTICE
, "IORegistryIteratorEnterEntry() returned 0x%x", kr
);
3217 iterateRegistryBusy(iterator
, newNodes
, count
);
3219 kr
= IORegistryIteratorExitEntry(iterator
);
3220 if (kr
!= kIOReturnSuccess
) {
3221 SC_log(LOG_NOTICE
, "IORegistryIteratorExitEntry() returned 0x%x", kr
);
3226 CFRelease(newNodes
);
3227 IOObjectRelease(obj
);
3237 io_iterator_t iterator
= MACH_PORT_NULL
;
3240 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
3244 if (kr
!= kIOReturnSuccess
) {
3245 SC_log(LOG_NOTICE
, "IORegistryCreateIterator() returned 0x%x", kr
);
3249 iterateRegistryBusy(iterator
, NULL
, &count
);
3251 SC_log(LOG_ERR
, "w/no busy services");
3254 IOObjectRelease(iterator
);
3258 timerCallback(CFRunLoopTimerRef timer
, void *info
)
3260 #pragma unused(timer)
3261 #pragma unused(info)
3262 os_activity_t activity
;
3264 activity
= os_activity_create("process IOKit timer",
3265 OS_ACTIVITY_CURRENT
,
3266 OS_ACTIVITY_FLAG_DEFAULT
);
3267 os_activity_scope(activity
);
3269 // We've been waiting for IOKit to quiesce and it just
3270 // hasn't happenned. Time to just move on!
3271 addTimestamp(S_state
, kInterfaceNamerKey_Timeout
);
3274 SC_log(LOG_ERR
, "timed out waiting for IOKit to quiesce");
3277 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
3279 addTimestamp(S_state
, CFSTR("*TIMEOUT&NAMED*"));
3282 os_release(activity
);
3288 setup_IOKit(CFBundleRef bundle
)
3290 #pragma unused(bundle)
3293 mach_port_t masterPort
= MACH_PORT_NULL
;
3295 io_object_t root
= MACH_PORT_NULL
;
3297 // read DB of previously named network interfaces
3298 S_dblist
= readInterfaceList();
3299 if (S_dblist
!= NULL
) {
3302 n
= CFArrayGetCount(S_dblist
);
3304 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
3308 // get interfaces that were named during the last boot
3309 S_prev_active_list
= previouslyActiveInterfaces();
3311 // track how long we've waited to see each interface.
3312 S_state
= CFDictionaryCreateMutable(NULL
,
3314 &kCFTypeDictionaryKeyCallBacks
,
3315 &kCFTypeDictionaryValueCallBacks
);
3316 addTimestamp(S_state
, CFSTR("*START*"));
3318 // Creates and returns a notification object for receiving IOKit
3319 // notifications of new devices or state changes.
3320 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
3321 if (kr
!= KERN_SUCCESS
) {
3322 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
3326 S_notify
= IONotificationPortCreate(masterPort
);
3327 if (S_notify
== NULL
) {
3328 SC_log(LOG_ERR
, "IONotificationPortCreate failed");
3332 // watch IOKit matching activity
3333 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
3334 if (root
== MACH_PORT_NULL
) {
3335 SC_log(LOG_ERR
, "IORegistryEntryFromPath failed");
3339 kr
= IOServiceAddInterestNotification(S_notify
,
3343 (void *)S_notify
, // refCon
3344 &S_quiet
); // notification
3345 if (kr
!= KERN_SUCCESS
) {
3346 SC_log(LOG_ERR
, "IOServiceAddInterestNotification returned 0x%x", kr
);
3350 kr
= IOServiceGetBusyState(root
, &busy
);
3351 if (kr
!= KERN_SUCCESS
) {
3352 SC_log(LOG_ERR
, "IOServiceGetBusyState returned 0x%x", kr
);
3356 // add a timer so we don't wait forever for IOKit to quiesce
3357 S_timer
= CFRunLoopTimerCreate(NULL
,
3358 CFAbsoluteTimeGetCurrent() + S_stack_timeout
,
3364 if (S_timer
== NULL
) {
3365 SC_log(LOG_ERR
, "CFRunLoopTimerCreate failed");
3369 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
3371 // watch for the introduction of the IONetworkStack
3372 kr
= IOServiceAddMatchingNotification(S_notify
,
3373 kIOFirstMatchNotification
,
3374 IOServiceMatching("IONetworkStack"),
3376 (void *)S_notify
, // refCon
3377 &S_stack
); // notification
3378 if (kr
!= KERN_SUCCESS
) {
3379 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
3383 // check and see if the stack is already available and arm the
3384 // notification for its introduction.
3385 stackCallback((void *)S_notify
, S_stack
);
3387 // watch for the introduction of new network interfaces
3388 kr
= IOServiceAddMatchingNotification(S_notify
,
3389 kIOFirstMatchNotification
,
3390 IOServiceMatching("IONetworkInterface"),
3391 &interfaceArrivalCallback
,
3392 (void *)S_notify
, // refCon
3393 &S_iter
); // notification
3394 if (kr
!= KERN_SUCCESS
) {
3395 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
3399 // Get the current list of matches and arm the notification for
3400 // future interface arrivals.
3401 interfaceArrivalCallback((void *)S_notify
, S_iter
);
3403 // Check if IOKit has already quiesced.
3404 quietCallback((void *)S_notify
,
3406 kIOMessageServiceBusyStateChange
,
3407 (void *)(uintptr_t)busy
);
3409 CFRunLoopAddSource(CFRunLoopGetCurrent(),
3410 IONotificationPortGetRunLoopSource(S_notify
),
3411 kCFRunLoopDefaultMode
);
3413 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
3415 * Start the wheels turning until we've named all of
3416 * the interfaces that were used during the previous
3417 * boot, until IOKit [matching] has quiesced, or
3418 * until we've waited long enough.
3420 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
3421 CFRunLoopAddSource(CFRunLoopGetCurrent(),
3422 IONotificationPortGetRunLoopSource(S_notify
),
3424 while (S_prev_active_list
!= NULL
) {
3427 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
3429 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
3432 if (S_dblist
!= NULL
) {
3433 // apply special handling for the BT-PAN interface (if present)
3434 CFArrayApplyFunction(S_dblist
,
3435 CFRangeMake(0, CFArrayGetCount(S_dblist
)),
3436 updateBTPANInformation
,
3439 #endif // TARGET_OS_OSX
3444 if (root
!= MACH_PORT_NULL
) {
3445 IOObjectRelease(root
);
3447 if (masterPort
!= MACH_PORT_NULL
) {
3448 mach_port_deallocate(mach_task_self(), masterPort
);
3455 setup_Virtual(CFBundleRef bundle
)
3457 #pragma unused(bundle)
3458 // open a SCPreferences session
3459 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":setup_Virtual"), NULL
);
3460 if (S_prefs
== NULL
) {
3461 SC_log(LOG_ERR
, "SCPreferencesCreate() failed: %s",
3462 SCErrorString(SCError()));
3466 // register for change notifications.
3467 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
3468 SC_log(LOG_ERR
, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
3474 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
3475 if (SCError() != kSCStatusNoStoreServer
) {
3476 SC_log(LOG_ERR
, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
3486 exec_InterfaceNamer(void *arg
)
3488 CFBundleRef bundle
= (CFBundleRef
)arg
;
3489 CFDictionaryRef dict
;
3491 pthread_setname_np(MY_PLUGIN_NAME
" thread");
3493 dict
= CFBundleGetInfoDictionary(bundle
);
3494 if (isA_CFDictionary(dict
)) {
3497 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_STACK_TIMEOUT_KEY
));
3499 if (!isA_CFNumber(num
) ||
3500 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_stack_timeout
) ||
3501 (S_stack_timeout
<= 0.0)) {
3502 SC_log(LOG_NOTICE
, WAIT_STACK_TIMEOUT_KEY
" value error");
3503 S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
3507 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
3509 if (!isA_CFNumber(num
) ||
3510 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_quiet_timeout
) ||
3511 (S_quiet_timeout
<= 0.0)) {
3512 SC_log(LOG_NOTICE
, WAIT_QUIET_TIMEOUT_KEY
" value error");
3513 S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
3518 // setup virtual network interface monitoring
3519 if (!setup_Virtual(bundle
)) {
3523 // setup [IOKit] network interface monitoring
3524 if (!setup_IOKit(bundle
)) {
3531 if (S_connect
!= MACH_PORT_NULL
) {
3532 IOServiceClose(S_connect
);
3533 S_connect
= MACH_PORT_NULL
;
3535 if (S_dblist
!= NULL
) {
3536 CFRelease(S_dblist
);
3539 if (S_iter
!= MACH_PORT_NULL
) {
3540 IOObjectRelease(S_iter
);
3541 S_iter
= MACH_PORT_NULL
;
3543 if (S_notify
!= MACH_PORT_NULL
) {
3544 IONotificationPortDestroy(S_notify
);
3546 if (S_quiet
!= MACH_PORT_NULL
) {
3547 IOObjectRelease(S_quiet
);
3548 S_quiet
= MACH_PORT_NULL
;
3550 if (S_stack
!= MACH_PORT_NULL
) {
3551 IOObjectRelease(S_stack
);
3552 S_stack
= MACH_PORT_NULL
;
3554 if (S_state
!= NULL
) {
3558 if (S_timer
!= NULL
) {
3559 CFRunLoopTimerInvalidate(S_timer
);
3573 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
3575 #pragma unused(bundleVerbose)
3576 pthread_attr_t tattr
;
3579 CFRetain(bundle
); // released in exec_InterfaceNamer
3581 pthread_attr_init(&tattr
);
3582 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
3583 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
3584 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
3585 pthread_create(&tid
, &tattr
, exec_InterfaceNamer
, bundle
);
3586 pthread_attr_destroy(&tattr
);
3591 //------------------------------------------------------------------------
3595 main(int argc
, char ** argv
)
3600 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
3602 bundle
= CFBundleGetMainBundle();
3603 CFRetain(bundle
); // released in exec_InterfaceNamer
3605 (void)exec_InterfaceNamer();
3613 #ifdef TEST_SNAPSHOT
3615 main(int argc
, char ** argv
)
3617 CFStringRef snapshot
;
3620 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
3622 snapshot
= captureBusy();
3623 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), snapshot
);
3624 CFRelease(snapshot
);
3629 #endif /* TEST_SNAPSHOT */