2 * Copyright (c) 2001-2008 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/sockio.h>
63 #include <sys/param.h>
64 #include <mach/mach.h>
65 #include <net/ethernet.h>
66 #include <net/if_types.h>
68 #include <CoreFoundation/CoreFoundation.h>
70 #include <SystemConfiguration/SystemConfiguration.h>
71 #include <SystemConfiguration/SCDPlugin.h>
72 #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
73 #include <SystemConfiguration/SCValidation.h>
75 #include <IOKit/IOKitLib.h>
76 #include <IOKit/IOBSD.h>
77 #include <IOKit/IOMessage.h>
78 #include <IOKit/network/IONetworkController.h>
79 #include <IOKit/network/IONetworkInterface.h>
82 #define kIOBuiltin "IOBuiltin"
85 #define kIONetworkStackUserCommand "IONetworkStackUserCommand"
86 #define kRegisterInterface 1
88 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
89 #define kSCNetworkInterfaceActive "Active"
91 #define MY_PLUGIN_NAME "InterfaceNamer"
92 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
94 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
95 #define WAIT_QUIET_TIMEOUT_DEFAULT 60.0
99 * "IONetworkStack" connect object used to "name" an interface.
101 static io_connect_t S_connect
= MACH_PORT_NULL
;
105 * An array of CFDictionary's representing the interfaces
106 * that have been identified and [need to be] named.
108 static CFMutableArrayRef S_dblist
= NULL
;
112 * A boolean that enables additional logging.
114 static boolean_t S_debug
= FALSE
;
118 * An array of SCNetworkInterface's representing the
119 * interfaces that have been identified.
121 static CFMutableArrayRef S_iflist
= NULL
;
125 * IOServiceAddMatchingNotification object used to watch for
126 * new network interfaces.
128 static io_iterator_t S_iter
= MACH_PORT_NULL
;
132 * notification object for receiving IOKit notifications of
133 * new devices or state changes.
135 static IONotificationPortRef S_notify
= NULL
;
137 /* S_prev_active_list
138 * An array of CFDictionary's representing the previously
141 static CFMutableArrayRef S_prev_active_list
= NULL
;
145 * IOServiceAddInterestNotification object used to watch for
146 * IOKit matching to quiesce.
148 static io_object_t S_quiet
= MACH_PORT_NULL
;
152 * IOServiceAddMatchingNotification object used to watch for
153 * the availability of the "IONetworkStack" object.
155 static io_iterator_t S_stack
= MACH_PORT_NULL
;
159 * A dictionary containing Information about each network
160 * interface. For now, the key is the BSD name and the
161 * value is a CFNumber noting how long (in milliseconds)
162 * it took for the interface to be recognized/named.
164 static CFMutableDictionaryRef S_state
= NULL
;
168 * CFRunLoopTimer tracking how long we are willing to wait
169 * for IOKit matching to quiesce (IOKitWaitQuiet).
171 static CFRunLoopTimerRef S_timer
= NULL
;
173 #if !TARGET_OS_IPHONE
175 * Virtual network interface configuration
176 * S_prefs : SCPreferences to configuration
177 * S_bonds : most recently actived Bond configuration
178 * S_vlans : most recently actived VLAN configuration
180 static SCPreferencesRef S_prefs
= NULL
;
181 static CFArrayRef S_bonds
= NULL
;
182 static CFArrayRef S_vlans
= NULL
;
183 #endif /* !TARGET_OS_IPHONE */
186 addTimestamp(CFMutableDictionaryRef dict
, CFStringRef key
)
191 now
= CFAbsoluteTimeGetCurrent();
192 val
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &now
);
193 CFDictionaryAddValue(dict
, key
, val
);
198 static CFComparisonResult
199 if_unit_compare(const void *val1
, const void *val2
, void *context
)
201 CFComparisonResult res
;
207 type1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
208 CFSTR(kIOInterfaceType
));
209 type2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
210 CFSTR(kIOInterfaceType
));
211 res
= CFNumberCompare(type1
, type2
, NULL
);
212 if (res
!= kCFCompareEqualTo
) {
215 unit1
= CFDictionaryGetValue((CFDictionaryRef
)val1
,
216 CFSTR(kIOInterfaceUnit
));
217 unit2
= CFDictionaryGetValue((CFDictionaryRef
)val2
,
218 CFSTR(kIOInterfaceUnit
));
219 return (CFNumberCompare(unit1
, unit2
, NULL
));
223 read_file(char * filename
, size_t * data_length
)
231 if (stat(filename
, &sb
) == -1)
241 fd
= open(filename
, O_RDONLY
);
245 if (read(fd
, data
, len
) != len
) {
247 CFSTR(MY_PLUGIN_NAME
": read %s failed, %s"),
248 filename
, strerror(errno
));
261 static CFPropertyListRef
262 readPropertyList(char * filename
)
266 CFDataRef data
= NULL
;
267 CFPropertyListRef plist
= NULL
;
268 CFStringRef errorString
= NULL
;
270 buf
= read_file(filename
, &bufsize
);
274 data
= CFDataCreate(NULL
, buf
, bufsize
);
279 plist
= CFPropertyListCreateFromXMLData(NULL
, data
,
280 kCFPropertyListMutableContainers
,
283 if (errorString
!= NULL
) {
285 CFSTR(MY_PLUGIN_NAME
": %@"),
287 CFRelease(errorString
);
298 #define INTERFACES CFSTR("Interfaces")
299 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
300 #define OLD_NETWORK_INTERFACES_FILE "/var/db/NetworkInterfaces.xml"
303 writeInterfaceList(CFArrayRef if_list
)
306 SCPreferencesRef prefs
;
308 if (isA_CFArray(if_list
) == NULL
) {
312 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
315 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate failed, %s"),
316 SCErrorString(SCError()));
320 cur_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
321 if (_SC_CFEqual(cur_list
, if_list
)) {
325 if (!SCPreferencesSetValue(prefs
, INTERFACES
, if_list
)) {
327 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetValue failed, %s"),
328 SCErrorString(SCError()));
332 if (!SCPreferencesCommitChanges(prefs
)) {
333 SCLog((SCError() != EROFS
), LOG_ERR
,
334 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCommitChanges failed, %s"),
335 SCErrorString(SCError()));
345 static CFMutableArrayRef
349 CFMutableArrayRef plist
= NULL
;
350 SCPreferencesRef prefs
= NULL
;
352 prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, NETWORK_INTERFACES_PREFS
);
355 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate failed, %s"),
356 SCErrorString(SCError()));
360 if_list
= SCPreferencesGetValue(prefs
, INTERFACES
);
361 if (!isA_CFArray(if_list
)) {
362 if_list
= (CFArrayRef
)readPropertyList(OLD_NETWORK_INTERFACES_FILE
);
363 if (if_list
== NULL
) {
366 if (!isA_CFArray(if_list
)) {
371 writeInterfaceList(if_list
);
372 (void)unlink(OLD_NETWORK_INTERFACES_FILE
);
376 if (if_list
!= NULL
) {
378 CFIndex n
= CFArrayGetCount(if_list
);
380 plist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
381 for (i
= 0; i
< n
; i
++) {
382 CFDictionaryRef dict
;
384 dict
= CFArrayGetValueAtIndex(if_list
, i
);
385 if (isA_CFDictionary(dict
) &&
386 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceType
)) &&
387 CFDictionaryContainsKey(dict
, CFSTR(kIOInterfaceUnit
)) &&
388 CFDictionaryContainsKey(dict
, CFSTR(kIOMACAddress
))) {
389 CFArrayAppendValue(plist
, dict
);
399 static CFMutableArrayRef
400 previouslyActiveInterfaces()
402 CFMutableArrayRef active
;
406 if (S_dblist
== NULL
) {
410 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
412 n
= CFArrayGetCount(S_dblist
);
413 for (i
= 0; i
< n
; i
++) {
414 CFDictionaryRef if_dict
;
416 if_dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
417 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
418 CFMutableDictionaryRef new_dict
;
420 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, if_dict
);
421 CFDictionaryRemoveValue(new_dict
, CFSTR(kSCNetworkInterfaceActive
));
422 CFArraySetValueAtIndex(S_dblist
, i
, new_dict
);
423 CFArrayAppendValue(active
, new_dict
);
435 SCDynamicStoreRef store
;
437 store
= SCDynamicStoreCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
, NULL
);
442 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@" MY_PLUGIN_NAME
),
443 kSCDynamicStoreDomainPlugin
);
444 (void)SCDynamicStoreSetValue(store
, key
, S_state
);
451 #if !TARGET_OS_IPHONE
453 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs
,
454 SCPreferencesNotification notificationType
,
457 CFArrayRef interfaces
;
459 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
464 // if a new interface has been "named"
466 if (S_bonds
!= NULL
) {
470 if (S_vlans
!= NULL
) {
476 // update Bond configuration
478 interfaces
= SCBondInterfaceCopyAll(prefs
);
479 if ((S_bonds
== NULL
) && (interfaces
== NULL
)) {
483 if ((S_bonds
!= NULL
) && (interfaces
!= NULL
) && CFEqual(S_bonds
, interfaces
)) {
485 CFRelease(interfaces
);
488 if (S_bonds
!= NULL
) CFRelease(S_bonds
);
489 S_bonds
= interfaces
;
491 if (!_SCBondInterfaceUpdateConfiguration(prefs
)) {
493 CFSTR(MY_PLUGIN_NAME
": _SCBondInterfaceUpdateConfiguration failed, %s"),
494 SCErrorString(SCError()));
499 // update VLAN configuration
501 interfaces
= SCVLANInterfaceCopyAll(prefs
);
502 if ((S_vlans
== NULL
) && (interfaces
== NULL
)) {
506 if ((S_vlans
!= NULL
) && (interfaces
!= NULL
) && CFEqual(S_vlans
, interfaces
)) {
508 CFRelease(interfaces
);
511 if (S_vlans
!= NULL
) CFRelease(S_vlans
);
512 S_vlans
= interfaces
;
514 if (!_SCVLANInterfaceUpdateConfiguration(prefs
)) {
516 CFSTR(MY_PLUGIN_NAME
": _SCVLANInterfaceUpdateConfiguration failed, %s"),
517 SCErrorString(SCError()));
522 // we are finished with current prefs, wait for changes
524 SCPreferencesSynchronize(prefs
);
527 #endif /* !TARGET_OS_IPHONE */
529 static CFDictionaryRef
530 createInterfaceDict(SCNetworkInterfaceRef interface
)
532 CFMutableDictionaryRef new_if
;
535 new_if
= CFDictionaryCreateMutable(NULL
,
537 &kCFTypeDictionaryKeyCallBacks
,
538 &kCFTypeDictionaryValueCallBacks
);
540 val
= _SCNetworkInterfaceGetIOPath(interface
);
542 CFDictionarySetValue(new_if
, CFSTR(kIOPathMatchKey
), val
);
545 val
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
547 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceType
), val
);
550 val
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
552 CFDictionarySetValue(new_if
, CFSTR(kIOInterfaceUnit
), val
);
555 val
= _SCNetworkInterfaceGetHardwareAddress(interface
);
557 CFDictionarySetValue(new_if
, CFSTR(kIOMACAddress
), val
);
560 val
= SCNetworkInterfaceGetBSDName(interface
);
562 CFDictionarySetValue(new_if
, CFSTR(kIOBSDNameKey
), val
);
565 val
= SCNetworkInterfaceGetInterfaceType(interface
);
567 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceType
), val
);
570 CFDictionarySetValue(new_if
,
572 _SCNetworkInterfaceIsBuiltin(interface
) ? kCFBooleanTrue
: kCFBooleanFalse
);
574 CFDictionarySetValue(new_if
, CFSTR(kSCNetworkInterfaceActive
), kCFBooleanTrue
);
579 static CFDictionaryRef
580 lookupInterfaceByAddress(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
587 if (db_list
== NULL
) {
590 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
591 addr
= _SCNetworkInterfaceGetHardwareAddress(interface
);
592 if (type
== NULL
|| addr
== NULL
) {
596 n
= CFArrayGetCount(db_list
);
597 for (i
= 0; i
< n
; i
++) {
599 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
602 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
603 a
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
604 if (t
== NULL
|| a
== NULL
)
607 if (CFEqual(type
, t
) && CFEqual(addr
, a
)) {
617 static CFDictionaryRef
618 lookupInterfaceByUnit(CFArrayRef db_list
, SCNetworkInterfaceRef interface
, CFIndex
* where
)
625 if (db_list
== NULL
) {
628 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
629 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
630 if (type
== NULL
|| unit
== NULL
) {
634 n
= CFArrayGetCount(db_list
);
635 for (i
= 0; i
< n
; i
++) {
636 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
640 t
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
641 u
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
642 if (t
== NULL
|| u
== NULL
) {
646 if (CFEqual(type
, t
) && CFEqual(unit
, u
)) {
655 static CFDictionaryRef
656 lookupAirPortInterface(CFArrayRef db_list
, CFIndex
* where
)
661 if (db_list
== NULL
) {
664 n
= CFArrayGetCount(db_list
);
665 for (i
= 0; i
< n
; i
++) {
666 CFDictionaryRef dict
;
669 dict
= CFArrayGetValueAtIndex(db_list
, i
);
670 if_type
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceType
));
671 if (if_type
!= NULL
) {
672 if (CFEqual(if_type
, kSCNetworkInterfaceTypeIEEE80211
)) {
680 path
= CFDictionaryGetValue(dict
, CFSTR(kIOPathMatchKey
));
681 if ((CFStringFind(path
, CFSTR("IO80211Interface") , 0).location
!= kCFNotFound
) ||
682 (CFStringFind(path
, CFSTR("AirPort") , 0).location
!= kCFNotFound
) ||
683 (CFStringFind(path
, CFSTR("AppleWireless80211"), 0).location
!= kCFNotFound
)) {
694 insertInterface(CFMutableArrayRef db_list
, SCNetworkInterfaceRef interface
)
697 CFDictionaryRef if_dict
;
701 CFIndex n
= CFArrayGetCount(db_list
);
702 CFComparisonResult res
;
704 if_name
= SCNetworkInterfaceGetBSDName(interface
);
705 if (if_name
!= NULL
) {
706 addTimestamp(S_state
, if_name
);
709 if_dict
= createInterfaceDict(interface
);
710 if_type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
711 if_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
712 if ((if_type
== NULL
) || (if_unit
== NULL
)) {
717 for (i
= 0; i
< n
; i
++) {
720 CFDictionaryRef dict
= CFArrayGetValueAtIndex(db_list
, i
);
722 db_type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
723 db_unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
724 res
= CFNumberCompare(if_type
, db_type
, NULL
);
725 if (res
== kCFCompareLessThan
726 || (res
== kCFCompareEqualTo
727 && (CFNumberCompare(if_unit
, db_unit
, NULL
)
728 == kCFCompareLessThan
))) {
729 CFArrayInsertValueAtIndex(db_list
, i
, if_dict
);
735 CFArrayAppendValue(S_dblist
, if_dict
);
741 replaceInterface(SCNetworkInterfaceRef interface
)
745 if (S_dblist
== NULL
) {
746 S_dblist
= CFArrayCreateMutable(NULL
, 0,
747 &kCFTypeArrayCallBacks
);
749 // remove any dict that has our type/addr
750 if (lookupInterfaceByAddress(S_dblist
, interface
, &where
) != NULL
) {
751 CFArrayRemoveValueAtIndex(S_dblist
, where
);
753 // remove any dict that has the same type/unit
754 if (lookupInterfaceByUnit(S_dblist
, interface
, &where
) != NULL
) {
755 CFArrayRemoveValueAtIndex(S_dblist
, where
);
757 insertInterface(S_dblist
, interface
);
762 getHighestUnitForType(CFNumberRef if_type
)
766 CFNumberRef ret_unit
= NULL
;
768 if (S_dblist
== NULL
) {
772 n
= CFArrayGetCount(S_dblist
);
773 for (i
= 0; i
< n
; i
++) {
774 CFDictionaryRef dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
777 type
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceType
));
778 if (CFEqual(type
, if_type
)) {
781 unit
= CFDictionaryGetValue(dict
, CFSTR(kIOInterfaceUnit
));
783 || (CFNumberCompare(unit
, ret_unit
, NULL
)
784 == kCFCompareGreaterThan
)) {
794 * Function: registerInterface
796 * Register a single interface with the given service path to the
797 * data link layer (BSD), using the specified unit number.
800 registerInterface(io_connect_t connect
,
804 static const int command
= kRegisterInterface
;
805 CFMutableDictionaryRef dict
;
809 dict
= CFDictionaryCreateMutable(NULL
, 0,
810 &kCFTypeDictionaryKeyCallBacks
,
811 &kCFTypeDictionaryValueCallBacks
);
812 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &command
);
813 CFDictionarySetValue(dict
, CFSTR(kIONetworkStackUserCommand
), num
);
815 CFDictionarySetValue(dict
, CFSTR(kIOPathMatchKey
), path
);
816 CFDictionarySetValue(dict
, CFSTR(kIOInterfaceUnit
), unit
);
817 kr
= IOConnectSetCFProperties(connect
, dict
);
822 static SCNetworkInterfaceRef
823 lookupIOKitPath(CFStringRef if_path
)
825 io_registry_entry_t entry
= MACH_PORT_NULL
;
826 SCNetworkInterfaceRef interface
= NULL
;
828 mach_port_t masterPort
= MACH_PORT_NULL
;
831 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
832 if (kr
!= KERN_SUCCESS
) {
834 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x\n"),
838 _SC_cfstring_to_cstring(if_path
, path
, sizeof(path
), kCFStringEncodingASCII
);
839 entry
= IORegistryEntryFromPath(masterPort
, path
);
840 if (entry
== MACH_PORT_NULL
) {
842 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryFromPath(%@) failed"),
847 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry
);
850 if (masterPort
!= MACH_PORT_NULL
) {
851 mach_port_deallocate(mach_task_self(), masterPort
);
853 if (entry
!= MACH_PORT_NULL
) {
854 IOObjectRelease(entry
);
861 displayInterface(SCNetworkInterfaceRef interface
)
868 name
= SCNetworkInterfaceGetBSDName(interface
);
869 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
870 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
871 addr
= SCNetworkInterfaceGetHardwareAddressString(interface
);
873 SCLog(TRUE
, LOG_INFO
,
874 CFSTR(MY_PLUGIN_NAME
": %s%@%sType: %@, %s%@%sMAC address: %@"),
875 (name
!= NULL
) ? "BSD Name: " : "",
876 (name
!= NULL
) ? name
: CFSTR(""),
877 (name
!= NULL
) ? ", " : "",
879 (unit
!= NULL
) ? "Unit: " : "",
880 (unit
!= NULL
) ? (CFTypeRef
)unit
: (CFTypeRef
)CFSTR(""),
881 (unit
!= NULL
) ? ", " : "",
886 builtinCount(CFArrayRef if_list
, CFIndex last
, CFNumberRef if_type
)
891 for (i
= 0; i
< last
; i
++) {
892 SCNetworkInterfaceRef builtin_if
;
893 CFNumberRef builtin_type
;
895 builtin_if
= CFArrayGetValueAtIndex(if_list
, i
);
896 builtin_type
= _SCNetworkInterfaceGetIOInterfaceType(builtin_if
);
897 if (CFEqual(if_type
, builtin_type
)) {
898 if (_SCNetworkInterfaceIsBuiltin(builtin_if
)) {
899 n
++; // if built-in interface
907 static __inline__ boolean_t
910 return (S_quiet
== MACH_PORT_NULL
);
914 nameInterfaces(CFMutableArrayRef if_list
)
917 CFIndex n
= CFArrayGetCount(if_list
);
919 for (i
= 0; i
< n
; i
++) {
920 SCNetworkInterfaceRef interface
;
926 interface
= CFArrayGetValueAtIndex(if_list
, i
);
927 path
= _SCNetworkInterfaceGetIOPath(interface
);
928 type
= _SCNetworkInterfaceGetIOInterfaceType(interface
);
929 unit
= _SCNetworkInterfaceGetIOInterfaceUnit(interface
);
935 if_name
= SCNetworkInterfaceGetBSDName(interface
);
936 if ((if_name
== NULL
) || !CFDictionaryContainsKey(S_state
, if_name
)) {
937 SCLog(TRUE
, LOG_INFO
,
938 CFSTR(MY_PLUGIN_NAME
": Interface already has a unit number"));
939 displayInterface(interface
);
943 // update the list of interfaces that were previously named
944 if ((S_prev_active_list
!= NULL
)
945 && lookupInterfaceByAddress(S_prev_active_list
, interface
, &where
) != NULL
) {
946 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
949 CFDictionaryRef dbdict
;
952 dbdict
= lookupInterfaceByAddress(S_dblist
, interface
, NULL
);
953 if (dbdict
!= NULL
) {
954 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
957 SCLog(S_debug
, LOG_INFO
,
958 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (from database)"),
963 if_type
= SCNetworkInterfaceGetInterfaceType(interface
);
964 if ((if_type
!= NULL
) &&
965 CFEqual(if_type
, kSCNetworkInterfaceTypeIEEE80211
)) {
966 dbdict
= lookupAirPortInterface(S_dblist
, NULL
);
967 if (dbdict
!= NULL
) {
968 unit
= CFDictionaryGetValue(dbdict
, CFSTR(kIOInterfaceUnit
));
971 SCLog(S_debug
, LOG_INFO
,
972 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (updating database)"),
978 if ((dbdict
!= NULL
) && (S_prev_active_list
!= NULL
)) {
979 // update the list of interfaces that were previously named
980 where
= CFArrayGetFirstIndexOfValue(S_prev_active_list
,
981 CFRangeMake(0, CFArrayGetCount(S_prev_active_list
)),
983 if (where
!= kCFNotFound
) {
984 CFArrayRemoveValueAtIndex(S_prev_active_list
, where
);
988 if (dbdict
== NULL
) {
989 boolean_t is_builtin
;
993 // if new interface, wait until quiet before naming
994 addTimestamp(S_state
, path
);
998 is_builtin
= _SCNetworkInterfaceIsBuiltin(interface
);
1001 // built-in interface, use the reserved slots
1002 next_unit
= builtinCount(if_list
, i
, type
);
1004 // not built-in, skip over the reserved slots
1005 next_unit
= builtinCount(if_list
, n
, type
);
1007 unit
= getHighestUnitForType(type
);
1011 CFNumberGetValue(unit
, kCFNumberIntType
, &high_unit
);
1012 if (high_unit
>= next_unit
) {
1013 next_unit
= high_unit
+ 1;
1017 unit
= CFNumberCreate(NULL
, kCFNumberIntType
, &next_unit
);
1019 SCLog(S_debug
, LOG_INFO
,
1020 CFSTR(MY_PLUGIN_NAME
": Interface assigned unit %@ (%s)"),
1022 is_builtin
? "built-in" : "next available");
1025 kr
= registerInterface(S_connect
, path
, unit
);
1026 if (kr
!= KERN_SUCCESS
) {
1027 SCLog(TRUE
, LOG_ERR
,
1028 CFSTR(MY_PLUGIN_NAME
": failed to name the interface, kr=0x%x"),
1031 displayInterface(interface
);
1034 SCNetworkInterfaceRef new_interface
;
1036 new_interface
= lookupIOKitPath(path
);
1037 if (new_interface
!= NULL
) {
1038 CFNumberRef new_unit
;
1040 new_unit
= _SCNetworkInterfaceGetIOInterfaceUnit(new_interface
);
1041 if (CFEqual(unit
, new_unit
) == FALSE
) {
1042 SCLog(S_debug
, LOG_INFO
,
1043 CFSTR(MY_PLUGIN_NAME
1044 ": interface type %@ assigned "
1045 "unit %@ instead of %@"),
1046 type
, new_unit
, unit
);
1049 displayInterface(new_interface
);
1052 // update if_list (with the interface name & unit)
1053 CFArraySetValueAtIndex(if_list
, i
, new_interface
);
1054 CFRelease(new_interface
);
1055 interface
= new_interface
; // if_list holds the reference
1063 replaceInterface(interface
);
1071 if (S_connect
== MACH_PORT_NULL
) {
1072 // if we don't have the "IONetworkStack" connect object
1076 if (S_iflist
!= NULL
) {
1079 n
= CFArrayGetCount(S_iflist
);
1081 CFArraySortValues(S_iflist
, CFRangeMake(0, n
), _SCNetworkInterfaceCompare
, NULL
);
1083 nameInterfaces(S_iflist
);
1088 * The registry [matching] has quiesced so let's
1089 * - save the DB with the interfaces that have been named
1090 * - update the VLAN/BOND configuration
1091 * - tell everyone that we've finished (at least for now)
1092 * - log those interfaces which are no longer present
1093 * in the HW config (or have yet to show up).
1095 writeInterfaceList(S_dblist
);
1096 #if !TARGET_OS_IPHONE
1097 updateVirtualNetworkInterfaceConfiguration(NULL
, kSCPreferencesNotificationApply
, NULL
);
1098 #endif /* !TARGET_OS_IPHONE */
1101 if (S_iflist
!= NULL
) {
1102 CFRelease(S_iflist
);
1106 if (S_prev_active_list
!= NULL
) {
1111 n
= CFArrayGetCount(S_prev_active_list
);
1112 SCLog(TRUE
, LOG_INFO
,
1113 CFSTR(MY_PLUGIN_NAME
": Interface%s not [yet] active"),
1114 (n
> 0) ? "s" : "");
1115 for (i
= 0; i
< n
; i
++) {
1116 CFDictionaryRef if_dict
;
1121 if_dict
= CFArrayGetValueAtIndex(S_prev_active_list
, i
);
1122 name
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
1123 type
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceType
));
1124 unit
= CFDictionaryGetValue(if_dict
, CFSTR(kIOInterfaceUnit
));
1125 SCLog(TRUE
, LOG_INFO
,
1126 CFSTR(MY_PLUGIN_NAME
": %s%@%sType: %@, Unit: %@"),
1127 (name
!= NULL
) ? "BSD Name: " : "",
1128 (name
!= NULL
) ? name
: CFSTR(""),
1129 (name
!= NULL
) ? ", " : "",
1134 CFRelease(S_prev_active_list
);
1135 S_prev_active_list
= NULL
;
1138 if ((S_prev_active_list
!= NULL
) && (CFArrayGetCount(S_prev_active_list
) == 0)) {
1140 * if we've named all of the interfaces that
1141 * were used during the previous boot.
1143 addTimestamp(S_state
, CFSTR("*RELEASE*"));
1144 SCLog(S_debug
, LOG_INFO
,
1145 CFSTR(MY_PLUGIN_NAME
": last boot interfaces have been named"));
1147 CFRelease(S_prev_active_list
);
1148 S_prev_active_list
= NULL
;
1155 static CFComparisonResult
1156 compareMacAddress(const void *val1
, const void *val2
, void *context
)
1158 CFDataRef mac1
= (CFDataRef
)val1
;
1159 CFDataRef mac2
= (CFDataRef
)val2
;
1162 CFComparisonResult res
;
1164 n1
= CFDataGetLength(mac1
);
1165 n2
= CFDataGetLength(mac2
);
1167 res
= kCFCompareLessThan
;
1168 } else if (n2
> n1
) {
1169 res
= kCFCompareGreaterThan
;
1171 res
= bcmp(CFDataGetBytePtr(mac1
), CFDataGetBytePtr(mac2
), n1
);
1177 #ifndef kIOPlatformUUIDKey
1178 #define kIOPlatformUUIDKey "IOPlatformUUID"
1181 updatePlatformUUID()
1184 CFMutableArrayRef addrs
= NULL
;
1188 io_registry_entry_t platform
;
1190 platform
= IORegistryEntryFromPath(kIOMasterPortDefault
, kIODeviceTreePlane
":/");
1191 if (platform
== MACH_PORT_NULL
) {
1195 guid
= IORegistryEntryCreateCFProperty(platform
, CFSTR(kIOPlatformUUIDKey
), NULL
, 0);
1197 // if GUID already defined
1201 addrs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1202 n
= (S_dblist
!= NULL
) ? CFArrayGetCount(S_dblist
) : 0;
1203 for (i
= 0; i
< n
; i
++) {
1204 CFBooleanRef builtin
;
1205 CFDictionaryRef dict
;
1208 dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1209 type
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceType
));
1210 if (!isA_CFString(type
) || !CFEqual(type
, kSCNetworkInterfaceTypeEthernet
)) {
1213 builtin
= CFDictionaryGetValue(dict
, CFSTR(kIOBuiltin
));
1214 if (!isA_CFBoolean(builtin
) || !CFBooleanGetValue(builtin
)) {
1217 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
1218 if (!isA_CFData(addr
) || (CFDataGetLength(addr
) != ETHER_ADDR_LEN
)) {
1221 CFArrayAppendValue(addrs
, addr
);
1224 if (CFArrayGetCount(addrs
) == 0) {
1225 // if no ethernet interfaces, look for wireless
1226 for (i
= 0; i
< n
; i
++) {
1227 CFDictionaryRef dict
;
1230 dict
= CFArrayGetValueAtIndex(S_dblist
, i
);
1231 type
= CFDictionaryGetValue(dict
, CFSTR(kSCNetworkInterfaceType
));
1232 if (!isA_CFString(type
) || !CFEqual(type
, kSCNetworkInterfaceTypeIEEE80211
)) {
1235 addr
= CFDictionaryGetValue(dict
, CFSTR(kIOMACAddress
));
1236 if (!isA_CFData(addr
) || (CFDataGetLength(addr
) != ETHER_ADDR_LEN
)) {
1239 CFArrayAppendValue(addrs
, addr
);
1243 n
= CFArrayGetCount(addrs
);
1246 SCLog(TRUE
, LOG_ERR
,
1247 CFSTR(MY_PLUGIN_NAME
": no network interfaces, could not update platform UUID"));
1250 // sort by MAC address
1251 CFArraySortValues(addrs
, CFRangeMake(0, n
), compareMacAddress
, NULL
);
1255 CFUUIDBytes bytes
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1256 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1261 addr
= CFArrayGetValueAtIndex(addrs
, 0);
1262 bcopy(CFDataGetBytePtr(addr
),
1263 (void *)&bytes
+ sizeof(bytes
) - ETHER_ADDR_LEN
,
1265 uuid
= CFUUIDCreateFromUUIDBytes(NULL
, bytes
);
1266 guid
= CFUUIDCreateString(NULL
, uuid
);
1269 SCLog(TRUE
, LOG_INFO
,
1270 CFSTR(MY_PLUGIN_NAME
": setting platform UUID = %@"),
1272 kr
= IORegistryEntrySetCFProperty(platform
, CFSTR(kIOPlatformUUIDKey
), guid
);
1273 if (kr
!= KERN_SUCCESS
) {
1274 SCLog(TRUE
, LOG_ERR
,
1275 CFSTR(MY_PLUGIN_NAME
": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"),
1279 addTimestamp(S_state
, CFSTR("*PLATFORM-UUID*"));
1287 if (addrs
!= NULL
) CFRelease(addrs
);
1288 if (platform
!= MACH_PORT_NULL
) IOObjectRelease(platform
);
1289 if (guid
!= NULL
) CFRelease(guid
);
1294 interfaceArrivalCallback(void *refcon
, io_iterator_t iter
)
1298 while ((obj
= IOIteratorNext(iter
)) != MACH_PORT_NULL
) {
1299 SCNetworkInterfaceRef interface
;
1301 interface
= _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj
);
1302 if (interface
!= NULL
) {
1303 if (S_iflist
== NULL
) {
1304 S_iflist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1306 CFArrayAppendValue(S_iflist
, interface
);
1307 CFRelease(interface
);
1309 IOObjectRelease(obj
);
1317 * Function: stackCallback
1319 * Get a reference to the single IONetworkStack object instance in
1320 * the kernel. Naming requests must be sent to this object, which is
1321 * attached as a client to all network interface objects in the system.
1323 * Call IOObjectRelease on the returned object.
1326 stackCallback(void *refcon
, io_iterator_t iter
)
1331 stack
= IOIteratorNext(iter
);
1332 if (stack
== MACH_PORT_NULL
) {
1336 kr
= IOServiceOpen(stack
, mach_task_self(), 0, &S_connect
);
1337 if (kr
!= KERN_SUCCESS
) {
1338 SCLog(TRUE
, LOG_ERR
,
1339 CFSTR(MY_PLUGIN_NAME
": IOServiceOpen returned 0x%x"),
1344 addTimestamp(S_state
, CFSTR("*STACK*"));
1345 SCLog(S_debug
, LOG_INFO
,
1346 CFSTR(MY_PLUGIN_NAME
": IONetworkStack found"));
1348 if (S_stack
!= MACH_PORT_NULL
) {
1349 IOObjectRelease(S_stack
);
1350 S_stack
= MACH_PORT_NULL
;
1356 if (stack
!= MACH_PORT_NULL
) {
1357 IOObjectRelease(stack
);
1364 quietCallback(void *refcon
,
1365 io_service_t service
,
1366 natural_t messageType
,
1367 void *messageArgument
)
1369 if (messageArgument
!= NULL
) {
1374 if (messageType
== kIOMessageServiceBusyStateChange
) {
1375 addTimestamp(S_state
, CFSTR("*QUIET*"));
1376 SCLog(S_debug
, LOG_INFO
,
1377 CFSTR(MY_PLUGIN_NAME
": IOKit quiet"));
1380 if (S_connect
== MACH_PORT_NULL
) {
1381 SCLog(TRUE
, LOG_ERR
,
1382 CFSTR(MY_PLUGIN_NAME
": No network stack object"));
1386 if (S_quiet
!= MACH_PORT_NULL
) {
1387 IOObjectRelease(S_quiet
);
1388 S_quiet
= MACH_PORT_NULL
;
1391 if (S_timer
!= NULL
) {
1392 CFRunLoopTimerInvalidate(S_timer
);
1397 // grab (and name) any additional interfaces.
1398 interfaceArrivalCallback((void *)S_notify
, S_iter
);
1400 updatePlatformUUID();
1406 iterateRegistryBusy(io_iterator_t iterator
, CFArrayRef nodes
, int *count
)
1408 kern_return_t kr
= kIOReturnSuccess
;;
1411 while ((kr
== kIOReturnSuccess
) &&
1412 ((obj
= IOIteratorNext(iterator
)) != MACH_PORT_NULL
)) {
1416 CFMutableArrayRef newNodes
;
1417 CFMutableStringRef str
= NULL
;
1419 if (nodes
== NULL
) {
1420 newNodes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1422 newNodes
= CFArrayCreateMutableCopy(NULL
, 0, nodes
);
1425 kr
= IORegistryEntryGetName(obj
, name
);
1426 if (kr
!= kIOReturnSuccess
) {
1427 SCLog(TRUE
, LOG_ERR
,
1428 CFSTR(MY_PLUGIN_NAME
": reportBusy IORegistryEntryGetName returned 0x%x"),
1433 str
= CFStringCreateMutable(NULL
, 0);
1434 CFStringAppendCString(str
, name
, kCFStringEncodingUTF8
);
1436 kr
= IORegistryEntryGetLocationInPlane(obj
, kIOServicePlane
, location
);
1438 case kIOReturnSuccess
:
1439 CFStringAppendCString(str
, "@", kCFStringEncodingUTF8
);
1440 CFStringAppendCString(str
, location
, kCFStringEncodingUTF8
);
1442 case kIOReturnNotFound
:
1445 SCLog(TRUE
, LOG_ERR
,
1446 CFSTR(MY_PLUGIN_NAME
": reportBusy IORegistryEntryGetLocationInPlane returned 0x%x"),
1452 CFArrayAppendValue(newNodes
, str
);
1455 kr
= IOServiceGetBusyState(obj
, &busy
);
1456 if (kr
!= kIOReturnSuccess
) {
1457 SCLog(TRUE
, LOG_ERR
,
1458 CFSTR(MY_PLUGIN_NAME
": reportBusy IOServiceGetBusyState returned 0x%x"),
1466 if ((*count
)++ == 0) {
1467 SCLog(TRUE
, LOG_WARNING
, CFSTR(MY_PLUGIN_NAME
": Busy services :"));
1470 path
= CFStringCreateByCombiningStrings(NULL
, newNodes
, CFSTR("/"));
1471 SCLog(TRUE
, LOG_WARNING
, CFSTR(MY_PLUGIN_NAME
": %@ [%d]"), path
, busy
);
1475 kr
= IORegistryIteratorEnterEntry(iterator
);
1476 if (kr
!= kIOReturnSuccess
) {
1477 SCLog(TRUE
, LOG_ERR
,
1478 CFSTR(MY_PLUGIN_NAME
": reportBusy IORegistryIteratorEnterEntry returned 0x%x"),
1483 iterateRegistryBusy(iterator
, newNodes
, count
);
1485 kr
= IORegistryIteratorExitEntry(iterator
);
1486 if (kr
!= kIOReturnSuccess
) {
1487 SCLog(TRUE
, LOG_ERR
,
1488 CFSTR(MY_PLUGIN_NAME
": reportBusy IORegistryIteratorExitEntry returned 0x%x"),
1494 CFRelease(newNodes
);
1495 IOObjectRelease(obj
);
1505 io_iterator_t iterator
= MACH_PORT_NULL
;
1508 kr
= IORegistryCreateIterator(kIOMasterPortDefault
,
1512 if (kr
!= kIOReturnSuccess
) {
1513 SCLog(TRUE
, LOG_ERR
,
1514 CFSTR(MY_PLUGIN_NAME
": reportBusy IORegistryCreateIterator returned 0x%x"),
1519 iterateRegistryBusy(iterator
, NULL
, &count
);
1520 SCLog((count
== 0), LOG_WARNING
,
1521 CFSTR(MY_PLUGIN_NAME
": w/no busy services"));
1522 IOObjectRelease(iterator
);
1527 timerCallback(CFRunLoopTimerRef timer
, void *info
)
1530 * We've been waiting for IOKit to quiesce and it just
1531 * hasn't happenned. Time to just move on!
1533 addTimestamp(S_state
, CFSTR("*TIMEOUT*"));
1534 SCLog(TRUE
, LOG_ERR
,
1535 CFSTR(MY_PLUGIN_NAME
": timed out waiting for IOKit to quiesce"));
1538 quietCallback((void *)S_notify
, MACH_PORT_NULL
, 0, NULL
);
1543 setup_IOKit(CFBundleRef bundle
)
1546 CFDictionaryRef dict
;
1548 mach_port_t masterPort
= MACH_PORT_NULL
;
1550 io_object_t root
= MACH_PORT_NULL
;
1551 double timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
1553 // read DB of previously named network interfaces
1554 S_dblist
= readInterfaceList();
1555 if (S_dblist
!= NULL
) {
1558 n
= CFArrayGetCount(S_dblist
);
1560 CFArraySortValues(S_dblist
, CFRangeMake(0, n
), if_unit_compare
, NULL
);
1564 // get interfaces that were named during the last boot
1565 S_prev_active_list
= previouslyActiveInterfaces();
1567 // track how long we've waited to see each interface.
1568 S_state
= CFDictionaryCreateMutable(NULL
,
1570 &kCFTypeDictionaryKeyCallBacks
,
1571 &kCFTypeDictionaryValueCallBacks
);
1572 addTimestamp(S_state
, CFSTR("*START*"));
1574 // Creates and returns a notification object for receiving IOKit
1575 // notifications of new devices or state changes.
1576 kr
= IOMasterPort(bootstrap_port
, &masterPort
);
1577 if (kr
!= KERN_SUCCESS
) {
1578 SCLog(TRUE
, LOG_ERR
,
1579 CFSTR(MY_PLUGIN_NAME
": IOMasterPort returned 0x%x"),
1584 S_notify
= IONotificationPortCreate(masterPort
);
1585 if (S_notify
== NULL
) {
1586 SCLog(TRUE
, LOG_ERR
,
1587 CFSTR(MY_PLUGIN_NAME
": IONotificationPortCreate failed"));
1591 // watch IOKit matching activity
1592 root
= IORegistryEntryFromPath(masterPort
, kIOServicePlane
":/");
1593 if (root
== MACH_PORT_NULL
) {
1594 SCLog(TRUE
, LOG_ERR
,
1595 CFSTR(MY_PLUGIN_NAME
": IORegistryEntryFromPath failed"));
1599 kr
= IOServiceAddInterestNotification(S_notify
,
1603 (void *)S_notify
, // refCon
1604 &S_quiet
); // notification
1605 if (kr
!= KERN_SUCCESS
) {
1606 SCLog(TRUE
, LOG_ERR
,
1607 CFSTR(MY_PLUGIN_NAME
": IOServiceAddInterestNotification returned 0x%x"),
1612 kr
= IOServiceGetBusyState(root
, &busy
);
1613 if (kr
!= KERN_SUCCESS
) {
1614 SCLog(TRUE
, LOG_ERR
,
1615 CFSTR(MY_PLUGIN_NAME
": IOServiceGetBusyState returned 0x%x"),
1620 // add a timer so we don't wait forever for IOKit to quiesce
1621 dict
= CFBundleGetInfoDictionary(bundle
);
1622 if (isA_CFDictionary(dict
)) {
1625 num
= CFDictionaryGetValue(dict
, CFSTR(WAIT_QUIET_TIMEOUT_KEY
));
1627 if (!isA_CFNumber(num
) ||
1628 !CFNumberGetValue(num
, kCFNumberDoubleType
, &timeout
) ||
1630 SCLog(TRUE
, LOG_ERR
,
1631 CFSTR(MY_PLUGIN_NAME
": " WAIT_QUIET_TIMEOUT_KEY
" value error"));
1632 timeout
= WAIT_QUIET_TIMEOUT_DEFAULT
;
1636 S_timer
= CFRunLoopTimerCreate(NULL
,
1637 CFAbsoluteTimeGetCurrent() + timeout
,
1643 if (S_timer
== NULL
) {
1644 SCLog(TRUE
, LOG_ERR
,
1645 CFSTR(MY_PLUGIN_NAME
": CFRunLoopTimerCreate failed"));
1649 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, kCFRunLoopDefaultMode
);
1651 // watch for the introduction of the IONetworkStack
1652 kr
= IOServiceAddMatchingNotification(S_notify
,
1653 kIOFirstMatchNotification
,
1654 IOServiceMatching("IONetworkStack"),
1656 (void *)S_notify
, // refCon
1657 &S_stack
); // notification
1658 if (kr
!= KERN_SUCCESS
) {
1659 SCLog(TRUE
, LOG_ERR
,
1660 CFSTR(MY_PLUGIN_NAME
": IOServiceAddMatchingNotification returned 0x%x"),
1665 // check and see if the stack is already available and arm the
1666 // notification for its introduction.
1667 stackCallback((void *)S_notify
, S_stack
);
1669 // watch for the introduction of new network interfaces
1670 kr
= IOServiceAddMatchingNotification(S_notify
,
1671 kIOFirstMatchNotification
,
1672 IOServiceMatching("IONetworkInterface"),
1673 &interfaceArrivalCallback
,
1674 (void *)S_notify
, // refCon
1675 &S_iter
); // notification
1676 if (kr
!= KERN_SUCCESS
) {
1677 SCLog(TRUE
, LOG_ERR
,
1678 CFSTR(MY_PLUGIN_NAME
": IOServiceAddMatchingNotification returned 0x%x"),
1683 // Get the current list of matches and arm the notification for
1684 // future interface arrivals.
1685 interfaceArrivalCallback((void *)S_notify
, S_iter
);
1687 // Check if IOKit has already quiesced.
1688 quietCallback((void *)S_notify
,
1690 kIOMessageServiceBusyStateChange
,
1691 (void *)(uintptr_t)busy
);
1693 CFRunLoopAddSource(CFRunLoopGetCurrent(),
1694 IONotificationPortGetRunLoopSource(S_notify
),
1695 kCFRunLoopDefaultMode
);
1697 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
1699 * Start the wheels turning until we've named all of
1700 * the interfaces that were used during the previous
1701 * boot, until IOKit [matching] has quiesced, or
1702 * until we've waited long enough.
1704 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer
, MY_PLUGIN_ID
);
1705 CFRunLoopAddSource(CFRunLoopGetCurrent(),
1706 IONotificationPortGetRunLoopSource(S_notify
),
1708 while (S_prev_active_list
!= NULL
) {
1711 rlStatus
= CFRunLoopRunInMode(MY_PLUGIN_ID
, 1.0e10
, TRUE
);
1713 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
1718 if (root
!= MACH_PORT_NULL
) {
1719 IOObjectRelease(root
);
1721 if (masterPort
!= MACH_PORT_NULL
) {
1722 mach_port_deallocate(mach_task_self(), masterPort
);
1728 #if !TARGET_OS_IPHONE
1730 setup_Virtual(CFBundleRef bundle
)
1732 // open a SCPreferences session
1733 S_prefs
= SCPreferencesCreate(NULL
, CFSTR(MY_PLUGIN_NAME
), NULL
);
1734 if (S_prefs
== NULL
) {
1735 SCLog(TRUE
, LOG_ERR
,
1736 CFSTR(MY_PLUGIN_NAME
": SCPreferencesCreate() failed: %s"),
1737 SCErrorString(SCError()));
1741 // register for change notifications.
1742 if (!SCPreferencesSetCallback(S_prefs
, updateVirtualNetworkInterfaceConfiguration
, NULL
)) {
1743 SCLog(TRUE
, LOG_ERR
,
1744 CFSTR(MY_PLUGIN_NAME
": SCPreferencesSetCallBack() failed: %s"),
1745 SCErrorString(SCError()));
1751 if (!SCPreferencesScheduleWithRunLoop(S_prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
1752 if (SCError() != kSCStatusNoStoreServer
) {
1753 SCLog(TRUE
, LOG_ERR
,
1754 CFSTR(MY_PLUGIN_NAME
": SCPreferencesScheduleWithRunLoop() failed: %s"),
1755 SCErrorString(SCError()));
1763 #endif /* !TARGET_OS_IPHONE */
1767 load_InterfaceNamer(CFBundleRef bundle
, Boolean bundleVerbose
)
1769 if (bundleVerbose
) {
1773 #if !TARGET_OS_IPHONE
1774 // setup virtual network interface monitoring
1775 if (!setup_Virtual(bundle
)) {
1778 #endif /* !TARGET_OS_IPHONE */
1780 // setup [IOKit] network interface monitoring
1781 if (!setup_IOKit(bundle
)) {
1788 if (S_connect
!= MACH_PORT_NULL
) {
1789 IOServiceClose(S_connect
);
1790 S_connect
= MACH_PORT_NULL
;
1792 if (S_dblist
!= NULL
) {
1793 CFRelease(S_dblist
);
1796 if (S_iter
!= MACH_PORT_NULL
) {
1797 IOObjectRelease(S_iter
);
1798 S_iter
= MACH_PORT_NULL
;
1800 if (S_notify
!= MACH_PORT_NULL
) {
1801 IONotificationPortDestroy(S_notify
);
1803 if (S_quiet
!= MACH_PORT_NULL
) {
1804 IOObjectRelease(S_quiet
);
1805 S_quiet
= MACH_PORT_NULL
;
1807 if (S_stack
!= MACH_PORT_NULL
) {
1808 IOObjectRelease(S_stack
);
1809 S_stack
= MACH_PORT_NULL
;
1811 if (S_state
!= NULL
) {
1815 if (S_timer
!= NULL
) {
1816 CFRunLoopTimerInvalidate(S_timer
);
1824 //------------------------------------------------------------------------
1828 main(int argc
, char ** argv
)
1831 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1833 load_InterfaceNamer(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);
1841 #ifdef TEST_PLATFORM_UUID
1843 main(int argc
, char ** argv
)
1845 CFArrayRef interfaces
;
1848 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1850 S_dblist
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1851 interfaces
= SCNetworkInterfaceCopyAll();
1852 if (interfaces
!= NULL
) {
1856 n
= CFArrayGetCount(interfaces
);
1857 for (i
= 0; i
< n
; i
++) {
1858 CFDictionaryRef dict
;
1859 SCNetworkInterfaceRef interface
;
1861 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1862 dict
= createInterfaceDict(interface
);
1863 CFArrayAppendValue(S_dblist
, dict
);
1866 CFRelease(interfaces
);
1868 updatePlatformUUID();
1869 CFRelease(S_dblist
);
1873 #endif /* TEST_PLATFORM_UUID */