2 * Copyright (c) 2001-2011 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 * November 6, 2006 Allan Nathanson <ajn@apple.com>
28 * Dan Markarian <markarian@apple.com>
29 * Dieter Siegmund <dieter@apple.com>
30 * - updated code to name interfaces quicker (without need for
31 * calling IOKitWaitQuiet).
33 * October 3, 2003 Allan Nathanson <ajn@apple.com>
34 * - sort new interfaces by IOKit path (rather than MAC address) to
35 * help facilitate a more predictable interface-->name mapping for
36 * like hardware configurations.
38 * June 23, 2001 Allan Nathanson <ajn@apple.com>
39 * - update to public SystemConfiguration.framework APIs
41 * January 23, 2001 Dieter Siegmund <dieter@apple.com>
47 * - module that receives IOKit Network Interface messages
48 * and names any interface that currently does not have a name
49 * - uses Interface Type and MACAddress as the unique identifying
50 * keys; any interface that doesn't contain both of these properties
51 * is ignored and not processed
52 * - stores the Interface Type, MACAddress, and Unit in permanent storage
53 * to give persistent interface names
61 #include <sys/ioctl.h>
62 #include <sys/socket.h>
63 #include <sys/sockio.h>
65 #include <sys/sysctl.h>
66 #include <sys/param.h>
67 #include <mach/mach.h>
68 #include <net/ethernet.h>
70 #include <net/if_types.h>
72 #include <CoreFoundation/CoreFoundation.h>
74 #include <SystemConfiguration/SystemConfiguration.h>
75 #include <SystemConfiguration/SCDPlugin.h>
76 #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
77 #include <SystemConfiguration/SCValidation.h>
79 #include <IOKit/IOKitLib.h>
80 #include <IOKit/IOKitLibPrivate.h>
81 #include <IOKit/IOBSD.h>
82 #include <IOKit/IOMessage.h>
83 #include <IOKit/network/IONetworkController.h>
84 #include <IOKit/network/IONetworkInterface.h>
85 #include <IOKit/usb/USB.h>
87 // from <IOKit/network/IONetworkStack.h>
88 #define kIONetworkStackUserCommand "IONetworkStackUserCommand"
90 kRegisterInterfaceWithFixedUnit
= 0,
92 kRegisterAllInterfaces
95 #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo"
96 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
97 #define kSCNetworkInterfaceActive "Active"
99 #define MY_PLUGIN_NAME "InterfaceNamer"
100 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
102 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
103 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
105 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
106 #define WAIT_QUIET_TIMEOUT_DEFAULT 60.0
110 * "IONetworkStack" connect object used to "name" an interface.
112 static io_connect_t S_connect
= MACH_PORT_NULL
;
116 * An array of CFDictionary's representing the interfaces
117 * that have been identified and [need to be] named.
119 static CFMutableArrayRef S_dblist
= NULL
;
123 * A boolean that enables additional logging.
125 static boolean_t S_debug
= FALSE
;
129 * An array of SCNetworkInterface's representing the
130 * interfaces that have been identified.
132 static CFMutableArrayRef S_iflist
= NULL
;
136 * IOServiceAddMatchingNotification object used to watch for
137 * new network interfaces.
139 static io_iterator_t S_iter
= MACH_PORT_NULL
;
143 * Hardware model for this network configuration.
145 static CFStringRef S_model
= NULL
;
149 * notification object for receiving IOKit notifications of
150 * new devices or state changes.
152 static IONotificationPortRef S_notify
= NULL
;
154 /* S_prev_active_list
155 * An array of CFDictionary's representing the previously
158 static CFMutableArrayRef S_prev_active_list
= NULL
;
162 * IOServiceAddInterestNotification object used to watch for
163 * IOKit matching to quiesce.
165 static io_object_t S_quiet
= MACH_PORT_NULL
;
169 * IOServiceAddMatchingNotification object used to watch for
170 * the availability of the "IONetworkStack" object.
172 static io_iterator_t S_stack
= MACH_PORT_NULL
;
176 * A dictionary containing Information about each network
177 * interface. For now, the key is the BSD name and the
178 * value is a CFNumber noting how long (in milliseconds)
179 * it took for the interface to be recognized/named.
181 static CFMutableDictionaryRef S_state
= NULL
;
185 * CFRunLoopTimer tracking how long we are willing to wait
186 * for IOKit matching to quiesce (IOKitWaitQuiet).
189 * time to wait for the IONetworkStack object to appear before timeout
192 * time to wait for the IOKit to quiesce (after the IONetworkStack is
195 static CFRunLoopTimerRef S_timer
= NULL
;
196 static double S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
197 static double S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
201 * Virtual network interface configuration
202 * S_prefs : SCPreferences to configuration
203 * S_bonds : most recently actived Bond configuration
204 * S_bridges : most recently actived Bridge configuration
205 * S_vlans : most recently actived VLAN configuration
207 static SCPreferencesRef S_prefs
= NULL
;
208 static CFArrayRef S_bonds
= NULL
;
209 static CFArrayRef S_bridges
= NULL
;
210 static CFArrayRef S_vlans
= NULL
;
213 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
218 now
= CFAbsoluteTimeGetCurrent();
219 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
220 CFDictionaryAddValue(dict
, key
, val
);
225 #define INTERFACES CFSTR("Interfaces")
226 #define MODEL CFSTR("Model")
227 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
232 if (S_model
== NULL
) {
234 int mib
[] = { CTL_HW
, HW_MODEL
};
235 size_t n
= sizeof(hwModel
);
239 bzero(&hwModel
, sizeof(hwModel
));
240 ret
= sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), &hwModel
, &n
, NULL
, 0);
242 SCLog(TRUE
, LOG_ERR
, CFSTR("sysctl() CTL_HW/HW_MODEL failed: %s"), strerror(errno
));
245 hwModel
[sizeof(hwModel
) - 1] = '\0';
247 S_model
= CFStringCreateWithCString(NULL
, hwModel
, kCFStringEncodingASCII
);
254 static CFComparisonResult
255 if_unit_compare(const void *val1
, const void *val2
, void *context
)
257 CFComparisonResult res
;
263 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
264 CFSTR(kIOInterfaceType
));
265 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
266 CFSTR(kIOInterfaceType
));
267 res
= CFNumberCompare(type1
, type2
, NULL
);
268 if (res
!= kCFCompareEqualTo
) {
271 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
272 CFSTR(kIOInterfaceUnit
));
273 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
274 CFSTR(kIOInterfaceUnit
));
275 return (CFNumberCompare(unit1
, unit2
, NULL
));
279 reportIssue(const char *signature
, CFStringRef issue
)
283 m
= asl_new(ASL_TYPE_MSG
);
284 asl_set(m
, "com.apple.message.domain", "com.apple.SystemConfiguration." MY_PLUGIN_NAME
);
285 asl_set(m
, "com.apple.message.signature", signature
);
286 asl_set(m
, "com.apple.message.result", "failure");
287 SCLOG(NULL
, m
, ~ASL_LEVEL_ERR
, CFSTR("%s\n%@"), signature
, issue
);
294 writeInterfaceList(CFArrayRef if_list
)
297 CFStringRef new_model
;
298 CFStringRef old_model
;
299 SCPreferencesRef prefs
;
301 if (isA_CFArray(if_list
) == NULL
) {
305 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
308 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate failed, %s"),
309 SCErrorString(SCError()));
313 cur_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
314 if (_SC_CFEqual(cur_list
, if_list
)) {
318 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
319 new_model
= hw_model();
320 if ((old_model
!= NULL
) &&
321 (new_model
!= NULL
) &&
322 !CFEqual(old_model
, new_model
) &&
323 (cur_list
!= NULL
)) {
327 // if interface list was created on other hardware
328 history
= CFStringCreateWithFormat(NULL
, NULL
,
332 SCPreferencesSetValue(prefs
, history
, cur_list
);
336 CFSTR(MY_PLUGIN_NAME
": Hardware model changed\n"
337 MY_PLUGIN_NAME
": created on \"%@\"\n"
338 MY_PLUGIN_NAME
": now on \"%@\""),
342 issue
= CFStringCreateWithFormat(NULL
, NULL
,
346 reportIssue("Hardware model changed", issue
);
350 if ((new_model
!= NULL
) &&
351 !SCPreferencesSetValue(prefs
, MODEL
, new_model
)) {
353 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetValue failed, %s"),
354 SCErrorString(SCError()));
358 if (!SCPreferencesSetValue(prefs
, INTERFACES
, if_list
)) {
360 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetValue failed, %s"),
361 SCErrorString(SCError()));
365 if (!SCPreferencesCommitChanges(prefs
)) {
366 SCLog((SCError() != EROFS
), LOG_ERR
,
367 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCommitChanges failed, %s"),
368 SCErrorString(SCError()));
378 static CFMutableArrayRef
382 CFStringRef old_model
;
383 CFMutableArrayRef plist
= NULL
;
384 SCPreferencesRef prefs
= NULL
;
386 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
389 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate failed, %s"),
390 SCErrorString(SCError()));
394 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
395 if_list
= isA_CFArray(if_list
);
397 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
398 if (old_model
!= NULL
) {
399 CFStringRef new_model
;
401 new_model
= hw_model();
402 if (!_SC_CFEqual(old_model
, new_model
)) {
403 // if interface list was created on other hardware
408 if (if_list
!= NULL
) {
410 CFIndex n
= CFArrayGetCount(if_list
);
412 plist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
413 for (i
= 0; i
< n
; i
++) {
414 CFDictionaryRef dict
;
416 dict
= CFArrayGetValueAtIndex(if_list
, i
);
417 if (isA_CFDictionary(dict
) &&
418 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceType
)) &&
419 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
420 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
421 CFArrayAppendValue(plist
, dict
);
432 static CFMutableArrayRef
433 previouslyActiveInterfaces()
435 CFMutableArrayRef active
;
439 if (S_dblist
== NULL
) {
443 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
445 n
= CFArrayGetCount(S_dblist
);
446 for (i
= 0; i
< n
; i
++) {
447 CFDictionaryRef if_dict
;
449 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
450 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
451 CFMutableDictionaryRef new_dict
;
453 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
454 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
455 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
456 CFArrayAppendValue(active
, new_dict
);
468 SCDynamicStoreRef store
;
470 store
= SCDynamicStoreCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
, NULL
);
475 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
),
476 kSCDynamicStoreDomainPlugin
);
477 (void)SCDynamicStoreSetValue(store
, key
, S_state
);
485 updateBondInterfaceConfiguration(SCPreferencesRef prefs
)
487 CFArrayRef interfaces
;
489 interfaces
= SCBondInterfaceCopyAll(prefs
);
490 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
491 CFRelease(interfaces
);
495 if (_SC_CFEqual(S_bonds
, interfaces
)) {
497 if (interfaces
!= NULL
) CFRelease(interfaces
);
501 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
502 S_bonds
= interfaces
;
504 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
506 CFSTR(MY_PLUGIN_NAME
": _SCBondInterfaceUpdateConfiguration failed, %s"),
507 SCErrorString(SCError()));
514 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs
)
516 CFArrayRef interfaces
;
518 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
519 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
520 CFRelease(interfaces
);
524 if (_SC_CFEqual(S_bridges
, interfaces
)) {
526 if (interfaces
!= NULL
) CFRelease(interfaces
);
530 if (S_bridges
!= NULL
) CFRelease(S_bridges
);
531 S_bridges
= interfaces
;
533 if (!_SCBridgeInterfaceUpdateConfiguration(prefs
)) {
535 CFSTR(MY_PLUGIN_NAME
": _SCBridgeInterfaceUpdateConfiguration failed, %s"),
536 SCErrorString(SCError()));
543 updateVLANInterfaceConfiguration(SCPreferencesRef prefs
)
545 CFArrayRef interfaces
;
547 interfaces
= SCVLANInterfaceCopyAll(prefs
);
548 if ((interfaces
!= NULL
) && (CFArrayGetCount(interfaces
) == 0)) {
549 CFRelease(interfaces
);
553 if (_SC_CFEqual(S_vlans
, interfaces
)) {
555 if (interfaces
!= NULL
) CFRelease(interfaces
);
559 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
560 S_vlans
= interfaces
;
562 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
564 CFSTR(MY_PLUGIN_NAME
": _SCVLANInterfaceUpdateConfiguration failed, %s"),
565 SCErrorString(SCError()));
572 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
573 SCPreferencesNotification notificationType
,
576 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
581 // if a new interface has been "named"
583 if (S_bonds
!= NULL
) {
587 if (S_bridges
!= NULL
) {
588 CFRelease(S_bridges
);
591 if (S_vlans
!= NULL
) {
597 updateBondInterfaceConfiguration (prefs
);
598 updateBridgeInterfaceConfiguration(prefs
);
599 updateVLANInterfaceConfiguration (prefs
);
601 // we are finished with current prefs, wait for changes
602 SCPreferencesSynchronize(prefs
);
606 static CFDictionaryRef
607 createInterfaceDict(SCNetworkInterfaceRef interface
)
609 CFMutableDictionaryRef new_if
;
612 new_if
= CFDictionaryCreateMutable(NULL
,
614 &kCFTypeDictionaryKeyCallBacks
,
615 &kCFTypeDictionaryValueCallBacks
);
617 val
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
619 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceInfo
), val
);
623 val
= _SCNetworkInterfaceGetIOPath(interface
);
625 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
628 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
630 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
633 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
635 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
638 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
640 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
643 val
= SCNetworkInterfaceGetBSDName(interface
);
645 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
648 val
= SCNetworkInterfaceGetInterfaceType(interface
);
650 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
653 CFDictionarySetValue(new_if
,
655 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
657 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
662 static CFDictionaryRef
663 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
670 if (db_list
== NULL
) {
673 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
674 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
675 if (type
== NULL
|| addr
== NULL
) {
679 n
= CFArrayGetCount(db_list
);
680 for (i
= 0; i
< n
; i
++) {
682 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
685 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
686 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
687 if (t
== NULL
|| a
== NULL
)
690 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
700 static CFDictionaryRef
701 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
708 if (db_list
== NULL
) {
711 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
712 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
713 if (type
== NULL
|| unit
== NULL
) {
717 n
= CFArrayGetCount(db_list
);
718 for (i
= 0; i
< n
; i
++) {
719 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
723 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
724 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
725 if (t
== NULL
|| u
== NULL
) {
729 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
739 CFDictionaryRef match_info
;
740 CFStringRef match_type
;
741 CFBooleanRef match_builtin
;
742 CFMutableArrayRef matches
;
743 } matchContext
, *matchContextRef
;
745 static CFDictionaryRef
746 thinInterfaceInfo(CFDictionaryRef info
)
751 if (CFDictionaryGetValueIfPresent(info
, CFSTR(kUSBVendorID
), (const void **)&num
)
753 && CFNumberGetValue(num
, kCFNumberIntType
, &vid
)
754 && (vid
== kIOUSBVendorIDAppleComputer
)) {
755 CFMutableDictionaryRef thin
;
757 // if this is an Apple USB device than we trust that
758 // the non-localized name will be correct.
759 thin
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
760 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductString
));
761 CFDictionaryRemoveValue(thin
, CFSTR(kUSBVendorID
));
762 CFDictionaryRemoveValue(thin
, CFSTR(kUSBProductID
));
766 return CFRetain(info
);
770 matchInterfaceInfo(CFDictionaryRef known_info
, CFDictionaryRef match_info
)
774 match
= _SC_CFEqual(known_info
, match_info
);
776 isA_CFDictionary(known_info
) &&
777 isA_CFDictionary(match_info
)) {
779 // if not an exact match, try thinning
780 known_info
= thinInterfaceInfo(known_info
);
781 match_info
= thinInterfaceInfo(match_info
);
782 match
= _SC_CFEqual(known_info
, match_info
);
783 CFRelease(known_info
);
784 CFRelease(match_info
);
791 matchKnown(const void *value
, void *context
)
793 CFDictionaryRef known_dict
= (CFDictionaryRef
)value
;
794 matchContextRef match_context
= (matchContextRef
)context
;
796 // match interface type
798 CFStringRef known_type
;
800 known_type
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceType
));
801 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
806 // match SCNetworkInterfaceInfo
808 CFDictionaryRef known_info
;
810 known_info
= CFDictionaryGetValue(known_dict
, CFSTR(kSCNetworkInterfaceInfo
));
811 if (!matchInterfaceInfo(known_info
, match_context
->match_info
)) {
816 // if requested, match [non-]builtin
817 if (match_context
->match_builtin
!= NULL
) {
818 CFBooleanRef known_builtin
;
820 known_builtin
= CFDictionaryGetValue(known_dict
, CFSTR(kIOBuiltin
));
821 if (!isA_CFBoolean(known_builtin
)) {
822 known_builtin
= kCFBooleanFalse
;
824 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
829 // if we have a match
830 if (match_context
->matches
== NULL
) {
831 match_context
->matches
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
833 CFArrayAppendValue(match_context
->matches
, known_dict
);
839 matchUnnamed(const void *value
, void *context
)
841 SCNetworkInterfaceRef known_if
= (SCNetworkInterfaceRef
)value
;
842 matchContextRef match_context
= (matchContextRef
)context
;
844 if (match_context
->matches
== NULL
) {
848 // match interface type
850 CFStringRef known_type
;
852 known_type
= SCNetworkInterfaceGetInterfaceType(known_if
);
853 if (!_SC_CFEqual(known_type
, match_context
->match_type
)) {
858 // match SCNetworkInterfaceInfo
860 CFDictionaryRef known_info
;
863 known_info
= _SCNetworkInterfaceCopyInterfaceInfo(known_if
);
864 match
= matchInterfaceInfo(known_info
, match_context
->match_info
);
865 if (known_info
!= NULL
) CFRelease(known_info
);
871 // if requested, match [non-]builtin
872 if (match_context
->match_builtin
!= NULL
) {
873 CFBooleanRef known_builtin
;
875 known_builtin
= _SCNetworkInterfaceIsBuiltin(known_if
) ? kCFBooleanTrue
877 if (!_SC_CFEqual(known_builtin
, match_context
->match_builtin
)) {
882 // if we have a match
883 CFRelease(match_context
->matches
);
884 match_context
->matches
= NULL
;
890 * lookupMatchingInterface
892 * Looks at the interfaces that have already been [or need to be] named with
893 * the goal of allowing a system using a single network interface/adaptor of
894 * a given type (vendor, model, ...) to not care about the specific adaptor
895 * that is used (i.e. swapping dongle's is OK). Once a system has had more
896 * than one interface/adaptor connected at the same time than we assume that
897 * the network configuration is being setup for multi-homing that should be
900 * If no matches are found or if more than one match is found, return NULL.
901 * If a single match is found, return the match.
903 static CFDictionaryRef
904 lookupMatchingInterface(SCNetworkInterfaceRef interface
,
905 CFArrayRef db_list
, // already named
906 CFArrayRef if_list
, // to be named
907 CFIndex if_list_index
,
908 CFBooleanRef builtin
)
911 CFDictionaryRef match
= NULL
;
912 matchContext match_context
;
914 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
915 if (if_type
== NULL
) {
919 match_context
.match_type
= if_type
;
920 match_context
.match_info
= _SCNetworkInterfaceCopyInterfaceInfo(interface
);
921 match_context
.match_builtin
= builtin
;
922 match_context
.matches
= NULL
;
924 // check for matches to already named interfaces
925 // ... and appends each match that we find to match_context.matches
926 if (db_list
!= NULL
) {
927 CFArrayApplyFunction(db_list
,
928 CFRangeMake(0, CFArrayGetCount(db_list
)),
933 // check for matches to to be named interfaces
934 // ... and CFReleases match_context.matches if we find another network
935 // interface of the same type that also needs to be named
936 if (if_list
!= NULL
) {
937 CFIndex if_list_count
;
939 if_list_count
= CFArrayGetCount(if_list
);
940 if (if_list_index
< if_list_count
) {
941 CFArrayApplyFunction(if_list
,
942 CFRangeMake(if_list_index
, if_list_count
- if_list_index
),
948 // check if we have a single match
949 if (match_context
.matches
!= NULL
) {
950 if (CFArrayGetCount(match_context
.matches
) == 1) {
951 match
= CFArrayGetValueAtIndex(match_context
.matches
, 0);
953 CFRelease(match_context
.matches
);
957 Boolean active
= TRUE
;
960 name
= CFDictionaryGetValue(match
, CFSTR(kIOBSDNameKey
));
961 if (isA_CFString(name
)) {
964 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
968 (void)_SC_cfstring_to_cstring(name
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
);
969 if (ioctl(sock
, SIOCGIFFLAGS
, &ifr
) == -1) {
970 // if interface name not currently in-use
982 if (match_context
.match_info
!= NULL
) CFRelease(match_context
.match_info
);
987 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
)
990 CFDictionaryRef if_dict
;
994 CFIndex n
= CFArrayGetCount(db_list
);
995 CFComparisonResult res
;
997 if_name
= SCNetworkInterfaceGetBSDName(interface
);
998 if (if_name
!= NULL
) {
999 addTimestamp(S_state
, if_name
);
1002 if_dict
= createInterfaceDict(interface
);
1003 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1004 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1005 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
1010 for (i
= 0; i
< n
; i
++) {
1011 CFNumberRef db_type
;
1012 CFNumberRef db_unit
;
1013 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
1015 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1016 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1017 res
= CFNumberCompare(if_type
, db_type
, NULL
);
1018 if (res
== kCFCompareLessThan
1019 || (res
== kCFCompareEqualTo
1020 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
1021 == kCFCompareLessThan
))) {
1022 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
1028 CFArrayAppendValue(S_dblist
, if_dict
);
1034 replaceInterface(SCNetworkInterfaceRef interface
)
1039 if (S_dblist
== NULL
) {
1040 S_dblist
= CFArrayCreateMutable(NULL
, 0,
1041 &kCFTypeArrayCallBacks
);
1043 // remove any dict that has our type/addr
1044 while (lookupInterfaceByAddress(S_dblist
, interface
, &where
) != NULL
) {
1045 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1048 // remove any dict that has the same type/unit
1049 while (lookupInterfaceByUnit(S_dblist
, interface
, &where
) != NULL
) {
1050 CFArrayRemoveValueAtIndex(S_dblist
, where
);
1053 insertInterface(S_dblist
, interface
);
1058 issue
= CFStringCreateWithFormat(NULL
, NULL
,
1059 CFSTR("n = %d, %@"),
1062 reportIssue("Multiple interfaces updated", issue
);
1070 getHighestUnitForType(CFNumberRef if_type
)
1074 CFNumberRef ret_unit
= NULL
;
1076 if (S_dblist
== NULL
) {
1080 n
= CFArrayGetCount(S_dblist
);
1081 for (i
= 0; i
< n
; i
++) {
1082 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1085 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
1086 if (CFEqual(type
, if_type
)) {
1089 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
1090 if (ret_unit
== NULL
1091 || (CFNumberCompare(unit
, ret_unit
, NULL
)
1092 == kCFCompareGreaterThan
)) {
1102 * Function: registerInterface
1104 * Register a single interface with the given service path to the
1105 * data link layer (BSD), using the specified unit number.
1107 static kern_return_t
1108 registerInterface(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(kIONetworkStackUserCommand
), num
);
1123 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
1124 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
1125 kr
= IOConnectSetCFProperties(connect
, dict
);
1130 static SCNetworkInterfaceRef
1131 lookupIOKitPath(CFStringRef if_path
)
1133 io_registry_entry_t entry
= MACH_PORT_NULL
;
1134 SCNetworkInterfaceRef interface
= NULL
;
1136 mach_port_t masterPort
= MACH_PORT_NULL
;
1139 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1140 if (kr
!= KERN_SUCCESS
) {
1141 SCLog(TRUE
, LOG_ERR
,
1142 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x"),
1146 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
1147 entry
= IORegistryEntryFromPath(masterPort
, path
);
1148 if (entry
== MACH_PORT_NULL
) {
1149 SCLog(TRUE
, LOG_ERR
,
1150 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryFromPath(%@) failed"),
1155 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
1158 if (masterPort
!= MACH_PORT_NULL
) {
1159 mach_port_deallocate(mach_task_self(), masterPort
);
1161 if (entry
!= MACH_PORT_NULL
) {
1162 IOObjectRelease(entry
);
1169 displayInterface(SCNetworkInterfaceRef interface
)
1176 name
= SCNetworkInterfaceGetBSDName(interface
);
1177 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1178 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1179 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
1181 SCLog(TRUE
, LOG_INFO
,
1182 CFSTR(MY_PLUGIN_NAME
": %s%@%sType: %@, %s%@%sMAC address: %@"),
1183 (name
!= NULL
) ? "BSD Name: " : "",
1184 (name
!= NULL
) ? name
: CFSTR(""),
1185 (name
!= NULL
) ? ", " : "",
1187 (unit
!= NULL
) ? "Unit: " : "",
1188 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
1189 (unit
!= NULL
) ? ", " : "",
1194 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
1199 for (i
= 0; i
< last
; i
++) {
1200 SCNetworkInterfaceRef builtin_if
;
1201 CFNumberRef builtin_type
;
1203 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
1204 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
1205 if (CFEqual(if_type
, builtin_type
)) {
1206 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
1207 n
++; // if built-in interface
1215 static __inline__ boolean_t
1218 return (S_quiet
== MACH_PORT_NULL
);
1222 nameInterfaces(CFMutableArrayRef if_list
)
1225 CFIndex n
= CFArrayGetCount(if_list
);
1227 for (i
= 0; i
< n
; i
++) {
1228 SCNetworkInterfaceRef interface
;
1235 interface
= CFArrayGetValueAtIndex(if_list
, i
);
1236 path
= _SCNetworkInterfaceGetIOPath(interface
);
1237 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
1238 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
1242 CFStringRef if_name
;
1244 if_name
= SCNetworkInterfaceGetBSDName(interface
);
1245 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
1246 SCLog(TRUE
, LOG_INFO
,
1247 CFSTR(MY_PLUGIN_NAME
": Interface already has a unit number"));
1248 displayInterface(interface
);
1252 // update the list of interfaces that were previously named
1253 if ((S_prev_active_list
!= NULL
)
1254 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
1255 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1258 CFDictionaryRef dbdict
;
1259 boolean_t is_builtin
;
1262 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
1263 if (dbdict
!= NULL
) {
1264 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1267 SCLog(S_debug
, LOG_INFO
,
1268 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (from database)"),
1272 if ((dbdict
== NULL
) && !isQuiet()) {
1273 // if new interface, wait until quiet before naming
1274 addTimestamp(S_state
, path
);
1278 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
1280 if (dbdict
== NULL
) {
1281 dbdict
= lookupMatchingInterface(interface
,
1285 is_builtin
? kCFBooleanTrue
: kCFBooleanFalse
);
1286 if (dbdict
!= NULL
) {
1287 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
1290 SCLog(S_debug
, LOG_INFO
,
1291 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (updating database)"),
1296 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
1297 // update the list of interfaces that were previously named
1298 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
1299 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
1301 if (where
!= kCFNotFound
) {
1302 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1306 if (dbdict
== NULL
) {
1310 // built-in interface, use the reserved slots
1311 next_unit
= builtinCount(if_list
, i
, type
);
1313 // not built-in, skip over the reserved slots
1314 next_unit
= builtinCount(if_list
, n
, type
);
1316 unit
= getHighestUnitForType(type
);
1320 CFNumberGetValue(unit
, kCFNumberIntType
, &high_unit
);
1321 if (high_unit
>= next_unit
) {
1322 next_unit
= high_unit
+ 1;
1326 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1328 SCLog(S_debug
, LOG_INFO
,
1329 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (%s)"),
1331 is_builtin
? "built-in" : "next available");
1334 kr
= registerInterface(S_connect
,
1337 (dbdict
== NULL
) ? kRegisterInterface
: kRegisterInterfaceWithFixedUnit
);
1338 if (kr
!= KERN_SUCCESS
) {
1340 const char *signature
;
1342 signature
= (dbdict
== NULL
) ? "failed to name new interface"
1343 : "failed to name known interface";
1345 SCLog(TRUE
, LOG_ERR
,
1346 CFSTR(MY_PLUGIN_NAME
": %s, kr=0x%x\n"
1347 MY_PLUGIN_NAME
": path = %@\n"
1348 MY_PLUGIN_NAME
": unit = %@"),
1355 displayInterface(interface
);
1358 // report issue w/MessageTracer
1359 issue
= CFStringCreateWithFormat(NULL
, NULL
,
1360 CFSTR("kr=0x%x, path=%@, unit=%@"),
1364 reportIssue(signature
, issue
);
1367 ok
= FALSE
; // ... and don't update the database
1369 SCNetworkInterfaceRef new_interface
;
1371 new_interface
= lookupIOKitPath(path
);
1372 if (new_interface
!= NULL
) {
1373 CFNumberRef new_unit
;
1375 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
1376 if (CFEqual(unit
, new_unit
) == FALSE
) {
1377 SCLog(S_debug
, LOG_INFO
,
1378 CFSTR(MY_PLUGIN_NAME
1379 ": interface type %@ assigned "
1380 "unit %@ instead of %@"),
1381 type
, new_unit
, unit
);
1384 displayInterface(new_interface
);
1387 // update if_list (with the interface name & unit)
1388 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
1389 CFRelease(new_interface
);
1390 interface
= new_interface
; // if_list holds the reference
1392 if (is_builtin
&& (S_prev_active_list
!= NULL
)) {
1395 // update the list of [built-in] interfaces that were previously named
1396 if (lookupInterfaceByUnit(S_prev_active_list
, interface
, &where
) != NULL
) {
1397 SCLog(S_debug
, LOG_INFO
,
1398 CFSTR(MY_PLUGIN_NAME
": and updated database (new address)"));
1399 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
1410 replaceInterface(interface
);
1419 if (S_connect
== MACH_PORT_NULL
) {
1420 // if we don't have the "IONetworkStack" connect object
1424 if (S_iflist
!= NULL
) {
1427 n
= CFArrayGetCount(S_iflist
);
1429 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
1431 nameInterfaces(S_iflist
);
1436 * The registry [matching] has quiesced so let's
1437 * - save the DB with the interfaces that have been named
1438 * - update the VLAN/BOND configuration
1439 * - tell everyone that we've finished (at least for now)
1440 * - log those interfaces which are no longer present
1441 * in the HW config (or have yet to show up).
1443 writeInterfaceList(S_dblist
);
1444 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
1447 if (S_iflist
!= NULL
) {
1448 CFRelease(S_iflist
);
1452 if (S_prev_active_list
!= NULL
) {
1457 n
= CFArrayGetCount(S_prev_active_list
);
1459 SCLog(TRUE
, LOG_INFO
,
1460 CFSTR(MY_PLUGIN_NAME
": Interface%s not [yet] active"),
1461 (n
> 1) ? "s" : "");
1463 for (i
= 0; i
< n
; i
++) {
1464 CFDictionaryRef if_dict
;
1469 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
1470 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
1471 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
1472 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
1473 SCLog(TRUE
, LOG_INFO
,
1474 CFSTR(MY_PLUGIN_NAME
": %s%@%sType: %@, Unit: %@"),
1475 (name
!= NULL
) ? "BSD Name: " : "",
1476 (name
!= NULL
) ? name
: CFSTR(""),
1477 (name
!= NULL
) ? ", " : "",
1482 CFRelease(S_prev_active_list
);
1483 S_prev_active_list
= NULL
;
1486 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
1488 * if we've named all of the interfaces that
1489 * were used during the previous boot.
1491 addTimestamp(S_state
, CFSTR("*RELEASE*"));
1492 SCLog(S_debug
, LOG_INFO
,
1493 CFSTR(MY_PLUGIN_NAME
": last boot interfaces have been named"));
1495 CFRelease(S_prev_active_list
);
1496 S_prev_active_list
= NULL
;
1503 static CFComparisonResult
1504 compareMacAddress(const void *val1
, const void *val2
, void *context
)
1506 CFDataRef mac1
= (CFDataRef
)val1
;
1507 CFDataRef mac2
= (CFDataRef
)val2
;
1510 CFComparisonResult res
;
1512 n1
= CFDataGetLength(mac1
);
1513 n2
= CFDataGetLength(mac2
);
1515 res
= kCFCompareLessThan
;
1516 } else if (n2
> n1
) {
1517 res
= kCFCompareGreaterThan
;
1519 res
= bcmp(CFDataGetBytePtr(mac1
), CFDataGetBytePtr(mac2
), n1
);
1525 #ifndef kIOPlatformUUIDKey
1526 #define kIOPlatformUUIDKey "IOPlatformUUID"
1529 updatePlatformUUID()
1532 CFMutableArrayRef addrs
= NULL
;
1536 io_registry_entry_t platform
;
1538 platform
= IORegistryEntryFromPath(kIOMasterPortDefault
, kIODeviceTreePlane
":/");
1539 if (platform
== MACH_PORT_NULL
) {
1543 guid
= IORegistryEntryCreateCFProperty(platform
, CFSTR(kIOPlatformUUIDKey
), NULL
, 0);
1545 // if GUID already defined
1549 addrs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1550 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1551 for (i
= 0; i
< n
; i
++) {
1552 CFBooleanRef builtin
;
1553 CFDictionaryRef dict
;
1556 dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1557 type
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceType
));
1558 if (!isA_CFString(type
) || !CFEqual(type
, kSCNetworkInterfaceTypeEthernet
)) {
1561 builtin
= CFDictionaryGetValue(dict
, CFSTR(kIOBuiltin
));
1562 if (!isA_CFBoolean(builtin
) || !CFBooleanGetValue(builtin
)) {
1565 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
1566 if (!isA_CFData(addr
) || (CFDataGetLength(addr
) != ETHER_ADDR_LEN
)) {
1569 CFArrayAppendValue(addrs
, addr
);
1572 if (CFArrayGetCount(addrs
) == 0) {
1573 // if no ethernet interfaces, look for wireless
1574 for (i
= 0; i
< n
; i
++) {
1575 CFDictionaryRef dict
;
1578 dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1579 type
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceType
));
1580 if (!isA_CFString(type
) || !CFEqual(type
, kSCNetworkInterfaceTypeIEEE80211
)) {
1583 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
1584 if (!isA_CFData(addr
) || (CFDataGetLength(addr
) != ETHER_ADDR_LEN
)) {
1587 CFArrayAppendValue(addrs
, addr
);
1591 n
= CFArrayGetCount(addrs
);
1594 SCLog(TRUE
, LOG_ERR
,
1595 CFSTR(MY_PLUGIN_NAME
": no network interfaces, could not update platform UUID"));
1598 // sort by MAC address
1599 CFArraySortValues(addrs
, CFRangeMake(0, n
), compareMacAddress
, NULL
);
1603 CFUUIDBytes bytes
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1604 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1609 addr
= CFArrayGetValueAtIndex(addrs
, 0);
1610 bcopy(CFDataGetBytePtr(addr
),
1611 (void *)&bytes
+ sizeof(bytes
) - ETHER_ADDR_LEN
,
1613 uuid
= CFUUIDCreateFromUUIDBytes(NULL
, bytes
);
1614 guid
= CFUUIDCreateString(NULL
, uuid
);
1617 SCLog(TRUE
, LOG_INFO
,
1618 CFSTR(MY_PLUGIN_NAME
": setting platform UUID = %@"),
1620 kr
= IORegistryEntrySetCFProperty(platform
, CFSTR(kIOPlatformUUIDKey
), guid
);
1621 if (kr
!= KERN_SUCCESS
) {
1622 SCLog(TRUE
, LOG_ERR
,
1623 CFSTR(MY_PLUGIN_NAME
": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"),
1627 addTimestamp(S_state
, CFSTR("*PLATFORM-UUID*"));
1635 if (addrs
!= NULL
) CFRelease(addrs
);
1636 if (platform
!= MACH_PORT_NULL
) IOObjectRelease(platform
);
1637 if (guid
!= NULL
) CFRelease(guid
);
1642 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
1646 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
1647 SCNetworkInterfaceRef interface
;
1649 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
1650 if (interface
!= NULL
) {
1651 if (S_iflist
== NULL
) {
1652 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1654 CFArrayAppendValue(S_iflist
, interface
);
1655 CFRelease(interface
);
1657 IOObjectRelease(obj
);
1665 * Function: stackCallback
1667 * Get a reference to the single IONetworkStack object instance in
1668 * the kernel. Naming requests must be sent to this object, which is
1669 * attached as a client to all network interface objects in the system.
1671 * Call IOObjectRelease on the returned object.
1674 stackCallback(void *refcon
, io_iterator_t iter
)
1679 stack
= IOIteratorNext(iter
);
1680 if (stack
== MACH_PORT_NULL
) {
1684 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
1685 if (kr
!= KERN_SUCCESS
) {
1686 SCLog(TRUE
, LOG_ERR
,
1687 CFSTR(MY_PLUGIN_NAME
": IOServiceOpen returned 0x%x"),
1692 addTimestamp(S_state
, CFSTR("*STACK*"));
1693 SCLog(S_debug
, LOG_INFO
,
1694 CFSTR(MY_PLUGIN_NAME
": IONetworkStack found"));
1696 if (S_stack
!= MACH_PORT_NULL
) {
1697 IOObjectRelease(S_stack
);
1698 S_stack
= MACH_PORT_NULL
;
1701 if ((S_timer
!= NULL
) && CFRunLoopTimerIsValid(S_timer
)) {
1702 // With the IONetworkStack object now available we can
1703 // reset (shorten?) the time we are willing to wait for
1704 // IOKit to quiesce.
1705 CFRunLoopTimerSetNextFireDate(S_timer
,
1706 CFAbsoluteTimeGetCurrent() + S_quiet_timeout
);
1712 if (stack
!= MACH_PORT_NULL
) {
1713 IOObjectRelease(stack
);
1720 quietCallback(void *refcon
,
1721 io_service_t service
,
1722 natural_t messageType
,
1723 void *messageArgument
)
1725 if (messageArgument
!= NULL
) {
1730 if (messageType
== kIOMessageServiceBusyStateChange
) {
1731 addTimestamp(S_state
, CFSTR("*QUIET*"));
1732 SCLog(S_debug
, LOG_INFO
,
1733 CFSTR(MY_PLUGIN_NAME
": IOKit quiet"));
1736 if (S_connect
== MACH_PORT_NULL
) {
1737 SCLog(TRUE
, LOG_ERR
,
1738 CFSTR(MY_PLUGIN_NAME
": No network stack object"));
1742 if (S_quiet
!= MACH_PORT_NULL
) {
1743 IOObjectRelease(S_quiet
);
1744 S_quiet
= MACH_PORT_NULL
;
1747 if (S_timer
!= NULL
) {
1748 CFRunLoopTimerInvalidate(S_timer
);
1753 // grab (and name) any additional interfaces.
1754 interfaceArrivalCallback((void *)S_notify
, S_iter
);
1756 updatePlatformUUID();
1762 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, CFMutableStringRef snapshot
, int *count
)
1764 kern_return_t kr
= kIOReturnSuccess
;;
1767 while ((kr
== kIOReturnSuccess
) &&
1768 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
1769 uint64_t accumulated_busy_time
;
1770 uint32_t busy_state
;
1773 CFMutableArrayRef newNodes
;
1775 CFMutableStringRef str
= NULL
;
1777 if (nodes
== NULL
) {
1778 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1780 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
1783 kr
= IORegistryEntryGetName(obj
, name
);
1784 if (kr
!= kIOReturnSuccess
) {
1785 SCLog(TRUE
, LOG_ERR
,
1786 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryEntryGetName returned 0x%x"),
1791 str
= CFStringCreateMutable(NULL
, 0);
1792 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
1794 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
1796 case kIOReturnSuccess
:
1797 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
1798 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
1800 case kIOReturnNotFound
:
1803 SCLog(TRUE
, LOG_ERR
,
1804 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryEntryGetLocationInPlane returned 0x%x"),
1810 CFArrayAppendValue(newNodes
, str
);
1813 kr
= IOServiceGetBusyStateAndTime(obj
, &state
, &busy_state
, &accumulated_busy_time
);
1814 if (kr
!= kIOReturnSuccess
) {
1815 SCLog(TRUE
, LOG_ERR
,
1816 CFSTR(MY_PLUGIN_NAME
": captureBusy IOServiceGetBusyStateAndTime returned 0x%x"),
1821 #ifdef TEST_SNAPSHOT
1824 #endif // TEST_SNAPSHOT
1826 if (busy_state
!= 0) {
1829 if ((*count
)++ == 0) {
1830 CFStringAppend(snapshot
, CFSTR("Busy services :"));
1833 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
1834 CFStringAppendFormat(snapshot
, NULL
,
1835 CFSTR("\n %@ [%s%s%s%d, %lld ms]"),
1837 (state
& kIOServiceRegisteredState
) ? "" : "!registered, ",
1838 (state
& kIOServiceMatchedState
) ? "" : "!matched, ",
1839 (state
& kIOServiceInactiveState
) ? "inactive, " : "",
1840 accumulated_busy_time
/ kMillisecondScale
);
1844 kr
= IORegistryIteratorEnterEntry(iterator
);
1845 if (kr
!= kIOReturnSuccess
) {
1846 SCLog(TRUE
, LOG_ERR
,
1847 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryIteratorEnterEntry returned 0x%x"),
1852 iterateRegistryBusy(iterator
, newNodes
, snapshot
, count
);
1854 kr
= IORegistryIteratorExitEntry(iterator
);
1855 if (kr
!= kIOReturnSuccess
) {
1856 SCLog(TRUE
, LOG_ERR
,
1857 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryIteratorExitEntry returned 0x%x"),
1863 CFRelease(newNodes
);
1864 IOObjectRelease(obj
);
1874 io_iterator_t iterator
= MACH_PORT_NULL
;
1876 CFMutableStringRef snapshot
;
1878 snapshot
= CFStringCreateMutable(NULL
, 0);
1880 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
1884 if (kr
!= kIOReturnSuccess
) {
1885 SCLog(TRUE
, LOG_ERR
,
1886 CFSTR(MY_PLUGIN_NAME
": captureBusy IORegistryCreateIterator returned 0x%x"),
1891 iterateRegistryBusy(iterator
, NULL
, snapshot
, &count
);
1893 CFStringAppend(snapshot
, CFSTR("w/no busy services"));
1896 IOObjectRelease(iterator
);
1901 timerCallback(CFRunLoopTimerRef timer
, void *info
)
1903 CFStringRef snapshot
;
1905 // We've been waiting for IOKit to quiesce and it just
1906 // hasn't happenned. Time to just move on!
1907 addTimestamp(S_state
, CFSTR("*TIMEOUT*"));
1910 snapshot
= captureBusy();
1911 SCLog(TRUE
, LOG_ERR
,
1912 CFSTR(MY_PLUGIN_NAME
": timed out waiting for IOKit to quiesce\n%@"),
1914 reportIssue("timed out waiting for IOKit to quiesce", snapshot
);
1915 CFRelease(snapshot
);
1917 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
1922 setup_IOKit(CFBundleRef bundle
)
1926 mach_port_t masterPort
= MACH_PORT_NULL
;
1928 io_object_t root
= MACH_PORT_NULL
;
1930 // read DB of previously named network interfaces
1931 S_dblist
= readInterfaceList();
1932 if (S_dblist
!= NULL
) {
1935 n
= CFArrayGetCount(S_dblist
);
1937 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
1941 // get interfaces that were named during the last boot
1942 S_prev_active_list
= previouslyActiveInterfaces();
1944 // track how long we've waited to see each interface.
1945 S_state
= CFDictionaryCreateMutable(NULL
,
1947 &kCFTypeDictionaryKeyCallBacks
,
1948 &kCFTypeDictionaryValueCallBacks
);
1949 addTimestamp(S_state
, CFSTR("*START*"));
1951 // Creates and returns a notification object for receiving IOKit
1952 // notifications of new devices or state changes.
1953 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1954 if (kr
!= KERN_SUCCESS
) {
1955 SCLog(TRUE
, LOG_ERR
,
1956 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x"),
1961 S_notify
= IONotificationPortCreate(masterPort
);
1962 if (S_notify
== NULL
) {
1963 SCLog(TRUE
, LOG_ERR
,
1964 CFSTR(MY_PLUGIN_NAME
": IONotificationPortCreate failed"));
1968 // watch IOKit matching activity
1969 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
1970 if (root
== MACH_PORT_NULL
) {
1971 SCLog(TRUE
, LOG_ERR
,
1972 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryFromPath failed"));
1976 kr
= IOServiceAddInterestNotification(S_notify
,
1980 (void *)S_notify
, // refCon
1981 &S_quiet
); // notification
1982 if (kr
!= KERN_SUCCESS
) {
1983 SCLog(TRUE
, LOG_ERR
,
1984 CFSTR(MY_PLUGIN_NAME
": IOServiceAddInterestNotification returned 0x%x"),
1989 kr
= IOServiceGetBusyState(root
, &busy
);
1990 if (kr
!= KERN_SUCCESS
) {
1991 SCLog(TRUE
, LOG_ERR
,
1992 CFSTR(MY_PLUGIN_NAME
": IOServiceGetBusyState returned 0x%x"),
1997 // add a timer so we don't wait forever for IOKit to quiesce
1998 S_timer
= CFRunLoopTimerCreate(NULL
,
1999 CFAbsoluteTimeGetCurrent() + S_stack_timeout
,
2005 if (S_timer
== NULL
) {
2006 SCLog(TRUE
, LOG_ERR
,
2007 CFSTR(MY_PLUGIN_NAME
": CFRunLoopTimerCreate failed"));
2011 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
2013 // watch for the introduction of the IONetworkStack
2014 kr
= IOServiceAddMatchingNotification(S_notify
,
2015 kIOFirstMatchNotification
,
2016 IOServiceMatching("IONetworkStack"),
2018 (void *)S_notify
, // refCon
2019 &S_stack
); // notification
2020 if (kr
!= KERN_SUCCESS
) {
2021 SCLog(TRUE
, LOG_ERR
,
2022 CFSTR(MY_PLUGIN_NAME
": IOServiceAddMatchingNotification returned 0x%x"),
2027 // check and see if the stack is already available and arm the
2028 // notification for its introduction.
2029 stackCallback((void *)S_notify
, S_stack
);
2031 // watch for the introduction of new network interfaces
2032 kr
= IOServiceAddMatchingNotification(S_notify
,
2033 kIOFirstMatchNotification
,
2034 IOServiceMatching("IONetworkInterface"),
2035 &interfaceArrivalCallback
,
2036 (void *)S_notify
, // refCon
2037 &S_iter
); // notification
2038 if (kr
!= KERN_SUCCESS
) {
2039 SCLog(TRUE
, LOG_ERR
,
2040 CFSTR(MY_PLUGIN_NAME
": IOServiceAddMatchingNotification returned 0x%x"),
2045 // Get the current list of matches and arm the notification for
2046 // future interface arrivals.
2047 interfaceArrivalCallback((void *)S_notify
, S_iter
);
2049 // Check if IOKit has already quiesced.
2050 quietCallback((void *)S_notify
,
2052 kIOMessageServiceBusyStateChange
,
2053 (void *)(uintptr_t)busy
);
2055 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2056 IONotificationPortGetRunLoopSource(S_notify
),
2057 kCFRunLoopDefaultMode
);
2059 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
2061 * Start the wheels turning until we've named all of
2062 * the interfaces that were used during the previous
2063 * boot, until IOKit [matching] has quiesced, or
2064 * until we've waited long enough.
2066 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
2067 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2068 IONotificationPortGetRunLoopSource(S_notify
),
2070 while (S_prev_active_list
!= NULL
) {
2073 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
2075 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
2080 if (root
!= MACH_PORT_NULL
) {
2081 IOObjectRelease(root
);
2083 if (masterPort
!= MACH_PORT_NULL
) {
2084 mach_port_deallocate(mach_task_self(), masterPort
);
2091 setup_Virtual(CFBundleRef bundle
)
2093 // open a SCPreferences session
2094 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
);
2095 if (S_prefs
== NULL
) {
2096 SCLog(TRUE
, LOG_ERR
,
2097 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate() failed: %s"),
2098 SCErrorString(SCError()));
2102 // register for change notifications.
2103 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
2104 SCLog(TRUE
, LOG_ERR
,
2105 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetCallBack() failed: %s"),
2106 SCErrorString(SCError()));
2112 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
2113 if (SCError() != kSCStatusNoStoreServer
) {
2114 SCLog(TRUE
, LOG_ERR
,
2115 CFSTR(MY_PLUGIN_NAME
": SCPreferencesScheduleWithRunLoop() failed: %s"),
2116 SCErrorString(SCError()));
2126 exec_InterfaceNamer(void *arg
)
2128 CFBundleRef bundle
= (CFBundleRef
)arg
;
2129 CFDictionaryRef dict
;
2131 #if !TARGET_OS_EMBEDDED
2132 pthread_setname_np(MY_PLUGIN_NAME
" thread");
2133 #endif // !TARGET_OS_EMBEDDED
2135 dict
= CFBundleGetInfoDictionary(bundle
);
2136 if (isA_CFDictionary(dict
)) {
2139 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_STACK_TIMEOUT_KEY
));
2141 if (!isA_CFNumber(num
) ||
2142 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_stack_timeout
) ||
2143 (S_stack_timeout
<= 0.0)) {
2144 SCLog(TRUE
, LOG_ERR
,
2145 CFSTR(MY_PLUGIN_NAME
": " WAIT_STACK_TIMEOUT_KEY
" value error"));
2146 S_stack_timeout
= WAIT_STACK_TIMEOUT_DEFAULT
;
2150 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
2152 if (!isA_CFNumber(num
) ||
2153 !CFNumberGetValue(num
, kCFNumberDoubleType
, &S_quiet_timeout
) ||
2154 (S_quiet_timeout
<= 0.0)) {
2155 SCLog(TRUE
, LOG_ERR
,
2156 CFSTR(MY_PLUGIN_NAME
": " WAIT_QUIET_TIMEOUT_KEY
" value error"));
2157 S_quiet_timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
2162 // setup virtual network interface monitoring
2163 if (!setup_Virtual(bundle
)) {
2167 // setup [IOKit] network interface monitoring
2168 if (!setup_IOKit(bundle
)) {
2175 if (S_connect
!= MACH_PORT_NULL
) {
2176 IOServiceClose(S_connect
);
2177 S_connect
= MACH_PORT_NULL
;
2179 if (S_dblist
!= NULL
) {
2180 CFRelease(S_dblist
);
2183 if (S_iter
!= MACH_PORT_NULL
) {
2184 IOObjectRelease(S_iter
);
2185 S_iter
= MACH_PORT_NULL
;
2187 if (S_notify
!= MACH_PORT_NULL
) {
2188 IONotificationPortDestroy(S_notify
);
2190 if (S_quiet
!= MACH_PORT_NULL
) {
2191 IOObjectRelease(S_quiet
);
2192 S_quiet
= MACH_PORT_NULL
;
2194 if (S_stack
!= MACH_PORT_NULL
) {
2195 IOObjectRelease(S_stack
);
2196 S_stack
= MACH_PORT_NULL
;
2198 if (S_state
!= NULL
) {
2202 if (S_timer
!= NULL
) {
2203 CFRunLoopTimerInvalidate(S_timer
);
2209 #if !TARGET_OS_EMBEDDED
2212 #endif // !TARGET_OS_EMBEDDED
2219 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
2221 if (bundleVerbose
) {
2225 #if !TARGET_OS_EMBEDDED
2227 pthread_attr_t tattr
;
2230 CFRetain(bundle
); // released in exec_InterfaceNamer
2232 pthread_attr_init(&tattr
);
2233 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
2234 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
2235 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
2236 pthread_create(&tid
, &tattr
, exec_InterfaceNamer
, bundle
);
2237 pthread_attr_destroy(&tattr
);
2239 #else // !TARGET_OS_EMBEDDED
2240 (void)exec_InterfaceNamer(bundle
);
2241 #endif // !TARGET_OS_EMBEDDED
2246 //------------------------------------------------------------------------
2250 main(int argc
, char ** argv
)
2253 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2255 load_InterfaceNamer(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);
2263 #ifdef TEST_PLATFORM_UUID
2265 main(int argc
, char ** argv
)
2267 CFArrayRef interfaces
;
2270 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2272 S_dblist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2273 interfaces
= SCNetworkInterfaceCopyAll();
2274 if (interfaces
!= NULL
) {
2278 n
= CFArrayGetCount(interfaces
);
2279 for (i
= 0; i
< n
; i
++) {
2280 CFDictionaryRef dict
;
2281 SCNetworkInterfaceRef interface
;
2283 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
2284 dict
= createInterfaceDict(interface
);
2285 CFArrayAppendValue(S_dblist
, dict
);
2288 CFRelease(interfaces
);
2290 updatePlatformUUID();
2291 CFRelease(S_dblist
);
2295 #endif /* TEST_PLATFORM_UUID */
2297 #ifdef TEST_SNAPSHOT
2299 main(int argc
, char ** argv
)
2301 CFStringRef snapshot
;
2304 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2306 snapshot
= captureBusy();
2307 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), snapshot
);
2308 CFRelease(snapshot
);
2313 #endif /* TEST_SNAPSHOT */