2 * Copyright (c) 2001-2020 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 "SCPreferencesInternal.h"
89 #include "plugin_shared.h"
91 #include "InterfaceNamerControlPrefs.h"
92 #endif // !TARGET_OS_IPHONE
94 #ifdef TEST_INTERFACE_ASSIGNMENT
95 #undef INTERFACES_DEFAULT_CONFIG
96 #define INTERFACES_DEFAULT_CONFIG CFSTR("/tmp/ifnamer-test-NetworkInterfaces.plist")
97 #endif // TEST_INTERFACE_ASSIGNMENT
99 #include <IOKit/IOKitLib.h>
100 #include <IOKit/IOKitLibPrivate.h>
101 #include <IOKit/IOKitKeysPrivate.h>
102 #include <IOKit/IOBSD.h>
103 #include <IOKit/IOMessage.h>
104 #include <IOKit/network/IONetworkController.h>
105 #include <IOKit/network/IONetworkInterface.h>
106 #include <IOKit/network/IONetworkStack.h>
107 #include <IOKit/usb/USB.h>
109 #ifdef kIONetworkStackUserCommandKey
110 #define USE_REGISTRY_ENTRY_ID
113 #ifndef USE_REGISTRY_ENTRY_ID
114 // from <IOKit/network/IONetworkStack.h>
115 #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand"
117 kRegisterInterfaceWithFixedUnit
= 0,
119 kRegisterAllInterfaces
121 #endif // !USE_REGISTRY_ENTRY_ID
123 #define MY_PLUGIN_NAME "InterfaceNamer"
124 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
126 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
127 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
129 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
130 #define WAIT_QUIET_TIMEOUT_DEFAULT 240.0
134 * "IONetworkStack" connect object used to "name" an interface.
136 static io_connect_t S_connect
= MACH_PORT_NULL
;
140 * An array of CFDictionary's representing the interfaces
141 * that have been identified and [need to be] named.
143 static CFMutableArrayRef S_dblist
= NULL
;
147 * An array of SCNetworkInterface's representing the
148 * interfaces that have been identified.
150 static CFMutableArrayRef S_iflist
= NULL
;
154 * IOServiceAddMatchingNotification object used to watch for
155 * new network interfaces.
157 static io_iterator_t S_iter
= MACH_PORT_NULL
;
159 #if !TARGET_OS_IPHONE
162 * An array of CFData(WatchedInfo) objects representing those
163 * interfaces that have been connected to the system while
166 static CFMutableArrayRef S_locked
= NULL
;
167 #endif // !TARGET_OS_IPHONE
171 * notification object for receiving IOKit notifications of
172 * new devices or state changes.
174 static IONotificationPortRef S_notify
= NULL
;
178 * An array of CFData(WatchedInfo) objects representing those
179 * pre-configured interfaces that have been connected to the
182 static CFMutableArrayRef S_preconfigured
= NULL
;
184 /* S_prev_active_list
185 * An array of CFDictionary's representing the previously
188 static CFMutableArrayRef S_prev_active_list
= NULL
;
192 * IOServiceAddInterestNotification object used to watch for
193 * IOKit matching to quiesce.
195 static io_object_t S_quiet
= MACH_PORT_NULL
;
199 * IOServiceAddMatchingNotification object used to watch for
200 * the availability of the "IONetworkStack" object.
202 static io_iterator_t S_stack
= MACH_PORT_NULL
;
206 * A dictionary containing Information about each network
207 * interface. For now, the key is the BSD name and the
208 * value is a CFNumber noting how long (in milliseconds)
209 * it took for the interface to be recognized/named.
211 static CFMutableDictionaryRef S_state
= NULL
;
215 * S_trustedHostAttached
217 * Note: this global must only be updated on trustRequired_queue()
219 static Boolean S_trustedHostAttached
= FALSE
;
223 * Note: this global must only be updated on trustRequired_queue()
225 static CFIndex S_trustedHostCount
= 0;
229 * An array of CFData(WatchedInfo) objects representing those
230 * interfaces that require [lockdownd] trust.
232 static CFMutableArrayRef S_trustRequired
= NULL
;
233 #endif // TARGET_OS_IPHONE
237 * CFRunLoopTimer tracking how long we are willing to wait
238 * for IOKit matching to quiesce (IOKitWaitQuiet).
241 * time to wait for the IONetworkStack object to appear before timeout
244 * time to wait for the IOKit to quiesce (after the IONetworkStack is
247 static CFRunLoopTimerRef S_timer
= NULL
;
248 static double S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
249 static double S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
252 * Virtual network interface configuration
253 * S_prefs : SCPreferences to configuration
254 * S_bonds : most recently actived Bond configuration
255 * S_bridges : most recently actived Bridge configuration
256 * S_vlans : most recently actived VLAN configuration
258 static SCPreferencesRef S_prefs
= NULL
;
259 static CFArrayRef S_bonds
= NULL
;
260 static CFArrayRef S_bridges
= NULL
;
261 static CFArrayRef S_vlans
= NULL
;
268 __log_InterfaceNamer(void)
270 static os_log_t log
= NULL
;
273 log
= os_log_create("com.apple.SystemConfiguration", "InterfaceNamer");
281 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
286 now
= CFAbsoluteTimeGetCurrent();
287 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
288 CFDictionaryAddValue(dict
, key
, val
);
293 static CFComparisonResult
294 if_unit_compare(const void *val1
, const void *val2
, void *context
)
296 #pragma unused(context)
297 CFComparisonResult res
;
303 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
304 CFSTR(kIOInterfaceType
));
305 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
306 CFSTR(kIOInterfaceType
));
307 res
= CFNumberCompare(type1
, type2
, NULL
);
308 if (res
!= kCFCompareEqualTo
) {
311 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
312 CFSTR(kIOInterfaceUnit
));
313 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
314 CFSTR(kIOInterfaceUnit
));
315 return (CFNumberCompare(unit1
, unit2
, NULL
));
319 writeInterfaceListForModel(SCPreferencesRef prefs
, CFStringRef old_model
)
322 CFPropertyListRef plist
;
323 SCPreferencesRef savedPrefs
;
324 CFStringRef savedPrefsID
;
326 savedPrefsID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-%@"),
327 INTERFACES_DEFAULT_CONFIG
,
329 savedPrefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":writeInterfaceListForModel"), savedPrefsID
);
330 CFRelease(savedPrefsID
);
331 if (savedPrefs
== NULL
) {
332 SC_log(LOG_NOTICE
, "SCPreferencesCreate(\"NetworkInterfaces-<model>.plist\") failed: %s", SCErrorString(SCError()));
336 plist
= SCPreferencesPathGetValue(prefs
, CFSTR("/"));
337 ok
= SCPreferencesPathSetValue(savedPrefs
, CFSTR("/"), plist
);
339 SC_log(LOG_NOTICE
, "SCPreferencesPathSetValue() failed: %s", SCErrorString(SCError()));
342 ok
= SCPreferencesCommitChanges(savedPrefs
);
343 CFRelease(savedPrefs
);
345 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges(\"NetworkInterfaces-<model>.plist\") failed: %s", SCErrorString(SCError()));
352 writeInterfaceList(CFArrayRef if_list
)
355 CFStringRef new_model
;
356 SCPreferencesRef ni_prefs
;
357 CFStringRef old_model
;
359 if (!isA_CFArray(if_list
)) {
363 ni_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":writeInterfaceList"), INTERFACES_DEFAULT_CONFIG
);
364 if (ni_prefs
== NULL
) {
365 SC_log(LOG_NOTICE
, "SCPreferencesCreate(\"NetworkInterfaces.plist\") failed: %s", SCErrorString(SCError()));
369 cur_list
= SCPreferencesGetValue(ni_prefs
, INTERFACES
);
370 if (_SC_CFEqual(cur_list
, if_list
)) {
374 old_model
= SCPreferencesGetValue(ni_prefs
, MODEL
);
375 new_model
= _SC_hw_model(FALSE
);
376 if ((old_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
378 if ((old_model
!= NULL
) && (cur_list
!= NULL
)) {
379 SC_log(LOG_NOTICE
, "Hardware model changed\n"
380 " created on \"%@\"\n"
385 // save the interface list that was created on "other" hardware
386 writeInterfaceListForModel(ni_prefs
, old_model
);
389 SCPreferencesSetValue(ni_prefs
, MODEL
, new_model
);
392 SCPreferencesSetValue(ni_prefs
, INTERFACES
, if_list
);
394 if (!SCPreferencesCommitChanges(ni_prefs
)) {
395 if (SCError() != EROFS
) {
396 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
407 static CF_RETURNS_RETAINED CFMutableArrayRef
411 SCPreferencesRef ni_prefs
;
412 CFStringRef old_model
;
413 static Boolean once
= FALSE
;
414 CFMutableArrayRef plist
= NULL
;
416 ni_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":readInterfaceList"), INTERFACES_DEFAULT_CONFIG
);
417 if (ni_prefs
== NULL
) {
418 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
423 __SCNetworkConfigurationUpgrade(NULL
, &ni_prefs
, TRUE
);
427 if_list
= SCPreferencesGetValue(ni_prefs
, INTERFACES
);
428 if_list
= isA_CFArray(if_list
);
430 old_model
= SCPreferencesGetValue(ni_prefs
, MODEL
);
431 if (old_model
!= NULL
) {
432 CFStringRef new_model
;
434 new_model
= _SC_hw_model(FALSE
);
435 if (!_SC_CFEqual(old_model
, new_model
)) {
437 * If the interface list was created on other hardware then
444 if (if_list
!= NULL
) {
445 CFIndex n
= CFArrayGetCount(if_list
);
447 plist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
448 for (CFIndex i
= 0; i
< n
; i
++) {
449 CFDictionaryRef dict
;
451 dict
= CFArrayGetValueAtIndex(if_list
, i
);
452 if (isA_CFDictionary(dict
) &&
453 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceType
)) &&
454 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
455 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
456 CFArrayAppendValue(plist
, dict
);
462 CFIndex n
= CFArrayGetCount(plist
);
465 CFArraySortValues(plist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
473 static CF_RETURNS_RETAINED CFMutableArrayRef
474 previouslyActiveInterfaces()
476 CFMutableArrayRef active
;
479 if (S_dblist
== NULL
) {
483 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
485 n
= CFArrayGetCount(S_dblist
);
486 for (CFIndex i
= 0; i
< n
; i
++) {
487 CFDictionaryRef if_dict
;
489 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
490 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
491 CFMutableDictionaryRef new_dict
;
493 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
494 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
495 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
496 CFArrayAppendValue(active
, new_dict
);
505 updateInterfaces(void);
512 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
), kSCDynamicStoreDomainPlugin
);
513 (void)SCDynamicStoreSetValue(NULL
, key
, S_state
);
519 #if !TARGET_OS_IPHONE
521 updateBondInterfaceConfiguration(SCPreferencesRef prefs
)
523 CFArrayRef interfaces
;
525 interfaces
= SCBondInterfaceCopyAll(prefs
);
526 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
527 CFRelease(interfaces
);
531 if (_SC_CFEqual(S_bonds
, interfaces
)) {
533 if (interfaces
!= NULL
) CFRelease(interfaces
);
537 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
538 S_bonds
= interfaces
;
540 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
541 SC_log(LOG_NOTICE
, "_SCBondInterfaceUpdateConfiguration() failed: %s",
542 SCErrorString(SCError()));
547 #endif // !TARGET_OS_IPHONE
550 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs
)
552 CFArrayRef interfaces
;
554 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
555 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
556 CFRelease(interfaces
);
560 if (_SC_CFEqual(S_bridges
, interfaces
)) {
562 if (interfaces
!= NULL
) CFRelease(interfaces
);
566 if (S_bridges
!= NULL
) CFRelease(S_bridges
);
567 S_bridges
= interfaces
;
569 if (!_SCBridgeInterfaceUpdateConfiguration(prefs
)) {
570 SC_log(LOG_NOTICE
, "_SCBridgeInterfaceUpdateConfiguration() failed: %s",
571 SCErrorString(SCError()));
578 updateVLANInterfaceConfiguration(SCPreferencesRef prefs
)
580 CFArrayRef interfaces
;
582 interfaces
= SCVLANInterfaceCopyAll(prefs
);
583 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
584 CFRelease(interfaces
);
588 if (_SC_CFEqual(S_vlans
, interfaces
)) {
590 if (interfaces
!= NULL
) CFRelease(interfaces
);
594 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
595 S_vlans
= interfaces
;
597 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
598 SC_log(LOG_NOTICE
, "_SCVLANInterfaceUpdateConfiguration() failed: %s",
599 SCErrorString(SCError()));
606 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
607 SCPreferencesNotification notificationType
,
611 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
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
);
647 updateBTPANInformation(const void *value
, void *context
)
649 #pragma unused(context)
651 CFDictionaryRef dict
= (CFDictionaryRef
)value
;
653 CFDictionaryRef info
;
656 if_name
= CFDictionaryGetValue(dict
, CFSTR(kIOBSDNameKey
));
657 if (!isA_CFString(if_name
)) {
662 info
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceInfo
));
663 if (!isA_CFDictionary(info
)) {
664 // if no SCNetworkInterface info
668 name
= CFDictionaryGetValue(info
, kSCPropUserDefinedName
);
669 if (!isA_CFString(name
) || !CFEqual(name
, CFSTR(BT_PAN_NAME
))) {
670 // if not BT-PAN interface
674 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Name
, if_name
);
676 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
677 if (isA_CFData(addr
)) {
678 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Mac
, addr
);
683 #endif // TARGET_OS_OSX
685 static CFDictionaryRef
686 createInterfaceDict(SCNetworkInterfaceRef interface
, CFArrayRef matchingMACs
)
688 CFMutableDictionaryRef new_if
;
691 new_if
= CFDictionaryCreateMutable(NULL
,
693 &kCFTypeDictionaryKeyCallBacks
,
694 &kCFTypeDictionaryValueCallBacks
);
696 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
698 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
702 val
= _SCNetworkInterfaceGetIOPath(interface
);
704 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
707 val
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
709 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceNamePrefix
), val
);
712 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
714 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
717 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
719 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
722 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
724 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
727 val
= SCNetworkInterfaceGetBSDName(interface
);
729 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
732 val
= SCNetworkInterfaceGetInterfaceType(interface
);
734 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
737 CFDictionarySetValue(new_if
,
739 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
741 if (_SCNetworkInterfaceIsHiddenConfiguration(interface
)) {
742 CFDictionarySetValue(new_if
, kSCNetworkInterfaceHiddenConfigurationKey
, kCFBooleanTrue
);
745 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
747 if (matchingMACs
!= NULL
) {
748 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceMatchingMACs
), matchingMACs
);
754 static CFDictionaryRef
755 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
761 if (db_list
== NULL
) {
764 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
765 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
766 if (type
== NULL
|| addr
== NULL
) {
770 n
= CFArrayGetCount(db_list
);
771 for (CFIndex i
= 0; i
< n
; i
++) {
773 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
776 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
777 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
778 if (t
== NULL
|| a
== NULL
)
781 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
791 static CFDictionaryRef
792 lookupInterfaceByName(CFArrayRef db_list
, CFStringRef bsdName
, CFIndex
* where
)
796 if (db_list
== NULL
) {
800 n
= CFArrayGetCount(db_list
);
801 for (CFIndex i
= 0; i
< n
; i
++) {
802 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
805 name
= CFDictionaryGetValue(dict
, CFSTR(kIOBSDNameKey
));
806 if (_SC_CFEqual(name
, bsdName
)) {
816 static CFDictionaryRef
817 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
823 if (db_list
== NULL
) {
826 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
827 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
828 if (type
== NULL
|| unit
== NULL
) {
832 n
= CFArrayGetCount(db_list
);
833 for (CFIndex i
= 0; i
< n
; i
++) {
834 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
838 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
839 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
840 if (t
== NULL
|| u
== NULL
) {
844 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
854 CFDictionaryRef match_info
;
855 CFStringRef match_type
;
856 CFBooleanRef match_builtin
;
857 CFMutableArrayRef matches
;
858 } matchContext
, *matchContextRef
;
860 static CF_RETURNS_RETAINED CFDictionaryRef
861 thinInterfaceInfo(CFDictionaryRef info
)
866 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
868 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
869 && (vid
== kIOUSBAppleVendorID
)) {
870 CFMutableDictionaryRef thin
;
872 // if this is an Apple USB device than we trust that
873 // the non-localized name will be correct.
874 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
875 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
876 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
877 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
881 return CFRetain(info
);
885 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
889 match
= _SC_CFEqual(known_info
, match_info
);
891 isA_CFDictionary(known_info
) &&
892 isA_CFDictionary(match_info
)) {
894 // if not an exact match, try thinning
895 known_info
= thinInterfaceInfo(known_info
);
896 match_info
= thinInterfaceInfo(match_info
);
897 match
= _SC_CFEqual(known_info
, match_info
);
898 if (known_info
!= NULL
) CFRelease(known_info
);
899 if (match_info
!= NULL
) CFRelease(match_info
);
906 matchKnown(const void *value
, void *context
)
908 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
909 matchContextRef match_context
= (matchContextRef
)context
;
911 // match interface type
913 CFStringRef known_type
;
915 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
916 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
921 // match SCNetworkInterfaceInfo
923 CFDictionaryRef known_info
;
925 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
926 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
931 // if requested, match [non-]builtin
932 if (match_context
->match_builtin
!= NULL
) {
933 CFBooleanRef known_builtin
;
935 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
936 if (!isA_CFBoolean(known_builtin
)) {
937 known_builtin
= kCFBooleanFalse
;
939 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
944 // if we have a match
945 if (match_context
->matches
== NULL
) {
946 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
948 CFArrayAppendValue(match_context
->matches
, known_dict
);
954 matchUnnamed(const void *value
, void *context
)
956 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
957 matchContextRef match_context
= (matchContextRef
)context
;
959 if (match_context
->matches
== NULL
) {
963 // match interface type
965 CFStringRef known_type
;
967 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
968 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
973 // match SCNetworkInterfaceInfo
975 CFDictionaryRef known_info
;
978 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
979 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
980 if (known_info
!= NULL
) CFRelease(known_info
);
986 // if requested, match [non-]builtin
987 if (match_context
->match_builtin
!= NULL
) {
988 CFBooleanRef known_builtin
;
990 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
992 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
997 // if we have a match
998 CFRelease(match_context
->matches
);
999 match_context
->matches
= NULL
;
1005 interfaceExists(CFStringRef prefix
, CFNumberRef unit
)
1007 Boolean found
= FALSE
;
1008 CFDictionaryRef match_dict
;
1009 CFStringRef match_keys
[2];
1010 CFTypeRef match_vals
[2];
1011 CFDictionaryRef matching
;
1015 io_registry_entry_t entry
= MACH_PORT_NULL
;
1016 io_iterator_t iterator
= MACH_PORT_NULL
;
1018 mach_port_t masterPort
= MACH_PORT_NULL
;
1020 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1021 if (kr
!= KERN_SUCCESS
) {
1022 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1026 // look for kIONetworkInterface with matching prefix and unit
1027 match_keys
[0] = CFSTR(kIOInterfaceNamePrefix
);
1028 match_vals
[0] = prefix
;
1029 match_keys
[1] = CFSTR(kIOInterfaceUnit
);
1030 match_vals
[1] = unit
;
1031 match_dict
= CFDictionaryCreate(NULL
,
1032 (const void **)match_keys
,
1033 (const void **)match_vals
,
1035 &kCFTypeDictionaryKeyCallBacks
,
1036 &kCFTypeDictionaryValueCallBacks
);
1038 match_keys
[0] = CFSTR(kIOProviderClassKey
);
1039 match_vals
[0] = CFSTR(kIONetworkInterfaceClass
);
1040 match_keys
[1] = CFSTR(kIOPropertyMatchKey
);
1041 match_vals
[1] = match_dict
;
1042 matching
= CFDictionaryCreate(NULL
,
1043 (const void **)match_keys
,
1044 (const void **)match_vals
,
1045 sizeof(match_keys
)/sizeof(match_keys
[0]),
1046 &kCFTypeDictionaryKeyCallBacks
,
1047 &kCFTypeDictionaryValueCallBacks
);
1048 CFRelease(match_dict
);
1050 // note: the "matching" dictionary will be consumed by the following
1051 kr
= IOServiceGetMatchingServices(masterPort
, matching
, &iterator
);
1052 if ((kr
!= kIOReturnSuccess
) || (iterator
== MACH_PORT_NULL
)) {
1057 entry
= IOIteratorNext(iterator
);
1058 if (entry
== MACH_PORT_NULL
) {
1066 if (masterPort
!= MACH_PORT_NULL
) {
1067 mach_port_deallocate(mach_task_self(), masterPort
);
1069 if (entry
!= MACH_PORT_NULL
) {
1070 IOObjectRelease(entry
);
1072 if (iterator
!= MACH_PORT_NULL
) {
1073 IOObjectRelease(iterator
);
1080 * lookupMatchingInterface
1082 * Looks at the interfaces that have already been [or need to be] named with
1083 * the goal of allowing a system using a single network interface/adaptor of
1084 * a given type (vendor, model, ...) to not care about the specific adaptor
1085 * that is used (i.e. swapping dongle's is OK). Once a system has had more
1086 * than one interface/adaptor connected at the same time than we assume that
1087 * the network configuration is being setup for multi-homing that should be
1090 * If no matches are found or if more than one match is found, return NULL.
1091 * If a single match is found, return the match.
1093 static CFDictionaryRef
1094 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
1095 CFArrayRef db_list
, // already named
1096 CFArrayRef if_list
, // to be named
1097 CFIndex if_list_index
,
1098 CFBooleanRef builtin
)
1100 CFStringRef if_type
;
1101 CFDictionaryRef match
= NULL
;
1102 matchContext match_context
;
1104 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
1105 if (if_type
== NULL
) {
1109 match_context
.match_type
= if_type
;
1110 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
1111 match_context
.match_builtin
= builtin
;
1112 match_context
.matches
= NULL
;
1114 // check for matches to interfaces that have already been named
1115 // ... and append each match that we find to match_context.matches
1116 if (db_list
!= NULL
) {
1117 CFArrayApplyFunction(db_list
,
1118 CFRangeMake(0, CFArrayGetCount(db_list
)),
1123 // check for matches to interfaces that will be named
1124 // ... and CFRelease match_context.matches if we find another network
1125 // interface of the same type that also needs to be named
1126 if (if_list
!= NULL
) {
1127 CFIndex if_list_count
;
1129 if_list_count
= CFArrayGetCount(if_list
);
1130 if (if_list_index
< if_list_count
) {
1131 CFArrayApplyFunction(if_list
,
1132 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
1138 // check if we have a single match
1139 if (match_context
.matches
!= NULL
) {
1140 if (CFArrayGetCount(match_context
.matches
) == 1) {
1141 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
1143 CFRelease(match_context
.matches
);
1146 if (match
!= NULL
) {
1147 Boolean active
= TRUE
;
1150 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
1151 if (isA_CFString(name
)) {
1155 prefix
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceNamePrefix
));
1156 unit
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceUnit
));
1157 if (isA_CFString(prefix
) && isA_CFNumber(unit
)) {
1158 if (!interfaceExists(prefix
, unit
)) {
1169 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
1174 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
, CFDictionaryRef db_dict_match
)
1177 CFDictionaryRef if_dict
;
1178 CFStringRef if_name
;
1179 CFNumberRef if_type
;
1180 CFNumberRef if_unit
;
1181 CFArrayRef matchingMACs
= NULL
;
1182 CFIndex n
= CFArrayGetCount(db_list
);
1183 CFComparisonResult res
;
1185 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1186 if (if_name
!= NULL
) {
1187 addTimestamp(S_state
, if_name
);
1190 if (!_SCNetworkInterfaceIsBuiltin(interface
) && (db_dict_match
!= NULL
)) {
1194 matchingMACs
= CFDictionaryGetValue(db_dict_match
, CFSTR(kSCNetworkInterfaceMatchingMACs
));
1195 if (matchingMACs
!= NULL
) {
1196 CFRetain(matchingMACs
);
1199 addr_old
= CFDictionaryGetValue(db_dict_match
, CFSTR(kIOMACAddress
));
1200 addr_cur
= _SCNetworkInterfaceGetHardwareAddress(interface
);
1201 if ((addr_old
!= NULL
) && (addr_cur
!= NULL
) && !CFEqual(addr_old
, addr_cur
)) {
1202 CFMutableArrayRef matching_new
;
1204 // if MAC address changed, add previous MAC to history
1205 if (matchingMACs
!= NULL
) {
1206 matching_new
= CFArrayCreateMutableCopy(NULL
, 0, matchingMACs
);
1207 CFRelease(matchingMACs
);
1209 // remove duplicates of the now current MAC from history
1210 i
= CFArrayGetFirstIndexOfValue(matching_new
, CFRangeMake(0, CFArrayGetCount(matching_new
)), addr_cur
);
1211 if (i
!= kCFNotFound
) {
1212 CFArrayRemoveValueAtIndex(matching_new
, i
);
1215 // remove duplicates of the previous MAC from history before re-inserting
1216 i
= CFArrayGetFirstIndexOfValue(matching_new
, CFRangeMake(0, CFArrayGetCount(matching_new
)), addr_old
);
1217 if (i
!= kCFNotFound
) {
1218 CFArrayRemoveValueAtIndex(matching_new
, i
);
1221 matching_new
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1223 CFArrayInsertValueAtIndex(matching_new
, 0, addr_old
);
1225 // limit history size
1226 #define MATCHING_HISTORY_MAXLEN 32
1227 for (i
= CFArrayGetCount(matching_new
); i
> MATCHING_HISTORY_MAXLEN
; i
--) {
1228 CFArrayRemoveValueAtIndex(matching_new
, i
- 1);
1231 matchingMACs
= matching_new
;
1235 if_dict
= createInterfaceDict(interface
, matchingMACs
);
1236 if (matchingMACs
!= NULL
) {
1237 CFRelease(matchingMACs
);
1240 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1241 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1242 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
1247 for (i
= 0; i
< n
; i
++) {
1248 CFNumberRef db_type
;
1249 CFNumberRef db_unit
;
1250 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
1252 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1253 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1254 res
= CFNumberCompare(if_type
, db_type
, NULL
);
1255 if (res
== kCFCompareLessThan
1256 || (res
== kCFCompareEqualTo
1257 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
1258 == kCFCompareLessThan
))) {
1259 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
1265 CFArrayAppendValue(S_dblist
, if_dict
);
1268 updateBTPANInformation(if_dict
, NULL
);
1269 #endif // TARGET_OS_OSX
1276 removeInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
, CFDictionaryRef
*matched
)
1278 CFDictionaryRef db_dict
;
1282 // remove any dict that has our type/addr
1284 db_dict
= lookupInterfaceByAddress(db_list
, interface
, &where
);
1285 if (db_dict
== NULL
) {
1288 if ((matched
!= NULL
) && (*matched
== NULL
)) {
1289 *matched
= CFRetain(db_dict
);
1291 CFArrayRemoveValueAtIndex(db_list
, where
);
1295 // remove any dict that has the same type/unit
1297 db_dict
= lookupInterfaceByUnit(db_list
, interface
, &where
);
1298 if (db_dict
== NULL
) {
1301 if ((matched
!= NULL
) && (*matched
== NULL
)) {
1302 *matched
= CFRetain(db_dict
);
1304 CFArrayRemoveValueAtIndex(db_list
, where
);
1309 SC_log(LOG_ERR
, "Multiple interfaces removed from database (n = %d, %@)", n
, interface
);
1316 replaceInterface(SCNetworkInterfaceRef interface
)
1318 CFDictionaryRef matched
= NULL
;
1320 if (S_dblist
== NULL
) {
1321 S_dblist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1323 // remove any matching interfaces
1324 removeInterface(S_dblist
, interface
, &matched
);
1327 // [re-]insert the new interface
1328 insertInterface(S_dblist
, interface
, matched
);
1330 if (matched
!= NULL
) {
1338 getNextUnitForType(CFNumberRef if_type
, int requested
)
1342 if (S_dblist
== NULL
) {
1346 n
= CFArrayGetCount(S_dblist
);
1347 for (CFIndex i
= 0; i
< n
; i
++) {
1348 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1351 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1352 if (CFEqual(type
, if_type
)) {
1356 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1357 if (!isA_CFNumber(unit
) ||
1358 !CFNumberGetValue(unit
, kCFNumberIntType
, &u
)) {
1362 if (u
< requested
) {
1363 // if we have not yet found our starting unit #
1367 if (u
== requested
) {
1368 // our starting (or now proposed) unit # is "in use" so
1369 // let's keep searching
1374 // we've found a unit # gap ... so let's re-assign it!
1382 * Function: ensureInterfaceHasUnit
1384 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1385 * release the interface and return NULL.
1387 static SCNetworkInterfaceRef
1388 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if
)
1391 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if
) == NULL
) {
1398 #ifdef USE_REGISTRY_ENTRY_ID
1399 static kern_return_t
1400 registerInterfaceWithIORegistryEntryID(io_connect_t connect
,
1406 CFMutableDictionaryRef dict
;
1410 dict
= CFDictionaryCreateMutable(NULL
, 0,
1411 &kCFTypeDictionaryKeyCallBacks
,
1412 &kCFTypeDictionaryValueCallBacks
);
1413 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1414 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1416 data
= CFDataCreate(NULL
, (void *) &entryID
, sizeof(entryID
));
1417 CFDictionarySetValue(dict
, CFSTR(kIORegistryEntryIDKey
), data
);
1419 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1420 kr
= IOConnectSetCFProperties(connect
, dict
);
1425 static SCNetworkInterfaceRef
1426 copyInterfaceForIORegistryEntryID(uint64_t entryID
)
1428 io_registry_entry_t entry
= MACH_PORT_NULL
;
1429 SCNetworkInterfaceRef interface
= NULL
;
1430 io_iterator_t iterator
= MACH_PORT_NULL
;
1432 mach_port_t masterPort
= MACH_PORT_NULL
;
1434 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1435 if (kr
!= KERN_SUCCESS
) {
1436 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1440 kr
= IOServiceGetMatchingServices(masterPort
,
1441 IORegistryEntryIDMatching(entryID
),
1443 if ((kr
!= KERN_SUCCESS
) || (iterator
== MACH_PORT_NULL
)) {
1444 SC_log(LOG_NOTICE
, "IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d",
1451 entry
= IOIteratorNext(iterator
);
1452 if (entry
== MACH_PORT_NULL
) {
1453 SC_log(LOG_NOTICE
, "IORegistryEntryIDMatching(0x%llx) failed", entryID
);
1457 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1460 if (masterPort
!= MACH_PORT_NULL
) {
1461 mach_port_deallocate(mach_task_self(), masterPort
);
1463 if (entry
!= MACH_PORT_NULL
) {
1464 IOObjectRelease(entry
);
1466 if (iterator
!= MACH_PORT_NULL
) {
1467 IOObjectRelease(iterator
);
1472 static SCNetworkInterfaceRef
1473 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID
)
1475 SCNetworkInterfaceRef net_if
;
1477 net_if
= copyInterfaceForIORegistryEntryID(entryID
);
1478 return (ensureInterfaceHasUnit(net_if
));
1481 #else // USE_REGISTRY_ENTRY_ID
1483 * Function: registerInterface
1485 * Register a single interface with the given service path to the
1486 * data link layer (BSD), using the specified unit number.
1488 static kern_return_t
1489 registerInterfaceWithIOServicePath(io_connect_t connect
,
1494 CFMutableDictionaryRef dict
;
1498 dict
= CFDictionaryCreateMutable(NULL
, 0,
1499 &kCFTypeDictionaryKeyCallBacks
,
1500 &kCFTypeDictionaryValueCallBacks
);
1501 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1502 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1504 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1505 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1506 kr
= IOConnectSetCFProperties(connect
, dict
);
1511 static SCNetworkInterfaceRef
1512 copyInterfaceForIOKitPath(CFStringRef if_path
)
1514 io_registry_entry_t entry
= MACH_PORT_NULL
;
1515 SCNetworkInterfaceRef interface
= NULL
;
1517 mach_port_t masterPort
= MACH_PORT_NULL
;
1520 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1521 if (kr
!= KERN_SUCCESS
) {
1522 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1525 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1526 entry
= IORegistryEntryFromPath(masterPort
, path
);
1527 if (entry
== MACH_PORT_NULL
) {
1528 SC_log(LOG_NOTICE
, "IORegistryEntryFromPath(%@) failed", if_path
);
1532 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1535 if (masterPort
!= MACH_PORT_NULL
) {
1536 mach_port_deallocate(mach_task_self(), masterPort
);
1538 if (entry
!= MACH_PORT_NULL
) {
1539 IOObjectRelease(entry
);
1545 static SCNetworkInterfaceRef
1546 copyNamedInterfaceForIOKitPath(CFStringRef if_path
)
1548 SCNetworkInterfaceRef net_if
;
1550 net_if
= copyInterfaceForIOKitPath(if_path
);
1551 return (ensureInterfaceHasUnit(net_if
));
1554 #endif // USE_REGISTRY_ENTRY_ID
1557 displayInterface(SCNetworkInterfaceRef interface
)
1564 name
= SCNetworkInterfaceGetBSDName(interface
);
1565 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1566 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1567 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1569 SC_log(LOG_INFO
, " %s%@%sType: %@, %s%@%sMAC address: %@",
1570 (name
!= NULL
) ? "BSD Name: " : "",
1571 (name
!= NULL
) ? name
: CFSTR(""),
1572 (name
!= NULL
) ? ", " : "",
1574 (unit
!= NULL
) ? "Unit: " : "",
1575 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1576 (unit
!= NULL
) ? ", " : "",
1577 (addr
!= NULL
) ? addr
: CFSTR("?"));
1581 builtinAvailable(SCNetworkInterfaceRef interface
, // new interface
1582 CFNumberRef if_unit
) // desired unit
1585 CFNumberRef if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1588 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1589 for (i
= 0; i
< n
; i
++) {
1590 CFStringRef if_path
;
1591 CFDictionaryRef known_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1592 CFStringRef known_path
;
1593 CFNumberRef known_type
;
1594 CFNumberRef known_unit
;
1596 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceType
));
1597 if (!_SC_CFEqual(if_type
, known_type
)) {
1598 continue; // if not the same interface type
1601 known_unit
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceUnit
));
1602 if (!_SC_CFEqual(if_unit
, known_unit
)) {
1603 continue; // if not the same interface unit
1606 if_path
= _SCNetworkInterfaceGetIOPath(interface
);
1607 known_path
= CFDictionaryGetValue(known_dict
, CFSTR(kIOPathMatchKey
));
1608 if (!_SC_CFEqual(if_path
, known_path
)) {
1609 // if different IORegistry path
1613 // if same type, same unit, same path
1617 // if interface type/unit not found
1622 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
1627 for (i
= 0; i
< last
; i
++) {
1628 SCNetworkInterfaceRef builtin_if
;
1629 CFNumberRef builtin_type
;
1631 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1632 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
1633 if (CFEqual(if_type
, builtin_type
)) {
1634 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1635 n
++; // if built-in interface
1645 #pragma mark Interface monitoring (e.g. watch for "detach")
1648 typedef struct WatchedInfo
*WatchedInfoRef
;
1650 typedef void (*InterfaceUpdateCallBack
) (
1652 natural_t messageType
,
1653 void *messageArgument
1657 SCNetworkInterfaceRef interface
;
1658 io_service_t interface_node
;
1659 io_object_t notification
;
1660 InterfaceUpdateCallBack callback
;
1664 watcherRelease(CFDataRef watched
);
1667 updateWatchedInterface(void *refCon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
1669 #pragma unused(service)
1670 #pragma unused(messageArgument)
1671 switch (messageType
) {
1672 case kIOMessageServiceIsTerminated
: { // if [watched] interface yanked
1673 SCNetworkInterfaceRef remove
= NULL
;
1674 CFDataRef watched
= (CFDataRef
)refCon
;
1675 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1677 remove
= watchedInfo
->interface
;
1678 if (!_SCNetworkInterfaceIsBuiltin(remove
) &&
1679 _SCNetworkInterfaceIsApplePreconfigured(remove
)) {
1680 // if not built-in *and* pre-configured, retain for cleanup
1687 watchedInfo
->callback(watched
, messageType
, messageArgument
);
1688 watcherRelease(watched
);
1691 if (remove
!= NULL
) {
1692 // if interface is not built-in *and* pre-configured
1693 SC_log(LOG_INFO
, "Interface released unit %@ (from database)",
1694 _SCNetworkInterfaceGetIOInterfaceUnit(remove
));
1695 removeInterface(S_dblist
, remove
, NULL
);
1698 // update the DB with the [remaining] interfaces that have been named
1699 writeInterfaceList(S_dblist
);
1713 watcherCreate(SCNetworkInterfaceRef interface
, InterfaceUpdateCallBack callback
)
1716 io_service_t interface_node
;
1718 CFDictionaryRef matching
;
1719 CFMutableDataRef watched
;
1720 WatchedInfo
*watchedInfo
;
1722 // get the IORegistry node
1723 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
1724 matching
= IORegistryEntryIDMatching(entryID
);
1725 interface_node
= IOServiceGetMatchingService(kIOMasterPortDefault
, matching
);
1726 if (interface_node
== MACH_PORT_NULL
) {
1727 // interface no longer present
1731 // create [locked/trusted] interface watcher
1732 watched
= CFDataCreateMutable(NULL
, sizeof(WatchedInfo
));
1733 CFDataSetLength(watched
, sizeof(WatchedInfo
));
1734 watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1735 memset(watchedInfo
, 0, sizeof(*watchedInfo
));
1738 watchedInfo
->interface
= CFRetain(interface
);
1740 // ... and the interface node
1741 watchedInfo
->interface_node
= interface_node
;
1743 // ... and set the callback
1744 watchedInfo
->callback
= callback
;
1746 kr
= IOServiceAddInterestNotification(S_notify
, // IONotificationPortRef
1747 watchedInfo
->interface_node
, // io_service_t
1748 kIOGeneralInterest
, // interestType
1749 updateWatchedInterface
, // IOServiceInterestCallback
1750 (void *)watched
, // refCon
1751 &watchedInfo
->notification
); // notification
1752 if (kr
!= KERN_SUCCESS
) {
1754 "IOServiceAddInterestNotification() failed, kr = 0x%x",
1756 watcherRelease(watched
);
1765 watcherRelease(CFDataRef watched
)
1767 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1770 if (watchedInfo
->notification
!= IO_OBJECT_NULL
) {
1771 IOObjectRelease(watchedInfo
->notification
);
1772 watchedInfo
->notification
= IO_OBJECT_NULL
;
1775 // release interface node
1776 if (watchedInfo
->interface_node
!= IO_OBJECT_NULL
) {
1777 IOObjectRelease(watchedInfo
->interface_node
);
1778 watchedInfo
->interface_node
= IO_OBJECT_NULL
;
1781 // release interface
1782 if (watchedInfo
->interface
!= NULL
) {
1783 CFRelease(watchedInfo
->interface
);
1784 watchedInfo
->interface
= NULL
;
1791 isWatchedInterface(CFArrayRef watchedInterfaces
, SCNetworkInterfaceRef interface
)
1795 n
= (watchedInterfaces
!= NULL
) ? CFArrayGetCount(watchedInterfaces
) : 0;
1796 for (CFIndex i
= 0; i
< n
; i
++) {
1797 CFDataRef watched
= CFArrayGetValueAtIndex(watchedInterfaces
, i
);
1798 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1800 if (CFEqual((watchedInfo
->interface
), interface
)) {
1810 #pragma mark Locked device support [macOS]
1813 #if !TARGET_OS_IPHONE
1819 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
1821 CFMutableArrayRef locked
;
1823 locked
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1825 for (CFIndex i
= 0; i
< n
; i
++) {
1830 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
1831 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1833 name
= SCNetworkInterfaceGetLocalizedDisplayName(watchedInfo
->interface
);
1834 addr
= SCNetworkInterfaceGetHardwareAddressString(watchedInfo
->interface
);
1835 path
= _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
);
1836 str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@: %@: %@"),
1837 (name
!= NULL
) ? name
: CFSTR("?"),
1838 (addr
!= NULL
) ? addr
: CFSTR("?"),
1840 CFArrayAppendValue(locked
, str
);
1844 CFDictionarySetValue(S_state
, kInterfaceNamerKey_LockedInterfaces
, locked
);
1847 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_LockedInterfaces
);
1856 blockNewInterfaces()
1858 static boolean_t allow
= TRUE
;
1859 static dispatch_once_t once
;
1861 dispatch_once(&once
, ^{
1862 allow
= InterfaceNamerControlPrefsAllowNewInterfaces();
1871 CFArrayRef console_sessions
;
1872 boolean_t locked
= FALSE
;
1873 io_registry_entry_t root
;
1875 root
= IORegistryGetRootEntry(kIOMasterPortDefault
);
1876 console_sessions
= IORegistryEntryCreateCFProperty(root
,
1877 CFSTR(kIOConsoleUsersKey
),
1880 if (isA_CFArray(console_sessions
)) {
1883 n
= CFArrayGetCount(console_sessions
);
1884 for (CFIndex i
= 0; i
< n
; i
++) {
1885 CFBooleanRef isLocked
;
1886 CFBooleanRef isLoginDone
;
1887 CFBooleanRef onConsole
;
1888 CFDictionaryRef session
;
1890 session
= CFArrayGetValueAtIndex(console_sessions
, i
);
1891 if (!isA_CFDictionary(session
)) {
1892 // if not dictionary
1896 if (!CFDictionaryGetValueIfPresent(session
,
1897 CFSTR(kIOConsoleSessionOnConsoleKey
),
1898 (const void **)&onConsole
) ||
1899 !isA_CFBoolean(onConsole
) ||
1900 !CFBooleanGetValue(onConsole
)) {
1901 // if not "on console" session
1906 CFDictionaryGetValueIfPresent(session
,
1907 CFSTR(kIOConsoleSessionLoginDoneKey
),
1908 (const void **)&isLoginDone
) &&
1909 isA_CFBoolean(isLoginDone
) &&
1910 !CFBooleanGetValue(isLoginDone
)) {
1912 SC_log(LOG_INFO
, "multiple sessions, console @ loginwindow");
1917 if (CFDictionaryGetValueIfPresent(session
,
1918 CFSTR(kIOConsoleSessionScreenIsLockedKey
),
1919 (const void **)&isLocked
) &&
1920 isA_CFBoolean(isLocked
) &&
1921 CFBooleanGetValue(isLocked
)) {
1923 SC_log(LOG_INFO
, "console screen locked");
1930 SC_log(LOG_INFO
, "console not locked");
1934 if (console_sessions
!= NULL
) {
1935 CFRelease(console_sessions
);
1937 IOObjectRelease(root
);
1942 //#define ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
1943 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
1945 static CFUserNotificationRef userNotification
;
1946 static CFRunLoopSourceRef userRls
;
1949 lockedNotification_remove(void)
1951 if (userRls
!= NULL
) {
1952 CFRunLoopSourceInvalidate(userRls
);
1956 if (userNotification
!= NULL
) {
1959 status
= CFUserNotificationCancel(userNotification
);
1962 "CFUserNotificationCancel() failed, status=%d",
1965 CFRelease(userNotification
);
1966 userNotification
= NULL
;
1972 #define MY_ICON_PATH "/System/Library/PreferencePanes/Network.prefPane/Contents/Resources/Network.icns"
1975 lockedNotification_reply(CFUserNotificationRef userNotification
, CFOptionFlags response_flags
)
1977 #pragma unused(userNotification)
1981 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
1982 for (CFIndex i
= 0; i
< n
; i
++) {
1983 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
1984 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1986 // process user response
1987 switch (response_flags
& 0x3) {
1988 case kCFUserNotificationDefaultResponse
: {
1989 // if OK'd, [re-]process new interfaces
1991 SC_log(LOG_INFO
, "Reprocessing %ld [locked] interface%s", n
, n
== 1 ? "" : "s");
1993 if (S_iflist
== NULL
) {
1994 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1998 // add the interface to those newly discovered
1999 CFArrayAppendValue(S_iflist
, watchedInfo
->interface
);
2003 // if cancelled, ignore [remaining] new interfaces
2004 SC_log(LOG_INFO
, "[locked] interface ignored");
2005 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
2011 watcherRelease(watched
);
2014 if (S_locked
!= NULL
) {
2015 CFRelease(S_locked
);
2019 lockedNotification_remove();
2021 if (S_iflist
!= NULL
) {
2029 lockedNotification_add(void)
2032 CFMutableDictionaryRef dict
;
2034 CFMutableArrayRef message
;
2036 CFURLRef url
= NULL
;
2038 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
2040 // no locked interfaces, no notification needed
2044 dict
= CFDictionaryCreateMutable(NULL
,
2046 &kCFTypeDictionaryKeyCallBacks
,
2047 &kCFTypeDictionaryValueCallBacks
);
2049 // set localization URL
2050 bundle
= _SC_CFBundleGet();
2051 if (bundle
!= NULL
) {
2052 url
= CFBundleCopyBundleURL(bundle
);
2056 CFDictionarySetValue(dict
, kCFUserNotificationLocalizationURLKey
, url
);
2059 SC_log(LOG_ERR
, "can't find bundle");
2064 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
2065 (const UInt8
*)MY_ICON_PATH
,
2066 sizeof(MY_ICON_PATH
) - 1,
2069 CFDictionarySetValue(dict
, kCFUserNotificationIconURLKey
, url
);
2074 CFDictionarySetValue(dict
,
2075 kCFUserNotificationAlertHeaderKey
,
2076 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_HEADER")
2077 : CFSTR("LOCKED_MULTIPLE_INTERFACES_HEADER"));
2080 message
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2081 CFArrayAppendValue(message
,
2082 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_MESSAGE")
2083 : CFSTR("LOCKED_MULTIPLE_INTERFACES_MESSAGE"));
2084 for (CFIndex i
= 0; i
< n
; i
++) {
2087 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
2088 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2090 name
= SCNetworkInterfaceGetLocalizedDisplayName(watchedInfo
->interface
);
2091 str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("\r\t%@"), name
);
2092 CFArrayAppendValue(message
, str
);
2095 CFDictionarySetValue(dict
, kCFUserNotificationAlertMessageKey
, message
);
2099 CFDictionarySetValue(dict
,
2100 kCFUserNotificationDefaultButtonTitleKey
,
2101 CFSTR("LOCKED_INTERFACES_IGNORE"));
2102 CFDictionarySetValue(dict
,
2103 kCFUserNotificationAlternateButtonTitleKey
,
2104 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_ADD")
2105 : CFSTR("LOCKED_MULTIPLE_INTERFACES_ADD"));
2107 // create and post notification
2108 userNotification
= CFUserNotificationCreate(NULL
,
2110 kCFUserNotificationNoteAlertLevel
,
2113 if (userNotification
== NULL
) {
2114 SC_log(LOG_ERR
, "CFUserNotificationCreate() failed: %d", (int)error
);
2118 // establish callback
2119 userRls
= CFUserNotificationCreateRunLoopSource(NULL
,
2121 lockedNotification_reply
,
2123 if (userRls
== NULL
) {
2124 SC_log(LOG_ERR
, "CFUserNotificationCreateRunLoopSource() failed");
2125 CFRelease(userNotification
);
2126 userNotification
= NULL
;
2129 CFRunLoopAddSource(CFRunLoopGetCurrent(), userRls
, kCFRunLoopDefaultMode
);
2133 if (dict
!= NULL
) CFRelease(dict
);
2138 lockedNotification_update(void)
2140 // if present, remove current notification
2141 lockedNotification_remove();
2143 // post notification (if needed)
2144 lockedNotification_add();
2149 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2152 lockedInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2154 #pragma unused(messageArgument)
2155 Boolean updated
= FALSE
;
2156 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2158 switch (messageType
) {
2159 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2160 SC_log(LOG_INFO
, "[locked] interface removed");
2161 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
2163 if (S_locked
!= NULL
) {
2165 CFIndex n
= CFArrayGetCount(S_locked
);
2167 i
= CFArrayGetFirstIndexOfValue(S_locked
, CFRangeMake(0, n
), watched
);
2168 if (i
!= kCFNotFound
) {
2169 CFArrayRemoveValueAtIndex(S_locked
, i
);
2170 if (CFArrayGetCount(S_locked
) == 0) {
2171 CFRelease(S_locked
);
2186 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2187 // update user notification after interface removed
2188 lockedNotification_update();
2189 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2191 // post info about interfaces not added because the console is locked
2199 watchLockedInterface(SCNetworkInterfaceRef interface
)
2201 Boolean updated
= FALSE
;
2204 watched
= watcherCreate(interface
, lockedInterfaceUpdated
);
2205 if (watched
!= NULL
) {
2206 SC_log(LOG_INFO
, "watching [locked] interface");
2207 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(interface
));
2209 if (S_locked
== NULL
) {
2210 S_locked
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2212 CFArrayAppendValue(S_locked
, watched
);
2217 // post info about interfaces not added because the console is locked
2220 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2221 // post/update user notification with new interface
2222 lockedNotification_update();
2223 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2228 #endif // !TARGET_OS_IPHONE
2232 #pragma mark Trust required support [iOS]
2235 #if TARGET_OS_IPHONE
2237 #include <SoftLinking/WeakLinking.h>
2238 WEAK_LINK_FORCE_IMPORT(lockdown_is_host_trusted
);
2239 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationHostAttached
);
2240 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationHostDetached
);
2241 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationTrustedHostAttached
);
2242 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationTrustedPTPAttached
);
2247 Boolean haveLibrary
;
2249 haveLibrary
= ((lockdown_is_host_trusted
!= NULL
) &&
2250 (&kLockdownNotificationHostAttached
!= NULL
) &&
2251 (&kLockdownNotificationHostDetached
!= NULL
) &&
2252 (&kLockdownNotificationTrustedHostAttached
!= NULL
) &&
2253 (&kLockdownNotificationTrustedPTPAttached
!= NULL
)
2263 n
= (S_trustRequired
!= NULL
) ? CFArrayGetCount(S_trustRequired
) : 0;
2264 if ((n
> 0) && !S_trustedHostAttached
) {
2265 CFMutableArrayRef excluded
;
2267 // if we have interfaces that require not [yet] granted "trust".
2269 excluded
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2271 for (CFIndex i
= 0; i
< n
; i
++) {
2272 CFStringRef bsdName
;
2273 CFDataRef watched
= CFArrayGetValueAtIndex(S_trustRequired
, i
);
2274 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2276 bsdName
= SCNetworkInterfaceGetBSDName(watchedInfo
->interface
);
2277 if (bsdName
== NULL
) {
2278 SC_log(LOG_NOTICE
, "[trust required] interface w/no BSD name not excluded");
2279 SC_log(LOG_NOTICE
, " interface = %@", watchedInfo
->interface
);
2282 CFArrayAppendValue(excluded
, bsdName
);
2285 CFDictionarySetValue(S_state
, kInterfaceNamerKey_ExcludedInterfaces
, excluded
);
2286 CFRelease(excluded
);
2288 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_ExcludedInterfaces
);
2296 static dispatch_queue_t
2297 trustRequired_queue()
2299 static dispatch_once_t once
;
2300 static dispatch_queue_t q
;
2302 dispatch_once(&once
, ^{
2303 q
= dispatch_queue_create("Trust Required queue", NULL
);
2310 // runs on "Trust Required" dispatch queue
2312 trustRequiredNotification_update(CFRunLoopRef rl
, CFStringRef reason
)
2314 Boolean changed
= FALSE
;
2315 CFStringRef error
= NULL
;
2320 * determine whether the device has "trusted" the host (or other device)
2322 trusted
= lockdown_is_host_trusted(MY_PLUGIN_ID
, NULL
, &error
);
2323 n
= (S_trustRequired
!= NULL
) ? CFArrayGetCount(S_trustRequired
) : 0;
2324 if ((S_trustedHostCount
!= n
) || (S_trustedHostAttached
!= trusted
)) {
2328 SC_log(LOG_INFO
, "%@, trusted = %s%s%@, %ld interface%s)%s",
2330 trusted
? "Yes" : "No",
2331 (error
!= NULL
) ? ", error = " : "",
2332 (error
!= NULL
) ? error
: CFSTR(""),
2334 (n
== 1) ? "" : "s",
2335 changed
? " *" : "");
2338 S_trustedHostAttached
= trusted
;
2339 S_trustedHostCount
= n
;
2340 CFRunLoopPerformBlock(rl
, kCFRunLoopDefaultMode
, ^{
2343 CFRunLoopWakeUp(rl
);
2346 if (error
!= NULL
) {
2354 trustRequiredInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2356 #pragma unused(messageArgument)
2357 Boolean updated
= FALSE
;
2358 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2360 switch (messageType
) {
2361 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2362 SC_log(LOG_INFO
, "[trust required] interface removed");
2363 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
2365 if (S_trustRequired
!= NULL
) {
2367 CFIndex n
= CFArrayGetCount(S_trustRequired
);
2369 i
= CFArrayGetFirstIndexOfValue(S_trustRequired
, CFRangeMake(0, n
), watched
);
2370 if (i
!= kCFNotFound
) {
2371 CFArrayRemoveValueAtIndex(S_trustRequired
, i
);
2372 if (CFArrayGetCount(S_trustRequired
) == 0) {
2373 CFRelease(S_trustRequired
);
2374 S_trustRequired
= NULL
;
2388 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2391 dispatch_async(trustRequired_queue(), ^{
2392 trustRequiredNotification_update(rl
, CFSTR("TrustRequired interface removed"));
2401 watchTrustedStatus(CFStringRef notification
, CFStringRef reason
)
2404 int notify_token
= -1;
2406 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2408 key
= CFStringGetCStringPtr(notification
, kCFStringEncodingUTF8
);
2409 assert(key
!= NULL
);
2413 ret
= notify_register_dispatch(key
,
2415 trustRequired_queue(),
2417 #pragma unused(token)
2418 trustRequiredNotification_update(rl
, reason
);
2420 if (ret
!= NOTIFY_STATUS_OK
) {
2421 SC_log(LOG_ERR
, "notify_register_dispatch(%@) failed: %u", notification
, ret
);
2430 updateTrustRequiredInterfaces(CFArrayRef interfaces
)
2433 Boolean updated
= FALSE
;
2435 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
2436 for (CFIndex i
= 0; i
< n
; i
++) {
2437 SCNetworkInterfaceRef interface
;
2439 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2440 if (_SCNetworkInterfaceIsTrustRequired(interface
) &&
2441 !isWatchedInterface(S_trustRequired
, interface
)) {
2444 watched
= watcherCreate(interface
, trustRequiredInterfaceUpdated
);
2445 if (watched
!= NULL
) {
2446 CFStringRef bsdName
;
2448 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
2449 if (bsdName
!= NULL
) {
2450 SC_log(LOG_INFO
, "watching [trust required] interface: %@", bsdName
);
2452 SC_log(LOG_INFO
, "watching [trust required] interface w/no BSD name");
2453 SC_log(LOG_INFO
, " interface = %@", interface
);
2456 if (S_trustRequired
== NULL
) {
2457 S_trustRequired
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2459 CFArrayAppendValue(S_trustRequired
, watched
);
2466 static dispatch_once_t once
;
2467 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2469 dispatch_once(&once
, ^{
2470 // watch for "Host attached"
2471 watchTrustedStatus(kLockdownNotificationHostAttached
,
2472 CFSTR("Host attached"));
2474 // watch for "Host detached"
2475 watchTrustedStatus(kLockdownNotificationHostDetached
,
2476 CFSTR("Host detached"));
2478 // watch for "Trusted host attached"
2479 watchTrustedStatus(kLockdownNotificationTrustedHostAttached
,
2480 CFSTR("Trusted Host attached"));
2482 // watch for "Trusted PDP attached"
2483 watchTrustedStatus(kLockdownNotificationTrustedPTPAttached
,
2484 CFSTR("Trusted PTP attached"));
2488 dispatch_async(trustRequired_queue(), ^{
2489 trustRequiredNotification_update(rl
, CFSTR("TrustRequired interface added"));
2496 #endif // TARGET_OS_IPHONE
2500 #pragma mark Pre-configured interface support
2504 sharePreconfigured()
2508 n
= (S_preconfigured
!= NULL
) ? CFArrayGetCount(S_preconfigured
) : 0;
2510 CFMutableArrayRef preconfigured
;
2512 preconfigured
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2514 for (CFIndex i
= 0; i
< n
; i
++) {
2515 CFStringRef bsdName
;
2516 CFDataRef watched
= CFArrayGetValueAtIndex(S_preconfigured
, i
);
2517 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2519 bsdName
= SCNetworkInterfaceGetBSDName(watchedInfo
->interface
);
2520 if (bsdName
== NULL
) {
2521 SC_log(LOG_NOTICE
, "pre-configured interface w/no BSD name");
2522 SC_log(LOG_NOTICE
, " interface = %@", watchedInfo
->interface
);
2525 CFArrayAppendValue(preconfigured
, bsdName
);
2528 CFDictionarySetValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
, preconfigured
);
2529 CFRelease(preconfigured
);
2531 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
);
2540 preconfiguredInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2542 Boolean updated
= FALSE
;
2543 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2545 #pragma unused(messageArgument)
2546 switch (messageType
) {
2547 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2548 CFStringRef bsdName
;
2550 bsdName
= SCNetworkInterfaceGetBSDName(watchedInfo
->interface
);
2551 if (bsdName
!= NULL
) {
2552 SC_log(LOG_INFO
, "[pre-configured] interface removed: %@", bsdName
);
2554 SC_log(LOG_INFO
, "[pre-configured] interface w/no BSD name removed");
2555 SC_log(LOG_INFO
, " interface = %@", watchedInfo
->interface
);
2558 if (S_preconfigured
!= NULL
) {
2560 CFIndex n
= CFArrayGetCount(S_preconfigured
);
2562 i
= CFArrayGetFirstIndexOfValue(S_preconfigured
, CFRangeMake(0, n
), watched
);
2563 if (i
!= kCFNotFound
) {
2564 CFArrayRemoveValueAtIndex(S_preconfigured
, i
);
2565 if (CFArrayGetCount(S_preconfigured
) == 0) {
2566 CFRelease(S_preconfigured
);
2567 S_preconfigured
= NULL
;
2581 sharePreconfigured();
2588 updatePreConfiguredInterfaces(CFArrayRef interfaces
)
2591 Boolean updated
= FALSE
;
2593 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
2594 for (CFIndex i
= 0; i
< n
; i
++) {
2595 SCNetworkInterfaceRef interface
;
2597 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2598 if (_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
2599 !isWatchedInterface(S_preconfigured
, interface
)) {
2602 watched
= watcherCreate(interface
, preconfiguredInterfaceUpdated
);
2603 if (watched
!= NULL
) {
2604 CFStringRef bsdName
;
2606 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
2607 if (bsdName
!= NULL
) {
2608 SC_log(LOG_INFO
, "watching [pre-configured] interface: %@", bsdName
);
2610 SC_log(LOG_INFO
, "watching [pre-configured] interface w/no BSD name");
2611 SC_log(LOG_INFO
, " interface = %@", interface
);
2614 if (S_preconfigured
== NULL
) {
2615 S_preconfigured
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2617 CFArrayAppendValue(S_preconfigured
, watched
);
2624 sharePreconfigured();
2632 #pragma mark Interface naming
2635 static __inline__ boolean_t
2638 return (S_quiet
== MACH_PORT_NULL
);
2642 wasPreviouslyUsedInterface(CFDictionaryRef dbdict
, SCNetworkInterfaceRef interface
)
2644 CFArrayRef matchingMACs
;
2646 matchingMACs
= CFDictionaryGetValue(dbdict
, CFSTR(kSCNetworkInterfaceMatchingMACs
));
2647 if (matchingMACs
!= NULL
) {
2650 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
2652 if (CFArrayContainsValue(matchingMACs
,
2653 CFRangeMake(0, CFArrayGetCount(matchingMACs
)),
2664 nameInterfaces(CFMutableArrayRef if_list
)
2667 CFIndex n
= CFArrayGetCount(if_list
);
2669 for (i
= 0; i
< n
; i
++) {
2671 SCNetworkInterfaceRef interface
;
2672 SCNetworkInterfaceRef new_interface
;
2678 interface
= CFArrayGetValueAtIndex(if_list
, i
);
2679 path
= _SCNetworkInterfaceGetIOPath(interface
);
2680 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
2681 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
2682 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
2685 CFStringRef if_name
;
2687 if_name
= SCNetworkInterfaceGetBSDName(interface
);
2688 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
2689 SC_log(LOG_INFO
, "Interface already has a unit number");
2690 displayInterface(interface
);
2693 // update the list of interfaces that were previously named
2694 if ((S_prev_active_list
!= NULL
)
2695 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
2696 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
2699 replaceInterface(interface
);
2701 CFDictionaryRef dbdict
;
2702 boolean_t is_builtin
;
2706 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
2707 if (dbdict
!= NULL
) {
2708 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2711 SC_log(LOG_INFO
, "Interface assigned unit %@ (from database)", unit
);
2714 if ((dbdict
== NULL
) && !isQuiet()) {
2715 // if new interface, wait until quiet before naming
2716 addTimestamp(S_state
, path
);
2720 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
2722 if (dbdict
== NULL
) {
2723 dbdict
= lookupMatchingInterface(interface
,
2727 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
2729 if ((dbdict
!= NULL
) && wasPreviouslyUsedInterface(dbdict
, interface
)) {
2730 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2733 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database w/previously used interface)", unit
);
2736 #if !TARGET_OS_IPHONE
2737 if ((unit
== NULL
) &&
2740 blockNewInterfaces() &&
2741 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
2742 isConsoleLocked()) {
2745 // if new (but matching) interface and console locked, ignore
2746 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
2747 SC_log(LOG_NOTICE
, "Console locked, network interface* ignored");
2748 SC_log(LOG_INFO
, " path = %@, addr = %@",
2750 (addr
!= NULL
) ? addr
: CFSTR("?"));
2751 watchLockedInterface(interface
);
2754 #endif // !TARGET_OS_IPHONE
2756 if ((unit
== NULL
) && (dbdict
!= NULL
)) {
2757 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2760 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database w/new interface)", unit
);
2764 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
2765 // update the list of interfaces that were previously named
2766 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
2767 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
2769 if (where
!= kCFNotFound
) {
2770 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
2774 if (dbdict
== NULL
) {
2778 // built-in interface, try to use the reserved slots
2779 next_unit
= builtinCount(if_list
, i
, type
);
2781 // But, before claiming a reserved slot we check to see if the
2782 // slot had previously been used. If so, and if the slot had been
2783 // assigned to the same type of interface, then we will perform a
2784 // replacement (e.g. assume that this was a board swap). But, if
2785 // the new interface is a different type then we assume that the
2786 // built-in configuration has changed and allocate a new unit from
2787 // the non-reserved slots.
2789 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
2790 if (!builtinAvailable(interface
, unit
)) {
2791 // if [built-in] unit not available
2792 SC_log(LOG_INFO
, "Interface not assigned [built-in] unit %@", unit
);
2798 #if !TARGET_OS_IPHONE
2801 blockNewInterfaces() &&
2802 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
2803 isConsoleLocked()) {
2806 // if new interface and console locked, ignore
2807 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
2808 SC_log(LOG_NOTICE
, "Console locked, network interface ignored");
2809 SC_log(LOG_INFO
, " path = %@, addr = %@",
2811 (addr
!= NULL
) ? addr
: CFSTR("?"));
2812 watchLockedInterface(interface
);
2815 #endif // !TARGET_OS_IPHONE
2818 // not built-in (or built-in unit not available), allocate from
2819 // the non-reserved slots
2820 next_unit
= builtinCount(if_list
, n
, type
);
2821 next_unit
= getNextUnitForType(type
, next_unit
);
2822 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
2825 SC_log(LOG_INFO
, "Interface assigned unit %@ (%s)",
2827 is_builtin
? "built-in" : "next available");
2832 #ifdef USE_REGISTRY_ENTRY_ID
2833 kr
= registerInterfaceWithIORegistryEntryID(S_connect
,
2836 (dbdict
== NULL
) ? kIONetworkStackRegisterInterfaceWithLowestUnit
2837 : kIONetworkStackRegisterInterfaceWithUnit
);
2838 new_interface
= copyNamedInterfaceForIORegistryEntryID(entryID
);
2839 #else // USE_REGISTRY_ENTRY_ID
2840 kr
= registerInterfaceWithIOServicePath(S_connect
,
2843 (dbdict
== NULL
) ? kRegisterInterface
2844 : kRegisterInterfaceWithFixedUnit
);
2845 new_interface
= copyNamedInterfaceForIOKitPath(path
);
2846 #endif // USE_REGISTRY_ENTRY_ID
2847 if (new_interface
== NULL
) {
2848 const char *signature
;
2850 signature
= (dbdict
== NULL
) ? "failed to name new interface"
2851 : "failed to name known interface";
2853 SC_log(LOG_NOTICE
, "%s, kr=0x%x\n"
2863 displayInterface(interface
);
2865 if ((dbdict
!= NULL
) && (retries
++ < 5)) {
2866 usleep(50 * 1000); // sleep 50ms between attempts
2871 CFNumberRef new_unit
;
2874 SC_log(LOG_INFO
, "%s interface named after %d %s\n"
2877 (dbdict
== NULL
) ? "New" : "Known",
2879 (retries
== 1) ? "try" : "tries",
2883 #ifdef SHOW_NAMING_FAILURE
2884 str
= CFStringCreateWithFormat(NULL
,
2886 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
2887 (dbdict
== NULL
) ? "New" : "Known",
2889 (retries
== 1) ? "try" : "tries",
2891 CFUserNotificationDisplayNotice(0,
2892 kCFUserNotificationStopAlertLevel
,
2897 CFSTR("Please report repeated failures."),
2900 #endif // SHOW_NAMING_FAILURE
2903 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
2904 if (!CFEqual(unit
, new_unit
)) {
2905 SC_log(LOG_INFO
, "interface type %@ assigned unit %@ instead of %@",
2906 type
, new_unit
, unit
);
2909 displayInterface(new_interface
);
2911 // update if_list (with the interface name & unit)
2912 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
2913 CFRelease(new_interface
);
2914 interface
= new_interface
; // if_list holds the reference
2916 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
2919 // update the list of [built-in] interfaces that were previously named
2920 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
2921 SC_log(LOG_DEBUG
, " and updated database (new address)");
2922 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
2925 replaceInterface(interface
);
2933 #if !TARGET_OS_IPHONE
2935 #define INSTALL_ENVIRONMENT "__OSINSTALL_ENVIRONMENT"
2940 static Boolean isRecovery
= FALSE
;
2941 static dispatch_once_t once
;
2944 * We check to see if the __OSINSTALL_ENVIRONMENT env var is present. If
2945 * so, then we are most likely booted into the Recovery OS with no [Aqua]
2946 * "SCMonitor" [UserEventAgent] plugin.
2948 dispatch_once(&once
, ^{
2949 if (getenv(INSTALL_ENVIRONMENT
) != NULL
) {
2959 updateNetworkConfiguration(CFArrayRef if_list
)
2961 Boolean do_commit
= FALSE
;
2964 SCPreferencesRef prefs
= NULL
;
2965 SCNetworkSetRef set
= NULL
;
2967 prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":updateNetworkConfiguration"), NULL
);
2968 if (prefs
== NULL
) {
2969 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
2973 set
= SCNetworkSetCopyCurrent(prefs
);
2975 SC_log(LOG_INFO
, "No current set, adding default");
2976 set
= _SCNetworkSetCreateDefault(prefs
);
2978 SC_log(LOG_NOTICE
, "_SCNetworkSetCreateDefault() failed: %s", SCErrorString(SCError()));
2983 n
= (if_list
!= NULL
) ? CFArrayGetCount(if_list
) : 0;
2984 for (i
= 0; i
< n
; i
++) {
2985 SCNetworkInterfaceRef interface
;
2987 interface
= CFArrayGetValueAtIndex(if_list
, i
);
2988 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set
, interface
)) {
2989 SC_log(LOG_INFO
, "adding default configuration for %@",
2990 SCNetworkInterfaceGetBSDName(interface
));
2998 ok
= SCPreferencesCommitChanges(prefs
);
3000 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
3004 ok
= SCPreferencesApplyChanges(prefs
);
3006 SC_log(LOG_NOTICE
, "SCPreferencesApplyChanges() failed: %s", SCErrorString(SCError()));
3018 if (prefs
!= NULL
) {
3025 #endif // !TARGET_OS_IPHONE
3028 removeInactiveInterfaces(void)
3033 * remove any previous interfaces that were built-in,
3034 * were active, and were hidden (pre-configured) that
3035 * are no longer plugged in.
3038 if ((S_dblist
== NULL
) || (S_prev_active_list
== NULL
)) {
3042 n
= CFArrayGetCount(S_prev_active_list
);
3043 for (CFIndex i
= n
- 1; i
>= 0; i
--) {
3044 CFBooleanRef builtin
;
3045 CFBooleanRef hidden
;
3046 CFDictionaryRef if_dict
;
3047 CFDictionaryRef info
;
3051 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
3053 // Note: keep the following logic in sync with _SCNetworkInterfaceIsApplePreconfigured()
3055 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
3056 if (!isA_CFString(name
)) {
3061 hidden
= CFDictionaryGetValue(if_dict
, kSCNetworkInterfaceHiddenConfigurationKey
);
3062 if (!isA_CFBoolean(hidden
) || !CFBooleanGetValue(hidden
)) {
3067 builtin
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBuiltin
));
3068 if (isA_CFBoolean(builtin
) && CFBooleanGetValue(builtin
)) {
3069 // if [hidden] builtin
3073 info
= CFDictionaryGetValue(if_dict
, CFSTR(kSCNetworkInterfaceInfo
));
3074 if (isA_CFDictionary(info
)) {
3078 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&vidNum
) &&
3079 isA_CFNumber(vidNum
) &&
3080 CFNumberGetValue(vidNum
, kCFNumberIntType
, &vid
) &&
3081 (vid
== kIOUSBAppleVendorID
)) {
3082 // if [hidden] Apple interface
3091 SC_log(LOG_INFO
, "Removing no-longer-active \"hidden\" interface: %@", name
);
3093 if (lookupInterfaceByName(S_dblist
, name
, &where
) != NULL
) {
3094 // remove from the list of interfaces we know about
3095 CFArrayRemoveValueAtIndex(S_dblist
, where
);
3096 // remove from the previously active list
3097 CFArrayRemoveValueAtIndex(S_prev_active_list
, i
);
3105 reportInactiveInterfaces(void)
3110 * report any previous interfaces that are not [yet] active
3113 if (S_prev_active_list
== NULL
) {
3117 n
= CFArrayGetCount(S_prev_active_list
);
3119 SC_log(LOG_INFO
, "Interface%s not [yet] active",
3120 (n
> 1) ? "s" : "");
3122 for (CFIndex i
= 0; i
< n
; i
++) {
3123 CFDictionaryRef if_dict
;
3128 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
3129 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
3130 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
3131 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
3132 SC_log(LOG_INFO
, " %s%@%sType: %@, Unit: %@",
3133 (name
!= NULL
) ? "BSD Name: " : "",
3134 (name
!= NULL
) ? name
: CFSTR(""),
3135 (name
!= NULL
) ? ", " : "",
3144 updateInterfaces(void)
3146 if (S_connect
== MACH_PORT_NULL
) {
3147 // if we don't have the "IONetworkStack" connect object
3151 if (S_iflist
!= NULL
) {
3154 n
= CFArrayGetCount(S_iflist
);
3156 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
3158 nameInterfaces(S_iflist
);
3162 * Update the list of [Apple] pre-configured interfaces
3164 updatePreConfiguredInterfaces(S_iflist
);
3166 #if TARGET_OS_IPHONE
3168 * Update the list of "trust required" interfaces
3170 if (haveLockdown()) {
3171 updateTrustRequiredInterfaces(S_iflist
);
3173 #endif // TARGET_OS_IPHONE
3177 * The registry [matching] has quiesced
3180 // remove any inactive interfaces
3181 removeInactiveInterfaces();
3183 // save the DB with the interfaces that have been named
3184 writeInterfaceList(S_dblist
);
3186 // update the VLAN/BOND configuration
3187 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
3189 #if !TARGET_OS_IPHONE
3190 if (isRecoveryOS()) {
3192 * We are most likely booted into the Recovery OS with no "SCMonitor"
3193 * UserEventAgent plugin running so let's make sure we update the
3194 * network configuration for new interfaces.
3196 updateNetworkConfiguration(S_iflist
);
3198 #endif // !TARGET_OS_IPHONE
3200 // tell everyone that we've finished (at least for now)
3203 // log those interfaces which are no longer present in
3204 // the HW config (or have yet to show up).
3205 reportInactiveInterfaces();
3207 if (S_prev_active_list
!= NULL
) {
3208 CFRelease(S_prev_active_list
);
3209 S_prev_active_list
= NULL
;
3212 if (S_iflist
!= NULL
) {
3213 CFRelease(S_iflist
);
3217 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
3219 * if we've named all of the interfaces that
3220 * were used during the previous boot.
3222 addTimestamp(S_state
, CFSTR("*RELEASE*"));
3223 SC_log(LOG_INFO
, "last boot interfaces have been named");
3225 CFRelease(S_prev_active_list
);
3226 S_prev_active_list
= NULL
;
3234 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
3236 #pragma unused(refcon)
3239 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
3240 SCNetworkInterfaceRef interface
;
3242 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
3243 if (interface
!= NULL
) {
3244 if (S_iflist
== NULL
) {
3245 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3247 CFArrayAppendValue(S_iflist
, interface
);
3248 CFRelease(interface
);
3250 IOObjectRelease(obj
);
3259 * Function: stackCallback
3261 * Get a reference to the single IONetworkStack object instance in
3262 * the kernel. Naming requests must be sent to this object, which is
3263 * attached as a client to all network interface objects in the system.
3265 * Call IOObjectRelease on the returned object.
3268 stackCallback(void *refcon
, io_iterator_t iter
)
3270 #pragma unused(refcon)
3274 stack
= IOIteratorNext(iter
);
3275 if (stack
== MACH_PORT_NULL
) {
3279 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
3280 if (kr
!= KERN_SUCCESS
) {
3281 SC_log(LOG_ERR
, "IOServiceOpen returned 0x%x", kr
);
3285 addTimestamp(S_state
, CFSTR("*STACK*"));
3286 SC_log(LOG_INFO
, "IONetworkStack found");
3288 if (S_stack
!= MACH_PORT_NULL
) {
3289 IOObjectRelease(S_stack
);
3290 S_stack
= MACH_PORT_NULL
;
3293 if ((S_timer
!= NULL
) && CFRunLoopTimerIsValid(S_timer
)) {
3294 // With the IONetworkStack object now available we can
3295 // reset (shorten?) the time we are willing to wait for
3296 // IOKit to quiesce.
3297 CFRunLoopTimerSetNextFireDate(S_timer
,
3298 CFAbsoluteTimeGetCurrent() + S_quiet_timeout
);
3305 if (stack
!= MACH_PORT_NULL
) {
3306 IOObjectRelease(stack
);
3313 quietCallback(void *refcon
,
3314 io_service_t service
,
3315 natural_t messageType
,
3316 void *messageArgument
)
3318 #pragma unused(refcon)
3319 #pragma unused(service)
3320 if (messageArgument
!= NULL
) {
3325 if (messageType
== kIOMessageServiceBusyStateChange
) {
3326 addTimestamp(S_state
, kInterfaceNamerKey_Quiet
);
3327 SC_log(LOG_INFO
, "IOKit quiet");
3330 if (S_connect
== MACH_PORT_NULL
) {
3331 SC_log(LOG_ERR
, "No network stack object");
3335 if (S_quiet
!= MACH_PORT_NULL
) {
3336 IOObjectRelease(S_quiet
);
3337 S_quiet
= MACH_PORT_NULL
;
3340 if (S_timer
!= NULL
) {
3341 CFRunLoopTimerInvalidate(S_timer
);
3346 // grab (and name) any additional interfaces.
3347 interfaceArrivalCallback((void *)S_notify
, S_iter
);
3349 if (messageType
== kIOMessageServiceBusyStateChange
) {
3350 addTimestamp(S_state
, CFSTR("*QUIET&NAMED*"));
3358 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, int *count
)
3360 kern_return_t kr
= kIOReturnSuccess
;;
3363 while ((kr
== kIOReturnSuccess
) &&
3364 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
3365 uint64_t accumulated_busy_time
;
3366 uint32_t busy_state
;
3369 CFMutableArrayRef newNodes
;
3371 CFMutableStringRef str
= NULL
;
3373 if (nodes
== NULL
) {
3374 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3376 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
3378 assert(newNodes
!= NULL
);
3380 kr
= IORegistryEntryGetName(obj
, name
);
3381 if (kr
!= kIOReturnSuccess
) {
3382 SC_log(LOG_NOTICE
, "IORegistryEntryGetName() returned 0x%x", kr
);
3386 str
= CFStringCreateMutable(NULL
, 0);
3387 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
3389 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
3391 case kIOReturnSuccess
:
3392 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
3393 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
3395 case kIOReturnNotFound
:
3398 SC_log(LOG_NOTICE
, "IORegistryEntryGetLocationInPlane() returned 0x%x", kr
);
3403 CFArrayAppendValue(newNodes
, str
);
3406 kr
= IOServiceGetBusyStateAndTime(obj
, &state
, &busy_state
, &accumulated_busy_time
);
3407 if (kr
!= kIOReturnSuccess
) {
3408 SC_log(LOG_NOTICE
, "IOServiceGetBusyStateAndTime() returned 0x%x", kr
);
3412 #ifdef TEST_SNAPSHOT
3415 #endif // TEST_SNAPSHOT
3417 if (busy_state
!= 0) {
3420 if ((*count
)++ == 0) {
3421 SC_log(LOG_ERR
, "Busy services :");
3424 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
3425 SC_log(LOG_ERR
, " %@ [%s%s%s%d, %lld ms]",
3427 (state
& kIOServiceRegisteredState
) ? "" : "!registered, ",
3428 (state
& kIOServiceMatchedState
) ? "" : "!matched, ",
3429 (state
& kIOServiceInactiveState
) ? "inactive, " : "",
3431 accumulated_busy_time
/ kMillisecondScale
);
3435 kr
= IORegistryIteratorEnterEntry(iterator
);
3436 if (kr
!= kIOReturnSuccess
) {
3437 SC_log(LOG_NOTICE
, "IORegistryIteratorEnterEntry() returned 0x%x", kr
);
3441 iterateRegistryBusy(iterator
, newNodes
, count
);
3443 kr
= IORegistryIteratorExitEntry(iterator
);
3444 if (kr
!= kIOReturnSuccess
) {
3445 SC_log(LOG_NOTICE
, "IORegistryIteratorExitEntry() returned 0x%x", kr
);
3450 CFRelease(newNodes
);
3451 IOObjectRelease(obj
);
3461 io_iterator_t iterator
= MACH_PORT_NULL
;
3464 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
3468 if (kr
!= kIOReturnSuccess
) {
3469 SC_log(LOG_NOTICE
, "IORegistryCreateIterator() returned 0x%x", kr
);
3473 iterateRegistryBusy(iterator
, NULL
, &count
);
3475 SC_log(LOG_ERR
, "w/no busy services");
3478 IOObjectRelease(iterator
);
3482 timerCallback(CFRunLoopTimerRef timer
, void *info
)
3484 #pragma unused(timer)
3485 #pragma unused(info)
3486 // We've been waiting for IOKit to quiesce and it just
3487 // hasn't happenned. Time to just move on!
3488 addTimestamp(S_state
, kInterfaceNamerKey_Timeout
);
3491 SC_log(LOG_ERR
, "timed out waiting for IOKit to quiesce");
3494 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
3496 addTimestamp(S_state
, CFSTR("*TIMEOUT&NAMED*"));
3503 setup_IOKit(CFBundleRef bundle
)
3505 #pragma unused(bundle)
3508 mach_port_t masterPort
= MACH_PORT_NULL
;
3510 io_object_t root
= MACH_PORT_NULL
;
3512 // read DB of previously named network interfaces
3513 S_dblist
= readInterfaceList();
3514 if (S_dblist
!= NULL
) {
3517 n
= CFArrayGetCount(S_dblist
);
3519 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
3523 // get interfaces that were named during the last boot
3524 S_prev_active_list
= previouslyActiveInterfaces();
3526 // track how long we've waited to see each interface.
3527 S_state
= CFDictionaryCreateMutable(NULL
,
3529 &kCFTypeDictionaryKeyCallBacks
,
3530 &kCFTypeDictionaryValueCallBacks
);
3531 addTimestamp(S_state
, CFSTR("*START*"));
3533 // Creates and returns a notification object for receiving IOKit
3534 // notifications of new devices or state changes.
3535 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
3536 if (kr
!= KERN_SUCCESS
) {
3537 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
3541 S_notify
= IONotificationPortCreate(masterPort
);
3542 if (S_notify
== NULL
) {
3543 SC_log(LOG_ERR
, "IONotificationPortCreate failed");
3547 // watch IOKit matching activity
3548 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
3549 if (root
== MACH_PORT_NULL
) {
3550 SC_log(LOG_ERR
, "IORegistryEntryFromPath failed");
3554 kr
= IOServiceAddInterestNotification(S_notify
,
3558 (void *)S_notify
, // refCon
3559 &S_quiet
); // notification
3560 if (kr
!= KERN_SUCCESS
) {
3561 SC_log(LOG_ERR
, "IOServiceAddInterestNotification returned 0x%x", kr
);
3565 kr
= IOServiceGetBusyState(root
, &busy
);
3566 if (kr
!= KERN_SUCCESS
) {
3567 SC_log(LOG_ERR
, "IOServiceGetBusyState returned 0x%x", kr
);
3571 // add a timer so we don't wait forever for IOKit to quiesce
3572 S_timer
= CFRunLoopTimerCreate(NULL
,
3573 CFAbsoluteTimeGetCurrent() + S_stack_timeout
,
3579 if (S_timer
== NULL
) {
3580 SC_log(LOG_ERR
, "CFRunLoopTimerCreate failed");
3584 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
3586 // watch for the introduction of the IONetworkStack
3587 kr
= IOServiceAddMatchingNotification(S_notify
,
3588 kIOFirstMatchNotification
,
3589 IOServiceMatching("IONetworkStack"),
3591 (void *)S_notify
, // refCon
3592 &S_stack
); // notification
3593 if (kr
!= KERN_SUCCESS
) {
3594 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
3598 // check and see if the stack is already available and arm the
3599 // notification for its introduction.
3600 stackCallback((void *)S_notify
, S_stack
);
3602 // watch for the introduction of new network interfaces
3603 kr
= IOServiceAddMatchingNotification(S_notify
,
3604 kIOFirstMatchNotification
,
3605 IOServiceMatching("IONetworkInterface"),
3606 &interfaceArrivalCallback
,
3607 (void *)S_notify
, // refCon
3608 &S_iter
); // notification
3609 if (kr
!= KERN_SUCCESS
) {
3610 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
3614 // Get the current list of matches and arm the notification for
3615 // future interface arrivals.
3616 interfaceArrivalCallback((void *)S_notify
, S_iter
);
3618 // Check if IOKit has already quiesced.
3619 quietCallback((void *)S_notify
,
3621 kIOMessageServiceBusyStateChange
,
3622 (void *)(uintptr_t)busy
);
3624 CFRunLoopAddSource(CFRunLoopGetCurrent(),
3625 IONotificationPortGetRunLoopSource(S_notify
),
3626 kCFRunLoopDefaultMode
);
3628 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
3630 * Start the wheels turning until we've named all of
3631 * the interfaces that were used during the previous
3632 * boot, until IOKit [matching] has quiesced, or
3633 * until we've waited long enough.
3635 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
3636 CFRunLoopAddSource(CFRunLoopGetCurrent(),
3637 IONotificationPortGetRunLoopSource(S_notify
),
3639 while (S_prev_active_list
!= NULL
) {
3642 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
3644 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
3647 if (S_dblist
!= NULL
) {
3648 // apply special handling for the BT-PAN interface (if present)
3649 CFArrayApplyFunction(S_dblist
,
3650 CFRangeMake(0, CFArrayGetCount(S_dblist
)),
3651 updateBTPANInformation
,
3654 #endif // TARGET_OS_OSX
3659 if (root
!= MACH_PORT_NULL
) {
3660 IOObjectRelease(root
);
3662 if (masterPort
!= MACH_PORT_NULL
) {
3663 mach_port_deallocate(mach_task_self(), masterPort
);
3670 setup_Virtual(CFBundleRef bundle
)
3672 #pragma unused(bundle)
3673 // open a SCPreferences session
3674 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":setup_Virtual"), NULL
);
3675 if (S_prefs
== NULL
) {
3676 SC_log(LOG_ERR
, "SCPreferencesCreate() failed: %s",
3677 SCErrorString(SCError()));
3681 // register for change notifications.
3682 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
3683 SC_log(LOG_ERR
, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
3689 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
3690 if (SCError() != kSCStatusNoStoreServer
) {
3691 SC_log(LOG_ERR
, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
3701 exec_InterfaceNamer(void *arg
)
3703 CFBundleRef bundle
= (CFBundleRef
)arg
;
3704 CFDictionaryRef dict
;
3706 pthread_setname_np(MY_PLUGIN_NAME
" thread");
3708 dict
= CFBundleGetInfoDictionary(bundle
);
3709 if (isA_CFDictionary(dict
)) {
3712 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_STACK_TIMEOUT_KEY
));
3714 if (!isA_CFNumber(num
) ||
3715 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_stack_timeout
) ||
3716 (S_stack_timeout
<= 0.0)) {
3717 SC_log(LOG_NOTICE
, WAIT_STACK_TIMEOUT_KEY
" value error");
3718 S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
3722 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
3724 if (!isA_CFNumber(num
) ||
3725 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_quiet_timeout
) ||
3726 (S_quiet_timeout
<= 0.0)) {
3727 SC_log(LOG_NOTICE
, WAIT_QUIET_TIMEOUT_KEY
" value error");
3728 S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
3733 // setup virtual network interface monitoring
3734 if (!setup_Virtual(bundle
)) {
3738 // setup [IOKit] network interface monitoring
3739 if (!setup_IOKit(bundle
)) {
3746 if (S_connect
!= MACH_PORT_NULL
) {
3747 IOServiceClose(S_connect
);
3748 S_connect
= MACH_PORT_NULL
;
3750 if (S_dblist
!= NULL
) {
3751 CFRelease(S_dblist
);
3754 if (S_iter
!= MACH_PORT_NULL
) {
3755 IOObjectRelease(S_iter
);
3756 S_iter
= MACH_PORT_NULL
;
3758 if (S_notify
!= MACH_PORT_NULL
) {
3759 IONotificationPortDestroy(S_notify
);
3761 if (S_quiet
!= MACH_PORT_NULL
) {
3762 IOObjectRelease(S_quiet
);
3763 S_quiet
= MACH_PORT_NULL
;
3765 if (S_stack
!= MACH_PORT_NULL
) {
3766 IOObjectRelease(S_stack
);
3767 S_stack
= MACH_PORT_NULL
;
3769 if (S_state
!= NULL
) {
3773 if (S_timer
!= NULL
) {
3774 CFRunLoopTimerInvalidate(S_timer
);
3788 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
3790 #pragma unused(bundleVerbose)
3791 pthread_attr_t tattr
;
3794 CFRetain(bundle
); // released in exec_InterfaceNamer
3796 pthread_attr_init(&tattr
);
3797 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
3798 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
3799 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
3800 pthread_create(&tid
, &tattr
, exec_InterfaceNamer
, bundle
);
3801 pthread_attr_destroy(&tattr
);
3806 //------------------------------------------------------------------------
3808 #ifdef TEST_INTERFACE_ASSIGNMENT
3810 main(int argc
, char ** argv
)
3812 #pragma unused(argv)
3814 CFMutableArrayRef interfaces
;
3815 CFArrayRef interfaces_all
;
3819 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
3821 bundle
= CFBundleGetMainBundle();
3822 CFRetain(bundle
); // released in exec_InterfaceNamer
3825 setup_IOKit(bundle
);
3827 // but, when running this test we know that the IORegistry has already quiesced
3828 IOObjectRelease(S_quiet
);
3829 S_quiet
= MACH_PORT_NULL
;
3831 // collect the interfaces
3832 interfaces
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3833 interfaces_all
= SCNetworkInterfaceCopyAll();
3834 n
= CFArrayGetCount(interfaces_all
);
3835 for (CFIndex i
= 0; i
< n
; i
++) {
3836 SCNetworkInterfaceRef interface
= CFArrayGetValueAtIndex(interfaces_all
, i
);
3837 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)interface
;
3839 if (interfacePrivate
->type
== NULL
) {
3840 // skip interfaces with a kIOInterfaceType property
3844 if (interfacePrivate
->unit
!= NULL
) {
3845 // remove any already assigned unit #
3846 CFRelease(interfacePrivate
->unit
);
3847 interfacePrivate
->unit
= NULL
;
3850 CFArrayAppendValue(interfaces
, interface
);
3852 CFRelease(interfaces_all
);
3853 SC_log(LOG_INFO
, "interfaces = %@", interfaces
);
3855 // exercise the interface naming assignments
3856 nameInterfaces(interfaces
);
3857 CFRelease(interfaces
);
3864 #ifdef TEST_SNAPSHOT
3866 main(int argc
, char ** argv
)
3869 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
3876 #endif /* TEST_SNAPSHOT */