2 * Copyright (c) 2001-2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * May 20, 2006 Joe Liu <joe.liu@apple.com>
28 * Allan Nathanson <ajn@apple.com>
29 * - register interface by entryID (and not path)
31 * November 6, 2006 Allan Nathanson <ajn@apple.com>
32 * Dan Markarian <markarian@apple.com>
33 * Dieter Siegmund <dieter@apple.com>
34 * - updated code to name interfaces quicker (without need for
35 * calling IOKitWaitQuiet).
37 * October 3, 2003 Allan Nathanson <ajn@apple.com>
38 * - sort new interfaces by IOKit path (rather than MAC address) to
39 * help facilitate a more predictable interface-->name mapping for
40 * like hardware configurations.
42 * June 23, 2001 Allan Nathanson <ajn@apple.com>
43 * - update to public SystemConfiguration.framework APIs
45 * January 23, 2001 Dieter Siegmund <dieter@apple.com>
51 * - module that receives IOKit Network Interface messages
52 * and names any interface that currently does not have a name
53 * - uses Interface Type and MACAddress as the unique identifying
54 * keys; any interface that doesn't contain both of these properties
55 * is ignored and not processed
56 * - stores the Interface Type, MACAddress, and Unit in permanent storage
57 * to give persistent interface names
65 #include <sys/ioctl.h>
67 #include <sys/sysctl.h>
68 #include <sys/param.h>
69 #include <mach/mach.h>
70 #include <net/ethernet.h>
71 #include <net/if_types.h>
74 #include <CommonCrypto/CommonDigest.h>
76 #include <CoreFoundation/CoreFoundation.h>
78 #define SC_LOG_HANDLE __log_InterfaceNamer()
79 #include <SystemConfiguration/SystemConfiguration.h>
80 #include <SystemConfiguration/SCDPlugin.h>
81 #include <SystemConfiguration/SCPrivate.h>
82 #include <SystemConfiguration/SCValidation.h>
83 #include "plugin_shared.h"
85 #include <IOKit/IOKitLib.h>
86 #include <IOKit/IOKitLibPrivate.h>
87 #include <IOKit/IOBSD.h>
88 #include <IOKit/IOMessage.h>
89 #include <IOKit/network/IONetworkController.h>
90 #include <IOKit/network/IONetworkInterface.h>
91 #include <IOKit/network/IONetworkStack.h>
92 #include <IOKit/usb/USB.h>
94 #ifdef kIONetworkStackUserCommandKey
95 #define USE_REGISTRY_ENTRY_ID
98 #ifndef USE_REGISTRY_ENTRY_ID
99 // from <IOKit/network/IONetworkStack.h>
100 #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand"
102 kRegisterInterfaceWithFixedUnit
= 0,
104 kRegisterAllInterfaces
106 #endif // !USE_REGISTRY_ENTRY_ID
108 #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo"
109 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
110 #define kSCNetworkInterfaceActive "Active"
112 #define MY_PLUGIN_NAME "InterfaceNamer"
113 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
115 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
116 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
118 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
119 #define WAIT_QUIET_TIMEOUT_DEFAULT 60.0
123 * "IONetworkStack" connect object used to "name" an interface.
125 static io_connect_t S_connect
= MACH_PORT_NULL
;
129 * An array of CFDictionary's representing the interfaces
130 * that have been identified and [need to be] named.
132 static CFMutableArrayRef S_dblist
= NULL
;
136 * An array of SCNetworkInterface's representing the
137 * interfaces that have been identified.
139 static CFMutableArrayRef S_iflist
= NULL
;
143 * IOServiceAddMatchingNotification object used to watch for
144 * new network interfaces.
146 static io_iterator_t S_iter
= MACH_PORT_NULL
;
150 * notification object for receiving IOKit notifications of
151 * new devices or state changes.
153 static IONotificationPortRef S_notify
= NULL
;
155 /* S_prev_active_list
156 * An array of CFDictionary's representing the previously
159 static CFMutableArrayRef S_prev_active_list
= NULL
;
163 * IOServiceAddInterestNotification object used to watch for
164 * IOKit matching to quiesce.
166 static io_object_t S_quiet
= MACH_PORT_NULL
;
170 * IOServiceAddMatchingNotification object used to watch for
171 * the availability of the "IONetworkStack" object.
173 static io_iterator_t S_stack
= MACH_PORT_NULL
;
177 * A dictionary containing Information about each network
178 * interface. For now, the key is the BSD name and the
179 * value is a CFNumber noting how long (in milliseconds)
180 * it took for the interface to be recognized/named.
182 static CFMutableDictionaryRef S_state
= NULL
;
186 * CFRunLoopTimer tracking how long we are willing to wait
187 * for IOKit matching to quiesce (IOKitWaitQuiet).
190 * time to wait for the IONetworkStack object to appear before timeout
193 * time to wait for the IOKit to quiesce (after the IONetworkStack is
196 static CFRunLoopTimerRef S_timer
= NULL
;
197 static double S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
198 static double S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
201 * Virtual network interface configuration
202 * S_prefs : SCPreferences to configuration
203 * S_bonds : most recently actived Bond configuration
204 * S_bridges : most recently actived Bridge configuration
205 * S_vlans : most recently actived VLAN configuration
207 static SCPreferencesRef S_prefs
= NULL
;
208 static CFArrayRef S_bonds
= NULL
;
209 static CFArrayRef S_bridges
= NULL
;
210 static CFArrayRef S_vlans
= NULL
;
216 __log_InterfaceNamer()
218 static os_log_t log
= NULL
;
221 log
= os_log_create("com.apple.SystemConfiguration", "InterfaceNamer");
229 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
234 now
= CFAbsoluteTimeGetCurrent();
235 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
236 CFDictionaryAddValue(dict
, key
, val
);
241 #define INTERFACES CFSTR("Interfaces")
242 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
244 static CFComparisonResult
245 if_unit_compare(const void *val1
, const void *val2
, void *context
)
247 CFComparisonResult res
;
253 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
254 CFSTR(kIOInterfaceType
));
255 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
256 CFSTR(kIOInterfaceType
));
257 res
= CFNumberCompare(type1
, type2
, NULL
);
258 if (res
!= kCFCompareEqualTo
) {
261 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
262 CFSTR(kIOInterfaceUnit
));
263 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
264 CFSTR(kIOInterfaceUnit
));
265 return (CFNumberCompare(unit1
, unit2
, NULL
));
269 writeInterfaceList(CFArrayRef if_list
)
272 CFStringRef new_model
;
273 CFStringRef old_model
;
274 SCPreferencesRef prefs
;
276 if (isA_CFArray(if_list
) == NULL
) {
280 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
282 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
286 cur_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
287 if (_SC_CFEqual(cur_list
, if_list
)) {
291 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
292 new_model
= _SC_hw_model(FALSE
);
293 if ((new_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
295 if ((old_model
!= NULL
) && (cur_list
!= NULL
)) {
298 // if interface list was created on other hardware
299 history
= CFStringCreateWithFormat(NULL
, NULL
,
303 SCPreferencesSetValue(prefs
, history
, cur_list
);
306 SC_log(LOG_NOTICE
, "Hardware model changed\n"
307 " created on \"%@\"\n"
313 SCPreferencesSetValue(prefs
, MODEL
, new_model
);
316 SCPreferencesSetValue(prefs
, INTERFACES
, if_list
);
318 if (!SCPreferencesCommitChanges(prefs
)) {
319 if (SCError() != EROFS
) {
320 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
331 static CFPropertyListRef
332 restoreNIPrefsFromBackup(SCPreferencesRef prefs
, CFStringRef current_model
)
334 CFPropertyListRef if_list
;
337 key
= CFStringCreateWithFormat(NULL
, 0, CFSTR("%@:%@"), INTERFACES
, current_model
);
338 if_list
= SCPreferencesGetValue(prefs
, key
);
339 if_list
= isA_CFArray(if_list
);
340 if (if_list
!= NULL
) {
341 /* Write the previously backed up Interface list for this hardware */
342 writeInterfaceList(if_list
);
344 /* Synchronize the prefs */
345 SCPreferencesSynchronize(prefs
);
347 /* Re-fetch the interface list */
348 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
349 if_list
= isA_CFArray(if_list
);
350 if (if_list
!= NULL
) {
351 /* We do not need the old interface list any more */
352 SCPreferencesRemoveValue(prefs
, key
);
353 if (!SCPreferencesCommitChanges(prefs
)) {
354 if (SCError() != EROFS
) {
355 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
366 static CF_RETURNS_RETAINED CFMutableArrayRef
370 CFStringRef old_model
;
371 CFMutableArrayRef plist
= NULL
;
372 SCPreferencesRef prefs
= NULL
;
374 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
376 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
380 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
381 if_list
= isA_CFArray(if_list
);
383 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
384 if (old_model
!= NULL
) {
385 CFStringRef new_model
;
387 new_model
= _SC_hw_model(FALSE
);
388 if (!_SC_CFEqual(old_model
, new_model
)) {
389 /* if interface list was created on other hardware,
390 Restore if a backup interface list is present */
391 if_list
= restoreNIPrefsFromBackup(prefs
, new_model
);
395 if (if_list
!= NULL
) {
397 CFIndex n
= CFArrayGetCount(if_list
);
399 plist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
400 for (i
= 0; i
< n
; i
++) {
401 CFDictionaryRef dict
;
403 dict
= CFArrayGetValueAtIndex(if_list
, i
);
404 if (isA_CFDictionary(dict
) &&
405 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceType
)) &&
406 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
407 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
408 CFArrayAppendValue(plist
, dict
);
419 static CF_RETURNS_RETAINED CFMutableArrayRef
420 previouslyActiveInterfaces()
422 CFMutableArrayRef active
;
426 if (S_dblist
== NULL
) {
430 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
432 n
= CFArrayGetCount(S_dblist
);
433 for (i
= 0; i
< n
; i
++) {
434 CFDictionaryRef if_dict
;
436 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
437 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
438 CFMutableDictionaryRef new_dict
;
440 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
441 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
442 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
443 CFArrayAppendValue(active
, new_dict
);
456 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
),
457 kSCDynamicStoreDomainPlugin
);
458 (void)SCDynamicStoreSetValue(NULL
, key
, S_state
);
464 #if !TARGET_OS_IPHONE
466 updateBondInterfaceConfiguration(SCPreferencesRef prefs
)
468 CFArrayRef interfaces
;
470 interfaces
= SCBondInterfaceCopyAll(prefs
);
471 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
472 CFRelease(interfaces
);
476 if (_SC_CFEqual(S_bonds
, interfaces
)) {
478 if (interfaces
!= NULL
) CFRelease(interfaces
);
482 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
483 S_bonds
= interfaces
;
485 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
486 SC_log(LOG_NOTICE
, "_SCBondInterfaceUpdateConfiguration() failed: %s",
487 SCErrorString(SCError()));
492 #endif // !TARGET_OS_IPHONE
495 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs
)
497 CFArrayRef interfaces
;
499 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
500 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
501 CFRelease(interfaces
);
505 if (_SC_CFEqual(S_bridges
, interfaces
)) {
507 if (interfaces
!= NULL
) CFRelease(interfaces
);
511 if (S_bridges
!= NULL
) CFRelease(S_bridges
);
512 S_bridges
= interfaces
;
514 if (!_SCBridgeInterfaceUpdateConfiguration(prefs
)) {
515 SC_log(LOG_NOTICE
, "_SCBridgeInterfaceUpdateConfiguration() failed: %s",
516 SCErrorString(SCError()));
523 updateVLANInterfaceConfiguration(SCPreferencesRef prefs
)
525 CFArrayRef interfaces
;
527 interfaces
= SCVLANInterfaceCopyAll(prefs
);
528 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
529 CFRelease(interfaces
);
533 if (_SC_CFEqual(S_vlans
, interfaces
)) {
535 if (interfaces
!= NULL
) CFRelease(interfaces
);
539 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
540 S_vlans
= interfaces
;
542 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
543 SC_log(LOG_NOTICE
, "_SCVLANInterfaceUpdateConfiguration() failed: %s",
544 SCErrorString(SCError()));
551 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
552 SCPreferencesNotification notificationType
,
555 os_activity_t activity
;
557 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
561 activity
= os_activity_create("check/update virtual network interface configuration",
563 OS_ACTIVITY_FLAG_DEFAULT
);
564 os_activity_scope(activity
);
567 // if a new interface has been "named"
569 if (S_bonds
!= NULL
) {
573 if (S_bridges
!= NULL
) {
574 CFRelease(S_bridges
);
577 if (S_vlans
!= NULL
) {
583 #if !TARGET_OS_IPHONE
584 updateBondInterfaceConfiguration (prefs
);
585 #endif // !TARGET_OS_IPHONE
586 updateBridgeInterfaceConfiguration(prefs
);
587 updateVLANInterfaceConfiguration (prefs
);
589 // we are finished with current prefs, wait for changes
590 SCPreferencesSynchronize(prefs
);
592 os_release(activity
);
597 #if !TARGET_OS_EMBEDDED
600 updateBTPANInformation(const void *value
, void *context
)
603 CFDictionaryRef dict
= (CFDictionaryRef
)value
;
605 CFDictionaryRef info
;
608 if_name
= CFDictionaryGetValue(dict
, CFSTR(kIOBSDNameKey
));
609 if (!isA_CFString(if_name
)) {
614 info
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceInfo
));
615 if (!isA_CFDictionary(info
)) {
616 // if no SCNetworkInterface info
620 name
= CFDictionaryGetValue(info
, kSCPropUserDefinedName
);
621 if (!isA_CFString(name
) || !CFEqual(name
, CFSTR(BT_PAN_NAME
))) {
622 // if not BT-PAN interface
626 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Name
, if_name
);
628 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
629 if (isA_CFData(addr
)) {
630 CFDictionaryAddValue(S_state
, kInterfaceNamerKey_BT_PAN_Mac
, addr
);
635 #endif // !TARGET_OS_EMBEDDED
637 static CFDictionaryRef
638 createInterfaceDict(SCNetworkInterfaceRef interface
)
640 CFMutableDictionaryRef new_if
;
643 new_if
= CFDictionaryCreateMutable(NULL
,
645 &kCFTypeDictionaryKeyCallBacks
,
646 &kCFTypeDictionaryValueCallBacks
);
648 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
650 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
654 val
= _SCNetworkInterfaceGetIOPath(interface
);
656 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
659 val
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
661 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceNamePrefix
), val
);
664 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
666 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
669 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
671 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
674 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
676 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
679 val
= SCNetworkInterfaceGetBSDName(interface
);
681 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
684 val
= SCNetworkInterfaceGetInterfaceType(interface
);
686 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
689 CFDictionarySetValue(new_if
,
691 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
693 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
698 static CFDictionaryRef
699 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
706 if (db_list
== NULL
) {
709 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
710 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
711 if (type
== NULL
|| addr
== NULL
) {
715 n
= CFArrayGetCount(db_list
);
716 for (i
= 0; i
< n
; i
++) {
718 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
721 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
722 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
723 if (t
== NULL
|| a
== NULL
)
726 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
736 static CFDictionaryRef
737 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
744 if (db_list
== NULL
) {
747 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
748 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
749 if (type
== NULL
|| unit
== NULL
) {
753 n
= CFArrayGetCount(db_list
);
754 for (i
= 0; i
< n
; i
++) {
755 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
759 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
760 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
761 if (t
== NULL
|| u
== NULL
) {
765 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
775 CFDictionaryRef match_info
;
776 CFStringRef match_type
;
777 CFBooleanRef match_builtin
;
778 CFMutableArrayRef matches
;
779 } matchContext
, *matchContextRef
;
781 static CF_RETURNS_RETAINED CFDictionaryRef
782 thinInterfaceInfo(CFDictionaryRef info
)
787 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
789 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
790 && (vid
== kIOUSBVendorIDAppleComputer
)) {
791 CFMutableDictionaryRef thin
;
793 // if this is an Apple USB device than we trust that
794 // the non-localized name will be correct.
795 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
796 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
797 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
798 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
802 return CFRetain(info
);
806 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
810 match
= _SC_CFEqual(known_info
, match_info
);
812 isA_CFDictionary(known_info
) &&
813 isA_CFDictionary(match_info
)) {
815 // if not an exact match, try thinning
816 known_info
= thinInterfaceInfo(known_info
);
817 match_info
= thinInterfaceInfo(match_info
);
818 match
= _SC_CFEqual(known_info
, match_info
);
819 if (known_info
!= NULL
) CFRelease(known_info
);
820 if (match_info
!= NULL
) CFRelease(match_info
);
827 matchKnown(const void *value
, void *context
)
829 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
830 matchContextRef match_context
= (matchContextRef
)context
;
832 // match interface type
834 CFStringRef known_type
;
836 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
837 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
842 // match SCNetworkInterfaceInfo
844 CFDictionaryRef known_info
;
846 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
847 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
852 // if requested, match [non-]builtin
853 if (match_context
->match_builtin
!= NULL
) {
854 CFBooleanRef known_builtin
;
856 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
857 if (!isA_CFBoolean(known_builtin
)) {
858 known_builtin
= kCFBooleanFalse
;
860 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
865 // if we have a match
866 if (match_context
->matches
== NULL
) {
867 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
869 CFArrayAppendValue(match_context
->matches
, known_dict
);
875 matchUnnamed(const void *value
, void *context
)
877 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
878 matchContextRef match_context
= (matchContextRef
)context
;
880 if (match_context
->matches
== NULL
) {
884 // match interface type
886 CFStringRef known_type
;
888 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
889 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
894 // match SCNetworkInterfaceInfo
896 CFDictionaryRef known_info
;
899 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
900 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
901 if (known_info
!= NULL
) CFRelease(known_info
);
907 // if requested, match [non-]builtin
908 if (match_context
->match_builtin
!= NULL
) {
909 CFBooleanRef known_builtin
;
911 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
913 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
918 // if we have a match
919 CFRelease(match_context
->matches
);
920 match_context
->matches
= NULL
;
926 interfaceExists(CFStringRef prefix
, CFNumberRef unit
)
928 Boolean found
= FALSE
;
929 CFDictionaryRef match_dict
;
930 CFStringRef match_keys
[2];
931 CFTypeRef match_vals
[2];
932 CFDictionaryRef matching
;
936 io_registry_entry_t entry
= MACH_PORT_NULL
;
937 io_iterator_t iterator
= MACH_PORT_NULL
;
939 mach_port_t masterPort
= MACH_PORT_NULL
;
941 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
942 if (kr
!= KERN_SUCCESS
) {
943 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
947 // look for kIONetworkInterface with matching prefix and unit
948 match_keys
[0] = CFSTR(kIOInterfaceNamePrefix
);
949 match_vals
[0] = prefix
;
950 match_keys
[1] = CFSTR(kIOInterfaceUnit
);
951 match_vals
[1] = unit
;
952 match_dict
= CFDictionaryCreate(NULL
,
953 (const void **)match_keys
,
954 (const void **)match_vals
,
956 &kCFTypeDictionaryKeyCallBacks
,
957 &kCFTypeDictionaryValueCallBacks
);
959 match_keys
[0] = CFSTR(kIOProviderClassKey
);
960 match_vals
[0] = CFSTR(kIONetworkInterfaceClass
);
961 match_keys
[1] = CFSTR(kIOPropertyMatchKey
);
962 match_vals
[1] = match_dict
;
963 matching
= CFDictionaryCreate(NULL
,
964 (const void **)match_keys
,
965 (const void **)match_vals
,
966 sizeof(match_keys
)/sizeof(match_keys
[0]),
967 &kCFTypeDictionaryKeyCallBacks
,
968 &kCFTypeDictionaryValueCallBacks
);
969 CFRelease(match_dict
);
971 // note: the "matching" dictionary will be consumed by the following
972 kr
= IOServiceGetMatchingServices(masterPort
, matching
, &iterator
);
973 if ((kr
!= kIOReturnSuccess
) || (iterator
== MACH_PORT_NULL
)) {
978 entry
= IOIteratorNext(iterator
);
979 if (entry
== MACH_PORT_NULL
) {
987 if (masterPort
!= MACH_PORT_NULL
) {
988 mach_port_deallocate(mach_task_self(), masterPort
);
990 if (entry
!= MACH_PORT_NULL
) {
991 IOObjectRelease(entry
);
993 if (iterator
!= MACH_PORT_NULL
) {
994 IOObjectRelease(iterator
);
1001 * lookupMatchingInterface
1003 * Looks at the interfaces that have already been [or need to be] named with
1004 * the goal of allowing a system using a single network interface/adaptor of
1005 * a given type (vendor, model, ...) to not care about the specific adaptor
1006 * that is used (i.e. swapping dongle's is OK). Once a system has had more
1007 * than one interface/adaptor connected at the same time than we assume that
1008 * the network configuration is being setup for multi-homing that should be
1011 * If no matches are found or if more than one match is found, return NULL.
1012 * If a single match is found, return the match.
1014 static CFDictionaryRef
1015 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
1016 CFArrayRef db_list
, // already named
1017 CFArrayRef if_list
, // to be named
1018 CFIndex if_list_index
,
1019 CFBooleanRef builtin
)
1021 CFStringRef if_type
;
1022 CFDictionaryRef match
= NULL
;
1023 matchContext match_context
;
1025 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
1026 if (if_type
== NULL
) {
1030 match_context
.match_type
= if_type
;
1031 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
1032 match_context
.match_builtin
= builtin
;
1033 match_context
.matches
= NULL
;
1035 // check for matches to interfaces that have already been named
1036 // ... and append each match that we find to match_context.matches
1037 if (db_list
!= NULL
) {
1038 CFArrayApplyFunction(db_list
,
1039 CFRangeMake(0, CFArrayGetCount(db_list
)),
1044 // check for matches to interfaces that will be named
1045 // ... and CFRelease match_context.matches if we find another network
1046 // interface of the same type that also needs to be named
1047 if (if_list
!= NULL
) {
1048 CFIndex if_list_count
;
1050 if_list_count
= CFArrayGetCount(if_list
);
1051 if (if_list_index
< if_list_count
) {
1052 CFArrayApplyFunction(if_list
,
1053 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
1059 // check if we have a single match
1060 if (match_context
.matches
!= NULL
) {
1061 if (CFArrayGetCount(match_context
.matches
) == 1) {
1062 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
1064 CFRelease(match_context
.matches
);
1067 if (match
!= NULL
) {
1068 Boolean active
= TRUE
;
1071 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
1072 if (isA_CFString(name
)) {
1076 prefix
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceNamePrefix
));
1077 unit
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceUnit
));
1078 if (isA_CFString(prefix
) && isA_CFNumber(unit
)) {
1079 if (!interfaceExists(prefix
, unit
)) {
1090 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
1095 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
)
1098 CFDictionaryRef if_dict
;
1099 CFStringRef if_name
;
1100 CFNumberRef if_type
;
1101 CFNumberRef if_unit
;
1102 CFIndex n
= CFArrayGetCount(db_list
);
1103 CFComparisonResult res
;
1105 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1106 if (if_name
!= NULL
) {
1107 addTimestamp(S_state
, if_name
);
1110 if_dict
= createInterfaceDict(interface
);
1111 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1112 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1113 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
1118 for (i
= 0; i
< n
; i
++) {
1119 CFNumberRef db_type
;
1120 CFNumberRef db_unit
;
1121 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
1123 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1124 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1125 res
= CFNumberCompare(if_type
, db_type
, NULL
);
1126 if (res
== kCFCompareLessThan
1127 || (res
== kCFCompareEqualTo
1128 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
1129 == kCFCompareLessThan
))) {
1130 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
1136 CFArrayAppendValue(S_dblist
, if_dict
);
1138 #if !TARGET_OS_EMBEDDED
1139 updateBTPANInformation(if_dict
, NULL
);
1140 #endif // !TARGET_OS_EMBEDDED
1147 replaceInterface(SCNetworkInterfaceRef interface
)
1152 if (S_dblist
== NULL
) {
1153 S_dblist
= CFArrayCreateMutable(NULL
, 0,
1154 &kCFTypeArrayCallBacks
);
1156 // remove any dict that has our type/addr
1157 while (lookupInterfaceByAddress(S_dblist
, interface
, &where
) != NULL
) {
1158 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1161 // remove any dict that has the same type/unit
1162 while (lookupInterfaceByUnit(S_dblist
, interface
, &where
) != NULL
) {
1163 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1166 insertInterface(S_dblist
, interface
);
1169 SC_log(LOG_ERR
, "Multiple interfaces updated (n = %d, %@)", n
, interface
);
1176 getHighestUnitForType(CFNumberRef if_type
)
1180 CFNumberRef ret_unit
= NULL
;
1182 if (S_dblist
== NULL
) {
1186 n
= CFArrayGetCount(S_dblist
);
1187 for (i
= 0; i
< n
; i
++) {
1188 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1191 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1192 if (CFEqual(type
, if_type
)) {
1195 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1196 if (ret_unit
== NULL
1197 || (CFNumberCompare(unit
, ret_unit
, NULL
)
1198 == kCFCompareGreaterThan
)) {
1208 * Function: ensureInterfaceHasUnit
1210 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1211 * release the interface and return NULL.
1213 static SCNetworkInterfaceRef
1214 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if
)
1217 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if
) == NULL
) {
1224 #ifdef USE_REGISTRY_ENTRY_ID
1225 static kern_return_t
1226 registerInterfaceWithIORegistryEntryID(io_connect_t connect
,
1232 CFMutableDictionaryRef dict
;
1236 dict
= CFDictionaryCreateMutable(NULL
, 0,
1237 &kCFTypeDictionaryKeyCallBacks
,
1238 &kCFTypeDictionaryValueCallBacks
);
1239 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1240 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1242 data
= CFDataCreate(NULL
, (void *) &entryID
, sizeof(entryID
));
1243 CFDictionarySetValue(dict
, CFSTR(kIORegistryEntryIDKey
), data
);
1245 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1246 kr
= IOConnectSetCFProperties(connect
, dict
);
1251 static SCNetworkInterfaceRef
1252 copyInterfaceForIORegistryEntryID(uint64_t entryID
)
1254 io_registry_entry_t entry
= MACH_PORT_NULL
;
1255 SCNetworkInterfaceRef interface
= NULL
;
1256 io_iterator_t iterator
= MACH_PORT_NULL
;
1258 mach_port_t masterPort
= MACH_PORT_NULL
;
1260 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1261 if (kr
!= KERN_SUCCESS
) {
1262 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1266 kr
= IOServiceGetMatchingServices(masterPort
,
1267 IORegistryEntryIDMatching(entryID
),
1269 if ((kr
!= KERN_SUCCESS
) || (iterator
== MACH_PORT_NULL
)) {
1270 SC_log(LOG_NOTICE
, "IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d",
1277 entry
= IOIteratorNext(iterator
);
1278 if (entry
== MACH_PORT_NULL
) {
1279 SC_log(LOG_NOTICE
, "IORegistryEntryIDMatching(0x%llx) failed", entryID
);
1283 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1286 if (masterPort
!= MACH_PORT_NULL
) {
1287 mach_port_deallocate(mach_task_self(), masterPort
);
1289 if (entry
!= MACH_PORT_NULL
) {
1290 IOObjectRelease(entry
);
1292 if (iterator
!= MACH_PORT_NULL
) {
1293 IOObjectRelease(iterator
);
1298 static SCNetworkInterfaceRef
1299 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID
)
1301 SCNetworkInterfaceRef net_if
;
1303 net_if
= copyInterfaceForIORegistryEntryID(entryID
);
1304 return (ensureInterfaceHasUnit(net_if
));
1307 #else // USE_REGISTRY_ENTRY_ID
1309 * Function: registerInterface
1311 * Register a single interface with the given service path to the
1312 * data link layer (BSD), using the specified unit number.
1314 static kern_return_t
1315 registerInterfaceWithIOServicePath(io_connect_t connect
,
1320 CFMutableDictionaryRef dict
;
1324 dict
= CFDictionaryCreateMutable(NULL
, 0,
1325 &kCFTypeDictionaryKeyCallBacks
,
1326 &kCFTypeDictionaryValueCallBacks
);
1327 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1328 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1330 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1331 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1332 kr
= IOConnectSetCFProperties(connect
, dict
);
1337 static SCNetworkInterfaceRef
1338 copyInterfaceForIOKitPath(CFStringRef if_path
)
1340 io_registry_entry_t entry
= MACH_PORT_NULL
;
1341 SCNetworkInterfaceRef interface
= NULL
;
1343 mach_port_t masterPort
= MACH_PORT_NULL
;
1346 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1347 if (kr
!= KERN_SUCCESS
) {
1348 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1351 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1352 entry
= IORegistryEntryFromPath(masterPort
, path
);
1353 if (entry
== MACH_PORT_NULL
) {
1354 SC_log(LOG_NOTICE
, "IORegistryEntryFromPath(%@) failed", if_path
);
1358 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1361 if (masterPort
!= MACH_PORT_NULL
) {
1362 mach_port_deallocate(mach_task_self(), masterPort
);
1364 if (entry
!= MACH_PORT_NULL
) {
1365 IOObjectRelease(entry
);
1371 static SCNetworkInterfaceRef
1372 copyNamedInterfaceForIOKitPath(CFStringRef if_path
)
1374 SCNetworkInterfaceRef net_if
;
1376 net_if
= copyInterfaceForIOKitPath(if_path
);
1377 return (ensureInterfaceHasUnit(net_if
));
1380 #endif // USE_REGISTRY_ENTRY_ID
1383 displayInterface(SCNetworkInterfaceRef interface
)
1390 name
= SCNetworkInterfaceGetBSDName(interface
);
1391 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1392 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1393 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1395 SC_log(LOG_INFO
, " %s%@%sType: %@, %s%@%sMAC address: %@",
1396 (name
!= NULL
) ? "BSD Name: " : "",
1397 (name
!= NULL
) ? name
: CFSTR(""),
1398 (name
!= NULL
) ? ", " : "",
1400 (unit
!= NULL
) ? "Unit: " : "",
1401 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1402 (unit
!= NULL
) ? ", " : "",
1407 builtinAvailable(SCNetworkInterfaceRef interface
, // new interface
1408 CFNumberRef if_unit
) // desired unit
1411 CFNumberRef if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1414 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1415 for (i
= 0; i
< n
; i
++) {
1416 CFStringRef if_path
;
1417 CFDictionaryRef known_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1418 CFStringRef known_path
;
1419 CFNumberRef known_type
;
1420 CFNumberRef known_unit
;
1422 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceType
));
1423 if (!_SC_CFEqual(if_type
, known_type
)) {
1424 continue; // if not the same interface type
1427 known_unit
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceUnit
));
1428 if (!_SC_CFEqual(if_unit
, known_unit
)) {
1429 continue; // if not the same interface unit
1432 if_path
= _SCNetworkInterfaceGetIOPath(interface
);
1433 known_path
= CFDictionaryGetValue(known_dict
, CFSTR(kIOPathMatchKey
));
1434 if (!_SC_CFEqual(if_path
, known_path
)) {
1435 // if different IORegistry path
1439 // if same type, same unit, same path
1443 // if interface type/unit not found
1448 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
1453 for (i
= 0; i
< last
; i
++) {
1454 SCNetworkInterfaceRef builtin_if
;
1455 CFNumberRef builtin_type
;
1457 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1458 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
1459 if (CFEqual(if_type
, builtin_type
)) {
1460 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1461 n
++; // if built-in interface
1469 static __inline__ boolean_t
1472 return (S_quiet
== MACH_PORT_NULL
);
1476 nameInterfaces(CFMutableArrayRef if_list
)
1479 CFIndex n
= CFArrayGetCount(if_list
);
1481 for (i
= 0; i
< n
; i
++) {
1483 SCNetworkInterfaceRef interface
;
1484 SCNetworkInterfaceRef new_interface
;
1490 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1491 path
= _SCNetworkInterfaceGetIOPath(interface
);
1492 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1493 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1494 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
1497 CFStringRef if_name
;
1499 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1500 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
1501 SC_log(LOG_INFO
, "Interface already has a unit number");
1502 displayInterface(interface
);
1505 // update the list of interfaces that were previously named
1506 if ((S_prev_active_list
!= NULL
)
1507 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
1508 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1511 replaceInterface(interface
);
1513 CFDictionaryRef dbdict
;
1514 boolean_t is_builtin
;
1518 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
1519 if (dbdict
!= NULL
) {
1520 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1523 SC_log(LOG_INFO
, "Interface assigned unit %@ (from database)", unit
);
1526 if ((dbdict
== NULL
) && !isQuiet()) {
1527 // if new interface, wait until quiet before naming
1528 addTimestamp(S_state
, path
);
1532 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
1534 if (dbdict
== NULL
) {
1535 dbdict
= lookupMatchingInterface(interface
,
1539 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
1540 if (dbdict
!= NULL
) {
1541 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1544 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database)", unit
);
1548 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
1549 // update the list of interfaces that were previously named
1550 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
1551 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
1553 if (where
!= kCFNotFound
) {
1554 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1558 if (dbdict
== NULL
) {
1562 // built-in interface, try to use the reserved slots
1563 next_unit
= builtinCount(if_list
, i
, type
);
1565 // But, before claiming a reserved slot we check to see if the
1566 // slot had previously been used. If so, and if the slot had been
1567 // assigned to the same type of interface, then we will perform a
1568 // replacement (e.g. assume that this was a board swap). But, if
1569 // the new interface is a different type then we assume that the
1570 // built-in configuration has changed and allocate a new unit from
1571 // the non-reserved slots.
1573 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1574 if (!builtinAvailable(interface
, unit
)) {
1575 // if [built-in] unit not available
1576 SC_log(LOG_INFO
, "Interface not assigned [built-in] unit %@", unit
);
1583 // not built-in (or built-in unit not available), allocate from
1584 // the non-reserved slots
1585 next_unit
= builtinCount(if_list
, n
, type
);
1587 unit
= getHighestUnitForType(type
);
1591 CFNumberGetValue(unit
, kCFNumberIntType
, &high_unit
);
1592 if (high_unit
>= next_unit
) {
1593 next_unit
= high_unit
+ 1;
1597 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1600 SC_log(LOG_INFO
, "Interface assigned unit %@ (%s)",
1602 is_builtin
? "built-in" : "next available");
1607 #ifdef USE_REGISTRY_ENTRY_ID
1608 kr
= registerInterfaceWithIORegistryEntryID(S_connect
,
1611 (dbdict
== NULL
) ? kIONetworkStackRegisterInterfaceWithLowestUnit
1612 : kIONetworkStackRegisterInterfaceWithUnit
);
1613 new_interface
= copyNamedInterfaceForIORegistryEntryID(entryID
);
1614 #else // USE_REGISTRY_ENTRY_ID
1615 kr
= registerInterfaceWithIOServicePath(S_connect
,
1618 (dbdict
== NULL
) ? kRegisterInterface
1619 : kRegisterInterfaceWithFixedUnit
);
1620 new_interface
= copyNamedInterfaceForIOKitPath(path
);
1621 #endif // USE_REGISTRY_ENTRY_ID
1622 if (new_interface
== NULL
) {
1623 const char *signature
;
1625 signature
= (dbdict
== NULL
) ? "failed to name new interface"
1626 : "failed to name known interface";
1628 SC_log(LOG_NOTICE
, "%s, kr=0x%x\n"
1638 displayInterface(interface
);
1640 if ((dbdict
!= NULL
) && (retries
++ < 5)) {
1641 usleep(50 * 1000); // sleep 50ms between attempts
1646 CFNumberRef new_unit
;
1649 SC_log(LOG_INFO
, "%s interface named after %d %s\n"
1652 (dbdict
== NULL
) ? "New" : "Known",
1654 (retries
== 1) ? "try" : "tries",
1658 #ifdef SHOW_NAMING_FAILURE
1659 str
= CFStringCreateWithFormat(NULL
,
1661 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
1662 (dbdict
== NULL
) ? "New" : "Known",
1664 (retries
== 1) ? "try" : "tries",
1666 CFUserNotificationDisplayNotice(0,
1667 kCFUserNotificationStopAlertLevel
,
1672 CFSTR("Please report repeated failures."),
1675 #endif // SHOW_NAMING_FAILURE
1678 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
1679 if (!CFEqual(unit
, new_unit
)) {
1680 SC_log(LOG_INFO
, "interface type %@ assigned unit %@ instead of %@",
1681 type
, new_unit
, unit
);
1684 displayInterface(new_interface
);
1686 // update if_list (with the interface name & unit)
1687 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
1688 CFRelease(new_interface
);
1689 interface
= new_interface
; // if_list holds the reference
1691 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
1694 // update the list of [built-in] interfaces that were previously named
1695 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
1696 SC_log(LOG_DEBUG
, " and updated database (new address)");
1697 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1700 replaceInterface(interface
);
1708 #if !TARGET_OS_IPHONE
1712 static Boolean isRecovery
= FALSE
;
1713 static dispatch_once_t once
;
1716 * We check to see if the UserEventAgent daemon is present. If not, then
1717 * we are most likely booted into the Recovery OS with no "SCMonitor"
1718 * [UserEventAgent] plugin.
1720 dispatch_once(&once
, ^{
1721 if ((access("/usr/libexec/UserEventAgent", X_OK
) == -1) && (errno
== ENOENT
)) {
1731 updateNetworkConfiguration(CFArrayRef if_list
)
1733 Boolean do_commit
= FALSE
;
1736 SCPreferencesRef prefs
= NULL
;
1737 SCNetworkSetRef set
= NULL
;
1739 prefs
= SCPreferencesCreate(NULL
, CFSTR("InterfaceNamer:updateNetworkConfiguration"), NULL
);
1741 set
= SCNetworkSetCopyCurrent(prefs
);
1743 SC_log(LOG_INFO
, "No current set");
1747 n
= CFArrayGetCount(if_list
);
1748 for (i
= 0; i
< n
; i
++) {
1749 SCNetworkInterfaceRef interface
;
1751 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1752 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set
, interface
)) {
1753 SC_log(LOG_INFO
, "adding default configuration for %@",
1754 SCNetworkInterfaceGetBSDName(interface
));
1762 ok
= SCPreferencesCommitChanges(prefs
);
1764 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
1768 ok
= SCPreferencesApplyChanges(prefs
);
1770 SC_log(LOG_NOTICE
, "SCPreferencesApplyChanges() failed: %s", SCErrorString(SCError()));
1782 if (prefs
!= NULL
) {
1789 #endif // !TARGET_OS_IPHONE
1792 updatePreConfigured(CFArrayRef interfaces
)
1796 CFMutableArrayRef new_list
= NULL
;
1797 Boolean updated
= FALSE
;
1799 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
1800 for (i
= 0; i
< n
; i
++) {
1801 SCNetworkInterfaceRef interface
;
1803 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1804 if (_SCNetworkInterfaceIsApplePreconfigured(interface
)) {
1805 CFStringRef bsdName
;
1807 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
1808 if (bsdName
== NULL
) {
1812 // add pre-configured interface
1813 if (new_list
== NULL
) {
1814 CFArrayRef cur_list
;
1816 cur_list
= CFDictionaryGetValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
);
1817 if (cur_list
!= NULL
) {
1818 new_list
= CFArrayCreateMutableCopy(NULL
, 0, cur_list
);
1820 new_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1824 if (!CFArrayContainsValue(new_list
, CFRangeMake(0, CFArrayGetCount(new_list
)), bsdName
)) {
1825 CFArrayAppendValue(new_list
, bsdName
);
1831 if (new_list
!= NULL
) {
1833 CFDictionarySetValue(S_state
, kInterfaceNamerKey_PreConfiguredInterfaces
, new_list
);
1837 CFRelease(new_list
);
1846 if (S_connect
== MACH_PORT_NULL
) {
1847 // if we don't have the "IONetworkStack" connect object
1851 if (S_iflist
!= NULL
) {
1854 n
= CFArrayGetCount(S_iflist
);
1856 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
1858 nameInterfaces(S_iflist
);
1862 * Update the list of [Apple] pre-configured interfaces
1864 updatePreConfigured(S_iflist
);
1868 * The registry [matching] has quiesced so let's
1869 * - save the DB with the interfaces that have been named
1870 * - update the VLAN/BOND configuration
1871 * - tell everyone that we've finished (at least for now)
1872 * - log those interfaces which are no longer present
1873 * in the HW config (or have yet to show up).
1875 writeInterfaceList(S_dblist
);
1876 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
1878 #if !TARGET_OS_IPHONE
1879 if (isRecoveryOS()) {
1881 * We are most likely booted into the Recovery OS with no "SCMonitor"
1882 * UserEventAgent plugin running so let's make sure we update the
1883 * network configuration for new interfaces.
1885 updateNetworkConfiguration(S_iflist
);
1887 #endif // !TARGET_OS_IPHONE
1891 if (S_iflist
!= NULL
) {
1892 CFRelease(S_iflist
);
1896 if (S_prev_active_list
!= NULL
) {
1900 n
= CFArrayGetCount(S_prev_active_list
);
1902 SC_log(LOG_INFO
, "Interface%s not [yet] active",
1903 (n
> 1) ? "s" : "");
1905 for (i
= 0; i
< n
; i
++) {
1906 CFDictionaryRef if_dict
;
1911 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
1912 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
1913 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
1914 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
1915 SC_log(LOG_INFO
, " %s%@%sType: %@, Unit: %@",
1916 (name
!= NULL
) ? "BSD Name: " : "",
1917 (name
!= NULL
) ? name
: CFSTR(""),
1918 (name
!= NULL
) ? ", " : "",
1923 CFRelease(S_prev_active_list
);
1924 S_prev_active_list
= NULL
;
1927 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
1929 * if we've named all of the interfaces that
1930 * were used during the previous boot.
1932 addTimestamp(S_state
, CFSTR("*RELEASE*"));
1933 SC_log(LOG_INFO
, "last boot interfaces have been named");
1935 CFRelease(S_prev_active_list
);
1936 S_prev_active_list
= NULL
;
1944 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
1946 os_activity_t activity
;
1949 activity
= os_activity_create("process new network interface",
1950 OS_ACTIVITY_CURRENT
,
1951 OS_ACTIVITY_FLAG_DEFAULT
);
1952 os_activity_scope(activity
);
1954 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
1955 SCNetworkInterfaceRef interface
;
1957 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
1958 if (interface
!= NULL
) {
1959 if (S_iflist
== NULL
) {
1960 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1962 CFArrayAppendValue(S_iflist
, interface
);
1963 CFRelease(interface
);
1965 IOObjectRelease(obj
);
1970 os_release(activity
);
1976 * Function: stackCallback
1978 * Get a reference to the single IONetworkStack object instance in
1979 * the kernel. Naming requests must be sent to this object, which is
1980 * attached as a client to all network interface objects in the system.
1982 * Call IOObjectRelease on the returned object.
1985 stackCallback(void *refcon
, io_iterator_t iter
)
1987 os_activity_t activity
;
1991 activity
= os_activity_create("process IONetworkStack",
1992 OS_ACTIVITY_CURRENT
,
1993 OS_ACTIVITY_FLAG_DEFAULT
);
1994 os_activity_scope(activity
);
1996 stack
= IOIteratorNext(iter
);
1997 if (stack
== MACH_PORT_NULL
) {
2001 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
2002 if (kr
!= KERN_SUCCESS
) {
2003 SC_log(LOG_ERR
, "IOServiceOpen returned 0x%x", kr
);
2007 addTimestamp(S_state
, CFSTR("*STACK*"));
2008 SC_log(LOG_INFO
, "IONetworkStack found");
2010 if (S_stack
!= MACH_PORT_NULL
) {
2011 IOObjectRelease(S_stack
);
2012 S_stack
= MACH_PORT_NULL
;
2015 if ((S_timer
!= NULL
) && CFRunLoopTimerIsValid(S_timer
)) {
2016 // With the IONetworkStack object now available we can
2017 // reset (shorten?) the time we are willing to wait for
2018 // IOKit to quiesce.
2019 CFRunLoopTimerSetNextFireDate(S_timer
,
2020 CFAbsoluteTimeGetCurrent() + S_quiet_timeout
);
2027 if (stack
!= MACH_PORT_NULL
) {
2028 IOObjectRelease(stack
);
2031 os_release(activity
);
2037 quietCallback(void *refcon
,
2038 io_service_t service
,
2039 natural_t messageType
,
2040 void *messageArgument
)
2042 os_activity_t activity
;
2044 if (messageArgument
!= NULL
) {
2049 activity
= os_activity_create("process IOKit quiet",
2050 OS_ACTIVITY_CURRENT
,
2051 OS_ACTIVITY_FLAG_DEFAULT
);
2052 os_activity_scope(activity
);
2054 if (messageType
== kIOMessageServiceBusyStateChange
) {
2055 addTimestamp(S_state
, kInterfaceNamerKey_Quiet
);
2056 SC_log(LOG_INFO
, "IOKit quiet");
2059 if (S_connect
== MACH_PORT_NULL
) {
2060 SC_log(LOG_ERR
, "No network stack object");
2064 if (S_quiet
!= MACH_PORT_NULL
) {
2065 IOObjectRelease(S_quiet
);
2066 S_quiet
= MACH_PORT_NULL
;
2069 if (S_timer
!= NULL
) {
2070 CFRunLoopTimerInvalidate(S_timer
);
2075 // grab (and name) any additional interfaces.
2076 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2078 if (messageType
== kIOMessageServiceBusyStateChange
) {
2079 addTimestamp(S_state
, CFSTR("*QUIET&NAMED*"));
2085 os_release(activity
);
2091 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, int *count
)
2093 kern_return_t kr
= kIOReturnSuccess
;;
2096 while ((kr
== kIOReturnSuccess
) &&
2097 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
2098 uint64_t accumulated_busy_time
;
2099 uint32_t busy_state
;
2102 CFMutableArrayRef newNodes
;
2104 CFMutableStringRef str
= NULL
;
2106 if (nodes
== NULL
) {
2107 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2109 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
2111 assert(newNodes
!= NULL
);
2113 kr
= IORegistryEntryGetName(obj
, name
);
2114 if (kr
!= kIOReturnSuccess
) {
2115 SC_log(LOG_NOTICE
, "IORegistryEntryGetName() returned 0x%x", kr
);
2119 str
= CFStringCreateMutable(NULL
, 0);
2120 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
2122 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
2124 case kIOReturnSuccess
:
2125 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
2126 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
2128 case kIOReturnNotFound
:
2131 SC_log(LOG_NOTICE
, "IORegistryEntryGetLocationInPlane() returned 0x%x", kr
);
2136 CFArrayAppendValue(newNodes
, str
);
2139 kr
= IOServiceGetBusyStateAndTime(obj
, &state
, &busy_state
, &accumulated_busy_time
);
2140 if (kr
!= kIOReturnSuccess
) {
2141 SC_log(LOG_NOTICE
, "IOServiceGetBusyStateAndTime() returned 0x%x", kr
);
2145 #ifdef TEST_SNAPSHOT
2148 #endif // TEST_SNAPSHOT
2150 if (busy_state
!= 0) {
2153 if ((*count
)++ == 0) {
2154 SC_log(LOG_ERR
, "Busy services :");
2157 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
2158 SC_log(LOG_ERR
, " %@ [%s%s%s%d, %lld ms]",
2160 (state
& kIOServiceRegisteredState
) ? "" : "!registered, ",
2161 (state
& kIOServiceMatchedState
) ? "" : "!matched, ",
2162 (state
& kIOServiceInactiveState
) ? "inactive, " : "",
2164 accumulated_busy_time
/ kMillisecondScale
);
2168 kr
= IORegistryIteratorEnterEntry(iterator
);
2169 if (kr
!= kIOReturnSuccess
) {
2170 SC_log(LOG_NOTICE
, "IORegistryIteratorEnterEntry() returned 0x%x", kr
);
2174 iterateRegistryBusy(iterator
, newNodes
, count
);
2176 kr
= IORegistryIteratorExitEntry(iterator
);
2177 if (kr
!= kIOReturnSuccess
) {
2178 SC_log(LOG_NOTICE
, "IORegistryIteratorExitEntry() returned 0x%x", kr
);
2183 CFRelease(newNodes
);
2184 IOObjectRelease(obj
);
2194 io_iterator_t iterator
= MACH_PORT_NULL
;
2197 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
2201 if (kr
!= kIOReturnSuccess
) {
2202 SC_log(LOG_NOTICE
, "IORegistryCreateIterator() returned 0x%x", kr
);
2206 iterateRegistryBusy(iterator
, NULL
, &count
);
2208 SC_log(LOG_ERR
, "w/no busy services");
2211 IOObjectRelease(iterator
);
2215 timerCallback(CFRunLoopTimerRef timer
, void *info
)
2217 os_activity_t activity
;
2219 activity
= os_activity_create("process IOKit timer",
2220 OS_ACTIVITY_CURRENT
,
2221 OS_ACTIVITY_FLAG_DEFAULT
);
2222 os_activity_scope(activity
);
2224 // We've been waiting for IOKit to quiesce and it just
2225 // hasn't happenned. Time to just move on!
2226 addTimestamp(S_state
, kInterfaceNamerKey_Timeout
);
2229 SC_log(LOG_ERR
, "timed out waiting for IOKit to quiesce");
2232 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
2234 addTimestamp(S_state
, CFSTR("*TIMEOUT&NAMED*"));
2237 os_release(activity
);
2243 setup_IOKit(CFBundleRef bundle
)
2247 mach_port_t masterPort
= MACH_PORT_NULL
;
2249 io_object_t root
= MACH_PORT_NULL
;
2251 // read DB of previously named network interfaces
2252 S_dblist
= readInterfaceList();
2253 if (S_dblist
!= NULL
) {
2256 n
= CFArrayGetCount(S_dblist
);
2258 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
2262 // get interfaces that were named during the last boot
2263 S_prev_active_list
= previouslyActiveInterfaces();
2265 // track how long we've waited to see each interface.
2266 S_state
= CFDictionaryCreateMutable(NULL
,
2268 &kCFTypeDictionaryKeyCallBacks
,
2269 &kCFTypeDictionaryValueCallBacks
);
2270 addTimestamp(S_state
, CFSTR("*START*"));
2272 // Creates and returns a notification object for receiving IOKit
2273 // notifications of new devices or state changes.
2274 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
2275 if (kr
!= KERN_SUCCESS
) {
2276 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
2280 S_notify
= IONotificationPortCreate(masterPort
);
2281 if (S_notify
== NULL
) {
2282 SC_log(LOG_ERR
, "IONotificationPortCreate failed");
2286 // watch IOKit matching activity
2287 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
2288 if (root
== MACH_PORT_NULL
) {
2289 SC_log(LOG_ERR
, "IORegistryEntryFromPath failed");
2293 kr
= IOServiceAddInterestNotification(S_notify
,
2297 (void *)S_notify
, // refCon
2298 &S_quiet
); // notification
2299 if (kr
!= KERN_SUCCESS
) {
2300 SC_log(LOG_ERR
, "IOServiceAddInterestNotification returned 0x%x", kr
);
2304 kr
= IOServiceGetBusyState(root
, &busy
);
2305 if (kr
!= KERN_SUCCESS
) {
2306 SC_log(LOG_ERR
, "IOServiceGetBusyState returned 0x%x", kr
);
2310 // add a timer so we don't wait forever for IOKit to quiesce
2311 S_timer
= CFRunLoopTimerCreate(NULL
,
2312 CFAbsoluteTimeGetCurrent() + S_stack_timeout
,
2318 if (S_timer
== NULL
) {
2319 SC_log(LOG_ERR
, "CFRunLoopTimerCreate failed");
2323 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
2325 // watch for the introduction of the IONetworkStack
2326 kr
= IOServiceAddMatchingNotification(S_notify
,
2327 kIOFirstMatchNotification
,
2328 IOServiceMatching("IONetworkStack"),
2330 (void *)S_notify
, // refCon
2331 &S_stack
); // notification
2332 if (kr
!= KERN_SUCCESS
) {
2333 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
2337 // check and see if the stack is already available and arm the
2338 // notification for its introduction.
2339 stackCallback((void *)S_notify
, S_stack
);
2341 // watch for the introduction of new network interfaces
2342 kr
= IOServiceAddMatchingNotification(S_notify
,
2343 kIOFirstMatchNotification
,
2344 IOServiceMatching("IONetworkInterface"),
2345 &interfaceArrivalCallback
,
2346 (void *)S_notify
, // refCon
2347 &S_iter
); // notification
2348 if (kr
!= KERN_SUCCESS
) {
2349 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
2353 // Get the current list of matches and arm the notification for
2354 // future interface arrivals.
2355 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2357 // Check if IOKit has already quiesced.
2358 quietCallback((void *)S_notify
,
2360 kIOMessageServiceBusyStateChange
,
2361 (void *)(uintptr_t)busy
);
2363 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2364 IONotificationPortGetRunLoopSource(S_notify
),
2365 kCFRunLoopDefaultMode
);
2367 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
2369 * Start the wheels turning until we've named all of
2370 * the interfaces that were used during the previous
2371 * boot, until IOKit [matching] has quiesced, or
2372 * until we've waited long enough.
2374 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
2375 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2376 IONotificationPortGetRunLoopSource(S_notify
),
2378 while (S_prev_active_list
!= NULL
) {
2381 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
2383 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
2385 #if !TARGET_OS_EMBEDDED
2386 if (S_dblist
!= NULL
) {
2387 // apply special handling for the BT-PAN interface (if present)
2388 CFArrayApplyFunction(S_dblist
,
2389 CFRangeMake(0, CFArrayGetCount(S_dblist
)),
2390 updateBTPANInformation
,
2393 #endif // !TARGET_OS_EMBEDDED
2398 if (root
!= MACH_PORT_NULL
) {
2399 IOObjectRelease(root
);
2401 if (masterPort
!= MACH_PORT_NULL
) {
2402 mach_port_deallocate(mach_task_self(), masterPort
);
2409 setup_Virtual(CFBundleRef bundle
)
2411 // open a SCPreferences session
2412 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
);
2413 if (S_prefs
== NULL
) {
2414 SC_log(LOG_ERR
, "SCPreferencesCreate() failed: %s",
2415 SCErrorString(SCError()));
2419 // register for change notifications.
2420 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
2421 SC_log(LOG_ERR
, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
2427 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
2428 if (SCError() != kSCStatusNoStoreServer
) {
2429 SC_log(LOG_ERR
, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
2439 exec_InterfaceNamer(void *arg
)
2441 CFBundleRef bundle
= (CFBundleRef
)arg
;
2442 CFDictionaryRef dict
;
2444 pthread_setname_np(MY_PLUGIN_NAME
" thread");
2446 dict
= CFBundleGetInfoDictionary(bundle
);
2447 if (isA_CFDictionary(dict
)) {
2450 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_STACK_TIMEOUT_KEY
));
2452 if (!isA_CFNumber(num
) ||
2453 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_stack_timeout
) ||
2454 (S_stack_timeout
<= 0.0)) {
2455 SC_log(LOG_NOTICE
, WAIT_STACK_TIMEOUT_KEY
" value error");
2456 S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
2460 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
2462 if (!isA_CFNumber(num
) ||
2463 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_quiet_timeout
) ||
2464 (S_quiet_timeout
<= 0.0)) {
2465 SC_log(LOG_NOTICE
, WAIT_QUIET_TIMEOUT_KEY
" value error");
2466 S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
2471 // setup virtual network interface monitoring
2472 if (!setup_Virtual(bundle
)) {
2476 // setup [IOKit] network interface monitoring
2477 if (!setup_IOKit(bundle
)) {
2484 if (S_connect
!= MACH_PORT_NULL
) {
2485 IOServiceClose(S_connect
);
2486 S_connect
= MACH_PORT_NULL
;
2488 if (S_dblist
!= NULL
) {
2489 CFRelease(S_dblist
);
2492 if (S_iter
!= MACH_PORT_NULL
) {
2493 IOObjectRelease(S_iter
);
2494 S_iter
= MACH_PORT_NULL
;
2496 if (S_notify
!= MACH_PORT_NULL
) {
2497 IONotificationPortDestroy(S_notify
);
2499 if (S_quiet
!= MACH_PORT_NULL
) {
2500 IOObjectRelease(S_quiet
);
2501 S_quiet
= MACH_PORT_NULL
;
2503 if (S_stack
!= MACH_PORT_NULL
) {
2504 IOObjectRelease(S_stack
);
2505 S_stack
= MACH_PORT_NULL
;
2507 if (S_state
!= NULL
) {
2511 if (S_timer
!= NULL
) {
2512 CFRunLoopTimerInvalidate(S_timer
);
2526 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
2528 pthread_attr_t tattr
;
2531 CFRetain(bundle
); // released in exec_InterfaceNamer
2533 pthread_attr_init(&tattr
);
2534 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
2535 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
2536 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
2537 pthread_create(&tid
, &tattr
, exec_InterfaceNamer
, bundle
);
2538 pthread_attr_destroy(&tattr
);
2543 //------------------------------------------------------------------------
2547 main(int argc
, char ** argv
)
2552 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2554 bundle
= CFBundleGetMainBundle();
2555 CFRetain(bundle
); // released in exec_InterfaceNamer
2557 (void)exec_InterfaceNamer();
2565 #ifdef TEST_SNAPSHOT
2567 main(int argc
, char ** argv
)
2569 CFStringRef snapshot
;
2572 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2574 snapshot
= captureBusy();
2575 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), snapshot
);
2576 CFRelease(snapshot
);
2581 #endif /* TEST_SNAPSHOT */