2 * Copyright (c) 2001-2019 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * May 20, 2006 Joe Liu <joe.liu@apple.com>
28 * Allan Nathanson <ajn@apple.com>
29 * - register interface by entryID (and not path)
31 * November 6, 2006 Allan Nathanson <ajn@apple.com>
32 * Dan Markarian <markarian@apple.com>
33 * Dieter Siegmund <dieter@apple.com>
34 * - updated code to name interfaces quicker (without need for
35 * calling IOKitWaitQuiet).
37 * October 3, 2003 Allan Nathanson <ajn@apple.com>
38 * - sort new interfaces by IOKit path (rather than MAC address) to
39 * help facilitate a more predictable interface-->name mapping for
40 * like hardware configurations.
42 * June 23, 2001 Allan Nathanson <ajn@apple.com>
43 * - update to public SystemConfiguration.framework APIs
45 * January 23, 2001 Dieter Siegmund <dieter@apple.com>
51 * - module that receives IOKit Network Interface messages
52 * and names any interface that currently does not have a name
53 * - uses Interface Type and MACAddress as the unique identifying
54 * keys; any interface that doesn't contain both of these properties
55 * is ignored and not processed
56 * - stores the Interface Type, MACAddress, and Unit in permanent storage
57 * to give persistent interface names
60 #include <TargetConditionals.h>
69 #endif // TARGET_OS_IPHONE
70 #include <sys/ioctl.h>
72 #include <sys/sysctl.h>
73 #include <sys/param.h>
74 #include <mach/mach.h>
75 #include <net/ethernet.h>
76 #include <net/if_types.h>
79 #include <CommonCrypto/CommonDigest.h>
81 #include <CoreFoundation/CoreFoundation.h>
83 #include <SystemConfiguration/SystemConfiguration.h>
84 #include <SystemConfiguration/SCDPlugin.h>
85 #include <SystemConfiguration/SCPrivate.h>
86 #include <SystemConfiguration/SCValidation.h>
87 #include "SCNetworkConfigurationInternal.h"
88 #include "plugin_shared.h"
90 #include "InterfaceNamerControlPrefs.h"
91 #endif // !TARGET_OS_IPHONE
93 #include <IOKit/IOKitLib.h>
94 #include <IOKit/IOKitLibPrivate.h>
95 #include <IOKit/IOKitKeysPrivate.h>
96 #include <IOKit/IOBSD.h>
97 #include <IOKit/IOMessage.h>
98 #include <IOKit/network/IONetworkController.h>
99 #include <IOKit/network/IONetworkInterface.h>
100 #include <IOKit/network/IONetworkStack.h>
101 #include <IOKit/usb/USB.h>
103 #ifdef kIONetworkStackUserCommandKey
104 #define USE_REGISTRY_ENTRY_ID
107 #ifndef USE_REGISTRY_ENTRY_ID
108 // from <IOKit/network/IONetworkStack.h>
109 #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand"
111 kRegisterInterfaceWithFixedUnit
= 0,
113 kRegisterAllInterfaces
115 #endif // !USE_REGISTRY_ENTRY_ID
117 #define kSCNetworkInterfaceActive "Active"
118 #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo"
119 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
120 #define kSCNetworkInterfaceMatchingMACs "MatchingMACs"
122 #define MY_PLUGIN_NAME "InterfaceNamer"
123 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
125 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
126 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
128 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
129 #define WAIT_QUIET_TIMEOUT_DEFAULT 240.0
133 * "IONetworkStack" connect object used to "name" an interface.
135 static io_connect_t S_connect
= MACH_PORT_NULL
;
139 * An array of CFDictionary's representing the interfaces
140 * that have been identified and [need to be] named.
142 static CFMutableArrayRef S_dblist
= NULL
;
146 * An array of SCNetworkInterface's representing the
147 * interfaces that have been identified.
149 static CFMutableArrayRef S_iflist
= NULL
;
153 * IOServiceAddMatchingNotification object used to watch for
154 * new network interfaces.
156 static io_iterator_t S_iter
= MACH_PORT_NULL
;
158 #if !TARGET_OS_IPHONE
161 * An array of CFData(WatchedInfo) objects representing those
162 * interfaces that have been connected to the system while
165 static CFMutableArrayRef S_locked
= NULL
;
166 #endif // !TARGET_OS_IPHONE
170 * notification object for receiving IOKit notifications of
171 * new devices or state changes.
173 static IONotificationPortRef S_notify
= NULL
;
177 * An array of CFData(WatchedInfo) objects representing those
178 * pre-configured interfaces that have been connected to the
181 static CFMutableArrayRef S_preconfigured
= NULL
;
183 /* S_prev_active_list
184 * An array of CFDictionary's representing the previously
187 static CFMutableArrayRef S_prev_active_list
= NULL
;
191 * IOServiceAddInterestNotification object used to watch for
192 * IOKit matching to quiesce.
194 static io_object_t S_quiet
= MACH_PORT_NULL
;
198 * IOServiceAddMatchingNotification object used to watch for
199 * the availability of the "IONetworkStack" object.
201 static io_iterator_t S_stack
= MACH_PORT_NULL
;
205 * A dictionary containing Information about each network
206 * interface. For now, the key is the BSD name and the
207 * value is a CFNumber noting how long (in milliseconds)
208 * it took for the interface to be recognized/named.
210 static CFMutableDictionaryRef S_state
= NULL
;
214 * S_trustedHostAttached
216 * Note: this global must only be updated on trustRequired_queue()
218 static Boolean S_trustedHostAttached
= FALSE
;
222 * Note: this global must only be updated on trustRequired_queue()
224 static CFIndex S_trustedHostCount
= 0;
228 * An array of CFData(WatchedInfo) objects representing those
229 * interfaces that require [lockdownd] trust.
231 static CFMutableArrayRef S_trustRequired
= NULL
;
232 #endif // TARGET_OS_IPHONE
236 * CFRunLoopTimer tracking how long we are willing to wait
237 * for IOKit matching to quiesce (IOKitWaitQuiet).
240 * time to wait for the IONetworkStack object to appear before timeout
243 * time to wait for the IOKit to quiesce (after the IONetworkStack is
246 static CFRunLoopTimerRef S_timer
= NULL
;
247 static double S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
248 static double S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
251 * Virtual network interface configuration
252 * S_prefs : SCPreferences to configuration
253 * S_bonds : most recently actived Bond configuration
254 * S_bridges : most recently actived Bridge configuration
255 * S_vlans : most recently actived VLAN configuration
257 static SCPreferencesRef S_prefs
= NULL
;
258 static CFArrayRef S_bonds
= NULL
;
259 static CFArrayRef S_bridges
= NULL
;
260 static CFArrayRef S_vlans
= NULL
;
267 __log_InterfaceNamer(void)
269 static os_log_t log
= NULL
;
272 log
= os_log_create("com.apple.SystemConfiguration", "InterfaceNamer");
280 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
285 now
= CFAbsoluteTimeGetCurrent();
286 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
287 CFDictionaryAddValue(dict
, key
, val
);
292 #define INTERFACES CFSTR("Interfaces")
293 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
295 static CFComparisonResult
296 if_unit_compare(const void *val1
, const void *val2
, void *context
)
298 #pragma unused(context)
299 CFComparisonResult res
;
305 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
306 CFSTR(kIOInterfaceType
));
307 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
308 CFSTR(kIOInterfaceType
));
309 res
= CFNumberCompare(type1
, type2
, NULL
);
310 if (res
!= kCFCompareEqualTo
) {
313 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
314 CFSTR(kIOInterfaceUnit
));
315 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
316 CFSTR(kIOInterfaceUnit
));
317 return (CFNumberCompare(unit1
, unit2
, NULL
));
321 writeInterfaceList(CFArrayRef if_list
)
324 CFStringRef new_model
;
325 CFStringRef old_model
;
326 SCPreferencesRef prefs
;
328 if (isA_CFArray(if_list
) == NULL
) {
332 prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":writeInterfaceList"), NETWORK_INTERFACES_PREFS
);
334 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
338 cur_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
339 if (_SC_CFEqual(cur_list
, if_list
)) {
343 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
344 new_model
= _SC_hw_model(FALSE
);
345 if ((new_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
347 if ((old_model
!= NULL
) && (cur_list
!= NULL
)) {
350 // if interface list was created on other hardware
351 history
= CFStringCreateWithFormat(NULL
, NULL
,
355 SCPreferencesSetValue(prefs
, history
, cur_list
);
358 SC_log(LOG_NOTICE
, "Hardware model changed\n"
359 " created on \"%@\"\n"
365 SCPreferencesSetValue(prefs
, MODEL
, new_model
);
368 SCPreferencesSetValue(prefs
, INTERFACES
, if_list
);
370 if (!SCPreferencesCommitChanges(prefs
)) {
371 if (SCError() != EROFS
) {
372 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
383 static CFPropertyListRef
384 restoreNIPrefsFromBackup(SCPreferencesRef prefs
, CFStringRef current_model
)
386 CFPropertyListRef if_list
;
389 key
= CFStringCreateWithFormat(NULL
, 0, CFSTR("%@:%@"), INTERFACES
, current_model
);
390 if_list
= SCPreferencesGetValue(prefs
, key
);
391 if_list
= isA_CFArray(if_list
);
392 if (if_list
!= NULL
) {
393 /* Write the previously backed up Interface list for this hardware */
394 writeInterfaceList(if_list
);
396 /* Synchronize the prefs */
397 SCPreferencesSynchronize(prefs
);
399 /* Re-fetch the interface list */
400 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
401 if_list
= isA_CFArray(if_list
);
402 if (if_list
!= NULL
) {
403 /* We do not need the old interface list any more */
404 SCPreferencesRemoveValue(prefs
, key
);
405 if (!SCPreferencesCommitChanges(prefs
)) {
406 if (SCError() != EROFS
) {
407 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
418 static CF_RETURNS_RETAINED CFMutableArrayRef
422 CFStringRef old_model
;
423 CFMutableArrayRef plist
= NULL
;
424 SCPreferencesRef prefs
= NULL
;
426 prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":readInterfaceList"), NETWORK_INTERFACES_PREFS
);
428 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
432 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
433 if_list
= isA_CFArray(if_list
);
435 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
436 if (old_model
!= NULL
) {
437 CFStringRef new_model
;
439 new_model
= _SC_hw_model(FALSE
);
440 if (!_SC_CFEqual(old_model
, new_model
)) {
441 /* if interface list was created on other hardware,
442 Restore if a backup interface list is present */
443 if_list
= restoreNIPrefsFromBackup(prefs
, new_model
);
447 if (if_list
!= NULL
) {
449 CFIndex n
= CFArrayGetCount(if_list
);
451 plist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
452 for (i
= 0; i
< n
; i
++) {
453 CFDictionaryRef dict
;
455 dict
= CFArrayGetValueAtIndex(if_list
, i
);
456 if (isA_CFDictionary(dict
) &&
457 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceType
)) &&
458 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
459 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
460 CFArrayAppendValue(plist
, dict
);
471 static CF_RETURNS_RETAINED CFMutableArrayRef
472 previouslyActiveInterfaces()
474 CFMutableArrayRef active
;
478 if (S_dblist
== NULL
) {
482 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
484 n
= CFArrayGetCount(S_dblist
);
485 for (i
= 0; i
< n
; i
++) {
486 CFDictionaryRef if_dict
;
488 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
489 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
490 CFMutableDictionaryRef new_dict
;
492 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
493 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
494 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
495 CFArrayAppendValue(active
, new_dict
);
504 updateInterfaces(void);
511 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
), kSCDynamicStoreDomainPlugin
);
512 (void)SCDynamicStoreSetValue(NULL
, key
, S_state
);
518 #if !TARGET_OS_IPHONE
520 updateBondInterfaceConfiguration(SCPreferencesRef prefs
)
522 CFArrayRef interfaces
;
524 interfaces
= SCBondInterfaceCopyAll(prefs
);
525 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
526 CFRelease(interfaces
);
530 if (_SC_CFEqual(S_bonds
, interfaces
)) {
532 if (interfaces
!= NULL
) CFRelease(interfaces
);
536 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
537 S_bonds
= interfaces
;
539 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
540 SC_log(LOG_NOTICE
, "_SCBondInterfaceUpdateConfiguration() failed: %s",
541 SCErrorString(SCError()));
546 #endif // !TARGET_OS_IPHONE
549 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs
)
551 CFArrayRef interfaces
;
553 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
554 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
555 CFRelease(interfaces
);
559 if (_SC_CFEqual(S_bridges
, interfaces
)) {
561 if (interfaces
!= NULL
) CFRelease(interfaces
);
565 if (S_bridges
!= NULL
) CFRelease(S_bridges
);
566 S_bridges
= interfaces
;
568 if (!_SCBridgeInterfaceUpdateConfiguration(prefs
)) {
569 SC_log(LOG_NOTICE
, "_SCBridgeInterfaceUpdateConfiguration() failed: %s",
570 SCErrorString(SCError()));
577 updateVLANInterfaceConfiguration(SCPreferencesRef prefs
)
579 CFArrayRef interfaces
;
581 interfaces
= SCVLANInterfaceCopyAll(prefs
);
582 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
583 CFRelease(interfaces
);
587 if (_SC_CFEqual(S_vlans
, interfaces
)) {
589 if (interfaces
!= NULL
) CFRelease(interfaces
);
593 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
594 S_vlans
= interfaces
;
596 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
597 SC_log(LOG_NOTICE
, "_SCVLANInterfaceUpdateConfiguration() failed: %s",
598 SCErrorString(SCError()));
605 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
606 SCPreferencesNotification notificationType
,
610 os_activity_t activity
;
612 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
616 activity
= os_activity_create("check/update virtual network interface configuration",
618 OS_ACTIVITY_FLAG_DEFAULT
);
619 os_activity_scope(activity
);
622 // if a new interface has been "named"
624 if (S_bonds
!= NULL
) {
628 if (S_bridges
!= NULL
) {
629 CFRelease(S_bridges
);
632 if (S_vlans
!= NULL
) {
638 #if !TARGET_OS_IPHONE
639 updateBondInterfaceConfiguration (prefs
);
640 #endif // !TARGET_OS_IPHONE
641 updateBridgeInterfaceConfiguration(prefs
);
642 updateVLANInterfaceConfiguration (prefs
);
644 // we are finished with current prefs, wait for changes
645 SCPreferencesSynchronize(prefs
);
647 os_release(activity
);
655 updateBTPANInformation(const void *value
, void *context
)
657 #pragma unused(context)
659 CFDictionaryRef dict
= (CFDictionaryRef
)value
;
661 CFDictionaryRef info
;
664 if_name
= CFDictionaryGetValue(dict
, CFSTR(kIOBSDNameKey
));
665 if (!isA_CFString(if_name
)) {
670 info
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceInfo
));
671 if (!isA_CFDictionary(info
)) {
672 // if no SCNetworkInterface info
676 name
= CFDictionaryGetValue(info
, kSCPropUserDefinedName
);
677 if (!isA_CFString(name
) || !CFEqual(name
, CFSTR(BT_PAN_NAME
))) {
678 // if not BT-PAN interface
682 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Name
, if_name
);
684 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
685 if (isA_CFData(addr
)) {
686 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Mac
, addr
);
691 #endif // TARGET_OS_OSX
693 static CFDictionaryRef
694 createInterfaceDict(SCNetworkInterfaceRef interface
, CFArrayRef matchingMACs
)
696 CFMutableDictionaryRef new_if
;
699 new_if
= CFDictionaryCreateMutable(NULL
,
701 &kCFTypeDictionaryKeyCallBacks
,
702 &kCFTypeDictionaryValueCallBacks
);
704 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
706 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
710 val
= _SCNetworkInterfaceGetIOPath(interface
);
712 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
715 val
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
717 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceNamePrefix
), val
);
720 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
722 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
725 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
727 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
730 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
732 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
735 val
= SCNetworkInterfaceGetBSDName(interface
);
737 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
740 val
= SCNetworkInterfaceGetInterfaceType(interface
);
742 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
745 CFDictionarySetValue(new_if
,
747 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
749 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
751 if (matchingMACs
!= NULL
) {
752 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceMatchingMACs
), matchingMACs
);
758 static CFDictionaryRef
759 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
766 if (db_list
== NULL
) {
769 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
770 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
771 if (type
== NULL
|| addr
== NULL
) {
775 n
= CFArrayGetCount(db_list
);
776 for (i
= 0; i
< n
; i
++) {
778 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
781 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
782 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
783 if (t
== NULL
|| a
== NULL
)
786 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
796 static CFDictionaryRef
797 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
804 if (db_list
== NULL
) {
807 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
808 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
809 if (type
== NULL
|| unit
== NULL
) {
813 n
= CFArrayGetCount(db_list
);
814 for (i
= 0; i
< n
; i
++) {
815 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
819 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
820 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
821 if (t
== NULL
|| u
== NULL
) {
825 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
835 CFDictionaryRef match_info
;
836 CFStringRef match_type
;
837 CFBooleanRef match_builtin
;
838 CFMutableArrayRef matches
;
839 } matchContext
, *matchContextRef
;
841 static CF_RETURNS_RETAINED CFDictionaryRef
842 thinInterfaceInfo(CFDictionaryRef info
)
847 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
849 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
850 && (vid
== kIOUSBVendorIDAppleComputer
)) {
851 CFMutableDictionaryRef thin
;
853 // if this is an Apple USB device than we trust that
854 // the non-localized name will be correct.
855 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
856 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
857 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
858 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
862 return CFRetain(info
);
866 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
870 match
= _SC_CFEqual(known_info
, match_info
);
872 isA_CFDictionary(known_info
) &&
873 isA_CFDictionary(match_info
)) {
875 // if not an exact match, try thinning
876 known_info
= thinInterfaceInfo(known_info
);
877 match_info
= thinInterfaceInfo(match_info
);
878 match
= _SC_CFEqual(known_info
, match_info
);
879 if (known_info
!= NULL
) CFRelease(known_info
);
880 if (match_info
!= NULL
) CFRelease(match_info
);
887 matchKnown(const void *value
, void *context
)
889 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
890 matchContextRef match_context
= (matchContextRef
)context
;
892 // match interface type
894 CFStringRef known_type
;
896 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
897 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
902 // match SCNetworkInterfaceInfo
904 CFDictionaryRef known_info
;
906 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
907 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
912 // if requested, match [non-]builtin
913 if (match_context
->match_builtin
!= NULL
) {
914 CFBooleanRef known_builtin
;
916 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
917 if (!isA_CFBoolean(known_builtin
)) {
918 known_builtin
= kCFBooleanFalse
;
920 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
925 // if we have a match
926 if (match_context
->matches
== NULL
) {
927 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
929 CFArrayAppendValue(match_context
->matches
, known_dict
);
935 matchUnnamed(const void *value
, void *context
)
937 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
938 matchContextRef match_context
= (matchContextRef
)context
;
940 if (match_context
->matches
== NULL
) {
944 // match interface type
946 CFStringRef known_type
;
948 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
949 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
954 // match SCNetworkInterfaceInfo
956 CFDictionaryRef known_info
;
959 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
960 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
961 if (known_info
!= NULL
) CFRelease(known_info
);
967 // if requested, match [non-]builtin
968 if (match_context
->match_builtin
!= NULL
) {
969 CFBooleanRef known_builtin
;
971 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
973 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
978 // if we have a match
979 CFRelease(match_context
->matches
);
980 match_context
->matches
= NULL
;
986 interfaceExists(CFStringRef prefix
, CFNumberRef unit
)
988 Boolean found
= FALSE
;
989 CFDictionaryRef match_dict
;
990 CFStringRef match_keys
[2];
991 CFTypeRef match_vals
[2];
992 CFDictionaryRef matching
;
996 io_registry_entry_t entry
= MACH_PORT_NULL
;
997 io_iterator_t iterator
= MACH_PORT_NULL
;
999 mach_port_t masterPort
= MACH_PORT_NULL
;
1001 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1002 if (kr
!= KERN_SUCCESS
) {
1003 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1007 // look for kIONetworkInterface with matching prefix and unit
1008 match_keys
[0] = CFSTR(kIOInterfaceNamePrefix
);
1009 match_vals
[0] = prefix
;
1010 match_keys
[1] = CFSTR(kIOInterfaceUnit
);
1011 match_vals
[1] = unit
;
1012 match_dict
= CFDictionaryCreate(NULL
,
1013 (const void **)match_keys
,
1014 (const void **)match_vals
,
1016 &kCFTypeDictionaryKeyCallBacks
,
1017 &kCFTypeDictionaryValueCallBacks
);
1019 match_keys
[0] = CFSTR(kIOProviderClassKey
);
1020 match_vals
[0] = CFSTR(kIONetworkInterfaceClass
);
1021 match_keys
[1] = CFSTR(kIOPropertyMatchKey
);
1022 match_vals
[1] = match_dict
;
1023 matching
= CFDictionaryCreate(NULL
,
1024 (const void **)match_keys
,
1025 (const void **)match_vals
,
1026 sizeof(match_keys
)/sizeof(match_keys
[0]),
1027 &kCFTypeDictionaryKeyCallBacks
,
1028 &kCFTypeDictionaryValueCallBacks
);
1029 CFRelease(match_dict
);
1031 // note: the "matching" dictionary will be consumed by the following
1032 kr
= IOServiceGetMatchingServices(masterPort
, matching
, &iterator
);
1033 if ((kr
!= kIOReturnSuccess
) || (iterator
== MACH_PORT_NULL
)) {
1038 entry
= IOIteratorNext(iterator
);
1039 if (entry
== MACH_PORT_NULL
) {
1047 if (masterPort
!= MACH_PORT_NULL
) {
1048 mach_port_deallocate(mach_task_self(), masterPort
);
1050 if (entry
!= MACH_PORT_NULL
) {
1051 IOObjectRelease(entry
);
1053 if (iterator
!= MACH_PORT_NULL
) {
1054 IOObjectRelease(iterator
);
1061 * lookupMatchingInterface
1063 * Looks at the interfaces that have already been [or need to be] named with
1064 * the goal of allowing a system using a single network interface/adaptor of
1065 * a given type (vendor, model, ...) to not care about the specific adaptor
1066 * that is used (i.e. swapping dongle's is OK). Once a system has had more
1067 * than one interface/adaptor connected at the same time than we assume that
1068 * the network configuration is being setup for multi-homing that should be
1071 * If no matches are found or if more than one match is found, return NULL.
1072 * If a single match is found, return the match.
1074 static CFDictionaryRef
1075 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
1076 CFArrayRef db_list
, // already named
1077 CFArrayRef if_list
, // to be named
1078 CFIndex if_list_index
,
1079 CFBooleanRef builtin
)
1081 CFStringRef if_type
;
1082 CFDictionaryRef match
= NULL
;
1083 matchContext match_context
;
1085 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
1086 if (if_type
== NULL
) {
1090 match_context
.match_type
= if_type
;
1091 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
1092 match_context
.match_builtin
= builtin
;
1093 match_context
.matches
= NULL
;
1095 // check for matches to interfaces that have already been named
1096 // ... and append each match that we find to match_context.matches
1097 if (db_list
!= NULL
) {
1098 CFArrayApplyFunction(db_list
,
1099 CFRangeMake(0, CFArrayGetCount(db_list
)),
1104 // check for matches to interfaces that will be named
1105 // ... and CFRelease match_context.matches if we find another network
1106 // interface of the same type that also needs to be named
1107 if (if_list
!= NULL
) {
1108 CFIndex if_list_count
;
1110 if_list_count
= CFArrayGetCount(if_list
);
1111 if (if_list_index
< if_list_count
) {
1112 CFArrayApplyFunction(if_list
,
1113 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
1119 // check if we have a single match
1120 if (match_context
.matches
!= NULL
) {
1121 if (CFArrayGetCount(match_context
.matches
) == 1) {
1122 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
1124 CFRelease(match_context
.matches
);
1127 if (match
!= NULL
) {
1128 Boolean active
= TRUE
;
1131 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
1132 if (isA_CFString(name
)) {
1136 prefix
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceNamePrefix
));
1137 unit
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceUnit
));
1138 if (isA_CFString(prefix
) && isA_CFNumber(unit
)) {
1139 if (!interfaceExists(prefix
, unit
)) {
1150 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
1155 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
, CFDictionaryRef db_dict_match
)
1158 CFDictionaryRef if_dict
;
1159 CFStringRef if_name
;
1160 CFNumberRef if_type
;
1161 CFNumberRef if_unit
;
1162 CFArrayRef matchingMACs
= NULL
;
1163 CFIndex n
= CFArrayGetCount(db_list
);
1164 CFComparisonResult res
;
1166 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1167 if (if_name
!= NULL
) {
1168 addTimestamp(S_state
, if_name
);
1171 if (!_SCNetworkInterfaceIsBuiltin(interface
) && (db_dict_match
!= NULL
)) {
1175 matchingMACs
= CFDictionaryGetValue(db_dict_match
, CFSTR(kSCNetworkInterfaceMatchingMACs
));
1176 if (matchingMACs
!= NULL
) {
1177 CFRetain(matchingMACs
);
1180 addr_old
= CFDictionaryGetValue(db_dict_match
, CFSTR(kIOMACAddress
));
1181 addr_cur
= _SCNetworkInterfaceGetHardwareAddress(interface
);
1182 if ((addr_old
!= NULL
) && (addr_cur
!= NULL
) && !CFEqual(addr_old
, addr_cur
)) {
1183 CFMutableArrayRef matching_new
;
1185 // if MAC address changed, add previous MAC to history
1186 if (matchingMACs
!= NULL
) {
1187 matching_new
= CFArrayCreateMutableCopy(NULL
, 0, matchingMACs
);
1188 CFRelease(matchingMACs
);
1190 // remove duplicates of the now current MAC from history
1191 i
= CFArrayGetFirstIndexOfValue(matching_new
, CFRangeMake(0, CFArrayGetCount(matching_new
)), addr_cur
);
1192 if (i
!= kCFNotFound
) {
1193 CFArrayRemoveValueAtIndex(matching_new
, i
);
1196 // remove duplicates of the previous MAC from history before re-inserting
1197 i
= CFArrayGetFirstIndexOfValue(matching_new
, CFRangeMake(0, CFArrayGetCount(matching_new
)), addr_old
);
1198 if (i
!= kCFNotFound
) {
1199 CFArrayRemoveValueAtIndex(matching_new
, i
);
1202 matching_new
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1204 CFArrayInsertValueAtIndex(matching_new
, 0, addr_old
);
1206 // limit history size
1207 #define MATCHING_HISTORY_MAXLEN 32
1208 for (i
= CFArrayGetCount(matching_new
); i
> MATCHING_HISTORY_MAXLEN
; i
--) {
1209 CFArrayRemoveValueAtIndex(matching_new
, i
- 1);
1212 matchingMACs
= matching_new
;
1216 if_dict
= createInterfaceDict(interface
, matchingMACs
);
1217 if (matchingMACs
!= NULL
) {
1218 CFRelease(matchingMACs
);
1221 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1222 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1223 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
1228 for (i
= 0; i
< n
; i
++) {
1229 CFNumberRef db_type
;
1230 CFNumberRef db_unit
;
1231 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
1233 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1234 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1235 res
= CFNumberCompare(if_type
, db_type
, NULL
);
1236 if (res
== kCFCompareLessThan
1237 || (res
== kCFCompareEqualTo
1238 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
1239 == kCFCompareLessThan
))) {
1240 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
1246 CFArrayAppendValue(S_dblist
, if_dict
);
1249 updateBTPANInformation(if_dict
, NULL
);
1250 #endif // TARGET_OS_OSX
1257 replaceInterface(SCNetworkInterfaceRef interface
)
1259 CFDictionaryRef db_dict
;
1260 CFDictionaryRef db_dict_match
= NULL
;
1264 if (S_dblist
== NULL
) {
1265 S_dblist
= CFArrayCreateMutable(NULL
, 0,
1266 &kCFTypeArrayCallBacks
);
1269 // remove any dict that has our type/addr
1271 db_dict
= lookupInterfaceByAddress(S_dblist
, interface
, &where
);
1272 if (db_dict
== NULL
) {
1275 if (db_dict_match
== NULL
) {
1276 db_dict_match
= CFRetain(db_dict
);
1278 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1282 // remove any dict that has the same type/unit
1284 db_dict
= lookupInterfaceByUnit(S_dblist
, interface
, &where
);
1285 if (db_dict
== NULL
) {
1288 if (db_dict_match
== NULL
) {
1289 db_dict_match
= CFRetain(db_dict
);
1291 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1295 insertInterface(S_dblist
, interface
, db_dict_match
);
1296 if (db_dict_match
!= NULL
) {
1297 CFRelease(db_dict_match
);
1301 SC_log(LOG_ERR
, "Multiple interfaces updated (n = %d, %@)", n
, interface
);
1308 getHighestUnitForType(CFNumberRef if_type
)
1312 CFNumberRef ret_unit
= NULL
;
1314 if (S_dblist
== NULL
) {
1318 n
= CFArrayGetCount(S_dblist
);
1319 for (i
= 0; i
< n
; i
++) {
1320 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1323 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1324 if (CFEqual(type
, if_type
)) {
1327 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1328 if (ret_unit
== NULL
1329 || (CFNumberCompare(unit
, ret_unit
, NULL
)
1330 == kCFCompareGreaterThan
)) {
1340 * Function: ensureInterfaceHasUnit
1342 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1343 * release the interface and return NULL.
1345 static SCNetworkInterfaceRef
1346 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if
)
1349 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if
) == NULL
) {
1356 #ifdef USE_REGISTRY_ENTRY_ID
1357 static kern_return_t
1358 registerInterfaceWithIORegistryEntryID(io_connect_t connect
,
1364 CFMutableDictionaryRef dict
;
1368 dict
= CFDictionaryCreateMutable(NULL
, 0,
1369 &kCFTypeDictionaryKeyCallBacks
,
1370 &kCFTypeDictionaryValueCallBacks
);
1371 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1372 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1374 data
= CFDataCreate(NULL
, (void *) &entryID
, sizeof(entryID
));
1375 CFDictionarySetValue(dict
, CFSTR(kIORegistryEntryIDKey
), data
);
1377 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1378 kr
= IOConnectSetCFProperties(connect
, dict
);
1383 static SCNetworkInterfaceRef
1384 copyInterfaceForIORegistryEntryID(uint64_t entryID
)
1386 io_registry_entry_t entry
= MACH_PORT_NULL
;
1387 SCNetworkInterfaceRef interface
= NULL
;
1388 io_iterator_t iterator
= MACH_PORT_NULL
;
1390 mach_port_t masterPort
= MACH_PORT_NULL
;
1392 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1393 if (kr
!= KERN_SUCCESS
) {
1394 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1398 kr
= IOServiceGetMatchingServices(masterPort
,
1399 IORegistryEntryIDMatching(entryID
),
1401 if ((kr
!= KERN_SUCCESS
) || (iterator
== MACH_PORT_NULL
)) {
1402 SC_log(LOG_NOTICE
, "IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d",
1409 entry
= IOIteratorNext(iterator
);
1410 if (entry
== MACH_PORT_NULL
) {
1411 SC_log(LOG_NOTICE
, "IORegistryEntryIDMatching(0x%llx) failed", entryID
);
1415 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1418 if (masterPort
!= MACH_PORT_NULL
) {
1419 mach_port_deallocate(mach_task_self(), masterPort
);
1421 if (entry
!= MACH_PORT_NULL
) {
1422 IOObjectRelease(entry
);
1424 if (iterator
!= MACH_PORT_NULL
) {
1425 IOObjectRelease(iterator
);
1430 static SCNetworkInterfaceRef
1431 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID
)
1433 SCNetworkInterfaceRef net_if
;
1435 net_if
= copyInterfaceForIORegistryEntryID(entryID
);
1436 return (ensureInterfaceHasUnit(net_if
));
1439 #else // USE_REGISTRY_ENTRY_ID
1441 * Function: registerInterface
1443 * Register a single interface with the given service path to the
1444 * data link layer (BSD), using the specified unit number.
1446 static kern_return_t
1447 registerInterfaceWithIOServicePath(io_connect_t connect
,
1452 CFMutableDictionaryRef dict
;
1456 dict
= CFDictionaryCreateMutable(NULL
, 0,
1457 &kCFTypeDictionaryKeyCallBacks
,
1458 &kCFTypeDictionaryValueCallBacks
);
1459 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1460 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1462 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1463 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1464 kr
= IOConnectSetCFProperties(connect
, dict
);
1469 static SCNetworkInterfaceRef
1470 copyInterfaceForIOKitPath(CFStringRef if_path
)
1472 io_registry_entry_t entry
= MACH_PORT_NULL
;
1473 SCNetworkInterfaceRef interface
= NULL
;
1475 mach_port_t masterPort
= MACH_PORT_NULL
;
1478 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1479 if (kr
!= KERN_SUCCESS
) {
1480 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1483 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1484 entry
= IORegistryEntryFromPath(masterPort
, path
);
1485 if (entry
== MACH_PORT_NULL
) {
1486 SC_log(LOG_NOTICE
, "IORegistryEntryFromPath(%@) failed", if_path
);
1490 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1493 if (masterPort
!= MACH_PORT_NULL
) {
1494 mach_port_deallocate(mach_task_self(), masterPort
);
1496 if (entry
!= MACH_PORT_NULL
) {
1497 IOObjectRelease(entry
);
1503 static SCNetworkInterfaceRef
1504 copyNamedInterfaceForIOKitPath(CFStringRef if_path
)
1506 SCNetworkInterfaceRef net_if
;
1508 net_if
= copyInterfaceForIOKitPath(if_path
);
1509 return (ensureInterfaceHasUnit(net_if
));
1512 #endif // USE_REGISTRY_ENTRY_ID
1515 displayInterface(SCNetworkInterfaceRef interface
)
1522 name
= SCNetworkInterfaceGetBSDName(interface
);
1523 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1524 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1525 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1527 SC_log(LOG_INFO
, " %s%@%sType: %@, %s%@%sMAC address: %@",
1528 (name
!= NULL
) ? "BSD Name: " : "",
1529 (name
!= NULL
) ? name
: CFSTR(""),
1530 (name
!= NULL
) ? ", " : "",
1532 (unit
!= NULL
) ? "Unit: " : "",
1533 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1534 (unit
!= NULL
) ? ", " : "",
1535 (addr
!= NULL
) ? addr
: CFSTR("?"));
1539 builtinAvailable(SCNetworkInterfaceRef interface
, // new interface
1540 CFNumberRef if_unit
) // desired unit
1543 CFNumberRef if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1546 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1547 for (i
= 0; i
< n
; i
++) {
1548 CFStringRef if_path
;
1549 CFDictionaryRef known_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1550 CFStringRef known_path
;
1551 CFNumberRef known_type
;
1552 CFNumberRef known_unit
;
1554 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceType
));
1555 if (!_SC_CFEqual(if_type
, known_type
)) {
1556 continue; // if not the same interface type
1559 known_unit
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceUnit
));
1560 if (!_SC_CFEqual(if_unit
, known_unit
)) {
1561 continue; // if not the same interface unit
1564 if_path
= _SCNetworkInterfaceGetIOPath(interface
);
1565 known_path
= CFDictionaryGetValue(known_dict
, CFSTR(kIOPathMatchKey
));
1566 if (!_SC_CFEqual(if_path
, known_path
)) {
1567 // if different IORegistry path
1571 // if same type, same unit, same path
1575 // if interface type/unit not found
1580 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
1585 for (i
= 0; i
< last
; i
++) {
1586 SCNetworkInterfaceRef builtin_if
;
1587 CFNumberRef builtin_type
;
1589 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1590 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
1591 if (CFEqual(if_type
, builtin_type
)) {
1592 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1593 n
++; // if built-in interface
1603 #pragma mark Interface monitoring (e.g. watch for "detach")
1606 typedef struct WatchedInfo
*WatchedInfoRef
;
1608 typedef void (*InterfaceUpdateCallBack
) (
1610 natural_t messageType
,
1611 void *messageArgument
1615 SCNetworkInterfaceRef interface
;
1616 io_service_t interface_node
;
1617 io_object_t notification
;
1618 InterfaceUpdateCallBack callback
;
1622 watcherRelease(CFDataRef watched
);
1625 updateWatchedInterface(void *refCon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
1627 #pragma unused(service)
1628 #pragma unused(messageArgument)
1629 switch (messageType
) {
1630 case kIOMessageServiceIsTerminated
: { // if [watched] interface yanked
1631 CFDataRef watched
= (CFDataRef
)refCon
;
1632 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1635 watchedInfo
->callback(watched
, messageType
, messageArgument
);
1636 watcherRelease(watched
);
1649 watcherCreate(SCNetworkInterfaceRef interface
, InterfaceUpdateCallBack callback
)
1652 io_service_t interface_node
;
1654 CFDictionaryRef matching
;
1655 CFMutableDataRef watched
;
1656 WatchedInfo
*watchedInfo
;
1658 // get the IORegistry node
1659 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
1660 matching
= IORegistryEntryIDMatching(entryID
);
1661 interface_node
= IOServiceGetMatchingService(kIOMasterPortDefault
, matching
);
1662 if (interface_node
== MACH_PORT_NULL
) {
1663 // interface no longer present
1667 // create [locked/trusted] interface watcher
1668 watched
= CFDataCreateMutable(NULL
, sizeof(WatchedInfo
));
1669 CFDataSetLength(watched
, sizeof(WatchedInfo
));
1670 watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1671 bzero(watchedInfo
, sizeof(*watchedInfo
));
1674 watchedInfo
->interface
= CFRetain(interface
);
1676 // ... and the interface node
1677 watchedInfo
->interface_node
= interface_node
;
1679 // ... and set the callback
1680 watchedInfo
->callback
= callback
;
1682 kr
= IOServiceAddInterestNotification(S_notify
, // IONotificationPortRef
1683 watchedInfo
->interface_node
, // io_service_t
1684 kIOGeneralInterest
, // interestType
1685 updateWatchedInterface
, // IOServiceInterestCallback
1686 (void *)watched
, // refCon
1687 &watchedInfo
->notification
); // notification
1688 if (kr
!= KERN_SUCCESS
) {
1690 "IOServiceAddInterestNotification() failed, kr = 0x%x",
1692 watcherRelease(watched
);
1701 watcherRelease(CFDataRef watched
)
1703 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1706 if (watchedInfo
->notification
!= IO_OBJECT_NULL
) {
1707 IOObjectRelease(watchedInfo
->notification
);
1708 watchedInfo
->notification
= IO_OBJECT_NULL
;
1711 // release interface node
1712 if (watchedInfo
->interface_node
!= IO_OBJECT_NULL
) {
1713 IOObjectRelease(watchedInfo
->interface_node
);
1714 watchedInfo
->interface_node
= IO_OBJECT_NULL
;
1717 // release interface
1718 if (watchedInfo
->interface
!= NULL
) {
1719 CFRelease(watchedInfo
->interface
);
1720 watchedInfo
->interface
= NULL
;
1728 #pragma mark Locked device support [macOS]
1731 #if !TARGET_OS_IPHONE
1737 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
1739 CFMutableArrayRef locked
;
1741 locked
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1743 for (CFIndex i
= 0; i
< n
; i
++) {
1748 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
1749 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1751 name
= SCNetworkInterfaceGetLocalizedDisplayName(watchedInfo
->interface
);
1752 addr
= SCNetworkInterfaceGetHardwareAddressString(watchedInfo
->interface
);
1753 path
= _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
);
1754 str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@: %@: %@"),
1755 (name
!= NULL
) ? name
: CFSTR("?"),
1756 (addr
!= NULL
) ? addr
: CFSTR("?"),
1758 CFArrayAppendValue(locked
, str
);
1762 CFDictionarySetValue(S_state
, kInterfaceNamerKey_LockedInterfaces
, locked
);
1765 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_LockedInterfaces
);
1774 blockNewInterfaces()
1776 static boolean_t allow
= TRUE
;
1777 static dispatch_once_t once
;
1779 dispatch_once(&once
, ^{
1780 allow
= InterfaceNamerControlPrefsAllowNewInterfaces();
1789 CFArrayRef console_sessions
;
1790 boolean_t locked
= FALSE
;
1791 io_registry_entry_t root
;
1793 root
= IORegistryGetRootEntry(kIOMasterPortDefault
);
1794 console_sessions
= IORegistryEntryCreateCFProperty(root
,
1795 CFSTR(kIOConsoleUsersKey
),
1798 if (isA_CFArray(console_sessions
)) {
1801 n
= CFArrayGetCount(console_sessions
);
1802 for (CFIndex i
= 0; i
< n
; i
++) {
1803 CFBooleanRef isLocked
;
1804 CFBooleanRef isLoginDone
;
1805 CFBooleanRef onConsole
;
1806 CFDictionaryRef session
;
1808 session
= CFArrayGetValueAtIndex(console_sessions
, i
);
1809 if (!isA_CFDictionary(session
)) {
1810 // if not dictionary
1814 if (!CFDictionaryGetValueIfPresent(session
,
1815 CFSTR(kIOConsoleSessionOnConsoleKey
),
1816 (const void **)&onConsole
) ||
1817 !isA_CFBoolean(onConsole
) ||
1818 !CFBooleanGetValue(onConsole
)) {
1819 // if not "on console" session
1824 CFDictionaryGetValueIfPresent(session
,
1825 CFSTR(kIOConsoleSessionLoginDoneKey
),
1826 (const void **)&isLoginDone
) &&
1827 isA_CFBoolean(isLoginDone
) &&
1828 !CFBooleanGetValue(isLoginDone
)) {
1830 SC_log(LOG_INFO
, "multiple sessions, console @ loginwindow");
1835 if (CFDictionaryGetValueIfPresent(session
,
1836 CFSTR(kIOConsoleSessionScreenIsLockedKey
),
1837 (const void **)&isLocked
) &&
1838 isA_CFBoolean(isLocked
) &&
1839 CFBooleanGetValue(isLocked
)) {
1841 SC_log(LOG_INFO
, "console screen locked");
1848 SC_log(LOG_INFO
, "console not locked");
1852 if (console_sessions
!= NULL
) {
1853 CFRelease(console_sessions
);
1855 IOObjectRelease(root
);
1860 //#define ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
1861 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
1863 static CFUserNotificationRef userNotification
;
1864 static CFRunLoopSourceRef userRls
;
1867 lockedNotification_remove(void)
1869 if (userRls
!= NULL
) {
1870 CFRunLoopSourceInvalidate(userRls
);
1874 if (userNotification
!= NULL
) {
1877 status
= CFUserNotificationCancel(userNotification
);
1880 "CFUserNotificationCancel() failed, status=%d",
1883 CFRelease(userNotification
);
1884 userNotification
= NULL
;
1890 #define MY_ICON_PATH "/System/Library/PreferencePanes/Network.prefPane/Contents/Resources/Network.icns"
1893 lockedNotification_reply(CFUserNotificationRef userNotification
, CFOptionFlags response_flags
)
1895 #pragma unused(userNotification)
1897 os_activity_t activity
;
1900 activity
= os_activity_create("process locked interface notification",
1901 OS_ACTIVITY_CURRENT
,
1902 OS_ACTIVITY_FLAG_DEFAULT
);
1903 os_activity_scope(activity
);
1905 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
1906 for (CFIndex i
= 0; i
< n
; i
++) {
1907 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
1908 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
1910 // process user response
1911 switch (response_flags
& 0x3) {
1912 case kCFUserNotificationDefaultResponse
: {
1913 // if OK'd, [re-]process new interfaces
1915 SC_log(LOG_INFO
, "Reprocessing %ld [locked] interface%s", n
, n
== 1 ? "" : "s");
1917 if (S_iflist
== NULL
) {
1918 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1922 // add the interface to those newly discovered
1923 CFArrayAppendValue(S_iflist
, watchedInfo
->interface
);
1927 // if cancelled, ignore [remaining] new interfaces
1928 SC_log(LOG_INFO
, "[locked] interface ignored");
1929 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
1935 watcherRelease(watched
);
1938 if (S_locked
!= NULL
) {
1939 CFRelease(S_locked
);
1943 lockedNotification_remove();
1945 if (S_iflist
!= NULL
) {
1949 os_release(activity
);
1955 lockedNotification_add(void)
1958 CFMutableDictionaryRef dict
;
1960 CFMutableArrayRef message
;
1962 CFURLRef url
= NULL
;
1964 n
= (S_locked
!= NULL
) ? CFArrayGetCount(S_locked
) : 0;
1966 // no locked interfaces, no notification needed
1970 dict
= CFDictionaryCreateMutable(NULL
,
1972 &kCFTypeDictionaryKeyCallBacks
,
1973 &kCFTypeDictionaryValueCallBacks
);
1975 // set localization URL
1976 bundle
= _SC_CFBundleGet();
1977 if (bundle
!= NULL
) {
1978 url
= CFBundleCopyBundleURL(bundle
);
1982 CFDictionarySetValue(dict
, kCFUserNotificationLocalizationURLKey
, url
);
1985 SC_log(LOG_ERR
, "can't find bundle");
1990 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
1991 (const UInt8
*)MY_ICON_PATH
,
1992 sizeof(MY_ICON_PATH
) - 1,
1995 CFDictionarySetValue(dict
, kCFUserNotificationIconURLKey
, url
);
2000 CFDictionarySetValue(dict
,
2001 kCFUserNotificationAlertHeaderKey
,
2002 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_HEADER")
2003 : CFSTR("LOCKED_MULTIPLE_INTERFACES_HEADER"));
2006 message
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2007 CFArrayAppendValue(message
,
2008 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_MESSAGE")
2009 : CFSTR("LOCKED_MULTIPLE_INTERFACES_MESSAGE"));
2010 for (CFIndex i
= 0; i
< n
; i
++) {
2013 CFDataRef watched
= CFArrayGetValueAtIndex(S_locked
, i
);
2014 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2016 name
= SCNetworkInterfaceGetLocalizedDisplayName(watchedInfo
->interface
);
2017 str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("\r\t%@"), name
);
2018 CFArrayAppendValue(message
, str
);
2021 CFDictionarySetValue(dict
, kCFUserNotificationAlertMessageKey
, message
);
2025 CFDictionarySetValue(dict
,
2026 kCFUserNotificationDefaultButtonTitleKey
,
2027 CFSTR("LOCKED_INTERFACES_IGNORE"));
2028 CFDictionarySetValue(dict
,
2029 kCFUserNotificationAlternateButtonTitleKey
,
2030 (n
== 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_ADD")
2031 : CFSTR("LOCKED_MULTIPLE_INTERFACES_ADD"));
2033 // create and post notification
2034 userNotification
= CFUserNotificationCreate(NULL
,
2036 kCFUserNotificationNoteAlertLevel
,
2039 if (userNotification
== NULL
) {
2040 SC_log(LOG_ERR
, "CFUserNotificationCreate() failed: %d", (int)error
);
2044 // establish callback
2045 userRls
= CFUserNotificationCreateRunLoopSource(NULL
,
2047 lockedNotification_reply
,
2049 if (userRls
== NULL
) {
2050 SC_log(LOG_ERR
, "CFUserNotificationCreateRunLoopSource() failed");
2051 CFRelease(userNotification
);
2052 userNotification
= NULL
;
2055 CFRunLoopAddSource(CFRunLoopGetCurrent(), userRls
, kCFRunLoopDefaultMode
);
2059 if (dict
!= NULL
) CFRelease(dict
);
2064 lockedNotification_update(void)
2066 // if present, remove current notification
2067 lockedNotification_remove();
2069 // post notification (if needed)
2070 lockedNotification_add();
2075 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2078 lockedInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2080 #pragma unused(messageArgument)
2081 Boolean updated
= FALSE
;
2082 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2084 switch (messageType
) {
2085 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2086 SC_log(LOG_INFO
, "[locked] interface removed");
2087 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
2089 if (S_locked
!= NULL
) {
2091 CFIndex n
= CFArrayGetCount(S_locked
);
2093 i
= CFArrayGetFirstIndexOfValue(S_locked
, CFRangeMake(0, n
), watched
);
2094 if (i
!= kCFNotFound
) {
2095 CFArrayRemoveValueAtIndex(S_locked
, i
);
2096 if (CFArrayGetCount(S_locked
) == 0) {
2097 CFRelease(S_locked
);
2112 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2113 // update user notification after interface removed
2114 lockedNotification_update();
2115 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2117 // post info about interfaces not added because the console is locked
2125 watchLockedInterface(SCNetworkInterfaceRef interface
)
2127 Boolean updated
= FALSE
;
2130 watched
= watcherCreate(interface
, lockedInterfaceUpdated
);
2131 if (watched
!= NULL
) {
2132 SC_log(LOG_INFO
, "watching [locked] interface");
2133 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(interface
));
2135 if (S_locked
== NULL
) {
2136 S_locked
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2138 CFArrayAppendValue(S_locked
, watched
);
2143 // post info about interfaces not added because the console is locked
2146 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2147 // post/update user notification with new interface
2148 lockedNotification_update();
2149 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2154 #endif // !TARGET_OS_IPHONE
2158 #pragma mark Trust required support [iOS]
2161 #if TARGET_OS_IPHONE
2167 n
= (S_trustRequired
!= NULL
) ? CFArrayGetCount(S_trustRequired
) : 0;
2168 if ((n
> 0) && !S_trustedHostAttached
) {
2169 CFMutableArrayRef excluded
;
2171 // if we have interfaces that require not [yet] granted "trust".
2173 excluded
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2175 for (CFIndex i
= 0; i
< n
; i
++) {
2176 CFStringRef bsdName
;
2177 CFDataRef watched
= CFArrayGetValueAtIndex(S_trustRequired
, i
);
2178 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2180 bsdName
= SCNetworkInterfaceGetBSDName(watchedInfo
->interface
);
2181 if (bsdName
== NULL
) {
2182 SC_log(LOG_NOTICE
, "[trust required] excluded interface w/no BSD name");
2183 SC_log(LOG_NOTICE
, " interface = %@", watchedInfo
->interface
);
2186 CFArrayAppendValue(excluded
, bsdName
);
2189 CFDictionarySetValue(S_state
, kInterfaceNamerKey_ExcludedInterfaces
, excluded
);
2190 CFRelease(excluded
);
2192 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_ExcludedInterfaces
);
2200 static dispatch_queue_t
2201 trustRequired_queue()
2203 static dispatch_once_t once
;
2204 static dispatch_queue_t q
;
2206 dispatch_once(&once
, ^{
2207 q
= dispatch_queue_create("Trust Required queue", NULL
);
2214 // runs on "Trust Required" dispatch queue
2216 trustRequiredNotification_update(CFRunLoopRef rl
, CFStringRef reason
)
2218 Boolean changed
= FALSE
;
2219 CFStringRef error
= NULL
;
2224 * determine whether the device has "trusted" the host (or other device)
2226 trusted
= lockdown_is_host_trusted(MY_PLUGIN_ID
, NULL
, &error
);
2227 n
= (S_trustRequired
!= NULL
) ? CFArrayGetCount(S_trustRequired
) : 0;
2228 if ((S_trustedHostCount
!= n
) || (S_trustedHostAttached
!= trusted
)) {
2232 SC_log(LOG_INFO
, "%@, trusted = %s%s%@, %ld interface%s)%s",
2234 trusted
? "Yes" : "No",
2235 (error
!= NULL
) ? ", error = " : "",
2236 (error
!= NULL
) ? error
: CFSTR(""),
2238 (n
== 1) ? "" : "s",
2239 changed
? " *" : "");
2242 S_trustedHostAttached
= trusted
;
2243 S_trustedHostCount
= n
;
2244 CFRunLoopPerformBlock(rl
, kCFRunLoopDefaultMode
, ^{
2247 CFRunLoopWakeUp(rl
);
2250 if (error
!= NULL
) {
2258 trustRequiredInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2260 #pragma unused(messageArgument)
2261 Boolean updated
= FALSE
;
2262 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2264 switch (messageType
) {
2265 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2266 SC_log(LOG_INFO
, "[trust required] interface removed");
2267 SC_log(LOG_INFO
, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo
->interface
));
2269 if (S_trustRequired
!= NULL
) {
2271 CFIndex n
= CFArrayGetCount(S_trustRequired
);
2273 i
= CFArrayGetFirstIndexOfValue(S_trustRequired
, CFRangeMake(0, n
), watched
);
2274 if (i
!= kCFNotFound
) {
2275 CFArrayRemoveValueAtIndex(S_trustRequired
, i
);
2276 if (CFArrayGetCount(S_trustRequired
) == 0) {
2277 CFRelease(S_trustRequired
);
2278 S_trustRequired
= NULL
;
2292 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2295 dispatch_async(trustRequired_queue(), ^{
2296 trustRequiredNotification_update(rl
, CFSTR("TrustRequired interface removed"));
2305 watchTrustedStatus(CFStringRef notification
, CFStringRef reason
)
2308 int notify_token
= -1;
2310 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2312 key
= CFStringGetCStringPtr(notification
, kCFStringEncodingUTF8
);
2313 assert(key
!= NULL
);
2317 ret
= notify_register_dispatch(key
,
2319 trustRequired_queue(),
2321 #pragma unused(token)
2322 trustRequiredNotification_update(rl
, reason
);
2324 if (ret
!= NOTIFY_STATUS_OK
) {
2325 SC_log(LOG_ERR
, "notify_register_dispatch(%@) failed: %u", notification
, ret
);
2334 isWatchedInterface(SCNetworkInterfaceRef interface
)
2336 Boolean found
= FALSE
;
2339 n
= (S_trustRequired
!= NULL
) ? CFArrayGetCount(S_trustRequired
) : 0;
2340 for (CFIndex i
= 0; i
< n
; i
++) {
2341 CFDataRef watched
= CFArrayGetValueAtIndex(S_trustRequired
, i
);
2342 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2344 if (CFEqual((watchedInfo
->interface
), interface
)) {
2354 updateTrustRequiredInterfaces(CFArrayRef interfaces
)
2357 Boolean updated
= FALSE
;
2359 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
2360 for (CFIndex i
= 0; i
< n
; i
++) {
2361 SCNetworkInterfaceRef interface
;
2363 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2364 if (_SCNetworkInterfaceIsTrustRequired(interface
) && !isWatchedInterface(interface
)) {
2367 watched
= watcherCreate(interface
, trustRequiredInterfaceUpdated
);
2368 if (watched
!= NULL
) {
2369 SC_log(LOG_INFO
, "watching [trust required] interface: %@",
2370 SCNetworkInterfaceGetBSDName(interface
));
2372 if (S_trustRequired
== NULL
) {
2373 S_trustRequired
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2375 CFArrayAppendValue(S_trustRequired
, watched
);
2382 static dispatch_once_t once
;
2383 CFRunLoopRef rl
= CFRunLoopGetCurrent();
2385 dispatch_once(&once
, ^{
2386 // watch for "Host attached"
2387 watchTrustedStatus(kLockdownNotificationHostAttached
,
2388 CFSTR("Host attached"));
2390 // watch for "Host detached"
2391 watchTrustedStatus(kLockdownNotificationHostDetached
,
2392 CFSTR("Host detached"));
2394 // watch for "Trusted host attached"
2395 watchTrustedStatus(kLockdownNotificationTrustedHostAttached
,
2396 CFSTR("Trusted Host attached"));
2398 // watch for "Trusted PDP attached"
2399 watchTrustedStatus(kLockdownNotificationTrustedPTPAttached
,
2400 CFSTR("Trusted PTP attached"));
2404 dispatch_async(trustRequired_queue(), ^{
2405 trustRequiredNotification_update(rl
, CFSTR("TrustRequired interface added"));
2412 #endif // TARGET_OS_IPHONE
2416 #pragma mark Interface naming
2419 static __inline__ boolean_t
2422 return (S_quiet
== MACH_PORT_NULL
);
2426 wasPreviouslyUsedInterface(CFDictionaryRef dbdict
, SCNetworkInterfaceRef interface
)
2428 CFArrayRef matchingMACs
;
2430 matchingMACs
= CFDictionaryGetValue(dbdict
, CFSTR(kSCNetworkInterfaceMatchingMACs
));
2431 if (matchingMACs
!= NULL
) {
2434 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
2436 if (CFArrayContainsValue(matchingMACs
,
2437 CFRangeMake(0, CFArrayGetCount(matchingMACs
)),
2448 nameInterfaces(CFMutableArrayRef if_list
)
2451 CFIndex n
= CFArrayGetCount(if_list
);
2453 for (i
= 0; i
< n
; i
++) {
2455 SCNetworkInterfaceRef interface
;
2456 SCNetworkInterfaceRef new_interface
;
2462 interface
= CFArrayGetValueAtIndex(if_list
, i
);
2463 path
= _SCNetworkInterfaceGetIOPath(interface
);
2464 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
2465 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
2466 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
2469 CFStringRef if_name
;
2471 if_name
= SCNetworkInterfaceGetBSDName(interface
);
2472 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
2473 SC_log(LOG_INFO
, "Interface already has a unit number");
2474 displayInterface(interface
);
2477 // update the list of interfaces that were previously named
2478 if ((S_prev_active_list
!= NULL
)
2479 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
2480 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
2483 replaceInterface(interface
);
2485 CFDictionaryRef dbdict
;
2486 boolean_t is_builtin
;
2490 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
2491 if (dbdict
!= NULL
) {
2492 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2495 SC_log(LOG_INFO
, "Interface assigned unit %@ (from database)", unit
);
2498 if ((dbdict
== NULL
) && !isQuiet()) {
2499 // if new interface, wait until quiet before naming
2500 addTimestamp(S_state
, path
);
2504 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
2506 if (dbdict
== NULL
) {
2507 dbdict
= lookupMatchingInterface(interface
,
2511 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
2513 if ((dbdict
!= NULL
) && wasPreviouslyUsedInterface(dbdict
, interface
)) {
2514 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2517 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database w/previously used interface)", unit
);
2520 #if !TARGET_OS_IPHONE
2521 if ((unit
== NULL
) &&
2524 blockNewInterfaces() &&
2525 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
2526 isConsoleLocked()) {
2529 // if new (but matching) interface and console locked, ignore
2530 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
2531 SC_log(LOG_NOTICE
, "Console locked, network interface* ignored");
2532 SC_log(LOG_INFO
, " path = %@, addr = %@",
2534 (addr
!= NULL
) ? addr
: CFSTR("?"));
2535 watchLockedInterface(interface
);
2538 #endif // !TARGET_OS_IPHONE
2540 if ((unit
== NULL
) && (dbdict
!= NULL
)) {
2541 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
2544 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database w/new interface)", unit
);
2548 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
2549 // update the list of interfaces that were previously named
2550 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
2551 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
2553 if (where
!= kCFNotFound
) {
2554 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
2558 if (dbdict
== NULL
) {
2562 // built-in interface, try to use the reserved slots
2563 next_unit
= builtinCount(if_list
, i
, type
);
2565 // But, before claiming a reserved slot we check to see if the
2566 // slot had previously been used. If so, and if the slot had been
2567 // assigned to the same type of interface, then we will perform a
2568 // replacement (e.g. assume that this was a board swap). But, if
2569 // the new interface is a different type then we assume that the
2570 // built-in configuration has changed and allocate a new unit from
2571 // the non-reserved slots.
2573 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
2574 if (!builtinAvailable(interface
, unit
)) {
2575 // if [built-in] unit not available
2576 SC_log(LOG_INFO
, "Interface not assigned [built-in] unit %@", unit
);
2582 #if !TARGET_OS_IPHONE
2585 blockNewInterfaces() &&
2586 !_SCNetworkInterfaceIsApplePreconfigured(interface
) &&
2587 isConsoleLocked()) {
2590 // if new interface and console locked, ignore
2591 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
2592 SC_log(LOG_NOTICE
, "Console locked, network interface ignored");
2593 SC_log(LOG_INFO
, " path = %@, addr = %@",
2595 (addr
!= NULL
) ? addr
: CFSTR("?"));
2596 watchLockedInterface(interface
);
2599 #endif // !TARGET_OS_IPHONE
2602 // not built-in (or built-in unit not available), allocate from
2603 // the non-reserved slots
2604 next_unit
= builtinCount(if_list
, n
, type
);
2606 unit
= getHighestUnitForType(type
);
2610 CFNumberGetValue(unit
, kCFNumberIntType
, &high_unit
);
2611 if (high_unit
>= next_unit
) {
2612 next_unit
= high_unit
+ 1;
2616 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
2619 SC_log(LOG_INFO
, "Interface assigned unit %@ (%s)",
2621 is_builtin
? "built-in" : "next available");
2626 #ifdef USE_REGISTRY_ENTRY_ID
2627 kr
= registerInterfaceWithIORegistryEntryID(S_connect
,
2630 (dbdict
== NULL
) ? kIONetworkStackRegisterInterfaceWithLowestUnit
2631 : kIONetworkStackRegisterInterfaceWithUnit
);
2632 new_interface
= copyNamedInterfaceForIORegistryEntryID(entryID
);
2633 #else // USE_REGISTRY_ENTRY_ID
2634 kr
= registerInterfaceWithIOServicePath(S_connect
,
2637 (dbdict
== NULL
) ? kRegisterInterface
2638 : kRegisterInterfaceWithFixedUnit
);
2639 new_interface
= copyNamedInterfaceForIOKitPath(path
);
2640 #endif // USE_REGISTRY_ENTRY_ID
2641 if (new_interface
== NULL
) {
2642 const char *signature
;
2644 signature
= (dbdict
== NULL
) ? "failed to name new interface"
2645 : "failed to name known interface";
2647 SC_log(LOG_NOTICE
, "%s, kr=0x%x\n"
2657 displayInterface(interface
);
2659 if ((dbdict
!= NULL
) && (retries
++ < 5)) {
2660 usleep(50 * 1000); // sleep 50ms between attempts
2665 CFNumberRef new_unit
;
2668 SC_log(LOG_INFO
, "%s interface named after %d %s\n"
2671 (dbdict
== NULL
) ? "New" : "Known",
2673 (retries
== 1) ? "try" : "tries",
2677 #ifdef SHOW_NAMING_FAILURE
2678 str
= CFStringCreateWithFormat(NULL
,
2680 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
2681 (dbdict
== NULL
) ? "New" : "Known",
2683 (retries
== 1) ? "try" : "tries",
2685 CFUserNotificationDisplayNotice(0,
2686 kCFUserNotificationStopAlertLevel
,
2691 CFSTR("Please report repeated failures."),
2694 #endif // SHOW_NAMING_FAILURE
2697 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
2698 if (!CFEqual(unit
, new_unit
)) {
2699 SC_log(LOG_INFO
, "interface type %@ assigned unit %@ instead of %@",
2700 type
, new_unit
, unit
);
2703 displayInterface(new_interface
);
2705 // update if_list (with the interface name & unit)
2706 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
2707 CFRelease(new_interface
);
2708 interface
= new_interface
; // if_list holds the reference
2710 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
2713 // update the list of [built-in] interfaces that were previously named
2714 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
2715 SC_log(LOG_DEBUG
, " and updated database (new address)");
2716 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
2719 replaceInterface(interface
);
2727 #if !TARGET_OS_IPHONE
2731 static Boolean isRecovery
= FALSE
;
2732 static dispatch_once_t once
;
2735 * We check to see if the UserEventAgent daemon is present. If not, then
2736 * we are most likely booted into the Recovery OS with no "SCMonitor"
2737 * [UserEventAgent] plugin.
2739 dispatch_once(&once
, ^{
2740 if ((access("/usr/libexec/UserEventAgent", X_OK
) == -1) && (errno
== ENOENT
)) {
2750 updateNetworkConfiguration(CFArrayRef if_list
)
2752 Boolean do_commit
= FALSE
;
2755 SCPreferencesRef prefs
= NULL
;
2756 SCNetworkSetRef set
= NULL
;
2758 prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":updateNetworkConfiguration"), NULL
);
2759 if (prefs
== NULL
) {
2760 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
2764 set
= SCNetworkSetCopyCurrent(prefs
);
2766 SC_log(LOG_INFO
, "No current set, adding default");
2767 set
= _SCNetworkSetCreateDefault(prefs
);
2769 SC_log(LOG_NOTICE
, "_SCNetworkSetCreateDefault() failed: %s", SCErrorString(SCError()));
2774 n
= (if_list
!= NULL
) ? CFArrayGetCount(if_list
) : 0;
2775 for (i
= 0; i
< n
; i
++) {
2776 SCNetworkInterfaceRef interface
;
2778 interface
= CFArrayGetValueAtIndex(if_list
, i
);
2779 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set
, interface
)) {
2780 SC_log(LOG_INFO
, "adding default configuration for %@",
2781 SCNetworkInterfaceGetBSDName(interface
));
2789 ok
= SCPreferencesCommitChanges(prefs
);
2791 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
2795 ok
= SCPreferencesApplyChanges(prefs
);
2797 SC_log(LOG_NOTICE
, "SCPreferencesApplyChanges() failed: %s", SCErrorString(SCError()));
2809 if (prefs
!= NULL
) {
2816 #endif // !TARGET_OS_IPHONE
2819 sharePreconfigured()
2823 n
= (S_preconfigured
!= NULL
) ? CFArrayGetCount(S_preconfigured
) : 0;
2825 CFMutableArrayRef preconfigured
;
2827 preconfigured
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2829 for (CFIndex i
= 0; i
< n
; i
++) {
2830 CFStringRef bsdName
;
2831 CFDataRef watched
= CFArrayGetValueAtIndex(S_preconfigured
, i
);
2832 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2834 bsdName
= SCNetworkInterfaceGetBSDName(watchedInfo
->interface
);
2835 CFArrayAppendValue(preconfigured
, bsdName
);
2838 CFDictionarySetValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
, preconfigured
);
2839 CFRelease(preconfigured
);
2841 CFDictionaryRemoveValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
);
2850 preconfiguredInterfaceUpdated(CFDataRef watched
, natural_t messageType
, void *messageArgument
)
2852 Boolean updated
= FALSE
;
2853 WatchedInfo
*watchedInfo
= (WatchedInfo
*)(void *)CFDataGetBytePtr(watched
);
2855 #pragma unused(messageArgument)
2856 switch (messageType
) {
2857 case kIOMessageServiceIsTerminated
: { // if [locked] interface yanked
2858 SC_log(LOG_INFO
, "[pre-configured] interface removed: %@",
2859 SCNetworkInterfaceGetBSDName(watchedInfo
->interface
));
2861 if (S_preconfigured
!= NULL
) {
2863 CFIndex n
= CFArrayGetCount(S_preconfigured
);
2865 i
= CFArrayGetFirstIndexOfValue(S_preconfigured
, CFRangeMake(0, n
), watched
);
2866 if (i
!= kCFNotFound
) {
2867 CFArrayRemoveValueAtIndex(S_preconfigured
, i
);
2868 if (CFArrayGetCount(S_preconfigured
) == 0) {
2869 CFRelease(S_preconfigured
);
2870 S_preconfigured
= NULL
;
2884 sharePreconfigured();
2891 updatePreConfiguredInterfaces(CFArrayRef interfaces
)
2894 Boolean updated
= FALSE
;
2896 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
2897 for (CFIndex i
= 0; i
< n
; i
++) {
2898 SCNetworkInterfaceRef interface
;
2900 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2901 if (_SCNetworkInterfaceIsApplePreconfigured(interface
)) {
2904 watched
= watcherCreate(interface
, preconfiguredInterfaceUpdated
);
2905 if (watched
!= NULL
) {
2906 SC_log(LOG_INFO
, "watching [pre-configured] interface: %@",
2907 SCNetworkInterfaceGetBSDName(interface
));
2909 if (S_preconfigured
== NULL
) {
2910 S_preconfigured
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2912 CFArrayAppendValue(S_preconfigured
, watched
);
2919 sharePreconfigured();
2928 if (S_connect
== MACH_PORT_NULL
) {
2929 // if we don't have the "IONetworkStack" connect object
2933 if (S_iflist
!= NULL
) {
2936 n
= CFArrayGetCount(S_iflist
);
2938 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
2940 nameInterfaces(S_iflist
);
2944 * Update the list of [Apple] pre-configured interfaces
2946 updatePreConfiguredInterfaces(S_iflist
);
2948 #if TARGET_OS_IPHONE
2950 * Update the list of "trust required" interfaces
2952 updateTrustRequiredInterfaces(S_iflist
);
2953 #endif // TARGET_OS_IPHONE
2957 * The registry [matching] has quiesced so let's
2958 * - save the DB with the interfaces that have been named
2959 * - update the VLAN/BOND configuration
2960 * - tell everyone that we've finished (at least for now)
2961 * - log those interfaces which are no longer present
2962 * in the HW config (or have yet to show up).
2964 writeInterfaceList(S_dblist
);
2965 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
2967 #if !TARGET_OS_IPHONE
2968 if (isRecoveryOS()) {
2970 * We are most likely booted into the Recovery OS with no "SCMonitor"
2971 * UserEventAgent plugin running so let's make sure we update the
2972 * network configuration for new interfaces.
2974 updateNetworkConfiguration(S_iflist
);
2976 #endif // !TARGET_OS_IPHONE
2980 if (S_iflist
!= NULL
) {
2981 CFRelease(S_iflist
);
2985 if (S_prev_active_list
!= NULL
) {
2989 n
= CFArrayGetCount(S_prev_active_list
);
2991 SC_log(LOG_INFO
, "Interface%s not [yet] active",
2992 (n
> 1) ? "s" : "");
2994 for (i
= 0; i
< n
; i
++) {
2995 CFDictionaryRef if_dict
;
3000 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
3001 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
3002 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
3003 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
3004 SC_log(LOG_INFO
, " %s%@%sType: %@, Unit: %@",
3005 (name
!= NULL
) ? "BSD Name: " : "",
3006 (name
!= NULL
) ? name
: CFSTR(""),
3007 (name
!= NULL
) ? ", " : "",
3012 CFRelease(S_prev_active_list
);
3013 S_prev_active_list
= NULL
;
3016 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
3018 * if we've named all of the interfaces that
3019 * were used during the previous boot.
3021 addTimestamp(S_state
, CFSTR("*RELEASE*"));
3022 SC_log(LOG_INFO
, "last boot interfaces have been named");
3024 CFRelease(S_prev_active_list
);
3025 S_prev_active_list
= NULL
;
3033 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
3035 #pragma unused(refcon)
3036 os_activity_t activity
;
3039 activity
= os_activity_create("process new network interface",
3040 OS_ACTIVITY_CURRENT
,
3041 OS_ACTIVITY_FLAG_DEFAULT
);
3042 os_activity_scope(activity
);
3044 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
3045 SCNetworkInterfaceRef interface
;
3047 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
3048 if (interface
!= NULL
) {
3049 if (S_iflist
== NULL
) {
3050 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3052 CFArrayAppendValue(S_iflist
, interface
);
3053 CFRelease(interface
);
3055 IOObjectRelease(obj
);
3060 os_release(activity
);
3066 * Function: stackCallback
3068 * Get a reference to the single IONetworkStack object instance in
3069 * the kernel. Naming requests must be sent to this object, which is
3070 * attached as a client to all network interface objects in the system.
3072 * Call IOObjectRelease on the returned object.
3075 stackCallback(void *refcon
, io_iterator_t iter
)
3077 #pragma unused(refcon)
3078 os_activity_t activity
;
3082 activity
= os_activity_create("process IONetworkStack",
3083 OS_ACTIVITY_CURRENT
,
3084 OS_ACTIVITY_FLAG_DEFAULT
);
3085 os_activity_scope(activity
);
3087 stack
= IOIteratorNext(iter
);
3088 if (stack
== MACH_PORT_NULL
) {
3092 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
3093 if (kr
!= KERN_SUCCESS
) {
3094 SC_log(LOG_ERR
, "IOServiceOpen returned 0x%x", kr
);
3098 addTimestamp(S_state
, CFSTR("*STACK*"));
3099 SC_log(LOG_INFO
, "IONetworkStack found");
3101 if (S_stack
!= MACH_PORT_NULL
) {
3102 IOObjectRelease(S_stack
);
3103 S_stack
= MACH_PORT_NULL
;
3106 if ((S_timer
!= NULL
) && CFRunLoopTimerIsValid(S_timer
)) {
3107 // With the IONetworkStack object now available we can
3108 // reset (shorten?) the time we are willing to wait for
3109 // IOKit to quiesce.
3110 CFRunLoopTimerSetNextFireDate(S_timer
,
3111 CFAbsoluteTimeGetCurrent() + S_quiet_timeout
);
3118 if (stack
!= MACH_PORT_NULL
) {
3119 IOObjectRelease(stack
);
3122 os_release(activity
);
3128 quietCallback(void *refcon
,
3129 io_service_t service
,
3130 natural_t messageType
,
3131 void *messageArgument
)
3133 #pragma unused(refcon)
3134 #pragma unused(service)
3135 os_activity_t activity
;
3137 if (messageArgument
!= NULL
) {
3142 activity
= os_activity_create("process IOKit quiet",
3143 OS_ACTIVITY_CURRENT
,
3144 OS_ACTIVITY_FLAG_DEFAULT
);
3145 os_activity_scope(activity
);
3147 if (messageType
== kIOMessageServiceBusyStateChange
) {
3148 addTimestamp(S_state
, kInterfaceNamerKey_Quiet
);
3149 SC_log(LOG_INFO
, "IOKit quiet");
3152 if (S_connect
== MACH_PORT_NULL
) {
3153 SC_log(LOG_ERR
, "No network stack object");
3157 if (S_quiet
!= MACH_PORT_NULL
) {
3158 IOObjectRelease(S_quiet
);
3159 S_quiet
= MACH_PORT_NULL
;
3162 if (S_timer
!= NULL
) {
3163 CFRunLoopTimerInvalidate(S_timer
);
3168 // grab (and name) any additional interfaces.
3169 interfaceArrivalCallback((void *)S_notify
, S_iter
);
3171 if (messageType
== kIOMessageServiceBusyStateChange
) {
3172 addTimestamp(S_state
, CFSTR("*QUIET&NAMED*"));
3178 os_release(activity
);
3184 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, int *count
)
3186 kern_return_t kr
= kIOReturnSuccess
;;
3189 while ((kr
== kIOReturnSuccess
) &&
3190 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
3191 uint64_t accumulated_busy_time
;
3192 uint32_t busy_state
;
3195 CFMutableArrayRef newNodes
;
3197 CFMutableStringRef str
= NULL
;
3199 if (nodes
== NULL
) {
3200 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3202 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
3204 assert(newNodes
!= NULL
);
3206 kr
= IORegistryEntryGetName(obj
, name
);
3207 if (kr
!= kIOReturnSuccess
) {
3208 SC_log(LOG_NOTICE
, "IORegistryEntryGetName() returned 0x%x", kr
);
3212 str
= CFStringCreateMutable(NULL
, 0);
3213 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
3215 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
3217 case kIOReturnSuccess
:
3218 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
3219 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
3221 case kIOReturnNotFound
:
3224 SC_log(LOG_NOTICE
, "IORegistryEntryGetLocationInPlane() returned 0x%x", kr
);
3229 CFArrayAppendValue(newNodes
, str
);
3232 kr
= IOServiceGetBusyStateAndTime(obj
, &state
, &busy_state
, &accumulated_busy_time
);
3233 if (kr
!= kIOReturnSuccess
) {
3234 SC_log(LOG_NOTICE
, "IOServiceGetBusyStateAndTime() returned 0x%x", kr
);
3238 #ifdef TEST_SNAPSHOT
3241 #endif // TEST_SNAPSHOT
3243 if (busy_state
!= 0) {
3246 if ((*count
)++ == 0) {
3247 SC_log(LOG_ERR
, "Busy services :");
3250 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
3251 SC_log(LOG_ERR
, " %@ [%s%s%s%d, %lld ms]",
3253 (state
& kIOServiceRegisteredState
) ? "" : "!registered, ",
3254 (state
& kIOServiceMatchedState
) ? "" : "!matched, ",
3255 (state
& kIOServiceInactiveState
) ? "inactive, " : "",
3257 accumulated_busy_time
/ kMillisecondScale
);
3261 kr
= IORegistryIteratorEnterEntry(iterator
);
3262 if (kr
!= kIOReturnSuccess
) {
3263 SC_log(LOG_NOTICE
, "IORegistryIteratorEnterEntry() returned 0x%x", kr
);
3267 iterateRegistryBusy(iterator
, newNodes
, count
);
3269 kr
= IORegistryIteratorExitEntry(iterator
);
3270 if (kr
!= kIOReturnSuccess
) {
3271 SC_log(LOG_NOTICE
, "IORegistryIteratorExitEntry() returned 0x%x", kr
);
3276 CFRelease(newNodes
);
3277 IOObjectRelease(obj
);
3287 io_iterator_t iterator
= MACH_PORT_NULL
;
3290 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
3294 if (kr
!= kIOReturnSuccess
) {
3295 SC_log(LOG_NOTICE
, "IORegistryCreateIterator() returned 0x%x", kr
);
3299 iterateRegistryBusy(iterator
, NULL
, &count
);
3301 SC_log(LOG_ERR
, "w/no busy services");
3304 IOObjectRelease(iterator
);
3308 timerCallback(CFRunLoopTimerRef timer
, void *info
)
3310 #pragma unused(timer)
3311 #pragma unused(info)
3312 os_activity_t activity
;
3314 activity
= os_activity_create("process IOKit timer",
3315 OS_ACTIVITY_CURRENT
,
3316 OS_ACTIVITY_FLAG_DEFAULT
);
3317 os_activity_scope(activity
);
3319 // We've been waiting for IOKit to quiesce and it just
3320 // hasn't happenned. Time to just move on!
3321 addTimestamp(S_state
, kInterfaceNamerKey_Timeout
);
3324 SC_log(LOG_ERR
, "timed out waiting for IOKit to quiesce");
3327 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
3329 addTimestamp(S_state
, CFSTR("*TIMEOUT&NAMED*"));
3332 os_release(activity
);
3338 setup_IOKit(CFBundleRef bundle
)
3340 #pragma unused(bundle)
3343 mach_port_t masterPort
= MACH_PORT_NULL
;
3345 io_object_t root
= MACH_PORT_NULL
;
3347 // read DB of previously named network interfaces
3348 S_dblist
= readInterfaceList();
3349 if (S_dblist
!= NULL
) {
3352 n
= CFArrayGetCount(S_dblist
);
3354 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
3358 // get interfaces that were named during the last boot
3359 S_prev_active_list
= previouslyActiveInterfaces();
3361 // track how long we've waited to see each interface.
3362 S_state
= CFDictionaryCreateMutable(NULL
,
3364 &kCFTypeDictionaryKeyCallBacks
,
3365 &kCFTypeDictionaryValueCallBacks
);
3366 addTimestamp(S_state
, CFSTR("*START*"));
3368 // Creates and returns a notification object for receiving IOKit
3369 // notifications of new devices or state changes.
3370 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
3371 if (kr
!= KERN_SUCCESS
) {
3372 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
3376 S_notify
= IONotificationPortCreate(masterPort
);
3377 if (S_notify
== NULL
) {
3378 SC_log(LOG_ERR
, "IONotificationPortCreate failed");
3382 // watch IOKit matching activity
3383 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
3384 if (root
== MACH_PORT_NULL
) {
3385 SC_log(LOG_ERR
, "IORegistryEntryFromPath failed");
3389 kr
= IOServiceAddInterestNotification(S_notify
,
3393 (void *)S_notify
, // refCon
3394 &S_quiet
); // notification
3395 if (kr
!= KERN_SUCCESS
) {
3396 SC_log(LOG_ERR
, "IOServiceAddInterestNotification returned 0x%x", kr
);
3400 kr
= IOServiceGetBusyState(root
, &busy
);
3401 if (kr
!= KERN_SUCCESS
) {
3402 SC_log(LOG_ERR
, "IOServiceGetBusyState returned 0x%x", kr
);
3406 // add a timer so we don't wait forever for IOKit to quiesce
3407 S_timer
= CFRunLoopTimerCreate(NULL
,
3408 CFAbsoluteTimeGetCurrent() + S_stack_timeout
,
3414 if (S_timer
== NULL
) {
3415 SC_log(LOG_ERR
, "CFRunLoopTimerCreate failed");
3419 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
3421 // watch for the introduction of the IONetworkStack
3422 kr
= IOServiceAddMatchingNotification(S_notify
,
3423 kIOFirstMatchNotification
,
3424 IOServiceMatching("IONetworkStack"),
3426 (void *)S_notify
, // refCon
3427 &S_stack
); // notification
3428 if (kr
!= KERN_SUCCESS
) {
3429 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
3433 // check and see if the stack is already available and arm the
3434 // notification for its introduction.
3435 stackCallback((void *)S_notify
, S_stack
);
3437 // watch for the introduction of new network interfaces
3438 kr
= IOServiceAddMatchingNotification(S_notify
,
3439 kIOFirstMatchNotification
,
3440 IOServiceMatching("IONetworkInterface"),
3441 &interfaceArrivalCallback
,
3442 (void *)S_notify
, // refCon
3443 &S_iter
); // notification
3444 if (kr
!= KERN_SUCCESS
) {
3445 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
3449 // Get the current list of matches and arm the notification for
3450 // future interface arrivals.
3451 interfaceArrivalCallback((void *)S_notify
, S_iter
);
3453 // Check if IOKit has already quiesced.
3454 quietCallback((void *)S_notify
,
3456 kIOMessageServiceBusyStateChange
,
3457 (void *)(uintptr_t)busy
);
3459 CFRunLoopAddSource(CFRunLoopGetCurrent(),
3460 IONotificationPortGetRunLoopSource(S_notify
),
3461 kCFRunLoopDefaultMode
);
3463 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
3465 * Start the wheels turning until we've named all of
3466 * the interfaces that were used during the previous
3467 * boot, until IOKit [matching] has quiesced, or
3468 * until we've waited long enough.
3470 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
3471 CFRunLoopAddSource(CFRunLoopGetCurrent(),
3472 IONotificationPortGetRunLoopSource(S_notify
),
3474 while (S_prev_active_list
!= NULL
) {
3477 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
3479 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
3482 if (S_dblist
!= NULL
) {
3483 // apply special handling for the BT-PAN interface (if present)
3484 CFArrayApplyFunction(S_dblist
,
3485 CFRangeMake(0, CFArrayGetCount(S_dblist
)),
3486 updateBTPANInformation
,
3489 #endif // TARGET_OS_OSX
3494 if (root
!= MACH_PORT_NULL
) {
3495 IOObjectRelease(root
);
3497 if (masterPort
!= MACH_PORT_NULL
) {
3498 mach_port_deallocate(mach_task_self(), masterPort
);
3505 setup_Virtual(CFBundleRef bundle
)
3507 #pragma unused(bundle)
3508 // open a SCPreferences session
3509 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
":setup_Virtual"), NULL
);
3510 if (S_prefs
== NULL
) {
3511 SC_log(LOG_ERR
, "SCPreferencesCreate() failed: %s",
3512 SCErrorString(SCError()));
3516 // register for change notifications.
3517 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
3518 SC_log(LOG_ERR
, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
3524 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
3525 if (SCError() != kSCStatusNoStoreServer
) {
3526 SC_log(LOG_ERR
, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
3536 exec_InterfaceNamer(void *arg
)
3538 CFBundleRef bundle
= (CFBundleRef
)arg
;
3539 CFDictionaryRef dict
;
3541 pthread_setname_np(MY_PLUGIN_NAME
" thread");
3543 dict
= CFBundleGetInfoDictionary(bundle
);
3544 if (isA_CFDictionary(dict
)) {
3547 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_STACK_TIMEOUT_KEY
));
3549 if (!isA_CFNumber(num
) ||
3550 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_stack_timeout
) ||
3551 (S_stack_timeout
<= 0.0)) {
3552 SC_log(LOG_NOTICE
, WAIT_STACK_TIMEOUT_KEY
" value error");
3553 S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
3557 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
3559 if (!isA_CFNumber(num
) ||
3560 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_quiet_timeout
) ||
3561 (S_quiet_timeout
<= 0.0)) {
3562 SC_log(LOG_NOTICE
, WAIT_QUIET_TIMEOUT_KEY
" value error");
3563 S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
3568 // setup virtual network interface monitoring
3569 if (!setup_Virtual(bundle
)) {
3573 // setup [IOKit] network interface monitoring
3574 if (!setup_IOKit(bundle
)) {
3581 if (S_connect
!= MACH_PORT_NULL
) {
3582 IOServiceClose(S_connect
);
3583 S_connect
= MACH_PORT_NULL
;
3585 if (S_dblist
!= NULL
) {
3586 CFRelease(S_dblist
);
3589 if (S_iter
!= MACH_PORT_NULL
) {
3590 IOObjectRelease(S_iter
);
3591 S_iter
= MACH_PORT_NULL
;
3593 if (S_notify
!= MACH_PORT_NULL
) {
3594 IONotificationPortDestroy(S_notify
);
3596 if (S_quiet
!= MACH_PORT_NULL
) {
3597 IOObjectRelease(S_quiet
);
3598 S_quiet
= MACH_PORT_NULL
;
3600 if (S_stack
!= MACH_PORT_NULL
) {
3601 IOObjectRelease(S_stack
);
3602 S_stack
= MACH_PORT_NULL
;
3604 if (S_state
!= NULL
) {
3608 if (S_timer
!= NULL
) {
3609 CFRunLoopTimerInvalidate(S_timer
);
3623 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
3625 #pragma unused(bundleVerbose)
3626 pthread_attr_t tattr
;
3629 CFRetain(bundle
); // released in exec_InterfaceNamer
3631 pthread_attr_init(&tattr
);
3632 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
3633 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
3634 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
3635 pthread_create(&tid
, &tattr
, exec_InterfaceNamer
, bundle
);
3636 pthread_attr_destroy(&tattr
);
3641 //------------------------------------------------------------------------
3645 main(int argc
, char ** argv
)
3650 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
3652 bundle
= CFBundleGetMainBundle();
3653 CFRetain(bundle
); // released in exec_InterfaceNamer
3655 (void)exec_InterfaceNamer();
3663 #ifdef TEST_SNAPSHOT
3665 main(int argc
, char ** argv
)
3667 CFStringRef snapshot
;
3670 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
3672 snapshot
= captureBusy();
3673 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), snapshot
);
3674 CFRelease(snapshot
);
3679 #endif /* TEST_SNAPSHOT */