2 * Copyright (c) 2001-2013 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>
75 #include <CommonCrypto/CommonDigest.h>
77 #include <CoreFoundation/CoreFoundation.h>
79 #include <SystemConfiguration/SystemConfiguration.h>
80 #include <SystemConfiguration/SCDPlugin.h>
81 #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
82 #include <SystemConfiguration/SCValidation.h>
84 #include <IOKit/IOKitLib.h>
85 #include <IOKit/IOKitLibPrivate.h>
86 #include <IOKit/IOBSD.h>
87 #include <IOKit/IOMessage.h>
88 #include <IOKit/network/IONetworkController.h>
89 #include <IOKit/network/IONetworkInterface.h>
90 #include <IOKit/network/IONetworkStack.h>
91 #include <IOKit/usb/USB.h>
93 #ifdef kIONetworkStackUserCommandKey
94 #define USE_REGISTRY_ENTRY_ID
97 #ifndef USE_REGISTRY_ENTRY_ID
98 // from <IOKit/network/IONetworkStack.h>
99 #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand"
101 kRegisterInterfaceWithFixedUnit
= 0,
103 kRegisterAllInterfaces
105 #endif // !USE_REGISTRY_ENTRY_ID
107 #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo"
108 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
109 #define kSCNetworkInterfaceActive "Active"
111 #define MY_PLUGIN_NAME "InterfaceNamer"
112 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
114 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
115 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
117 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
118 #define WAIT_QUIET_TIMEOUT_DEFAULT 60.0
122 * "IONetworkStack" connect object used to "name" an interface.
124 static io_connect_t S_connect
= MACH_PORT_NULL
;
128 * An array of CFDictionary's representing the interfaces
129 * that have been identified and [need to be] named.
131 static CFMutableArrayRef S_dblist
= NULL
;
135 * A boolean that enables additional logging.
137 static boolean_t S_debug
= FALSE
;
141 * An array of SCNetworkInterface's representing the
142 * interfaces that have been identified.
144 static CFMutableArrayRef S_iflist
= NULL
;
148 * IOServiceAddMatchingNotification object used to watch for
149 * new network interfaces.
151 static io_iterator_t S_iter
= MACH_PORT_NULL
;
155 * notification object for receiving IOKit notifications of
156 * new devices or state changes.
158 static IONotificationPortRef S_notify
= NULL
;
160 /* S_prev_active_list
161 * An array of CFDictionary's representing the previously
164 static CFMutableArrayRef S_prev_active_list
= NULL
;
168 * IOServiceAddInterestNotification object used to watch for
169 * IOKit matching to quiesce.
171 static io_object_t S_quiet
= MACH_PORT_NULL
;
175 * IOServiceAddMatchingNotification object used to watch for
176 * the availability of the "IONetworkStack" object.
178 static io_iterator_t S_stack
= MACH_PORT_NULL
;
182 * A dictionary containing Information about each network
183 * interface. For now, the key is the BSD name and the
184 * value is a CFNumber noting how long (in milliseconds)
185 * it took for the interface to be recognized/named.
187 static CFMutableDictionaryRef S_state
= NULL
;
191 * CFRunLoopTimer tracking how long we are willing to wait
192 * for IOKit matching to quiesce (IOKitWaitQuiet).
195 * time to wait for the IONetworkStack object to appear before timeout
198 * time to wait for the IOKit to quiesce (after the IONetworkStack is
201 static CFRunLoopTimerRef S_timer
= NULL
;
202 static double S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
203 static double S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
205 #if !TARGET_OS_EMBEDDED
207 * S_vproc_transaction
208 * The vproc transaction used to keep launchd from sending us
209 * a SIGKILL before we've had a chance to set the platform UUID
211 vproc_transaction_t S_vproc_transaction
= NULL
;
212 #endif // !TARGET_OS_EMBEDDED
215 * Virtual network interface configuration
216 * S_prefs : SCPreferences to configuration
217 * S_bonds : most recently actived Bond configuration
218 * S_bridges : most recently actived Bridge configuration
219 * S_vlans : most recently actived VLAN configuration
221 static SCPreferencesRef S_prefs
= NULL
;
222 static CFArrayRef S_bonds
= NULL
;
223 static CFArrayRef S_bridges
= NULL
;
224 static CFArrayRef S_vlans
= NULL
;
227 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
232 now
= CFAbsoluteTimeGetCurrent();
233 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
234 CFDictionaryAddValue(dict
, key
, val
);
239 #define INTERFACES CFSTR("Interfaces")
240 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
242 static CFComparisonResult
243 if_unit_compare(const void *val1
, const void *val2
, void *context
)
245 CFComparisonResult res
;
251 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
252 CFSTR(kIOInterfaceType
));
253 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
254 CFSTR(kIOInterfaceType
));
255 res
= CFNumberCompare(type1
, type2
, NULL
);
256 if (res
!= kCFCompareEqualTo
) {
259 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
260 CFSTR(kIOInterfaceUnit
));
261 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
262 CFSTR(kIOInterfaceUnit
));
263 return (CFNumberCompare(unit1
, unit2
, NULL
));
267 reportIssue(const char *signature
, CFStringRef issue
)
271 m
= asl_new(ASL_TYPE_MSG
);
272 asl_set(m
, "com.apple.message.domain", "com.apple.SystemConfiguration." MY_PLUGIN_NAME
);
273 asl_set(m
, "com.apple.message.signature", signature
);
274 asl_set(m
, "com.apple.message.result", "failure");
275 SCLOG(NULL
, m
, ~ASL_LEVEL_ERR
, CFSTR("%s\n%@"), signature
, issue
);
282 writeInterfaceList(CFArrayRef if_list
)
285 CFStringRef new_model
;
286 CFStringRef old_model
;
287 SCPreferencesRef prefs
;
289 if (isA_CFArray(if_list
) == NULL
) {
293 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
296 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate failed, %s"),
297 SCErrorString(SCError()));
301 cur_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
302 if (_SC_CFEqual(cur_list
, if_list
)) {
306 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
307 new_model
= _SC_hw_model();
308 if ((new_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
310 if ((old_model
!= NULL
) && (cur_list
!= NULL
)) {
314 // if interface list was created on other hardware
315 history
= CFStringCreateWithFormat(NULL
, NULL
,
319 SCPreferencesSetValue(prefs
, history
, cur_list
);
323 CFSTR(MY_PLUGIN_NAME
": Hardware model changed\n"
324 MY_PLUGIN_NAME
": created on \"%@\"\n"
325 MY_PLUGIN_NAME
": now on \"%@\""),
329 issue
= CFStringCreateWithFormat(NULL
, NULL
,
333 reportIssue("Hardware model changed", issue
);
337 if (!SCPreferencesSetValue(prefs
, MODEL
, new_model
)) {
339 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetValue failed, %s"),
340 SCErrorString(SCError()));
345 if (!SCPreferencesSetValue(prefs
, INTERFACES
, if_list
)) {
347 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetValue failed, %s"),
348 SCErrorString(SCError()));
352 if (!SCPreferencesCommitChanges(prefs
)) {
353 SCLog((SCError() != EROFS
), LOG_ERR
,
354 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCommitChanges failed, %s"),
355 SCErrorString(SCError()));
365 static CF_RETURNS_RETAINED CFMutableArrayRef
369 CFStringRef old_model
;
370 CFMutableArrayRef plist
= NULL
;
371 SCPreferencesRef prefs
= NULL
;
373 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
376 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate failed, %s"),
377 SCErrorString(SCError()));
381 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
382 if_list
= isA_CFArray(if_list
);
384 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
385 if (old_model
!= NULL
) {
386 CFStringRef new_model
;
388 new_model
= _SC_hw_model();
389 if (!_SC_CFEqual(old_model
, new_model
)) {
390 // if interface list was created on other hardware
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
)) {
487 CFSTR(MY_PLUGIN_NAME
": _SCBondInterfaceUpdateConfiguration failed, %s"),
488 SCErrorString(SCError()));
493 #endif // !TARGET_OS_IPHONE
496 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs
)
498 CFArrayRef interfaces
;
500 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
501 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
502 CFRelease(interfaces
);
506 if (_SC_CFEqual(S_bridges
, interfaces
)) {
508 if (interfaces
!= NULL
) CFRelease(interfaces
);
512 if (S_bridges
!= NULL
) CFRelease(S_bridges
);
513 S_bridges
= interfaces
;
515 if (!_SCBridgeInterfaceUpdateConfiguration(prefs
)) {
517 CFSTR(MY_PLUGIN_NAME
": _SCBridgeInterfaceUpdateConfiguration failed, %s"),
518 SCErrorString(SCError()));
525 updateVLANInterfaceConfiguration(SCPreferencesRef prefs
)
527 CFArrayRef interfaces
;
529 interfaces
= SCVLANInterfaceCopyAll(prefs
);
530 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
531 CFRelease(interfaces
);
535 if (_SC_CFEqual(S_vlans
, interfaces
)) {
537 if (interfaces
!= NULL
) CFRelease(interfaces
);
541 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
542 S_vlans
= interfaces
;
544 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
546 CFSTR(MY_PLUGIN_NAME
": _SCVLANInterfaceUpdateConfiguration failed, %s"),
547 SCErrorString(SCError()));
554 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
555 SCPreferencesNotification notificationType
,
558 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
563 // if a new interface has been "named"
565 if (S_bonds
!= NULL
) {
569 if (S_bridges
!= NULL
) {
570 CFRelease(S_bridges
);
573 if (S_vlans
!= NULL
) {
579 #if !TARGET_OS_IPHONE
580 updateBondInterfaceConfiguration (prefs
);
581 #endif // !TARGET_OS_IPHONE
582 updateBridgeInterfaceConfiguration(prefs
);
583 updateVLANInterfaceConfiguration (prefs
);
585 // we are finished with current prefs, wait for changes
586 SCPreferencesSynchronize(prefs
);
590 #if !TARGET_OS_EMBEDDED
592 #define BT_PAN_NAME "Bluetooth PAN"
595 updateBTPANInformation(const void *value
, void *context
)
596 { CFDictionaryRef dict
= (CFDictionaryRef
)value
;
598 CFDictionaryRef info
;
601 if_name
= CFDictionaryGetValue(dict
, CFSTR(kIOBSDNameKey
));
602 if (!isA_CFString(if_name
)) {
607 info
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceInfo
));
608 if (!isA_CFDictionary(info
)) {
609 // if no SCNetworkInterface info
613 name
= CFDictionaryGetValue(info
, kSCPropUserDefinedName
);
614 if (!isA_CFString(name
) || !CFEqual(name
, CFSTR(BT_PAN_NAME
))) {
615 // if not BT-PAN interface
619 CFDictionaryAddValue(S_state
, CFSTR("_" BT_PAN_NAME
"_"), if_name
);
622 #endif // !TARGET_OS_EMBEDDED
624 static CFDictionaryRef
625 createInterfaceDict(SCNetworkInterfaceRef interface
)
627 CFMutableDictionaryRef new_if
;
630 new_if
= CFDictionaryCreateMutable(NULL
,
632 &kCFTypeDictionaryKeyCallBacks
,
633 &kCFTypeDictionaryValueCallBacks
);
635 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
637 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
641 val
= _SCNetworkInterfaceGetIOPath(interface
);
643 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
646 val
= _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface
);
648 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceNamePrefix
), val
);
651 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
653 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
656 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
658 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
661 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
663 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
666 val
= SCNetworkInterfaceGetBSDName(interface
);
668 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
671 val
= SCNetworkInterfaceGetInterfaceType(interface
);
673 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
676 CFDictionarySetValue(new_if
,
678 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
680 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
685 static CFDictionaryRef
686 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
693 if (db_list
== NULL
) {
696 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
697 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
698 if (type
== NULL
|| addr
== NULL
) {
702 n
= CFArrayGetCount(db_list
);
703 for (i
= 0; i
< n
; i
++) {
705 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
708 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
709 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
710 if (t
== NULL
|| a
== NULL
)
713 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
723 static CFDictionaryRef
724 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
731 if (db_list
== NULL
) {
734 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
735 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
736 if (type
== NULL
|| unit
== NULL
) {
740 n
= CFArrayGetCount(db_list
);
741 for (i
= 0; i
< n
; i
++) {
742 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
746 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
747 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
748 if (t
== NULL
|| u
== NULL
) {
752 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
762 CFDictionaryRef match_info
;
763 CFStringRef match_type
;
764 CFBooleanRef match_builtin
;
765 CFMutableArrayRef matches
;
766 } matchContext
, *matchContextRef
;
768 static CF_RETURNS_RETAINED CFDictionaryRef
769 thinInterfaceInfo(CFDictionaryRef info
)
774 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
776 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
777 && (vid
== kIOUSBVendorIDAppleComputer
)) {
778 CFMutableDictionaryRef thin
;
780 // if this is an Apple USB device than we trust that
781 // the non-localized name will be correct.
782 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
783 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
784 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
785 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
789 return CFRetain(info
);
793 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
797 match
= _SC_CFEqual(known_info
, match_info
);
799 isA_CFDictionary(known_info
) &&
800 isA_CFDictionary(match_info
)) {
802 // if not an exact match, try thinning
803 known_info
= thinInterfaceInfo(known_info
);
804 match_info
= thinInterfaceInfo(match_info
);
805 match
= _SC_CFEqual(known_info
, match_info
);
806 if (known_info
!= NULL
) CFRelease(known_info
);
807 if (match_info
!= NULL
) CFRelease(match_info
);
814 matchKnown(const void *value
, void *context
)
816 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
817 matchContextRef match_context
= (matchContextRef
)context
;
819 // match interface type
821 CFStringRef known_type
;
823 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
824 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
829 // match SCNetworkInterfaceInfo
831 CFDictionaryRef known_info
;
833 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
834 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
839 // if requested, match [non-]builtin
840 if (match_context
->match_builtin
!= NULL
) {
841 CFBooleanRef known_builtin
;
843 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
844 if (!isA_CFBoolean(known_builtin
)) {
845 known_builtin
= kCFBooleanFalse
;
847 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
852 // if we have a match
853 if (match_context
->matches
== NULL
) {
854 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
856 CFArrayAppendValue(match_context
->matches
, known_dict
);
862 matchUnnamed(const void *value
, void *context
)
864 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
865 matchContextRef match_context
= (matchContextRef
)context
;
867 if (match_context
->matches
== NULL
) {
871 // match interface type
873 CFStringRef known_type
;
875 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
876 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
881 // match SCNetworkInterfaceInfo
883 CFDictionaryRef known_info
;
886 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
887 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
888 if (known_info
!= NULL
) CFRelease(known_info
);
894 // if requested, match [non-]builtin
895 if (match_context
->match_builtin
!= NULL
) {
896 CFBooleanRef known_builtin
;
898 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
900 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
905 // if we have a match
906 CFRelease(match_context
->matches
);
907 match_context
->matches
= NULL
;
913 interfaceExists(CFStringRef prefix
, CFNumberRef unit
)
915 Boolean found
= FALSE
;
916 CFDictionaryRef match_dict
;
917 CFStringRef match_keys
[2];
918 CFTypeRef match_vals
[2];
919 CFDictionaryRef matching
;
923 io_registry_entry_t entry
= MACH_PORT_NULL
;
924 io_iterator_t iterator
= MACH_PORT_NULL
;
926 mach_port_t masterPort
= MACH_PORT_NULL
;
928 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
929 if (kr
!= KERN_SUCCESS
) {
931 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x"),
936 // look for kIONetworkInterface with matching prefix and unit
937 match_keys
[0] = CFSTR(kIOInterfaceNamePrefix
);
938 match_vals
[0] = prefix
;
939 match_keys
[1] = CFSTR(kIOInterfaceUnit
);
940 match_vals
[1] = unit
;
941 match_dict
= CFDictionaryCreate(NULL
,
942 (const void **)match_keys
,
943 (const void **)match_vals
,
945 &kCFTypeDictionaryKeyCallBacks
,
946 &kCFTypeDictionaryValueCallBacks
);
948 match_keys
[0] = CFSTR(kIOProviderClassKey
);
949 match_vals
[0] = CFSTR(kIONetworkInterfaceClass
);
950 match_keys
[1] = CFSTR(kIOPropertyMatchKey
);
951 match_vals
[1] = match_dict
;
952 matching
= CFDictionaryCreate(NULL
,
953 (const void **)match_keys
,
954 (const void **)match_vals
,
955 sizeof(match_keys
)/sizeof(match_keys
[0]),
956 &kCFTypeDictionaryKeyCallBacks
,
957 &kCFTypeDictionaryValueCallBacks
);
958 CFRelease(match_dict
);
960 // note: the "matching" dictionary will be consumed by the following
961 kr
= IOServiceGetMatchingServices(masterPort
, matching
, &iterator
);
962 if ((kr
!= kIOReturnSuccess
) || (iterator
== MACH_PORT_NULL
)) {
967 entry
= IOIteratorNext(iterator
);
968 if (entry
== MACH_PORT_NULL
) {
976 if (masterPort
!= MACH_PORT_NULL
) {
977 mach_port_deallocate(mach_task_self(), masterPort
);
979 if (entry
!= MACH_PORT_NULL
) {
980 IOObjectRelease(entry
);
982 if (iterator
!= MACH_PORT_NULL
) {
983 IOObjectRelease(iterator
);
990 * lookupMatchingInterface
992 * Looks at the interfaces that have already been [or need to be] named with
993 * the goal of allowing a system using a single network interface/adaptor of
994 * a given type (vendor, model, ...) to not care about the specific adaptor
995 * that is used (i.e. swapping dongle's is OK). Once a system has had more
996 * than one interface/adaptor connected at the same time than we assume that
997 * the network configuration is being setup for multi-homing that should be
1000 * If no matches are found or if more than one match is found, return NULL.
1001 * If a single match is found, return the match.
1003 static CFDictionaryRef
1004 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
1005 CFArrayRef db_list
, // already named
1006 CFArrayRef if_list
, // to be named
1007 CFIndex if_list_index
,
1008 CFBooleanRef builtin
)
1010 CFStringRef if_type
;
1011 CFDictionaryRef match
= NULL
;
1012 matchContext match_context
;
1014 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
1015 if (if_type
== NULL
) {
1019 match_context
.match_type
= if_type
;
1020 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
1021 match_context
.match_builtin
= builtin
;
1022 match_context
.matches
= NULL
;
1024 // check for matches to interfaces that have already been named
1025 // ... and append each match that we find to match_context.matches
1026 if (db_list
!= NULL
) {
1027 CFArrayApplyFunction(db_list
,
1028 CFRangeMake(0, CFArrayGetCount(db_list
)),
1033 // check for matches to interfaces that will be named
1034 // ... and CFRelease match_context.matches if we find another network
1035 // interface of the same type that also needs to be named
1036 if (if_list
!= NULL
) {
1037 CFIndex if_list_count
;
1039 if_list_count
= CFArrayGetCount(if_list
);
1040 if (if_list_index
< if_list_count
) {
1041 CFArrayApplyFunction(if_list
,
1042 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
1048 // check if we have a single match
1049 if (match_context
.matches
!= NULL
) {
1050 if (CFArrayGetCount(match_context
.matches
) == 1) {
1051 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
1053 CFRelease(match_context
.matches
);
1056 if (match
!= NULL
) {
1057 Boolean active
= TRUE
;
1060 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
1061 if (isA_CFString(name
)) {
1065 prefix
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceNamePrefix
));
1066 unit
= CFDictionaryGetValue(match
, CFSTR(kIOInterfaceUnit
));
1067 if (isA_CFString(prefix
) && isA_CFNumber(unit
)) {
1068 if (!interfaceExists(prefix
, unit
)) {
1079 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
1084 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
)
1087 CFDictionaryRef if_dict
;
1088 CFStringRef if_name
;
1089 CFNumberRef if_type
;
1090 CFNumberRef if_unit
;
1091 CFIndex n
= CFArrayGetCount(db_list
);
1092 CFComparisonResult res
;
1094 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1095 if (if_name
!= NULL
) {
1096 addTimestamp(S_state
, if_name
);
1099 if_dict
= createInterfaceDict(interface
);
1100 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1101 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1102 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
1107 for (i
= 0; i
< n
; i
++) {
1108 CFNumberRef db_type
;
1109 CFNumberRef db_unit
;
1110 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
1112 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1113 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1114 res
= CFNumberCompare(if_type
, db_type
, NULL
);
1115 if (res
== kCFCompareLessThan
1116 || (res
== kCFCompareEqualTo
1117 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
1118 == kCFCompareLessThan
))) {
1119 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
1125 CFArrayAppendValue(S_dblist
, if_dict
);
1127 #if !TARGET_OS_EMBEDDED
1128 updateBTPANInformation(if_dict
, NULL
);
1129 #endif // !TARGET_OS_EMBEDDED
1136 replaceInterface(SCNetworkInterfaceRef interface
)
1141 if (S_dblist
== NULL
) {
1142 S_dblist
= CFArrayCreateMutable(NULL
, 0,
1143 &kCFTypeArrayCallBacks
);
1145 // remove any dict that has our type/addr
1146 while (lookupInterfaceByAddress(S_dblist
, interface
, &where
) != NULL
) {
1147 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1150 // remove any dict that has the same type/unit
1151 while (lookupInterfaceByUnit(S_dblist
, interface
, &where
) != NULL
) {
1152 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1155 insertInterface(S_dblist
, interface
);
1160 issue
= CFStringCreateWithFormat(NULL
, NULL
,
1161 CFSTR("n = %d, %@"),
1164 reportIssue("Multiple interfaces updated", issue
);
1172 getHighestUnitForType(CFNumberRef if_type
)
1176 CFNumberRef ret_unit
= NULL
;
1178 if (S_dblist
== NULL
) {
1182 n
= CFArrayGetCount(S_dblist
);
1183 for (i
= 0; i
< n
; i
++) {
1184 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1187 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1188 if (CFEqual(type
, if_type
)) {
1191 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1192 if (ret_unit
== NULL
1193 || (CFNumberCompare(unit
, ret_unit
, NULL
)
1194 == kCFCompareGreaterThan
)) {
1204 * Function: ensureInterfaceHasUnit
1206 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1207 * release the interface and return NULL.
1209 static SCNetworkInterfaceRef
1210 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if
)
1213 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if
) == NULL
) {
1220 #ifdef USE_REGISTRY_ENTRY_ID
1221 static kern_return_t
1222 registerInterfaceWithIORegistryEntryID(io_connect_t connect
,
1228 CFMutableDictionaryRef dict
;
1232 dict
= CFDictionaryCreateMutable(NULL
, 0,
1233 &kCFTypeDictionaryKeyCallBacks
,
1234 &kCFTypeDictionaryValueCallBacks
);
1235 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1236 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1238 data
= CFDataCreate(NULL
, (void *) &entryID
, sizeof(entryID
));
1239 CFDictionarySetValue(dict
, CFSTR(kIORegistryEntryIDKey
), data
);
1241 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1242 kr
= IOConnectSetCFProperties(connect
, dict
);
1247 static SCNetworkInterfaceRef
1248 copyInterfaceForIORegistryEntryID(uint64_t entryID
)
1250 io_registry_entry_t entry
= MACH_PORT_NULL
;
1251 SCNetworkInterfaceRef interface
= NULL
;
1252 io_iterator_t iterator
= MACH_PORT_NULL
;
1254 mach_port_t masterPort
= MACH_PORT_NULL
;
1256 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1257 if (kr
!= KERN_SUCCESS
) {
1258 SCLog(TRUE
, LOG_ERR
,
1259 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x"),
1264 kr
= IOServiceGetMatchingServices(masterPort
,
1265 IORegistryEntryIDMatching(entryID
),
1267 if ((kr
!= KERN_SUCCESS
) || (iterator
== MACH_PORT_NULL
)) {
1268 SCLog(TRUE
, LOG_ERR
,
1269 CFSTR(MY_PLUGIN_NAME
": IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d"),
1276 entry
= IOIteratorNext(iterator
);
1277 if (entry
== MACH_PORT_NULL
) {
1278 SCLog(TRUE
, LOG_ERR
,
1279 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryIDMatching(0x%llx) failed"),
1284 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1287 if (masterPort
!= MACH_PORT_NULL
) {
1288 mach_port_deallocate(mach_task_self(), masterPort
);
1290 if (entry
!= MACH_PORT_NULL
) {
1291 IOObjectRelease(entry
);
1293 if (iterator
!= MACH_PORT_NULL
) {
1294 IOObjectRelease(iterator
);
1299 static SCNetworkInterfaceRef
1300 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID
)
1302 SCNetworkInterfaceRef net_if
;
1304 net_if
= copyInterfaceForIORegistryEntryID(entryID
);
1305 return (ensureInterfaceHasUnit(net_if
));
1308 #else // USE_REGISTRY_ENTRY_ID
1310 * Function: registerInterface
1312 * Register a single interface with the given service path to the
1313 * data link layer (BSD), using the specified unit number.
1315 static kern_return_t
1316 registerInterfaceWithIOServicePath(io_connect_t connect
,
1321 CFMutableDictionaryRef dict
;
1325 dict
= CFDictionaryCreateMutable(NULL
, 0,
1326 &kCFTypeDictionaryKeyCallBacks
,
1327 &kCFTypeDictionaryValueCallBacks
);
1328 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1329 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1331 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1332 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1333 kr
= IOConnectSetCFProperties(connect
, dict
);
1338 static SCNetworkInterfaceRef
1339 copyInterfaceForIOKitPath(CFStringRef if_path
)
1341 io_registry_entry_t entry
= MACH_PORT_NULL
;
1342 SCNetworkInterfaceRef interface
= NULL
;
1344 mach_port_t masterPort
= MACH_PORT_NULL
;
1347 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1348 if (kr
!= KERN_SUCCESS
) {
1349 SCLog(TRUE
, LOG_ERR
,
1350 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x"),
1354 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1355 entry
= IORegistryEntryFromPath(masterPort
, path
);
1356 if (entry
== MACH_PORT_NULL
) {
1357 SCLog(TRUE
, LOG_ERR
,
1358 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryFromPath(%@) failed"),
1363 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1366 if (masterPort
!= MACH_PORT_NULL
) {
1367 mach_port_deallocate(mach_task_self(), masterPort
);
1369 if (entry
!= MACH_PORT_NULL
) {
1370 IOObjectRelease(entry
);
1376 static SCNetworkInterfaceRef
1377 copyNamedInterfaceForIOKitPath(CFStringRef if_path
)
1379 SCNetworkInterfaceRef net_if
;
1381 net_if
= copyInterfaceForIOKitPath(if_path
);
1382 return (ensureInterfaceHasUnit(net_if
));
1385 #endif // USE_REGISTRY_ENTRY_ID
1388 displayInterface(SCNetworkInterfaceRef interface
)
1395 name
= SCNetworkInterfaceGetBSDName(interface
);
1396 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1397 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1398 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1400 SCLog(TRUE
, LOG_INFO
,
1401 CFSTR(MY_PLUGIN_NAME
": %s%@%sType: %@, %s%@%sMAC address: %@"),
1402 (name
!= NULL
) ? "BSD Name: " : "",
1403 (name
!= NULL
) ? name
: CFSTR(""),
1404 (name
!= NULL
) ? ", " : "",
1406 (unit
!= NULL
) ? "Unit: " : "",
1407 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1408 (unit
!= NULL
) ? ", " : "",
1413 builtinAvailable(SCNetworkInterfaceRef interface
, // new interface
1414 CFNumberRef if_unit
) // desired unit
1417 CFNumberRef if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1420 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1421 for (i
= 0; i
< n
; i
++) {
1422 CFStringRef if_path
;
1423 CFDictionaryRef known_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1424 CFStringRef known_path
;
1425 CFNumberRef known_type
;
1426 CFNumberRef known_unit
;
1428 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceType
));
1429 if (!_SC_CFEqual(if_type
, known_type
)) {
1430 continue; // if not the same interface type
1433 known_unit
= CFDictionaryGetValue(known_dict
, CFSTR(kIOInterfaceUnit
));
1434 if (!_SC_CFEqual(if_unit
, known_unit
)) {
1435 continue; // if not the same interface unit
1438 if_path
= _SCNetworkInterfaceGetIOPath(interface
);
1439 known_path
= CFDictionaryGetValue(known_dict
, CFSTR(kIOPathMatchKey
));
1440 if (!_SC_CFEqual(if_path
, known_path
)) {
1441 // if different IORegistry path
1445 // if same type, same unit, same path
1449 // if interface type/unit not found
1454 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
1459 for (i
= 0; i
< last
; i
++) {
1460 SCNetworkInterfaceRef builtin_if
;
1461 CFNumberRef builtin_type
;
1463 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1464 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
1465 if (CFEqual(if_type
, builtin_type
)) {
1466 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1467 n
++; // if built-in interface
1475 static __inline__ boolean_t
1478 return (S_quiet
== MACH_PORT_NULL
);
1482 nameInterfaces(CFMutableArrayRef if_list
)
1485 CFIndex n
= CFArrayGetCount(if_list
);
1487 for (i
= 0; i
< n
; i
++) {
1489 SCNetworkInterfaceRef interface
;
1490 SCNetworkInterfaceRef new_interface
;
1497 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1498 path
= _SCNetworkInterfaceGetIOPath(interface
);
1499 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1500 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1501 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
1505 CFStringRef if_name
;
1507 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1508 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
1509 SCLog(TRUE
, LOG_INFO
,
1510 CFSTR(MY_PLUGIN_NAME
": Interface already has a unit number"));
1511 displayInterface(interface
);
1515 // update the list of interfaces that were previously named
1516 if ((S_prev_active_list
!= NULL
)
1517 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
1518 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1521 replaceInterface(interface
);
1523 CFDictionaryRef dbdict
;
1524 boolean_t is_builtin
;
1528 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
1529 if (dbdict
!= NULL
) {
1530 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1533 SCLog(S_debug
, LOG_INFO
,
1534 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (from database)"),
1538 if ((dbdict
== NULL
) && !isQuiet()) {
1539 // if new interface, wait until quiet before naming
1540 addTimestamp(S_state
, path
);
1544 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
1546 if (dbdict
== NULL
) {
1547 dbdict
= lookupMatchingInterface(interface
,
1551 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
1552 if (dbdict
!= NULL
) {
1553 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1556 SCLog(S_debug
, LOG_INFO
,
1557 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (updating database)"),
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 SCLog(S_debug
, LOG_INFO
,
1591 CFSTR(MY_PLUGIN_NAME
": Interface not assigned [built-in] unit %@"),
1599 // not built-in (or built-in unit not available), allocate from
1600 // the non-reserved slots
1601 next_unit
= builtinCount(if_list
, n
, type
);
1603 unit
= getHighestUnitForType(type
);
1607 CFNumberGetValue(unit
, kCFNumberIntType
, &high_unit
);
1608 if (high_unit
>= next_unit
) {
1609 next_unit
= high_unit
+ 1;
1613 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1616 SCLog(S_debug
, LOG_INFO
,
1617 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (%s)"),
1619 is_builtin
? "built-in" : "next available");
1624 #ifdef USE_REGISTRY_ENTRY_ID
1625 kr
= registerInterfaceWithIORegistryEntryID(S_connect
,
1628 (dbdict
== NULL
) ? kIONetworkStackRegisterInterfaceWithLowestUnit
1629 : kIONetworkStackRegisterInterfaceWithUnit
);
1630 new_interface
= copyNamedInterfaceForIORegistryEntryID(entryID
);
1631 #else // USE_REGISTRY_ENTRY_ID
1632 kr
= registerInterfaceWithIOServicePath(S_connect
,
1635 (dbdict
== NULL
) ? kRegisterInterface
1636 : kRegisterInterfaceWithFixedUnit
);
1637 new_interface
= copyNamedInterfaceForIOKitPath(path
);
1638 #endif // USE_REGISTRY_ENTRY_ID
1639 if (new_interface
== NULL
) {
1640 const char *signature
;
1642 signature
= (dbdict
== NULL
) ? "failed to name new interface"
1643 : "failed to name known interface";
1645 SCLog(TRUE
, LOG_ERR
,
1646 CFSTR(MY_PLUGIN_NAME
": %s, kr=0x%x\n"
1647 MY_PLUGIN_NAME
": path = %@\n"
1648 MY_PLUGIN_NAME
": id = 0x%llx\n"
1649 MY_PLUGIN_NAME
": unit = %@"),
1657 displayInterface(interface
);
1660 // report issue w/MessageTracer
1661 str
= CFStringCreateWithFormat(NULL
, NULL
,
1662 CFSTR("kr=0x%x, path=%@, unit=%@"),
1666 reportIssue(signature
, str
);
1669 if ((dbdict
!= NULL
) && (retries
++ < 5)) {
1670 usleep(50 * 1000); // sleep 50ms between attempts
1675 CFNumberRef new_unit
;
1678 SCLog(TRUE
, LOG_ERR
,
1679 CFSTR(MY_PLUGIN_NAME
": %s interface named after %d %s\n"
1680 MY_PLUGIN_NAME
": path = %@\n"
1681 MY_PLUGIN_NAME
": unit = %@"),
1682 (dbdict
== NULL
) ? "New" : "Known",
1684 (retries
== 1) ? "try" : "tries",
1688 #ifdef SHOW_NAMING_FAILURE
1689 str
= CFStringCreateWithFormat(NULL
,
1691 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
1692 (dbdict
== NULL
) ? "New" : "Known",
1694 (retries
== 1) ? "try" : "tries",
1696 CFUserNotificationDisplayNotice(0,
1697 kCFUserNotificationStopAlertLevel
,
1702 CFSTR("Please report repeated failures."),
1705 #endif // SHOW_NAMING_FAILURE
1708 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
1709 if (CFEqual(unit
, new_unit
) == FALSE
) {
1710 SCLog(S_debug
, LOG_INFO
,
1711 CFSTR(MY_PLUGIN_NAME
1712 ": interface type %@ assigned "
1713 "unit %@ instead of %@"),
1714 type
, new_unit
, unit
);
1717 displayInterface(new_interface
);
1720 // update if_list (with the interface name & unit)
1721 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
1722 CFRelease(new_interface
);
1723 interface
= new_interface
; // if_list holds the reference
1725 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
1728 // update the list of [built-in] interfaces that were previously named
1729 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
1730 SCLog(S_debug
, LOG_INFO
,
1731 CFSTR(MY_PLUGIN_NAME
": and updated database (new address)"));
1732 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1735 replaceInterface(interface
);
1743 #if !TARGET_OS_IPHONE
1745 updateNetworkConfiguration(CFArrayRef if_list
)
1747 Boolean do_commit
= FALSE
;
1750 SCPreferencesRef prefs
= NULL
;
1751 SCNetworkSetRef set
= NULL
;
1753 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCMonitor"), NULL
);
1755 set
= SCNetworkSetCopyCurrent(prefs
);
1757 SCLog(TRUE
, LOG_ERR
, CFSTR(MY_PLUGIN_NAME
": No current set"));
1761 n
= CFArrayGetCount(if_list
);
1762 for (i
= 0; i
< n
; i
++) {
1763 SCNetworkInterfaceRef interface
;
1765 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1766 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set
, interface
)) {
1767 SCLog(TRUE
, LOG_INFO
,
1768 CFSTR(MY_PLUGIN_NAME
": adding default configuration for %s"),
1769 SCNetworkInterfaceGetBSDName(interface
));
1777 ok
= SCPreferencesCommitChanges(prefs
);
1779 SCLog(TRUE
, LOG_INFO
,
1780 CFSTR(MY_PLUGIN_NAME
": updateNetworkConfiguration: SCPreferencesCommitChanges() failed: %s"),
1781 SCErrorString(SCError()));
1785 ok
= SCPreferencesApplyChanges(prefs
);
1787 SCLog(TRUE
, LOG_INFO
,
1788 CFSTR(MY_PLUGIN_NAME
": updateNetworkConfiguration: SCPreferencesApplyChanges() failed: %s"),
1789 SCErrorString(SCError()));
1801 if (prefs
!= NULL
) {
1808 #endif // !TARGET_OS_IPHONE
1813 if (S_connect
== MACH_PORT_NULL
) {
1814 // if we don't have the "IONetworkStack" connect object
1818 if (S_iflist
!= NULL
) {
1821 n
= CFArrayGetCount(S_iflist
);
1823 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
1825 nameInterfaces(S_iflist
);
1830 * The registry [matching] has quiesced so let's
1831 * - save the DB with the interfaces that have been named
1832 * - update the VLAN/BOND configuration
1833 * - tell everyone that we've finished (at least for now)
1834 * - log those interfaces which are no longer present
1835 * in the HW config (or have yet to show up).
1837 writeInterfaceList(S_dblist
);
1838 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
1840 #if !TARGET_OS_IPHONE
1841 if (access("/usr/libexec/UserEventAgent", X_OK
) == -1
1842 && errno
== ENOENT
) {
1844 * We are most likely booted into the Recovery OS with no "SCMonitor"
1845 * UserEventAgent plugin running so let's make sure we update the
1846 * network configuration for new interfaces.
1848 updateNetworkConfiguration(S_iflist
);
1850 #endif // !TARGET_OS_IPHONE
1854 if (S_iflist
!= NULL
) {
1855 CFRelease(S_iflist
);
1859 if (S_prev_active_list
!= NULL
) {
1864 n
= CFArrayGetCount(S_prev_active_list
);
1866 SCLog(TRUE
, LOG_INFO
,
1867 CFSTR(MY_PLUGIN_NAME
": Interface%s not [yet] active"),
1868 (n
> 1) ? "s" : "");
1870 for (i
= 0; i
< n
; i
++) {
1871 CFDictionaryRef if_dict
;
1876 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
1877 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
1878 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
1879 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
1880 SCLog(TRUE
, LOG_INFO
,
1881 CFSTR(MY_PLUGIN_NAME
": %s%@%sType: %@, Unit: %@"),
1882 (name
!= NULL
) ? "BSD Name: " : "",
1883 (name
!= NULL
) ? name
: CFSTR(""),
1884 (name
!= NULL
) ? ", " : "",
1889 CFRelease(S_prev_active_list
);
1890 S_prev_active_list
= NULL
;
1893 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
1895 * if we've named all of the interfaces that
1896 * were used during the previous boot.
1898 addTimestamp(S_state
, CFSTR("*RELEASE*"));
1899 SCLog(S_debug
, LOG_INFO
,
1900 CFSTR(MY_PLUGIN_NAME
": last boot interfaces have been named"));
1902 CFRelease(S_prev_active_list
);
1903 S_prev_active_list
= NULL
;
1910 #if !TARGET_OS_EMBEDDED
1911 static CFComparisonResult
1912 compareMacAddress(const void *val1
, const void *val2
, void *context
)
1914 CFDataRef mac1
= (CFDataRef
)val1
;
1915 CFDataRef mac2
= (CFDataRef
)val2
;
1918 CFComparisonResult res
;
1920 n1
= CFDataGetLength(mac1
);
1921 n2
= CFDataGetLength(mac2
);
1923 res
= kCFCompareLessThan
;
1924 } else if (n2
> n1
) {
1925 res
= kCFCompareGreaterThan
;
1927 res
= bcmp(CFDataGetBytePtr(mac1
), CFDataGetBytePtr(mac2
), n1
);
1937 CFMutableArrayRef addrs
= NULL
;
1938 CFStringRef guid
= NULL
;
1942 addrs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1943 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1944 for (i
= 0; i
< n
; i
++) {
1945 CFBooleanRef builtin
;
1946 CFDictionaryRef dict
;
1949 dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1950 type
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceType
));
1951 if (!isA_CFString(type
) || !CFEqual(type
, kSCNetworkInterfaceTypeEthernet
)) {
1954 builtin
= CFDictionaryGetValue(dict
, CFSTR(kIOBuiltin
));
1955 if (!isA_CFBoolean(builtin
) || !CFBooleanGetValue(builtin
)) {
1958 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
1959 if (!isA_CFData(addr
) || (CFDataGetLength(addr
) != ETHER_ADDR_LEN
)) {
1962 CFArrayAppendValue(addrs
, addr
);
1965 if (CFArrayGetCount(addrs
) == 0) {
1966 // if no ethernet interfaces, look for wireless
1967 for (i
= 0; i
< n
; i
++) {
1968 CFDictionaryRef dict
;
1971 dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1972 type
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceType
));
1973 if (!isA_CFString(type
) || !CFEqual(type
, kSCNetworkInterfaceTypeIEEE80211
)) {
1976 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
1977 if (!isA_CFData(addr
) || (CFDataGetLength(addr
) != ETHER_ADDR_LEN
)) {
1980 CFArrayAppendValue(addrs
, addr
);
1984 n
= CFArrayGetCount(addrs
);
1987 // if no network interfaces
1990 // sort by MAC address
1991 CFArraySortValues(addrs
, CFRangeMake(0, n
), compareMacAddress
, NULL
);
1995 CFUUIDBytes bytes
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1996 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
2000 addr
= CFArrayGetValueAtIndex(addrs
, 0);
2001 bcopy(CFDataGetBytePtr(addr
),
2002 (void *)&bytes
+ sizeof(bytes
) - ETHER_ADDR_LEN
,
2004 uuid
= CFUUIDCreateFromUUIDBytes(NULL
, bytes
);
2005 guid
= CFUUIDCreateString(NULL
, uuid
);
2008 SCLog(TRUE
, LOG_INFO
,
2009 CFSTR(MY_PLUGIN_NAME
": setting platform UUID [MAC] = %@"),
2015 if (addrs
!= NULL
) CFRelease(addrs
);
2019 #ifndef kIOPlatformUUIDKey
2020 #define kIOPlatformUUIDKey "IOPlatformUUID"
2023 updatePlatformUUID()
2025 CFStringRef guid
= NULL
;
2027 io_registry_entry_t platform
;
2029 platform
= IORegistryEntryFromPath(kIOMasterPortDefault
, kIODeviceTreePlane
":/");
2030 if (platform
== MACH_PORT_NULL
) {
2034 guid
= IORegistryEntryCreateCFProperty(platform
, CFSTR(kIOPlatformUUIDKey
), NULL
, 0);
2036 // if GUID already defined
2040 guid
= copyEthernetUUID();
2044 uuid
= CFUUIDCreate(NULL
);
2045 guid
= CFUUIDCreateString(NULL
, uuid
);
2048 SCLog(TRUE
, LOG_INFO
,
2049 CFSTR(MY_PLUGIN_NAME
": setting platform UUID [random] = %@"),
2053 if (getenv("DO_NOT_SET_PLATFORM_UUID") == NULL
) {
2054 kr
= IORegistryEntrySetCFProperty(platform
, CFSTR(kIOPlatformUUIDKey
), guid
);
2055 if (kr
!= KERN_SUCCESS
) {
2056 SCLog(TRUE
, LOG_ERR
,
2057 CFSTR(MY_PLUGIN_NAME
": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"),
2062 addTimestamp(S_state
, CFSTR("*PLATFORM-UUID*"));
2067 if (S_vproc_transaction
!= NULL
) {
2068 vproc_transaction_end(NULL
, S_vproc_transaction
);
2069 S_vproc_transaction
= NULL
;
2072 if (platform
!= MACH_PORT_NULL
) IOObjectRelease(platform
);
2073 if (guid
!= NULL
) CFRelease(guid
);
2076 #endif // !TARGET_OS_EMBEDDED
2079 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
2083 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
2084 SCNetworkInterfaceRef interface
;
2086 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
2087 if (interface
!= NULL
) {
2088 if (S_iflist
== NULL
) {
2089 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2091 CFArrayAppendValue(S_iflist
, interface
);
2092 CFRelease(interface
);
2094 IOObjectRelease(obj
);
2102 * Function: stackCallback
2104 * Get a reference to the single IONetworkStack object instance in
2105 * the kernel. Naming requests must be sent to this object, which is
2106 * attached as a client to all network interface objects in the system.
2108 * Call IOObjectRelease on the returned object.
2111 stackCallback(void *refcon
, io_iterator_t iter
)
2116 stack
= IOIteratorNext(iter
);
2117 if (stack
== MACH_PORT_NULL
) {
2121 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
2122 if (kr
!= KERN_SUCCESS
) {
2123 SCLog(TRUE
, LOG_ERR
,
2124 CFSTR(MY_PLUGIN_NAME
": IOServiceOpen returned 0x%x"),
2129 addTimestamp(S_state
, CFSTR("*STACK*"));
2130 SCLog(S_debug
, LOG_INFO
,
2131 CFSTR(MY_PLUGIN_NAME
": IONetworkStack found"));
2133 if (S_stack
!= MACH_PORT_NULL
) {
2134 IOObjectRelease(S_stack
);
2135 S_stack
= MACH_PORT_NULL
;
2138 if ((S_timer
!= NULL
) && CFRunLoopTimerIsValid(S_timer
)) {
2139 // With the IONetworkStack object now available we can
2140 // reset (shorten?) the time we are willing to wait for
2141 // IOKit to quiesce.
2142 CFRunLoopTimerSetNextFireDate(S_timer
,
2143 CFAbsoluteTimeGetCurrent() + S_quiet_timeout
);
2149 if (stack
!= MACH_PORT_NULL
) {
2150 IOObjectRelease(stack
);
2157 quietCallback(void *refcon
,
2158 io_service_t service
,
2159 natural_t messageType
,
2160 void *messageArgument
)
2162 if (messageArgument
!= NULL
) {
2167 if (messageType
== kIOMessageServiceBusyStateChange
) {
2168 addTimestamp(S_state
, CFSTR("*QUIET*"));
2169 SCLog(S_debug
, LOG_INFO
,
2170 CFSTR(MY_PLUGIN_NAME
": IOKit quiet"));
2173 if (S_connect
== MACH_PORT_NULL
) {
2174 SCLog(TRUE
, LOG_ERR
,
2175 CFSTR(MY_PLUGIN_NAME
": No network stack object"));
2179 if (S_quiet
!= MACH_PORT_NULL
) {
2180 IOObjectRelease(S_quiet
);
2181 S_quiet
= MACH_PORT_NULL
;
2184 if (S_timer
!= NULL
) {
2185 CFRunLoopTimerInvalidate(S_timer
);
2190 // grab (and name) any additional interfaces.
2191 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2193 #if !TARGET_OS_EMBEDDED
2194 updatePlatformUUID();
2195 #endif // !TARGET_OS_EMBEDDED
2201 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, CFMutableStringRef snapshot
, int *count
)
2203 kern_return_t kr
= kIOReturnSuccess
;;
2206 while ((kr
== kIOReturnSuccess
) &&
2207 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
2208 uint64_t accumulated_busy_time
;
2209 uint32_t busy_state
;
2212 CFMutableArrayRef newNodes
;
2214 CFMutableStringRef str
= NULL
;
2216 if (nodes
== NULL
) {
2217 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2219 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
2221 assert(newNodes
!= NULL
);
2223 kr
= IORegistryEntryGetName(obj
, name
);
2224 if (kr
!= kIOReturnSuccess
) {
2225 SCLog(TRUE
, LOG_ERR
,
2226 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryEntryGetName returned 0x%x"),
2231 str
= CFStringCreateMutable(NULL
, 0);
2232 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
2234 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
2236 case kIOReturnSuccess
:
2237 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
2238 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
2240 case kIOReturnNotFound
:
2243 SCLog(TRUE
, LOG_ERR
,
2244 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryEntryGetLocationInPlane returned 0x%x"),
2250 CFArrayAppendValue(newNodes
, str
);
2253 kr
= IOServiceGetBusyStateAndTime(obj
, &state
, &busy_state
, &accumulated_busy_time
);
2254 if (kr
!= kIOReturnSuccess
) {
2255 SCLog(TRUE
, LOG_ERR
,
2256 CFSTR(MY_PLUGIN_NAME
": captureBusy IOServiceGetBusyStateAndTime returned 0x%x"),
2261 #ifdef TEST_SNAPSHOT
2264 #endif // TEST_SNAPSHOT
2266 if (busy_state
!= 0) {
2269 if ((*count
)++ == 0) {
2270 CFStringAppend(snapshot
, CFSTR("Busy services :"));
2273 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
2274 CFStringAppendFormat(snapshot
, NULL
,
2275 CFSTR("\n %@ [%s%s%s%d, %lld ms]"),
2277 (state
& kIOServiceRegisteredState
) ? "" : "!registered, ",
2278 (state
& kIOServiceMatchedState
) ? "" : "!matched, ",
2279 (state
& kIOServiceInactiveState
) ? "inactive, " : "",
2281 accumulated_busy_time
/ kMillisecondScale
);
2285 kr
= IORegistryIteratorEnterEntry(iterator
);
2286 if (kr
!= kIOReturnSuccess
) {
2287 SCLog(TRUE
, LOG_ERR
,
2288 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryIteratorEnterEntry returned 0x%x"),
2293 iterateRegistryBusy(iterator
, newNodes
, snapshot
, count
);
2295 kr
= IORegistryIteratorExitEntry(iterator
);
2296 if (kr
!= kIOReturnSuccess
) {
2297 SCLog(TRUE
, LOG_ERR
,
2298 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryIteratorExitEntry returned 0x%x"),
2304 CFRelease(newNodes
);
2305 IOObjectRelease(obj
);
2311 static CF_RETURNS_RETAINED CFStringRef
2315 io_iterator_t iterator
= MACH_PORT_NULL
;
2317 CFMutableStringRef snapshot
;
2319 snapshot
= CFStringCreateMutable(NULL
, 0);
2321 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
2325 if (kr
!= kIOReturnSuccess
) {
2326 SCLog(TRUE
, LOG_ERR
,
2327 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryCreateIterator returned 0x%x"),
2332 iterateRegistryBusy(iterator
, NULL
, snapshot
, &count
);
2334 CFStringAppend(snapshot
, CFSTR("w/no busy services"));
2337 IOObjectRelease(iterator
);
2342 timerCallback(CFRunLoopTimerRef timer
, void *info
)
2344 CFStringRef snapshot
;
2346 // We've been waiting for IOKit to quiesce and it just
2347 // hasn't happenned. Time to just move on!
2348 addTimestamp(S_state
, CFSTR("*TIMEOUT*"));
2351 snapshot
= captureBusy();
2352 SCLog(TRUE
, LOG_ERR
,
2353 CFSTR(MY_PLUGIN_NAME
": timed out waiting for IOKit to quiesce\n%@"),
2355 reportIssue("timed out waiting for IOKit to quiesce", snapshot
);
2356 CFRelease(snapshot
);
2358 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
2363 setup_IOKit(CFBundleRef bundle
)
2367 mach_port_t masterPort
= MACH_PORT_NULL
;
2369 io_object_t root
= MACH_PORT_NULL
;
2371 // read DB of previously named network interfaces
2372 S_dblist
= readInterfaceList();
2373 if (S_dblist
!= NULL
) {
2376 n
= CFArrayGetCount(S_dblist
);
2378 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
2382 // get interfaces that were named during the last boot
2383 S_prev_active_list
= previouslyActiveInterfaces();
2385 // track how long we've waited to see each interface.
2386 S_state
= CFDictionaryCreateMutable(NULL
,
2388 &kCFTypeDictionaryKeyCallBacks
,
2389 &kCFTypeDictionaryValueCallBacks
);
2390 addTimestamp(S_state
, CFSTR("*START*"));
2392 // Creates and returns a notification object for receiving IOKit
2393 // notifications of new devices or state changes.
2394 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
2395 if (kr
!= KERN_SUCCESS
) {
2396 SCLog(TRUE
, LOG_ERR
,
2397 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x"),
2402 S_notify
= IONotificationPortCreate(masterPort
);
2403 if (S_notify
== NULL
) {
2404 SCLog(TRUE
, LOG_ERR
,
2405 CFSTR(MY_PLUGIN_NAME
": IONotificationPortCreate failed"));
2409 // watch IOKit matching activity
2410 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
2411 if (root
== MACH_PORT_NULL
) {
2412 SCLog(TRUE
, LOG_ERR
,
2413 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryFromPath failed"));
2417 kr
= IOServiceAddInterestNotification(S_notify
,
2421 (void *)S_notify
, // refCon
2422 &S_quiet
); // notification
2423 if (kr
!= KERN_SUCCESS
) {
2424 SCLog(TRUE
, LOG_ERR
,
2425 CFSTR(MY_PLUGIN_NAME
": IOServiceAddInterestNotification returned 0x%x"),
2430 kr
= IOServiceGetBusyState(root
, &busy
);
2431 if (kr
!= KERN_SUCCESS
) {
2432 SCLog(TRUE
, LOG_ERR
,
2433 CFSTR(MY_PLUGIN_NAME
": IOServiceGetBusyState returned 0x%x"),
2438 // add a timer so we don't wait forever for IOKit to quiesce
2439 S_timer
= CFRunLoopTimerCreate(NULL
,
2440 CFAbsoluteTimeGetCurrent() + S_stack_timeout
,
2446 if (S_timer
== NULL
) {
2447 SCLog(TRUE
, LOG_ERR
,
2448 CFSTR(MY_PLUGIN_NAME
": CFRunLoopTimerCreate failed"));
2452 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
2454 // watch for the introduction of the IONetworkStack
2455 kr
= IOServiceAddMatchingNotification(S_notify
,
2456 kIOFirstMatchNotification
,
2457 IOServiceMatching("IONetworkStack"),
2459 (void *)S_notify
, // refCon
2460 &S_stack
); // notification
2461 if (kr
!= KERN_SUCCESS
) {
2462 SCLog(TRUE
, LOG_ERR
,
2463 CFSTR(MY_PLUGIN_NAME
": IOServiceAddMatchingNotification returned 0x%x"),
2468 // check and see if the stack is already available and arm the
2469 // notification for its introduction.
2470 stackCallback((void *)S_notify
, S_stack
);
2472 // watch for the introduction of new network interfaces
2473 kr
= IOServiceAddMatchingNotification(S_notify
,
2474 kIOFirstMatchNotification
,
2475 IOServiceMatching("IONetworkInterface"),
2476 &interfaceArrivalCallback
,
2477 (void *)S_notify
, // refCon
2478 &S_iter
); // notification
2479 if (kr
!= KERN_SUCCESS
) {
2480 SCLog(TRUE
, LOG_ERR
,
2481 CFSTR(MY_PLUGIN_NAME
": IOServiceAddMatchingNotification returned 0x%x"),
2486 // Get the current list of matches and arm the notification for
2487 // future interface arrivals.
2488 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2490 // Check if IOKit has already quiesced.
2491 quietCallback((void *)S_notify
,
2493 kIOMessageServiceBusyStateChange
,
2494 (void *)(uintptr_t)busy
);
2496 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2497 IONotificationPortGetRunLoopSource(S_notify
),
2498 kCFRunLoopDefaultMode
);
2500 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
2502 * Start the wheels turning until we've named all of
2503 * the interfaces that were used during the previous
2504 * boot, until IOKit [matching] has quiesced, or
2505 * until we've waited long enough.
2507 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
2508 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2509 IONotificationPortGetRunLoopSource(S_notify
),
2511 while (S_prev_active_list
!= NULL
) {
2514 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
2516 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
2518 #if !TARGET_OS_EMBEDDED
2519 if (S_dblist
!= NULL
) {
2520 // apply special handling for the BT-PAN interface (if present)
2521 CFArrayApplyFunction(S_dblist
,
2522 CFRangeMake(0, CFArrayGetCount(S_dblist
)),
2523 updateBTPANInformation
,
2526 #endif // !TARGET_OS_EMBEDDED
2531 if (root
!= MACH_PORT_NULL
) {
2532 IOObjectRelease(root
);
2534 if (masterPort
!= MACH_PORT_NULL
) {
2535 mach_port_deallocate(mach_task_self(), masterPort
);
2542 setup_Virtual(CFBundleRef bundle
)
2544 // open a SCPreferences session
2545 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
);
2546 if (S_prefs
== NULL
) {
2547 SCLog(TRUE
, LOG_ERR
,
2548 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate() failed: %s"),
2549 SCErrorString(SCError()));
2553 // register for change notifications.
2554 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
2555 SCLog(TRUE
, LOG_ERR
,
2556 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetCallBack() failed: %s"),
2557 SCErrorString(SCError()));
2563 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
2564 if (SCError() != kSCStatusNoStoreServer
) {
2565 SCLog(TRUE
, LOG_ERR
,
2566 CFSTR(MY_PLUGIN_NAME
": SCPreferencesScheduleWithRunLoop() failed: %s"),
2567 SCErrorString(SCError()));
2577 exec_InterfaceNamer(void *arg
)
2579 CFBundleRef bundle
= (CFBundleRef
)arg
;
2580 CFDictionaryRef dict
;
2582 pthread_setname_np(MY_PLUGIN_NAME
" thread");
2584 dict
= CFBundleGetInfoDictionary(bundle
);
2585 if (isA_CFDictionary(dict
)) {
2588 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_STACK_TIMEOUT_KEY
));
2590 if (!isA_CFNumber(num
) ||
2591 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_stack_timeout
) ||
2592 (S_stack_timeout
<= 0.0)) {
2593 SCLog(TRUE
, LOG_ERR
,
2594 CFSTR(MY_PLUGIN_NAME
": " WAIT_STACK_TIMEOUT_KEY
" value error"));
2595 S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
2599 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
2601 if (!isA_CFNumber(num
) ||
2602 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_quiet_timeout
) ||
2603 (S_quiet_timeout
<= 0.0)) {
2604 SCLog(TRUE
, LOG_ERR
,
2605 CFSTR(MY_PLUGIN_NAME
": " WAIT_QUIET_TIMEOUT_KEY
" value error"));
2606 S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
2611 // setup virtual network interface monitoring
2612 if (!setup_Virtual(bundle
)) {
2616 // setup [IOKit] network interface monitoring
2617 if (!setup_IOKit(bundle
)) {
2621 #if !TARGET_OS_EMBEDDED
2622 // keep launchd from SIGKILL'ing us until after the platform-uuid has
2624 S_vproc_transaction
= vproc_transaction_begin(NULL
);
2625 #endif // !TARGET_OS_EMBEDDED
2630 if (S_connect
!= MACH_PORT_NULL
) {
2631 IOServiceClose(S_connect
);
2632 S_connect
= MACH_PORT_NULL
;
2634 if (S_dblist
!= NULL
) {
2635 CFRelease(S_dblist
);
2638 if (S_iter
!= MACH_PORT_NULL
) {
2639 IOObjectRelease(S_iter
);
2640 S_iter
= MACH_PORT_NULL
;
2642 if (S_notify
!= MACH_PORT_NULL
) {
2643 IONotificationPortDestroy(S_notify
);
2645 if (S_quiet
!= MACH_PORT_NULL
) {
2646 IOObjectRelease(S_quiet
);
2647 S_quiet
= MACH_PORT_NULL
;
2649 if (S_stack
!= MACH_PORT_NULL
) {
2650 IOObjectRelease(S_stack
);
2651 S_stack
= MACH_PORT_NULL
;
2653 if (S_state
!= NULL
) {
2657 if (S_timer
!= NULL
) {
2658 CFRunLoopTimerInvalidate(S_timer
);
2672 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
2674 pthread_attr_t tattr
;
2677 if (bundleVerbose
) {
2681 CFRetain(bundle
); // released in exec_InterfaceNamer
2683 pthread_attr_init(&tattr
);
2684 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
2685 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
2686 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
2687 pthread_create(&tid
, &tattr
, exec_InterfaceNamer
, bundle
);
2688 pthread_attr_destroy(&tattr
);
2693 //------------------------------------------------------------------------
2697 main(int argc
, char ** argv
)
2702 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2704 S_debug
= _sc_verbose
;
2706 bundle
= CFBundleGetMainBundle();
2707 CFRetain(bundle
); // released in exec_InterfaceNamer
2709 (void)exec_InterfaceNamer();
2717 #ifdef TEST_PLATFORM_UUID
2719 main(int argc
, char ** argv
)
2722 CFArrayRef interfaces
;
2725 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2727 S_dblist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2728 interfaces
= SCNetworkInterfaceCopyAll();
2729 if (interfaces
!= NULL
) {
2733 n
= CFArrayGetCount(interfaces
);
2734 for (i
= 0; i
< n
; i
++) {
2735 CFDictionaryRef dict
;
2736 SCNetworkInterfaceRef interface
;
2738 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2739 dict
= createInterfaceDict(interface
);
2740 CFArrayAppendValue(S_dblist
, dict
);
2743 CFRelease(interfaces
);
2746 guid
= copyEthernetUUID();
2747 SCPrint(TRUE
, stdout
, CFSTR("copyEthernetUUID() = %@\n"), (guid
!= NULL
) ? guid
: CFSTR("NULL"));
2748 if (guid
!= NULL
) CFRelease(guid
);
2750 updatePlatformUUID();
2751 CFRelease(S_dblist
);
2755 #endif /* TEST_PLATFORM_UUID */
2757 #ifdef TEST_SNAPSHOT
2759 main(int argc
, char ** argv
)
2761 CFStringRef snapshot
;
2764 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2766 snapshot
= captureBusy();
2767 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), snapshot
);
2768 CFRelease(snapshot
);
2773 #endif /* TEST_SNAPSHOT */