/*
- * Copyright (c) 2001-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2001-2007 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
/*
* Modification History
*
+ * November 6, 2006 Allan Nathanson <ajn@apple.com>
+ * Dan Markarian <markarian@apple.com>
+ * Dieter Siegmund <dieter@apple.com>
+ * - updated code to name interfaces quicker (without need for
+ * calling IOKitWaitQuiet).
+ *
* October 3, 2003 Allan Nathanson <ajn@apple.com>
* - sort new interfaces by IOKit path (rather than MAC address) to
* help facilitate a more predictable interface-->name mapping for
#include <sys/stat.h>
#include <sys/param.h>
#include <mach/mach.h>
+#include <net/ethernet.h>
#include <net/if_types.h>
#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
#include <SystemConfiguration/SCValidation.h>
-#include <SystemConfiguration/BondConfiguration.h>
-#include <SystemConfiguration/BondConfigurationPrivate.h>
-
-#include <SystemConfiguration/VLANConfiguration.h>
-#include <SystemConfiguration/VLANConfigurationPrivate.h>
-
#include <IOKit/IOKitLib.h>
#include <IOKit/IOBSD.h>
+#include <IOKit/IOMessage.h>
#include <IOKit/network/IONetworkController.h>
#include <IOKit/network/IONetworkInterface.h>
#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
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)
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;
{
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) {
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);
}
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;
}
}
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;
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);
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);
}
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;
}
{
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)
}
}
}
+
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;
_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) {
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;
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;
}
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 */