2 * Copyright (c) 2001-2012 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>
66 #include <sys/socket.h>
67 #include <sys/sockio.h>
69 #include <sys/sysctl.h>
70 #include <sys/param.h>
71 #include <mach/mach.h>
72 #include <net/ethernet.h>
74 #include <net/if_types.h>
78 #include <CommonCrypto/CommonDigest.h>
80 #include <CoreFoundation/CoreFoundation.h>
82 #include <SystemConfiguration/SystemConfiguration.h>
83 #include <SystemConfiguration/SCDPlugin.h>
84 #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
85 #include <SystemConfiguration/SCValidation.h>
87 #include <IOKit/IOKitLib.h>
88 #include <IOKit/IOKitLibPrivate.h>
89 #include <IOKit/IOBSD.h>
90 #include <IOKit/IOMessage.h>
91 #include <IOKit/network/IONetworkController.h>
92 #include <IOKit/network/IONetworkInterface.h>
93 #include <IOKit/network/IONetworkStack.h>
94 #include <IOKit/usb/USB.h>
96 #ifdef kIONetworkStackUserCommandKey
97 #define USE_REGISTRY_ENTRY_ID
100 #ifndef USE_REGISTRY_ENTRY_ID
101 // from <IOKit/network/IONetworkStack.h>
102 #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand"
104 kRegisterInterfaceWithFixedUnit
= 0,
106 kRegisterAllInterfaces
108 #endif // !USE_REGISTRY_ENTRY_ID
110 #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo"
111 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
112 #define kSCNetworkInterfaceActive "Active"
114 #define MY_PLUGIN_NAME "InterfaceNamer"
115 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
117 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
118 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
120 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
121 #define WAIT_QUIET_TIMEOUT_DEFAULT 60.0
125 * "IONetworkStack" connect object used to "name" an interface.
127 static io_connect_t S_connect
= MACH_PORT_NULL
;
131 * An array of CFDictionary's representing the interfaces
132 * that have been identified and [need to be] named.
134 static CFMutableArrayRef S_dblist
= NULL
;
138 * A boolean that enables additional logging.
140 static boolean_t S_debug
= FALSE
;
144 * An array of SCNetworkInterface's representing the
145 * interfaces that have been identified.
147 static CFMutableArrayRef S_iflist
= NULL
;
151 * IOServiceAddMatchingNotification object used to watch for
152 * new network interfaces.
154 static io_iterator_t S_iter
= MACH_PORT_NULL
;
158 * notification object for receiving IOKit notifications of
159 * new devices or state changes.
161 static IONotificationPortRef S_notify
= NULL
;
163 /* S_prev_active_list
164 * An array of CFDictionary's representing the previously
167 static CFMutableArrayRef S_prev_active_list
= NULL
;
171 * IOServiceAddInterestNotification object used to watch for
172 * IOKit matching to quiesce.
174 static io_object_t S_quiet
= MACH_PORT_NULL
;
178 * IOServiceAddMatchingNotification object used to watch for
179 * the availability of the "IONetworkStack" object.
181 static io_iterator_t S_stack
= MACH_PORT_NULL
;
185 * A dictionary containing Information about each network
186 * interface. For now, the key is the BSD name and the
187 * value is a CFNumber noting how long (in milliseconds)
188 * it took for the interface to be recognized/named.
190 static CFMutableDictionaryRef S_state
= NULL
;
194 * CFRunLoopTimer tracking how long we are willing to wait
195 * for IOKit matching to quiesce (IOKitWaitQuiet).
198 * time to wait for the IONetworkStack object to appear before timeout
201 * time to wait for the IOKit to quiesce (after the IONetworkStack is
204 static CFRunLoopTimerRef S_timer
= NULL
;
205 static double S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
206 static double S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
208 #if !TARGET_OS_EMBEDDED
210 * S_vproc_transaction
211 * The vproc transaction used to keep launchd from sending us
212 * a SIGKILL before we've had a chance to set the platform UUID
214 vproc_transaction_t S_vproc_transaction
= NULL
;
215 #endif // !TARGET_OS_EMBEDDED
218 * Virtual network interface configuration
219 * S_prefs : SCPreferences to configuration
220 * S_bonds : most recently actived Bond configuration
221 * S_bridges : most recently actived Bridge configuration
222 * S_vlans : most recently actived VLAN configuration
224 static SCPreferencesRef S_prefs
= NULL
;
225 static CFArrayRef S_bonds
= NULL
;
226 static CFArrayRef S_bridges
= NULL
;
227 static CFArrayRef S_vlans
= NULL
;
230 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
235 now
= CFAbsoluteTimeGetCurrent();
236 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
237 CFDictionaryAddValue(dict
, key
, val
);
242 #define INTERFACES CFSTR("Interfaces")
243 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
245 static CFComparisonResult
246 if_unit_compare(const void *val1
, const void *val2
, void *context
)
248 CFComparisonResult res
;
254 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
255 CFSTR(kIOInterfaceType
));
256 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
257 CFSTR(kIOInterfaceType
));
258 res
= CFNumberCompare(type1
, type2
, NULL
);
259 if (res
!= kCFCompareEqualTo
) {
262 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
263 CFSTR(kIOInterfaceUnit
));
264 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
265 CFSTR(kIOInterfaceUnit
));
266 return (CFNumberCompare(unit1
, unit2
, NULL
));
270 reportIssue(const char *signature
, CFStringRef issue
)
274 m
= asl_new(ASL_TYPE_MSG
);
275 asl_set(m
, "com.apple.message.domain", "com.apple.SystemConfiguration." MY_PLUGIN_NAME
);
276 asl_set(m
, "com.apple.message.signature", signature
);
277 asl_set(m
, "com.apple.message.result", "failure");
278 SCLOG(NULL
, m
, ~ASL_LEVEL_ERR
, CFSTR("%s\n%@"), signature
, issue
);
285 writeInterfaceList(CFArrayRef if_list
)
288 CFStringRef new_model
;
289 CFStringRef old_model
;
290 SCPreferencesRef prefs
;
292 if (isA_CFArray(if_list
) == NULL
) {
296 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
299 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate failed, %s"),
300 SCErrorString(SCError()));
304 cur_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
305 if (_SC_CFEqual(cur_list
, if_list
)) {
309 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
310 new_model
= _SC_hw_model();
311 if ((new_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
313 if ((old_model
!= NULL
) && (cur_list
!= NULL
)) {
317 // if interface list was created on other hardware
318 history
= CFStringCreateWithFormat(NULL
, NULL
,
322 SCPreferencesSetValue(prefs
, history
, cur_list
);
326 CFSTR(MY_PLUGIN_NAME
": Hardware model changed\n"
327 MY_PLUGIN_NAME
": created on \"%@\"\n"
328 MY_PLUGIN_NAME
": now on \"%@\""),
332 issue
= CFStringCreateWithFormat(NULL
, NULL
,
336 reportIssue("Hardware model changed", issue
);
340 if (!SCPreferencesSetValue(prefs
, MODEL
, new_model
)) {
342 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetValue failed, %s"),
343 SCErrorString(SCError()));
348 if (!SCPreferencesSetValue(prefs
, INTERFACES
, if_list
)) {
350 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetValue failed, %s"),
351 SCErrorString(SCError()));
355 if (!SCPreferencesCommitChanges(prefs
)) {
356 SCLog((SCError() != EROFS
), LOG_ERR
,
357 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCommitChanges failed, %s"),
358 SCErrorString(SCError()));
368 static CF_RETURNS_RETAINED CFMutableArrayRef
372 CFStringRef old_model
;
373 CFMutableArrayRef plist
= NULL
;
374 SCPreferencesRef prefs
= NULL
;
376 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
379 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate failed, %s"),
380 SCErrorString(SCError()));
384 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
385 if_list
= isA_CFArray(if_list
);
387 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
388 if (old_model
!= NULL
) {
389 CFStringRef new_model
;
391 new_model
= _SC_hw_model();
392 if (!_SC_CFEqual(old_model
, new_model
)) {
393 // if interface list was created on other hardware
398 if (if_list
!= NULL
) {
400 CFIndex n
= CFArrayGetCount(if_list
);
402 plist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
403 for (i
= 0; i
< n
; i
++) {
404 CFDictionaryRef dict
;
406 dict
= CFArrayGetValueAtIndex(if_list
, i
);
407 if (isA_CFDictionary(dict
) &&
408 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceType
)) &&
409 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
410 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
411 CFArrayAppendValue(plist
, dict
);
422 static CF_RETURNS_RETAINED CFMutableArrayRef
423 previouslyActiveInterfaces()
425 CFMutableArrayRef active
;
429 if (S_dblist
== NULL
) {
433 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
435 n
= CFArrayGetCount(S_dblist
);
436 for (i
= 0; i
< n
; i
++) {
437 CFDictionaryRef if_dict
;
439 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
440 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
441 CFMutableDictionaryRef new_dict
;
443 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
444 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
445 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
446 CFArrayAppendValue(active
, new_dict
);
459 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
),
460 kSCDynamicStoreDomainPlugin
);
461 (void)SCDynamicStoreSetValue(NULL
, key
, S_state
);
467 #if !TARGET_OS_IPHONE
469 updateBondInterfaceConfiguration(SCPreferencesRef prefs
)
471 CFArrayRef interfaces
;
473 interfaces
= SCBondInterfaceCopyAll(prefs
);
474 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
475 CFRelease(interfaces
);
479 if (_SC_CFEqual(S_bonds
, interfaces
)) {
481 if (interfaces
!= NULL
) CFRelease(interfaces
);
485 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
486 S_bonds
= interfaces
;
488 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
490 CFSTR(MY_PLUGIN_NAME
": _SCBondInterfaceUpdateConfiguration failed, %s"),
491 SCErrorString(SCError()));
496 #endif // !TARGET_OS_IPHONE
499 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs
)
501 CFArrayRef interfaces
;
503 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
504 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
505 CFRelease(interfaces
);
509 if (_SC_CFEqual(S_bridges
, interfaces
)) {
511 if (interfaces
!= NULL
) CFRelease(interfaces
);
515 if (S_bridges
!= NULL
) CFRelease(S_bridges
);
516 S_bridges
= interfaces
;
518 if (!_SCBridgeInterfaceUpdateConfiguration(prefs
)) {
520 CFSTR(MY_PLUGIN_NAME
": _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
)) {
549 CFSTR(MY_PLUGIN_NAME
": _SCVLANInterfaceUpdateConfiguration failed, %s"),
550 SCErrorString(SCError()));
557 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
558 SCPreferencesNotification notificationType
,
561 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
566 // if a new interface has been "named"
568 if (S_bonds
!= NULL
) {
572 if (S_bridges
!= NULL
) {
573 CFRelease(S_bridges
);
576 if (S_vlans
!= NULL
) {
582 #if !TARGET_OS_IPHONE
583 updateBondInterfaceConfiguration (prefs
);
584 #endif // !TARGET_OS_IPHONE
585 updateBridgeInterfaceConfiguration(prefs
);
586 updateVLANInterfaceConfiguration (prefs
);
588 // we are finished with current prefs, wait for changes
589 SCPreferencesSynchronize(prefs
);
593 static CFDictionaryRef
594 createInterfaceDict(SCNetworkInterfaceRef interface
)
596 CFMutableDictionaryRef new_if
;
599 new_if
= CFDictionaryCreateMutable(NULL
,
601 &kCFTypeDictionaryKeyCallBacks
,
602 &kCFTypeDictionaryValueCallBacks
);
604 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
606 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
610 val
= _SCNetworkInterfaceGetIOPath(interface
);
612 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
615 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
617 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
620 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
622 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
625 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
627 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
630 val
= SCNetworkInterfaceGetBSDName(interface
);
632 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
635 val
= SCNetworkInterfaceGetInterfaceType(interface
);
637 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
640 CFDictionarySetValue(new_if
,
642 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
644 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
649 static CFDictionaryRef
650 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
657 if (db_list
== NULL
) {
660 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
661 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
662 if (type
== NULL
|| addr
== NULL
) {
666 n
= CFArrayGetCount(db_list
);
667 for (i
= 0; i
< n
; i
++) {
669 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
672 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
673 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
674 if (t
== NULL
|| a
== NULL
)
677 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
687 static CFDictionaryRef
688 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
695 if (db_list
== NULL
) {
698 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
699 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
700 if (type
== NULL
|| unit
== NULL
) {
704 n
= CFArrayGetCount(db_list
);
705 for (i
= 0; i
< n
; i
++) {
706 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
710 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
711 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
712 if (t
== NULL
|| u
== NULL
) {
716 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
726 CFDictionaryRef match_info
;
727 CFStringRef match_type
;
728 CFBooleanRef match_builtin
;
729 CFMutableArrayRef matches
;
730 } matchContext
, *matchContextRef
;
732 static CF_RETURNS_RETAINED CFDictionaryRef
733 thinInterfaceInfo(CFDictionaryRef info
)
738 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
740 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
741 && (vid
== kIOUSBVendorIDAppleComputer
)) {
742 CFMutableDictionaryRef thin
;
744 // if this is an Apple USB device than we trust that
745 // the non-localized name will be correct.
746 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
747 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
748 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
749 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
753 return CFRetain(info
);
757 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
761 match
= _SC_CFEqual(known_info
, match_info
);
763 isA_CFDictionary(known_info
) &&
764 isA_CFDictionary(match_info
)) {
766 // if not an exact match, try thinning
767 known_info
= thinInterfaceInfo(known_info
);
768 match_info
= thinInterfaceInfo(match_info
);
769 match
= _SC_CFEqual(known_info
, match_info
);
770 CFRelease(known_info
);
771 CFRelease(match_info
);
778 matchKnown(const void *value
, void *context
)
780 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
781 matchContextRef match_context
= (matchContextRef
)context
;
783 // match interface type
785 CFStringRef known_type
;
787 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
788 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
793 // match SCNetworkInterfaceInfo
795 CFDictionaryRef known_info
;
797 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
798 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
803 // if requested, match [non-]builtin
804 if (match_context
->match_builtin
!= NULL
) {
805 CFBooleanRef known_builtin
;
807 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
808 if (!isA_CFBoolean(known_builtin
)) {
809 known_builtin
= kCFBooleanFalse
;
811 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
816 // if we have a match
817 if (match_context
->matches
== NULL
) {
818 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
820 CFArrayAppendValue(match_context
->matches
, known_dict
);
826 matchUnnamed(const void *value
, void *context
)
828 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
829 matchContextRef match_context
= (matchContextRef
)context
;
831 if (match_context
->matches
== NULL
) {
835 // match interface type
837 CFStringRef known_type
;
839 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
840 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
845 // match SCNetworkInterfaceInfo
847 CFDictionaryRef known_info
;
850 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
851 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
852 if (known_info
!= NULL
) CFRelease(known_info
);
858 // if requested, match [non-]builtin
859 if (match_context
->match_builtin
!= NULL
) {
860 CFBooleanRef known_builtin
;
862 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
864 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
869 // if we have a match
870 CFRelease(match_context
->matches
);
871 match_context
->matches
= NULL
;
877 * lookupMatchingInterface
879 * Looks at the interfaces that have already been [or need to be] named with
880 * the goal of allowing a system using a single network interface/adaptor of
881 * a given type (vendor, model, ...) to not care about the specific adaptor
882 * that is used (i.e. swapping dongle's is OK). Once a system has had more
883 * than one interface/adaptor connected at the same time than we assume that
884 * the network configuration is being setup for multi-homing that should be
887 * If no matches are found or if more than one match is found, return NULL.
888 * If a single match is found, return the match.
890 static CFDictionaryRef
891 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
892 CFArrayRef db_list
, // already named
893 CFArrayRef if_list
, // to be named
894 CFIndex if_list_index
,
895 CFBooleanRef builtin
)
898 CFDictionaryRef match
= NULL
;
899 matchContext match_context
;
901 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
902 if (if_type
== NULL
) {
906 match_context
.match_type
= if_type
;
907 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
908 match_context
.match_builtin
= builtin
;
909 match_context
.matches
= NULL
;
911 // check for matches to already named interfaces
912 // ... and appends each match that we find to match_context.matches
913 if (db_list
!= NULL
) {
914 CFArrayApplyFunction(db_list
,
915 CFRangeMake(0, CFArrayGetCount(db_list
)),
920 // check for matches to to be named interfaces
921 // ... and CFReleases match_context.matches if we find another network
922 // interface of the same type that also needs to be named
923 if (if_list
!= NULL
) {
924 CFIndex if_list_count
;
926 if_list_count
= CFArrayGetCount(if_list
);
927 if (if_list_index
< if_list_count
) {
928 CFArrayApplyFunction(if_list
,
929 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
935 // check if we have a single match
936 if (match_context
.matches
!= NULL
) {
937 if (CFArrayGetCount(match_context
.matches
) == 1) {
938 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
940 CFRelease(match_context
.matches
);
944 Boolean active
= TRUE
;
947 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
948 if (isA_CFString(name
)) {
951 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
955 (void)_SC_cfstring_to_cstring(name
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
);
956 if (ioctl(sock
, SIOCGIFFLAGS
, &ifr
) == -1) {
957 // if interface name not currently in-use
969 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
974 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
)
977 CFDictionaryRef if_dict
;
981 CFIndex n
= CFArrayGetCount(db_list
);
982 CFComparisonResult res
;
984 if_name
= SCNetworkInterfaceGetBSDName(interface
);
985 if (if_name
!= NULL
) {
986 addTimestamp(S_state
, if_name
);
989 if_dict
= createInterfaceDict(interface
);
990 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
991 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
992 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
997 for (i
= 0; i
< n
; i
++) {
1000 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
1002 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1003 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1004 res
= CFNumberCompare(if_type
, db_type
, NULL
);
1005 if (res
== kCFCompareLessThan
1006 || (res
== kCFCompareEqualTo
1007 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
1008 == kCFCompareLessThan
))) {
1009 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
1015 CFArrayAppendValue(S_dblist
, if_dict
);
1021 replaceInterface(SCNetworkInterfaceRef interface
)
1026 if (S_dblist
== NULL
) {
1027 S_dblist
= CFArrayCreateMutable(NULL
, 0,
1028 &kCFTypeArrayCallBacks
);
1030 // remove any dict that has our type/addr
1031 while (lookupInterfaceByAddress(S_dblist
, interface
, &where
) != NULL
) {
1032 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1035 // remove any dict that has the same type/unit
1036 while (lookupInterfaceByUnit(S_dblist
, interface
, &where
) != NULL
) {
1037 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1040 insertInterface(S_dblist
, interface
);
1045 issue
= CFStringCreateWithFormat(NULL
, NULL
,
1046 CFSTR("n = %d, %@"),
1049 reportIssue("Multiple interfaces updated", issue
);
1057 getHighestUnitForType(CFNumberRef if_type
)
1061 CFNumberRef ret_unit
= NULL
;
1063 if (S_dblist
== NULL
) {
1067 n
= CFArrayGetCount(S_dblist
);
1068 for (i
= 0; i
< n
; i
++) {
1069 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1072 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1073 if (CFEqual(type
, if_type
)) {
1076 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1077 if (ret_unit
== NULL
1078 || (CFNumberCompare(unit
, ret_unit
, NULL
)
1079 == kCFCompareGreaterThan
)) {
1089 * Function: ensureInterfaceHasUnit
1091 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1092 * release the interface and return NULL.
1094 static SCNetworkInterfaceRef
1095 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if
)
1098 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if
) == NULL
) {
1105 #ifdef USE_REGISTRY_ENTRY_ID
1106 static kern_return_t
1107 registerInterfaceWithIORegistryEntryID(io_connect_t connect
,
1113 CFMutableDictionaryRef dict
;
1117 dict
= CFDictionaryCreateMutable(NULL
, 0,
1118 &kCFTypeDictionaryKeyCallBacks
,
1119 &kCFTypeDictionaryValueCallBacks
);
1120 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1121 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1123 data
= CFDataCreate(NULL
, (void *) &entryID
, sizeof(entryID
));
1124 CFDictionarySetValue(dict
, CFSTR(kIORegistryEntryIDKey
), data
);
1126 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1127 kr
= IOConnectSetCFProperties(connect
, dict
);
1132 static SCNetworkInterfaceRef
1133 copyInterfaceForIORegistryEntryID(uint64_t entryID
)
1135 io_registry_entry_t entry
= MACH_PORT_NULL
;
1136 SCNetworkInterfaceRef interface
= NULL
;
1137 io_iterator_t iterator
= MACH_PORT_NULL
;
1139 mach_port_t masterPort
= MACH_PORT_NULL
;
1141 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1142 if (kr
!= KERN_SUCCESS
) {
1143 SCLog(TRUE
, LOG_ERR
,
1144 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x"),
1149 kr
= IOServiceGetMatchingServices(masterPort
,
1150 IORegistryEntryIDMatching(entryID
),
1152 if ((kr
!= KERN_SUCCESS
) || (iterator
== MACH_PORT_NULL
)) {
1153 SCLog(TRUE
, LOG_ERR
,
1154 CFSTR(MY_PLUGIN_NAME
": IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d"),
1161 entry
= IOIteratorNext(iterator
);
1162 if (entry
== MACH_PORT_NULL
) {
1163 SCLog(TRUE
, LOG_ERR
,
1164 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryIDMatching(0x%llx) failed"),
1169 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1172 if (masterPort
!= MACH_PORT_NULL
) {
1173 mach_port_deallocate(mach_task_self(), masterPort
);
1175 if (entry
!= MACH_PORT_NULL
) {
1176 IOObjectRelease(entry
);
1178 if (iterator
!= MACH_PORT_NULL
) {
1179 IOObjectRelease(iterator
);
1185 static SCNetworkInterfaceRef
1186 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID
)
1188 SCNetworkInterfaceRef net_if
;
1190 net_if
= copyInterfaceForIORegistryEntryID(entryID
);
1191 return (ensureInterfaceHasUnit(net_if
));
1194 #else // USE_REGISTRY_ENTRY_ID
1196 * Function: registerInterface
1198 * Register a single interface with the given service path to the
1199 * data link layer (BSD), using the specified unit number.
1201 static kern_return_t
1202 registerInterfaceWithIOServicePath(io_connect_t connect
,
1207 CFMutableDictionaryRef dict
;
1211 dict
= CFDictionaryCreateMutable(NULL
, 0,
1212 &kCFTypeDictionaryKeyCallBacks
,
1213 &kCFTypeDictionaryValueCallBacks
);
1214 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
1215 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommandKey
), num
);
1217 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1218 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1219 kr
= IOConnectSetCFProperties(connect
, dict
);
1224 static SCNetworkInterfaceRef
1225 copyInterfaceForIOKitPath(CFStringRef if_path
)
1227 io_registry_entry_t entry
= MACH_PORT_NULL
;
1228 SCNetworkInterfaceRef interface
= NULL
;
1230 mach_port_t masterPort
= MACH_PORT_NULL
;
1233 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1234 if (kr
!= KERN_SUCCESS
) {
1235 SCLog(TRUE
, LOG_ERR
,
1236 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x"),
1240 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1241 entry
= IORegistryEntryFromPath(masterPort
, path
);
1242 if (entry
== MACH_PORT_NULL
) {
1243 SCLog(TRUE
, LOG_ERR
,
1244 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryFromPath(%@) failed"),
1249 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1252 if (masterPort
!= MACH_PORT_NULL
) {
1253 mach_port_deallocate(mach_task_self(), masterPort
);
1255 if (entry
!= MACH_PORT_NULL
) {
1256 IOObjectRelease(entry
);
1262 static SCNetworkInterfaceRef
1263 copyNamedInterfaceForIOKitPath(CFStringRef if_path
)
1265 SCNetworkInterfaceRef net_if
;
1267 net_if
= copyInterfaceForIOKitPath(if_path
);
1268 return (ensureInterfaceHasUnit(net_if
));
1271 #endif // USE_REGISTRY_ENTRY_ID
1274 displayInterface(SCNetworkInterfaceRef interface
)
1281 name
= SCNetworkInterfaceGetBSDName(interface
);
1282 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1283 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1284 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1286 SCLog(TRUE
, LOG_INFO
,
1287 CFSTR(MY_PLUGIN_NAME
": %s%@%sType: %@, %s%@%sMAC address: %@"),
1288 (name
!= NULL
) ? "BSD Name: " : "",
1289 (name
!= NULL
) ? name
: CFSTR(""),
1290 (name
!= NULL
) ? ", " : "",
1292 (unit
!= NULL
) ? "Unit: " : "",
1293 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1294 (unit
!= NULL
) ? ", " : "",
1299 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
1304 for (i
= 0; i
< last
; i
++) {
1305 SCNetworkInterfaceRef builtin_if
;
1306 CFNumberRef builtin_type
;
1308 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1309 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
1310 if (CFEqual(if_type
, builtin_type
)) {
1311 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1312 n
++; // if built-in interface
1320 static __inline__ boolean_t
1323 return (S_quiet
== MACH_PORT_NULL
);
1327 nameInterfaces(CFMutableArrayRef if_list
)
1330 CFIndex n
= CFArrayGetCount(if_list
);
1332 for (i
= 0; i
< n
; i
++) {
1334 SCNetworkInterfaceRef interface
;
1335 SCNetworkInterfaceRef new_interface
;
1342 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1343 path
= _SCNetworkInterfaceGetIOPath(interface
);
1344 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1345 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1346 entryID
= _SCNetworkInterfaceGetIORegistryEntryID(interface
);
1350 CFStringRef if_name
;
1352 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1353 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
1354 SCLog(TRUE
, LOG_INFO
,
1355 CFSTR(MY_PLUGIN_NAME
": Interface already has a unit number"));
1356 displayInterface(interface
);
1360 // update the list of interfaces that were previously named
1361 if ((S_prev_active_list
!= NULL
)
1362 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
1363 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1366 replaceInterface(interface
);
1368 CFDictionaryRef dbdict
;
1369 boolean_t is_builtin
;
1373 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
1374 if (dbdict
!= NULL
) {
1375 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1378 SCLog(S_debug
, LOG_INFO
,
1379 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (from database)"),
1383 if ((dbdict
== NULL
) && !isQuiet()) {
1384 // if new interface, wait until quiet before naming
1385 addTimestamp(S_state
, path
);
1389 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
1391 if (dbdict
== NULL
) {
1392 dbdict
= lookupMatchingInterface(interface
,
1396 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
1397 if (dbdict
!= NULL
) {
1398 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1401 SCLog(S_debug
, LOG_INFO
,
1402 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (updating database)"),
1407 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
1408 // update the list of interfaces that were previously named
1409 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
1410 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
1412 if (where
!= kCFNotFound
) {
1413 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1417 if (dbdict
== NULL
) {
1421 // built-in interface, use the reserved slots
1422 next_unit
= builtinCount(if_list
, i
, type
);
1424 // not built-in, skip over the reserved slots
1425 next_unit
= builtinCount(if_list
, n
, type
);
1427 unit
= getHighestUnitForType(type
);
1431 CFNumberGetValue(unit
, kCFNumberIntType
, &high_unit
);
1432 if (high_unit
>= next_unit
) {
1433 next_unit
= high_unit
+ 1;
1437 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1439 SCLog(S_debug
, LOG_INFO
,
1440 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (%s)"),
1442 is_builtin
? "built-in" : "next available");
1447 #ifdef USE_REGISTRY_ENTRY_ID
1448 kr
= registerInterfaceWithIORegistryEntryID(S_connect
,
1451 (dbdict
== NULL
) ? kIONetworkStackRegisterInterfaceWithLowestUnit
1452 : kIONetworkStackRegisterInterfaceWithUnit
);
1453 new_interface
= copyNamedInterfaceForIORegistryEntryID(entryID
);
1454 #else // USE_REGISTRY_ENTRY_ID
1455 kr
= registerInterfaceWithIOServicePath(S_connect
,
1458 (dbdict
== NULL
) ? kRegisterInterface
1459 : kRegisterInterfaceWithFixedUnit
);
1460 new_interface
= copyNamedInterfaceForIOKitPath(path
);
1461 #endif // USE_REGISTRY_ENTRY_ID
1462 if (new_interface
== NULL
) {
1463 const char *signature
;
1465 signature
= (dbdict
== NULL
) ? "failed to name new interface"
1466 : "failed to name known interface";
1468 SCLog(TRUE
, LOG_ERR
,
1469 CFSTR(MY_PLUGIN_NAME
": %s, kr=0x%x\n"
1470 MY_PLUGIN_NAME
": path = %@\n"
1471 MY_PLUGIN_NAME
": id = 0x%llx\n"
1472 MY_PLUGIN_NAME
": unit = %@"),
1480 displayInterface(interface
);
1483 // report issue w/MessageTracer
1484 str
= CFStringCreateWithFormat(NULL
, NULL
,
1485 CFSTR("kr=0x%x, path=%@, unit=%@"),
1489 reportIssue(signature
, str
);
1492 if ((dbdict
!= NULL
) && (retries
++ < 5)) {
1493 usleep(50 * 1000); // sleep 50ms between attempts
1498 CFNumberRef new_unit
;
1501 SCLog(TRUE
, LOG_ERR
,
1502 CFSTR(MY_PLUGIN_NAME
": %s interface named after %d %s\n"
1503 MY_PLUGIN_NAME
": path = %@\n"
1504 MY_PLUGIN_NAME
": unit = %@"),
1505 (dbdict
== NULL
) ? "New" : "Known",
1507 (retries
== 1) ? "try" : "tries",
1511 #ifdef SHOW_NAMING_FAILURE
1512 str
= CFStringCreateWithFormat(NULL
,
1514 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
1515 (dbdict
== NULL
) ? "New" : "Known",
1517 (retries
== 1) ? "try" : "tries",
1519 CFUserNotificationDisplayNotice(0,
1520 kCFUserNotificationStopAlertLevel
,
1525 CFSTR("Please report repeated failures."),
1528 #endif // SHOW_NAMING_FAILURE
1531 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
1532 if (CFEqual(unit
, new_unit
) == FALSE
) {
1533 SCLog(S_debug
, LOG_INFO
,
1534 CFSTR(MY_PLUGIN_NAME
1535 ": interface type %@ assigned "
1536 "unit %@ instead of %@"),
1537 type
, new_unit
, unit
);
1540 displayInterface(new_interface
);
1543 // update if_list (with the interface name & unit)
1544 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
1545 CFRelease(new_interface
);
1546 interface
= new_interface
; // if_list holds the reference
1548 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
1551 // update the list of [built-in] interfaces that were previously named
1552 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
1553 SCLog(S_debug
, LOG_INFO
,
1554 CFSTR(MY_PLUGIN_NAME
": and updated database (new address)"));
1555 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1558 replaceInterface(interface
);
1569 if (S_connect
== MACH_PORT_NULL
) {
1570 // if we don't have the "IONetworkStack" connect object
1574 if (S_iflist
!= NULL
) {
1577 n
= CFArrayGetCount(S_iflist
);
1579 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
1581 nameInterfaces(S_iflist
);
1586 * The registry [matching] has quiesced so let's
1587 * - save the DB with the interfaces that have been named
1588 * - update the VLAN/BOND configuration
1589 * - tell everyone that we've finished (at least for now)
1590 * - log those interfaces which are no longer present
1591 * in the HW config (or have yet to show up).
1593 writeInterfaceList(S_dblist
);
1594 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
1597 if (S_iflist
!= NULL
) {
1598 CFRelease(S_iflist
);
1602 if (S_prev_active_list
!= NULL
) {
1607 n
= CFArrayGetCount(S_prev_active_list
);
1609 SCLog(TRUE
, LOG_INFO
,
1610 CFSTR(MY_PLUGIN_NAME
": Interface%s not [yet] active"),
1611 (n
> 1) ? "s" : "");
1613 for (i
= 0; i
< n
; i
++) {
1614 CFDictionaryRef if_dict
;
1619 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
1620 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
1621 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
1622 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
1623 SCLog(TRUE
, LOG_INFO
,
1624 CFSTR(MY_PLUGIN_NAME
": %s%@%sType: %@, Unit: %@"),
1625 (name
!= NULL
) ? "BSD Name: " : "",
1626 (name
!= NULL
) ? name
: CFSTR(""),
1627 (name
!= NULL
) ? ", " : "",
1632 CFRelease(S_prev_active_list
);
1633 S_prev_active_list
= NULL
;
1636 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
1638 * if we've named all of the interfaces that
1639 * were used during the previous boot.
1641 addTimestamp(S_state
, CFSTR("*RELEASE*"));
1642 SCLog(S_debug
, LOG_INFO
,
1643 CFSTR(MY_PLUGIN_NAME
": last boot interfaces have been named"));
1645 CFRelease(S_prev_active_list
);
1646 S_prev_active_list
= NULL
;
1653 #if !TARGET_OS_EMBEDDED
1654 static CFComparisonResult
1655 compareMacAddress(const void *val1
, const void *val2
, void *context
)
1657 CFDataRef mac1
= (CFDataRef
)val1
;
1658 CFDataRef mac2
= (CFDataRef
)val2
;
1661 CFComparisonResult res
;
1663 n1
= CFDataGetLength(mac1
);
1664 n2
= CFDataGetLength(mac2
);
1666 res
= kCFCompareLessThan
;
1667 } else if (n2
> n1
) {
1668 res
= kCFCompareGreaterThan
;
1670 res
= bcmp(CFDataGetBytePtr(mac1
), CFDataGetBytePtr(mac2
), n1
);
1680 CFMutableArrayRef addrs
= NULL
;
1681 CFStringRef guid
= NULL
;
1685 addrs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1686 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1687 for (i
= 0; i
< n
; i
++) {
1688 CFBooleanRef builtin
;
1689 CFDictionaryRef dict
;
1692 dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1693 type
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceType
));
1694 if (!isA_CFString(type
) || !CFEqual(type
, kSCNetworkInterfaceTypeEthernet
)) {
1697 builtin
= CFDictionaryGetValue(dict
, CFSTR(kIOBuiltin
));
1698 if (!isA_CFBoolean(builtin
) || !CFBooleanGetValue(builtin
)) {
1701 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
1702 if (!isA_CFData(addr
) || (CFDataGetLength(addr
) != ETHER_ADDR_LEN
)) {
1705 CFArrayAppendValue(addrs
, addr
);
1708 if (CFArrayGetCount(addrs
) == 0) {
1709 // if no ethernet interfaces, look for wireless
1710 for (i
= 0; i
< n
; i
++) {
1711 CFDictionaryRef dict
;
1714 dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1715 type
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceType
));
1716 if (!isA_CFString(type
) || !CFEqual(type
, kSCNetworkInterfaceTypeIEEE80211
)) {
1719 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
1720 if (!isA_CFData(addr
) || (CFDataGetLength(addr
) != ETHER_ADDR_LEN
)) {
1723 CFArrayAppendValue(addrs
, addr
);
1727 n
= CFArrayGetCount(addrs
);
1730 // if no network interfaces
1733 // sort by MAC address
1734 CFArraySortValues(addrs
, CFRangeMake(0, n
), compareMacAddress
, NULL
);
1738 CFUUIDBytes bytes
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1739 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1743 addr
= CFArrayGetValueAtIndex(addrs
, 0);
1744 bcopy(CFDataGetBytePtr(addr
),
1745 (void *)&bytes
+ sizeof(bytes
) - ETHER_ADDR_LEN
,
1747 uuid
= CFUUIDCreateFromUUIDBytes(NULL
, bytes
);
1748 guid
= CFUUIDCreateString(NULL
, uuid
);
1751 SCLog(TRUE
, LOG_INFO
,
1752 CFSTR(MY_PLUGIN_NAME
": setting platform UUID [MAC] = %@"),
1758 if (addrs
!= NULL
) CFRelease(addrs
);
1762 #ifndef kIOPlatformUUIDKey
1763 #define kIOPlatformUUIDKey "IOPlatformUUID"
1766 updatePlatformUUID()
1768 CFStringRef guid
= NULL
;
1770 io_registry_entry_t platform
;
1772 platform
= IORegistryEntryFromPath(kIOMasterPortDefault
, kIODeviceTreePlane
":/");
1773 if (platform
== MACH_PORT_NULL
) {
1777 guid
= IORegistryEntryCreateCFProperty(platform
, CFSTR(kIOPlatformUUIDKey
), NULL
, 0);
1779 // if GUID already defined
1783 guid
= copyEthernetUUID();
1787 uuid
= CFUUIDCreate(NULL
);
1788 guid
= CFUUIDCreateString(NULL
, uuid
);
1791 SCLog(TRUE
, LOG_INFO
,
1792 CFSTR(MY_PLUGIN_NAME
": setting platform UUID [random] = %@"),
1796 if (getenv("DO_NOT_SET_PLATFORM_UUID") == NULL
) {
1797 kr
= IORegistryEntrySetCFProperty(platform
, CFSTR(kIOPlatformUUIDKey
), guid
);
1798 if (kr
!= KERN_SUCCESS
) {
1799 SCLog(TRUE
, LOG_ERR
,
1800 CFSTR(MY_PLUGIN_NAME
": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"),
1805 addTimestamp(S_state
, CFSTR("*PLATFORM-UUID*"));
1810 if (S_vproc_transaction
!= NULL
) {
1811 vproc_transaction_end(NULL
, S_vproc_transaction
);
1812 S_vproc_transaction
= NULL
;
1815 if (platform
!= MACH_PORT_NULL
) IOObjectRelease(platform
);
1816 if (guid
!= NULL
) CFRelease(guid
);
1819 #endif // !TARGET_OS_EMBEDDED
1822 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
1826 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
1827 SCNetworkInterfaceRef interface
;
1829 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
1830 if (interface
!= NULL
) {
1831 if (S_iflist
== NULL
) {
1832 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1834 CFArrayAppendValue(S_iflist
, interface
);
1835 CFRelease(interface
);
1837 IOObjectRelease(obj
);
1845 * Function: stackCallback
1847 * Get a reference to the single IONetworkStack object instance in
1848 * the kernel. Naming requests must be sent to this object, which is
1849 * attached as a client to all network interface objects in the system.
1851 * Call IOObjectRelease on the returned object.
1854 stackCallback(void *refcon
, io_iterator_t iter
)
1859 stack
= IOIteratorNext(iter
);
1860 if (stack
== MACH_PORT_NULL
) {
1864 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
1865 if (kr
!= KERN_SUCCESS
) {
1866 SCLog(TRUE
, LOG_ERR
,
1867 CFSTR(MY_PLUGIN_NAME
": IOServiceOpen returned 0x%x"),
1872 addTimestamp(S_state
, CFSTR("*STACK*"));
1873 SCLog(S_debug
, LOG_INFO
,
1874 CFSTR(MY_PLUGIN_NAME
": IONetworkStack found"));
1876 if (S_stack
!= MACH_PORT_NULL
) {
1877 IOObjectRelease(S_stack
);
1878 S_stack
= MACH_PORT_NULL
;
1881 if ((S_timer
!= NULL
) && CFRunLoopTimerIsValid(S_timer
)) {
1882 // With the IONetworkStack object now available we can
1883 // reset (shorten?) the time we are willing to wait for
1884 // IOKit to quiesce.
1885 CFRunLoopTimerSetNextFireDate(S_timer
,
1886 CFAbsoluteTimeGetCurrent() + S_quiet_timeout
);
1892 if (stack
!= MACH_PORT_NULL
) {
1893 IOObjectRelease(stack
);
1900 quietCallback(void *refcon
,
1901 io_service_t service
,
1902 natural_t messageType
,
1903 void *messageArgument
)
1905 if (messageArgument
!= NULL
) {
1910 if (messageType
== kIOMessageServiceBusyStateChange
) {
1911 addTimestamp(S_state
, CFSTR("*QUIET*"));
1912 SCLog(S_debug
, LOG_INFO
,
1913 CFSTR(MY_PLUGIN_NAME
": IOKit quiet"));
1916 if (S_connect
== MACH_PORT_NULL
) {
1917 SCLog(TRUE
, LOG_ERR
,
1918 CFSTR(MY_PLUGIN_NAME
": No network stack object"));
1922 if (S_quiet
!= MACH_PORT_NULL
) {
1923 IOObjectRelease(S_quiet
);
1924 S_quiet
= MACH_PORT_NULL
;
1927 if (S_timer
!= NULL
) {
1928 CFRunLoopTimerInvalidate(S_timer
);
1933 // grab (and name) any additional interfaces.
1934 interfaceArrivalCallback((void *)S_notify
, S_iter
);
1936 #if !TARGET_OS_EMBEDDED
1937 updatePlatformUUID();
1938 #endif // !TARGET_OS_EMBEDDED
1944 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, CFMutableStringRef snapshot
, int *count
)
1946 kern_return_t kr
= kIOReturnSuccess
;;
1949 while ((kr
== kIOReturnSuccess
) &&
1950 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
1951 uint64_t accumulated_busy_time
;
1952 uint32_t busy_state
;
1955 CFMutableArrayRef newNodes
;
1957 CFMutableStringRef str
= NULL
;
1959 if (nodes
== NULL
) {
1960 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1962 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
1965 kr
= IORegistryEntryGetName(obj
, name
);
1966 if (kr
!= kIOReturnSuccess
) {
1967 SCLog(TRUE
, LOG_ERR
,
1968 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryEntryGetName returned 0x%x"),
1973 str
= CFStringCreateMutable(NULL
, 0);
1974 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
1976 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
1978 case kIOReturnSuccess
:
1979 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
1980 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
1982 case kIOReturnNotFound
:
1985 SCLog(TRUE
, LOG_ERR
,
1986 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryEntryGetLocationInPlane returned 0x%x"),
1992 CFArrayAppendValue(newNodes
, str
);
1995 kr
= IOServiceGetBusyStateAndTime(obj
, &state
, &busy_state
, &accumulated_busy_time
);
1996 if (kr
!= kIOReturnSuccess
) {
1997 SCLog(TRUE
, LOG_ERR
,
1998 CFSTR(MY_PLUGIN_NAME
": captureBusy IOServiceGetBusyStateAndTime returned 0x%x"),
2003 #ifdef TEST_SNAPSHOT
2006 #endif // TEST_SNAPSHOT
2008 if (busy_state
!= 0) {
2011 if ((*count
)++ == 0) {
2012 CFStringAppend(snapshot
, CFSTR("Busy services :"));
2015 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
2016 CFStringAppendFormat(snapshot
, NULL
,
2017 CFSTR("\n %@ [%s%s%s%d, %lld ms]"),
2019 (state
& kIOServiceRegisteredState
) ? "" : "!registered, ",
2020 (state
& kIOServiceMatchedState
) ? "" : "!matched, ",
2021 (state
& kIOServiceInactiveState
) ? "inactive, " : "",
2023 accumulated_busy_time
/ kMillisecondScale
);
2027 kr
= IORegistryIteratorEnterEntry(iterator
);
2028 if (kr
!= kIOReturnSuccess
) {
2029 SCLog(TRUE
, LOG_ERR
,
2030 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryIteratorEnterEntry returned 0x%x"),
2035 iterateRegistryBusy(iterator
, newNodes
, snapshot
, count
);
2037 kr
= IORegistryIteratorExitEntry(iterator
);
2038 if (kr
!= kIOReturnSuccess
) {
2039 SCLog(TRUE
, LOG_ERR
,
2040 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryIteratorExitEntry returned 0x%x"),
2046 CFRelease(newNodes
);
2047 IOObjectRelease(obj
);
2053 static CF_RETURNS_RETAINED CFStringRef
2057 io_iterator_t iterator
= MACH_PORT_NULL
;
2059 CFMutableStringRef snapshot
;
2061 snapshot
= CFStringCreateMutable(NULL
, 0);
2063 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
2067 if (kr
!= kIOReturnSuccess
) {
2068 SCLog(TRUE
, LOG_ERR
,
2069 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryCreateIterator returned 0x%x"),
2074 iterateRegistryBusy(iterator
, NULL
, snapshot
, &count
);
2076 CFStringAppend(snapshot
, CFSTR("w/no busy services"));
2079 IOObjectRelease(iterator
);
2084 timerCallback(CFRunLoopTimerRef timer
, void *info
)
2086 CFStringRef snapshot
;
2088 // We've been waiting for IOKit to quiesce and it just
2089 // hasn't happenned. Time to just move on!
2090 addTimestamp(S_state
, CFSTR("*TIMEOUT*"));
2093 snapshot
= captureBusy();
2094 SCLog(TRUE
, LOG_ERR
,
2095 CFSTR(MY_PLUGIN_NAME
": timed out waiting for IOKit to quiesce\n%@"),
2097 reportIssue("timed out waiting for IOKit to quiesce", snapshot
);
2098 CFRelease(snapshot
);
2100 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
2105 setup_IOKit(CFBundleRef bundle
)
2109 mach_port_t masterPort
= MACH_PORT_NULL
;
2111 io_object_t root
= MACH_PORT_NULL
;
2113 // read DB of previously named network interfaces
2114 S_dblist
= readInterfaceList();
2115 if (S_dblist
!= NULL
) {
2118 n
= CFArrayGetCount(S_dblist
);
2120 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
2124 // get interfaces that were named during the last boot
2125 S_prev_active_list
= previouslyActiveInterfaces();
2127 // track how long we've waited to see each interface.
2128 S_state
= CFDictionaryCreateMutable(NULL
,
2130 &kCFTypeDictionaryKeyCallBacks
,
2131 &kCFTypeDictionaryValueCallBacks
);
2132 addTimestamp(S_state
, CFSTR("*START*"));
2134 // Creates and returns a notification object for receiving IOKit
2135 // notifications of new devices or state changes.
2136 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
2137 if (kr
!= KERN_SUCCESS
) {
2138 SCLog(TRUE
, LOG_ERR
,
2139 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x"),
2144 S_notify
= IONotificationPortCreate(masterPort
);
2145 if (S_notify
== NULL
) {
2146 SCLog(TRUE
, LOG_ERR
,
2147 CFSTR(MY_PLUGIN_NAME
": IONotificationPortCreate failed"));
2151 // watch IOKit matching activity
2152 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
2153 if (root
== MACH_PORT_NULL
) {
2154 SCLog(TRUE
, LOG_ERR
,
2155 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryFromPath failed"));
2159 kr
= IOServiceAddInterestNotification(S_notify
,
2163 (void *)S_notify
, // refCon
2164 &S_quiet
); // notification
2165 if (kr
!= KERN_SUCCESS
) {
2166 SCLog(TRUE
, LOG_ERR
,
2167 CFSTR(MY_PLUGIN_NAME
": IOServiceAddInterestNotification returned 0x%x"),
2172 kr
= IOServiceGetBusyState(root
, &busy
);
2173 if (kr
!= KERN_SUCCESS
) {
2174 SCLog(TRUE
, LOG_ERR
,
2175 CFSTR(MY_PLUGIN_NAME
": IOServiceGetBusyState returned 0x%x"),
2180 // add a timer so we don't wait forever for IOKit to quiesce
2181 S_timer
= CFRunLoopTimerCreate(NULL
,
2182 CFAbsoluteTimeGetCurrent() + S_stack_timeout
,
2188 if (S_timer
== NULL
) {
2189 SCLog(TRUE
, LOG_ERR
,
2190 CFSTR(MY_PLUGIN_NAME
": CFRunLoopTimerCreate failed"));
2194 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
2196 // watch for the introduction of the IONetworkStack
2197 kr
= IOServiceAddMatchingNotification(S_notify
,
2198 kIOFirstMatchNotification
,
2199 IOServiceMatching("IONetworkStack"),
2201 (void *)S_notify
, // refCon
2202 &S_stack
); // notification
2203 if (kr
!= KERN_SUCCESS
) {
2204 SCLog(TRUE
, LOG_ERR
,
2205 CFSTR(MY_PLUGIN_NAME
": IOServiceAddMatchingNotification returned 0x%x"),
2210 // check and see if the stack is already available and arm the
2211 // notification for its introduction.
2212 stackCallback((void *)S_notify
, S_stack
);
2214 // watch for the introduction of new network interfaces
2215 kr
= IOServiceAddMatchingNotification(S_notify
,
2216 kIOFirstMatchNotification
,
2217 IOServiceMatching("IONetworkInterface"),
2218 &interfaceArrivalCallback
,
2219 (void *)S_notify
, // refCon
2220 &S_iter
); // notification
2221 if (kr
!= KERN_SUCCESS
) {
2222 SCLog(TRUE
, LOG_ERR
,
2223 CFSTR(MY_PLUGIN_NAME
": IOServiceAddMatchingNotification returned 0x%x"),
2228 // Get the current list of matches and arm the notification for
2229 // future interface arrivals.
2230 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2232 // Check if IOKit has already quiesced.
2233 quietCallback((void *)S_notify
,
2235 kIOMessageServiceBusyStateChange
,
2236 (void *)(uintptr_t)busy
);
2238 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2239 IONotificationPortGetRunLoopSource(S_notify
),
2240 kCFRunLoopDefaultMode
);
2242 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
2244 * Start the wheels turning until we've named all of
2245 * the interfaces that were used during the previous
2246 * boot, until IOKit [matching] has quiesced, or
2247 * until we've waited long enough.
2249 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
2250 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2251 IONotificationPortGetRunLoopSource(S_notify
),
2253 while (S_prev_active_list
!= NULL
) {
2256 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
2258 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
2263 if (root
!= MACH_PORT_NULL
) {
2264 IOObjectRelease(root
);
2266 if (masterPort
!= MACH_PORT_NULL
) {
2267 mach_port_deallocate(mach_task_self(), masterPort
);
2274 setup_Virtual(CFBundleRef bundle
)
2276 // open a SCPreferences session
2277 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
);
2278 if (S_prefs
== NULL
) {
2279 SCLog(TRUE
, LOG_ERR
,
2280 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate() failed: %s"),
2281 SCErrorString(SCError()));
2285 // register for change notifications.
2286 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
2287 SCLog(TRUE
, LOG_ERR
,
2288 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetCallBack() failed: %s"),
2289 SCErrorString(SCError()));
2295 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
2296 if (SCError() != kSCStatusNoStoreServer
) {
2297 SCLog(TRUE
, LOG_ERR
,
2298 CFSTR(MY_PLUGIN_NAME
": SCPreferencesScheduleWithRunLoop() failed: %s"),
2299 SCErrorString(SCError()));
2309 exec_InterfaceNamer(void *arg
)
2311 CFBundleRef bundle
= (CFBundleRef
)arg
;
2312 CFDictionaryRef dict
;
2314 pthread_setname_np(MY_PLUGIN_NAME
" thread");
2316 dict
= CFBundleGetInfoDictionary(bundle
);
2317 if (isA_CFDictionary(dict
)) {
2320 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_STACK_TIMEOUT_KEY
));
2322 if (!isA_CFNumber(num
) ||
2323 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_stack_timeout
) ||
2324 (S_stack_timeout
<= 0.0)) {
2325 SCLog(TRUE
, LOG_ERR
,
2326 CFSTR(MY_PLUGIN_NAME
": " WAIT_STACK_TIMEOUT_KEY
" value error"));
2327 S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
2331 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
2333 if (!isA_CFNumber(num
) ||
2334 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_quiet_timeout
) ||
2335 (S_quiet_timeout
<= 0.0)) {
2336 SCLog(TRUE
, LOG_ERR
,
2337 CFSTR(MY_PLUGIN_NAME
": " WAIT_QUIET_TIMEOUT_KEY
" value error"));
2338 S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
2343 // setup virtual network interface monitoring
2344 if (!setup_Virtual(bundle
)) {
2348 // setup [IOKit] network interface monitoring
2349 if (!setup_IOKit(bundle
)) {
2353 #if !TARGET_OS_EMBEDDED
2354 // keep launchd from SIGKILL'ing us until after the platform-uuid has
2356 S_vproc_transaction
= vproc_transaction_begin(NULL
);
2357 #endif // !TARGET_OS_EMBEDDED
2362 if (S_connect
!= MACH_PORT_NULL
) {
2363 IOServiceClose(S_connect
);
2364 S_connect
= MACH_PORT_NULL
;
2366 if (S_dblist
!= NULL
) {
2367 CFRelease(S_dblist
);
2370 if (S_iter
!= MACH_PORT_NULL
) {
2371 IOObjectRelease(S_iter
);
2372 S_iter
= MACH_PORT_NULL
;
2374 if (S_notify
!= MACH_PORT_NULL
) {
2375 IONotificationPortDestroy(S_notify
);
2377 if (S_quiet
!= MACH_PORT_NULL
) {
2378 IOObjectRelease(S_quiet
);
2379 S_quiet
= MACH_PORT_NULL
;
2381 if (S_stack
!= MACH_PORT_NULL
) {
2382 IOObjectRelease(S_stack
);
2383 S_stack
= MACH_PORT_NULL
;
2385 if (S_state
!= NULL
) {
2389 if (S_timer
!= NULL
) {
2390 CFRunLoopTimerInvalidate(S_timer
);
2404 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
2406 pthread_attr_t tattr
;
2409 if (bundleVerbose
) {
2413 CFRetain(bundle
); // released in exec_InterfaceNamer
2415 pthread_attr_init(&tattr
);
2416 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
2417 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
2418 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
2419 pthread_create(&tid
, &tattr
, exec_InterfaceNamer
, bundle
);
2420 pthread_attr_destroy(&tattr
);
2425 //------------------------------------------------------------------------
2429 main(int argc
, char ** argv
)
2434 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2436 S_debug
= _sc_verbose
;
2438 bundle
= CFBundleGetMainBundle();
2439 CFRetain(bundle
); // released in exec_InterfaceNamer
2441 (void)exec_InterfaceNamer();
2449 #ifdef TEST_PLATFORM_UUID
2451 main(int argc
, char ** argv
)
2454 CFArrayRef interfaces
;
2457 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2459 S_dblist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2460 interfaces
= SCNetworkInterfaceCopyAll();
2461 if (interfaces
!= NULL
) {
2465 n
= CFArrayGetCount(interfaces
);
2466 for (i
= 0; i
< n
; i
++) {
2467 CFDictionaryRef dict
;
2468 SCNetworkInterfaceRef interface
;
2470 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2471 dict
= createInterfaceDict(interface
);
2472 CFArrayAppendValue(S_dblist
, dict
);
2475 CFRelease(interfaces
);
2478 guid
= copyEthernetUUID();
2479 SCPrint(TRUE
, stdout
, CFSTR("copyEthernetUUID() = %@\n"), (guid
!= NULL
) ? guid
: CFSTR("NULL"));
2480 if (guid
!= NULL
) CFRelease(guid
);
2482 updatePlatformUUID();
2483 CFRelease(S_dblist
);
2487 #endif /* TEST_PLATFORM_UUID */
2489 #ifdef TEST_SNAPSHOT
2491 main(int argc
, char ** argv
)
2493 CFStringRef snapshot
;
2496 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2498 snapshot
= captureBusy();
2499 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), snapshot
);
2500 CFRelease(snapshot
);
2505 #endif /* TEST_SNAPSHOT */