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 InterfaceNamePrefix 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 InterfaceNamePrefix, 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)
299 CFComparisonResult res
;
303 prefix1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
304 CFSTR(kIOInterfaceNamePrefix
));
305 prefix2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
306 CFSTR(kIOInterfaceNamePrefix
));
307 res
= CFStringCompare(prefix1
, prefix2
, 0);
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 (cur_list
== NULL
) {
395 const int new_version
= NETWORK_CONFIGURATION_VERSION
;
398 version
= CFNumberCreate(NULL
, kCFNumberIntType
, &new_version
);
399 SCPreferencesSetValue(ni_prefs
, kSCPrefVersion
, version
);
403 if (!SCPreferencesCommitChanges(ni_prefs
)) {
404 if (SCError() != EROFS
) {
405 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
416 static CF_RETURNS_RETAINED CFMutableArrayRef
419 CFMutableArrayRef db_list
= NULL
;
421 SCPreferencesRef ni_prefs
;
422 CFStringRef old_model
;
424 ni_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":readInterfaceList"), INTERFACES_DEFAULT_CONFIG
);
425 if (ni_prefs
== NULL
) {
426 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
430 if_list
= SCPreferencesGetValue(ni_prefs
, INTERFACES
);
431 if_list
= isA_CFArray(if_list
);
433 old_model
= SCPreferencesGetValue(ni_prefs
, MODEL
);
434 if (old_model
!= NULL
) {
435 CFStringRef new_model
;
437 new_model
= _SC_hw_model(FALSE
);
438 if (!_SC_CFEqual(old_model
, new_model
)) {
440 * If the interface list was created on other hardware then
447 if (if_list
!= NULL
) {
448 CFIndex n
= CFArrayGetCount(if_list
);
450 db_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
451 for (CFIndex i
= 0; i
< n
; i
++) {
452 CFDictionaryRef dict
;
454 dict
= CFArrayGetValueAtIndex(if_list
, i
);
455 if (isA_CFDictionary(dict
) &&
456 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceNamePrefix
)) &&
457 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
458 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
459 CFArrayAppendValue(db_list
, dict
);
464 if (db_list
!= NULL
) {
465 CFIndex n
= CFArrayGetCount(db_list
);
468 CFArraySortValues(db_list
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
476 static CF_RETURNS_RETAINED CFMutableArrayRef
477 previouslyActiveInterfaces()
479 CFMutableArrayRef active
;
482 if (S_dblist
== NULL
) {
486 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
488 n
= CFArrayGetCount(S_dblist
);
489 for (CFIndex i
= 0; i
< n
; i
++) {
490 CFDictionaryRef if_dict
;
492 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
493 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
494 CFMutableDictionaryRef new_dict
;
496 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
497 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
498 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
499 CFArrayAppendValue(active
, new_dict
);
508 updateInterfaces(void);
515 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
), kSCDynamicStoreDomainPlugin
);
516 (void)SCDynamicStoreSetValue(NULL
, key
, S_state
);
522 #if !TARGET_OS_IPHONE
524 updateBondInterfaceConfiguration(SCPreferencesRef prefs
)
526 CFArrayRef interfaces
;
528 interfaces
= SCBondInterfaceCopyAll(prefs
);
529 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
530 CFRelease(interfaces
);
534 if (_SC_CFEqual(S_bonds
, interfaces
)) {
536 if (interfaces
!= NULL
) CFRelease(interfaces
);
540 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
541 S_bonds
= interfaces
;
543 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
544 SC_log(LOG_NOTICE
, "_SCBondInterfaceUpdateConfiguration() failed: %s",
545 SCErrorString(SCError()));
550 #endif // !TARGET_OS_IPHONE
553 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs
)
555 CFArrayRef interfaces
;
557 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
558 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
559 CFRelease(interfaces
);
563 if (_SC_CFEqual(S_bridges
, interfaces
)) {
565 if (interfaces
!= NULL
) CFRelease(interfaces
);
569 if (S_bridges
!= NULL
) CFRelease(S_bridges
);
570 S_bridges
= interfaces
;
572 if (!_SCBridgeInterfaceUpdateConfiguration(prefs
)) {
573 SC_log(LOG_NOTICE
, "_SCBridgeInterfaceUpdateConfiguration() failed: %s",
574 SCErrorString(SCError()));
581 updateVLANInterfaceConfiguration(SCPreferencesRef prefs
)
583 CFArrayRef interfaces
;
585 interfaces
= SCVLANInterfaceCopyAll(prefs
);
586 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
587 CFRelease(interfaces
);
591 if (_SC_CFEqual(S_vlans
, interfaces
)) {
593 if (interfaces
!= NULL
) CFRelease(interfaces
);
597 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
598 S_vlans
= interfaces
;
600 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
601 SC_log(LOG_NOTICE
, "_SCVLANInterfaceUpdateConfiguration() failed: %s",
602 SCErrorString(SCError()));
609 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
610 SCPreferencesNotification notificationType
,
614 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
619 // if a new interface has been "named"
621 if (S_bonds
!= NULL
) {
625 if (S_bridges
!= NULL
) {
626 CFRelease(S_bridges
);
629 if (S_vlans
!= NULL
) {
635 #if !TARGET_OS_IPHONE
636 updateBondInterfaceConfiguration (prefs
);
637 #endif // !TARGET_OS_IPHONE
638 updateBridgeInterfaceConfiguration(prefs
);
639 updateVLANInterfaceConfiguration (prefs
);
641 // we are finished with current prefs, wait for changes
642 SCPreferencesSynchronize(prefs
);
650 updateBTPANInformation(const void *value
, void *context
)
652 #pragma unused(context)
654 CFDictionaryRef dict
= (CFDictionaryRef
)value
;
656 CFDictionaryRef info
;
659 if_name
= CFDictionaryGetValue(dict
, CFSTR(kIOBSDNameKey
));
660 if (!isA_CFString(if_name
)) {
665 info
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceInfo
));
666 if (!isA_CFDictionary(info
)) {
667 // if no SCNetworkInterface info
671 name
= CFDictionaryGetValue(info
, kSCPropUserDefinedName
);
672 if (!isA_CFString(name
) || !CFEqual(name
, CFSTR(BT_PAN_NAME
))) {
673 // if not BT-PAN interface
677 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Name
, if_name
);
679 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
680 if (isA_CFData(addr
)) {
681 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Mac
, addr
);
686 #endif // TARGET_OS_OSX
688 static CFDictionaryRef
689 createInterfaceDict(SCNetworkInterfaceRef interface
, CFArrayRef matchingMACs
)
691 CFMutableDictionaryRef new_if
;
694 new_if
= CFDictionaryCreateMutable(NULL
,
696 &kCFTypeDictionaryKeyCallBacks
,
697 &kCFTypeDictionaryValueCallBacks
);
699 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
701 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
705 val
= _SCNetworkInterfaceGetIOPath(interface
);
707 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
710 val
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
712 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceNamePrefix
), val
);
715 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
717 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
720 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
722 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
725 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
727 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
730 val
= SCNetworkInterfaceGetBSDName(interface
);
732 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
735 val
= SCNetworkInterfaceGetInterfaceType(interface
);
737 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
740 CFDictionarySetValue(new_if
,
742 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
744 if (_SCNetworkInterfaceIsHiddenConfiguration(interface
)) {
745 CFDictionarySetValue(new_if
, kSCNetworkInterfaceHiddenConfigurationKey
, kCFBooleanTrue
);
748 if (_SCNetworkInterfaceIsHiddenInterface(interface
)) {
749 CFDictionarySetValue(new_if
, kSCNetworkInterfaceHiddenInterfaceKey
, kCFBooleanTrue
);
752 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
754 if (matchingMACs
!= NULL
) {
755 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceMatchingMACs
), matchingMACs
);
761 static CFDictionaryRef
762 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
768 if (db_list
== NULL
) {
771 prefix
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
772 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
773 if (prefix
== NULL
|| addr
== NULL
) {
777 n
= CFArrayGetCount(db_list
);
778 for (CFIndex i
= 0; i
< n
; i
++) {
779 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
781 CFStringRef this_prefix
;
783 this_prefix
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceNamePrefix
));
784 this_addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
785 if (this_prefix
== NULL
|| this_addr
== NULL
)
788 if (CFEqual(prefix
, this_prefix
) && CFEqual(addr
, this_addr
)) {
798 static CFDictionaryRef
799 lookupInterfaceByName(CFArrayRef db_list
, CFStringRef bsdName
, CFIndex
* where
)
803 if (db_list
== NULL
) {
807 n
= CFArrayGetCount(db_list
);
808 for (CFIndex i
= 0; i
< n
; i
++) {
809 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
812 name
= CFDictionaryGetValue(dict
, CFSTR(kIOBSDNameKey
));
813 if (_SC_CFEqual(name
, bsdName
)) {
823 static CFDictionaryRef
824 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
830 if (db_list
== NULL
) {
833 prefix
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
834 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
835 if (prefix
== NULL
|| unit
== NULL
) {
839 n
= CFArrayGetCount(db_list
);
840 for (CFIndex i
= 0; i
< n
; i
++) {
841 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
842 CFStringRef this_prefix
;
843 CFNumberRef this_unit
;
845 this_prefix
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceNamePrefix
));
846 this_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
847 if (this_prefix
== NULL
|| this_unit
== NULL
) {
851 if (CFEqual(prefix
, this_prefix
) && CFEqual(unit
, this_unit
)) {
862 CFDictionaryRef match_info
;
863 CFStringRef match_type
;
864 CFStringRef match_prefix
;
865 CFBooleanRef match_builtin
;
866 CFMutableArrayRef matches
;
867 } matchContext
, *matchContextRef
;
869 static CF_RETURNS_RETAINED CFDictionaryRef
870 thinInterfaceInfo(CFDictionaryRef info
)
875 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
877 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
878 && (vid
== kIOUSBAppleVendorID
)) {
879 CFMutableDictionaryRef thin
;
881 // if this is an Apple USB device than we trust that
882 // the non-localized name will be correct.
883 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
884 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
885 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
886 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
890 return CFRetain(info
);
894 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
898 match
= _SC_CFEqual(known_info
, match_info
);
900 isA_CFDictionary(known_info
) &&
901 isA_CFDictionary(match_info
)) {
903 // if not an exact match, try thinning
904 known_info
= thinInterfaceInfo(known_info
);
905 match_info
= thinInterfaceInfo(match_info
);
906 match
= _SC_CFEqual(known_info
, match_info
);
907 if (known_info
!= NULL
) CFRelease(known_info
);
908 if (match_info
!= NULL
) CFRelease(match_info
);
915 matchKnown(const void *value
, void *context
)
917 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
918 matchContextRef match_context
= (matchContextRef
)context
;
922 CFStringRef known_prefix
;
925 = CFDictionaryGetValue(known_dict
,
926 CFSTR(kIOInterfaceNamePrefix
));
927 if (!_SC_CFEqual(known_prefix
, match_context
->match_prefix
)) {
932 // match interface type
934 CFStringRef known_type
;
936 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
937 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
942 // match SCNetworkInterfaceInfo
944 CFDictionaryRef known_info
;
946 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
947 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
952 // if requested, match [non-]builtin
953 if (match_context
->match_builtin
!= NULL
) {
954 CFBooleanRef known_builtin
;
956 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
957 if (!isA_CFBoolean(known_builtin
)) {
958 known_builtin
= kCFBooleanFalse
;
960 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
965 // if we have a match
966 if (match_context
->matches
== NULL
) {
967 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
969 CFArrayAppendValue(match_context
->matches
, known_dict
);
975 matchUnnamed(const void *value
, void *context
)
977 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
978 matchContextRef match_context
= (matchContextRef
)context
;
980 if (match_context
->matches
== NULL
) {
984 // match interface type
986 CFStringRef known_type
;
988 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
989 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
994 // match SCNetworkInterfaceInfo
996 CFDictionaryRef known_info
;
999 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
1000 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
1001 if (known_info
!= NULL
) CFRelease(known_info
);
1007 // if requested, match [non-]builtin
1008 if (match_context
->match_builtin
!= NULL
) {
1009 CFBooleanRef known_builtin
;
1011 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
1013 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
1018 // if we have a match
1019 CFRelease(match_context
->matches
);
1020 match_context
->matches
= NULL
;
1026 interfaceExists(CFStringRef prefix
, CFNumberRef unit
)
1028 Boolean found
= FALSE
;
1029 CFDictionaryRef match_dict
;
1030 CFStringRef match_keys
[2];
1031 CFTypeRef match_vals
[2];
1032 CFDictionaryRef matching
;
1036 io_registry_entry_t entry
= MACH_PORT_NULL
;
1037 io_iterator_t iterator
= MACH_PORT_NULL
;
1039 mach_port_t masterPort
= MACH_PORT_NULL
;
1041 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1042 if (kr
!= KERN_SUCCESS
) {
1043 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1047 // look for kIONetworkInterface with matching prefix and unit
1048 match_keys
[0] = CFSTR(kIOInterfaceNamePrefix
);
1049 match_vals
[0] = prefix
;
1050 match_keys
[1] = CFSTR(kIOInterfaceUnit
);
1051 match_vals
[1] = unit
;
1052 match_dict
= CFDictionaryCreate(NULL
,
1053 (const void **)match_keys
,
1054 (const void **)match_vals
,
1056 &kCFTypeDictionaryKeyCallBacks
,
1057 &kCFTypeDictionaryValueCallBacks
);
1059 match_keys
[0] = CFSTR(kIOProviderClassKey
);
1060 match_vals
[0] = CFSTR(kIONetworkInterfaceClass
);
1061 match_keys
[1] = CFSTR(kIOPropertyMatchKey
);
1062 match_vals
[1] = match_dict
;
1063 matching
= CFDictionaryCreate(NULL
,
1064 (const void **)match_keys
,
1065 (const void **)match_vals
,
1066 sizeof(match_keys
)/sizeof(match_keys
[0]),
1067 &kCFTypeDictionaryKeyCallBacks
,
1068 &kCFTypeDictionaryValueCallBacks
);
1069 CFRelease(match_dict
);
1071 // note: the "matching" dictionary will be consumed by the following
1072 kr
= IOServiceGetMatchingServices(masterPort
, matching
, &iterator
);
1073 if ((kr
!= kIOReturnSuccess
) || (iterator
== MACH_PORT_NULL
)) {
1078 entry
= IOIteratorNext(iterator
);
1079 if (entry
== MACH_PORT_NULL
) {
1087 if (masterPort
!= MACH_PORT_NULL
) {
1088 mach_port_deallocate(mach_task_self(), masterPort
);
1090 if (entry
!= MACH_PORT_NULL
) {
1091 IOObjectRelease(entry
);
1093 if (iterator
!= MACH_PORT_NULL
) {
1094 IOObjectRelease(iterator
);
1101 * lookupMatchingInterface
1103 * Looks at the interfaces that have already been [or need to be] named with
1104 * the goal of allowing a system using a single network interface/adaptor of
1105 * a given type (vendor, model, ...) to not care about the specific adaptor
1106 * that is used (i.e. swapping dongle's is OK). Once a system has had more
1107 * than one interface/adaptor connected at the same time than we assume that
1108 * the network configuration is being setup for multi-homing that should be
1111 * If no matches are found or if more than one match is found, return NULL.
1112 * If a single match is found, return the match.
1114 static CFDictionaryRef
1115 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
1116 CFArrayRef db_list
, // already named
1117 CFArrayRef if_list
, // to be named
1118 CFIndex if_list_index
,
1119 CFBooleanRef builtin
)
1121 CFStringRef if_type
;
1122 CFStringRef if_prefix
;
1123 CFDictionaryRef match
= NULL
;
1124 matchContext match_context
;
1126 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
1127 if (if_type
== NULL
) {
1130 if_prefix
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
1131 if (if_prefix
== NULL
) {
1135 match_context
.match_type
= if_type
;
1136 match_context
.match_prefix
= if_prefix
;
1137 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
1138 match_context
.match_builtin
= builtin
;
1139 match_context
.matches
= NULL
;
1141 // check for matches to interfaces that have already been named
1142 // ... and append each match that we find to match_context.matches
1143 if (db_list
!= NULL
) {
1144 CFArrayApplyFunction(db_list
,
1145 CFRangeMake(0, CFArrayGetCount(db_list
)),
1150 // check for matches to interfaces that will be named
1151 // ... and CFRelease match_context.matches if we find another network
1152 // interface of the same type that also needs to be named
1153 if (if_list
!= NULL
) {
1154 CFIndex if_list_count
;
1156 if_list_count
= CFArrayGetCount(if_list
);
1157 if (if_list_index
< if_list_count
) {
1158 CFArrayApplyFunction(if_list
,
1159 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
1165 // check if we have a single match
1166 if (match_context
.matches
!= NULL
) {
1167 if (CFArrayGetCount(match_context
.matches
) == 1) {
1168 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
1170 CFRelease(match_context
.matches
);
1173 if (match
!= NULL
) {
1174 Boolean active
= TRUE
;
1177 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
1178 if (isA_CFString(name
)) {
1182 prefix
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceNamePrefix
));
1183 unit
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceUnit
));
1184 if (isA_CFString(prefix
) && isA_CFNumber(unit
)) {
1185 if (!interfaceExists(prefix
, unit
)) {
1196 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
1201 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
, CFDictionaryRef db_dict_match
)
1204 CFDictionaryRef if_dict
;
1205 CFStringRef if_name
;
1206 CFStringRef if_prefix
;
1207 CFNumberRef if_unit
;
1208 CFArrayRef matchingMACs
= NULL
;
1209 CFIndex n
= CFArrayGetCount(db_list
);
1210 CFComparisonResult res
;
1212 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1213 if (if_name
!= NULL
) {
1214 addTimestamp(S_state
, if_name
);
1217 if (!_SCNetworkInterfaceIsBuiltin(interface
) && (db_dict_match
!= NULL
)) {
1221 matchingMACs
= CFDictionaryGetValue(db_dict_match
, CFSTR(kSCNetworkInterfaceMatchingMACs
));
1222 if (matchingMACs
!= NULL
) {
1223 CFRetain(matchingMACs
);
1226 addr_old
= CFDictionaryGetValue(db_dict_match
, CFSTR(kIOMACAddress
));
1227 addr_cur
= _SCNetworkInterfaceGetHardwareAddress(interface
);
1228 if ((addr_old
!= NULL
) && (addr_cur
!= NULL
) && !CFEqual(addr_old
, addr_cur
)) {
1229 CFMutableArrayRef matching_new
;
1231 // if MAC address changed, add previous MAC to history
1232 if (matchingMACs
!= NULL
) {
1233 matching_new
= CFArrayCreateMutableCopy(NULL
, 0, matchingMACs
);
1234 CFRelease(matchingMACs
);
1236 // remove duplicates of the now current MAC from history
1237 i
= CFArrayGetFirstIndexOfValue(matching_new
, CFRangeMake(0, CFArrayGetCount(matching_new
)), addr_cur
);
1238 if (i
!= kCFNotFound
) {
1239 CFArrayRemoveValueAtIndex(matching_new
, i
);
1242 // remove duplicates of the previous MAC from history before re-inserting
1243 i
= CFArrayGetFirstIndexOfValue(matching_new
, CFRangeMake(0, CFArrayGetCount(matching_new
)), addr_old
);
1244 if (i
!= kCFNotFound
) {
1245 CFArrayRemoveValueAtIndex(matching_new
, i
);
1248 matching_new
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1250 CFArrayInsertValueAtIndex(matching_new
, 0, addr_old
);
1252 // limit history size
1253 #define MATCHING_HISTORY_MAXLEN 32
1254 for (i
= CFArrayGetCount(matching_new
); i
> MATCHING_HISTORY_MAXLEN
; i
--) {
1255 CFArrayRemoveValueAtIndex(matching_new
, i
- 1);
1258 matchingMACs
= matching_new
;
1262 if_dict
= createInterfaceDict(interface
, matchingMACs
);
1263 if (matchingMACs
!= NULL
) {
1264 CFRelease(matchingMACs
);
1267 if_prefix
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
1268 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1269 if ((if_prefix
== NULL
) || (if_unit
== NULL
)) {
1274 for (i
= 0; i
< n
; i
++) {
1275 CFStringRef db_prefix
;
1276 CFNumberRef db_unit
;
1277 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
1279 db_prefix
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceNamePrefix
));
1280 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1281 res
= CFStringCompare(if_prefix
, db_prefix
, 0);
1282 if (res
== kCFCompareLessThan
1283 || (res
== kCFCompareEqualTo
1284 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
1285 == kCFCompareLessThan
))) {
1286 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
1292 CFArrayAppendValue(S_dblist
, if_dict
);
1295 updateBTPANInformation(if_dict
, NULL
);
1296 #endif // TARGET_OS_OSX
1303 removeInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
, CFDictionaryRef
*matched
)
1305 CFDictionaryRef db_dict
;
1309 // remove any dict that has our prefix+addr
1311 db_dict
= lookupInterfaceByAddress(db_list
, interface
, &where
);
1312 if (db_dict
== NULL
) {
1315 if ((matched
!= NULL
) && (*matched
== NULL
)) {
1316 *matched
= CFRetain(db_dict
);
1318 CFArrayRemoveValueAtIndex(db_list
, where
);
1322 // remove any dict that has the same prefix+unit
1324 db_dict
= lookupInterfaceByUnit(db_list
, interface
, &where
);
1325 if (db_dict
== NULL
) {
1328 if ((matched
!= NULL
) && (*matched
== NULL
)) {
1329 *matched
= CFRetain(db_dict
);
1331 CFArrayRemoveValueAtIndex(db_list
, where
);
1336 SC_log(LOG_ERR
, "Multiple interfaces removed from database (n = %d, %@)", n
, interface
);
1343 replaceInterface(SCNetworkInterfaceRef interface
)
1345 CFDictionaryRef matched
= NULL
;
1347 if (S_dblist
== NULL
) {
1348 S_dblist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1350 // remove any matching interfaces
1351 removeInterface(S_dblist
, interface
, &matched
);
1354 // [re-]insert the new interface
1355 insertInterface(S_dblist
, interface
, matched
);
1357 if (matched
!= NULL
) {
1365 getNextUnitForPrefix(CFStringRef if_prefix
, int requested
)
1369 if (S_dblist
== NULL
) {
1373 n
= CFArrayGetCount(S_dblist
);
1374 for (CFIndex i
= 0; i
< n
; i
++) {
1375 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1378 prefix
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceNamePrefix
));
1379 if (CFEqual(prefix
, if_prefix
)) {
1383 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1384 if (!isA_CFNumber(unit
) ||
1385 !CFNumberGetValue(unit
, kCFNumberIntType
, &u
)) {
1389 if (u
< requested
) {
1390 // if we have not yet found our starting unit #
1394 if (u
== requested
) {
1395 // our starting (or now proposed) unit # is "in use" so
1396 // let's keep searching
1401 // we've found a unit # gap ... so let's re-assign it!
1409 * Function: ensureInterfaceHasUnit
1411 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1412 * release the interface and return NULL.
1414 static SCNetworkInterfaceRef
1415 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if
)
1418 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if
) == NULL
) {
1425 #ifdef USE_REGISTRY_ENTRY_ID
1426 static kern_return_t
1427 registerInterfaceWithIORegistryEntryID(io_connect_t connect
,
1433 CFMutableDictionaryRef dict
;
1437 dict
= CFDictionaryCreateMutable(NULL
, 0,
1438 &kCFTypeDictionaryKeyCallBacks
,
1439 &kCFTypeDictionaryValueCallBacks
);
1440 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1441 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1443 data
= CFDataCreate(NULL
, (void *) &entryID
, sizeof(entryID
));
1444 CFDictionarySetValue(dict
, CFSTR(kIORegistryEntryIDKey
), data
);
1446 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1447 kr
= IOConnectSetCFProperties(connect
, dict
);
1452 static SCNetworkInterfaceRef
1453 copyInterfaceForIORegistryEntryID(uint64_t entryID
)
1455 io_registry_entry_t entry
= MACH_PORT_NULL
;
1456 SCNetworkInterfaceRef interface
= NULL
;
1457 io_iterator_t iterator
= MACH_PORT_NULL
;
1459 mach_port_t masterPort
= MACH_PORT_NULL
;
1461 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1462 if (kr
!= KERN_SUCCESS
) {
1463 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1467 kr
= IOServiceGetMatchingServices(masterPort
,
1468 IORegistryEntryIDMatching(entryID
),
1470 if ((kr
!= KERN_SUCCESS
) || (iterator
== MACH_PORT_NULL
)) {
1471 SC_log(LOG_NOTICE
, "IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d",
1478 entry
= IOIteratorNext(iterator
);
1479 if (entry
== MACH_PORT_NULL
) {
1480 SC_log(LOG_NOTICE
, "IORegistryEntryIDMatching(0x%llx) failed", entryID
);
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
);
1493 if (iterator
!= MACH_PORT_NULL
) {
1494 IOObjectRelease(iterator
);
1499 static SCNetworkInterfaceRef
1500 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID
)
1502 SCNetworkInterfaceRef net_if
;
1504 net_if
= copyInterfaceForIORegistryEntryID(entryID
);
1505 return (ensureInterfaceHasUnit(net_if
));
1508 #else // USE_REGISTRY_ENTRY_ID
1510 * Function: registerInterface
1512 * Register a single interface with the given service path to the
1513 * data link layer (BSD), using the specified unit number.
1515 static kern_return_t
1516 registerInterfaceWithIOServicePath(io_connect_t connect
,
1521 CFMutableDictionaryRef dict
;
1525 dict
= CFDictionaryCreateMutable(NULL
, 0,
1526 &kCFTypeDictionaryKeyCallBacks
,
1527 &kCFTypeDictionaryValueCallBacks
);
1528 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1529 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1531 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1532 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1533 kr
= IOConnectSetCFProperties(connect
, dict
);
1538 static SCNetworkInterfaceRef
1539 copyInterfaceForIOKitPath(CFStringRef if_path
)
1541 io_registry_entry_t entry
= MACH_PORT_NULL
;
1542 SCNetworkInterfaceRef interface
= NULL
;
1544 mach_port_t masterPort
= MACH_PORT_NULL
;
1547 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1548 if (kr
!= KERN_SUCCESS
) {
1549 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1552 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1553 entry
= IORegistryEntryFromPath(masterPort
, path
);
1554 if (entry
== MACH_PORT_NULL
) {
1555 SC_log(LOG_NOTICE
, "IORegistryEntryFromPath(%@) failed", if_path
);
1559 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1562 if (masterPort
!= MACH_PORT_NULL
) {
1563 mach_port_deallocate(mach_task_self(), masterPort
);
1565 if (entry
!= MACH_PORT_NULL
) {
1566 IOObjectRelease(entry
);
1572 static SCNetworkInterfaceRef
1573 copyNamedInterfaceForIOKitPath(CFStringRef if_path
)
1575 SCNetworkInterfaceRef net_if
;
1577 net_if
= copyInterfaceForIOKitPath(if_path
);
1578 return (ensureInterfaceHasUnit(net_if
));
1581 #endif // USE_REGISTRY_ENTRY_ID
1584 displayInterface(SCNetworkInterfaceRef interface
)
1591 name
= SCNetworkInterfaceGetBSDName(interface
);
1592 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1593 prefix
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
1594 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1596 SC_log(LOG_INFO
, " %s%@%sPrefix: %@, %s%@%sMAC address: %@",
1597 (name
!= NULL
) ? "BSD Name: " : "",
1598 (name
!= NULL
) ? name
: CFSTR(""),
1599 (name
!= NULL
) ? ", " : "",
1601 (unit
!= NULL
) ? "Unit: " : "",
1602 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1603 (unit
!= NULL
) ? ", " : "",
1604 (addr
!= NULL
) ? addr
: CFSTR("?"));
1608 builtinAvailable(SCNetworkInterfaceRef interface
, // new interface
1609 CFNumberRef if_unit
) // desired unit
1612 CFStringRef if_prefix
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
1615 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1616 for (i
= 0; i
< n
; i
++) {
1617 CFStringRef if_path
;
1618 CFDictionaryRef known_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1619 CFStringRef known_path
;
1620 CFStringRef known_prefix
;
1621 CFNumberRef known_unit
;
1623 known_prefix
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceNamePrefix
));
1624 if (!_SC_CFEqual(if_prefix
, known_prefix
)) {
1625 continue; // if not the same interface prefix
1628 known_unit
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceUnit
));
1629 if (!_SC_CFEqual(if_unit
, known_unit
)) {
1630 continue; // if not the same interface unit
1633 if_path
= _SCNetworkInterfaceGetIOPath(interface
);
1634 known_path
= CFDictionaryGetValue(known_dict
, CFSTR(kIOPathMatchKey
));
1635 if (!_SC_CFEqual(if_path
, known_path
)) {
1636 // if different IORegistry path
1640 // if same prefix+unit+path
1644 // if interface prefix+unit not found
1649 builtinCount(CFArrayRef if_list
, CFIndex last
, CFStringRef if_prefix
)
1654 for (i
= 0; i
< last
; i
++) {
1655 SCNetworkInterfaceRef builtin_if
;
1656 CFStringRef builtin_prefix
;
1658 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1659 builtin_prefix
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(builtin_if
);
1660 if (CFEqual(if_prefix
, builtin_prefix
)) {
1661 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1662 n
++; // if built-in interface
1672 #pragma mark Internet Sharing configuration support
1677 static SCPreferencesRef nat_configuration
= NULL
; // com.apple.nat.plist
1678 static SCPreferencesRef nat_preferences
= NULL
; // preferences.plist
1682 sharingConfigurationClose(void)
1684 if (nat_configuration
!= NULL
) {
1685 CFRelease(nat_configuration
);
1686 nat_configuration
= NULL
;
1689 if (nat_preferences
!= NULL
) {
1690 CFRelease(nat_preferences
);
1691 nat_preferences
= NULL
;
1699 sharingConfigurationUsesInterface(CFStringRef bsdName
, Boolean keepOpen
)
1701 CFDictionaryRef config
;
1702 Boolean isShared
= FALSE
;
1704 if (nat_configuration
== NULL
) {
1705 nat_configuration
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":sharingConfigurationUsesInterface"), CFSTR("com.apple.nat.plist"));
1706 if (nat_configuration
== NULL
) {
1711 config
= SCPreferencesGetValue(nat_configuration
, CFSTR("NAT"));
1712 if (isA_CFDictionary(config
)) {
1713 CFBooleanRef bVal
= NULL
;
1714 Boolean enabled
= FALSE
;
1715 CFStringRef sharedFromServiceID
= NULL
;
1716 CFArrayRef sharedToInterfaces
= NULL
;
1718 if (CFDictionaryGetValueIfPresent(config
,
1720 (const void **)&bVal
) &&
1721 isA_CFBoolean(bVal
)) {
1722 enabled
= CFBooleanGetValue(bVal
);
1726 CFDictionaryGetValueIfPresent(config
,
1727 CFSTR("SharingDevices"),
1728 (const void **)&sharedToInterfaces
) &&
1729 isA_CFArray(sharedToInterfaces
)) {
1732 // if "To computers using" interfaces configured
1733 n
= CFArrayGetCount(sharedToInterfaces
);
1734 for (CFIndex i
= 0; i
< n
; i
++) {
1735 CFStringRef sharedToInterface_bsdName
;
1737 sharedToInterface_bsdName
= CFArrayGetValueAtIndex(sharedToInterfaces
, i
);
1738 if (_SC_CFEqual(bsdName
, sharedToInterface_bsdName
)) {
1747 CFDictionaryGetValueIfPresent(config
,
1748 CFSTR("PrimaryService"),
1749 (const void **)&sharedFromServiceID
) &&
1750 isA_CFString(sharedFromServiceID
)) {
1751 if (nat_preferences
== NULL
) {
1752 nat_preferences
= SCPreferencesCreateCompanion(nat_configuration
, NULL
);
1754 if (nat_preferences
!= NULL
) {
1755 SCNetworkServiceRef sharedFromService
;
1757 // if "Share your connection from" service configured
1758 sharedFromService
= SCNetworkServiceCopy(nat_preferences
, sharedFromServiceID
);
1759 if (sharedFromService
!= NULL
) {
1760 CFStringRef sharedFromService_bsdName
;
1761 SCNetworkInterfaceRef sharedFromService_interface
;
1763 sharedFromService_interface
= SCNetworkServiceGetInterface(sharedFromService
);
1764 sharedFromService_bsdName
= SCNetworkInterfaceGetBSDName(sharedFromService_interface
);
1765 isShared
= _SC_CFEqual(bsdName
, sharedFromService_bsdName
);
1766 CFRelease(sharedFromService
);
1773 sharingConfigurationClose();
1779 #endif // TARGET_OS_OSX
1783 #pragma mark Interface monitoring (e.g. watch for "detach")
1786 typedef struct WatchedInfo
*WatchedInfoRef
;
1788 typedef void (*InterfaceUpdateCallBack
) (
1790 natural_t messageType
,
1791 void *messageArgument
1795 SCNetworkInterfaceRef interface
;
1796 io_service_t interface_node
;
1797 io_object_t notification
;
1798 InterfaceUpdateCallBack callback
;
1802 watcherRelease(CFDataRef watched
);
1805 updateWatchedInterface(void *refCon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
1807 #pragma unused(service)
1808 #pragma unused(messageArgument)
1809 switch (messageType
) {
1810 case kIOMessageServiceIsTerminated
: { // if [watched] interface yanked
1811 SCNetworkInterfaceRef remove
;
1812 CFDataRef watched
= (CFDataRef
)refCon
;
1813 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1815 remove
= watchedInfo
->interface
;
1816 if (_SCNetworkInterfaceIsBuiltin(remove
)) {
1817 // if built-in, keep
1819 } else if (!_SCNetworkInterfaceIsApplePreconfigured(remove
)) {
1820 // if not pre-configured, keep
1823 // if not built-in *and* pre-configured
1828 if (remove
!= NULL
) {
1829 CFStringRef bsdName
;
1831 bsdName
= SCNetworkInterfaceGetBSDName(remove
);
1832 if ((bsdName
!= NULL
) && sharingConfigurationUsesInterface(bsdName
, FALSE
)) {
1833 // if referenced in the Internet Sharing configuration, keep
1838 #endif // TARGET_OS_OSX
1841 watchedInfo
->callback(watched
, messageType
, messageArgument
);
1842 watcherRelease(watched
);
1845 if (remove
!= NULL
) {
1846 SC_log(LOG_INFO
, "Interface released unit %@ (from database)",
1847 _SCNetworkInterfaceGetIOInterfaceUnit(remove
));
1848 removeInterface(S_dblist
, remove
, NULL
);
1851 // update the DB with the [remaining] interfaces that have been named
1852 writeInterfaceList(S_dblist
);
1866 watcherCreate(SCNetworkInterfaceRef interface
, InterfaceUpdateCallBack callback
)
1869 io_service_t interface_node
;
1871 CFDictionaryRef matching
;
1872 CFMutableDataRef watched
;
1873 WatchedInfo
*watchedInfo
;
1875 // get the IORegistry node
1876 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
1877 matching
= IORegistryEntryIDMatching(entryID
);
1878 interface_node
= IOServiceGetMatchingService(kIOMasterPortDefault
, matching
);
1879 if (interface_node
== MACH_PORT_NULL
) {
1880 // interface no longer present
1884 // create [locked/trusted] interface watcher
1885 watched
= CFDataCreateMutable(NULL
, sizeof(WatchedInfo
));
1886 CFDataSetLength(watched
, sizeof(WatchedInfo
));
1887 watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1888 memset(watchedInfo
, 0, sizeof(*watchedInfo
));
1891 watchedInfo
->interface
= CFRetain(interface
);
1893 // ... and the interface node
1894 watchedInfo
->interface_node
= interface_node
;
1896 // ... and set the callback
1897 watchedInfo
->callback
= callback
;
1899 kr
= IOServiceAddInterestNotification(S_notify
, // IONotificationPortRef
1900 watchedInfo
->interface_node
, // io_service_t
1901 kIOGeneralInterest
, // interestType
1902 updateWatchedInterface
, // IOServiceInterestCallback
1903 (void *)watched
, // refCon
1904 &watchedInfo
->notification
); // notification
1905 if (kr
!= KERN_SUCCESS
) {
1907 "IOServiceAddInterestNotification() failed, kr = 0x%x",
1909 watcherRelease(watched
);
1918 watcherRelease(CFDataRef watched
)
1920 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1923 if (watchedInfo
->notification
!= IO_OBJECT_NULL
) {
1924 IOObjectRelease(watchedInfo
->notification
);
1925 watchedInfo
->notification
= IO_OBJECT_NULL
;
1928 // release interface node
1929 if (watchedInfo
->interface_node
!= IO_OBJECT_NULL
) {
1930 IOObjectRelease(watchedInfo
->interface_node
);
1931 watchedInfo
->interface_node
= IO_OBJECT_NULL
;
1934 // release interface
1935 if (watchedInfo
->interface
!= NULL
) {
1936 CFRelease(watchedInfo
->interface
);
1937 watchedInfo
->interface
= NULL
;
1944 isWatchedInterface(CFArrayRef watchedInterfaces
, SCNetworkInterfaceRef interface
)
1948 n
= (watchedInterfaces
!= NULL
) ? CFArrayGetCount(watchedInterfaces
) : 0;
1949 for (CFIndex i
= 0; i
< n
; i
++) {
1950 CFDataRef watched
= CFArrayGetValueAtIndex(watchedInterfaces
, i
);
1951 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1953 if (CFEqual((watchedInfo
->interface
), interface
)) {
1963 #pragma mark Locked device support [macOS]
1966 #if !TARGET_OS_IPHONE
1972 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
1974 CFMutableArrayRef locked
;
1976 locked
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1978 for (CFIndex i
= 0; i
< n
; i
++) {
1983 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
1984 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1986 name
= SCNetworkInterfaceGetLocalizedDisplayName(watchedInfo
->interface
);
1987 addr
= SCNetworkInterfaceGetHardwareAddressString(watchedInfo
->interface
);
1988 path
= _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
);
1989 str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@: %@: %@"),
1990 (name
!= NULL
) ? name
: CFSTR("?"),
1991 (addr
!= NULL
) ? addr
: CFSTR("?"),
1993 CFArrayAppendValue(locked
, str
);
1997 CFDictionarySetValue(S_state
, kInterfaceNamerKey_LockedInterfaces
, locked
);
2000 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_LockedInterfaces
);
2009 blockNewInterfaces()
2011 static boolean_t allow
= TRUE
;
2012 static dispatch_once_t once
;
2014 dispatch_once(&once
, ^{
2015 allow
= InterfaceNamerControlPrefsAllowNewInterfaces();
2024 CFArrayRef console_sessions
;
2025 boolean_t locked
= FALSE
;
2026 io_registry_entry_t root
;
2028 root
= IORegistryGetRootEntry(kIOMasterPortDefault
);
2029 console_sessions
= IORegistryEntryCreateCFProperty(root
,
2030 CFSTR(kIOConsoleUsersKey
),
2033 if (isA_CFArray(console_sessions
)) {
2036 n
= CFArrayGetCount(console_sessions
);
2037 for (CFIndex i
= 0; i
< n
; i
++) {
2038 CFBooleanRef isLocked
;
2039 CFBooleanRef isLoginDone
;
2040 CFBooleanRef onConsole
;
2041 CFDictionaryRef session
;
2043 session
= CFArrayGetValueAtIndex(console_sessions
, i
);
2044 if (!isA_CFDictionary(session
)) {
2045 // if not dictionary
2049 if (!CFDictionaryGetValueIfPresent(session
,
2050 CFSTR(kIOConsoleSessionOnConsoleKey
),
2051 (const void **)&onConsole
) ||
2052 !isA_CFBoolean(onConsole
) ||
2053 !CFBooleanGetValue(onConsole
)) {
2054 // if not "on console" session
2059 CFDictionaryGetValueIfPresent(session
,
2060 CFSTR(kIOConsoleSessionLoginDoneKey
),
2061 (const void **)&isLoginDone
) &&
2062 isA_CFBoolean(isLoginDone
) &&
2063 !CFBooleanGetValue(isLoginDone
)) {
2065 SC_log(LOG_INFO
, "multiple sessions, console @ loginwindow");
2070 if (CFDictionaryGetValueIfPresent(session
,
2071 CFSTR(kIOConsoleSessionScreenIsLockedKey
),
2072 (const void **)&isLocked
) &&
2073 isA_CFBoolean(isLocked
) &&
2074 CFBooleanGetValue(isLocked
)) {
2076 SC_log(LOG_INFO
, "console screen locked");
2083 SC_log(LOG_INFO
, "console not locked");
2087 if (console_sessions
!= NULL
) {
2088 CFRelease(console_sessions
);
2090 IOObjectRelease(root
);
2095 //#define ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2096 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2098 static CFUserNotificationRef userNotification
;
2099 static CFRunLoopSourceRef userRls
;
2102 lockedNotification_remove(void)
2104 if (userRls
!= NULL
) {
2105 CFRunLoopSourceInvalidate(userRls
);
2109 if (userNotification
!= NULL
) {
2112 status
= CFUserNotificationCancel(userNotification
);
2115 "CFUserNotificationCancel() failed, status=%d",
2118 CFRelease(userNotification
);
2119 userNotification
= NULL
;
2125 #define MY_ICON_PATH "/System/Library/PreferencePanes/Network.prefPane/Contents/Resources/Network.icns"
2128 lockedNotification_reply(CFUserNotificationRef userNotification
, CFOptionFlags response_flags
)
2130 #pragma unused(userNotification)
2134 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
2135 for (CFIndex i
= 0; i
< n
; i
++) {
2136 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
2137 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2139 // process user response
2140 switch (response_flags
& 0x3) {
2141 case kCFUserNotificationDefaultResponse
: {
2142 // if OK'd, [re-]process new interfaces
2144 SC_log(LOG_INFO
, "Reprocessing %ld [locked] interface%s", n
, n
== 1 ? "" : "s");
2146 if (S_iflist
== NULL
) {
2147 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2151 // add the interface to those newly discovered
2152 CFArrayAppendValue(S_iflist
, watchedInfo
->interface
);
2156 // if cancelled, ignore [remaining] new interfaces
2157 SC_log(LOG_INFO
, "[locked] interface ignored");
2158 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
2164 watcherRelease(watched
);
2167 if (S_locked
!= NULL
) {
2168 CFRelease(S_locked
);
2172 lockedNotification_remove();
2174 if (S_iflist
!= NULL
) {
2182 lockedNotification_add(void)
2185 CFMutableDictionaryRef dict
;
2187 CFMutableArrayRef message
;
2189 CFURLRef url
= NULL
;
2191 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
2193 // no locked interfaces, no notification needed
2197 dict
= CFDictionaryCreateMutable(NULL
,
2199 &kCFTypeDictionaryKeyCallBacks
,
2200 &kCFTypeDictionaryValueCallBacks
);
2202 // set localization URL
2203 bundle
= _SC_CFBundleGet();
2204 if (bundle
!= NULL
) {
2205 url
= CFBundleCopyBundleURL(bundle
);
2209 CFDictionarySetValue(dict
, kCFUserNotificationLocalizationURLKey
, url
);
2212 SC_log(LOG_ERR
, "can't find bundle");
2217 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
2218 (const UInt8
*)MY_ICON_PATH
,
2219 sizeof(MY_ICON_PATH
) - 1,
2222 CFDictionarySetValue(dict
, kCFUserNotificationIconURLKey
, url
);
2227 CFDictionarySetValue(dict
,
2228 kCFUserNotificationAlertHeaderKey
,
2229 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_HEADER")
2230 : CFSTR("LOCKED_MULTIPLE_INTERFACES_HEADER"));
2233 message
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2234 CFArrayAppendValue(message
,
2235 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_MESSAGE")
2236 : CFSTR("LOCKED_MULTIPLE_INTERFACES_MESSAGE"));
2237 for (CFIndex i
= 0; i
< n
; i
++) {
2240 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
2241 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2243 name
= SCNetworkInterfaceGetLocalizedDisplayName(watchedInfo
->interface
);
2244 str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("\n\t%@"), name
);
2245 CFArrayAppendValue(message
, str
);
2248 CFDictionarySetValue(dict
, kCFUserNotificationAlertMessageKey
, message
);
2252 CFDictionarySetValue(dict
,
2253 kCFUserNotificationDefaultButtonTitleKey
,
2254 CFSTR("LOCKED_INTERFACES_IGNORE"));
2255 CFDictionarySetValue(dict
,
2256 kCFUserNotificationAlternateButtonTitleKey
,
2257 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_ADD")
2258 : CFSTR("LOCKED_MULTIPLE_INTERFACES_ADD"));
2260 // create and post notification
2261 userNotification
= CFUserNotificationCreate(NULL
,
2263 kCFUserNotificationNoteAlertLevel
,
2266 if (userNotification
== NULL
) {
2267 SC_log(LOG_ERR
, "CFUserNotificationCreate() failed: %d", (int)error
);
2271 // establish callback
2272 userRls
= CFUserNotificationCreateRunLoopSource(NULL
,
2274 lockedNotification_reply
,
2276 if (userRls
== NULL
) {
2277 SC_log(LOG_ERR
, "CFUserNotificationCreateRunLoopSource() failed");
2278 CFRelease(userNotification
);
2279 userNotification
= NULL
;
2282 CFRunLoopAddSource(CFRunLoopGetCurrent(), userRls
, kCFRunLoopDefaultMode
);
2286 if (dict
!= NULL
) CFRelease(dict
);
2291 lockedNotification_update(void)
2293 // if present, remove current notification
2294 lockedNotification_remove();
2296 // post notification (if needed)
2297 lockedNotification_add();
2302 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2305 lockedInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2307 #pragma unused(messageArgument)
2308 Boolean updated
= FALSE
;
2309 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2311 switch (messageType
) {
2312 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2313 SC_log(LOG_INFO
, "[locked] interface removed");
2314 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
2316 if (S_locked
!= NULL
) {
2318 CFIndex n
= CFArrayGetCount(S_locked
);
2320 i
= CFArrayGetFirstIndexOfValue(S_locked
, CFRangeMake(0, n
), watched
);
2321 if (i
!= kCFNotFound
) {
2322 CFArrayRemoveValueAtIndex(S_locked
, i
);
2323 if (CFArrayGetCount(S_locked
) == 0) {
2324 CFRelease(S_locked
);
2339 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2340 // update user notification after interface removed
2341 lockedNotification_update();
2342 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2344 // post info about interfaces not added because the console is locked
2352 watchLockedInterface(SCNetworkInterfaceRef interface
)
2354 Boolean updated
= FALSE
;
2357 watched
= watcherCreate(interface
, lockedInterfaceUpdated
);
2358 if (watched
!= NULL
) {
2359 SC_log(LOG_INFO
, "watching [locked] interface");
2360 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(interface
));
2362 if (S_locked
== NULL
) {
2363 S_locked
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2365 CFArrayAppendValue(S_locked
, watched
);
2371 // post info about interfaces not added because the console is locked
2374 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2375 // post/update user notification with new interface
2376 lockedNotification_update();
2377 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2382 #endif // !TARGET_OS_IPHONE
2386 #pragma mark Trust required support [iOS]
2389 #if TARGET_OS_IPHONE
2391 #include <SoftLinking/WeakLinking.h>
2392 WEAK_LINK_FORCE_IMPORT(lockdown_is_host_trusted
);
2393 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationHostAttached
);
2394 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationHostDetached
);
2395 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationTrustedHostAttached
);
2396 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationTrustedPTPAttached
);
2401 Boolean haveLibrary
;
2403 haveLibrary
= ((lockdown_is_host_trusted
!= NULL
) &&
2404 (&kLockdownNotificationHostAttached
!= NULL
) &&
2405 (&kLockdownNotificationHostDetached
!= NULL
) &&
2406 (&kLockdownNotificationTrustedHostAttached
!= NULL
) &&
2407 (&kLockdownNotificationTrustedPTPAttached
!= NULL
)
2417 n
= (S_trustRequired
!= NULL
) ? CFArrayGetCount(S_trustRequired
) : 0;
2418 if ((n
> 0) && !S_trustedHostAttached
) {
2419 CFMutableArrayRef excluded
;
2421 // if we have interfaces that require not [yet] granted "trust".
2423 excluded
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2425 for (CFIndex i
= 0; i
< n
; i
++) {
2426 CFStringRef bsdName
;
2427 CFDataRef watched
= CFArrayGetValueAtIndex(S_trustRequired
, i
);
2428 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2430 bsdName
= SCNetworkInterfaceGetBSDName(watchedInfo
->interface
);
2431 if (bsdName
== NULL
) {
2432 SC_log(LOG_NOTICE
, "[trust required] interface w/no BSD name not excluded");
2433 SC_log(LOG_NOTICE
, " interface = %@", watchedInfo
->interface
);
2436 CFArrayAppendValue(excluded
, bsdName
);
2439 CFDictionarySetValue(S_state
, kInterfaceNamerKey_ExcludedInterfaces
, excluded
);
2440 CFRelease(excluded
);
2442 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_ExcludedInterfaces
);
2450 static dispatch_queue_t
2451 trustRequired_queue()
2453 static dispatch_once_t once
;
2454 static dispatch_queue_t q
;
2456 dispatch_once(&once
, ^{
2457 q
= dispatch_queue_create("Trust Required queue", NULL
);
2464 // runs on "Trust Required" dispatch queue
2466 trustRequiredNotification_update(CFRunLoopRef rl
, CFStringRef reason
)
2468 Boolean changed
= FALSE
;
2469 CFStringRef error
= NULL
;
2474 * determine whether the device has "trusted" the host (or other device)
2476 trusted
= lockdown_is_host_trusted(MY_PLUGIN_ID
, NULL
, &error
);
2477 n
= (S_trustRequired
!= NULL
) ? CFArrayGetCount(S_trustRequired
) : 0;
2478 if ((S_trustedHostCount
!= n
) || (S_trustedHostAttached
!= trusted
)) {
2482 SC_log(LOG_INFO
, "%@, trusted = %s%s%@, %ld interface%s)%s",
2484 trusted
? "Yes" : "No",
2485 (error
!= NULL
) ? ", error = " : "",
2486 (error
!= NULL
) ? error
: CFSTR(""),
2488 (n
== 1) ? "" : "s",
2489 changed
? " *" : "");
2492 S_trustedHostAttached
= trusted
;
2493 S_trustedHostCount
= n
;
2494 CFRunLoopPerformBlock(rl
, kCFRunLoopDefaultMode
, ^{
2497 CFRunLoopWakeUp(rl
);
2500 if (error
!= NULL
) {
2508 trustRequiredInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2510 #pragma unused(messageArgument)
2511 Boolean updated
= FALSE
;
2512 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2514 switch (messageType
) {
2515 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2516 SC_log(LOG_INFO
, "[trust required] interface removed");
2517 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
2519 if (S_trustRequired
!= NULL
) {
2521 CFIndex n
= CFArrayGetCount(S_trustRequired
);
2523 i
= CFArrayGetFirstIndexOfValue(S_trustRequired
, CFRangeMake(0, n
), watched
);
2524 if (i
!= kCFNotFound
) {
2525 CFArrayRemoveValueAtIndex(S_trustRequired
, i
);
2526 if (CFArrayGetCount(S_trustRequired
) == 0) {
2527 CFRelease(S_trustRequired
);
2528 S_trustRequired
= NULL
;
2542 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2545 dispatch_async(trustRequired_queue(), ^{
2546 trustRequiredNotification_update(rl
, CFSTR("TrustRequired interface removed"));
2555 watchTrustedStatus(CFStringRef notification
, CFStringRef reason
)
2558 int notify_token
= -1;
2560 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2562 key
= CFStringGetCStringPtr(notification
, kCFStringEncodingUTF8
);
2563 assert(key
!= NULL
);
2567 ret
= notify_register_dispatch(key
,
2569 trustRequired_queue(),
2571 #pragma unused(token)
2572 trustRequiredNotification_update(rl
, reason
);
2574 if (ret
!= NOTIFY_STATUS_OK
) {
2575 SC_log(LOG_ERR
, "notify_register_dispatch(%@) failed: %u", notification
, ret
);
2584 updateTrustRequiredInterfaces(CFArrayRef interfaces
)
2587 Boolean updated
= FALSE
;
2589 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
2590 for (CFIndex i
= 0; i
< n
; i
++) {
2591 SCNetworkInterfaceRef interface
;
2593 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2594 if (_SCNetworkInterfaceIsTrustRequired(interface
) &&
2595 !isWatchedInterface(S_trustRequired
, interface
)) {
2598 watched
= watcherCreate(interface
, trustRequiredInterfaceUpdated
);
2599 if (watched
!= NULL
) {
2600 CFStringRef bsdName
;
2602 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
2603 if (bsdName
!= NULL
) {
2604 SC_log(LOG_INFO
, "watching [trust required] interface: %@", bsdName
);
2606 SC_log(LOG_INFO
, "watching [trust required] interface w/no BSD name");
2607 SC_log(LOG_INFO
, " interface = %@", interface
);
2610 if (S_trustRequired
== NULL
) {
2611 S_trustRequired
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2613 CFArrayAppendValue(S_trustRequired
, watched
);
2621 static dispatch_once_t once
;
2622 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2624 dispatch_once(&once
, ^{
2625 // watch for "Host attached"
2626 watchTrustedStatus(kLockdownNotificationHostAttached
,
2627 CFSTR("Host attached"));
2629 // watch for "Host detached"
2630 watchTrustedStatus(kLockdownNotificationHostDetached
,
2631 CFSTR("Host detached"));
2633 // watch for "Trusted host attached"
2634 watchTrustedStatus(kLockdownNotificationTrustedHostAttached
,
2635 CFSTR("Trusted Host attached"));
2637 // watch for "Trusted PDP attached"
2638 watchTrustedStatus(kLockdownNotificationTrustedPTPAttached
,
2639 CFSTR("Trusted PTP attached"));
2643 dispatch_async(trustRequired_queue(), ^{
2644 trustRequiredNotification_update(rl
, CFSTR("TrustRequired interface added"));
2651 #endif // TARGET_OS_IPHONE
2655 #pragma mark Pre-configured interface support
2659 sharePreconfigured()
2663 n
= (S_preconfigured
!= NULL
) ? CFArrayGetCount(S_preconfigured
) : 0;
2665 CFMutableArrayRef preconfigured
;
2667 preconfigured
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2669 for (CFIndex i
= 0; i
< n
; i
++) {
2670 CFStringRef bsdName
;
2671 CFDataRef watched
= CFArrayGetValueAtIndex(S_preconfigured
, i
);
2672 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2674 bsdName
= SCNetworkInterfaceGetBSDName(watchedInfo
->interface
);
2675 if (bsdName
== NULL
) {
2676 SC_log(LOG_NOTICE
, "pre-configured interface w/no BSD name");
2677 SC_log(LOG_NOTICE
, " interface = %@", watchedInfo
->interface
);
2680 CFArrayAppendValue(preconfigured
, bsdName
);
2683 CFDictionarySetValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
, preconfigured
);
2684 CFRelease(preconfigured
);
2686 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
);
2695 preconfiguredInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2697 Boolean updated
= FALSE
;
2698 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2700 #pragma unused(messageArgument)
2701 switch (messageType
) {
2702 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2703 CFStringRef bsdName
;
2705 bsdName
= SCNetworkInterfaceGetBSDName(watchedInfo
->interface
);
2706 if (bsdName
!= NULL
) {
2707 SC_log(LOG_INFO
, "[pre-configured] interface removed: %@", bsdName
);
2709 SC_log(LOG_INFO
, "[pre-configured] interface w/no BSD name removed");
2710 SC_log(LOG_INFO
, " interface = %@", watchedInfo
->interface
);
2713 if (S_preconfigured
!= NULL
) {
2715 CFIndex n
= CFArrayGetCount(S_preconfigured
);
2717 i
= CFArrayGetFirstIndexOfValue(S_preconfigured
, CFRangeMake(0, n
), watched
);
2718 if (i
!= kCFNotFound
) {
2719 CFArrayRemoveValueAtIndex(S_preconfigured
, i
);
2720 if (CFArrayGetCount(S_preconfigured
) == 0) {
2721 CFRelease(S_preconfigured
);
2722 S_preconfigured
= NULL
;
2736 sharePreconfigured();
2743 updatePreConfiguredInterfaces(CFArrayRef interfaces
)
2746 Boolean updated
= FALSE
;
2748 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
2749 for (CFIndex i
= 0; i
< n
; i
++) {
2750 SCNetworkInterfaceRef interface
;
2752 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2753 if (_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
2754 !isWatchedInterface(S_preconfigured
, interface
)) {
2757 watched
= watcherCreate(interface
, preconfiguredInterfaceUpdated
);
2758 if (watched
!= NULL
) {
2759 CFStringRef bsdName
;
2761 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
2762 if (bsdName
!= NULL
) {
2763 SC_log(LOG_INFO
, "watching [pre-configured] interface: %@", bsdName
);
2765 SC_log(LOG_INFO
, "watching [pre-configured] interface w/no BSD name");
2766 SC_log(LOG_INFO
, " interface = %@", interface
);
2769 if (S_preconfigured
== NULL
) {
2770 S_preconfigured
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2772 CFArrayAppendValue(S_preconfigured
, watched
);
2780 sharePreconfigured();
2788 #pragma mark Interface naming
2791 static __inline__ boolean_t
2794 return (S_quiet
== MACH_PORT_NULL
);
2798 wasPreviouslyUsedInterface(CFDictionaryRef dbdict
, SCNetworkInterfaceRef interface
)
2800 CFArrayRef matchingMACs
;
2802 matchingMACs
= CFDictionaryGetValue(dbdict
, CFSTR(kSCNetworkInterfaceMatchingMACs
));
2803 if (matchingMACs
!= NULL
) {
2806 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
2808 if (CFArrayContainsValue(matchingMACs
,
2809 CFRangeMake(0, CFArrayGetCount(matchingMACs
)),
2820 nameInterfaces(CFMutableArrayRef if_list
)
2823 CFIndex n
= CFArrayGetCount(if_list
);
2825 for (i
= 0; i
< n
; i
++) {
2827 SCNetworkInterfaceRef interface
;
2828 SCNetworkInterfaceRef new_interface
;
2834 interface
= CFArrayGetValueAtIndex(if_list
, i
);
2835 path
= _SCNetworkInterfaceGetIOPath(interface
);
2836 prefix
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
2837 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
2838 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
2841 CFStringRef if_name
;
2843 if_name
= SCNetworkInterfaceGetBSDName(interface
);
2844 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
2845 SC_log(LOG_INFO
, "Interface already has a unit number");
2846 displayInterface(interface
);
2849 // update the list of interfaces that were previously named
2850 if ((S_prev_active_list
!= NULL
)
2851 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
2852 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
2855 replaceInterface(interface
);
2857 CFDictionaryRef dbdict
;
2858 boolean_t is_builtin
;
2862 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
2863 if (dbdict
!= NULL
) {
2864 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2867 SC_log(LOG_INFO
, "Interface assigned unit %@ (from database)", unit
);
2870 if ((dbdict
== NULL
) && !isQuiet()) {
2871 // if new interface, wait until quiet before naming
2872 addTimestamp(S_state
, path
);
2876 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
2878 if (dbdict
== NULL
) {
2879 dbdict
= lookupMatchingInterface(interface
,
2883 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
2885 if ((dbdict
!= NULL
) && wasPreviouslyUsedInterface(dbdict
, interface
)) {
2886 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2889 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database w/previously used interface)", unit
);
2892 #if !TARGET_OS_IPHONE
2893 if ((unit
== NULL
) &&
2896 blockNewInterfaces() &&
2897 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
2898 isConsoleLocked()) {
2901 // if new (but matching) interface and console locked, ignore
2902 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
2903 SC_log(LOG_NOTICE
, "Console locked, network interface* ignored");
2904 SC_log(LOG_INFO
, " path = %@, addr = %@",
2906 (addr
!= NULL
) ? addr
: CFSTR("?"));
2907 watchLockedInterface(interface
);
2910 #endif // !TARGET_OS_IPHONE
2912 if ((unit
== NULL
) && (dbdict
!= NULL
)) {
2913 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2916 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database w/new interface)", unit
);
2920 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
2921 // update the list of interfaces that were previously named
2922 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
2923 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
2925 if (where
!= kCFNotFound
) {
2926 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
2930 if (dbdict
== NULL
) {
2934 // built-in interface, try to use the reserved slots
2935 next_unit
= builtinCount(if_list
, i
, prefix
);
2937 // But, before claiming a reserved slot we check to see if the
2938 // slot had previously been used. If so, and if the slot had been
2939 // assigned to the same type of interface, then we will perform a
2940 // replacement (e.g. assume that this was a board swap). But, if
2941 // the new interface is a different type then we assume that the
2942 // built-in configuration has changed and allocate a new unit from
2943 // the non-reserved slots.
2945 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
2946 if (!builtinAvailable(interface
, unit
)) {
2947 // if [built-in] unit not available
2948 SC_log(LOG_INFO
, "Interface not assigned [built-in] unit %@", unit
);
2954 #if !TARGET_OS_IPHONE
2957 blockNewInterfaces() &&
2958 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
2959 isConsoleLocked()) {
2962 // if new interface and console locked, ignore
2963 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
2964 SC_log(LOG_NOTICE
, "Console locked, network interface ignored");
2965 SC_log(LOG_INFO
, " path = %@, addr = %@",
2967 (addr
!= NULL
) ? addr
: CFSTR("?"));
2968 watchLockedInterface(interface
);
2971 #endif // !TARGET_OS_IPHONE
2974 // not built-in (or built-in unit not available), allocate from
2975 // the non-reserved slots
2976 next_unit
= builtinCount(if_list
, n
, prefix
);
2977 next_unit
= getNextUnitForPrefix(prefix
, next_unit
);
2978 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
2981 SC_log(LOG_INFO
, "Interface assigned unit %@ (%s)",
2983 is_builtin
? "built-in" : "next available");
2988 #ifdef USE_REGISTRY_ENTRY_ID
2989 kr
= registerInterfaceWithIORegistryEntryID(S_connect
,
2992 (dbdict
== NULL
) ? kIONetworkStackRegisterInterfaceWithLowestUnit
2993 : kIONetworkStackRegisterInterfaceWithUnit
);
2994 new_interface
= copyNamedInterfaceForIORegistryEntryID(entryID
);
2995 #else // USE_REGISTRY_ENTRY_ID
2996 kr
= registerInterfaceWithIOServicePath(S_connect
,
2999 (dbdict
== NULL
) ? kRegisterInterface
3000 : kRegisterInterfaceWithFixedUnit
);
3001 new_interface
= copyNamedInterfaceForIOKitPath(path
);
3002 #endif // USE_REGISTRY_ENTRY_ID
3003 if (new_interface
== NULL
) {
3004 const char *signature
;
3006 signature
= (dbdict
== NULL
) ? "failed to name new interface"
3007 : "failed to name known interface";
3009 SC_log(LOG_NOTICE
, "%s, kr=0x%x\n"
3019 displayInterface(interface
);
3021 if ((dbdict
!= NULL
) && (retries
++ < 5)) {
3022 usleep(50 * 1000); // sleep 50ms between attempts
3027 CFNumberRef new_unit
;
3030 SC_log(LOG_INFO
, "%s interface named after %d %s\n"
3033 (dbdict
== NULL
) ? "New" : "Known",
3035 (retries
== 1) ? "try" : "tries",
3039 #ifdef SHOW_NAMING_FAILURE
3040 str
= CFStringCreateWithFormat(NULL
,
3042 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
3043 (dbdict
== NULL
) ? "New" : "Known",
3045 (retries
== 1) ? "try" : "tries",
3047 CFUserNotificationDisplayNotice(0,
3048 kCFUserNotificationStopAlertLevel
,
3053 CFSTR("Please report repeated failures."),
3056 #endif // SHOW_NAMING_FAILURE
3059 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
3060 if (!CFEqual(unit
, new_unit
)) {
3061 SC_log(LOG_INFO
, "interface prefix %@ assigned unit %@ instead of %@",
3062 prefix
, new_unit
, unit
);
3065 displayInterface(new_interface
);
3067 // update if_list (with the interface name & unit)
3068 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
3069 CFRelease(new_interface
);
3070 interface
= new_interface
; // if_list holds the reference
3072 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
3075 // update the list of [built-in] interfaces that were previously named
3076 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
3077 SC_log(LOG_DEBUG
, " and updated database (new address)");
3078 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
3081 replaceInterface(interface
);
3089 #if !TARGET_OS_IPHONE
3091 #define INSTALL_ENVIRONMENT "__OSINSTALL_ENVIRONMENT"
3096 static Boolean isRecovery
= FALSE
;
3097 static dispatch_once_t once
;
3100 * We check to see if the __OSINSTALL_ENVIRONMENT env var is present. If
3101 * so, then we are most likely booted into the Recovery OS with no [Aqua]
3102 * "SCMonitor" [UserEventAgent] plugin.
3104 dispatch_once(&once
, ^{
3105 if (getenv(INSTALL_ENVIRONMENT
) != NULL
) {
3115 updateNetworkConfiguration(CFArrayRef if_list
)
3117 Boolean do_commit
= FALSE
;
3120 SCPreferencesRef prefs
= NULL
;
3121 SCNetworkSetRef set
= NULL
;
3123 prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":updateNetworkConfiguration"), NULL
);
3124 if (prefs
== NULL
) {
3125 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
3129 set
= SCNetworkSetCopyCurrent(prefs
);
3131 SC_log(LOG_INFO
, "No current set, adding default");
3132 set
= _SCNetworkSetCreateDefault(prefs
);
3134 SC_log(LOG_NOTICE
, "_SCNetworkSetCreateDefault() failed: %s", SCErrorString(SCError()));
3139 n
= (if_list
!= NULL
) ? CFArrayGetCount(if_list
) : 0;
3140 for (i
= 0; i
< n
; i
++) {
3141 SCNetworkInterfaceRef interface
;
3143 interface
= CFArrayGetValueAtIndex(if_list
, i
);
3144 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set
, interface
)) {
3145 SC_log(LOG_INFO
, "adding default configuration for %@",
3146 SCNetworkInterfaceGetBSDName(interface
));
3154 ok
= SCPreferencesCommitChanges(prefs
);
3156 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
3160 ok
= SCPreferencesApplyChanges(prefs
);
3162 SC_log(LOG_NOTICE
, "SCPreferencesApplyChanges() failed: %s", SCErrorString(SCError()));
3174 if (prefs
!= NULL
) {
3181 #endif // !TARGET_OS_IPHONE
3184 upgradeNetworkConfiguration()
3186 static dispatch_once_t once
;
3189 * Once, per start of InterfaceNamer, we check/ensure that the
3190 * configuration has been upgraded.
3192 * Note: this check should not be performed until we know that
3193 * the __wait_for_IOKit_to_quiesce() conditions have been
3197 dispatch_once(&once
, ^{
3198 SCPreferencesRef ni_prefs
;
3201 // save the [current] DB with the interfaces that have been named
3202 writeInterfaceList(S_dblist
);
3204 // upgrade the configuration
3205 ni_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":upgradeNetworkConfiguration"), INTERFACES_DEFAULT_CONFIG
);
3206 if (ni_prefs
== NULL
) {
3207 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
3210 updated
= __SCNetworkConfigurationUpgrade(NULL
, &ni_prefs
, TRUE
);
3211 CFRelease(ni_prefs
);
3214 // re-read list of previously named network interfaces
3215 if (S_dblist
!= NULL
) {
3216 CFRelease(S_dblist
);
3218 S_dblist
= readInterfaceList();
3220 addTimestamp(S_state
, CFSTR("*UPGRADED*"));
3221 SC_log(LOG_INFO
, "network configuration upgraded");
3230 removeInactiveInterfaces(void)
3235 * remove any previous interfaces that were built-in,
3236 * were active, and were hidden (pre-configured) that
3237 * are no longer plugged in.
3240 if ((S_dblist
== NULL
) || (S_prev_active_list
== NULL
)) {
3244 n
= CFArrayGetCount(S_prev_active_list
);
3245 for (CFIndex i
= n
- 1; i
>= 0; i
--) {
3246 CFBooleanRef builtin
;
3247 CFBooleanRef hidden
;
3248 CFDictionaryRef if_dict
;
3249 CFDictionaryRef info
;
3253 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
3255 // Note: keep the following logic in sync with _SCNetworkInterfaceIsApplePreconfigured()
3257 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
3258 if (!isA_CFString(name
)) {
3263 hidden
= CFDictionaryGetValue(if_dict
, kSCNetworkInterfaceHiddenConfigurationKey
);
3264 if (!isA_CFBoolean(hidden
) || !CFBooleanGetValue(hidden
)) {
3269 builtin
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBuiltin
));
3270 if (isA_CFBoolean(builtin
) && CFBooleanGetValue(builtin
)) {
3271 // if [hidden] builtin
3275 info
= CFDictionaryGetValue(if_dict
, CFSTR(kSCNetworkInterfaceInfo
));
3276 if (isA_CFDictionary(info
)) {
3280 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&vidNum
) &&
3281 isA_CFNumber(vidNum
) &&
3282 CFNumberGetValue(vidNum
, kCFNumberIntType
, &vid
) &&
3283 (vid
== kIOUSBAppleVendorID
)) {
3284 // if [hidden] Apple interface
3287 if (sharingConfigurationUsesInterface(name
, TRUE
)) {
3288 // do not remove interfaces referenced in the sharing configuration
3291 #endif // TARGET_OS_OSX
3301 SC_log(LOG_INFO
, "Removing no-longer-active \"hidden\" interface: %@", name
);
3303 if (lookupInterfaceByName(S_dblist
, name
, &where
) != NULL
) {
3304 // remove from the list of interfaces we know about
3305 CFArrayRemoveValueAtIndex(S_dblist
, where
);
3306 // remove from the previously active list
3307 CFArrayRemoveValueAtIndex(S_prev_active_list
, i
);
3312 sharingConfigurationClose();
3313 #endif // TARGET_OS_OSX
3319 reportInactiveInterfaces(void)
3324 * report any previous interfaces that are not [yet] active
3327 if (S_prev_active_list
== NULL
) {
3331 n
= CFArrayGetCount(S_prev_active_list
);
3333 SC_log(LOG_INFO
, "Interface%s not [yet] active",
3334 (n
> 1) ? "s" : "");
3336 for (CFIndex i
= 0; i
< n
; i
++) {
3337 CFDictionaryRef if_dict
;
3342 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
3343 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
3344 prefix
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceNamePrefix
));
3345 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
3346 SC_log(LOG_INFO
, " %s%@%sPrefix: %@, Unit: %@",
3347 (name
!= NULL
) ? "BSD Name: " : "",
3348 (name
!= NULL
) ? name
: CFSTR(""),
3349 (name
!= NULL
) ? ", " : "",
3358 updateInterfaces(void)
3360 if (S_connect
== MACH_PORT_NULL
) {
3361 // if we don't have the "IONetworkStack" connect object
3365 if (S_iflist
!= NULL
) {
3368 n
= CFArrayGetCount(S_iflist
);
3370 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
3372 nameInterfaces(S_iflist
);
3376 * Update the list of [Apple] pre-configured interfaces
3378 updatePreConfiguredInterfaces(S_iflist
);
3380 #if TARGET_OS_IPHONE
3382 * Update the list of "trust required" interfaces
3384 if (haveLockdown()) {
3385 updateTrustRequiredInterfaces(S_iflist
);
3387 #endif // TARGET_OS_IPHONE
3391 * The registry [matching] has quiesced
3394 // remove any inactive interfaces
3395 removeInactiveInterfaces();
3397 // save the DB with the interfaces that have been named
3398 writeInterfaceList(S_dblist
);
3400 // update the VLAN/BOND configuration
3401 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
3403 #if !TARGET_OS_IPHONE
3404 if (isRecoveryOS()) {
3406 * We are most likely booted into the Recovery OS with no "SCMonitor"
3407 * UserEventAgent plugin running so let's make sure we update the
3408 * network configuration for new interfaces.
3410 updateNetworkConfiguration(S_iflist
);
3412 #endif // !TARGET_OS_IPHONE
3414 // tell everyone that we've finished (at least for now)
3417 // log those interfaces which are no longer present in
3418 // the HW config (or have yet to show up).
3419 reportInactiveInterfaces();
3421 if (S_prev_active_list
!= NULL
) {
3422 CFRelease(S_prev_active_list
);
3423 S_prev_active_list
= NULL
;
3426 if (S_iflist
!= NULL
) {
3427 CFRelease(S_iflist
);
3431 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
3433 * if we've named all of the interfaces that
3434 * were used during the previous boot.
3436 addTimestamp(S_state
, kInterfaceNamerKey_Complete
);
3437 SC_log(LOG_INFO
, "last boot interfaces have been named");
3439 CFRelease(S_prev_active_list
);
3440 S_prev_active_list
= NULL
;
3448 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
3450 #pragma unused(refcon)
3453 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
3454 SCNetworkInterfaceRef interface
;
3456 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
3457 if (interface
!= NULL
) {
3458 if (S_iflist
== NULL
) {
3459 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3461 CFArrayAppendValue(S_iflist
, interface
);
3462 CFRelease(interface
);
3464 IOObjectRelease(obj
);
3473 * Function: stackCallback
3475 * Get a reference to the single IONetworkStack object instance in
3476 * the kernel. Naming requests must be sent to this object, which is
3477 * attached as a client to all network interface objects in the system.
3479 * Call IOObjectRelease on the returned object.
3482 stackCallback(void *refcon
, io_iterator_t iter
)
3484 #pragma unused(refcon)
3488 stack
= IOIteratorNext(iter
);
3489 if (stack
== MACH_PORT_NULL
) {
3493 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
3494 if (kr
!= KERN_SUCCESS
) {
3495 SC_log(LOG_ERR
, "IOServiceOpen returned 0x%x", kr
);
3499 addTimestamp(S_state
, CFSTR("*STACK*"));
3500 SC_log(LOG_INFO
, "IONetworkStack found");
3502 if (S_stack
!= MACH_PORT_NULL
) {
3503 IOObjectRelease(S_stack
);
3504 S_stack
= MACH_PORT_NULL
;
3507 if ((S_timer
!= NULL
) && CFRunLoopTimerIsValid(S_timer
)) {
3508 // With the IONetworkStack object now available we can
3509 // reset (shorten?) the time we are willing to wait for
3510 // IOKit to quiesce.
3511 CFRunLoopTimerSetNextFireDate(S_timer
,
3512 CFAbsoluteTimeGetCurrent() + S_quiet_timeout
);
3519 if (stack
!= MACH_PORT_NULL
) {
3520 IOObjectRelease(stack
);
3527 quietCallback(void *refcon
,
3528 io_service_t service
,
3529 natural_t messageType
,
3530 void *messageArgument
)
3532 #pragma unused(refcon)
3533 #pragma unused(service)
3534 if (messageArgument
!= NULL
) {
3539 if (messageType
== kIOMessageServiceBusyStateChange
) {
3540 addTimestamp(S_state
, kInterfaceNamerKey_Quiet
);
3541 SC_log(LOG_INFO
, "IOKit quiet");
3544 if (S_connect
== MACH_PORT_NULL
) {
3545 SC_log(LOG_ERR
, "No network stack object");
3549 if (S_quiet
!= MACH_PORT_NULL
) {
3550 IOObjectRelease(S_quiet
);
3551 S_quiet
= MACH_PORT_NULL
;
3554 if (S_timer
!= NULL
) {
3555 CFRunLoopTimerInvalidate(S_timer
);
3560 // grab (and name) any additional interfaces.
3561 interfaceArrivalCallback((void *)S_notify
, S_iter
);
3563 if (messageType
== kIOMessageServiceBusyStateChange
) {
3564 addTimestamp(S_state
, CFSTR("*QUIET&NAMED*"));
3566 upgradeNetworkConfiguration();
3573 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, int *count
)
3575 kern_return_t kr
= kIOReturnSuccess
;;
3578 while ((kr
== kIOReturnSuccess
) &&
3579 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
3580 uint64_t accumulated_busy_time
;
3581 uint32_t busy_state
;
3584 CFMutableArrayRef newNodes
;
3586 CFMutableStringRef str
= NULL
;
3588 if (nodes
== NULL
) {
3589 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3591 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
3593 assert(newNodes
!= NULL
);
3595 kr
= IORegistryEntryGetName(obj
, name
);
3596 if (kr
!= kIOReturnSuccess
) {
3597 SC_log(LOG_NOTICE
, "IORegistryEntryGetName() returned 0x%x", kr
);
3601 str
= CFStringCreateMutable(NULL
, 0);
3602 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
3604 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
3606 case kIOReturnSuccess
:
3607 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
3608 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
3610 case kIOReturnNotFound
:
3613 SC_log(LOG_NOTICE
, "IORegistryEntryGetLocationInPlane() returned 0x%x", kr
);
3618 CFArrayAppendValue(newNodes
, str
);
3621 kr
= IOServiceGetBusyStateAndTime(obj
, &state
, &busy_state
, &accumulated_busy_time
);
3622 if (kr
!= kIOReturnSuccess
) {
3623 SC_log(LOG_NOTICE
, "IOServiceGetBusyStateAndTime() returned 0x%x", kr
);
3627 #ifdef TEST_SNAPSHOT
3630 #endif // TEST_SNAPSHOT
3632 if (busy_state
!= 0) {
3635 if ((*count
)++ == 0) {
3636 SC_log(LOG_ERR
, "Busy services :");
3639 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
3640 SC_log(LOG_ERR
, " %@ [%s%s%s%d, %lld ms]",
3642 (state
& kIOServiceRegisteredState
) ? "" : "!registered, ",
3643 (state
& kIOServiceMatchedState
) ? "" : "!matched, ",
3644 (state
& kIOServiceInactiveState
) ? "inactive, " : "",
3646 accumulated_busy_time
/ kMillisecondScale
);
3650 kr
= IORegistryIteratorEnterEntry(iterator
);
3651 if (kr
!= kIOReturnSuccess
) {
3652 SC_log(LOG_NOTICE
, "IORegistryIteratorEnterEntry() returned 0x%x", kr
);
3656 iterateRegistryBusy(iterator
, newNodes
, count
);
3658 kr
= IORegistryIteratorExitEntry(iterator
);
3659 if (kr
!= kIOReturnSuccess
) {
3660 SC_log(LOG_NOTICE
, "IORegistryIteratorExitEntry() returned 0x%x", kr
);
3665 CFRelease(newNodes
);
3666 IOObjectRelease(obj
);
3676 io_iterator_t iterator
= MACH_PORT_NULL
;
3679 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
3683 if (kr
!= kIOReturnSuccess
) {
3684 SC_log(LOG_NOTICE
, "IORegistryCreateIterator() returned 0x%x", kr
);
3688 iterateRegistryBusy(iterator
, NULL
, &count
);
3690 SC_log(LOG_ERR
, "w/no busy services");
3693 IOObjectRelease(iterator
);
3697 timerCallback(CFRunLoopTimerRef timer
, void *info
)
3699 #pragma unused(timer)
3700 #pragma unused(info)
3701 // We've been waiting for IOKit to quiesce and it just
3702 // hasn't happenned. Time to just move on!
3703 addTimestamp(S_state
, kInterfaceNamerKey_Timeout
);
3706 SC_log(LOG_ERR
, "timed out waiting for IOKit to quiesce");
3709 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
3711 addTimestamp(S_state
, CFSTR("*TIMEOUT&NAMED*"));
3713 upgradeNetworkConfiguration();
3719 setup_IOKit(CFBundleRef bundle
)
3721 #pragma unused(bundle)
3724 mach_port_t masterPort
= MACH_PORT_NULL
;
3726 io_object_t root
= MACH_PORT_NULL
;
3728 // read DB of previously named network interfaces
3729 S_dblist
= readInterfaceList();
3731 // get interfaces that were named during the last boot
3732 S_prev_active_list
= previouslyActiveInterfaces();
3734 // track how long we've waited to see each interface.
3735 S_state
= CFDictionaryCreateMutable(NULL
,
3737 &kCFTypeDictionaryKeyCallBacks
,
3738 &kCFTypeDictionaryValueCallBacks
);
3739 addTimestamp(S_state
, CFSTR("*START*"));
3741 // Creates and returns a notification object for receiving IOKit
3742 // notifications of new devices or state changes.
3743 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
3744 if (kr
!= KERN_SUCCESS
) {
3745 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
3749 S_notify
= IONotificationPortCreate(masterPort
);
3750 if (S_notify
== NULL
) {
3751 SC_log(LOG_ERR
, "IONotificationPortCreate failed");
3755 // watch IOKit matching activity
3756 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
3757 if (root
== MACH_PORT_NULL
) {
3758 SC_log(LOG_ERR
, "IORegistryEntryFromPath failed");
3762 kr
= IOServiceAddInterestNotification(S_notify
,
3766 (void *)S_notify
, // refCon
3767 &S_quiet
); // notification
3768 if (kr
!= KERN_SUCCESS
) {
3769 SC_log(LOG_ERR
, "IOServiceAddInterestNotification returned 0x%x", kr
);
3773 kr
= IOServiceGetBusyState(root
, &busy
);
3774 if (kr
!= KERN_SUCCESS
) {
3775 SC_log(LOG_ERR
, "IOServiceGetBusyState returned 0x%x", kr
);
3779 // add a timer so we don't wait forever for IOKit to quiesce
3780 S_timer
= CFRunLoopTimerCreate(NULL
,
3781 CFAbsoluteTimeGetCurrent() + S_stack_timeout
,
3787 if (S_timer
== NULL
) {
3788 SC_log(LOG_ERR
, "CFRunLoopTimerCreate failed");
3792 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
3794 // watch for the introduction of the IONetworkStack
3795 kr
= IOServiceAddMatchingNotification(S_notify
,
3796 kIOFirstMatchNotification
,
3797 IOServiceMatching("IONetworkStack"),
3799 (void *)S_notify
, // refCon
3800 &S_stack
); // notification
3801 if (kr
!= KERN_SUCCESS
) {
3802 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
3806 // check and see if the stack is already available and arm the
3807 // notification for its introduction.
3808 stackCallback((void *)S_notify
, S_stack
);
3810 // watch for the introduction of new network interfaces
3811 kr
= IOServiceAddMatchingNotification(S_notify
,
3812 kIOFirstMatchNotification
,
3813 IOServiceMatching("IONetworkInterface"),
3814 &interfaceArrivalCallback
,
3815 (void *)S_notify
, // refCon
3816 &S_iter
); // notification
3817 if (kr
!= KERN_SUCCESS
) {
3818 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
3822 // Get the current list of matches and arm the notification for
3823 // future interface arrivals.
3824 interfaceArrivalCallback((void *)S_notify
, S_iter
);
3826 // Check if IOKit has already quiesced.
3827 quietCallback((void *)S_notify
,
3829 kIOMessageServiceBusyStateChange
,
3830 (void *)(uintptr_t)busy
);
3832 CFRunLoopAddSource(CFRunLoopGetCurrent(),
3833 IONotificationPortGetRunLoopSource(S_notify
),
3834 kCFRunLoopDefaultMode
);
3836 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
3838 * Start the wheels turning until we've named all of
3839 * the interfaces that were used during the previous
3840 * boot, until IOKit [matching] has quiesced, or
3841 * until we've waited long enough.
3843 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
3844 CFRunLoopAddSource(CFRunLoopGetCurrent(),
3845 IONotificationPortGetRunLoopSource(S_notify
),
3847 while (S_prev_active_list
!= NULL
) {
3850 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
3852 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
3855 if (S_dblist
!= NULL
) {
3856 // apply special handling for the BT-PAN interface (if present)
3857 CFArrayApplyFunction(S_dblist
,
3858 CFRangeMake(0, CFArrayGetCount(S_dblist
)),
3859 updateBTPANInformation
,
3862 #endif // TARGET_OS_OSX
3867 if (root
!= MACH_PORT_NULL
) {
3868 IOObjectRelease(root
);
3870 if (masterPort
!= MACH_PORT_NULL
) {
3871 mach_port_deallocate(mach_task_self(), masterPort
);
3878 setup_Virtual(CFBundleRef bundle
)
3880 #pragma unused(bundle)
3881 // open a SCPreferences session
3882 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":setup_Virtual"), NULL
);
3883 if (S_prefs
== NULL
) {
3884 SC_log(LOG_ERR
, "SCPreferencesCreate() failed: %s",
3885 SCErrorString(SCError()));
3889 // register for change notifications.
3890 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
3891 SC_log(LOG_ERR
, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
3897 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
3898 if (SCError() != kSCStatusNoStoreServer
) {
3899 SC_log(LOG_ERR
, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
3909 exec_InterfaceNamer(void *arg
)
3911 CFBundleRef bundle
= (CFBundleRef
)arg
;
3912 CFDictionaryRef dict
;
3914 pthread_setname_np(MY_PLUGIN_NAME
" thread");
3916 dict
= CFBundleGetInfoDictionary(bundle
);
3917 if (isA_CFDictionary(dict
)) {
3920 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_STACK_TIMEOUT_KEY
));
3922 if (!isA_CFNumber(num
) ||
3923 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_stack_timeout
) ||
3924 (S_stack_timeout
<= 0.0)) {
3925 SC_log(LOG_NOTICE
, WAIT_STACK_TIMEOUT_KEY
" value error");
3926 S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
3930 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
3932 if (!isA_CFNumber(num
) ||
3933 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_quiet_timeout
) ||
3934 (S_quiet_timeout
<= 0.0)) {
3935 SC_log(LOG_NOTICE
, WAIT_QUIET_TIMEOUT_KEY
" value error");
3936 S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
3941 // setup virtual network interface monitoring
3942 if (!setup_Virtual(bundle
)) {
3946 // setup [IOKit] network interface monitoring
3947 if (!setup_IOKit(bundle
)) {
3954 if (S_connect
!= MACH_PORT_NULL
) {
3955 IOServiceClose(S_connect
);
3956 S_connect
= MACH_PORT_NULL
;
3958 if (S_dblist
!= NULL
) {
3959 CFRelease(S_dblist
);
3962 if (S_iter
!= MACH_PORT_NULL
) {
3963 IOObjectRelease(S_iter
);
3964 S_iter
= MACH_PORT_NULL
;
3966 if (S_notify
!= MACH_PORT_NULL
) {
3967 IONotificationPortDestroy(S_notify
);
3969 if (S_quiet
!= MACH_PORT_NULL
) {
3970 IOObjectRelease(S_quiet
);
3971 S_quiet
= MACH_PORT_NULL
;
3973 if (S_stack
!= MACH_PORT_NULL
) {
3974 IOObjectRelease(S_stack
);
3975 S_stack
= MACH_PORT_NULL
;
3977 if (S_state
!= NULL
) {
3981 if (S_timer
!= NULL
) {
3982 CFRunLoopTimerInvalidate(S_timer
);
3996 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
3998 #pragma unused(bundleVerbose)
3999 pthread_attr_t tattr
;
4002 CFRetain(bundle
); // released in exec_InterfaceNamer
4004 pthread_attr_init(&tattr
);
4005 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
4006 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
4007 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
4008 pthread_create(&tid
, &tattr
, exec_InterfaceNamer
, bundle
);
4009 pthread_attr_destroy(&tattr
);
4014 //------------------------------------------------------------------------
4016 #ifdef TEST_INTERFACE_ASSIGNMENT
4018 main(int argc
, char ** argv
)
4020 #pragma unused(argv)
4022 CFMutableArrayRef interfaces
;
4023 CFArrayRef interfaces_all
;
4026 _sc_log
= kSCLogDestinationFile
;
4027 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
4029 bundle
= CFBundleGetMainBundle();
4030 CFRetain(bundle
); // released in exec_InterfaceNamer
4033 setup_IOKit(bundle
);
4035 // but, when running this test we know that the IORegistry has already quiesced
4036 IOObjectRelease(S_quiet
);
4037 S_quiet
= MACH_PORT_NULL
;
4039 // collect the interfaces
4040 interfaces
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
4041 interfaces_all
= SCNetworkInterfaceCopyAll();
4042 n
= CFArrayGetCount(interfaces_all
);
4043 for (CFIndex i
= 0; i
< n
; i
++) {
4044 SCNetworkInterfaceRef interface
= CFArrayGetValueAtIndex(interfaces_all
, i
);
4045 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)interface
;
4047 if (interfacePrivate
->prefix
== NULL
) {
4048 // skip interfaces with no kIOInterfaceNamePrefix property
4052 if (interfacePrivate
->unit
!= NULL
) {
4053 // remove any already assigned unit #
4054 CFRelease(interfacePrivate
->unit
);
4055 interfacePrivate
->unit
= NULL
;
4058 CFArrayAppendValue(interfaces
, interface
);
4060 CFRelease(interfaces_all
);
4061 SC_log(LOG_INFO
, "interfaces = %@", interfaces
);
4063 // exercise the interface naming assignments
4064 nameInterfaces(interfaces
);
4065 CFRelease(interfaces
);
4072 #ifdef TEST_SNAPSHOT
4074 main(int argc
, char ** argv
)
4076 _sc_log
= kSCLogDestinationFile
;
4077 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
4084 #endif /* TEST_SNAPSHOT */