SCNetworkInterface.c [plain text]
#include <Availability.h>
#include <TargetConditionals.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFRuntime.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include "SCNetworkConfigurationInternal.h"
#include <SystemConfiguration/SCValidation.h>
#include <SystemConfiguration/SCPrivate.h>
#include "SCPreferencesInternal.h"
#include "SCHelper_client.h"
#if !TARGET_OS_IPHONE
#include <EAP8021X/EAPClientProperties.h>
#else // !TARGET_OS_IPHONE
#ifndef kEAPClientPropUserName
#define kEAPClientPropUserName CFSTR("UserName")
#endif
#ifndef kEAPClientPropUserPasswordKeychainItemID
#define kEAPClientPropUserPasswordKeychainItemID CFSTR("UserPasswordKeychainItemID")
#endif
#endif // !TARGET_OS_IPHONE
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFBundle.h>
#include <IOKit/IOBSD.h>
#include <IOKit/network/IONetworkController.h>
#include <IOKit/network/IONetworkInterface.h>
#include <IOKit/network/IOEthernetInterface.h> // for kIOEthernetInterfaceClass
#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
#include <IOKit/usb/USB.h>
#include "dy_framework.h"
#ifndef kIODeviceSupportsHoldKey
#define kIODeviceSupportsHoldKey "V92Modem"
#endif
#ifndef kUSBProductString
#define kUSBProductString "USB Product Name"
#endif
#include <string.h>
#include <mach/mach.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <pthread.h>
#include <NSSystemDirectories.h>
static CFStringRef copy_interface_string (CFBundleRef bundle, CFStringRef key, Boolean localized);
static CFStringRef __SCNetworkInterfaceCopyDescription (CFTypeRef cf);
static void __SCNetworkInterfaceDeallocate (CFTypeRef cf);
static Boolean __SCNetworkInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2);
static CFHashCode __SCNetworkInterfaceHash (CFTypeRef cf);
enum {
kSortInternalModem,
kSortUSBModem,
kSortModem,
kSortBluetooth,
kSortIrDA,
kSortSerialPort,
kSortWWAN,
kSortEthernetPPP,
kSortAirportPPP,
kSortEthernet,
kSortFireWire,
kSortAirPort,
kSortOtherWireless,
kSortTethered,
kSortWWANEthernet,
kSortBluetoothPAN,
#if !TARGET_OS_IPHONE
kSortBond,
kSortVLAN,
#endif // !TARGET_OS_IPHONE
kSortUnknown
};
const CFStringRef kSCNetworkInterfaceType6to4 = CFSTR("6to4");
const CFStringRef kSCNetworkInterfaceTypeBluetooth = CFSTR("Bluetooth");
#if !TARGET_OS_IPHONE
const CFStringRef kSCNetworkInterfaceTypeBond = CFSTR("Bond");
#endif // !TARGET_OS_IPHONE
const CFStringRef kSCNetworkInterfaceTypeEthernet = CFSTR("Ethernet");
const CFStringRef kSCNetworkInterfaceTypeFireWire = CFSTR("FireWire");
const CFStringRef kSCNetworkInterfaceTypeIEEE80211 = CFSTR("IEEE80211"); const CFStringRef kSCNetworkInterfaceTypeIPSec = CFSTR("IPSec");
const CFStringRef kSCNetworkInterfaceTypeIrDA = CFSTR("IrDA");
const CFStringRef kSCNetworkInterfaceTypeL2TP = CFSTR("L2TP");
const CFStringRef kSCNetworkInterfaceTypeModem = CFSTR("Modem");
const CFStringRef kSCNetworkInterfaceTypePPP = CFSTR("PPP");
const CFStringRef kSCNetworkInterfaceTypePPTP = CFSTR("PPTP");
const CFStringRef kSCNetworkInterfaceTypeSerial = CFSTR("Serial");
#if !TARGET_OS_IPHONE
const CFStringRef kSCNetworkInterfaceTypeVLAN = CFSTR("VLAN");
#endif // !TARGET_OS_IPHONE
const CFStringRef kSCNetworkInterfaceTypeWWAN = CFSTR("WWAN");
const CFStringRef kSCNetworkInterfaceTypeIPv4 = CFSTR("IPv4");
static SCNetworkInterfacePrivate __kSCNetworkInterfaceIPv4 = {
INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, FALSE, NULL, NULL, NULL, NULL, FALSE, NULL, NULL, kSortUnknown, #if !TARGET_OS_IPHONE
FALSE, { NULL, NULL}, FALSE, { NULL, NULL, NULL } #endif // !TARGET_OS_IPHONE
};
const SCNetworkInterfaceRef kSCNetworkInterfaceIPv4 = (SCNetworkInterfaceRef)&__kSCNetworkInterfaceIPv4;
#pragma mark -
#pragma mark SCNetworkInterface configuration details
#define doNone 0
#define do6to4 1<<0
#define doL2TP 1<<1
#define doPPP 1<<2
#define doPPTP 1<<3
#define doIPSec 1<<4
#define doOverIP do6to4|doL2TP|doPPTP|doIPSec
#if !TARGET_OS_IPHONE
#define doAppleTalk 1<<0
#else // !TARGET_OS_IPHONE
#define doAppleTalk 0
#endif // !TARGET_OS_IPHONE
#define doDNS 1<<1
#define doIPv4 1<<2
#define doIPv6 1<<3
#define doProxies 1<<4
#if !TARGET_OS_IPHONE
#define doSMB 1<<5
#else // !TARGET_OS_IPHONE
#define doSMB 0
#endif // !TARGET_OS_IPHONE
static const struct {
const CFStringRef *interface_type;
const CFStringRef *entity_hardware;
Boolean per_interface_config;
uint32_t supported_interfaces;
const CFStringRef *ppp_subtype;
uint32_t supported_protocols;
} configurations[] = {
{ &kSCNetworkInterfaceType6to4 , &kSCEntNet6to4 , FALSE, doNone, NULL, doIPv6 },
{ &kSCNetworkInterfaceTypeBluetooth , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
#if !TARGET_OS_IPHONE
{ &kSCNetworkInterfaceTypeBond , &kSCEntNetEthernet, TRUE , doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB },
#endif // !TARGET_OS_IPHONE
{ &kSCNetworkInterfaceTypeEthernet , &kSCEntNetEthernet, TRUE , doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB },
{ &kSCNetworkInterfaceTypeFireWire , &kSCEntNetFireWire, TRUE , doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB },
{ &kSCNetworkInterfaceTypeIEEE80211 , &kSCEntNetAirPort , TRUE , doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB },
{ &kSCNetworkInterfaceTypeIPSec , &kSCEntNetIPSec , FALSE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB },
{ &kSCNetworkInterfaceTypeIrDA , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
{ &kSCNetworkInterfaceTypeL2TP , NULL , FALSE, doPPP, &kSCValNetInterfaceSubTypeL2TP, doNone },
{ &kSCNetworkInterfaceTypeModem , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
{ &kSCNetworkInterfaceTypePPP , &kSCEntNetPPP , FALSE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB },
{ &kSCNetworkInterfaceTypePPTP , NULL , FALSE, doPPP, &kSCValNetInterfaceSubTypePPTP, doNone },
{ &kSCNetworkInterfaceTypeSerial , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
#if !TARGET_OS_IPHONE
{ &kSCNetworkInterfaceTypeVLAN , &kSCEntNetEthernet, TRUE , doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB },
#endif // !TARGET_OS_IPHONE
{ &kSCNetworkInterfaceTypeWWAN , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
{ &kSCNetworkInterfaceTypeIPv4 , NULL , FALSE, doOverIP, NULL, doNone }
};
#define NETWORKINTERFACE_LOCALIZATIONS CFSTR("NetworkInterface")
static CFBundleRef bundle = NULL;
static CFTypeID __kSCNetworkInterfaceTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __SCNetworkInterfaceClass = {
0, "SCNetworkInterface", NULL, NULL, __SCNetworkInterfaceDeallocate, __SCNetworkInterfaceEqual, __SCNetworkInterfaceHash, NULL, __SCNetworkInterfaceCopyDescription };
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static pthread_once_t iokit_quiet = PTHREAD_ONCE_INIT;
static mach_port_t masterPort = MACH_PORT_NULL;
static CFStringRef
__SCNetworkInterfaceCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)cf;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkInterface %p [%p]> {"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR("type = %@"), interfacePrivate->interface_type);
CFStringAppendFormat(result, NULL, CFSTR(", entity_device = %@"), interfacePrivate->entity_device);
if (interfacePrivate->entity_device_unique != NULL) {
CFStringAppendFormat(result, NULL, CFSTR("+%@"), interfacePrivate->entity_device_unique);
}
CFStringAppendFormat(result, NULL, CFSTR(", entity_type = %@"), interfacePrivate->entity_type);
if (interfacePrivate->entity_subtype != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(" / %@"), interfacePrivate->entity_subtype);
}
if (interfacePrivate->name != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), interfacePrivate->name);
}
if (interfacePrivate->localized_name != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", name(l) = %@"), interfacePrivate->localized_name);
} else {
if (interfacePrivate->localized_key != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", name(k) = \"%@\""), interfacePrivate->localized_key);
if (interfacePrivate->localized_arg1 != NULL) {
CFStringAppendFormat(result, NULL, CFSTR("+\"%@\""), interfacePrivate->localized_arg1);
}
if (interfacePrivate->localized_arg2 != NULL) {
CFStringAppendFormat(result, NULL, CFSTR("+\"%@\""), interfacePrivate->localized_arg2);
}
}
}
if (interfacePrivate->address != NULL) {
const uint8_t *data;
CFIndex dataLen;
CFIndex i;
CFStringAppendFormat(result, NULL, CFSTR(", address = 0x"));
data = CFDataGetBytePtr(interfacePrivate->address);
dataLen = CFDataGetLength(interfacePrivate->address);
for (i = 0; i < dataLen; i++) {
CFStringAppendFormat(result, NULL, CFSTR("%02x"), data[i]);
}
}
CFStringAppendFormat(result, NULL, CFSTR(", builtin = %s"), interfacePrivate->builtin ? "TRUE" : "FALSE");
if (interfacePrivate->modemIsV92) {
CFStringAppendFormat(result, NULL, CFSTR(", v.92"));
}
if (interfacePrivate->location != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", location = %@"), interfacePrivate->location);
}
if (interfacePrivate->type != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", type = %@"), interfacePrivate->type);
}
if (interfacePrivate->unit != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", unit = %@"), interfacePrivate->unit);
}
if (interfacePrivate->path != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", path = %@"), interfacePrivate->path);
}
if (interfacePrivate->configurationAction != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", action = %@"), interfacePrivate->configurationAction);
}
if (interfacePrivate->overrides != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", overrides = %p"), interfacePrivate->overrides);
}
CFStringAppendFormat(result, NULL, CFSTR(", order = %d"), interfacePrivate->sort_order);
if (interfacePrivate->prefs != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), interfacePrivate->prefs);
}
if (interfacePrivate->serviceID != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", service = %@"), interfacePrivate->serviceID);
}
if (interfacePrivate->interface != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", interface = %@"), interfacePrivate->interface);
}
if (interfacePrivate->unsaved != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", unsaved = %@"), interfacePrivate->unsaved);
}
#if !TARGET_OS_IPHONE
if (interfacePrivate->bond.interfaces != NULL) {
CFIndex i;
CFIndex n;
n = CFArrayGetCount(interfacePrivate->bond.interfaces);
for (i = 0; i < n; i++) {
SCNetworkInterfaceRef member;
member = CFArrayGetValueAtIndex(interfacePrivate->bond.interfaces, i);
CFStringAppendFormat(result, NULL,
CFSTR("%s%@"),
(i == 0) ? ", interfaces = " : ", ",
SCNetworkInterfaceGetBSDName(member));
}
}
if (interfacePrivate->bond.mode != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", mode = %@"), interfacePrivate->bond.mode);
}
if (interfacePrivate->bond.options != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", options = %@"), interfacePrivate->bond.options);
}
if (interfacePrivate->bond.mode != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", mode = %@"), interfacePrivate->bond.mode);
}
if (interfacePrivate->vlan.interface != NULL) {
CFStringAppendFormat(result, NULL,
CFSTR(", interface = %@"),
SCNetworkInterfaceGetBSDName(interfacePrivate->vlan.interface));
}
if (interfacePrivate->vlan.tag != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", tag = %@"), interfacePrivate->vlan.tag);
}
if (interfacePrivate->vlan.options != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", options = %@"), interfacePrivate->vlan.options);
}
#endif // !TARGET_OS_IPHONE
CFStringAppendFormat(result, NULL, CFSTR("}"));
return result;
}
static void
__SCNetworkInterfaceDeallocate(CFTypeRef cf)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)cf;
if (interfacePrivate->interface != NULL)
CFRelease(interfacePrivate->interface);
if (interfacePrivate->name != NULL)
CFRelease(interfacePrivate->name);
if (interfacePrivate->localized_name != NULL)
CFRelease(interfacePrivate->localized_name);
if (interfacePrivate->localized_arg1 != NULL)
CFRelease(interfacePrivate->localized_arg1);
if (interfacePrivate->localized_arg2 != NULL)
CFRelease(interfacePrivate->localized_arg2);
if (interfacePrivate->prefs != NULL)
CFRelease(interfacePrivate->prefs);
if (interfacePrivate->serviceID != NULL)
CFRelease(interfacePrivate->serviceID);
if (interfacePrivate->unsaved != NULL)
CFRelease(interfacePrivate->unsaved);
if (interfacePrivate->entity_device != NULL)
CFRelease(interfacePrivate->entity_device);
if (interfacePrivate->entity_device_unique != NULL)
CFRelease(interfacePrivate->entity_device_unique);
if (interfacePrivate->supported_interface_types != NULL)
CFRelease(interfacePrivate->supported_interface_types);
if (interfacePrivate->supported_protocol_types != NULL)
CFRelease(interfacePrivate->supported_protocol_types);
if (interfacePrivate->address != NULL)
CFRelease(interfacePrivate->address);
if (interfacePrivate->addressString != NULL)
CFRelease(interfacePrivate->addressString);
if (interfacePrivate->location != NULL)
CFRelease(interfacePrivate->location);
if (interfacePrivate->path != NULL)
CFRelease(interfacePrivate->path);
if (interfacePrivate->configurationAction != NULL)
CFRelease(interfacePrivate->configurationAction);
if (interfacePrivate->overrides != NULL)
CFRelease(interfacePrivate->overrides);
if (interfacePrivate->type != NULL)
CFRelease(interfacePrivate->type);
if (interfacePrivate->unit != NULL)
CFRelease(interfacePrivate->unit);
#if !TARGET_OS_IPHONE
if (interfacePrivate->bond.interfaces != NULL)
CFRelease(interfacePrivate->bond.interfaces);
if (interfacePrivate->bond.mode != NULL)
CFRelease(interfacePrivate->bond.mode);
if (interfacePrivate->bond.options != NULL)
CFRelease(interfacePrivate->bond.options);
if (interfacePrivate->vlan.interface != NULL)
CFRelease(interfacePrivate->vlan.interface);
if (interfacePrivate->vlan.tag != NULL)
CFRelease(interfacePrivate->vlan.tag);
if (interfacePrivate->vlan.options != NULL)
CFRelease(interfacePrivate->vlan.options);
#endif // !TARGET_OS_IPHONE
return;
}
static Boolean
__SCNetworkInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2)
{
SCNetworkInterfacePrivateRef if1 = (SCNetworkInterfacePrivateRef)cf1;
SCNetworkInterfacePrivateRef if2 = (SCNetworkInterfacePrivateRef)cf2;
if (if1 == if2)
return TRUE;
if (!CFEqual(if1->interface_type, if2->interface_type)) {
return FALSE; }
if (!_SC_CFEqual(if1->entity_device, if2->entity_device)) {
return FALSE; }
if (!_SC_CFEqual(if1->entity_device_unique, if2->entity_device_unique)) {
return FALSE; }
#if !TARGET_OS_IPHONE
if (CFEqual(if1->interface_type, kSCNetworkInterfaceTypeBond)) {
if (!_SC_CFEqual(if1->bond.interfaces, if2->bond.interfaces)) {
return FALSE; }
if (!_SC_CFEqual(if1->bond.mode, if2->bond.mode)) {
return FALSE; }
}
if (CFEqual(if1->interface_type, kSCNetworkInterfaceTypeVLAN)) {
if (!_SC_CFEqual(if1->vlan.interface, if2->vlan.interface)) {
return FALSE; }
if (!_SC_CFEqual(if1->vlan.tag, if2->vlan.tag)) {
return FALSE; }
}
#endif // !TARGET_OS_IPHONE
if (!_SC_CFEqual(if1->interface, if2->interface)) {
return FALSE; }
return TRUE;
}
static CFHashCode
__SCNetworkInterfaceHash(CFTypeRef cf)
{
CFHashCode hash = 0;
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)cf;
if (interfacePrivate->entity_device != NULL) {
if (interfacePrivate->entity_device_unique == NULL) {
hash = CFHash(interfacePrivate->entity_device);
} else {
CFStringRef str;
str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@+%@"),
interfacePrivate->entity_device,
interfacePrivate->entity_device_unique);
hash = CFHash(str);
CFRelease(str);
}
}
return hash;
}
static void
__SCNetworkInterfaceInitialize(void)
{
kern_return_t kr;
__kSCNetworkInterfaceTypeID = _CFRuntimeRegisterClass(&__SCNetworkInterfaceClass);
_CFRuntimeSetInstanceTypeID(&__kSCNetworkInterfaceIPv4, __kSCNetworkInterfaceTypeID);
__kSCNetworkInterfaceIPv4.interface_type = kSCNetworkInterfaceTypeIPv4;
__kSCNetworkInterfaceIPv4.localized_key = CFSTR("ipv4");
bundle = _SC_CFBundleGet();
kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
if (kr != KERN_SUCCESS) {
SCLog(TRUE, LOG_DEBUG,
CFSTR("__SCNetworkInterfaceInitialize(), could not get IOMasterPort, kr = 0x%x"),
kr);
}
return;
}
__private_extern__
SCNetworkInterfacePrivateRef
__SCNetworkInterfaceCreatePrivate(CFAllocatorRef allocator,
SCNetworkInterfaceRef interface,
SCPreferencesRef prefs,
CFStringRef serviceID,
io_string_t path)
{
SCNetworkInterfacePrivateRef interfacePrivate;
uint32_t size;
pthread_once(&initialized, __SCNetworkInterfaceInitialize);
size = sizeof(SCNetworkInterfacePrivate) - sizeof(CFRuntimeBase);
interfacePrivate = (SCNetworkInterfacePrivateRef)_CFRuntimeCreateInstance(allocator,
__kSCNetworkInterfaceTypeID,
size,
NULL);
if (interfacePrivate == NULL) {
return NULL;
}
interfacePrivate->interface_type = NULL;
interfacePrivate->name = NULL;
interfacePrivate->localized_name = NULL;
interfacePrivate->localized_key = NULL;
interfacePrivate->localized_arg1 = NULL;
interfacePrivate->localized_arg2 = NULL;
interfacePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL;
interfacePrivate->prefs = (prefs != NULL) ? CFRetain(prefs) : NULL;
interfacePrivate->serviceID = (serviceID != NULL) ? CFRetain(serviceID) : NULL;
interfacePrivate->unsaved = NULL;
interfacePrivate->entity_device = NULL;
interfacePrivate->entity_device_unique = NULL;
interfacePrivate->entity_type = NULL;
interfacePrivate->entity_subtype = NULL;
interfacePrivate->supported_interface_types = NULL;
interfacePrivate->supported_protocol_types = NULL;
interfacePrivate->address = NULL;
interfacePrivate->addressString = NULL;
interfacePrivate->builtin = FALSE;
interfacePrivate->configurationAction = NULL;
interfacePrivate->path = (path != NULL) ? CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8)
: NULL;
interfacePrivate->location = NULL;
interfacePrivate->overrides = NULL;
interfacePrivate->modemIsV92 = FALSE;
interfacePrivate->type = NULL;
interfacePrivate->unit = NULL;
interfacePrivate->sort_order = kSortUnknown;
#if !TARGET_OS_IPHONE
interfacePrivate->supportsBond = FALSE;
interfacePrivate->bond.interfaces = NULL;
interfacePrivate->bond.mode = NULL;
interfacePrivate->bond.options = NULL;
interfacePrivate->supportsVLAN = FALSE;
interfacePrivate->vlan.interface = NULL;
interfacePrivate->vlan.tag = NULL;
interfacePrivate->vlan.options = NULL;
#endif // !TARGET_OS_IPHONE
return interfacePrivate;
}
#if !TARGET_OS_IPHONE
__private_extern__
Boolean
__SCNetworkInterfaceSupportsVLAN(CFStringRef bsd_if)
{
char * buf = NULL;
size_t buf_len = 0;
struct if_msghdr * ifm;
char * if_name = NULL;
unsigned int if_index;
int mib[6];
Boolean vlanOK = FALSE;
if_name = _SC_cfstring_to_cstring(bsd_if, NULL, 0, kCFStringEncodingASCII);
if (if_name == NULL) {
return FALSE; }
if_index = if_nametoindex(if_name);
if (if_index == 0) {
goto done; }
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_LINK;
mib[4] = NET_RT_IFLIST;
mib[5] = if_index;
if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) == -1) {
SCLog(TRUE, LOG_ERR, CFSTR("sysctl() size failed: %s"), strerror(errno));
goto done;
}
buf = CFAllocatorAllocate(NULL, buf_len, 0);
if (sysctl(mib, 6, buf, &buf_len, NULL, 0) == -1) {
SCLog(TRUE, LOG_ERR, CFSTR("sysctl() failed: %s"), strerror(errno));
goto done;
}
ifm = (struct if_msghdr *)buf;
switch (ifm->ifm_type) {
case RTM_IFINFO : {
#if defined(IF_HWASSIST_VLAN_TAGGING) && defined(IF_HWASSIST_VLAN_MTU)
struct if_data *if_data = &ifm->ifm_data;
if (if_data->ifi_hwassist & (IF_HWASSIST_VLAN_TAGGING | IF_HWASSIST_VLAN_MTU)) {
vlanOK = TRUE;
}
#endif
break;
}
}
done :
if (if_name != NULL) CFAllocatorDeallocate(NULL, if_name);
if (buf != NULL) CFAllocatorDeallocate(NULL, buf);
return vlanOK;
}
__private_extern__
SCNetworkInterfacePrivateRef
_SCBondInterfaceCreatePrivate(CFAllocatorRef allocator,
CFStringRef bond_if)
{
SCNetworkInterfacePrivateRef interfacePrivate;
interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL, NULL);
if (interfacePrivate == NULL) {
return NULL;
}
interfacePrivate->interface_type = kSCNetworkInterfaceTypeBond;
interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
interfacePrivate->entity_device = CFStringCreateCopy(allocator, bond_if);
interfacePrivate->builtin = TRUE;
interfacePrivate->supportsVLAN = __SCNetworkInterfaceSupportsVLAN(bond_if);
interfacePrivate->sort_order = kSortBond;
interfacePrivate->localized_key = CFSTR("bond");
interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device);
interfacePrivate->bond.interfaces = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
return interfacePrivate;
}
__private_extern__
SCNetworkInterfacePrivateRef
_SCVLANInterfaceCreatePrivate(CFAllocatorRef allocator,
CFStringRef vlan_if)
{
SCNetworkInterfacePrivateRef interfacePrivate;
interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL, NULL);
if (interfacePrivate == NULL) {
return NULL;
}
interfacePrivate->interface_type = kSCNetworkInterfaceTypeVLAN;
interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
interfacePrivate->entity_device = CFStringCreateCopy(allocator, vlan_if);
interfacePrivate->builtin = TRUE;
interfacePrivate->sort_order = kSortVLAN;
interfacePrivate->localized_key = CFSTR("vlan");
interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device);
return interfacePrivate;
}
#endif // !TARGET_OS_IPHONE
#pragma mark -
#pragma mark Interface ordering
static CFArrayRef
split_path(CFStringRef path)
{
CFArrayRef components;
CFMutableStringRef nPath;
nPath = CFStringCreateMutableCopy(NULL, 0, path);
(void) CFStringFindAndReplace(nPath,
CFSTR("@"),
CFSTR("/"),
CFRangeMake(0, CFStringGetLength(nPath)),
0);
components = CFStringCreateArrayBySeparatingStrings(NULL, nPath, CFSTR("/"));
CFRelease(nPath);
return components;
}
CFComparisonResult
_SCNetworkInterfaceCompare(const void *val1, const void *val2, void *context)
{
SCNetworkInterfacePrivateRef dev1 = (SCNetworkInterfacePrivateRef)val1;
SCNetworkInterfacePrivateRef dev2 = (SCNetworkInterfacePrivateRef)val2;
CFComparisonResult res = kCFCompareEqualTo;
if (dev1->sort_order != dev2->sort_order) {
if (dev1->sort_order < dev2->sort_order) {
res = kCFCompareLessThan;
} else {
res = kCFCompareGreaterThan;
}
return (res);
}
if (dev1->builtin != dev2->builtin) {
if (dev1->builtin) {
res = kCFCompareLessThan;
} else {
res = kCFCompareGreaterThan;
}
return (res);
}
if (dev1->builtin) {
if (dev1->location != dev2->location) {
if (isA_CFString(dev1->location)) {
if (isA_CFString(dev2->location)) {
res = CFStringCompare(dev1->location, dev2->location, 0);
} else {
res = kCFCompareLessThan;
}
} else {
res = kCFCompareGreaterThan;
}
if (res != kCFCompareEqualTo) {
return (res);
}
}
}
if ((dev1->path != NULL) && (dev2->path != NULL)) {
CFArrayRef elements1;
CFArrayRef elements2;
CFIndex i;
CFIndex n;
CFIndex n1;
CFIndex n2;
elements1 = split_path(dev1->path);
n1 = CFArrayGetCount(elements1);
elements2 = split_path(dev2->path);
n2 = CFArrayGetCount(elements2);
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, kCFStringEncodingUTF8);
errno = 0;
q1 = strtoq(str, &end, 16);
isNum = ((*str != '\0') && (*end == '\0') && (errno == 0));
CFAllocatorDeallocate(NULL, str);
if (isNum) {
str = _SC_cfstring_to_cstring(e2, NULL, 0, kCFStringEncodingUTF8);
errno = 0;
q2 = strtoq(str, &end, 16);
isNum = ((*str != '\0') && (*end == '\0') && (errno == 0));
CFAllocatorDeallocate(NULL, str);
if (isNum) {
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;
}
}
CFRelease(elements1);
CFRelease(elements2);
if (res != kCFCompareEqualTo) {
return (res);
}
}
if ((dev1->entity_device != NULL) && (dev2->entity_device != NULL)) {
res = CFStringCompare(dev1->entity_device, dev2->entity_device, 0);
if (res != kCFCompareEqualTo) {
return (res);
}
}
if ((dev1->entity_device_unique != NULL) && (dev2->entity_device_unique != NULL)) {
res = CFStringCompare(dev1->entity_device_unique, dev2->entity_device_unique, 0);
}
return res;
}
static void
sort_interfaces(CFMutableArrayRef all_interfaces)
{
int n = CFArrayGetCount(all_interfaces);
if (n < 2) {
return;
}
CFArraySortValues(all_interfaces, CFRangeMake(0, n), _SCNetworkInterfaceCompare, NULL);
return;
}
__private_extern__
int
__SCNetworkInterfaceOrder(SCNetworkInterfaceRef interface)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
return interfacePrivate->sort_order;
}
#pragma mark -
#pragma mark Interface details
static CFStringRef
IOCopyCFStringValue(CFTypeRef ioVal)
{
if (isA_CFString(ioVal)) {
return CFStringCreateCopy(NULL, ioVal);
}
if (isA_CFData(ioVal)) {
return CFStringCreateWithCString(NULL,
(const char *)CFDataGetBytePtr(ioVal),
kCFStringEncodingUTF8);
}
return NULL;
}
static CFStringRef
IODictionaryCopyCFStringValue(CFDictionaryRef io_dict, CFStringRef io_key)
{
CFTypeRef ioVal;
ioVal = CFDictionaryGetValue(io_dict, io_key);
return IOCopyCFStringValue(ioVal);
}
static Boolean
IOStringValueHasPrefix(CFTypeRef ioVal, CFStringRef prefix)
{
Boolean match = FALSE;
CFIndex prefixLen = CFStringGetLength(prefix);
CFStringRef str = NULL;
if (!isA_CFString(ioVal)) {
if (isA_CFData(ioVal)) {
str = CFStringCreateWithCStringNoCopy(NULL,
(const char *)CFDataGetBytePtr(ioVal),
kCFStringEncodingUTF8,
kCFAllocatorNull);
ioVal = str;
} else {
return FALSE;
}
}
if ((ioVal != NULL) &&
(CFStringGetLength(ioVal) >= prefixLen) &&
(CFStringCompareWithOptions(ioVal,
prefix,
CFRangeMake(0, prefixLen),
kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
match = TRUE;
}
if (str != NULL) CFRelease(str);
return match;
}
static const struct {
const CFStringRef name;
const CFStringRef slot;
} slot_mappings[] = {
{ CFSTR("A1") , CFSTR("1") },
{ CFSTR("B1") , CFSTR("2") },
{ CFSTR("C1") , CFSTR("3") },
{ CFSTR("J12"), CFSTR("1") },
{ CFSTR("J11"), CFSTR("2") },
{ CFSTR("J10"), CFSTR("3") },
{ CFSTR("J9"), CFSTR("4") },
{ CFSTR("A") , CFSTR("1") },
{ CFSTR("B") , CFSTR("2") },
{ CFSTR("C") , CFSTR("3") },
{ CFSTR("D") , CFSTR("4") },
{ CFSTR("1") , CFSTR("1") },
{ CFSTR("2") , CFSTR("2") },
{ CFSTR("3") , CFSTR("3") },
{ CFSTR("4") , CFSTR("4") },
{ CFSTR("5") , CFSTR("5") }
};
static CFStringRef
pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name)
{
kern_return_t kr;
io_registry_entry_t parent;
CFMutableStringRef slot;
CFTypeRef slot_name;
slot = NULL;
if (pci_slot_name != NULL) *pci_slot_name = NULL;
slot_name = IORegistryEntryCreateCFProperty(interface, CFSTR("AAPL,slot-name"), NULL, 0);
if (slot_name != NULL) {
CFIndex i;
slot = CFStringCreateMutable(NULL, 0);
if (isA_CFString(slot_name)) {
if (pci_slot_name != NULL) *pci_slot_name = CFStringCreateCopy(NULL, slot_name);
CFStringAppend(slot, slot_name);
} else if (isA_CFData(slot_name)) {
if (pci_slot_name != NULL) *pci_slot_name = CFDataCreateCopy(NULL, slot_name);
CFStringAppendCString(slot,
(const char *)CFDataGetBytePtr(slot_name),
kCFStringEncodingUTF8);
}
if (CFStringGetLength(slot) > 5) {
(void) CFStringFindAndReplace(slot,
CFSTR("slot-"),
CFSTR(""),
CFRangeMake(0, 5),
kCFCompareCaseInsensitive|kCFCompareAnchored);
}
for (i = 0; i < sizeof(slot_mappings)/sizeof(slot_mappings[0]); i++) {
if (CFStringCompare(slot,
slot_mappings[i].name,
kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
CFRelease(slot);
slot = (CFMutableStringRef)CFRetain(slot_mappings[i].slot);
break;
}
}
CFRelease(slot_name);
}
kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &parent);
switch (kr) {
case kIOReturnSuccess : {
CFTypeRef parent_pci_slot_name = NULL;
CFStringRef parent_slot;
parent_slot = pci_slot(parent, &parent_pci_slot_name);
if (parent_slot != NULL) {
if (slot != NULL) CFRelease(slot);
slot = (CFMutableStringRef)parent_slot;
if (pci_slot_name != NULL) {
if (*pci_slot_name != NULL) CFRelease(*pci_slot_name);
*pci_slot_name = parent_pci_slot_name;
} else {
CFRelease(parent_pci_slot_name);
}
}
IOObjectRelease(parent);
break;
}
case kIOReturnNoDevice :
break;
default :
SCLog(TRUE, LOG_DEBUG, CFSTR("pci_slot IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
break;
}
return slot;
}
static CFComparisonResult
compare_bsdNames(const void *val1, const void *val2, void *context)
{
CFStringRef bsd1 = (CFStringRef)val1;
CFStringRef bsd2 = (CFStringRef)val2;
return CFStringCompare(bsd1, bsd2, 0);
}
static CFStringRef
pci_port(CFTypeRef slot_name, CFStringRef bsdName)
{
CFIndex n;
CFStringRef port_name = NULL;
CFMutableArrayRef port_names;
kern_return_t kr;
CFStringRef match_keys[2];
CFTypeRef match_vals[2];
CFDictionaryRef match_dict;
CFDictionaryRef matching;
io_registry_entry_t slot;
io_iterator_t slot_iterator = MACH_PORT_NULL;
match_keys[0] = CFSTR("AAPL,slot-name");
match_vals[0] = slot_name;
match_dict = CFDictionaryCreate(NULL,
(const void **)match_keys,
(const void **)match_vals,
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
match_keys[0] = CFSTR(kIOProviderClassKey);
match_vals[0] = CFSTR("IOPCIDevice");
match_keys[1] = CFSTR(kIOPropertyMatchKey);
match_vals[1] = match_dict;
matching = CFDictionaryCreate(NULL,
(const void **)match_keys,
(const void **)match_vals,
sizeof(match_keys)/sizeof(match_keys[0]),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease(match_dict);
kr = IOServiceGetMatchingServices(masterPort, matching, &slot_iterator);
if (kr != kIOReturnSuccess) {
SCLog(TRUE, LOG_DEBUG, CFSTR("pci_port IOServiceGetMatchingServices() failed, kr = 0x%x"), kr);
return MACH_PORT_NULL;
}
port_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
while ((slot = IOIteratorNext(slot_iterator)) != MACH_PORT_NULL) {
io_registry_entry_t child;
io_iterator_t child_iterator = MACH_PORT_NULL;
kr = IORegistryEntryCreateIterator(slot,
kIOServicePlane,
kIORegistryIterateRecursively,
&child_iterator);
if (kr != kIOReturnSuccess) {
SCLog(TRUE, LOG_DEBUG, CFSTR("pci_port IORegistryEntryCreateIterator() failed, kr = 0x%x"), kr);
CFRelease(port_names);
return MACH_PORT_NULL;
}
while ((child = IOIteratorNext(child_iterator)) != MACH_PORT_NULL) {
if (IOObjectConformsTo(child, kIONetworkInterfaceClass)) {
CFStringRef if_bsdName;
if_bsdName = IORegistryEntryCreateCFProperty(child,
CFSTR(kIOBSDNameKey),
NULL,
0);
if (if_bsdName != NULL) {
CFArrayAppendValue(port_names, if_bsdName);
CFRelease(if_bsdName);
}
}
IOObjectRelease(child);
}
IOObjectRelease(child_iterator);
IOObjectRelease(slot);
}
IOObjectRelease(slot_iterator);
n = CFArrayGetCount(port_names);
if (n > 1) {
CFArraySortValues(port_names, CFRangeMake(0, n), compare_bsdNames, NULL);
n = CFArrayGetFirstIndexOfValue(port_names, CFRangeMake(0, n), bsdName);
if (n != kCFNotFound) {
port_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), n + 1);
}
}
CFRelease(port_names);
return port_name;
}
static Boolean
pci_slot_info(io_registry_entry_t interface, CFStringRef *slot_name, CFStringRef *port_name)
{
CFStringRef bsd_name;
Boolean ok = FALSE;
CFTypeRef pci_slot_name;
*slot_name = NULL;
*port_name = NULL;
bsd_name = IORegistryEntryCreateCFProperty(interface, CFSTR(kIOBSDNameKey), NULL, 0);
if (bsd_name == NULL) {
return FALSE;
}
*slot_name = pci_slot(interface, &pci_slot_name);
if (*slot_name != NULL) {
if (pci_slot_name != NULL) {
*port_name = pci_port(pci_slot_name, bsd_name);
CFRelease(pci_slot_name);
}
ok = TRUE;
}
CFRelease(bsd_name);
return ok;
}
static Boolean
isBuiltin(io_registry_entry_t interface)
{
CFStringRef slot;
slot = pci_slot(interface, NULL);
if (slot != NULL) {
CFRelease(slot);
return FALSE;
}
return TRUE;
}
static Boolean
isBluetoothBuiltin(Boolean *haveController)
{
Boolean builtin = FALSE;
io_object_t hciController;
io_iterator_t iter = MACH_PORT_NULL;
kern_return_t kr;
kr = IOServiceGetMatchingServices(masterPort,
IOServiceMatching("IOBluetoothHCIController"),
&iter);
if ((kr != kIOReturnSuccess) || (iter == MACH_PORT_NULL)) {
if (kr != kIOReturnSuccess) {
SCLog(TRUE, LOG_DEBUG, CFSTR("isBluetoothBuiltin IOServiceGetMatchingServices() failed, kr = 0x%x"), kr);
}
*haveController = FALSE;
return FALSE;
}
*haveController = TRUE;
hciController = IOIteratorNext(iter);
IOObjectRelease(iter);
if(hciController != MACH_PORT_NULL) {
CFNumberRef idVendor;
idVendor = IORegistryEntryCreateCFProperty(hciController, CFSTR(kUSBVendorID), NULL, 0);
if (idVendor != NULL) {
int idVendorVal;
if (isA_CFNumber(idVendor) &&
CFNumberGetValue(idVendor, kCFNumberIntType, &idVendorVal) &&
(idVendorVal == kIOUSBVendorIDAppleComputer)) {
builtin = TRUE;
}
CFRelease(idVendor);
}
IOObjectRelease(hciController);
}
return builtin;
}
#pragma mark -
#pragma mark Interface enumeration
typedef Boolean (*processInterface)(SCNetworkInterfacePrivateRef interfacePrivate,
io_registry_entry_t interface,
CFDictionaryRef interface_dict,
io_registry_entry_t controller,
CFDictionaryRef controller_dict,
io_registry_entry_t bus,
CFDictionaryRef bus_dict);
static Boolean
processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate,
io_registry_entry_t interface,
CFDictionaryRef interface_dict,
io_registry_entry_t controller,
CFDictionaryRef controller_dict,
io_registry_entry_t bus,
CFDictionaryRef bus_dict)
{
CFDataRef data;
int ift = -1;
int iVal;
CFNumberRef num;
CFStringRef str;
CFBooleanRef val;
num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceType));
if (isA_CFNumber(num) &&
CFNumberGetValue(num, kCFNumberIntType, &ift)) {
interfacePrivate->type = CFRetain(num);
} else {
SCLog(TRUE, LOG_DEBUG, CFSTR("processNetworkInterface() failed, no interface type"));
return FALSE;
}
switch (ift) {
case IFT_ETHER :
if ((IOObjectConformsTo(controller, "IO80211Controller")) ||
(IOObjectConformsTo(controller, "AirPortPCI" )) ||
(IOObjectConformsTo(controller, "AirPortDriver" ))) {
interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
interfacePrivate->sort_order = kSortAirPort;
} else if (IOObjectConformsTo(controller, "IOBluetoothBNEPDriver")) {
interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
interfacePrivate->sort_order = kSortBluetoothPAN;
} else {
str = IODictionaryCopyCFStringValue(bus_dict, CFSTR("name"));
if ((str != NULL) && CFEqual(str, CFSTR("radio"))) {
interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
interfacePrivate->sort_order = kSortOtherWireless;
} else {
interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
interfacePrivate->sort_order = kSortEthernet;
#if !TARGET_OS_IPHONE
interfacePrivate->supportsBond = TRUE;
#endif // !TARGET_OS_IPHONE
}
if (str != NULL) CFRelease(str);
}
if (IOObjectConformsTo(controller, "AppleUSBEthernetHost")) {
interfacePrivate->sort_order = kSortTethered;
} else if (IOObjectConformsTo(controller, "AppleUSBCDCECMData")) {
interfacePrivate->sort_order = kSortWWANEthernet;
}
val = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOBuiltin)));
if (val == NULL) {
val = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOPrimaryInterface)));
}
if (val != NULL) {
interfacePrivate->builtin = CFBooleanGetValue(val);
} else {
interfacePrivate->builtin = isBuiltin(interface);
}
if (!interfacePrivate->builtin &&
CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) {
interfacePrivate->builtin = TRUE;
}
interfacePrivate->location = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOLocation));
#if !TARGET_OS_IPHONE
num = CFDictionaryGetValue(controller_dict, CFSTR(kIOFeatures));
if (isA_CFNumber(num) &&
CFNumberGetValue(num, kCFNumberIntType, & iVal)) {
if (iVal & (kIONetworkFeatureHardwareVlan | kIONetworkFeatureSoftwareVlan)) {
interfacePrivate->supportsVLAN = TRUE;
}
}
#endif // !TARGET_OS_IPHONE
if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) {
interfacePrivate->localized_key = CFSTR("airport");
} else if (interfacePrivate->sort_order == kSortBluetoothPAN) {
interfacePrivate->localized_key = CFSTR("bluetooth-pan");
} else if (interfacePrivate->sort_order == kSortOtherWireless) {
interfacePrivate->localized_key = CFSTR("wireless");
interfacePrivate->localized_arg1 = CFRetain(CFSTR("")); } else if (interfacePrivate->builtin) {
if ((interfacePrivate->location == NULL) ||
(CFStringGetLength(interfacePrivate->location) == 0)) {
interfacePrivate->localized_key = CFSTR("ether");
} else {
interfacePrivate->localized_key = CFSTR("multiether");
interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->location);
}
} else {
CFStringRef provider;
provider = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR(kIOProviderClassKey),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (provider != NULL) {
if (CFEqual(provider, CFSTR("IOPCIDevice"))) {
CFStringRef port_name;
CFStringRef slot_name;
if (pci_slot_info(interface, &slot_name, &port_name)) {
if (port_name == NULL) {
interfacePrivate->localized_key = CFSTR("pci-ether");
interfacePrivate->localized_arg1 = slot_name;
} else {
interfacePrivate->localized_key = CFSTR("pci-multiether");
interfacePrivate->localized_arg1 = slot_name;
interfacePrivate->localized_arg2 = port_name;
}
}
} else if (CFEqual(provider, CFSTR("IOUSBDevice")) ||
CFEqual(provider, CFSTR("IOUSBInterface"))) {
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR(kIOPropertyProductNameKey),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (val == NULL) {
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR(kUSBProductString),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
}
if (val != NULL) {
CFStringRef productName;
productName = IOCopyCFStringValue(val);
CFRelease(val);
if (productName != NULL) {
if (CFStringGetLength(productName) > 0) {
if (interfacePrivate->name != NULL) {
CFRelease(interfacePrivate->name);
}
interfacePrivate->name = CFRetain(productName);
if (interfacePrivate->localized_name != NULL) {
CFRelease(interfacePrivate->localized_name);
}
interfacePrivate->localized_name = copy_interface_string(bundle, productName, TRUE);
}
CFRelease(productName);
}
} else {
interfacePrivate->localized_key = CFSTR("usb-ether");
interfacePrivate->localized_arg1 = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey));
}
}
CFRelease(provider);
}
if (interfacePrivate->localized_key == NULL) {
interfacePrivate->localized_key = CFSTR("generic-ether");
interfacePrivate->localized_arg1 = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey));
}
}
break;
case IFT_IEEE1394 :
interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire;
interfacePrivate->entity_type = kSCValNetInterfaceTypeFireWire;
interfacePrivate->builtin = isBuiltin(interface);
interfacePrivate->sort_order = kSortFireWire;
if (interfacePrivate->builtin) {
interfacePrivate->localized_key = CFSTR("firewire");
} else {
CFStringRef slot_name;
slot_name = pci_slot(interface, NULL);
if (slot_name != NULL) {
interfacePrivate->localized_key = CFSTR("pci-firewire");
interfacePrivate->localized_arg1 = slot_name;
}
}
break;
default :
SCLog(TRUE, LOG_DEBUG, CFSTR("processNetworkInterface() failed, unknown interface type = %d"), ift);
return FALSE;
}
interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey));
data = CFDictionaryGetValue(controller_dict, CFSTR(kIOMACAddress));
if (isA_CFData(data)) {
interfacePrivate->address = CFRetain(data);
}
num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceUnit));
if (isA_CFNumber(num) &&
CFNumberGetValue(num, kCFNumberIntType, & iVal)) {
interfacePrivate->unit = CFRetain(num);
}
return TRUE;
}
static void
set_connection_script(SCNetworkInterfacePrivateRef interfacePrivate, CFStringRef script)
{
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
if (interfacePrivate->overrides == NULL) {
interfacePrivate->overrides = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
dict = CFDictionaryGetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem);
if (dict != NULL) {
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
} else {
newDict = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
if (script != NULL) {
CFDictionarySetValue(newDict, kSCPropNetModemConnectionScript, script);
} else {
CFDictionaryRemoveValue(newDict, kSCPropNetModemConnectionScript);
}
if (CFDictionaryGetCount(newDict) > 0) {
CFDictionarySetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem, newDict);
} else {
CFDictionaryRemoveValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem);
}
CFRelease(newDict);
if (CFDictionaryGetCount(interfacePrivate->overrides) == 0) {
CFRelease(interfacePrivate->overrides);
interfacePrivate->overrides = NULL;
}
return;
}
static Boolean
is_valid_connection_script(CFStringRef script)
{
char ccl[MAXPATHLEN];
char path[MAXPATHLEN];
NSSearchPathEnumerationState state;
(void) _SC_cfstring_to_cstring(script,
ccl,
sizeof(ccl),
kCFStringEncodingUTF8);
state = NSStartSearchPathEnumeration(NSLibraryDirectory,
NSLocalDomainMask|NSSystemDomainMask);
while ((state = NSGetNextSearchPathEnumeration(state, path))) {
size_t n;
struct stat statBuf;
if (ccl[0] == '/') {
path[0] = '\0'; } else {
strlcat(path, "/Modem Scripts/", sizeof(path));
}
strlcat(path, ccl, sizeof(path));
if (stat(path, &statBuf) != 0) {
if (errno == ENOENT) {
goto bundle;
}
SCLog(TRUE, LOG_DEBUG,
CFSTR("processSerialInterface stat() failed: %s"),
strerror(errno));
continue;
}
if (S_ISREG(statBuf.st_mode)) {
return TRUE;
}
#define BUNDLE_EXT ".ccl"
#define BUNDLE_EXT_LEN sizeof(BUNDLE_EXT) - 1
bundle :
n = strlen(path);
if ((n <= BUNDLE_EXT_LEN) ||
(strstr(&path[n - BUNDLE_EXT_LEN], BUNDLE_EXT) == NULL)) {
strlcat(path, BUNDLE_EXT, sizeof(path));
if (stat(path, &statBuf) != 0) {
if (errno == ENOENT) {
continue;
}
SCLog(TRUE, LOG_DEBUG,
CFSTR("processSerialInterface stat() failed: %s"),
strerror(errno));
continue;
}
}
if (S_ISDIR(statBuf.st_mode)) {
return TRUE;
}
}
return FALSE;
}
static Boolean
processSerialInterface(SCNetworkInterfacePrivateRef interfacePrivate,
io_registry_entry_t interface,
CFDictionaryRef interface_dict,
io_registry_entry_t controller,
CFDictionaryRef controller_dict,
io_registry_entry_t bus,
CFDictionaryRef bus_dict)
{
CFStringRef base = NULL;
CFStringRef ift;
Boolean isModem = FALSE;
Boolean isWWAN = FALSE;
CFStringRef modemCCL = NULL;
Boolean ok = FALSE;
CFTypeRef val;
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR("HiddenPort"),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (val != NULL) {
CFRelease(val);
return FALSE; }
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR("Initializing"),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (val != NULL) {
Boolean initializing;
initializing = isA_CFBoolean(val) && CFBooleanGetValue(val);
CFRelease(val);
if (initializing) {
return FALSE; }
}
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR("WWAN"),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (val != NULL) {
isWWAN = isA_CFBoolean(val) && CFBooleanGetValue(val);
CFRelease(val);
}
interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOTTYDeviceKey));
if (interfacePrivate->entity_device == NULL) {
return FALSE;
}
base = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOTTYBaseNameKey));
if (base == NULL) {
base = CFRetain(interfacePrivate->entity_device);
}
if (CFStringCompare(base,
CFSTR("irda"),
kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
goto done;
}
if (IOStringValueHasPrefix(base, CFSTR("bluetooth"))) {
Boolean haveController = FALSE;
interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth;
interfacePrivate->sort_order = kSortBluetooth;
interfacePrivate->builtin = isBluetoothBuiltin(&haveController);
if (!haveController) {
goto done;
}
} else if (IOStringValueHasPrefix(base, CFSTR("irda-ircomm"))) {
interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA;
interfacePrivate->sort_order = kSortIrDA;
} else if (isWWAN) {
interfacePrivate->interface_type = kSCNetworkInterfaceTypeWWAN;
interfacePrivate->sort_order = kSortWWAN;
} else {
interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem;
interfacePrivate->sort_order = kSortModem;
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR(kIODeviceSupportsHoldKey),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (val != NULL) {
uint32_t v92;
if (isA_CFNumber(val) &&
CFNumberGetValue(val, kCFNumberSInt32Type, &v92)) {
interfacePrivate->modemIsV92 = (v92 == 1);
}
CFRelease(val);
}
}
interfacePrivate->entity_type = kSCEntNetModem;
ift = CFDictionaryGetValue(interface_dict, CFSTR(kIOSerialBSDTypeKey));
if (!isA_CFString(ift)) {
goto done;
}
if (CFEqual(ift, CFSTR(kIOSerialBSDModemType))) {
isModem = TRUE;
if (CFEqual(base, CFSTR("modem"))) {
interfacePrivate->builtin = TRUE;
interfacePrivate->sort_order = kSortInternalModem;
} else if (CFEqual(base, CFSTR("usbmodem"))) {
interfacePrivate->sort_order = kSortUSBModem;
}
} else if (CFEqual(ift, CFSTR(kIOSerialBSDRS232Type))) {
interfacePrivate->sort_order = kSortSerialPort;
} else {
goto done;
}
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR("DevicePPPOverrides"),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (val != NULL) {
if (isA_CFDictionary(val)) {
if (interfacePrivate->overrides == NULL) {
interfacePrivate->overrides = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
CFDictionarySetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypePPP, val);
}
CFRelease(val);
}
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR("DeviceModemOverrides"),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (val != NULL) {
if (isA_CFDictionary(val)) {
CFStringRef uniqueID;
if (interfacePrivate->overrides == NULL) {
interfacePrivate->overrides = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
CFDictionarySetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem, val);
modemCCL = CFDictionaryGetValue(val, kSCPropNetModemConnectionScript);
modemCCL = isA_CFString(modemCCL);
uniqueID = CFDictionaryGetValue(val, CFSTR("UniqueIdentifier"));
uniqueID = isA_CFString(uniqueID);
if (uniqueID != NULL) {
CFRelease(interfacePrivate->entity_device);
interfacePrivate->entity_device = CFRetain(base);
interfacePrivate->entity_device_unique = CFStringCreateCopy(NULL, uniqueID);
}
}
CFRelease(val);
}
if (modemCCL == NULL) {
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR("ModemCCL"),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (val != NULL) {
modemCCL = IOCopyCFStringValue(val);
if (modemCCL != NULL) {
set_connection_script(interfacePrivate, modemCCL);
CFRelease(modemCCL);
}
CFRelease(val);
}
}
if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIrDA)) {
interfacePrivate->localized_key = CFSTR("irda");
} else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBluetooth)) {
interfacePrivate->localized_key = CFSTR("bluetooth");
} else {
CFStringRef localized = NULL;
CFStringRef name = NULL;
CFMutableStringRef port;
port = CFStringCreateMutableCopy(NULL, 0, base);
CFStringLowercase(port, NULL);
if (!isModem) {
CFStringAppend(port, CFSTR("-port"));
}
if (bundle != NULL) {
name = copy_interface_string(bundle, port, FALSE);
}
if (name != NULL) {
if (!CFEqual(port, name)) {
interfacePrivate->name = name;
} else {
CFRelease(name);
interfacePrivate->name = CFStringCreateCopy(NULL, base);
}
} else {
interfacePrivate->name = CFStringCreateCopy(NULL, base);
}
if (bundle != NULL) {
localized = copy_interface_string(bundle, port, TRUE);
}
if (localized != NULL) {
if (!CFEqual(port, localized)) {
interfacePrivate->localized_name = localized;
} else {
CFRelease(localized);
interfacePrivate->localized_name = CFStringCreateCopy(NULL, base);
}
} else {
interfacePrivate->localized_name = CFStringCreateCopy(NULL, base);
}
if (!isModem || !CFEqual(base, CFSTR("modem"))) {
CFStringRef productName;
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR(kIOPropertyProductNameKey),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (val == NULL) {
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
CFSTR(kUSBProductString),
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
}
if (val != NULL) {
productName = IOCopyCFStringValue(val);
CFRelease(val);
if (productName != NULL) {
if (CFStringGetLength(productName) > 0) {
if (interfacePrivate->name != NULL) {
CFRelease(interfacePrivate->name);
}
interfacePrivate->name = CFRetain(productName);
if (interfacePrivate->localized_name != NULL) {
CFRelease(interfacePrivate->localized_name);
}
interfacePrivate->localized_name = copy_interface_string(bundle, productName, TRUE);
if ((modemCCL == NULL) &&
is_valid_connection_script(productName)) {
set_connection_script(interfacePrivate, productName);
}
}
CFRelease(productName);
}
}
}
CFRelease(port);
}
ok = TRUE;
done :
if (!ok && (interfacePrivate->entity_device != NULL)) {
CFRelease(interfacePrivate->entity_device);
interfacePrivate->entity_device = NULL;
}
if (base != NULL) CFRelease(base);
return ok;
}
static SCNetworkInterfaceRef
createInterface(io_registry_entry_t interface, processInterface func)
{
io_registry_entry_t bus = MACH_PORT_NULL;
CFMutableDictionaryRef bus_dict = NULL;
io_registry_entry_t controller = MACH_PORT_NULL;
CFMutableDictionaryRef controller_dict = NULL;
SCNetworkInterfacePrivateRef interfacePrivate = NULL;
CFMutableDictionaryRef interface_dict = NULL;
kern_return_t kr;
io_string_t path;
kr = IORegistryEntryGetPath(interface, kIOServicePlane, path);
if (kr != kIOReturnSuccess) {
SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetPath() failed, kr = 0x%x"), kr);
goto done;
}
kr = IORegistryEntryCreateCFProperties(interface, &interface_dict, NULL, kNilOptions);
if (kr != kIOReturnSuccess) {
SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
goto done;
}
kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &controller);
if (kr != KERN_SUCCESS) {
SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
goto done;
}
kr = IORegistryEntryCreateCFProperties(controller, &controller_dict, NULL, kNilOptions);
if (kr != KERN_SUCCESS) {
SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
goto done;
}
kr = IORegistryEntryGetParentEntry(controller, kIOServicePlane, &bus);
if (kr != KERN_SUCCESS) {
SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
goto done;
}
kr = IORegistryEntryCreateCFProperties(bus, &bus_dict, NULL, kNilOptions);
if (kr != KERN_SUCCESS) {
SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
goto done;
}
interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL, path);
if ((*func)(interfacePrivate, interface, interface_dict, controller, controller_dict, bus, bus_dict)) {
CFTypeRef val;
val = IORegistryEntrySearchCFProperty(interface,
kIOServicePlane,
kSCNetworkInterfaceConfigurationActionKey,
NULL,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (val != NULL) {
if (isA_CFString(val)) {
interfacePrivate->configurationAction = CFRetain(val);
}
CFRelease(val);
}
} else {
CFRelease(interfacePrivate);
interfacePrivate = NULL;
}
done :
if (interface_dict != NULL) CFRelease(interface_dict);
if (controller != MACH_PORT_NULL) IOObjectRelease(controller);
if (controller_dict != NULL) CFRelease(controller_dict);
if (bus != MACH_PORT_NULL) IOObjectRelease(bus);
if (bus_dict != NULL) CFRelease(bus_dict);
return (SCNetworkInterfaceRef)interfacePrivate;
}
static CFArrayRef
findMatchingInterfaces(CFDictionaryRef matching, processInterface func)
{
CFMutableArrayRef interfaces;
io_registry_entry_t interface;
kern_return_t kr;
io_iterator_t iterator = MACH_PORT_NULL;
kr = IOServiceGetMatchingServices(masterPort, matching, &iterator);
if (kr != kIOReturnSuccess) {
SCLog(TRUE, LOG_DEBUG, CFSTR("findMatchingInterfaces IOServiceGetMatchingServices() failed, kr = 0x%x"), kr);
return NULL;
}
interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
while ((interface = IOIteratorNext(iterator)) != MACH_PORT_NULL) {
SCNetworkInterfaceRef match;
match = createInterface(interface, func);
if (match != NULL) {
CFArrayAppendValue(interfaces, match);
CFRelease(match);
}
IOObjectRelease(interface);
}
IOObjectRelease(iterator);
return interfaces;
}
#pragma mark -
#pragma mark helper functions
static CFIndex
findConfiguration(CFStringRef interface_type)
{
CFIndex i;
for (i = 0; i < sizeof(configurations)/sizeof(configurations[0]); i++) {
if (CFEqual(interface_type, *configurations[i].interface_type)) {
return i;
}
}
return kCFNotFound;
}
__private_extern__
CFStringRef
__SCNetworkInterfaceGetDefaultConfigurationType(SCNetworkInterfaceRef interface)
{
CFIndex interfaceIndex;
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
if (interfacePrivate->serviceID == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
interfaceIndex = findConfiguration(interfacePrivate->interface_type);
if (interfaceIndex == kCFNotFound) {
return interfacePrivate->interface_type; }
if (configurations[interfaceIndex].entity_hardware != NULL) {
return *configurations[interfaceIndex].entity_hardware;
}
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
__private_extern__
Boolean
__SCNetworkInterfaceIsValidExtendedConfigurationType(SCNetworkInterfaceRef interface,
CFStringRef extendedType,
Boolean requirePerInterface)
{
CFStringRef defaultType;
CFIndex extendedIndex;
CFIndex interfaceIndex;
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
Boolean isL2TP = FALSE;
Boolean ok = FALSE;
defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
if (defaultType == NULL) {
goto done;
}
if (CFEqual(extendedType, defaultType)) {
goto done;
}
interfaceIndex = findConfiguration(interfacePrivate->interface_type);
if (interfaceIndex == kCFNotFound) {
goto done;
}
if (CFEqual(extendedType, kSCEntNetIPSec)) {
CFStringRef interfaceType;
interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
SCNetworkInterfaceRef child;
child = SCNetworkInterfaceGetInterface(interface);
if (child != NULL) {
interfaceType = SCNetworkInterfaceGetInterfaceType(child);
if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
isL2TP = TRUE;
}
}
}
}
if (requirePerInterface &&
!configurations[interfaceIndex].per_interface_config &&
!isL2TP) {
goto done;
}
extendedIndex = findConfiguration(extendedType);
if ((extendedIndex != kCFNotFound) && !isL2TP) {
goto done;
}
ok = TRUE;
done :
if (!ok) {
_SCErrorSet(kSCStatusInvalidArgument);
}
return ok;
}
typedef struct {
CFStringRef defaultType;
CFMutableArrayRef types;
} extendedConfiguration, *extendedConfigurationRef;
static void
__addExtendedConfigurationType(const void *key, const void *value, void *context)
{
CFStringRef extendedType = (CFStringRef)key;
extendedConfigurationRef myContextRef = (extendedConfigurationRef)context;
if (CFEqual(extendedType, myContextRef->defaultType)) {
return;
}
if (CFArrayContainsValue(myContextRef->types,
CFRangeMake(0, CFArrayGetCount(myContextRef->types)),
extendedType)) {
return;
}
CFArrayAppendValue(myContextRef->types, extendedType);
return;
}
static CFArrayRef
extendedConfigurationTypes(SCNetworkInterfaceRef interface)
{
CFIndex i;
CFIndex interfaceIndex;
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
extendedConfiguration myContext;
SCNetworkServiceRef service;
CFArrayRef sets;
CFIndex n;
myContext.defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
if (myContext.defaultType == NULL) {
myContext.types = NULL;
goto done;
}
myContext.types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (interfacePrivate->serviceID == NULL) {
goto done;
}
interfaceIndex = findConfiguration(interfacePrivate->interface_type);
if (interfaceIndex == kCFNotFound) {
goto done;
}
if (!configurations[interfaceIndex].per_interface_config) {
goto done;
}
service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
interfacePrivate->prefs,
interfacePrivate->serviceID,
interface);
sets = SCNetworkSetCopyAll(interfacePrivate->prefs);
n = (sets != NULL) ? CFArrayGetCount(sets) : 0;