2 * Copyright (c) 2001-2015 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 #include <SystemConfiguration/SystemConfiguration.h>
79 #include <SystemConfiguration/SCDPlugin.h>
80 #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
81 #include <SystemConfiguration/SCValidation.h>
83 #include <IOKit/IOKitLib.h>
84 #include <IOKit/IOKitLibPrivate.h>
85 #include <IOKit/IOBSD.h>
86 #include <IOKit/IOMessage.h>
87 #include <IOKit/network/IONetworkController.h>
88 #include <IOKit/network/IONetworkInterface.h>
89 #include <IOKit/network/IONetworkStack.h>
90 #include <IOKit/usb/USB.h>
92 #ifdef kIONetworkStackUserCommandKey
93 #define USE_REGISTRY_ENTRY_ID
96 #ifndef USE_REGISTRY_ENTRY_ID
97 // from <IOKit/network/IONetworkStack.h>
98 #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand"
100 kRegisterInterfaceWithFixedUnit
= 0,
102 kRegisterAllInterfaces
104 #endif // !USE_REGISTRY_ENTRY_ID
106 #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo"
107 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
108 #define kSCNetworkInterfaceActive "Active"
110 #define MY_PLUGIN_NAME "InterfaceNamer"
111 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
113 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
114 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
116 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
117 #define WAIT_QUIET_TIMEOUT_DEFAULT 60.0
121 * "IONetworkStack" connect object used to "name" an interface.
123 static io_connect_t S_connect
= MACH_PORT_NULL
;
127 * An array of CFDictionary's representing the interfaces
128 * that have been identified and [need to be] named.
130 static CFMutableArrayRef S_dblist
= NULL
;
134 * An array of SCNetworkInterface's representing the
135 * interfaces that have been identified.
137 static CFMutableArrayRef S_iflist
= NULL
;
141 * IOServiceAddMatchingNotification object used to watch for
142 * new network interfaces.
144 static io_iterator_t S_iter
= MACH_PORT_NULL
;
148 * notification object for receiving IOKit notifications of
149 * new devices or state changes.
151 static IONotificationPortRef S_notify
= NULL
;
153 /* S_prev_active_list
154 * An array of CFDictionary's representing the previously
157 static CFMutableArrayRef S_prev_active_list
= NULL
;
161 * IOServiceAddInterestNotification object used to watch for
162 * IOKit matching to quiesce.
164 static io_object_t S_quiet
= MACH_PORT_NULL
;
168 * IOServiceAddMatchingNotification object used to watch for
169 * the availability of the "IONetworkStack" object.
171 static io_iterator_t S_stack
= MACH_PORT_NULL
;
175 * A dictionary containing Information about each network
176 * interface. For now, the key is the BSD name and the
177 * value is a CFNumber noting how long (in milliseconds)
178 * it took for the interface to be recognized/named.
180 static CFMutableDictionaryRef S_state
= NULL
;
184 * CFRunLoopTimer tracking how long we are willing to wait
185 * for IOKit matching to quiesce (IOKitWaitQuiet).
188 * time to wait for the IONetworkStack object to appear before timeout
191 * time to wait for the IOKit to quiesce (after the IONetworkStack is
194 static CFRunLoopTimerRef S_timer
= NULL
;
195 static double S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
196 static double S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
199 * Virtual network interface configuration
200 * S_prefs : SCPreferences to configuration
201 * S_bonds : most recently actived Bond configuration
202 * S_bridges : most recently actived Bridge configuration
203 * S_vlans : most recently actived VLAN configuration
205 static SCPreferencesRef S_prefs
= NULL
;
206 static CFArrayRef S_bonds
= NULL
;
207 static CFArrayRef S_bridges
= NULL
;
208 static CFArrayRef S_vlans
= NULL
;
211 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
216 now
= CFAbsoluteTimeGetCurrent();
217 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
218 CFDictionaryAddValue(dict
, key
, val
);
223 #define INTERFACES CFSTR("Interfaces")
224 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
226 static CFComparisonResult
227 if_unit_compare(const void *val1
, const void *val2
, void *context
)
229 CFComparisonResult res
;
235 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
236 CFSTR(kIOInterfaceType
));
237 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
238 CFSTR(kIOInterfaceType
));
239 res
= CFNumberCompare(type1
, type2
, NULL
);
240 if (res
!= kCFCompareEqualTo
) {
243 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
244 CFSTR(kIOInterfaceUnit
));
245 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
246 CFSTR(kIOInterfaceUnit
));
247 return (CFNumberCompare(unit1
, unit2
, NULL
));
251 reportIssue(const char *signature
, CFStringRef issue
)
255 m
= asl_new(ASL_TYPE_MSG
);
256 asl_set(m
, "com.apple.message.domain", "com.apple.SystemConfiguration." MY_PLUGIN_NAME
);
257 asl_set(m
, "com.apple.message.signature", signature
);
258 asl_set(m
, "com.apple.message.result", "failure");
259 SCLOG(NULL
, m
, ~ASL_LEVEL_ERR
, CFSTR("%s\n%@"), signature
, issue
);
266 writeInterfaceList(CFArrayRef if_list
)
269 CFStringRef new_model
;
270 CFStringRef old_model
;
271 SCPreferencesRef prefs
;
273 if (isA_CFArray(if_list
) == NULL
) {
277 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
279 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
283 cur_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
284 if (_SC_CFEqual(cur_list
, if_list
)) {
288 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
289 new_model
= _SC_hw_model(FALSE
);
290 if ((new_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
292 if ((old_model
!= NULL
) && (cur_list
!= NULL
)) {
296 // if interface list was created on other hardware
297 history
= CFStringCreateWithFormat(NULL
, NULL
,
301 SCPreferencesSetValue(prefs
, history
, cur_list
);
304 SC_log(LOG_INFO
, "Hardware model changed\n"
305 " created on \"%@\"\n"
310 issue
= CFStringCreateWithFormat(NULL
, NULL
,
314 reportIssue("Hardware model changed", issue
);
318 SCPreferencesSetValue(prefs
, MODEL
, new_model
);
321 SCPreferencesSetValue(prefs
, INTERFACES
, if_list
);
323 if (!SCPreferencesCommitChanges(prefs
)) {
324 if (SCError() != EROFS
) {
325 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
336 static CFPropertyListRef
337 restoreNIPrefsFromBackup(SCPreferencesRef prefs
, CFStringRef current_model
)
339 CFPropertyListRef if_list
;
342 key
= CFStringCreateWithFormat(NULL
, 0, CFSTR("%@:%@"), INTERFACES
, current_model
);
343 if_list
= SCPreferencesGetValue(prefs
, key
);
344 if_list
= isA_CFArray(if_list
);
345 if (if_list
!= NULL
) {
346 /* Write the previously backed up Interface list for this hardware */
347 writeInterfaceList(if_list
);
349 /* Synchronize the prefs */
350 SCPreferencesSynchronize(prefs
);
352 /* Re-fetch the interface list */
353 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
354 if_list
= isA_CFArray(if_list
);
355 if (if_list
!= NULL
) {
356 /* We do not need the old interface list any more */
357 SCPreferencesRemoveValue(prefs
, key
);
358 if (!SCPreferencesCommitChanges(prefs
)) {
359 if (SCError() != EROFS
) {
360 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
371 static CF_RETURNS_RETAINED CFMutableArrayRef
375 CFStringRef old_model
;
376 CFMutableArrayRef plist
= NULL
;
377 SCPreferencesRef prefs
= NULL
;
379 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
381 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
385 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
386 if_list
= isA_CFArray(if_list
);
388 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
389 if (old_model
!= NULL
) {
390 CFStringRef new_model
;
392 new_model
= _SC_hw_model(FALSE
);
393 if (!_SC_CFEqual(old_model
, new_model
)) {
394 /* if interface list was created on other hardware,
395 Restore if a backup interface list is present */
396 if_list
= restoreNIPrefsFromBackup(prefs
, new_model
);
400 if (if_list
!= NULL
) {
402 CFIndex n
= CFArrayGetCount(if_list
);
404 plist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
405 for (i
= 0; i
< n
; i
++) {
406 CFDictionaryRef dict
;
408 dict
= CFArrayGetValueAtIndex(if_list
, i
);
409 if (isA_CFDictionary(dict
) &&
410 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceType
)) &&
411 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
412 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
413 CFArrayAppendValue(plist
, dict
);
424 static CF_RETURNS_RETAINED CFMutableArrayRef
425 previouslyActiveInterfaces()
427 CFMutableArrayRef active
;
431 if (S_dblist
== NULL
) {
435 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
437 n
= CFArrayGetCount(S_dblist
);
438 for (i
= 0; i
< n
; i
++) {
439 CFDictionaryRef if_dict
;
441 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
442 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
443 CFMutableDictionaryRef new_dict
;
445 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
446 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
447 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
448 CFArrayAppendValue(active
, new_dict
);
461 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
),
462 kSCDynamicStoreDomainPlugin
);
463 (void)SCDynamicStoreSetValue(NULL
, key
, S_state
);
469 #if !TARGET_OS_IPHONE
471 updateBondInterfaceConfiguration(SCPreferencesRef prefs
)
473 CFArrayRef interfaces
;
475 interfaces
= SCBondInterfaceCopyAll(prefs
);
476 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
477 CFRelease(interfaces
);
481 if (_SC_CFEqual(S_bonds
, interfaces
)) {
483 if (interfaces
!= NULL
) CFRelease(interfaces
);
487 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
488 S_bonds
= interfaces
;
490 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
491 SC_log(LOG_NOTICE
, "_SCBondInterfaceUpdateConfiguration() failed: %s",
492 SCErrorString(SCError()));
497 #endif // !TARGET_OS_IPHONE
500 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs
)
502 CFArrayRef interfaces
;
504 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
505 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
506 CFRelease(interfaces
);
510 if (_SC_CFEqual(S_bridges
, interfaces
)) {
512 if (interfaces
!= NULL
) CFRelease(interfaces
);
516 if (S_bridges
!= NULL
) CFRelease(S_bridges
);
517 S_bridges
= interfaces
;
519 if (!_SCBridgeInterfaceUpdateConfiguration(prefs
)) {
520 SC_log(LOG_NOTICE
, "_SCBridgeInterfaceUpdateConfiguration() failed: %s",
521 SCErrorString(SCError()));
528 updateVLANInterfaceConfiguration(SCPreferencesRef prefs
)
530 CFArrayRef interfaces
;
532 interfaces
= SCVLANInterfaceCopyAll(prefs
);
533 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
534 CFRelease(interfaces
);
538 if (_SC_CFEqual(S_vlans
, interfaces
)) {
540 if (interfaces
!= NULL
) CFRelease(interfaces
);
544 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
545 S_vlans
= interfaces
;
547 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
548 SC_log(LOG_NOTICE
, "_SCVLANInterfaceUpdateConfiguration() failed: %s",
549 SCErrorString(SCError()));
556 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
557 SCPreferencesNotification notificationType
,
560 os_activity_t activity_id
;
562 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
566 activity_id
= os_activity_start("check/update virtual network interface configuration",
567 OS_ACTIVITY_FLAG_DEFAULT
);
570 // if a new interface has been "named"
572 if (S_bonds
!= NULL
) {
576 if (S_bridges
!= NULL
) {
577 CFRelease(S_bridges
);
580 if (S_vlans
!= NULL
) {
586 #if !TARGET_OS_IPHONE
587 updateBondInterfaceConfiguration (prefs
);
588 #endif // !TARGET_OS_IPHONE
589 updateBridgeInterfaceConfiguration(prefs
);
590 updateVLANInterfaceConfiguration (prefs
);
592 // we are finished with current prefs, wait for changes
593 SCPreferencesSynchronize(prefs
);
595 os_activity_end(activity_id
);
600 #if !TARGET_OS_EMBEDDED
602 #define BT_PAN_NAME "Bluetooth PAN"
603 #define BT_PAN_MAC BT_PAN_NAME " (MAC)"
606 updateBTPANInformation(const void *value
, void *context
)
609 CFDictionaryRef dict
= (CFDictionaryRef
)value
;
611 CFDictionaryRef info
;
614 if_name
= CFDictionaryGetValue(dict
, CFSTR(kIOBSDNameKey
));
615 if (!isA_CFString(if_name
)) {
620 info
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceInfo
));
621 if (!isA_CFDictionary(info
)) {
622 // if no SCNetworkInterface info
626 name
= CFDictionaryGetValue(info
, kSCPropUserDefinedName
);
627 if (!isA_CFString(name
) || !CFEqual(name
, CFSTR(BT_PAN_NAME
))) {
628 // if not BT-PAN interface
632 CFDictionaryAddValue(S_state
, CFSTR("_" BT_PAN_NAME
"_"), if_name
);
634 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
635 if (isA_CFData(addr
)) {
636 CFDictionaryAddValue(S_state
, CFSTR("_" BT_PAN_MAC
"_"), addr
);
641 #endif // !TARGET_OS_EMBEDDED
643 static CFDictionaryRef
644 createInterfaceDict(SCNetworkInterfaceRef interface
)
646 CFMutableDictionaryRef new_if
;
649 new_if
= CFDictionaryCreateMutable(NULL
,
651 &kCFTypeDictionaryKeyCallBacks
,
652 &kCFTypeDictionaryValueCallBacks
);
654 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
656 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
660 val
= _SCNetworkInterfaceGetIOPath(interface
);
662 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
665 val
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
667 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceNamePrefix
), val
);
670 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
672 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
675 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
677 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
680 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
682 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
685 val
= SCNetworkInterfaceGetBSDName(interface
);
687 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
690 val
= SCNetworkInterfaceGetInterfaceType(interface
);
692 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
695 CFDictionarySetValue(new_if
,
697 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
699 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
704 static CFDictionaryRef
705 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
712 if (db_list
== NULL
) {
715 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
716 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
717 if (type
== NULL
|| addr
== NULL
) {
721 n
= CFArrayGetCount(db_list
);
722 for (i
= 0; i
< n
; i
++) {
724 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
727 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
728 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
729 if (t
== NULL
|| a
== NULL
)
732 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
742 static CFDictionaryRef
743 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
750 if (db_list
== NULL
) {
753 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
754 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
755 if (type
== NULL
|| unit
== NULL
) {
759 n
= CFArrayGetCount(db_list
);
760 for (i
= 0; i
< n
; i
++) {
761 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
765 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
766 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
767 if (t
== NULL
|| u
== NULL
) {
771 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
781 CFDictionaryRef match_info
;
782 CFStringRef match_type
;
783 CFBooleanRef match_builtin
;
784 CFMutableArrayRef matches
;
785 } matchContext
, *matchContextRef
;
787 static CF_RETURNS_RETAINED CFDictionaryRef
788 thinInterfaceInfo(CFDictionaryRef info
)
793 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
795 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
796 && (vid
== kIOUSBVendorIDAppleComputer
)) {
797 CFMutableDictionaryRef thin
;
799 // if this is an Apple USB device than we trust that
800 // the non-localized name will be correct.
801 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
802 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
803 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
804 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
808 return CFRetain(info
);
812 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
816 match
= _SC_CFEqual(known_info
, match_info
);
818 isA_CFDictionary(known_info
) &&
819 isA_CFDictionary(match_info
)) {
821 // if not an exact match, try thinning
822 known_info
= thinInterfaceInfo(known_info
);
823 match_info
= thinInterfaceInfo(match_info
);
824 match
= _SC_CFEqual(known_info
, match_info
);
825 if (known_info
!= NULL
) CFRelease(known_info
);
826 if (match_info
!= NULL
) CFRelease(match_info
);
833 matchKnown(const void *value
, void *context
)
835 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
836 matchContextRef match_context
= (matchContextRef
)context
;
838 // match interface type
840 CFStringRef known_type
;
842 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
843 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
848 // match SCNetworkInterfaceInfo
850 CFDictionaryRef known_info
;
852 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
853 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
858 // if requested, match [non-]builtin
859 if (match_context
->match_builtin
!= NULL
) {
860 CFBooleanRef known_builtin
;
862 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
863 if (!isA_CFBoolean(known_builtin
)) {
864 known_builtin
= kCFBooleanFalse
;
866 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
871 // if we have a match
872 if (match_context
->matches
== NULL
) {
873 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
875 CFArrayAppendValue(match_context
->matches
, known_dict
);
881 matchUnnamed(const void *value
, void *context
)
883 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
884 matchContextRef match_context
= (matchContextRef
)context
;
886 if (match_context
->matches
== NULL
) {
890 // match interface type
892 CFStringRef known_type
;
894 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
895 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
900 // match SCNetworkInterfaceInfo
902 CFDictionaryRef known_info
;
905 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
906 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
907 if (known_info
!= NULL
) CFRelease(known_info
);
913 // if requested, match [non-]builtin
914 if (match_context
->match_builtin
!= NULL
) {
915 CFBooleanRef known_builtin
;
917 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
919 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
924 // if we have a match
925 CFRelease(match_context
->matches
);
926 match_context
->matches
= NULL
;
932 interfaceExists(CFStringRef prefix
, CFNumberRef unit
)
934 Boolean found
= FALSE
;
935 CFDictionaryRef match_dict
;
936 CFStringRef match_keys
[2];
937 CFTypeRef match_vals
[2];
938 CFDictionaryRef matching
;
942 io_registry_entry_t entry
= MACH_PORT_NULL
;
943 io_iterator_t iterator
= MACH_PORT_NULL
;
945 mach_port_t masterPort
= MACH_PORT_NULL
;
947 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
948 if (kr
!= KERN_SUCCESS
) {
949 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
953 // look for kIONetworkInterface with matching prefix and unit
954 match_keys
[0] = CFSTR(kIOInterfaceNamePrefix
);
955 match_vals
[0] = prefix
;
956 match_keys
[1] = CFSTR(kIOInterfaceUnit
);
957 match_vals
[1] = unit
;
958 match_dict
= CFDictionaryCreate(NULL
,
959 (const void **)match_keys
,
960 (const void **)match_vals
,
962 &kCFTypeDictionaryKeyCallBacks
,
963 &kCFTypeDictionaryValueCallBacks
);
965 match_keys
[0] = CFSTR(kIOProviderClassKey
);
966 match_vals
[0] = CFSTR(kIONetworkInterfaceClass
);
967 match_keys
[1] = CFSTR(kIOPropertyMatchKey
);
968 match_vals
[1] = match_dict
;
969 matching
= CFDictionaryCreate(NULL
,
970 (const void **)match_keys
,
971 (const void **)match_vals
,
972 sizeof(match_keys
)/sizeof(match_keys
[0]),
973 &kCFTypeDictionaryKeyCallBacks
,
974 &kCFTypeDictionaryValueCallBacks
);
975 CFRelease(match_dict
);
977 // note: the "matching" dictionary will be consumed by the following
978 kr
= IOServiceGetMatchingServices(masterPort
, matching
, &iterator
);
979 if ((kr
!= kIOReturnSuccess
) || (iterator
== MACH_PORT_NULL
)) {
984 entry
= IOIteratorNext(iterator
);
985 if (entry
== MACH_PORT_NULL
) {
993 if (masterPort
!= MACH_PORT_NULL
) {
994 mach_port_deallocate(mach_task_self(), masterPort
);
996 if (entry
!= MACH_PORT_NULL
) {
997 IOObjectRelease(entry
);
999 if (iterator
!= MACH_PORT_NULL
) {
1000 IOObjectRelease(iterator
);
1007 * lookupMatchingInterface
1009 * Looks at the interfaces that have already been [or need to be] named with
1010 * the goal of allowing a system using a single network interface/adaptor of
1011 * a given type (vendor, model, ...) to not care about the specific adaptor
1012 * that is used (i.e. swapping dongle's is OK). Once a system has had more
1013 * than one interface/adaptor connected at the same time than we assume that
1014 * the network configuration is being setup for multi-homing that should be
1017 * If no matches are found or if more than one match is found, return NULL.
1018 * If a single match is found, return the match.
1020 static CFDictionaryRef
1021 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
1022 CFArrayRef db_list
, // already named
1023 CFArrayRef if_list
, // to be named
1024 CFIndex if_list_index
,
1025 CFBooleanRef builtin
)
1027 CFStringRef if_type
;
1028 CFDictionaryRef match
= NULL
;
1029 matchContext match_context
;
1031 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
1032 if (if_type
== NULL
) {
1036 match_context
.match_type
= if_type
;
1037 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
1038 match_context
.match_builtin
= builtin
;
1039 match_context
.matches
= NULL
;
1041 // check for matches to interfaces that have already been named
1042 // ... and append each match that we find to match_context.matches
1043 if (db_list
!= NULL
) {
1044 CFArrayApplyFunction(db_list
,
1045 CFRangeMake(0, CFArrayGetCount(db_list
)),
1050 // check for matches to interfaces that will be named
1051 // ... and CFRelease match_context.matches if we find another network
1052 // interface of the same type that also needs to be named
1053 if (if_list
!= NULL
) {
1054 CFIndex if_list_count
;
1056 if_list_count
= CFArrayGetCount(if_list
);
1057 if (if_list_index
< if_list_count
) {
1058 CFArrayApplyFunction(if_list
,
1059 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
1065 // check if we have a single match
1066 if (match_context
.matches
!= NULL
) {
1067 if (CFArrayGetCount(match_context
.matches
) == 1) {
1068 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
1070 CFRelease(match_context
.matches
);
1073 if (match
!= NULL
) {
1074 Boolean active
= TRUE
;
1077 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
1078 if (isA_CFString(name
)) {
1082 prefix
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceNamePrefix
));
1083 unit
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceUnit
));
1084 if (isA_CFString(prefix
) && isA_CFNumber(unit
)) {
1085 if (!interfaceExists(prefix
, unit
)) {
1096 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
1101 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
)
1104 CFDictionaryRef if_dict
;
1105 CFStringRef if_name
;
1106 CFNumberRef if_type
;
1107 CFNumberRef if_unit
;
1108 CFIndex n
= CFArrayGetCount(db_list
);
1109 CFComparisonResult res
;
1111 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1112 if (if_name
!= NULL
) {
1113 addTimestamp(S_state
, if_name
);
1116 if_dict
= createInterfaceDict(interface
);
1117 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1118 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1119 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
1124 for (i
= 0; i
< n
; i
++) {
1125 CFNumberRef db_type
;
1126 CFNumberRef db_unit
;
1127 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
1129 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1130 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1131 res
= CFNumberCompare(if_type
, db_type
, NULL
);
1132 if (res
== kCFCompareLessThan
1133 || (res
== kCFCompareEqualTo
1134 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
1135 == kCFCompareLessThan
))) {
1136 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
1142 CFArrayAppendValue(S_dblist
, if_dict
);
1144 #if !TARGET_OS_EMBEDDED
1145 updateBTPANInformation(if_dict
, NULL
);
1146 #endif // !TARGET_OS_EMBEDDED
1153 replaceInterface(SCNetworkInterfaceRef interface
)
1158 if (S_dblist
== NULL
) {
1159 S_dblist
= CFArrayCreateMutable(NULL
, 0,
1160 &kCFTypeArrayCallBacks
);
1162 // remove any dict that has our type/addr
1163 while (lookupInterfaceByAddress(S_dblist
, interface
, &where
) != NULL
) {
1164 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1167 // remove any dict that has the same type/unit
1168 while (lookupInterfaceByUnit(S_dblist
, interface
, &where
) != NULL
) {
1169 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1172 insertInterface(S_dblist
, interface
);
1177 issue
= CFStringCreateWithFormat(NULL
, NULL
,
1178 CFSTR("n = %d, %@"),
1181 reportIssue("Multiple interfaces updated", issue
);
1189 getHighestUnitForType(CFNumberRef if_type
)
1193 CFNumberRef ret_unit
= NULL
;
1195 if (S_dblist
== NULL
) {
1199 n
= CFArrayGetCount(S_dblist
);
1200 for (i
= 0; i
< n
; i
++) {
1201 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1204 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1205 if (CFEqual(type
, if_type
)) {
1208 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1209 if (ret_unit
== NULL
1210 || (CFNumberCompare(unit
, ret_unit
, NULL
)
1211 == kCFCompareGreaterThan
)) {
1221 * Function: ensureInterfaceHasUnit
1223 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1224 * release the interface and return NULL.
1226 static SCNetworkInterfaceRef
1227 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if
)
1230 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if
) == NULL
) {
1237 #ifdef USE_REGISTRY_ENTRY_ID
1238 static kern_return_t
1239 registerInterfaceWithIORegistryEntryID(io_connect_t connect
,
1245 CFMutableDictionaryRef dict
;
1249 dict
= CFDictionaryCreateMutable(NULL
, 0,
1250 &kCFTypeDictionaryKeyCallBacks
,
1251 &kCFTypeDictionaryValueCallBacks
);
1252 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1253 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1255 data
= CFDataCreate(NULL
, (void *) &entryID
, sizeof(entryID
));
1256 CFDictionarySetValue(dict
, CFSTR(kIORegistryEntryIDKey
), data
);
1258 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1259 kr
= IOConnectSetCFProperties(connect
, dict
);
1264 static SCNetworkInterfaceRef
1265 copyInterfaceForIORegistryEntryID(uint64_t entryID
)
1267 io_registry_entry_t entry
= MACH_PORT_NULL
;
1268 SCNetworkInterfaceRef interface
= NULL
;
1269 io_iterator_t iterator
= MACH_PORT_NULL
;
1271 mach_port_t masterPort
= MACH_PORT_NULL
;
1273 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1274 if (kr
!= KERN_SUCCESS
) {
1275 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1279 kr
= IOServiceGetMatchingServices(masterPort
,
1280 IORegistryEntryIDMatching(entryID
),
1282 if ((kr
!= KERN_SUCCESS
) || (iterator
== MACH_PORT_NULL
)) {
1283 SC_log(LOG_NOTICE
, "IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d",
1290 entry
= IOIteratorNext(iterator
);
1291 if (entry
== MACH_PORT_NULL
) {
1292 SC_log(LOG_NOTICE
, "IORegistryEntryIDMatching(0x%llx) failed", entryID
);
1296 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1299 if (masterPort
!= MACH_PORT_NULL
) {
1300 mach_port_deallocate(mach_task_self(), masterPort
);
1302 if (entry
!= MACH_PORT_NULL
) {
1303 IOObjectRelease(entry
);
1305 if (iterator
!= MACH_PORT_NULL
) {
1306 IOObjectRelease(iterator
);
1311 static SCNetworkInterfaceRef
1312 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID
)
1314 SCNetworkInterfaceRef net_if
;
1316 net_if
= copyInterfaceForIORegistryEntryID(entryID
);
1317 return (ensureInterfaceHasUnit(net_if
));
1320 #else // USE_REGISTRY_ENTRY_ID
1322 * Function: registerInterface
1324 * Register a single interface with the given service path to the
1325 * data link layer (BSD), using the specified unit number.
1327 static kern_return_t
1328 registerInterfaceWithIOServicePath(io_connect_t connect
,
1333 CFMutableDictionaryRef dict
;
1337 dict
= CFDictionaryCreateMutable(NULL
, 0,
1338 &kCFTypeDictionaryKeyCallBacks
,
1339 &kCFTypeDictionaryValueCallBacks
);
1340 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1341 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1343 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1344 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1345 kr
= IOConnectSetCFProperties(connect
, dict
);
1350 static SCNetworkInterfaceRef
1351 copyInterfaceForIOKitPath(CFStringRef if_path
)
1353 io_registry_entry_t entry
= MACH_PORT_NULL
;
1354 SCNetworkInterfaceRef interface
= NULL
;
1356 mach_port_t masterPort
= MACH_PORT_NULL
;
1359 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1360 if (kr
!= KERN_SUCCESS
) {
1361 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
1364 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1365 entry
= IORegistryEntryFromPath(masterPort
, path
);
1366 if (entry
== MACH_PORT_NULL
) {
1367 SC_log(LOG_NOTICE
, "IORegistryEntryFromPath(%@) failed", if_path
);
1371 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1374 if (masterPort
!= MACH_PORT_NULL
) {
1375 mach_port_deallocate(mach_task_self(), masterPort
);
1377 if (entry
!= MACH_PORT_NULL
) {
1378 IOObjectRelease(entry
);
1384 static SCNetworkInterfaceRef
1385 copyNamedInterfaceForIOKitPath(CFStringRef if_path
)
1387 SCNetworkInterfaceRef net_if
;
1389 net_if
= copyInterfaceForIOKitPath(if_path
);
1390 return (ensureInterfaceHasUnit(net_if
));
1393 #endif // USE_REGISTRY_ENTRY_ID
1396 displayInterface(SCNetworkInterfaceRef interface
)
1403 name
= SCNetworkInterfaceGetBSDName(interface
);
1404 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1405 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1406 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1408 SC_log(LOG_INFO
, " %s%@%sType: %@, %s%@%sMAC address: %@",
1409 (name
!= NULL
) ? "BSD Name: " : "",
1410 (name
!= NULL
) ? name
: CFSTR(""),
1411 (name
!= NULL
) ? ", " : "",
1413 (unit
!= NULL
) ? "Unit: " : "",
1414 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1415 (unit
!= NULL
) ? ", " : "",
1420 builtinAvailable(SCNetworkInterfaceRef interface
, // new interface
1421 CFNumberRef if_unit
) // desired unit
1424 CFNumberRef if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1427 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1428 for (i
= 0; i
< n
; i
++) {
1429 CFStringRef if_path
;
1430 CFDictionaryRef known_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1431 CFStringRef known_path
;
1432 CFNumberRef known_type
;
1433 CFNumberRef known_unit
;
1435 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceType
));
1436 if (!_SC_CFEqual(if_type
, known_type
)) {
1437 continue; // if not the same interface type
1440 known_unit
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceUnit
));
1441 if (!_SC_CFEqual(if_unit
, known_unit
)) {
1442 continue; // if not the same interface unit
1445 if_path
= _SCNetworkInterfaceGetIOPath(interface
);
1446 known_path
= CFDictionaryGetValue(known_dict
, CFSTR(kIOPathMatchKey
));
1447 if (!_SC_CFEqual(if_path
, known_path
)) {
1448 // if different IORegistry path
1452 // if same type, same unit, same path
1456 // if interface type/unit not found
1461 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
1466 for (i
= 0; i
< last
; i
++) {
1467 SCNetworkInterfaceRef builtin_if
;
1468 CFNumberRef builtin_type
;
1470 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1471 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
1472 if (CFEqual(if_type
, builtin_type
)) {
1473 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1474 n
++; // if built-in interface
1482 static __inline__ boolean_t
1485 return (S_quiet
== MACH_PORT_NULL
);
1489 nameInterfaces(CFMutableArrayRef if_list
)
1492 CFIndex n
= CFArrayGetCount(if_list
);
1494 for (i
= 0; i
< n
; i
++) {
1496 SCNetworkInterfaceRef interface
;
1497 SCNetworkInterfaceRef new_interface
;
1504 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1505 path
= _SCNetworkInterfaceGetIOPath(interface
);
1506 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1507 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1508 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
1511 CFStringRef if_name
;
1513 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1514 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
1515 SC_log(LOG_INFO
, "Interface already has a unit number");
1516 displayInterface(interface
);
1519 // update the list of interfaces that were previously named
1520 if ((S_prev_active_list
!= NULL
)
1521 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
1522 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1525 replaceInterface(interface
);
1527 CFDictionaryRef dbdict
;
1528 boolean_t is_builtin
;
1532 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
1533 if (dbdict
!= NULL
) {
1534 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1537 SC_log(LOG_INFO
, "Interface assigned unit %@ (from database)", unit
);
1540 if ((dbdict
== NULL
) && !isQuiet()) {
1541 // if new interface, wait until quiet before naming
1542 addTimestamp(S_state
, path
);
1546 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
1548 if (dbdict
== NULL
) {
1549 dbdict
= lookupMatchingInterface(interface
,
1553 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
1554 if (dbdict
!= NULL
) {
1555 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1558 SC_log(LOG_INFO
, "Interface assigned unit %@ (updating database)", unit
);
1562 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
1563 // update the list of interfaces that were previously named
1564 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
1565 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
1567 if (where
!= kCFNotFound
) {
1568 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1572 if (dbdict
== NULL
) {
1576 // built-in interface, try to use the reserved slots
1577 next_unit
= builtinCount(if_list
, i
, type
);
1579 // But, before claiming a reserved slot we check to see if the
1580 // slot had previously been used. If so, and if the slot had been
1581 // assigned to the same type of interface, then we will perform a
1582 // replacement (e.g. assume that this was a board swap). But, if
1583 // the new interface is a different type then we assume that the
1584 // built-in configuration has changed and allocate a new unit from
1585 // the non-reserved slots.
1587 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1588 if (!builtinAvailable(interface
, unit
)) {
1589 // if [built-in] unit not available
1590 SC_log(LOG_INFO
, "Interface not assigned [built-in] unit %@", unit
);
1597 // not built-in (or built-in unit not available), allocate from
1598 // the non-reserved slots
1599 next_unit
= builtinCount(if_list
, n
, type
);
1601 unit
= getHighestUnitForType(type
);
1605 CFNumberGetValue(unit
, kCFNumberIntType
, &high_unit
);
1606 if (high_unit
>= next_unit
) {
1607 next_unit
= high_unit
+ 1;
1611 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1614 SC_log(LOG_INFO
, "Interface assigned unit %@ (%s)",
1616 is_builtin
? "built-in" : "next available");
1621 #ifdef USE_REGISTRY_ENTRY_ID
1622 kr
= registerInterfaceWithIORegistryEntryID(S_connect
,
1625 (dbdict
== NULL
) ? kIONetworkStackRegisterInterfaceWithLowestUnit
1626 : kIONetworkStackRegisterInterfaceWithUnit
);
1627 new_interface
= copyNamedInterfaceForIORegistryEntryID(entryID
);
1628 #else // USE_REGISTRY_ENTRY_ID
1629 kr
= registerInterfaceWithIOServicePath(S_connect
,
1632 (dbdict
== NULL
) ? kRegisterInterface
1633 : kRegisterInterfaceWithFixedUnit
);
1634 new_interface
= copyNamedInterfaceForIOKitPath(path
);
1635 #endif // USE_REGISTRY_ENTRY_ID
1636 if (new_interface
== NULL
) {
1637 const char *signature
;
1639 signature
= (dbdict
== NULL
) ? "failed to name new interface"
1640 : "failed to name known interface";
1642 SC_log(LOG_NOTICE
, "%s, kr=0x%x\n"
1652 displayInterface(interface
);
1654 // report issue w/MessageTracer
1655 str
= CFStringCreateWithFormat(NULL
, NULL
,
1656 CFSTR("kr=0x%x, path=%@, unit=%@"),
1660 reportIssue(signature
, str
);
1663 if ((dbdict
!= NULL
) && (retries
++ < 5)) {
1664 usleep(50 * 1000); // sleep 50ms between attempts
1669 CFNumberRef new_unit
;
1672 SC_log(LOG_INFO
, "%s interface named after %d %s\n"
1675 (dbdict
== NULL
) ? "New" : "Known",
1677 (retries
== 1) ? "try" : "tries",
1681 #ifdef SHOW_NAMING_FAILURE
1682 str
= CFStringCreateWithFormat(NULL
,
1684 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
1685 (dbdict
== NULL
) ? "New" : "Known",
1687 (retries
== 1) ? "try" : "tries",
1689 CFUserNotificationDisplayNotice(0,
1690 kCFUserNotificationStopAlertLevel
,
1695 CFSTR("Please report repeated failures."),
1698 #endif // SHOW_NAMING_FAILURE
1701 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
1702 if (CFEqual(unit
, new_unit
) == FALSE
) {
1703 SC_log(LOG_INFO
, "interface type %@ assigned unit %@ instead of %@",
1704 type
, new_unit
, unit
);
1707 displayInterface(new_interface
);
1709 // update if_list (with the interface name & unit)
1710 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
1711 CFRelease(new_interface
);
1712 interface
= new_interface
; // if_list holds the reference
1714 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
1717 // update the list of [built-in] interfaces that were previously named
1718 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
1719 SC_log(LOG_DEBUG
, " and updated database (new address)");
1720 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1723 replaceInterface(interface
);
1731 #if !TARGET_OS_IPHONE
1733 updateNetworkConfiguration(CFArrayRef if_list
)
1735 Boolean do_commit
= FALSE
;
1738 SCPreferencesRef prefs
= NULL
;
1739 SCNetworkSetRef set
= NULL
;
1741 prefs
= SCPreferencesCreate(NULL
, CFSTR("InterfaceNamer:updateNetworkConfiguration"), NULL
);
1743 set
= SCNetworkSetCopyCurrent(prefs
);
1745 SC_log(LOG_INFO
, "No current set");
1749 n
= CFArrayGetCount(if_list
);
1750 for (i
= 0; i
< n
; i
++) {
1751 SCNetworkInterfaceRef interface
;
1753 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1754 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set
, interface
)) {
1755 SC_log(LOG_INFO
, "adding default configuration for %@",
1756 SCNetworkInterfaceGetBSDName(interface
));
1764 ok
= SCPreferencesCommitChanges(prefs
);
1766 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
1770 ok
= SCPreferencesApplyChanges(prefs
);
1772 SC_log(LOG_NOTICE
, "SCPreferencesApplyChanges() failed: %s", SCErrorString(SCError()));
1784 if (prefs
!= NULL
) {
1791 #endif // !TARGET_OS_IPHONE
1796 if (S_connect
== MACH_PORT_NULL
) {
1797 // if we don't have the "IONetworkStack" connect object
1801 if (S_iflist
!= NULL
) {
1804 n
= CFArrayGetCount(S_iflist
);
1806 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
1808 nameInterfaces(S_iflist
);
1813 * The registry [matching] has quiesced so let's
1814 * - save the DB with the interfaces that have been named
1815 * - update the VLAN/BOND configuration
1816 * - tell everyone that we've finished (at least for now)
1817 * - log those interfaces which are no longer present
1818 * in the HW config (or have yet to show up).
1820 writeInterfaceList(S_dblist
);
1821 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
1823 #if !TARGET_OS_IPHONE
1824 if (access("/usr/libexec/UserEventAgent", X_OK
) == -1
1825 && errno
== ENOENT
) {
1827 * We are most likely booted into the Recovery OS with no "SCMonitor"
1828 * UserEventAgent plugin running so let's make sure we update the
1829 * network configuration for new interfaces.
1831 updateNetworkConfiguration(S_iflist
);
1833 #endif // !TARGET_OS_IPHONE
1837 if (S_iflist
!= NULL
) {
1838 CFRelease(S_iflist
);
1842 if (S_prev_active_list
!= NULL
) {
1846 n
= CFArrayGetCount(S_prev_active_list
);
1848 SC_log(LOG_INFO
, "Interface%s not [yet] active",
1849 (n
> 1) ? "s" : "");
1851 for (i
= 0; i
< n
; i
++) {
1852 CFDictionaryRef if_dict
;
1857 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
1858 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
1859 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
1860 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
1861 SC_log(LOG_INFO
, " %s%@%sType: %@, Unit: %@",
1862 (name
!= NULL
) ? "BSD Name: " : "",
1863 (name
!= NULL
) ? name
: CFSTR(""),
1864 (name
!= NULL
) ? ", " : "",
1869 CFRelease(S_prev_active_list
);
1870 S_prev_active_list
= NULL
;
1873 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
1875 * if we've named all of the interfaces that
1876 * were used during the previous boot.
1878 addTimestamp(S_state
, CFSTR("*RELEASE*"));
1879 SC_log(LOG_INFO
, "last boot interfaces have been named");
1881 CFRelease(S_prev_active_list
);
1882 S_prev_active_list
= NULL
;
1890 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
1892 os_activity_t activity_id
;
1895 activity_id
= os_activity_start("process new network interface",
1896 OS_ACTIVITY_FLAG_DEFAULT
);
1898 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
1899 SCNetworkInterfaceRef interface
;
1901 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
1902 if (interface
!= NULL
) {
1903 if (S_iflist
== NULL
) {
1904 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1906 CFArrayAppendValue(S_iflist
, interface
);
1907 CFRelease(interface
);
1909 IOObjectRelease(obj
);
1914 os_activity_end(activity_id
);
1920 * Function: stackCallback
1922 * Get a reference to the single IONetworkStack object instance in
1923 * the kernel. Naming requests must be sent to this object, which is
1924 * attached as a client to all network interface objects in the system.
1926 * Call IOObjectRelease on the returned object.
1929 stackCallback(void *refcon
, io_iterator_t iter
)
1931 os_activity_t activity_id
;
1935 activity_id
= os_activity_start("process IONetworkStack",
1936 OS_ACTIVITY_FLAG_DEFAULT
);
1938 stack
= IOIteratorNext(iter
);
1939 if (stack
== MACH_PORT_NULL
) {
1943 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
1944 if (kr
!= KERN_SUCCESS
) {
1945 SC_log(LOG_ERR
, "IOServiceOpen returned 0x%x", kr
);
1949 addTimestamp(S_state
, CFSTR("*STACK*"));
1950 SC_log(LOG_INFO
, "IONetworkStack found");
1952 if (S_stack
!= MACH_PORT_NULL
) {
1953 IOObjectRelease(S_stack
);
1954 S_stack
= MACH_PORT_NULL
;
1957 if ((S_timer
!= NULL
) && CFRunLoopTimerIsValid(S_timer
)) {
1958 // With the IONetworkStack object now available we can
1959 // reset (shorten?) the time we are willing to wait for
1960 // IOKit to quiesce.
1961 CFRunLoopTimerSetNextFireDate(S_timer
,
1962 CFAbsoluteTimeGetCurrent() + S_quiet_timeout
);
1969 if (stack
!= MACH_PORT_NULL
) {
1970 IOObjectRelease(stack
);
1973 os_activity_end(activity_id
);
1979 quietCallback(void *refcon
,
1980 io_service_t service
,
1981 natural_t messageType
,
1982 void *messageArgument
)
1984 os_activity_t activity_id
;
1986 if (messageArgument
!= NULL
) {
1991 activity_id
= os_activity_start("process IOKit quiet",
1992 OS_ACTIVITY_FLAG_DEFAULT
);
1994 if (messageType
== kIOMessageServiceBusyStateChange
) {
1995 addTimestamp(S_state
, CFSTR("*QUIET*"));
1996 SC_log(LOG_INFO
, "IOKit quiet");
1999 if (S_connect
== MACH_PORT_NULL
) {
2000 SC_log(LOG_ERR
, "No network stack object");
2004 if (S_quiet
!= MACH_PORT_NULL
) {
2005 IOObjectRelease(S_quiet
);
2006 S_quiet
= MACH_PORT_NULL
;
2009 if (S_timer
!= NULL
) {
2010 CFRunLoopTimerInvalidate(S_timer
);
2015 // grab (and name) any additional interfaces.
2016 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2018 if (messageType
== kIOMessageServiceBusyStateChange
) {
2019 addTimestamp(S_state
, CFSTR("*QUIET&NAMED*"));
2025 os_activity_end(activity_id
);
2031 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, CFMutableStringRef snapshot
, int *count
)
2033 kern_return_t kr
= kIOReturnSuccess
;;
2036 while ((kr
== kIOReturnSuccess
) &&
2037 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
2038 uint64_t accumulated_busy_time
;
2039 uint32_t busy_state
;
2042 CFMutableArrayRef newNodes
;
2044 CFMutableStringRef str
= NULL
;
2046 if (nodes
== NULL
) {
2047 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2049 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
2051 assert(newNodes
!= NULL
);
2053 kr
= IORegistryEntryGetName(obj
, name
);
2054 if (kr
!= kIOReturnSuccess
) {
2055 SC_log(LOG_NOTICE
, "IORegistryEntryGetName() returned 0x%x", kr
);
2059 str
= CFStringCreateMutable(NULL
, 0);
2060 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
2062 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
2064 case kIOReturnSuccess
:
2065 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
2066 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
2068 case kIOReturnNotFound
:
2071 SC_log(LOG_NOTICE
, "IORegistryEntryGetLocationInPlane() returned 0x%x", kr
);
2076 CFArrayAppendValue(newNodes
, str
);
2079 kr
= IOServiceGetBusyStateAndTime(obj
, &state
, &busy_state
, &accumulated_busy_time
);
2080 if (kr
!= kIOReturnSuccess
) {
2081 SC_log(LOG_NOTICE
, "IOServiceGetBusyStateAndTime() returned 0x%x", kr
);
2085 #ifdef TEST_SNAPSHOT
2088 #endif // TEST_SNAPSHOT
2090 if (busy_state
!= 0) {
2093 if ((*count
)++ == 0) {
2094 CFStringAppend(snapshot
, CFSTR("Busy services :"));
2097 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
2098 CFStringAppendFormat(snapshot
, NULL
,
2099 CFSTR("\n %@ [%s%s%s%d, %lld ms]"),
2101 (state
& kIOServiceRegisteredState
) ? "" : "!registered, ",
2102 (state
& kIOServiceMatchedState
) ? "" : "!matched, ",
2103 (state
& kIOServiceInactiveState
) ? "inactive, " : "",
2105 accumulated_busy_time
/ kMillisecondScale
);
2109 kr
= IORegistryIteratorEnterEntry(iterator
);
2110 if (kr
!= kIOReturnSuccess
) {
2111 SC_log(LOG_NOTICE
, "IORegistryIteratorEnterEntry() returned 0x%x", kr
);
2115 iterateRegistryBusy(iterator
, newNodes
, snapshot
, count
);
2117 kr
= IORegistryIteratorExitEntry(iterator
);
2118 if (kr
!= kIOReturnSuccess
) {
2119 SC_log(LOG_NOTICE
, "IORegistryIteratorExitEntry() returned 0x%x", kr
);
2124 CFRelease(newNodes
);
2125 IOObjectRelease(obj
);
2131 static CF_RETURNS_RETAINED CFStringRef
2135 io_iterator_t iterator
= MACH_PORT_NULL
;
2137 CFMutableStringRef snapshot
;
2139 snapshot
= CFStringCreateMutable(NULL
, 0);
2141 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
2145 if (kr
!= kIOReturnSuccess
) {
2146 SC_log(LOG_NOTICE
, "IORegistryCreateIterator() returned 0x%x", kr
);
2150 iterateRegistryBusy(iterator
, NULL
, snapshot
, &count
);
2152 CFStringAppend(snapshot
, CFSTR("w/no busy services"));
2155 IOObjectRelease(iterator
);
2160 timerCallback(CFRunLoopTimerRef timer
, void *info
)
2162 os_activity_t activity_id
;
2163 CFStringRef snapshot
;
2165 activity_id
= os_activity_start("process IOKit timer",
2166 OS_ACTIVITY_FLAG_DEFAULT
);
2168 // We've been waiting for IOKit to quiesce and it just
2169 // hasn't happenned. Time to just move on!
2170 addTimestamp(S_state
, CFSTR("*TIMEOUT*"));
2173 snapshot
= captureBusy();
2174 SC_log(LOG_ERR
, "timed out waiting for IOKit to quiesce\n%@", snapshot
);
2175 reportIssue("timed out waiting for IOKit to quiesce", snapshot
);
2176 CFRelease(snapshot
);
2178 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
2180 addTimestamp(S_state
, CFSTR("*TIMEOUT&NAMED*"));
2183 os_activity_end(activity_id
);
2189 setup_IOKit(CFBundleRef bundle
)
2193 mach_port_t masterPort
= MACH_PORT_NULL
;
2195 io_object_t root
= MACH_PORT_NULL
;
2197 // read DB of previously named network interfaces
2198 S_dblist
= readInterfaceList();
2199 if (S_dblist
!= NULL
) {
2202 n
= CFArrayGetCount(S_dblist
);
2204 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
2208 // get interfaces that were named during the last boot
2209 S_prev_active_list
= previouslyActiveInterfaces();
2211 // track how long we've waited to see each interface.
2212 S_state
= CFDictionaryCreateMutable(NULL
,
2214 &kCFTypeDictionaryKeyCallBacks
,
2215 &kCFTypeDictionaryValueCallBacks
);
2216 addTimestamp(S_state
, CFSTR("*START*"));
2218 // Creates and returns a notification object for receiving IOKit
2219 // notifications of new devices or state changes.
2220 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
2221 if (kr
!= KERN_SUCCESS
) {
2222 SC_log(LOG_ERR
, "IOMasterPort returned 0x%x", kr
);
2226 S_notify
= IONotificationPortCreate(masterPort
);
2227 if (S_notify
== NULL
) {
2228 SC_log(LOG_ERR
, "IONotificationPortCreate failed");
2232 // watch IOKit matching activity
2233 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
2234 if (root
== MACH_PORT_NULL
) {
2235 SC_log(LOG_ERR
, "IORegistryEntryFromPath failed");
2239 kr
= IOServiceAddInterestNotification(S_notify
,
2243 (void *)S_notify
, // refCon
2244 &S_quiet
); // notification
2245 if (kr
!= KERN_SUCCESS
) {
2246 SC_log(LOG_ERR
, "IOServiceAddInterestNotification returned 0x%x", kr
);
2250 kr
= IOServiceGetBusyState(root
, &busy
);
2251 if (kr
!= KERN_SUCCESS
) {
2252 SC_log(LOG_ERR
, "IOServiceGetBusyState returned 0x%x", kr
);
2256 // add a timer so we don't wait forever for IOKit to quiesce
2257 S_timer
= CFRunLoopTimerCreate(NULL
,
2258 CFAbsoluteTimeGetCurrent() + S_stack_timeout
,
2264 if (S_timer
== NULL
) {
2265 SC_log(LOG_ERR
, "CFRunLoopTimerCreate failed");
2269 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
2271 // watch for the introduction of the IONetworkStack
2272 kr
= IOServiceAddMatchingNotification(S_notify
,
2273 kIOFirstMatchNotification
,
2274 IOServiceMatching("IONetworkStack"),
2276 (void *)S_notify
, // refCon
2277 &S_stack
); // notification
2278 if (kr
!= KERN_SUCCESS
) {
2279 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
2283 // check and see if the stack is already available and arm the
2284 // notification for its introduction.
2285 stackCallback((void *)S_notify
, S_stack
);
2287 // watch for the introduction of new network interfaces
2288 kr
= IOServiceAddMatchingNotification(S_notify
,
2289 kIOFirstMatchNotification
,
2290 IOServiceMatching("IONetworkInterface"),
2291 &interfaceArrivalCallback
,
2292 (void *)S_notify
, // refCon
2293 &S_iter
); // notification
2294 if (kr
!= KERN_SUCCESS
) {
2295 SC_log(LOG_ERR
, "IOServiceAddMatchingNotification returned 0x%x", kr
);
2299 // Get the current list of matches and arm the notification for
2300 // future interface arrivals.
2301 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2303 // Check if IOKit has already quiesced.
2304 quietCallback((void *)S_notify
,
2306 kIOMessageServiceBusyStateChange
,
2307 (void *)(uintptr_t)busy
);
2309 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2310 IONotificationPortGetRunLoopSource(S_notify
),
2311 kCFRunLoopDefaultMode
);
2313 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
2315 * Start the wheels turning until we've named all of
2316 * the interfaces that were used during the previous
2317 * boot, until IOKit [matching] has quiesced, or
2318 * until we've waited long enough.
2320 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
2321 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2322 IONotificationPortGetRunLoopSource(S_notify
),
2324 while (S_prev_active_list
!= NULL
) {
2327 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
2329 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
2331 #if !TARGET_OS_EMBEDDED
2332 if (S_dblist
!= NULL
) {
2333 // apply special handling for the BT-PAN interface (if present)
2334 CFArrayApplyFunction(S_dblist
,
2335 CFRangeMake(0, CFArrayGetCount(S_dblist
)),
2336 updateBTPANInformation
,
2339 #endif // !TARGET_OS_EMBEDDED
2344 if (root
!= MACH_PORT_NULL
) {
2345 IOObjectRelease(root
);
2347 if (masterPort
!= MACH_PORT_NULL
) {
2348 mach_port_deallocate(mach_task_self(), masterPort
);
2355 setup_Virtual(CFBundleRef bundle
)
2357 // open a SCPreferences session
2358 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
);
2359 if (S_prefs
== NULL
) {
2360 SC_log(LOG_ERR
, "SCPreferencesCreate() failed: %s",
2361 SCErrorString(SCError()));
2365 // register for change notifications.
2366 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
2367 SC_log(LOG_ERR
, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
2373 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
2374 if (SCError() != kSCStatusNoStoreServer
) {
2375 SC_log(LOG_ERR
, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
2385 exec_InterfaceNamer(void *arg
)
2387 CFBundleRef bundle
= (CFBundleRef
)arg
;
2388 CFDictionaryRef dict
;
2390 pthread_setname_np(MY_PLUGIN_NAME
" thread");
2392 dict
= CFBundleGetInfoDictionary(bundle
);
2393 if (isA_CFDictionary(dict
)) {
2396 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_STACK_TIMEOUT_KEY
));
2398 if (!isA_CFNumber(num
) ||
2399 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_stack_timeout
) ||
2400 (S_stack_timeout
<= 0.0)) {
2401 SC_log(LOG_NOTICE
, WAIT_STACK_TIMEOUT_KEY
" value error");
2402 S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
2406 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
2408 if (!isA_CFNumber(num
) ||
2409 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_quiet_timeout
) ||
2410 (S_quiet_timeout
<= 0.0)) {
2411 SC_log(LOG_NOTICE
, WAIT_QUIET_TIMEOUT_KEY
" value error");
2412 S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
2417 // setup virtual network interface monitoring
2418 if (!setup_Virtual(bundle
)) {
2422 // setup [IOKit] network interface monitoring
2423 if (!setup_IOKit(bundle
)) {
2430 if (S_connect
!= MACH_PORT_NULL
) {
2431 IOServiceClose(S_connect
);
2432 S_connect
= MACH_PORT_NULL
;
2434 if (S_dblist
!= NULL
) {
2435 CFRelease(S_dblist
);
2438 if (S_iter
!= MACH_PORT_NULL
) {
2439 IOObjectRelease(S_iter
);
2440 S_iter
= MACH_PORT_NULL
;
2442 if (S_notify
!= MACH_PORT_NULL
) {
2443 IONotificationPortDestroy(S_notify
);
2445 if (S_quiet
!= MACH_PORT_NULL
) {
2446 IOObjectRelease(S_quiet
);
2447 S_quiet
= MACH_PORT_NULL
;
2449 if (S_stack
!= MACH_PORT_NULL
) {
2450 IOObjectRelease(S_stack
);
2451 S_stack
= MACH_PORT_NULL
;
2453 if (S_state
!= NULL
) {
2457 if (S_timer
!= NULL
) {
2458 CFRunLoopTimerInvalidate(S_timer
);
2472 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
2474 pthread_attr_t tattr
;
2477 CFRetain(bundle
); // released in exec_InterfaceNamer
2479 pthread_attr_init(&tattr
);
2480 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
2481 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
2482 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
2483 pthread_create(&tid
, &tattr
, exec_InterfaceNamer
, bundle
);
2484 pthread_attr_destroy(&tattr
);
2489 //------------------------------------------------------------------------
2493 main(int argc
, char ** argv
)
2498 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2500 bundle
= CFBundleGetMainBundle();
2501 CFRetain(bundle
); // released in exec_InterfaceNamer
2503 (void)exec_InterfaceNamer();
2511 #ifdef TEST_SNAPSHOT
2513 main(int argc
, char ** argv
)
2515 CFStringRef snapshot
;
2518 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2520 snapshot
= captureBusy();
2521 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), snapshot
);
2522 CFRelease(snapshot
);
2527 #endif /* TEST_SNAPSHOT */