X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/791b08356c62be042d56dd05c1cc0ace4b068c53..edebe297f772e4cdd76278ebb777820466d2917b:/Plugins/InterfaceNamer/ifnamer.c?ds=sidebyside diff --git a/Plugins/InterfaceNamer/ifnamer.c b/Plugins/InterfaceNamer/ifnamer.c index a0a9620..6d94985 100644 --- a/Plugins/InterfaceNamer/ifnamer.c +++ b/Plugins/InterfaceNamer/ifnamer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2003 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2001-2007 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,6 +24,12 @@ /* * Modification History * + * November 6, 2006 Allan Nathanson + * Dan Markarian + * Dieter Siegmund + * - updated code to name interfaces quicker (without need for + * calling IOKitWaitQuiet). + * * October 3, 2003 Allan Nathanson * - sort new interfaces by IOKit path (rather than MAC address) to * help facilitate a more predictable interface-->name mapping for @@ -56,6 +62,7 @@ #include #include #include +#include #include #include @@ -65,14 +72,9 @@ #include // for SCLog(), SCPrint() #include -#include -#include - -#include -#include - #include #include +#include #include #include @@ -80,58 +82,115 @@ #define kIOBuiltin "IOBuiltin" #endif -#ifndef kIOLocation -#define kIOLocation "IOLocation" -#endif - #define kIONetworkStackUserCommand "IONetworkStackUserCommand" -#define kIORegisterOne 1 +#define kRegisterInterface 1 + +#define kSCNetworkInterfaceType "SCNetworkInterfaceType" +#define kSCNetworkInterfaceActive "Active" #define MY_PLUGIN_NAME "InterfaceNamer" +#define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME) -static boolean_t S_debug = FALSE; -static CFMutableArrayRef S_dblist = NULL; -static io_connect_t S_connect = MACH_PORT_NULL; -static io_iterator_t S_iter = MACH_PORT_NULL; -static IONotificationPortRef S_notify = NULL; +#define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout" +#define WAIT_QUIET_TIMEOUT_DEFAULT 60.0 -static void -writeInterfaceList(CFArrayRef ilist); +/* + * S_connect + * "IONetworkStack" connect object used to "name" an interface. + */ +static io_connect_t S_connect = MACH_PORT_NULL; -static void -displayInterface(CFDictionaryRef if_dict); +/* + * S_dblist + * An array of CFDictionary's representing the interfaces + * that have been identified and [need to be] named. + */ +static CFMutableArrayRef S_dblist = NULL; -static CFDictionaryRef -lookupIOKitPath(CFStringRef if_path); +/* + * S_debug + * A boolean that enables additional logging. + */ +static boolean_t S_debug = FALSE; + +/* + * S_iflist + * An array of SCNetworkInterface's representing the + * interfaces that have been identified. + */ +static CFMutableArrayRef S_iflist = NULL; + +/* + * S_iter + * IOServiceAddMatchingNotification object used to watch for + * new network interfaces. + */ +static io_iterator_t S_iter = MACH_PORT_NULL; + +/* + * S_notify + * notification object for receiving IOKit notifications of + * new devices or state changes. + */ +static IONotificationPortRef S_notify = NULL; + +/* S_prev_active_list + * An array of CFDictionary's representing the previously + * named interfaces. + */ +static CFMutableArrayRef S_prev_active_list = NULL; + +/* + * S_quiet + * IOServiceAddInterestNotification object used to watch for + * IOKit matching to quiesce. + */ +static io_object_t S_quiet = MACH_PORT_NULL; + +/* + * S_stack + * IOServiceAddMatchingNotification object used to watch for + * the availability of the "IONetworkStack" object. + */ +static io_iterator_t S_stack = MACH_PORT_NULL; -static __inline__ CFComparisonResult -compareMacAddress(CFDataRef addr1, CFDataRef addr2) +/* + * S_state + * A dictionary containing Information about each network + * interface. For now, the key is the BSD name and the + * value is a CFNumber noting how long (in milliseconds) + * it took for the interface to be recognized/named. + */ +static CFMutableDictionaryRef S_state = NULL; + +/* + * S_timer + * CFRunLoopTimer tracking how long we are willing to wait + * for IOKit matching to quiesce (IOKitWaitQuiet). + */ +static CFRunLoopTimerRef S_timer = NULL; + +/* + * Virtual network interface configuration + * S_prefs : SCPreferences to configuration + * S_bonds : most recently actived Bond configuration + * S_vlans : most recently actived VLAN configuration + */ +static SCPreferencesRef S_prefs = NULL; +static CFArrayRef S_bonds = NULL; +static CFArrayRef S_vlans = NULL; + +static void +addTimestamp(CFMutableDictionaryRef dict, CFStringRef key) { - int len1; - int len2; - int clen; - int res; - - len1 = CFDataGetLength(addr1); - len2 = CFDataGetLength(addr2); - - if (len1 == len2) { - if (len1 == 0) - return (kCFCompareEqualTo); - return (memcmp(CFDataGetBytePtr(addr1), - CFDataGetBytePtr(addr2), - len1)); - } - clen = len1; - if (len2 < clen) - clen = len2; - res = memcmp(CFDataGetBytePtr(addr1), - CFDataGetBytePtr(addr2), - clen); - if (res == 0) { - return (len1 - len2); - } - return (res); + CFAbsoluteTime now; + CFNumberRef val; + + now = CFAbsoluteTimeGetCurrent(); + val = CFNumberCreate(NULL, kCFNumberDoubleType, &now); + CFDictionaryAddValue(dict, key, val); + CFRelease(val); + return; } static CFComparisonResult @@ -158,249 +217,16 @@ if_unit_compare(const void *val1, const void *val2, void *context) return (CFNumberCompare(unit1, unit2, NULL)); } -static CFArrayRef -split_path(CFStringRef path) -{ - CFArrayRef components; - CFMutableStringRef nPath; - - // turn '@'s into '/'s - nPath = CFStringCreateMutableCopy(NULL, 0, path); - (void) CFStringFindAndReplace(nPath, - CFSTR("@"), - CFSTR("/"), - CFRangeMake(0, CFStringGetLength(nPath)), - 0); - - // split path into components to be compared - components = CFStringCreateArrayBySeparatingStrings(NULL, nPath, CFSTR("/")); - CFRelease(nPath); - - return components; -} - - -static CFComparisonResult -if_path_compare(const void *val1, const void *val2, void *context) -{ - CFBooleanRef builtin; - Boolean builtin_val1 = FALSE; - Boolean builtin_val2 = FALSE; - CFArrayRef elements1 = NULL; - CFArrayRef elements2 = NULL; - CFIndex i; - CFIndex n; - CFIndex n1 = 0; - CFIndex n2 = 0; - CFStringRef path; - CFComparisonResult res; - CFNumberRef type1; - CFNumberRef type2; - - /* sort by interface type */ - - type1 = CFDictionaryGetValue((CFDictionaryRef)val1, CFSTR(kIOInterfaceType)); - type2 = CFDictionaryGetValue((CFDictionaryRef)val2, CFSTR(kIOInterfaceType)); - res = CFNumberCompare(type1, type2, NULL); - if (res != kCFCompareEqualTo) { - return (res); - } - - /* built-in interfaces sort first */ - builtin = CFDictionaryGetValue((CFDictionaryRef)val1, CFSTR(kIOBuiltin)); - if (isA_CFBoolean(builtin) != NULL) { - builtin_val1 = CFBooleanGetValue(builtin); - } - builtin = CFDictionaryGetValue((CFDictionaryRef)val2, CFSTR(kIOBuiltin)); - if (isA_CFBoolean(builtin) != NULL) { - builtin_val2 = CFBooleanGetValue(builtin); - } - if (builtin_val1 != builtin_val2) { - if (builtin_val1) { - res = kCFCompareLessThan; - } else { - res = kCFCompareGreaterThan; - } - return (res); - } - - /* ... and then sort built-in interfaces by "location" */ - if (builtin_val1) { - CFStringRef location1; - CFStringRef location2; - - location1 = CFDictionaryGetValue((CFDictionaryRef)val1, CFSTR(kIOLocation)); - location2 = CFDictionaryGetValue((CFDictionaryRef)val2, CFSTR(kIOLocation)); - if (location1 != location2) { - if (isA_CFString(location1)) { - if (isA_CFString(location2)) { - res = CFStringCompare(location1, location2, 0); - } else { - res = kCFCompareLessThan; - } - } else { - res = kCFCompareGreaterThan; - } - - if (res != kCFCompareEqualTo) { - return (res); - } - } - } - - /* ... and then sort by IOPathMatch */ - - path = CFDictionaryGetValue((CFDictionaryRef)val1, CFSTR(kIOPathMatchKey)); - if (isA_CFString(path)) { - elements1 = split_path(path); - n1 = CFArrayGetCount(elements1); - } else { - goto done; - } - - path = CFDictionaryGetValue((CFDictionaryRef)val2, CFSTR(kIOPathMatchKey)); - if (isA_CFString(path)) { - elements2 = split_path(path); - n2 = CFArrayGetCount(elements2); - } else { - goto done; - } - - n = (n1 <= n2) ? n1 : n2; - for (i = 0; i < n; i++) { - CFStringRef e1; - CFStringRef e2; - char *end; - quad_t q1; - quad_t q2; - char *str; - Boolean isNum; - - e1 = CFArrayGetValueAtIndex(elements1, i); - e2 = CFArrayGetValueAtIndex(elements2, i); - - str = _SC_cfstring_to_cstring(e1, NULL, 0, kCFStringEncodingASCII); - errno = 0; - q1 = strtoq(str, &end, 16); - isNum = ((*str != '\0') && (*end == '\0') && (errno == 0)); - CFAllocatorDeallocate(NULL, str); - - if (isNum) { - // if e1 is a valid numeric string - str = _SC_cfstring_to_cstring(e2, NULL, 0, kCFStringEncodingASCII); - errno = 0; - q2 = strtoq(str, &end, 16); - isNum = ((*str != '\0') && (*end == '\0') && (errno == 0)); - CFAllocatorDeallocate(NULL, str); - - if (isNum) { - // if e2 is also a valid numeric string - - if (q1 == q2) { - res = kCFCompareEqualTo; - continue; - } else if (q1 < q2) { - res = kCFCompareLessThan; - } else { - res = kCFCompareGreaterThan; - } - break; - } - } - - res = CFStringCompare(e1, e2, 0); - if (res != kCFCompareEqualTo) { - break; - } - } - - if (res == kCFCompareEqualTo) { - if (n1 < n2) { - res = kCFCompareLessThan; - } else if (n1 < n2) { - res = kCFCompareGreaterThan; - } - } - - done : - if ( elements1 ) CFRelease( elements1 ); - if ( elements2 ) CFRelease( elements2 ); - - return res; -} - -static boolean_t -addCFStringProperty( CFMutableDictionaryRef dict, - const char * key, - const char * string ) -{ - boolean_t ret = false; - CFStringRef valObj, keyObj; - - if ( (string == 0) || (key == 0) || (dict == 0) ) - return false; - - keyObj = CFStringCreateWithCString(NULL, - key, - kCFStringEncodingASCII ); - - valObj = CFStringCreateWithCString(NULL, - string, - kCFStringEncodingASCII ); - - if (valObj && keyObj) { - CFDictionarySetValue( dict, keyObj, valObj ); - ret = true; - } - - if ( keyObj ) CFRelease( keyObj ); - if ( valObj ) CFRelease( valObj ); - - return ret; -} - -static boolean_t -addCFNumberProperty( CFMutableDictionaryRef dict, - const char * key, - unsigned int number ) -{ - boolean_t ret = false; - CFNumberRef numObj; - CFStringRef keyObj; - - if ( (key == 0) || (dict == 0) ) - return false; - - numObj = CFNumberCreate(NULL, - kCFNumberLongType, - &number); - - keyObj = CFStringCreateWithCString(NULL, - key, - kCFStringEncodingASCII ); - - if ( numObj && keyObj ) - { - CFDictionarySetValue( dict, keyObj, numObj ); - ret = true; - } - - if ( numObj ) CFRelease( numObj ); - if ( keyObj ) CFRelease( keyObj ); - - return ret; -} - static void * read_file(char * filename, size_t * data_length) { - void * data = NULL; - size_t len = 0; - int fd = -1; + void * data = NULL; + size_t len = 0; + int fd = -1; struct stat sb; *data_length = 0; - if (stat(filename, &sb) < 0) + if (stat(filename, &sb) == -1) goto done; len = sb.st_size; if (len == 0) @@ -411,17 +237,18 @@ read_file(char * filename, size_t * data_length) goto done; fd = open(filename, O_RDONLY); - if (fd < 0) + if (fd == -1) goto done; if (read(fd, data, len) != len) { - SCLog(TRUE, LOG_INFO, + SCLog(TRUE, LOG_ERR, CFSTR(MY_PLUGIN_NAME ": read %s failed, %s"), filename, strerror(errno)); goto done; } + done: - if (fd >= 0) + if (fd != -1) close(fd); if (data) { *data_length = len; @@ -434,9 +261,9 @@ readPropertyList(char * filename) { void * buf; size_t bufsize; - CFDataRef data = NULL; - CFPropertyListRef plist = NULL; - CFStringRef errorString = NULL; + CFDataRef data = NULL; + CFPropertyListRef plist = NULL; + CFStringRef errorString = NULL; buf = read_file(filename, &bufsize); if (buf == NULL) { @@ -451,9 +278,9 @@ readPropertyList(char * filename) kCFPropertyListMutableContainers, &errorString); if (plist == NULL) { - if (errorString) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME ":%@"), + if (errorString != NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": %@"), errorString); CFRelease(errorString); } @@ -466,173 +293,314 @@ readPropertyList(char * filename) return (plist); } -#define IFNAMER_ID CFSTR("com.apple.SystemConfiguration.InterfaceNamer") #define INTERFACES CFSTR("Interfaces") #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist") #define OLD_NETWORK_INTERFACES_FILE "/var/db/NetworkInterfaces.xml" +static void +writeInterfaceList(CFArrayRef if_list) +{ + CFArrayRef cur_list; + SCPreferencesRef prefs; + + if (isA_CFArray(if_list) == NULL) { + return; + } + + prefs = SCPreferencesCreate(NULL, MY_PLUGIN_ID, NETWORK_INTERFACES_PREFS); + if (prefs == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate failed, %s"), + SCErrorString(SCError())); + return; + } + + cur_list = SCPreferencesGetValue(prefs, INTERFACES); + if (_SC_CFEqual(cur_list, if_list)) { + goto done; + } + + if (!SCPreferencesSetValue(prefs, INTERFACES, if_list)) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetValue failed, %s"), + SCErrorString(SCError())); + goto done; + } + + if (!SCPreferencesCommitChanges(prefs)) { + SCLog((SCError() != EROFS), LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": SCPreferencesCommitChanges failed, %s"), + SCErrorString(SCError())); + goto done; + } + +done: + + CFRelease(prefs); + return; +} + static CFMutableArrayRef readInterfaceList() { - CFArrayRef ilist; + CFArrayRef if_list; CFMutableArrayRef plist = NULL; SCPreferencesRef prefs = NULL; - prefs = SCPreferencesCreate(NULL, IFNAMER_ID, NETWORK_INTERFACES_PREFS); + prefs = SCPreferencesCreate(NULL, MY_PLUGIN_ID, NETWORK_INTERFACES_PREFS); if (!prefs) { - SCLog(TRUE, LOG_INFO, + SCLog(TRUE, LOG_ERR, CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate failed, %s"), SCErrorString(SCError())); return (NULL); } - ilist = SCPreferencesGetValue(prefs, INTERFACES); - if (isA_CFArray(ilist)) { - plist = CFArrayCreateMutableCopy(NULL, 0, ilist); - } else { - plist = (CFMutableArrayRef)readPropertyList(OLD_NETWORK_INTERFACES_FILE); - if (plist == NULL) { + if_list = SCPreferencesGetValue(prefs, INTERFACES); + if (!isA_CFArray(if_list)) { + if_list = (CFArrayRef)readPropertyList(OLD_NETWORK_INTERFACES_FILE); + if (if_list == NULL) { goto done; } - if (isA_CFArray(plist) == NULL) { - CFRelease(plist); + if (!isA_CFArray(if_list)) { + CFRelease(if_list); + if_list = NULL; goto done; } - writeInterfaceList(plist); + writeInterfaceList(if_list); (void)unlink(OLD_NETWORK_INTERFACES_FILE); } done: + if (if_list != NULL) { + CFIndex i; + CFIndex n = CFArrayGetCount(if_list); + + plist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + for (i = 0; i < n; i++) { + CFDictionaryRef dict; + + dict = CFArrayGetValueAtIndex(if_list, i); + if (isA_CFDictionary(dict) && + CFDictionaryContainsKey(dict, CFSTR(kIOInterfaceType)) && + CFDictionaryContainsKey(dict, CFSTR(kIOInterfaceUnit)) && + CFDictionaryContainsKey(dict, CFSTR(kIOMACAddress))) { + CFArrayAppendValue(plist, dict); + } + } + } if (prefs) { CFRelease(prefs); } return (plist); } -static void -writeInterfaceList(CFArrayRef ilist) +static CFMutableArrayRef +previouslyActiveInterfaces() { - SCPreferencesRef prefs; + CFMutableArrayRef active; + CFIndex i; + CFIndex n; - if (isA_CFArray(ilist) == NULL) { - return; + if (S_dblist == NULL) { + return NULL; } - prefs = SCPreferencesCreate(NULL, IFNAMER_ID, NETWORK_INTERFACES_PREFS); - if (prefs == NULL) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate failed, %s"), - SCErrorString(SCError())); - return; - } + active = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - if (!SCPreferencesSetValue(prefs, INTERFACES, ilist)) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetValue failed, %s"), - SCErrorString(SCError())); - goto done; + n = CFArrayGetCount(S_dblist); + for (i = 0; i < n; i++) { + CFDictionaryRef if_dict; + + if_dict = CFArrayGetValueAtIndex(S_dblist, i); + if (CFDictionaryContainsKey(if_dict, CFSTR(kSCNetworkInterfaceActive))) { + CFMutableDictionaryRef new_dict; + + new_dict = CFDictionaryCreateMutableCopy(NULL, 0, if_dict); + CFDictionaryRemoveValue(new_dict, CFSTR(kSCNetworkInterfaceActive)); + CFArraySetValueAtIndex(S_dblist, i, new_dict); + CFArrayAppendValue(active, new_dict); + CFRelease(new_dict); + } } - if (!SCPreferencesCommitChanges(prefs)) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME ": SCPreferencesCommitChanges failed, %s"), - SCErrorString(SCError())); - goto done; + return active; +} + +static void +updateStore(void) +{ + CFStringRef key; + SCDynamicStoreRef store; + + store = SCDynamicStoreCreate(NULL, CFSTR(MY_PLUGIN_NAME), NULL, NULL); + if (store == NULL) { + return; } -done: + key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" MY_PLUGIN_NAME), + kSCDynamicStoreDomainPlugin); + (void)SCDynamicStoreSetValue(store, key, S_state); + CFRelease(key); + CFRelease(store); - CFRelease(prefs); return; } static void -updateBondConfiguration(void) +updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs, + SCPreferencesNotification notificationType, + void *info) { - BondPreferencesRef prefs; + CFArrayRef interfaces; - prefs = BondPreferencesCreate(NULL); - if (prefs == NULL) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME ": BondPreferencesCreate failed, %s"), - SCErrorString(SCError())); + if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) { return; } - if (!_BondPreferencesUpdateConfiguration(prefs)) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME ": _BondPreferencesUpdateConfiguration failed, %s"), + if (prefs == NULL) { + // if a new interface has been "named" + prefs = S_prefs; + if (S_bonds != NULL) { + CFRelease(S_bonds); + S_bonds = NULL; + } + if (S_vlans != NULL) { + CFRelease(S_vlans); + S_vlans = NULL; + } + } + + // update Bond configuration + + interfaces = SCBondInterfaceCopyAll(prefs); + if ((S_bonds == NULL) && (interfaces == NULL)) { + // if no change + goto vlan; + } + if ((S_bonds != NULL) && (interfaces != NULL) && CFEqual(S_bonds, interfaces)) { + // if no change + CFRelease(interfaces); + goto vlan; + } + if (S_bonds != NULL) CFRelease(S_bonds); + S_bonds = interfaces; + + if (!_SCBondInterfaceUpdateConfiguration(prefs)) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": _SCBondInterfaceUpdateConfiguration failed, %s"), SCErrorString(SCError())); + } + + vlan : + + // update VLAN configuration + + interfaces = SCVLANInterfaceCopyAll(prefs); + if ((S_vlans == NULL) && (interfaces == NULL)) { + // if no change goto done; } + if ((S_vlans != NULL) && (interfaces != NULL) && CFEqual(S_vlans, interfaces)) { + // if no change + CFRelease(interfaces); + goto done; + } + if (S_vlans != NULL) CFRelease(S_vlans); + S_vlans = interfaces; -done: + if (!_SCVLANInterfaceUpdateConfiguration(prefs)) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": _SCVLANInterfaceUpdateConfiguration failed, %s"), + SCErrorString(SCError())); + } - CFRelease(prefs); + done : + + // we are finished with current prefs, wait for changes + + SCPreferencesSynchronize(prefs); return; } -static void -updateVLANConfiguration(void) +static CFDictionaryRef +createInterfaceDict(SCNetworkInterfaceRef interface) { - VLANPreferencesRef prefs; + CFMutableDictionaryRef new_if; + CFTypeRef val; - prefs = VLANPreferencesCreate(NULL); - if (prefs == NULL) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME ": VLANPreferencesCreate failed, %s"), - SCErrorString(SCError())); - return; + new_if = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + val = _SCNetworkInterfaceGetIOPath(interface); + if (val != NULL) { + CFDictionarySetValue(new_if, CFSTR(kIOPathMatchKey), val); } - if (!_VLANPreferencesUpdateConfiguration(prefs)) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME ": _VLANPreferencesUpdateConfiguration failed, %s"), - SCErrorString(SCError())); - goto done; + val = _SCNetworkInterfaceGetIOInterfaceType(interface); + if (val != NULL) { + CFDictionarySetValue(new_if, CFSTR(kIOInterfaceType), val); } -done: + val = _SCNetworkInterfaceGetIOInterfaceUnit(interface); + if (val != NULL) { + CFDictionarySetValue(new_if, CFSTR(kIOInterfaceUnit), val); + } - CFRelease(prefs); - return; -} + val = _SCNetworkInterfaceGetHardwareAddress(interface); + if (val != NULL) { + CFDictionarySetValue(new_if, CFSTR(kIOMACAddress), val); + } + + val = SCNetworkInterfaceGetBSDName(interface); + if (val != NULL) { + CFDictionarySetValue(new_if, CFSTR(kIOBSDNameKey), val); + } + + val = SCNetworkInterfaceGetInterfaceType(interface); + if (val != NULL) { + CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceType), val); + } -#define INDEX_BAD (-1) + CFDictionarySetValue(new_if, + CFSTR(kIOBuiltin), + _SCNetworkInterfaceIsBuiltin(interface) ? kCFBooleanTrue : kCFBooleanFalse); + + CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceActive), kCFBooleanTrue); + + return new_if; +} static CFDictionaryRef -lookupInterfaceByType(CFArrayRef list, CFDictionaryRef if_dict, int * where) +lookupInterfaceByAddress(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where) { CFDataRef addr; CFIndex i; CFIndex n; CFNumberRef type; - if (where) { - *where = INDEX_BAD; - } - if (list == NULL) { + if (db_list == NULL) { return (NULL); } - addr = CFDictionaryGetValue(if_dict, CFSTR(kIOMACAddress)); - type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType)); + type = _SCNetworkInterfaceGetIOInterfaceType(interface); + addr = _SCNetworkInterfaceGetHardwareAddress(interface); if (type == NULL || addr == NULL) { return (NULL); } - n = CFArrayGetCount(list); + n = CFArrayGetCount(db_list); for (i = 0; i < n; i++) { - CFDictionaryRef dict = CFArrayGetValueAtIndex(list, i); CFDataRef a; + CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i); CFNumberRef t; - a = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); t = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); - if (a == NULL || t == NULL) + a = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); + if (t == NULL || a == NULL) continue; - if (CFNumberCompare(type, t, NULL) == kCFCompareEqualTo - && compareMacAddress(addr, a) == kCFCompareEqualTo) { + if (CFEqual(type, t) && CFEqual(addr, a)) { if (where) { *where = i; } @@ -643,28 +611,25 @@ lookupInterfaceByType(CFArrayRef list, CFDictionaryRef if_dict, int * where) } static CFDictionaryRef -lookupInterfaceByUnit(CFArrayRef list, CFDictionaryRef if_dict, int * where) +lookupInterfaceByUnit(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where) { CFIndex i; CFIndex n; CFNumberRef type; CFNumberRef unit; - if (where) { - *where = INDEX_BAD; - } - if (list == NULL) { + if (db_list == NULL) { return (NULL); } - type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType)); - unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit)); + type = _SCNetworkInterfaceGetIOInterfaceType(interface); + unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); if (type == NULL || unit == NULL) { return (NULL); } - n = CFArrayGetCount(list); + n = CFArrayGetCount(db_list); for (i = 0; i < n; i++) { - CFDictionaryRef dict = CFArrayGetValueAtIndex(list, i); + CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i); CFNumberRef t; CFNumberRef u; @@ -674,8 +639,7 @@ lookupInterfaceByUnit(CFArrayRef list, CFDictionaryRef if_dict, int * where) continue; } - if (CFNumberCompare(type, t, NULL) == kCFCompareEqualTo - && CFNumberCompare(unit, u, NULL) == kCFCompareEqualTo) { + if (CFEqual(type, t) && CFEqual(unit, u)) { if (where) *where = i; return (dict); @@ -684,55 +648,24 @@ lookupInterfaceByUnit(CFArrayRef list, CFDictionaryRef if_dict, int * where) return (NULL); } -#define kAirPortDriverPath CFSTR("AirPort") -#define kIO80211InterfacePath CFSTR("IO80211Interface") -#define APPLE_WIRELESS_80211 CFSTR("AppleWireless80211") - -static __inline__ boolean_t -pathIsAirPort(CFStringRef path) +static CFDictionaryRef +lookupAirPortInterface(CFArrayRef db_list, CFIndex * where) { - CFRange r; - - r = CFStringFind(path, kIO80211InterfacePath, 0); - if (r.location != kCFNotFound) { - return (TRUE); - } + CFIndex i; + CFIndex n; - r = CFStringFind(path, kAirPortDriverPath, 0); - if (r.location != kCFNotFound) { - return (TRUE); + if (db_list == NULL) { + return (NULL); } + n = CFArrayGetCount(db_list); + for (i = 0; i < n; i++) { + CFDictionaryRef dict; + CFStringRef if_type; - r = CFStringFind(path, APPLE_WIRELESS_80211, 0); - if (r.location != kCFNotFound) { - return (TRUE); - } - - return (FALSE); -} - -static CFDictionaryRef -lookupAirPortInterface(CFArrayRef list, int * where) -{ - CFIndex i; - CFIndex n; - - if (where) { - *where = INDEX_BAD; - } - if (list == NULL) { - return (NULL); - } - n = CFArrayGetCount(list); - for (i = 0; i < n; i++) { - CFDictionaryRef dict = CFArrayGetValueAtIndex(list, i); - CFStringRef path; - - path = CFDictionaryGetValue(dict, CFSTR(kIOPathMatchKey)); - if (path == NULL) { - continue; - } - if (pathIsAirPort(path) == TRUE) { + dict = CFArrayGetValueAtIndex(db_list, i); + if_type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType)); + if ((if_type != NULL) && + CFEqual(if_type, kSCNetworkInterfaceTypeIEEE80211)) { if (where) *where = i; return (dict); @@ -742,54 +675,70 @@ lookupAirPortInterface(CFArrayRef list, int * where) } static void -insertInterface(CFMutableArrayRef list, CFDictionaryRef if_dict) +insertInterface(CFMutableArrayRef db_list, SCNetworkInterfaceRef interface) { CFIndex i; + CFDictionaryRef if_dict; + CFStringRef if_name; CFNumberRef if_type; CFNumberRef if_unit; - CFIndex n = CFArrayGetCount(list); + CFIndex n = CFArrayGetCount(db_list); CFComparisonResult res; - if_type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType)); - if_unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit)); + if_name = SCNetworkInterfaceGetBSDName(interface); + if (if_name != NULL) { + addTimestamp(S_state, if_name); + } + + if_dict = createInterfaceDict(interface); + if_type = _SCNetworkInterfaceGetIOInterfaceType(interface); + if_unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); + if ((if_type == NULL) || (if_unit == NULL)) { + CFRelease(if_dict); + return; + } + for (i = 0; i < n; i++) { - CFDictionaryRef dict = CFArrayGetValueAtIndex(list, i); - CFNumberRef type; - CFNumberRef unit; + CFNumberRef db_type; + CFNumberRef db_unit; + CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i); - type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); - unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit)); - res = CFNumberCompare(if_type, type, NULL); + db_type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); + db_unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit)); + res = CFNumberCompare(if_type, db_type, NULL); if (res == kCFCompareLessThan || (res == kCFCompareEqualTo - && (CFNumberCompare(if_unit, unit, NULL) + && (CFNumberCompare(if_unit, db_unit, NULL) == kCFCompareLessThan))) { - CFArrayInsertValueAtIndex(list, i, if_dict); + CFArrayInsertValueAtIndex(db_list, i, if_dict); + CFRelease(if_dict); return; } } + CFArrayAppendValue(S_dblist, if_dict); + CFRelease(if_dict); return; } static void -replaceInterface(CFDictionaryRef if_dict) +replaceInterface(SCNetworkInterfaceRef interface) { - int where; + CFIndex where; if (S_dblist == NULL) { S_dblist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } - /* remove any dict that has our type/addr */ - if (lookupInterfaceByType(S_dblist, if_dict, &where) != NULL) { + // remove any dict that has our type/addr + if (lookupInterfaceByAddress(S_dblist, interface, &where) != NULL) { CFArrayRemoveValueAtIndex(S_dblist, where); } - /* remove any dict that has the same type/unit */ - if (lookupInterfaceByUnit(S_dblist, if_dict, &where) != NULL) { + // remove any dict that has the same type/unit + if (lookupInterfaceByUnit(S_dblist, interface, &where) != NULL) { CFArrayRemoveValueAtIndex(S_dblist, where); } - insertInterface(S_dblist, if_dict); + insertInterface(S_dblist, interface); return; } @@ -798,19 +747,21 @@ getHighestUnitForType(CFNumberRef if_type) { int i; CFIndex n; - CFNumberRef ret_unit = NULL; + CFNumberRef ret_unit = NULL; - if (S_dblist == NULL) + if (S_dblist == NULL) { return (NULL); + } n = CFArrayGetCount(S_dblist); for (i = 0; i < n; i++) { CFDictionaryRef dict = CFArrayGetValueAtIndex(S_dblist, i); CFNumberRef type; - CFNumberRef unit; type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); if (CFEqual(type, if_type)) { + CFNumberRef unit; + unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit)); if (ret_unit == NULL || (CFNumberCompare(unit, ret_unit, NULL) @@ -819,254 +770,51 @@ getHighestUnitForType(CFNumberRef if_type) } } } + return (ret_unit); } -//------------------------------------------------------------------------ -// Register a single interface with the given service path to the -// data link layer (BSD), using the specified unit number. - +/* + * Function: registerInterface + * Purpose: + * Register a single interface with the given service path to the + * data link layer (BSD), using the specified unit number. + */ static kern_return_t -registerInterface(io_connect_t connect, - CFStringRef path, - CFNumberRef unit) +registerInterface(io_connect_t connect, + CFStringRef path, + CFNumberRef unit) { + static const int command = kRegisterInterface; CFMutableDictionaryRef dict; - kern_return_t kr = kIOReturnNoMemory; + kern_return_t kr; + CFNumberRef num; dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (dict == NULL - || addCFNumberProperty(dict, kIONetworkStackUserCommand, - kIORegisterOne) == FALSE) - ; - else { - CFDictionarySetValue(dict, CFSTR(kIOPathMatchKey), path); - CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit); - kr = IOConnectSetCFProperties(connect, dict); - } - if (dict) CFRelease( dict ); + num = CFNumberCreate(NULL, kCFNumberIntType, &command); + CFDictionarySetValue(dict, CFSTR(kIONetworkStackUserCommand), num); + CFRelease(num); + CFDictionarySetValue(dict, CFSTR(kIOPathMatchKey), path); + CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit); + kr = IOConnectSetCFProperties(connect, dict); + CFRelease(dict); return kr; } -/* - * Note: this function blocks all other plug-ins until it completes - */ -static void -waitForQuiet(mach_port_t masterPort) -{ - mach_timespec_t t; - kern_return_t wait_ret; - - t.tv_sec = 4; - t.tv_nsec = 0; - - // kIOReturnTimeout if the wait timed out. - // kIOReturnSuccess on success. - wait_ret = IOKitWaitQuiet(masterPort, &t); - return; -} - -/* - * Function: createNetworkStackObject - * Purpose: - * Get a reference to the single IONetworkStack object instance in - * the kernel. Naming requests must be sent to this object, which is - * attached as a client to all network interface objects in the system. - * Note: - * Call IOObjectRelease on the returned object. - */ -static io_object_t -createNetworkStackObject(mach_port_t masterPort) -{ - io_iterator_t iter = MACH_PORT_NULL; - kern_return_t kr; - io_object_t stack = MACH_PORT_NULL; - - kr = IOServiceGetMatchingServices(masterPort, - IOServiceMatching("IONetworkStack"), - &iter); - if (iter != MACH_PORT_NULL) { - if (kr == KERN_SUCCESS) { - stack = IOIteratorNext(iter); - } - IOObjectRelease(iter); - } - return stack; -} - -static void -printMacAddress(CFDataRef data) -{ - int i; - CFIndex n = CFDataGetLength(data); - - for (i = 0; i < n; i++) { - if (i != 0) SCPrint(TRUE, stdout, CFSTR(":")); - SCPrint(TRUE, stdout, CFSTR("%02x"), CFDataGetBytePtr(data)[i]); - } - return; -} - -/* - * Function: getMacAddress - * - * Purpose: - * Given an interface object if_obj, return its associated mac address. - * The mac address is stored in the parent, the network controller object. - * - * Returns: - * The CFDataRef containing the bytes of the mac address. - */ -static CFDataRef -getMacAddress(io_object_t if_obj) -{ - CFMutableDictionaryRef dict = NULL; - CFDataRef data = NULL; - kern_return_t kr; - io_object_t parent_obj = MACH_PORT_NULL; - - /* get the parent node */ - kr = IORegistryEntryGetParentEntry(if_obj, kIOServicePlane, &parent_obj); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME - ": IORegistryEntryGetParentEntry returned 0x%x"), - kr); - goto failed; - } - - /* get the dictionary associated with the node */ - kr = IORegistryEntryCreateCFProperties(parent_obj, - &dict, - NULL, - kNilOptions ); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME - ": IORegistryEntryCreateCFProperties returned 0x%x"), - kr); - goto failed; - } - data = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); - if (data) { - CFRetain(data); - } - - failed: - if (dict) - CFRelease(dict); - if (parent_obj) - IOObjectRelease(parent_obj); - return (data); -} - -static CFDictionaryRef -getInterface(io_object_t if_obj) -{ - CFBooleanRef builtin; - kern_return_t kr; - CFDataRef mac_address = NULL; - CFStringRef location; - CFMutableDictionaryRef new_if = NULL; - io_string_t path; - CFMutableDictionaryRef reginfo_if = NULL; - CFDictionaryRef ret_dict = NULL; - CFStringRef string; - CFNumberRef type; - CFNumberRef unit; - - kr = IORegistryEntryGetPath(if_obj, kIOServicePlane, path); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME - ": IORegistryEntryGetPath returned 0x%x"), - kr); - goto failed; - } - kr = IORegistryEntryCreateCFProperties(if_obj, - ®info_if, - NULL, - kNilOptions); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME - ": IORegistryEntryCreateCFProperties returned 0x%x"), - kr); - goto failed; - } - type = isA_CFNumber(CFDictionaryGetValue(reginfo_if, - CFSTR(kIOInterfaceType))); - if (type == NULL) { - goto failed; - } - mac_address = getMacAddress(if_obj); - if (mac_address == NULL) { - goto failed; - } - builtin = isA_CFBoolean(CFDictionaryGetValue(reginfo_if, - CFSTR(kIOBuiltin))); - if ((builtin == NULL) || !CFBooleanGetValue(builtin)) { - builtin = isA_CFBoolean(CFDictionaryGetValue(reginfo_if, - CFSTR(kIOPrimaryInterface))); - } - location = isA_CFString(CFDictionaryGetValue(reginfo_if, - CFSTR(kIOLocation))); - - new_if = CFDictionaryCreateMutable(NULL, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (new_if == NULL) { - goto failed; - } - CFDictionarySetValue(new_if, CFSTR(kIOInterfaceType), type); - CFDictionarySetValue(new_if, CFSTR(kIOMACAddress), mac_address); - if (builtin) { - CFDictionarySetValue(new_if, CFSTR(kIOBuiltin), builtin); - } - if (location) { - CFDictionarySetValue(new_if, CFSTR(kIOLocation), location); - } - addCFStringProperty(new_if, kIOPathMatchKey, path); - - unit = isA_CFNumber(CFDictionaryGetValue(reginfo_if, - CFSTR(kIOInterfaceUnit))); - if (unit) { - CFDictionarySetValue(new_if, CFSTR(kIOInterfaceUnit), unit); - } - string = isA_CFString(CFDictionaryGetValue(reginfo_if, CFSTR(kIOBSDNameKey))); - if (string) { - CFDictionarySetValue(new_if, CFSTR(kIOBSDNameKey), string); - } - ret_dict = new_if; - new_if = NULL; - - failed: - if (new_if) { - CFRelease(new_if); - } - if (reginfo_if) { - CFRelease(reginfo_if); - } - if (mac_address) { - CFRelease(mac_address); - } - return (ret_dict); -} - -static CFDictionaryRef +static SCNetworkInterfaceRef lookupIOKitPath(CFStringRef if_path) { - CFDictionaryRef dict = NULL; - io_registry_entry_t entry = MACH_PORT_NULL; + io_registry_entry_t entry = MACH_PORT_NULL; + SCNetworkInterfaceRef interface = NULL; kern_return_t kr; - mach_port_t masterPort = MACH_PORT_NULL; + mach_port_t masterPort = MACH_PORT_NULL; io_string_t path; kr = IOMasterPort(bootstrap_port, &masterPort); if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, + SCLog(TRUE, LOG_ERR, CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x\n"), kr); goto error; @@ -1074,12 +822,13 @@ lookupIOKitPath(CFStringRef if_path) _SC_cfstring_to_cstring(if_path, path, sizeof(path), kCFStringEncodingASCII); entry = IORegistryEntryFromPath(masterPort, path); if (entry == MACH_PORT_NULL) { - SCLog(TRUE, LOG_INFO, + SCLog(TRUE, LOG_ERR, CFSTR(MY_PLUGIN_NAME ": IORegistryEntryFromPath(%@) failed"), if_path); goto error; } - dict = getInterface(entry); + + interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry); error: if (masterPort != MACH_PORT_NULL) { @@ -1088,324 +837,935 @@ lookupIOKitPath(CFStringRef if_path) if (entry != MACH_PORT_NULL) { IOObjectRelease(entry); } - return (dict); + return (interface); } static void -displayInterface(CFDictionaryRef if_dict) +displayInterface(SCNetworkInterfaceRef interface) { + CFStringRef addr; CFStringRef name; CFNumberRef type; CFNumberRef unit; - name = CFDictionaryGetValue(if_dict, CFSTR(kIOBSDNameKey)); - if (name) { - SCPrint(TRUE, stdout, CFSTR("BSD Name: %@\n"), name); - } - - unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit)); - if (unit) { - SCPrint(TRUE, stdout, CFSTR("Unit: %@\n"), unit); - } - - type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType)); - SCPrint(TRUE, stdout, CFSTR("Type: %@\n"), type); - - SCPrint(TRUE, stdout, CFSTR("MAC address: ")); - printMacAddress(CFDictionaryGetValue(if_dict, CFSTR(kIOMACAddress))); - SCPrint(TRUE, stdout, CFSTR("\n")); + name = SCNetworkInterfaceGetBSDName(interface); + unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); + type = _SCNetworkInterfaceGetIOInterfaceType(interface); + addr = SCNetworkInterfaceGetHardwareAddressString(interface); + + SCLog(TRUE, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": %s%@%sType: %@, %s%@%sMAC address: %@"), + (name != NULL) ? "BSD Name: " : "", + (name != NULL) ? name : CFSTR(""), + (name != NULL) ? ", " : "", + type, + (unit != NULL) ? "Unit: " : "", + (unit != NULL) ? (CFTypeRef)unit : (CFTypeRef)CFSTR(""), + (unit != NULL) ? ", " : "", + addr); } -static void -sort_interfaces_by_unit(CFMutableArrayRef if_list) +static int +builtinCount(CFArrayRef if_list, CFIndex last, CFNumberRef if_type) { - int count = CFArrayGetCount(if_list); - CFRange range = CFRangeMake(0, count); + CFIndex i; + int n = 0; - if (count < 2) - return; - CFArraySortValues(if_list, range, if_unit_compare, NULL); - return; + for (i = 0; i < last; i++) { + SCNetworkInterfaceRef builtin_if; + CFNumberRef builtin_type; + + builtin_if = CFArrayGetValueAtIndex(if_list, i); + builtin_type = _SCNetworkInterfaceGetIOInterfaceType(builtin_if); + if (CFEqual(if_type, builtin_type)) { + if (_SCNetworkInterfaceIsBuiltin(builtin_if)) { + n++; // if built-in interface + } + } + } + + return n; } -static void -sort_interfaces_by_path(CFMutableArrayRef if_list) +static __inline__ boolean_t +isQuiet(void) { - int count = CFArrayGetCount(if_list); - CFRange range = CFRangeMake(0, count); - - if (count < 2) - return; - CFArraySortValues(if_list, range, if_path_compare, NULL); - return; + return (S_quiet == MACH_PORT_NULL); } static void -name_interfaces(CFArrayRef if_list) +nameInterfaces(CFMutableArrayRef if_list) { CFIndex i; - CFIndex n = CFArrayGetCount(if_list); - CFIndex i_builtin = 0; - CFIndex n_builtin = 0; - - if (S_debug) - SCPrint(TRUE, stdout, CFSTR("\n")); - - for (i = 0; i < n; i++) { - CFBooleanRef builtin; - CFDictionaryRef if_dict; - - if_dict = CFArrayGetValueAtIndex(if_list, i); - builtin = CFDictionaryGetValue(if_dict, CFSTR(kIOBuiltin)); - if (builtin && CFBooleanGetValue(builtin)) { - n_builtin++; // reserve unit number for built-in interface - } - } + CFIndex n = CFArrayGetCount(if_list); for (i = 0; i < n; i++) { - CFDictionaryRef if_dict; - CFNumberRef type; - CFNumberRef unit; - - if (S_debug) { - if (i != 0) - SCPrint(TRUE, stdout, CFSTR("\n")); - } - - if_dict = CFArrayGetValueAtIndex(if_list, i); - unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit)); - type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType)); - if (unit) { + SCNetworkInterfaceRef interface; + CFStringRef path; + CFNumberRef type; + CFNumberRef unit; + CFIndex where; + + interface = CFArrayGetValueAtIndex(if_list, i); + path = _SCNetworkInterfaceGetIOPath(interface); + type = _SCNetworkInterfaceGetIOInterfaceType(interface); + unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); + + if (unit != NULL) { if (S_debug) { - SCPrint(TRUE, stdout, CFSTR("Interface already has a unit number\n")); - displayInterface(if_dict); + CFStringRef if_name; + + if_name = SCNetworkInterfaceGetBSDName(interface); + if ((if_name == NULL) || !CFDictionaryContainsKey(S_state, if_name)) { + SCLog(TRUE, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": Interface already has a unit number")); + displayInterface(interface); + } } - replaceInterface(if_dict); - } - else { - CFDictionaryRef dbdict = NULL; - kern_return_t kr = KERN_SUCCESS; - CFStringRef path; - CFNumberRef unit = NULL; - - path = CFDictionaryGetValue(if_dict, CFSTR(kIOPathMatchKey)); - dbdict = lookupInterfaceByType(S_dblist, if_dict, NULL); - if (dbdict == NULL - && pathIsAirPort(path) == TRUE) { - dbdict = lookupAirPortInterface(S_dblist, NULL); + + // update the list of interfaces that were previously named + if ((S_prev_active_list != NULL) + && lookupInterfaceByAddress(S_prev_active_list, interface, &where) != NULL) { + CFArrayRemoveValueAtIndex(S_prev_active_list, where); } + } else { + CFDictionaryRef dbdict; + kern_return_t kr; + + dbdict = lookupInterfaceByAddress(S_dblist, interface, NULL); if (dbdict != NULL) { - unit = CFDictionaryGetValue(dbdict, - CFSTR(kIOInterfaceUnit)); + unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit)); CFRetain(unit); - } - else { - int if_type; - boolean_t is_builtin = FALSE; - int next_unit = 0; - - CFNumberGetValue(type, - kCFNumberIntType, &if_type); - if (if_type == IFT_ETHER) { /* ethernet */ - CFBooleanRef builtin; - - builtin = CFDictionaryGetValue(if_dict, - CFSTR(kIOBuiltin)); - if (builtin && CFBooleanGetValue(builtin)) { - is_builtin = TRUE; - next_unit = i_builtin++; - } - else { -#if defined(__ppc__) - /* skip over slots reserved for built-in ethernet interface(s) */ - next_unit = n_builtin; -#endif + + SCLog(S_debug, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (from database)"), + unit); + } else { + CFStringRef if_type; + + if_type = SCNetworkInterfaceGetInterfaceType(interface); + if ((if_type != NULL) && + CFEqual(if_type, kSCNetworkInterfaceTypeIEEE80211)) { + dbdict = lookupAirPortInterface(S_dblist, NULL); + if (dbdict != NULL) { + unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit)); + CFRetain(unit); + + SCLog(S_debug, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (updating database)"), + unit); } } - if (is_builtin == FALSE) { + } + + if ((dbdict != NULL) && (S_prev_active_list != NULL)) { + // update the list of interfaces that were previously named + where = CFArrayGetFirstIndexOfValue(S_prev_active_list, + CFRangeMake(0, CFArrayGetCount(S_prev_active_list)), + dbdict); + if (where != kCFNotFound) { + CFArrayRemoveValueAtIndex(S_prev_active_list, where); + } + } + + if (dbdict == NULL) { + boolean_t is_builtin; + int next_unit = 0; + + if (!isQuiet()) { + // if new interface, wait until quiet before naming + addTimestamp(S_state, path); + continue; + } + + is_builtin = _SCNetworkInterfaceIsBuiltin(interface); + next_unit = 0; + if (is_builtin) { + // built-in interface, use the reserved slots + next_unit = builtinCount(if_list, i, type); + } else { + // not built-in, skip over the reserved slots + next_unit = builtinCount(if_list, n, type); + unit = getHighestUnitForType(type); - if (unit) { + if (unit != NULL) { int high_unit; - CFNumberGetValue(unit, - kCFNumberIntType, &high_unit); + CFNumberGetValue(unit, kCFNumberIntType, &high_unit); if (high_unit >= next_unit) { next_unit = high_unit + 1; } } } - unit = CFNumberCreate(NULL, - kCFNumberIntType, &next_unit); - } - if (S_debug) { - SCPrint(TRUE, stdout, CFSTR("Interface assigned unit %@ %s\n"), unit, - dbdict ? "(from database)" : "(next available)"); + unit = CFNumberCreate(NULL, kCFNumberIntType, &next_unit); + + SCLog(S_debug, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (%s)"), + unit, + is_builtin ? "built-in" : "next available"); } + kr = registerInterface(S_connect, path, unit); if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME - ": failed to name the interface 0x%x"), + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": failed to name the interface, kr=0x%x"), kr); if (S_debug) { - displayInterface(if_dict); + displayInterface(interface); } - } - else { - CFDictionaryRef new_dict; + } else { + SCNetworkInterfaceRef new_interface; - path = CFDictionaryGetValue(if_dict, - CFSTR(kIOPathMatchKey)); - new_dict = lookupIOKitPath(path); - if (new_dict != NULL) { - CFNumberRef new_unit; + new_interface = lookupIOKitPath(path); + if (new_interface != NULL) { + CFNumberRef new_unit; - new_unit = CFDictionaryGetValue(new_dict, - CFSTR(kIOInterfaceUnit)); + new_unit = _SCNetworkInterfaceGetIOInterfaceUnit(new_interface); if (CFEqual(unit, new_unit) == FALSE) { - SCLog(TRUE, LOG_INFO, + SCLog(S_debug, LOG_INFO, CFSTR(MY_PLUGIN_NAME ": interface type %@ assigned " "unit %@ instead of %@"), type, new_unit, unit); } if (S_debug) { - displayInterface(new_dict); + displayInterface(new_interface); } - replaceInterface(new_dict); - CFRelease(new_dict); + + // update if_list (with the interface name & unit) + CFArraySetValueAtIndex(if_list, i, new_interface); + CFRelease(new_interface); + interface = new_interface; // if_list holds the reference } } + CFRelease(unit); } + + // update db + replaceInterface(interface); } - writeInterfaceList(S_dblist); return; } static void -interfaceArrivalCallback( void * refcon, io_iterator_t iter ) +updateInterfaces() { - CFMutableArrayRef if_list = NULL; - io_object_t obj; + if (S_connect == MACH_PORT_NULL) { + // if we don't have the "IONetworkStack" connect object + return; + } + if (S_iflist != NULL) { + CFIndex n; - while ((obj = IOIteratorNext(iter))) { - CFDictionaryRef dict; + n = CFArrayGetCount(S_iflist); + if (n > 1) { + CFArraySortValues(S_iflist, CFRangeMake(0, n), _SCNetworkInterfaceCompare, NULL); + } + nameInterfaces(S_iflist); + } + + if (isQuiet()) { + /* + * The registry [matching] has quiesced so let's + * - save the DB with the interfaces that have been named + * - update the VLAN/BOND configuration + * - tell everyone that we've finished (at least for now) + * - log those interfaces which are no longer present + * in the HW config (or have yet to show up). + */ + writeInterfaceList(S_dblist); + updateVirtualNetworkInterfaceConfiguration(NULL, kSCPreferencesNotificationApply, NULL); + updateStore(); + + if (S_iflist != NULL) { + CFRelease(S_iflist); + S_iflist = NULL; + } + + if (S_prev_active_list != NULL) { + if (S_debug) { + CFIndex i; + CFIndex n; - dict = getInterface(obj); - if (dict) { - if (if_list == NULL) { - if_list = CFArrayCreateMutable(NULL, 0, - &kCFTypeArrayCallBacks); + n = CFArrayGetCount(S_prev_active_list); + SCLog(TRUE, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": Interface%s not [yet] active"), + (n > 0) ? "s" : ""); + for (i = 0; i < n; i++) { + CFDictionaryRef if_dict; + CFStringRef name; + CFNumberRef type; + CFNumberRef unit; + + if_dict = CFArrayGetValueAtIndex(S_prev_active_list, i); + name = CFDictionaryGetValue(if_dict, CFSTR(kIOBSDNameKey)); + type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType)); + unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit)); + SCLog(TRUE, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": %s%@%sType: %@, Unit: %@"), + (name != NULL) ? "BSD Name: " : "", + (name != NULL) ? name : CFSTR(""), + (name != NULL) ? ", " : "", + type, + unit); + } } - if (if_list) - CFArrayAppendValue(if_list, dict); - CFRelease(dict); + CFRelease(S_prev_active_list); + S_prev_active_list = NULL; } - IOObjectRelease(obj); + } else { + if ((S_prev_active_list != NULL) && (CFArrayGetCount(S_prev_active_list) == 0)) { + /* + * if we've named all of the interfaces that + * were used during the previous boot. + */ + addTimestamp(S_state, CFSTR("*RELEASE*")); + SCLog(S_debug, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": last boot interfaces have been named")); + updateStore(); + CFRelease(S_prev_active_list); + S_prev_active_list = NULL; + } + } + + return; +} + +static CFComparisonResult +compareMacAddress(const void *val1, const void *val2, void *context) +{ + CFDataRef mac1 = (CFDataRef)val1; + CFDataRef mac2 = (CFDataRef)val2; + CFIndex n1; + CFIndex n2; + CFComparisonResult res; + + n1 = CFDataGetLength(mac1); + n2 = CFDataGetLength(mac2); + if (n1 < n2) { + res = kCFCompareLessThan; + } else if (n2 > n1) { + res = kCFCompareGreaterThan; + } else { + res = bcmp(CFDataGetBytePtr(mac1), CFDataGetBytePtr(mac2), n1); + } + + return res; +} + +static void +updatePlatformUUID() +{ + CFDataRef addr; + CFMutableArrayRef addrs = NULL; + CFStringRef guid; + CFIndex i; + CFIndex n; + io_registry_entry_t platform; + + platform = IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreePlane ":/"); + if (platform == MACH_PORT_NULL) { + return; + } + + guid = IORegistryEntryCreateCFProperty(platform, CFSTR(kIOPlatformUUIDKey), NULL, 0); + if (guid != NULL) { + // if GUID already defined + goto done; } - if (if_list) { - sort_interfaces_by_path(if_list); - name_interfaces(if_list); - updateBondConfiguration(); - updateVLANConfiguration(); - CFRelease(if_list); + + addrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + n = (S_dblist != NULL) ? CFArrayGetCount(S_dblist) : 0; + for (i = 0; i < n; i++) { + CFBooleanRef builtin; + CFDictionaryRef dict; + CFStringRef type; + + dict = CFArrayGetValueAtIndex(S_dblist, i); + type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType)); + if (!isA_CFString(type) || !CFEqual(type, kSCNetworkInterfaceTypeEthernet)) { + continue; + } + builtin = CFDictionaryGetValue(dict, CFSTR(kIOBuiltin)); + if (!isA_CFBoolean(builtin) || !CFBooleanGetValue(builtin)) { + continue; + } + addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); + if (!isA_CFData(addr) || (CFDataGetLength(addr) != ETHER_ADDR_LEN)) { + continue; + } + CFArrayAppendValue(addrs, addr); + } + + if (CFArrayGetCount(addrs) == 0) { + // if no ethernet interfaces, look for wireless + for (i = 0; i < n; i++) { + CFDictionaryRef dict; + CFStringRef type; + + dict = CFArrayGetValueAtIndex(S_dblist, i); + type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType)); + if (!isA_CFString(type) || !CFEqual(type, kSCNetworkInterfaceTypeIEEE80211)) { + continue; + } + addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); + if (!isA_CFData(addr) || (CFDataGetLength(addr) != ETHER_ADDR_LEN)) { + continue; + } + CFArrayAppendValue(addrs, addr); + } + } + + n = CFArrayGetCount(addrs); + switch (n) { + case 0 : + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": no network interfaces, could not update platform UUID")); + break; + default : + // sort by MAC address + CFArraySortValues(addrs, CFRangeMake(0, n), compareMacAddress, NULL); + + // fall through + case 1 : { + CFUUIDBytes bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + kern_return_t kr; + CFUUIDRef uuid; + + // set GUID + addr = CFArrayGetValueAtIndex(addrs, 0); + bcopy(CFDataGetBytePtr(addr), + (void *)&bytes + sizeof(bytes) - ETHER_ADDR_LEN, + ETHER_ADDR_LEN); + uuid = CFUUIDCreateFromUUIDBytes(NULL, bytes); + guid = CFUUIDCreateString(NULL, uuid); + CFRelease(uuid); + + SCLog(TRUE, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": setting platform UUID = %@"), + guid); + kr = IORegistryEntrySetCFProperty(platform, CFSTR(kIOPlatformUUIDKey), guid); + if (kr != KERN_SUCCESS) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"), + kr); + } + + addTimestamp(S_state, CFSTR("*PLATFORM-UUID*")); + updateStore(); + break; + } } + + done : + + if (addrs != NULL) CFRelease(addrs); + if (platform != MACH_PORT_NULL) IOObjectRelease(platform); + if (guid != NULL) CFRelease(guid); return; } +static void +interfaceArrivalCallback(void *refcon, io_iterator_t iter) +{ + io_object_t obj; -__private_extern__ -void -load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose) + while ((obj = IOIteratorNext(iter)) != MACH_PORT_NULL) { + SCNetworkInterfaceRef interface; + + interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj); + if (interface != NULL) { + if (S_iflist == NULL) { + S_iflist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + CFArrayAppendValue(S_iflist, interface); + CFRelease(interface); + } + IOObjectRelease(obj); + } + + updateInterfaces(); + return; +} + +/* + * Function: stackCallback + * Purpose: + * Get a reference to the single IONetworkStack object instance in + * the kernel. Naming requests must be sent to this object, which is + * attached as a client to all network interface objects in the system. + * Note: + * Call IOObjectRelease on the returned object. + */ +static void +stackCallback(void *refcon, io_iterator_t iter) { kern_return_t kr; - mach_port_t masterPort = MACH_PORT_NULL; - io_object_t stack = MACH_PORT_NULL; + io_object_t stack; - if (bundleVerbose) { - S_debug++; + stack = IOIteratorNext(iter); + if (stack == MACH_PORT_NULL) { + goto error; } - kr = IOMasterPort(bootstrap_port, &masterPort); + kr = IOServiceOpen(stack, mach_task_self(), 0, &S_connect); if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"), + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": IOServiceOpen returned 0x%x"), kr); goto error; } - /* synchronize with any drivers that might be loading at boot time */ - waitForQuiet(masterPort); + addTimestamp(S_state, CFSTR("*STACK*")); + SCLog(S_debug, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": IONetworkStack found")); - stack = createNetworkStackObject(masterPort); - if (stack == MACH_PORT_NULL) { - SCLog(TRUE, LOG_INFO, + if (S_stack != MACH_PORT_NULL) { + IOObjectRelease(S_stack); + S_stack = MACH_PORT_NULL; + } + + updateInterfaces(); + + error: + if (stack != MACH_PORT_NULL) { + IOObjectRelease(stack); + } + + return; +} + +static void +quietCallback(void *refcon, + io_service_t service, + natural_t messageType, + void *messageArgument) +{ + if (messageArgument != NULL) { + // if not yet quiet + return; + } + + if (messageType == kIOMessageServiceBusyStateChange) { + addTimestamp(S_state, CFSTR("*QUIET*")); + SCLog(S_debug, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": IOKit quiet")); + } + + if (S_connect == MACH_PORT_NULL) { + SCLog(TRUE, LOG_ERR, CFSTR(MY_PLUGIN_NAME ": No network stack object")); - goto error; + return; } - kr = IOServiceOpen(stack, mach_task_self(), 0, &S_connect); - if (kr != KERN_SUCCESS) { - SCPrint(TRUE, stdout, CFSTR(MY_PLUGIN_NAME ": IOServiceOpen returned 0x%x\n"), kr); - goto error; + + if (S_quiet != MACH_PORT_NULL) { + IOObjectRelease(S_quiet); + S_quiet = MACH_PORT_NULL; + } + + if (S_timer != NULL) { + CFRunLoopTimerInvalidate(S_timer); + CFRelease(S_timer); + S_timer = NULL; + } + + // grab (and name) any additional interfaces. + interfaceArrivalCallback((void *)S_notify, S_iter); + + updatePlatformUUID(); + + return; +} + +static void +iterateRegistryBusy(io_iterator_t iterator, CFArrayRef nodes, int *count) +{ + kern_return_t kr = kIOReturnSuccess;; + io_object_t obj; + + while ((kr == kIOReturnSuccess) && + ((obj = IOIteratorNext(iterator)) != MACH_PORT_NULL)) { + uint32_t busy; + io_name_t location; + io_name_t name; + CFMutableArrayRef newNodes; + CFMutableStringRef str = NULL; + + if (nodes == NULL) { + newNodes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } else { + newNodes = CFArrayCreateMutableCopy(NULL, 0, nodes); + } + + kr = IORegistryEntryGetName(obj, name); + if (kr != kIOReturnSuccess) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": reportBusy IORegistryEntryGetName returned 0x%x"), + kr); + goto next; + } + + str = CFStringCreateMutable(NULL, 0); + CFStringAppendCString(str, name, kCFStringEncodingUTF8); + + kr = IORegistryEntryGetLocationInPlane(obj, kIOServicePlane, location); + switch (kr) { + case kIOReturnSuccess : + CFStringAppendCString(str, "@", kCFStringEncodingUTF8); + CFStringAppendCString(str, location, kCFStringEncodingUTF8); + break; + case kIOReturnNotFound : + break; + default : + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": reportBusy IORegistryEntryGetLocationInPlane returned 0x%x"), + kr); + goto next; + break; + } + + CFArrayAppendValue(newNodes, str); + CFRelease(str); + + kr = IOServiceGetBusyState(obj, &busy); + if (kr != kIOReturnSuccess) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": reportBusy IOServiceGetBusyState returned 0x%x"), + kr); + goto next; + } + + if (busy != 0) { + CFStringRef path; + + if ((*count)++ == 0) { + SCLog(TRUE, LOG_WARNING, CFSTR(MY_PLUGIN_NAME ": Busy services :")); + } + + path = CFStringCreateByCombiningStrings(NULL, newNodes, CFSTR("/")); + SCLog(TRUE, LOG_WARNING, CFSTR(MY_PLUGIN_NAME ": %@ [%d]"), path, busy); + CFRelease(path); + } + + kr = IORegistryIteratorEnterEntry(iterator); + if (kr != kIOReturnSuccess) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": reportBusy IORegistryIteratorEnterEntry returned 0x%x"), + kr); + goto next; + } + + iterateRegistryBusy(iterator, newNodes, count); + + kr = IORegistryIteratorExitEntry(iterator); + if (kr != kIOReturnSuccess) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": reportBusy IORegistryIteratorExitEntry returned 0x%x"), + kr); + } + + next : + + CFRelease(newNodes); + IOObjectRelease(obj); + } + + return; +} + +static void +reportBusy() +{ + int count = 0; + io_iterator_t iterator = MACH_PORT_NULL; + kern_return_t kr; + + kr = IORegistryCreateIterator(kIOMasterPortDefault, + kIOServicePlane, + 0, + &iterator); + if (kr != kIOReturnSuccess) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": reportBusy IORegistryCreateIterator returned 0x%x"), + kr); + return; + } + + iterateRegistryBusy(iterator, NULL, &count); + SCLog((count == 0), LOG_WARNING, + CFSTR(MY_PLUGIN_NAME ": w/no busy services")); + IOObjectRelease(iterator); + return; +} + +static void +timerCallback(CFRunLoopTimerRef timer, void *info) +{ + /* + * We've been waiting for IOKit to quiesce and it just + * hasn't happenned. Time to just move on! + */ + addTimestamp(S_state, CFSTR("*TIMEOUT*")); + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": timed out waiting for IOKit to quiesce")); + + reportBusy(); + quietCallback((void *)S_notify, MACH_PORT_NULL, 0, NULL); + return; +} + +static Boolean +setup_IOKit(CFBundleRef bundle) +{ + uint32_t busy; + CFDictionaryRef dict; + kern_return_t kr; + mach_port_t masterPort = MACH_PORT_NULL; + Boolean ok = FALSE; + io_object_t root = MACH_PORT_NULL; + double timeout = WAIT_QUIET_TIMEOUT_DEFAULT; + + // read DB of previously named network interfaces + S_dblist = readInterfaceList(); + if (S_dblist != NULL) { + CFIndex n; + + n = CFArrayGetCount(S_dblist); + if (n > 1) { + CFArraySortValues(S_dblist, CFRangeMake(0, n), if_unit_compare, NULL); + } } + // get interfaces that were named during the last boot + S_prev_active_list = previouslyActiveInterfaces(); + + // track how long we've waited to see each interface. + S_state = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + addTimestamp(S_state, CFSTR("*START*")); + // Creates and returns a notification object for receiving IOKit // notifications of new devices or state changes. + kr = IOMasterPort(bootstrap_port, &masterPort); + if (kr != KERN_SUCCESS) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"), + kr); + goto done; + } S_notify = IONotificationPortCreate(masterPort); if (S_notify == NULL) { - SCLog(TRUE, LOG_INFO, + SCLog(TRUE, LOG_ERR, CFSTR(MY_PLUGIN_NAME ": IONotificationPortCreate failed")); - goto error; + goto done; + } + + // watch IOKit matching activity + root = IORegistryEntryFromPath(masterPort, kIOServicePlane ":/"); + if (root == MACH_PORT_NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": IORegistryEntryFromPath failed")); + goto done; + } + + kr = IOServiceAddInterestNotification(S_notify, + root, + kIOBusyInterest, + &quietCallback, + (void *)S_notify, // refCon + &S_quiet); // notification + if (kr != KERN_SUCCESS) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": IOServiceAddInterestNotification returned 0x%x"), + kr); + goto done; + } + + kr = IOServiceGetBusyState(root, &busy); + if (kr != KERN_SUCCESS) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": IOServiceGetBusyState returned 0x%x"), + kr); + goto done; } + + // add a timer so we don't wait forever for IOKit to quiesce + dict = CFBundleGetInfoDictionary(bundle); + if (isA_CFDictionary(dict)) { + CFNumberRef num; + + num = CFDictionaryGetValue(dict, CFSTR(WAIT_QUIET_TIMEOUT_KEY)); + if (num != NULL) { + if (!isA_CFNumber(num) || + !CFNumberGetValue(num, kCFNumberDoubleType, &timeout) || + (timeout <= 0.0)) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": " WAIT_QUIET_TIMEOUT_KEY " value error")); + timeout = WAIT_QUIET_TIMEOUT_DEFAULT; + } + } + } + S_timer = CFRunLoopTimerCreate(NULL, + CFAbsoluteTimeGetCurrent() + timeout, + 0, + 0, + 0, + timerCallback, + NULL); + if (S_timer == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": CFRunLoopTimerCreate failed")); + goto done; + } + + CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, kCFRunLoopDefaultMode); + + // watch for the introduction of the IONetworkStack + kr = IOServiceAddMatchingNotification(S_notify, + kIOFirstMatchNotification, + IOServiceMatching("IONetworkStack"), + &stackCallback, + (void *)S_notify, // refCon + &S_stack); // notification + if (kr != KERN_SUCCESS) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": IOServiceAddMatchingNotification returned 0x%x"), + kr); + goto done; + } + + // check and see if the stack is already available and arm the + // notification for its introduction. + stackCallback((void *)S_notify, S_stack); + + // watch for the introduction of new network interfaces kr = IOServiceAddMatchingNotification(S_notify, kIOFirstMatchNotification, IOServiceMatching("IONetworkInterface"), &interfaceArrivalCallback, - (void *) S_notify, /* refCon */ - &S_iter ); /* notification */ - + (void *)S_notify, // refCon + &S_iter); // notification if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME - ": IOServiceAddMatchingNotification returned 0x%x"), + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": IOServiceAddMatchingNotification returned 0x%x"), kr); - goto error; + goto done; } - S_dblist = readInterfaceList(); - if (S_dblist) { - sort_interfaces_by_unit(S_dblist); - } - // Get the current list of matches and arms the notification for + // Get the current list of matches and arm the notification for // future interface arrivals. + interfaceArrivalCallback((void *)S_notify, S_iter); - interfaceArrivalCallback((void *) S_notify, S_iter); + // Check if IOKit has already quiesced. + quietCallback((void *)S_notify, + MACH_PORT_NULL, + kIOMessageServiceBusyStateChange, + (void *)busy); CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(S_notify), kCFRunLoopDefaultMode); - if (stack != MACH_PORT_NULL) { - IOObjectRelease(stack); + +#ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET + /* + * Start the wheels turning until we've named all of + * the interfaces that were used during the previous + * boot, until IOKit [matching] has quiesced, or + * until we've waited long enough. + */ + CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, MY_PLUGIN_ID); + CFRunLoopAddSource(CFRunLoopGetCurrent(), + IONotificationPortGetRunLoopSource(S_notify), + MY_PLUGIN_ID); + while (S_prev_active_list != NULL) { + int rlStatus; + + rlStatus = CFRunLoopRunInMode(MY_PLUGIN_ID, 1.0e10, TRUE); + } +#endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */ + + ok = TRUE; + + done: + if (root != MACH_PORT_NULL) { + IOObjectRelease(root); } if (masterPort != MACH_PORT_NULL) { mach_port_deallocate(mach_task_self(), masterPort); } - return; - error: - if (stack != MACH_PORT_NULL) { - IOObjectRelease(stack); + + return ok; +} + +static Boolean +setup_Virtual(CFBundleRef bundle) +{ + // open a SCPreferences session + S_prefs = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME), NULL); + if (S_prefs == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate() failed: %s"), + SCErrorString(SCError())); + return FALSE; } - if (masterPort != MACH_PORT_NULL) { - mach_port_deallocate(mach_task_self(), masterPort); + + // register for change notifications. + if (!SCPreferencesSetCallback(S_prefs, updateVirtualNetworkInterfaceConfiguration, NULL)) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetCallBack() failed: %s"), + SCErrorString(SCError())); + CFRelease(S_prefs); + return FALSE; + } + + // schedule + if (!SCPreferencesScheduleWithRunLoop(S_prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": SCPreferencesScheduleWithRunLoop() failed: %s"), + SCErrorString(SCError())); + CFRelease(S_prefs); + return FALSE; + } + + return TRUE; +} + +__private_extern__ +void +load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose) +{ + if (bundleVerbose) { + S_debug = TRUE; + } + + // setup virtual network interface monitoring + if (!setup_Virtual(bundle)) { + goto error; + } + + // setup [IOKit] network interface monitoring + if (!setup_IOKit(bundle)) { + goto error; } + + return; + + error : if (S_connect != MACH_PORT_NULL) { IOServiceClose(S_connect); S_connect = MACH_PORT_NULL; } + if (S_dblist != NULL) { + CFRelease(S_dblist); + S_dblist = NULL; + } if (S_iter != MACH_PORT_NULL) { IOObjectRelease(S_iter); S_iter = MACH_PORT_NULL; @@ -1413,6 +1773,24 @@ load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose) if (S_notify != MACH_PORT_NULL) { IONotificationPortDestroy(S_notify); } + if (S_quiet != MACH_PORT_NULL) { + IOObjectRelease(S_quiet); + S_quiet = MACH_PORT_NULL; + } + if (S_stack != MACH_PORT_NULL) { + IOObjectRelease(S_stack); + S_stack = MACH_PORT_NULL; + } + if (S_state != NULL) { + CFRelease(S_state); + S_state = NULL; + } + if (S_timer != NULL) { + CFRunLoopTimerInvalidate(S_timer); + CFRelease(S_timer); + S_timer = NULL; + } + return; } @@ -1422,11 +1800,47 @@ load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose) int main(int argc, char ** argv) { - load_InterfaceNamer(CFBundleGetMainBundle(), - (argc > 1) ? TRUE : FALSE); + _sc_log = FALSE; + _sc_verbose = (argc > 1) ? TRUE : FALSE; + + load_InterfaceNamer(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE); CFRunLoopRun(); /* not reached */ exit(0); return 0; } #endif /* MAIN */ + +#ifdef TEST_PLATFORM_UUID +int +main(int argc, char ** argv) +{ + CFArrayRef interfaces; + + _sc_log = FALSE; + _sc_verbose = (argc > 1) ? TRUE : FALSE; + + S_dblist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + interfaces = SCNetworkInterfaceCopyAll(); + if (interfaces != NULL) { + CFIndex i; + CFIndex n; + + n = CFArrayGetCount(interfaces); + for (i = 0; i < n; i++) { + CFDictionaryRef dict; + SCNetworkInterfaceRef interface; + + interface = CFArrayGetValueAtIndex(interfaces, i); + dict = createInterfaceDict(interface); + CFArrayAppendValue(S_dblist, dict); + CFRelease(dict); + } + CFRelease(interfaces); + } + updatePlatformUUID(); + CFRelease(S_dblist); + exit(0); + return 0; +} +#endif /* TEST_PLATFORM_UUID */