X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/dbf6a266c384fc8b55e00a396eebe5cb62e21547..d94708881e41bd90afd74b1a1dd0524d039ba3f7:/SystemConfiguration.fproj/SCNetworkInterface.c diff --git a/SystemConfiguration.fproj/SCNetworkInterface.c b/SystemConfiguration.fproj/SCNetworkInterface.c index bb4fd5a..32c6c61 100644 --- a/SystemConfiguration.fproj/SCNetworkInterface.c +++ b/SystemConfiguration.fproj/SCNetworkInterface.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2019 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -17,7 +17,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ @@ -28,19 +28,29 @@ * - initial revision * which includes code originally authored by * Robert Ulrich - * Elizaabeth Douglas + * Elizabeth Douglas * Quinn */ +#include #include #include -#include -#include -#include -#include -#include -#include +#include "SCNetworkConfigurationInternal.h" +#include "SCPreferencesInternal.h" +#include "SCHelper_client.h" +#include "plugin_shared.h" + +#if !TARGET_OS_IPHONE +#include +#else // !TARGET_OS_IPHONE +#ifndef kEAPClientPropUserName +#define kEAPClientPropUserName CFSTR("UserName") +#endif +#ifndef kEAPClientPropUserPasswordKeychainItemID +#define kEAPClientPropUserPasswordKeychainItemID CFSTR("UserPasswordKeychainItemID") +#endif +#endif // !TARGET_OS_IPHONE #include #include @@ -50,86 +60,161 @@ #include // for kIOEthernetInterfaceClass #include #include +#if !TARGET_OS_SIMULATOR +#include +#endif // !TARGET_OS_SIMULATOR + #include "dy_framework.h" -#ifndef kIODeviceSupportsHoldKey -#define kIODeviceSupportsHoldKey "V92Modem" +#ifndef kPCIThunderboltString +#define kPCIThunderboltString "PCI-Thunderbolt" #endif -#include "SCNetworkConfiguration.h" -#include "SCNetworkConfigurationInternal.h" +#if TARGET_OS_OSX +#ifndef kUSBSupportsIPhoneOS +#define kUSBSupportsIPhoneOS "SupportsIPhoneOS" +#endif // !kUSBSupportsIPhoneOS +#endif // TARGET_OS_OSX +#ifndef kIOUserEthernetInterfaceRoleKey +#define kIOUserEthernetInterfaceRoleKey "InterfaceRole" +#endif + +#ifndef kIOUSBHostInterfaceClassName +#define kIOUSBHostInterfaceClassName "IOUSBHostInterface" +#endif + +#include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +/* CrashReporter "Application Specific Information" */ +#include -static CFStringRef __SCNetworkInterfaceCopyDescription (CFTypeRef cf); -static void __SCNetworkInterfaceDeallocate (CFTypeRef cf); -static Boolean __SCNetworkInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2); + +static CFStringRef copy_interface_string (CFBundleRef bundle, CFStringRef key, Boolean localized); +static CFStringRef __SCNetworkInterfaceCopyDescription (CFTypeRef cf); +static CFStringRef __SCNetworkInterfaceCopyFormattingDescription (CFTypeRef cf, CFDictionaryRef formatOptions); +static void __SCNetworkInterfaceDeallocate (CFTypeRef cf); +static Boolean __SCNetworkInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2); +static CFHashCode __SCNetworkInterfaceHash (CFTypeRef cf); +static void __SCNetworkInterfaceCacheAdd (CFStringRef bsdName, CFArrayRef matchingInterfaces); +static Boolean __SCNetworkInterfaceCacheIsOpen (void); +static CFArrayRef __SCNetworkInterfaceCacheCopy (CFStringRef bsdName); enum { - kSortInternalModem, + kSortInternalModem = 0, kSortUSBModem, kSortModem, kSortBluetooth, kSortIrDA, kSortSerialPort, + kSortWWAN, + kSortEthernetPPP, + kSortAirportPPP, kSortEthernet, kSortFireWire, kSortAirPort, kSortOtherWireless, + kSortTethered, + kSortWWANEthernet, + kSortBluetoothPAN_GN, + kSortBluetoothPAN_NAP, + kSortBluetoothPAN_U, + kSortThunderbolt, + kSortCarPlay, kSortBond, + kSortBridge, kSortVLAN, kSortUnknown }; +static const char *sortOrderName[] = { + "InternalModem", + "USBModem", + "Modem", + "Bluetooth", + "IrDA", + "SerialPort", + "WWAN", + "EthernetPPP", + "AirportPPP", + "Ethernet", + "FireWire", + "AirPort", + "OtherWireless", + "Tethered", + "WWANEthernet", + "BluetoothPAN_GN", + "BluetoothPAN_NAP", + "BluetoothPAN_U", + "Thunderbolt", + "CarPlay", + "Bond", + "Bridge", + "VLAN", + "Unknown" +}; + + const CFStringRef kSCNetworkInterfaceType6to4 = CFSTR("6to4"); const CFStringRef kSCNetworkInterfaceTypeBluetooth = CFSTR("Bluetooth"); const CFStringRef kSCNetworkInterfaceTypeBond = CFSTR("Bond"); +const CFStringRef kSCNetworkInterfaceTypeBridge = CFSTR("Bridge"); const CFStringRef kSCNetworkInterfaceTypeEthernet = CFSTR("Ethernet"); const CFStringRef kSCNetworkInterfaceTypeFireWire = CFSTR("FireWire"); const CFStringRef kSCNetworkInterfaceTypeIEEE80211 = CFSTR("IEEE80211"); // IEEE 802.11, AirPort +const CFStringRef kSCNetworkInterfaceTypeIPSec = CFSTR("IPSec"); const CFStringRef kSCNetworkInterfaceTypeIrDA = CFSTR("IrDA"); const CFStringRef kSCNetworkInterfaceTypeL2TP = CFSTR("L2TP"); +const CFStringRef kSCNetworkInterfaceTypeLoopback = CFSTR("Loopback"); const CFStringRef kSCNetworkInterfaceTypeModem = CFSTR("Modem"); const CFStringRef kSCNetworkInterfaceTypePPP = CFSTR("PPP"); const CFStringRef kSCNetworkInterfaceTypePPTP = CFSTR("PPTP"); const CFStringRef kSCNetworkInterfaceTypeSerial = CFSTR("Serial"); const CFStringRef kSCNetworkInterfaceTypeVLAN = CFSTR("VLAN"); +const CFStringRef kSCNetworkInterfaceTypeVPN = CFSTR("VPN"); +const CFStringRef kSCNetworkInterfaceTypeWWAN = CFSTR("WWAN"); const CFStringRef kSCNetworkInterfaceTypeIPv4 = CFSTR("IPv4"); -static SCNetworkInterfacePrivate __kSCNetworkInterfaceIPv4 = { - INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), // cfBase - NULL, // interface type - NULL, // localized name - NULL, // localization key - NULL, // localization arg1 - NULL, // localization arg2 - NULL, // [layered] interface - NULL, // service - NULL, // unsaved - NULL, // entity_device - NULL, // entity_hardware - NULL, // entity_type - NULL, // entity_subtype - NULL, // supported_interface_types - NULL, // supported_protocol_types - NULL, // address - FALSE, // builtin - NULL, // location - NULL, // path - FALSE, // supportsDeviceOnHold - FALSE, // supportsBond - FALSE, // supportsVLAN - kSortUnknown // sort_order +static SCNetworkInterfacePrivate __kSCNetworkInterfaceIPv4 = { + .cfBase = INIT_CFRUNTIME_BASE(), // cfBase + .sort_order = kSortUnknown, // sort_order }; -const SCNetworkInterfaceRef kSCNetworkInterfaceIPv4 = (SCNetworkInterfaceRef)&__kSCNetworkInterfaceIPv4; +const SCNetworkInterfaceRef kSCNetworkInterfaceIPv4 = (SCNetworkInterfaceRef)&__kSCNetworkInterfaceIPv4; + +static SCNetworkInterfacePrivate __kSCNetworkInterfaceLoopback = { + .cfBase = INIT_CFRUNTIME_BASE(), // cfBase + .sort_order = kSortUnknown, // sort_order +}; + +const SCNetworkInterfaceRef kSCNetworkInterfaceLoopback = (SCNetworkInterfaceRef)&__kSCNetworkInterfaceLoopback; + +static CFMutableSetRef vendor_interface_types = NULL; + +// A thread-specific convenience cache of all interfaces matching a bsd name +// Key: CFStringRef (BSD name) +// Value: CFArrayRef (matching interfaces) +static __thread CFMutableDictionaryRef S_interface_cache = NULL; + +#pragma mark - +#pragma mark SCNetworkInterface configuration details #define doNone 0 @@ -137,41 +222,68 @@ const SCNetworkInterfaceRef kSCNetworkInterfaceIPv4 = (SCNetworkInterfaceRef #define doL2TP 1<<1 #define doPPP 1<<2 #define doPPTP 1<<3 +#define doIPSec 1<<4 +#define doOverIP do6to4|doL2TP|doPPTP|doIPSec -#define doAppleTalk 1<<0 #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[] = { - // interface type if config? interface types PPP sub-type interface protocols - // ===================================== ========== ======================= ======================================= ========================================= - { &kSCNetworkInterfaceType6to4 , FALSE, doNone, NULL, doIPv6 }, - { &kSCNetworkInterfaceTypeBluetooth , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, - { &kSCNetworkInterfaceTypeBond , TRUE, doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies }, - { &kSCNetworkInterfaceTypeEthernet , TRUE, doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies }, - { &kSCNetworkInterfaceTypeFireWire , TRUE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies }, - { &kSCNetworkInterfaceTypeIEEE80211 , TRUE, doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies }, - { &kSCNetworkInterfaceTypeIrDA , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, - { &kSCNetworkInterfaceTypeL2TP , FALSE, doPPP, &kSCValNetInterfaceSubTypeL2TP, doNone }, - { &kSCNetworkInterfaceTypeModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, - { &kSCNetworkInterfaceTypePPP , FALSE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies }, - { &kSCNetworkInterfaceTypePPTP , FALSE, doPPP, &kSCValNetInterfaceSubTypePPTP, doNone }, - { &kSCNetworkInterfaceTypeSerial , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, - { &kSCNetworkInterfaceTypeVLAN , TRUE, doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies }, - // ===================================== ========== ======================= ======================================= ========================================= - { &kSCNetworkInterfaceTypeIPv4 , FALSE, do6to4|doPPTP|doL2TP, NULL, doNone } + // interface type entity_hardware if config? interface types PPP sub-type interface protocols + // ===================================== ==================== ========== =============== ======================================= ========================================= + { &kSCNetworkInterfaceType6to4 , &kSCEntNet6to4 , FALSE, doNone, NULL, doIPv6 }, + { &kSCNetworkInterfaceTypeBluetooth , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, + { &kSCNetworkInterfaceTypeBond , &kSCEntNetEthernet , TRUE , doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB }, + { &kSCNetworkInterfaceTypeBridge , &kSCEntNetEthernet , TRUE , doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB }, + { &kSCNetworkInterfaceTypeEthernet , &kSCEntNetEthernet , TRUE , doPPP, &kSCValNetInterfaceSubTypePPPoE, doDNS|doIPv4|doIPv6|doProxies|doSMB }, + { &kSCNetworkInterfaceTypeFireWire , &kSCEntNetFireWire , TRUE , doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB }, + { &kSCNetworkInterfaceTypeIEEE80211 , &kSCEntNetAirPort , TRUE , doPPP, &kSCValNetInterfaceSubTypePPPoE, 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 }, +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated" + { &kSCNetworkInterfaceTypePPTP , NULL , FALSE, doPPP, &kSCValNetInterfaceSubTypePPTP, doNone }, +#pragma GCC diagnostic pop + { &kSCNetworkInterfaceTypeSerial , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, + { &kSCNetworkInterfaceTypeVLAN , &kSCEntNetEthernet , TRUE , doNone, &kSCValNetInterfaceSubTypePPPoE, doDNS|doIPv4|doIPv6|doProxies|doSMB }, + { &kSCNetworkInterfaceTypeVPN , &kSCEntNetVPN , FALSE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB }, + { &kSCNetworkInterfaceTypeWWAN , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, + // ===================================== =================== ========== =============== ======================================= ========================================= + { &kSCNetworkInterfaceTypeLoopback , NULL , TRUE , doNone, NULL, doIPv4|doIPv6 }, + // ===================================== =================== ========== =============== ======================================= ========================================= + { &kSCNetworkInterfaceTypeIPv4 , NULL , FALSE, doOverIP, NULL, doNone } }; -#define SYSTEMCONFIGURATION_BUNDLE_ID CFSTR("com.apple.SystemConfiguration") +#define kSCNetworkInterfaceActive "Active" +#define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo" +#define kSCNetworkInterfaceType "SCNetworkInterfaceType" +#define kSCNetworkInterfaceBSDName kIOBSDNameKey +#define kSCNetworkInterfaceIOBuiltin kIOBuiltin +#define kSCNetworkInterfaceIOInterfaceNamePrefix kIOInterfaceNamePrefix +#define kSCNetworkInterfaceIOInterfaceType kIOInterfaceType +#define kSCNetworkInterfaceIOInterfaceUnit kIOInterfaceUnit +#define kSCNetworkInterfaceIOMACAddress kIOMACAddress +#define kSCNetworkInterfaceIOPathMatch kIOPathMatchKey + + #define NETWORKINTERFACE_LOCALIZATIONS CFSTR("NetworkInterface") static CFBundleRef bundle = NULL; @@ -180,50 +292,57 @@ static CFTypeID __kSCNetworkInterfaceTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __SCNetworkInterfaceClass = { - 0, // version - "SCNetworkInterface", // className - NULL, // init - NULL, // copy - __SCNetworkInterfaceDeallocate, // dealloc - __SCNetworkInterfaceEqual, // equal - NULL, // hash - NULL, // copyFormattingDesc - __SCNetworkInterfaceCopyDescription // copyDebugDesc + 0, // version + "SCNetworkInterface", // className + NULL, // init + NULL, // copy + __SCNetworkInterfaceDeallocate, // dealloc + __SCNetworkInterfaceEqual, // equal + __SCNetworkInterfaceHash, // hash + __SCNetworkInterfaceCopyFormattingDescription, // copyFormattingDesc + __SCNetworkInterfaceCopyDescription // copyDebugDesc }; static pthread_once_t initialized = PTHREAD_ONCE_INIT; +static pthread_once_t iokit_quiet = PTHREAD_ONCE_INIT; +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; -static __inline__ CFTypeRef -isA_SCNetworkInterface(CFTypeRef obj) +static mach_port_t masterPort = MACH_PORT_NULL; + +static CFStringRef +__SCNetworkInterfaceCopyDescription(CFTypeRef cf) { - return (isA_CFType(obj, SCNetworkInterfaceGetTypeID())); + return __SCNetworkInterfaceCopyFormattingDescription(cf, NULL); } - static CFStringRef -__SCNetworkInterfaceCopyDescription(CFTypeRef cf) +__SCNetworkInterfaceCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { CFAllocatorRef allocator = CFGetAllocator(cf); CFMutableStringRef result; SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)cf; result = CFStringCreateMutable(allocator, 0); - CFStringAppendFormat(result, NULL, CFSTR(" { "), cf, allocator); + CFStringAppendFormat(result, NULL, CFSTR(" {"), cf, allocator); CFStringAppendFormat(result, NULL, CFSTR("type = %@"), interfacePrivate->interface_type); - CFStringAppendFormat(result, NULL, CFSTR(", entity = %@ / %@ / %@"), - interfacePrivate->entity_device, - interfacePrivate->entity_hardware, - interfacePrivate->entity_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 = %@"), interfacePrivate->localized_name); + CFStringAppendFormat(result, NULL, CFSTR(", name(l) = %@"), interfacePrivate->localized_name); } else { if (interfacePrivate->localized_key != NULL) { - CFStringAppendFormat(result, NULL, CFSTR(", name = \"%@\""), interfacePrivate->localized_key); + CFStringAppendFormat(result, NULL, CFSTR(", name(k) = \"%@\""), interfacePrivate->localized_key); if (interfacePrivate->localized_arg1 != NULL) { CFStringAppendFormat(result, NULL, CFSTR("+\"%@\""), interfacePrivate->localized_arg1); } @@ -233,27 +352,164 @@ __SCNetworkInterfaceCopyDescription(CFTypeRef cf) } } if (interfacePrivate->address != NULL) { - CFStringAppendFormat(result, NULL, CFSTR(", address = %@"), interfacePrivate->address); + const uint8_t *data; + CFIndex dataLen; + CFIndex i; + + CFStringAppendFormat(result, NULL, CFSTR(", address = ")); + + data = CFDataGetBytePtr(interfacePrivate->address); + dataLen = CFDataGetLength(interfacePrivate->address); + for (i = 0; i < dataLen; i++) { + CFStringAppendFormat(result, NULL, CFSTR("%s%02x"), + (i > 0) ? ":" : "", + data[i]); + } } CFStringAppendFormat(result, NULL, CFSTR(", builtin = %s"), interfacePrivate->builtin ? "TRUE" : "FALSE"); + if (interfacePrivate->hidden) { + CFStringAppendFormat(result, NULL, CFSTR(", hidden = TRUE")); + } +#if TARGET_OS_IPHONE + if (interfacePrivate->trustRequired) { + CFStringAppendFormat(result, NULL, CFSTR(", trust required = TRUE")); + } +#endif // TARGET_OS_IPHONE if (interfacePrivate->location != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", location = %@"), interfacePrivate->location); } - CFStringAppendFormat(result, NULL, CFSTR(", path = %@"), interfacePrivate->path); - CFStringAppendFormat(result, NULL, CFSTR(", order = %d"), interfacePrivate->sort_order); + if (interfacePrivate->path != NULL) { + CFStringAppendFormat(result, NULL, CFSTR(", path = %@"), interfacePrivate->path); + } + if (interfacePrivate->entryID != 0) { + CFStringAppendFormat(result, NULL, CFSTR(", entryID = 0x%llx"), interfacePrivate->entryID); + } + if (interfacePrivate->type != NULL) { + CFStringAppendFormat(result, NULL, CFSTR(", type = %@"), interfacePrivate->type); + } + if (interfacePrivate->unit != NULL) { + CFStringAppendFormat(result, NULL, CFSTR(", unit = %@"), interfacePrivate->unit); + } + if (interfacePrivate->family != NULL) { + CFStringAppendFormat(result, NULL, CFSTR(", family = %@"), interfacePrivate->family); + } + if (interfacePrivate->subfamily != NULL) { + CFStringAppendFormat(result, NULL, CFSTR(", subfamily = %@"), interfacePrivate->subfamily); + } + if ((interfacePrivate->usb.vid != NULL) || (interfacePrivate->usb.pid != NULL)) { + int pid = 0; + int vid = 0; - if (interfacePrivate->service != NULL) { - CFStringAppendFormat(result, NULL, CFSTR(", service=%@"), interfacePrivate->service); + if (!isA_CFNumber(interfacePrivate->usb.pid) || + !CFNumberGetValue(interfacePrivate->usb.pid, kCFNumberIntType, &pid)) { + pid = 0; + } + if (!isA_CFNumber(interfacePrivate->usb.vid) || + !CFNumberGetValue(interfacePrivate->usb.vid, kCFNumberIntType, &vid)) { + vid = 0; + } + + if (interfacePrivate->usb.name != NULL) { + CFStringAppendFormat(result, NULL, CFSTR(", USB name = %@"), + interfacePrivate->usb.name); + } + + CFStringAppendFormat(result, NULL, CFSTR(", USB vid/pid = 0x%0x/0x%0x"), + vid, + pid); + } + if (interfacePrivate->configurationAction != NULL) { + CFStringAppendFormat(result, NULL, CFSTR(", action = %@"), interfacePrivate->configurationAction); } + if (interfacePrivate->overrides != NULL) { + CFStringRef str; + str = _SCCopyDescription(interfacePrivate->overrides, formatOptions); + CFStringAppendFormat(result, formatOptions, CFSTR(", overrides = %@"), str); + CFRelease(str); + } + CFStringAppendFormat(result, NULL, CFSTR(", order = %d (%s)"), + interfacePrivate->sort_order, + interfacePrivate->sort_order <= kSortUnknown ? sortOrderName[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); + CFStringAppendFormat(result, NULL, CFSTR(", interface = %@"), interfacePrivate->interface); } - if (interfacePrivate->unsaved != NULL) { - CFStringAppendFormat(result, NULL, CFSTR(", unsaved=%@"), interfacePrivate->unsaved); + CFStringAppendFormat(result, formatOptions, CFSTR(", unsaved = %@"), interfacePrivate->unsaved); + } + + 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) { + CFStringRef str; + + str = _SCCopyDescription(interfacePrivate->bond.options, formatOptions); + CFStringAppendFormat(result, formatOptions, CFSTR(", options = %@"), str); + CFRelease(str); + } + + if (interfacePrivate->bridge.interfaces != NULL) { + CFIndex i; + CFIndex n; + + n = CFArrayGetCount(interfacePrivate->bridge.interfaces); + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef member; + + member = CFArrayGetValueAtIndex(interfacePrivate->bridge.interfaces, i); + CFStringAppendFormat(result, NULL, + CFSTR("%s%@"), + (i == 0) ? ", interfaces = " : ",", + SCNetworkInterfaceGetBSDName(member)); + } + } + if (interfacePrivate->bridge.options != NULL) { + CFStringRef str; + + str = _SCCopyDescription(interfacePrivate->bridge.options, formatOptions); + CFStringAppendFormat(result, formatOptions, CFSTR(", options = %@"), str); + CFRelease(str); + } + + 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) { + CFStringRef str; + + str = _SCCopyDescription(interfacePrivate->vlan.options, formatOptions); + CFStringAppendFormat(result, formatOptions, CFSTR(", options = %@"), str); + CFRelease(str); } - CFStringAppendFormat(result, NULL, CFSTR(" }")); + + CFStringAppendFormat(result, NULL, CFSTR("}")); return result; } @@ -266,8 +522,8 @@ __SCNetworkInterfaceDeallocate(CFTypeRef cf) /* release resources */ - if (interfacePrivate->interface != NULL) - CFRelease(interfacePrivate->interface); + if (interfacePrivate->name != NULL) + CFRelease(interfacePrivate->name); if (interfacePrivate->localized_name != NULL) CFRelease(interfacePrivate->localized_name); @@ -278,12 +534,27 @@ __SCNetworkInterfaceDeallocate(CFTypeRef cf) if (interfacePrivate->localized_arg2 != NULL) CFRelease(interfacePrivate->localized_arg2); + if (interfacePrivate->interface != NULL) + CFRelease(interfacePrivate->interface); + + if (interfacePrivate->prefs != NULL) + CFRelease(interfacePrivate->prefs); + + if (interfacePrivate->store != NULL) + CFRelease(interfacePrivate->store); + + 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); @@ -293,12 +564,72 @@ __SCNetworkInterfaceDeallocate(CFTypeRef cf) if (interfacePrivate->address != NULL) CFRelease(interfacePrivate->address); + if (interfacePrivate->addressString != NULL) + CFRelease(interfacePrivate->addressString); + + if (interfacePrivate->configurationAction != NULL) + CFRelease(interfacePrivate->configurationAction); + if (interfacePrivate->location != NULL) CFRelease(interfacePrivate->location); if (interfacePrivate->path != NULL) CFRelease(interfacePrivate->path); + if (interfacePrivate->overrides != NULL) + CFRelease(interfacePrivate->overrides); + + if (interfacePrivate->prefix != NULL) + CFRelease(interfacePrivate->prefix); + + if (interfacePrivate->type != NULL) + CFRelease(interfacePrivate->type); + + if (interfacePrivate->unit != NULL) + CFRelease(interfacePrivate->unit); + + if (interfacePrivate->family != NULL) + CFRelease(interfacePrivate->family); + + if (interfacePrivate->subfamily != NULL) + CFRelease(interfacePrivate->subfamily); + + if (interfacePrivate->usb.name != NULL) + CFRelease(interfacePrivate->usb.name); + + if (interfacePrivate->usb.pid != NULL) + CFRelease(interfacePrivate->usb.pid); + + if (interfacePrivate->usb.vid != NULL) + CFRelease(interfacePrivate->usb.vid); + + 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->bridge.interfaces != NULL) + CFRelease(interfacePrivate->bridge.interfaces); + + if (interfacePrivate->bridge.options != NULL) + CFRelease(interfacePrivate->bridge.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); +#if !TARGET_OS_SIMULATOR + if (interfacePrivate->IPMonitorControl != NULL) + CFRelease(interfacePrivate->IPMonitorControl); +#endif // !TARGET_OS_SIMULATOR return; } @@ -316,54 +647,120 @@ __SCNetworkInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2) return FALSE; // if not the same interface type } - if (if1->entity_device != if2->entity_device) { - if ((if1->entity_device != NULL) && (if2->entity_device != NULL)) { - if (!CFEqual(if1->entity_device, if2->entity_device)) { - return FALSE; // if not the same device - } - } else { - return FALSE; // if only one interface has a device + if (!_SC_CFEqual(if1->entity_device, if2->entity_device)) { + return FALSE; // if not the same device + } + + if ((if1->entity_device_unique != NULL) && (if2->entity_device_unique != NULL)) { + if (!_SC_CFEqual(if1->entity_device_unique, if2->entity_device_unique)) { + return FALSE; // if not the same device unique identifier + } + } else if ((if1->entity_device_unique != NULL) || (if2->entity_device_unique != NULL)) { + CFStringRef name1; + CFStringRef name2; + + name1 = __SCNetworkInterfaceGetNonLocalizedDisplayName((SCNetworkInterfaceRef)if1); + name2 = __SCNetworkInterfaceGetNonLocalizedDisplayName((SCNetworkInterfaceRef)if2); + if ((name1 != NULL) && (name2 != NULL) && !_SC_CFEqual(name1, name2)) { + return FALSE; // if same device but not the same display name + } + } + + if (CFEqual(if1->interface_type, kSCNetworkInterfaceTypeBond)) { + if (!_SC_CFEqual(if1->bond.interfaces, if2->bond.interfaces)) { + return FALSE; // if not the same interfaces + } + if (!_SC_CFEqual(if1->bond.mode, if2->bond.mode)) { + return FALSE; // if not the same mode + } + } + + if (CFEqual(if1->interface_type, kSCNetworkInterfaceTypeBridge)) { + if (!_SC_CFEqual(if1->bridge.interfaces, if2->bridge.interfaces)) { + return FALSE; // if not the same interfaces } } + if (CFEqual(if1->interface_type, kSCNetworkInterfaceTypeVLAN)) { + if (!_SC_CFEqual(if1->vlan.interface, if2->vlan.interface)) { + return FALSE; // if not the same physical interface + } + if (!_SC_CFEqual(if1->vlan.tag, if2->vlan.tag)) { + return FALSE; // if not the same tag + } + } + + if (!_SC_CFEqual(if1->interface, if2->interface)) { + return FALSE; // if not the same layering + } + 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; + // register w/CF __kSCNetworkInterfaceTypeID = _CFRuntimeRegisterClass(&__SCNetworkInterfaceClass); // initialize __kSCNetworkInterfaceIPv4 - _CFRuntimeSetInstanceTypeID(&__kSCNetworkInterfaceIPv4, __kSCNetworkInterfaceTypeID); + _CFRuntimeInitStaticInstance(&__kSCNetworkInterfaceIPv4, __kSCNetworkInterfaceTypeID); __kSCNetworkInterfaceIPv4.interface_type = kSCNetworkInterfaceTypeIPv4; __kSCNetworkInterfaceIPv4.localized_key = CFSTR("ipv4"); + // initialize __kSCNetworkInterfaceLoopback + _CFRuntimeInitStaticInstance(&__kSCNetworkInterfaceLoopback, __kSCNetworkInterfaceTypeID); + __kSCNetworkInterfaceLoopback.interface_type = kSCNetworkInterfaceTypeLoopback; + __kSCNetworkInterfaceLoopback.localized_key = CFSTR("loopback"); + __kSCNetworkInterfaceLoopback.entity_device = CFRetain(CFSTR("lo0")); + __kSCNetworkInterfaceLoopback.entity_type = kSCValNetInterfaceTypeLoopback; + // get CFBundleRef for SystemConfiguration.framework - bundle = CFBundleGetBundleWithIdentifier(SYSTEMCONFIGURATION_BUNDLE_ID); - if (bundle == NULL) { - // try a bit harder - CFURLRef url; + bundle = _SC_CFBundleGet(); - url = CFURLCreateWithFileSystemPath(NULL, - CFSTR("/System/Library/Frameworks/SystemConfiguration.framework"), - kCFURLPOSIXPathStyle, - TRUE); - bundle = CFBundleCreate(NULL, url); - CFRelease(url); + // get mach port used to communication with IOKit + kr = IOMasterPort(MACH_PORT_NULL, &masterPort); + if (kr != kIOReturnSuccess) { + SC_log(LOG_NOTICE, "could not get IOMasterPort, kr = 0x%x", kr); } return; } -__private_extern__ SCNetworkInterfacePrivateRef +__private_extern__ +SCNetworkInterfacePrivateRef __SCNetworkInterfaceCreatePrivate(CFAllocatorRef allocator, SCNetworkInterfaceRef interface, - SCNetworkServiceRef service, - io_string_t path) + SCPreferencesRef prefs, + CFStringRef serviceID) { SCNetworkInterfacePrivateRef interfacePrivate; uint32_t size; @@ -381,38 +778,219 @@ __SCNetworkInterfaceCreatePrivate(CFAllocatorRef allocator, return NULL; } - interfacePrivate->interface_type = 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->service = service; - interfacePrivate->unsaved = NULL; - interfacePrivate->entity_device = NULL; - interfacePrivate->entity_hardware = NULL; - interfacePrivate->entity_type = NULL; - interfacePrivate->entity_subtype = NULL; - interfacePrivate->supported_interface_types = NULL; - interfacePrivate->supported_protocol_types = NULL; - interfacePrivate->address = NULL; - interfacePrivate->builtin = FALSE; - interfacePrivate->path = (path != NULL) ? CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8) - : NULL; - interfacePrivate->location = NULL; - interfacePrivate->supportsDeviceOnHold = FALSE; - interfacePrivate->supportsBond = FALSE; - interfacePrivate->supportsVLAN = FALSE; - interfacePrivate->sort_order = kSortUnknown; + /* initialize non-zero/NULL members */ + interfacePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL; + interfacePrivate->prefs = (prefs != NULL) ? CFRetain(prefs) : NULL; + interfacePrivate->serviceID = (serviceID != NULL) ? CFRetain(serviceID) : NULL; + interfacePrivate->sort_order = kSortUnknown; return interfacePrivate; } -/* ---------- ordering ---------- */ +__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; + + // get the interface index + if_name = _SC_cfstring_to_cstring(bsd_if, NULL, 0, kCFStringEncodingASCII); + if (if_name == NULL) { + return FALSE; // if conversion error + } + if_index = if_nametoindex(if_name); + if (if_index == 0) { + goto done; // if unknown interface + } + + // get information for the specified interface + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_LINK; + mib[4] = NET_RT_IFLIST; + mib[5] = if_index; /* ask for exactly one interface */ + + if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) == -1) { + SC_log(LOG_NOTICE, "sysctl() size failed: %s", strerror(errno)); + goto done; + } + buf = CFAllocatorAllocate(NULL, buf_len, 0); + if (sysctl(mib, 6, buf, &buf_len, NULL, 0) == -1) { + SC_log(LOG_NOTICE, "sysctl() failed: %s", strerror(errno)); + goto done; + } + // check the link type and hwassist flags + // ALIGN: buf is aligned + ifm = (struct if_msghdr *)(void *)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; -static CFArrayRef + 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; +} + + +static CFDataRef +__SCCopyMacAddress(CFStringRef ifname) +{ + struct ifaddrs *ifap; + char ifname_c[IFNAMSIZ]; + struct ifaddrs *ifp; + CFDataRef macAddress = NULL; + + if(_SC_cfstring_to_cstring(ifname, + ifname_c, + sizeof(ifname_c), + kCFStringEncodingUTF8) == NULL) { + return NULL; + } + + if (getifaddrs(&ifap) == -1) { + _SCErrorSet(errno); + SC_log(LOG_NOTICE, "getifaddrs() failed: %s", strerror(errno)); + return NULL; + } + + for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) { + struct sockaddr_dl *sdl; + + if(strcmp(ifname_c, ifp->ifa_name) != 0) { + continue; + } + + /* ALIGN: cast ok, this should be aligned (getifaddrs). */ + sdl = (struct sockaddr_dl *)(void *)ifp->ifa_addr; + if (sdl->sdl_family != AF_LINK) { + continue; + } + + macAddress = CFDataCreate(NULL, (UInt8 *)LLADDR(sdl), sdl->sdl_alen); + break; + } + freeifaddrs(ifap); + return macAddress; +} + + +__private_extern__ +SCNetworkInterfacePrivateRef +_SCBondInterfaceCreatePrivate(CFAllocatorRef allocator, + CFStringRef bond_if) +{ + SCNetworkInterfacePrivateRef interfacePrivate; + + interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL); + if (interfacePrivate == NULL) { + return NULL; + } + + interfacePrivate->interface_type = kSCNetworkInterfaceTypeBond; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->entity_device = CFStringCreateCopy(allocator, bond_if); + interfacePrivate->address = __SCCopyMacAddress(interfacePrivate->entity_device); + 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); +// interfacePrivate->bond.mode = NULL; +// interfacePrivate->bond.options = NULL; + + return interfacePrivate; +} + + +__private_extern__ +SCNetworkInterfacePrivateRef +_SCBridgeInterfaceCreatePrivate(CFAllocatorRef allocator, + CFStringRef bridge_if) +{ + SCNetworkInterfacePrivateRef interfacePrivate; + + interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL); + if (interfacePrivate == NULL) { + return NULL; + } + + interfacePrivate->interface_type = kSCNetworkInterfaceTypeBridge; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->entity_device = CFStringCreateCopy(allocator, bridge_if); + interfacePrivate->address = __SCCopyMacAddress(interfacePrivate->entity_device); + interfacePrivate->builtin = TRUE; + interfacePrivate->supportsVLAN = __SCNetworkInterfaceSupportsVLAN(bridge_if); + interfacePrivate->sort_order = kSortBridge; + + interfacePrivate->localized_key = CFSTR("bridge"); + interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device); + + interfacePrivate->bridge.interfaces = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); +// interfacePrivate->bridge.options = NULL; + + return interfacePrivate; +} + + +__private_extern__ +SCNetworkInterfacePrivateRef +_SCVLANInterfaceCreatePrivate(CFAllocatorRef allocator, + CFStringRef vlan_if) +{ + SCNetworkInterfacePrivateRef interfacePrivate; + + interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL); + if (interfacePrivate == NULL) { + return NULL; + } + + interfacePrivate->interface_type = kSCNetworkInterfaceTypeVLAN; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->entity_device = CFStringCreateCopy(allocator, vlan_if); + interfacePrivate->address = __SCCopyMacAddress(interfacePrivate->entity_device); + interfacePrivate->builtin = TRUE; + interfacePrivate->sort_order = kSortVLAN; + + interfacePrivate->localized_key = CFSTR("vlan"); + interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device); + +// interfacePrivate->vlan.interface = NULL; +// interfacePrivate->vlan.tag = NULL; +// interfacePrivate->vlan.options = NULL; + + return interfacePrivate; +} + + +#pragma mark - +#pragma mark Interface ordering + + +static CF_RETURNS_RETAINED CFArrayRef split_path(CFStringRef path) { CFArrayRef components; @@ -434,9 +1012,10 @@ split_path(CFStringRef path) } -static CFComparisonResult -compare_interfaces(const void *val1, const void *val2, void *context) +CFComparisonResult +_SCNetworkInterfaceCompare(const void *val1, const void *val2, void *context) { +#pragma unused(context) SCNetworkInterfacePrivateRef dev1 = (SCNetworkInterfacePrivateRef)val1; SCNetworkInterfacePrivateRef dev2 = (SCNetworkInterfacePrivateRef)val2; CFComparisonResult res = kCFCompareEqualTo; @@ -559,9 +1138,20 @@ compare_interfaces(const void *val1, const void *val2, void *context) } } - /* ... and lastly, sort by BSD interface name */ + /* ... and, then sort by BSD interface name */ if ((dev1->entity_device != NULL) && (dev2->entity_device != NULL)) { res = CFStringCompare(dev1->entity_device, dev2->entity_device, 0); + if (res != kCFCompareEqualTo) { + return (res); + } + } + + /* ... and lastly, sort by BSD interface unique identifier */ + if ((dev1->entity_device_unique != NULL) && (dev2->entity_device_unique != NULL)) { + res = CFStringCompare(dev1->entity_device_unique, dev2->entity_device_unique, 0); +// if (res != kCFCompareEqualTo) { +// return (res); +// } } return res; @@ -571,18 +1161,30 @@ compare_interfaces(const void *val1, const void *val2, void *context) static void sort_interfaces(CFMutableArrayRef all_interfaces) { - int n = CFArrayGetCount(all_interfaces); + CFIndex n; + n = CFArrayGetCount(all_interfaces); if (n < 2) { return; } - CFArraySortValues(all_interfaces, CFRangeMake(0, n), compare_interfaces, NULL); + CFArraySortValues(all_interfaces, CFRangeMake(0, n), _SCNetworkInterfaceCompare, NULL); return; } -/* ---------- interface details ---------- */ +__private_extern__ +int +__SCNetworkInterfaceOrder(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->sort_order; +} + + +#pragma mark - +#pragma mark Interface details static CFStringRef @@ -593,13 +1195,43 @@ IOCopyCFStringValue(CFTypeRef ioVal) } if (isA_CFData(ioVal)) { - return CFStringCreateWithCString(NULL, CFDataGetBytePtr(ioVal), kCFStringEncodingUTF8); + return CFStringCreateWithCString(NULL, + (const char *)CFDataGetBytePtr(ioVal), + kCFStringEncodingUTF8); } return NULL; } +static CFStringRef +IODictionaryCopyBSDName(CFDictionaryRef io_dict) +{ + CFStringRef if_bsdName; + CFStringRef if_prefix; + CFNumberRef if_unit; + + if_bsdName = CFDictionaryGetValue(io_dict, CFSTR(kIOBSDNameKey)); + if (if_bsdName != NULL) { + return IOCopyCFStringValue(if_bsdName); + } + + // no BSD name, get interface prefix and unit + if_prefix = CFDictionaryGetValue(io_dict, CFSTR(kIOInterfaceNamePrefix)); + if_unit = CFDictionaryGetValue(io_dict, CFSTR(kIOInterfaceUnit)); + if (isA_CFString(if_prefix) && isA_CFNumber(if_unit)) { + // if both prefix and unit available, construct BSD name + if_bsdName = CFStringCreateWithFormat(NULL, + NULL, + CFSTR("%@%@"), + if_prefix, + if_unit); + } + + return if_bsdName; +}; + + static CFStringRef IODictionaryCopyCFStringValue(CFDictionaryRef io_dict, CFStringRef io_key) { @@ -615,7 +1247,7 @@ IOStringValueHasPrefix(CFTypeRef ioVal, CFStringRef prefix) { Boolean match = FALSE; CFIndex prefixLen = CFStringGetLength(prefix); - CFStringRef str = ioVal; + CFStringRef str = NULL; if (!isA_CFString(ioVal)) { if (isA_CFData(ioVal)) { @@ -623,58 +1255,26 @@ IOStringValueHasPrefix(CFTypeRef ioVal, CFStringRef prefix) (const char *)CFDataGetBytePtr(ioVal), kCFStringEncodingUTF8, kCFAllocatorNull); + ioVal = str; } else { return FALSE; } } - if ((str != NULL) && - (CFStringGetLength(str) >= prefixLen) && - (CFStringCompareWithOptions(str, + if ((ioVal != NULL) && + (CFStringGetLength(ioVal) >= prefixLen) && + (CFStringCompareWithOptions(ioVal, prefix, CFRangeMake(0, prefixLen), kCFCompareCaseInsensitive) == kCFCompareEqualTo)) { match = TRUE; } - if (str != ioVal) CFRelease(str); + if (str != NULL) CFRelease(str); return match; } -static CFStringRef -copyMACAddress(CFDictionaryRef controller_dict) -{ - CFStringRef address = NULL; - uint8_t *bp; - char *cp; - CFDataRef data; - CFIndex n; - char mac[sizeof("xx:xx:xx:xx:xx:xx:xx:xx")]; - char *mac_p = mac; - - data = CFDictionaryGetValue(controller_dict, CFSTR(kIOMACAddress)); - if (data == NULL) { - return NULL; - } - - bp = (uint8_t *)CFDataGetBytePtr(data); - n = CFDataGetLength(data) * 3; - - if (n > sizeof(mac)) { - mac_p = CFAllocatorAllocate(NULL, 0, n); - } - - for (cp = mac_p; n > 0; n -= 3) { - cp += snprintf(cp, n, "%2.2x:", *bp++); - } - - address = CFStringCreateWithCString(NULL, mac_p, kCFStringEncodingUTF8); - if (mac_p != mac) CFAllocatorDeallocate(NULL, mac_p); - return address; -} - - static const struct { const CFStringRef name; const CFStringRef slot; @@ -705,85 +1305,101 @@ static const struct { }; -static CFStringRef +static const CFStringRef slot_prefixes[] = { + CFSTR("thunderbolt slot "), + CFSTR("pci slot "), + CFSTR("slot-"), +}; + + +static CF_RETURNS_RETAINED CFStringRef pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name) { kern_return_t kr; - io_registry_entry_t slot = interface; + io_registry_entry_t parent; + CFMutableStringRef slot; + CFTypeRef slot_name; + slot = NULL; if (pci_slot_name != NULL) *pci_slot_name = NULL; - while (slot != MACH_PORT_NULL) { - io_registry_entry_t parent; - CFTypeRef slot_name; - - slot_name = IORegistryEntryCreateCFProperty(slot, CFSTR("AAPL,slot-name"), NULL, 0); - if (slot_name != NULL) { - Boolean found; - - found = IOStringValueHasPrefix(slot_name, CFSTR("slot")); - if (found) { - CFIndex i; - CFMutableStringRef name; + slot_name = IORegistryEntryCreateCFProperty(interface, CFSTR("AAPL,slot-name"), NULL, 0); + if (slot_name != NULL) { + 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 we found a slot # - name = CFStringCreateMutable(NULL, 0); - if (isA_CFString(slot_name)) { - if (pci_slot_name != NULL) *pci_slot_name = CFStringCreateCopy(NULL, slot_name); - CFStringAppend(name, slot_name); - } else if (isA_CFData(slot_name)) { - if (pci_slot_name != NULL) *pci_slot_name = CFDataCreateCopy(NULL, slot_name); - CFStringAppendCString(name, CFDataGetBytePtr(slot_name), kCFStringEncodingUTF8); - } + for (size_t i = 0; i < sizeof(slot_prefixes)/sizeof(slot_prefixes[0]); i++) { + CFIndex len; - (void) CFStringFindAndReplace(name, - CFSTR("slot-"), + len = CFStringGetLength(slot_prefixes[i]); + if (CFStringGetLength(slot) > len) { + (void) CFStringFindAndReplace(slot, + slot_prefixes[i], CFSTR(""), - CFRangeMake(0, 5), + CFRangeMake(0, len), kCFCompareCaseInsensitive|kCFCompareAnchored); - for (i = 0; i < sizeof(slot_mappings)/sizeof(slot_mappings[0]); i++) { - if (CFStringCompareWithOptions(name, - slot_mappings[i].name, - CFRangeMake(0, CFStringGetLength(slot_mappings[i].name)), - kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - CFRelease(name); - name = (CFMutableStringRef)CFRetain(slot_mappings[i].slot); - break; - } - } - - CFRelease(slot_name); - if (slot != interface) IOObjectRelease(slot); - return name; } - - CFRelease(slot_name); } - kr = IORegistryEntryGetParentEntry(slot, kIOServicePlane, &parent); - if (slot != interface) IOObjectRelease(slot); - switch (kr) { - case kIOReturnSuccess : - slot = parent; + for (size_t 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; - case kIOReturnNoDevice : - // if we have hit the root node without finding a slot # - goto done; - default : - SCLog(TRUE, LOG_INFO, CFSTR("pci_slot IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr); - goto done; + } } + + CFRelease(slot_name); } - done : + kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &parent); + switch (kr) { + case kIOReturnSuccess : { + CFTypeRef parent_pci_slot_name = NULL; + CFStringRef parent_slot; - return NULL; + 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 { + if (parent_pci_slot_name != NULL) CFRelease(parent_pci_slot_name); + } + } + + IOObjectRelease(parent); + break; + } + case kIOReturnNoDevice : + // if we have hit the root node + break; + default : + SC_log(LOG_INFO, "IORegistryEntryGetParentEntry() failed, kr = 0x%x", kr); + break; + } + + return slot; } static CFComparisonResult compare_bsdNames(const void *val1, const void *val2, void *context) { +#pragma unused(context) CFStringRef bsd1 = (CFStringRef)val1; CFStringRef bsd2 = (CFStringRef)val2; @@ -791,8 +1407,8 @@ compare_bsdNames(const void *val1, const void *val2, void *context) } -static CFStringRef -pci_port(mach_port_t masterPort, CFTypeRef slot_name, CFStringRef bsdName) +static CF_RETURNS_RETAINED CFStringRef +pci_port(CFTypeRef slot_name, int ift, CFStringRef bsdName) { CFIndex n; CFStringRef port_name = NULL; @@ -833,7 +1449,7 @@ pci_port(mach_port_t masterPort, CFTypeRef slot_name, CFStringRef bsdName) kr = IOServiceGetMatchingServices(masterPort, matching, &slot_iterator); if (kr != kIOReturnSuccess) { - SCPrint(TRUE, stderr, CFSTR("IOServiceGetMatchingServices() failed, kr = 0x%x\n"), kr); + SC_log(LOG_INFO, "IOServiceGetMatchingServices() failed, kr = 0x%x", kr); return MACH_PORT_NULL; } @@ -848,21 +1464,40 @@ pci_port(mach_port_t masterPort, CFTypeRef slot_name, CFStringRef bsdName) kIORegistryIterateRecursively, &child_iterator); if (kr != kIOReturnSuccess) { - SCPrint(TRUE, stderr, CFSTR("IORegistryEntryCreateIterator() failed, kr = 0x%x\n"), kr); + SC_log(LOG_INFO, "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; + CFMutableDictionaryRef interface_dict = NULL; + + (void) IORegistryEntryCreateCFProperties(child, &interface_dict, NULL, kNilOptions); + if (interface_dict != NULL) { + CFNumberRef child_if_type; + int child_ift = ift; + + child_if_type = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceType)); + if (child_if_type != NULL) { + if (!isA_CFNumber(child_if_type) || + !CFNumberGetValue(child_if_type, kCFNumberIntType, &child_ift)) { + // assume that it's a match + child_ift = ift; + } + } - if_bsdName = IORegistryEntryCreateCFProperty(child, - CFSTR(kIOBSDNameKey), - NULL, - 0); - if (if_bsdName != NULL) { - CFArrayAppendValue(port_names, if_bsdName); - CFRelease(if_bsdName); + if (ift == child_ift) { + CFStringRef if_bsdName; + + if_bsdName = IODictionaryCopyBSDName(interface_dict); + if (if_bsdName != NULL) { + CFArrayAppendValue(port_names, if_bsdName); + CFRelease(if_bsdName); + } + } + + CFRelease(interface_dict); } } IOObjectRelease(child); @@ -877,7 +1512,7 @@ pci_port(mach_port_t masterPort, CFTypeRef slot_name, CFStringRef bsdName) 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); + port_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%ld"), n + 1); } } @@ -887,16 +1522,22 @@ pci_port(mach_port_t masterPort, CFTypeRef slot_name, CFStringRef bsdName) static Boolean -pci_slot_info(mach_port_t masterPort, io_registry_entry_t interface, CFStringRef *slot_name, CFStringRef *port_name) +pci_slot_info(io_registry_entry_t interface, int ift, CFStringRef *slot_name, CFStringRef *port_name) { - CFStringRef bsd_name; - Boolean ok = FALSE; - CFTypeRef pci_slot_name; + CFStringRef bsd_name = NULL; + CFMutableDictionaryRef interface_dict = NULL; + Boolean ok = FALSE; + CFTypeRef pci_slot_name; *slot_name = NULL; *port_name = NULL; - bsd_name = IORegistryEntryCreateCFProperty(interface, CFSTR(kIOBSDNameKey), NULL, 0); + (void) IORegistryEntryCreateCFProperties(interface, &interface_dict, NULL, kNilOptions); + if (interface_dict != NULL) { + bsd_name = IODictionaryCopyBSDName(interface_dict); + CFRelease(interface_dict); + } + if (bsd_name == NULL) { return FALSE; } @@ -904,7 +1545,7 @@ pci_slot_info(mach_port_t masterPort, io_registry_entry_t interface, CFStringRef *slot_name = pci_slot(interface, &pci_slot_name); if (*slot_name != NULL) { if (pci_slot_name != NULL) { - *port_name = pci_port(masterPort, pci_slot_name, bsd_name); + *port_name = pci_port(pci_slot_name, ift, bsd_name); CFRelease(pci_slot_name); } ok = TRUE; @@ -916,53 +1557,189 @@ pci_slot_info(mach_port_t masterPort, io_registry_entry_t interface, CFStringRef static Boolean -isBuiltIn(io_registry_entry_t interface) +isBuiltin(io_registry_entry_t interface) { - kern_return_t kr; - io_registry_entry_t slot = interface; + CFStringRef slot; - while (slot != MACH_PORT_NULL) { - io_registry_entry_t parent; - CFTypeRef slot_name; + slot = pci_slot(interface, NULL); + if (slot != NULL) { + // interfaces which have a "slot" are not built-in + CFRelease(slot); + return FALSE; + } - slot_name = IORegistryEntryCreateCFProperty(slot, CFSTR("AAPL,slot-name"), NULL, 0); - if (slot_name != NULL) { - Boolean found; + return TRUE; +} - found = IOStringValueHasPrefix(slot_name, CFSTR("slot")); - CFRelease(slot_name); - if (found) { - // if we found a slot # then this is not a built-in interface - if (slot != interface) IOObjectRelease(slot); - return FALSE; - } +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) { + SC_log(LOG_INFO, "IOServiceGetMatchingServices() failed, kr = 0x%x", kr); } + *haveController = FALSE; + return FALSE; + } + *haveController = TRUE; + + hciController = IOIteratorNext(iter); + IOObjectRelease(iter); + if(hciController != MACH_PORT_NULL) { +#if !TARGET_OS_SIMULATOR + 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; + } - kr = IORegistryEntryGetParentEntry(slot, kIOServicePlane, &parent); - if (slot != interface) IOObjectRelease(slot); - switch (kr) { - case kIOReturnSuccess : - slot = parent; - break; - case kIOReturnNoDevice : - // if we have hit the root node without finding a slot # - return TRUE; - default : - SCLog(TRUE, LOG_INFO, CFSTR("isBuiltIn IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr); - return FALSE; + CFRelease(idVendor); } +#endif // !TARGET_OS_SIMULATOR + + IOObjectRelease(hciController); + } + + return builtin; +} + + +static Boolean +isThunderbolt(io_registry_entry_t interface) +{ + CFTypeRef val; + + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + CFSTR(kPCIThunderboltString), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if (val != NULL) { + CFRelease(val); + return TRUE; } return FALSE; } -/* ---------- interface enumeration ---------- */ +static void +processUSBInterface(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) +{ +#if TARGET_OS_SIMULATOR +#pragma unused(interfacePrivate) +#pragma unused(interface) +#endif // TARGET_OS_SIMULATOR +#pragma unused(interface_dict) +#pragma unused(controller) +#pragma unused(controller_dict) +#pragma unused(bus) +#pragma unused(bus_dict) +#if !TARGET_OS_SIMULATOR + // capture USB info + if (interfacePrivate->usb.name == NULL) { + interfacePrivate->usb.name = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + CFSTR(kUSBProductString), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + } + if (interfacePrivate->usb.vid == NULL) { + interfacePrivate->usb.vid = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + CFSTR(kUSBVendorID), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + } + if (interfacePrivate->usb.pid == NULL) { + interfacePrivate->usb.pid = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + CFSTR(kUSBProductID), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + } +#endif // !TARGET_OS_SIMULATOR + + return; +} + + +static Boolean +update_interface_name(SCNetworkInterfacePrivateRef interfacePrivate, + io_registry_entry_t interface, + Boolean useUSBInfo) +{ + Boolean updated = FALSE; + CFTypeRef val; + + // check if a "Product Name" has been provided + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + CFSTR(kIOPropertyProductNameKey), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if ((val == NULL) && useUSBInfo && (interfacePrivate->usb.name != NULL)) { + // else, use "USB Product Name" if available + val = CFRetain(interfacePrivate->usb.name); + } + if (val != NULL) { + CFStringRef productName; + + productName = IOCopyCFStringValue(val); + CFRelease(val); + + if (productName != NULL) { + if (CFStringGetLength(productName) > 0) { + // if we have a [somewhat reasonable?] product name + if (interfacePrivate->name != NULL) { + CFRelease(interfacePrivate->name); + } + interfacePrivate->name = CFRetain(productName); + if (interfacePrivate->localized_name != NULL) { + CFRelease(interfacePrivate->localized_name); + interfacePrivate->localized_name = NULL; + } + if (bundle != NULL) { + interfacePrivate->localized_name = copy_interface_string(bundle, productName, TRUE); + } + + updated = TRUE; + } + + CFRelease(productName); + } + } + + return updated; +} + + +#pragma mark - +#pragma mark Interface enumeration -typedef Boolean (*processInterface)(mach_port_t masterPort, - SCNetworkInterfacePrivateRef interfacePrivate, +typedef Boolean (*processInterface)(SCNetworkInterfacePrivateRef interfacePrivate, io_registry_entry_t interface, CFDictionaryRef interface_dict, io_registry_entry_t controller, @@ -971,9 +1748,40 @@ typedef Boolean (*processInterface)(mach_port_t masterPort, CFDictionaryRef bus_dict); +static void +merge_override(SCNetworkInterfacePrivateRef interfacePrivate, + io_registry_entry_t interface, + CFStringRef override) +{ + CFStringRef key; + CFTypeRef val; + + key = CFStringCreateWithFormat(NULL, NULL, CFSTR("Device%@Overrides"), override); + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + key, + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + CFRelease(key); + if (val != NULL) { + if (isA_CFDictionary(val)) { + if (interfacePrivate->overrides == NULL) { + interfacePrivate->overrides = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + CFDictionarySetValue(interfacePrivate->overrides, override, val); + } + CFRelease(val); + } + + return; +} + + static Boolean -processNetworkInterface(mach_port_t masterPort, - SCNetworkInterfacePrivateRef interfacePrivate, +processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate, io_registry_entry_t interface, CFDictionaryRef interface_dict, io_registry_entry_t controller, @@ -981,21 +1789,20 @@ processNetworkInterface(mach_port_t masterPort, io_registry_entry_t bus, CFDictionaryRef bus_dict) { - CFBooleanRef bVal; - io_name_t c_IOClass; - io_name_t c_IOName; - io_name_t i_IOClass; + CFDataRef data; int ift = -1; int iVal; CFNumberRef num; CFStringRef str; + CFBooleanRef val; - // get the interface type - + // interface type num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceType)); - if (!isA_CFNumber(num) || - !CFNumberGetValue(num, kCFNumberIntType, &ift)) { - SCPrint(TRUE, stderr, CFSTR("Could not get interface type\n")); + if (isA_CFNumber(num) && + CFNumberGetValue(num, kCFNumberIntType, &ift)) { + interfacePrivate->type = CFRetain(num); + } else { + SC_log(LOG_INFO, "no interface type: %@", interface_dict); return FALSE; } @@ -1003,57 +1810,129 @@ processNetworkInterface(mach_port_t masterPort, case IFT_ETHER : // Type, Hardware - if (IOObjectGetClass(interface, i_IOClass) != KERN_SUCCESS) { - i_IOClass[0] = '\0'; + 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, "AppleThunderboltIPPort")) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortThunderbolt; + } else if (IOObjectConformsTo(controller, "IOBluetoothBNEPDriver")) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortBluetoothPAN_GN; + } else if (IOObjectConformsTo(controller, "AppleUSBEthernetHost")) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortTethered; + } else if (IOObjectConformsTo(controller, "AppleUSBCDCECMData")) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortWWANEthernet; } - if (IOObjectGetClass(controller, c_IOClass) != KERN_SUCCESS) { - c_IOClass[0] = '\0'; + + if (interfacePrivate->interface_type == NULL) { + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + CFSTR(kIOUserEthernetInterfaceRoleKey), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if (val != NULL) { + if (isA_CFString(val)) { + if (CFEqual(val, CFSTR(BT_PAN_NAME))) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortBluetoothPAN_GN; + } else if (CFEqual(val, CFSTR("Bluetooth PAN-NAP"))) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortBluetoothPAN_NAP; + } else if (CFEqual(val, CFSTR("Bluetooth P2P"))) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortBluetoothPAN_U; + } else if (CFEqual(val, CFSTR("CarPlay"))) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortCarPlay; + } + } + + CFRelease(val); + } } - if (IORegistryEntryGetName(controller, c_IOName) != KERN_SUCCESS) { - c_IOName[0] = '\0'; + +#if TARGET_OS_OSX + if (interfacePrivate->interface_type == NULL) { + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + CFSTR(kUSBSupportsIPhoneOS), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if (val != NULL) { + if (isA_CFBoolean(val) && CFBooleanGetValue(val)) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortTethered; + } + + CFRelease(val); + } } +#endif // TARGET_OS_OSX - if ((strcmp(i_IOClass, "IO80211Interface" ) == 0) || - (strcmp(c_IOClass, "AirPortPCI" ) == 0) || - (strcmp(c_IOClass, "AirPortDriver" ) == 0) || - (strcmp(c_IOName , "AppleWireless80211") == 0)) { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211; - interfacePrivate->entity_type = kSCEntNetEthernet; - interfacePrivate->entity_hardware = kSCEntNetAirPort; - interfacePrivate->sort_order = kSortAirPort; - } else { + if (interfacePrivate->interface_type == NULL) { str = IODictionaryCopyCFStringValue(bus_dict, CFSTR("name")); - if ((str != NULL) && CFEqual(str, CFSTR("radio"))) { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; // ?? - interfacePrivate->entity_type = kSCEntNetEthernet; - interfacePrivate->entity_hardware = kSCEntNetEthernet; // ?? - interfacePrivate->sort_order = kSortOtherWireless; - } else { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; - interfacePrivate->entity_type = kSCEntNetEthernet; - interfacePrivate->entity_hardware = kSCEntNetEthernet; - interfacePrivate->sort_order = kSortEthernet; + if (str != NULL) { + if (CFEqual(str, CFSTR("radio"))) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; // ?? + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortOtherWireless; + } - // BOND support only enabled for ethernet devices - interfacePrivate->supportsBond = TRUE; + CFRelease(str); } + } + + if (interfacePrivate->interface_type == NULL) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortEthernet; - if (str != NULL) CFRelease(str); + // BOND support only enabled for ethernet devices + interfacePrivate->supportsBond = TRUE; } + // enable Bridge support + interfacePrivate->supportsBridge = TRUE; + // built-in - bVal = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOBuiltin))); - if ((bVal == NULL) || !CFBooleanGetValue(bVal)) { - bVal = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOPrimaryInterface))); + val = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOBuiltin))); + if (val == NULL) { + val = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOPrimaryInterface))); } - if (bVal != NULL) { - interfacePrivate->builtin = CFBooleanGetValue(bVal); + if (val != NULL) { + interfacePrivate->builtin = CFBooleanGetValue(val); } else { - interfacePrivate->builtin = isBuiltIn(interface); + interfacePrivate->builtin = isBuiltin(interface); + } + + if (!interfacePrivate->builtin && + CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) { + // always treat AirPort interfaces as built-in + interfacePrivate->builtin = TRUE; } // location interfacePrivate->location = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOLocation)); + if ((interfacePrivate->location != NULL) && + (CFStringGetLength(interfacePrivate->location) == 0)) { + CFRelease(interfacePrivate->location); + interfacePrivate->location = NULL; + } // VLAN support num = CFDictionaryGetValue(controller_dict, CFSTR(kIOFeatures)); @@ -1065,19 +1944,33 @@ processNetworkInterface(mach_port_t masterPort, } // localized name - if (interfacePrivate->builtin) { + if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) { + interfacePrivate->localized_key = CFSTR("airport"); + } else if (interfacePrivate->sort_order == kSortThunderbolt) { if ((interfacePrivate->location == NULL) || (CFStringGetLength(interfacePrivate->location) == 0)) { - interfacePrivate->localized_key = CFSTR("ether"); + interfacePrivate->localized_key = CFSTR("thunderbolt"); } else { - interfacePrivate->localized_key = CFSTR("multiether"); + interfacePrivate->localized_key = CFSTR("multithunderbolt"); interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->location); } - } else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) { - interfacePrivate->localized_key = CFSTR("airport"); - } else if (interfacePrivate->sort_order == kSortOtherWireless) { + } else if (interfacePrivate->sort_order == kSortBluetoothPAN_GN) { + interfacePrivate->localized_key = CFSTR("bluetooth-pan-gn"); + } else if (interfacePrivate->sort_order == kSortBluetoothPAN_NAP) { + interfacePrivate->localized_key = CFSTR("bluetooth-pan-nap"); + } else if (interfacePrivate->sort_order == kSortBluetoothPAN_U) { + interfacePrivate->localized_key = CFSTR("bluetooth-pan-u"); + } 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; @@ -1092,24 +1985,84 @@ processNetworkInterface(mach_port_t masterPort, CFStringRef port_name; CFStringRef slot_name; - if (pci_slot_info(masterPort, interface, &slot_name, &port_name)) { - if (port_name == NULL) { - interfacePrivate->localized_key = CFSTR("pci-ether"); - interfacePrivate->localized_arg1 = slot_name; + // set interface "name" + if (!update_interface_name(interfacePrivate, interface, FALSE) && + pci_slot_info(interface, ift, &slot_name, &port_name)) { + if (isThunderbolt(interface)) { + if (port_name == NULL) { + interfacePrivate->localized_key = CFSTR("thunderbolt-ether"); + interfacePrivate->localized_arg1 = slot_name; + } else { + interfacePrivate->localized_key = CFSTR("thunderbolt-multiether"); + interfacePrivate->localized_arg1 = slot_name; + interfacePrivate->localized_arg2 = port_name; + } + + } else { + 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 { + io_registry_entry_t node = interface; + + while (provider != NULL) { +#if !TARGET_OS_SIMULATOR + if (CFEqual(provider, CFSTR(kIOUSBDeviceClassName)) || + CFEqual(provider, CFSTR(kIOUSBInterfaceClassName)) || + CFEqual(provider, CFSTR(kIOUSBHostInterfaceClassName))) { + // get USB info (if available) + processUSBInterface(interfacePrivate, + interface, + interface_dict, + controller, + controller_dict, + bus, + bus_dict); + + // set interface "name" + if (!update_interface_name(interfacePrivate, interface, TRUE)) { + interfacePrivate->localized_key = CFSTR("usb-ether"); + interfacePrivate->localized_arg1 = IODictionaryCopyBSDName(interface_dict); + } + break; + } +#endif // !TARGET_OS_SIMULATOR + + if (node == interface) { + node = controller; + } else if (node == controller ) { + node = bus; } else { - interfacePrivate->localized_key = CFSTR("pci-multiether"); - interfacePrivate->localized_arg1 = slot_name; - interfacePrivate->localized_arg2 = port_name; + break; } + + CFRelease(provider); + provider = IORegistryEntrySearchCFProperty(node, + kIOServicePlane, + CFSTR(kIOProviderClassKey), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + } + + if (interfacePrivate->localized_key == NULL) { + update_interface_name(interfacePrivate, interface, FALSE); } } - CFRelease(provider); + + if (provider != NULL) CFRelease(provider); } if (interfacePrivate->localized_key == NULL) { // if no provider, not a PCI device, or no slot information interfacePrivate->localized_key = CFSTR("generic-ether"); - interfacePrivate->localized_arg1 = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey)); + interfacePrivate->localized_arg1 = IODictionaryCopyBSDName(interface_dict); } } @@ -1119,11 +2072,10 @@ processNetworkInterface(mach_port_t masterPort, interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire; // Entity - interfacePrivate->entity_type = kSCEntNetFireWire; - interfacePrivate->entity_hardware = kSCEntNetFireWire; + interfacePrivate->entity_type = kSCValNetInterfaceTypeFireWire; // built-in - interfacePrivate->builtin = isBuiltIn(interface); + interfacePrivate->builtin = isBuiltin(interface); // sort order interfacePrivate->sort_order = kSortFireWire; @@ -1132,34 +2084,179 @@ processNetworkInterface(mach_port_t masterPort, if (interfacePrivate->builtin) { interfacePrivate->localized_key = CFSTR("firewire"); } else { + CFStringRef port_name; CFStringRef slot_name; - slot_name = pci_slot(interface, NULL); - if (slot_name != NULL) { - interfacePrivate->localized_key = CFSTR("pci-firewire"); - interfacePrivate->localized_arg1 = slot_name; + // set interface "name" + if (!update_interface_name(interfacePrivate, interface, FALSE) && + pci_slot_info(interface, ift, &slot_name, &port_name)) { + if (isThunderbolt(interface)) { + if (port_name == NULL) { + interfacePrivate->localized_key = CFSTR("thunderbolt-firewire"); + interfacePrivate->localized_arg1 = slot_name; + } else { + interfacePrivate->localized_key = CFSTR("thunderbolt-multifirewire"); + interfacePrivate->localized_arg1 = slot_name; + interfacePrivate->localized_arg2 = port_name; + } + } else { + if (port_name == NULL) { + interfacePrivate->localized_key = CFSTR("pci-firewire"); + interfacePrivate->localized_arg1 = slot_name; + } else { + interfacePrivate->localized_key = CFSTR("pci-multifirewire"); + interfacePrivate->localized_arg1 = slot_name; + interfacePrivate->localized_arg2 = port_name; + } + } } } break; default : - SCPrint(TRUE, stderr, CFSTR("Unknown interface type = %d\n"), ift); + SC_log(LOG_INFO, "unknown interface type = %d", ift); return FALSE; } // Device - interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey)); + interfacePrivate->entity_device = IODictionaryCopyBSDName(interface_dict); // Hardware (MAC) address - interfacePrivate->address = copyMACAddress(controller_dict); + data = CFDictionaryGetValue(controller_dict, CFSTR(kIOMACAddress)); + if (isA_CFData(data)) { + interfacePrivate->address = CFRetain(data); + } + + // interface prefix + str = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceNamePrefix)); + if (isA_CFString(str)) { + interfacePrivate->prefix = CFRetain(str); + } + + // interface unit + num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceUnit)); + if (isA_CFNumber(num) && + CFNumberGetValue(num, kCFNumberIntType, & iVal)) { + interfacePrivate->unit = CFRetain(num); + } + + // configuration [PPP] template override (now deprecated, use NetworkConfigurationOverrides) + merge_override(interfacePrivate, interface, kSCNetworkInterfaceTypePPP); 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]; + sysdir_search_path_enumeration_state state; + + (void) _SC_cfstring_to_cstring(script, + ccl, + sizeof(ccl), + kCFStringEncodingUTF8); + + state = sysdir_start_search_path_enumeration(SYSDIR_DIRECTORY_LIBRARY, + SYSDIR_DOMAIN_MASK_LOCAL|SYSDIR_DOMAIN_MASK_SYSTEM); + while ((state = sysdir_get_next_search_path_enumeration(state, path))) { + size_t n; + struct stat statBuf; + + if (ccl[0] == '/') { + path[0] = '\0'; // if modemCCL is a full path + } else { + strlcat(path, "/Modem Scripts/", sizeof(path)); + } + strlcat(path, ccl, sizeof(path)); + + if (stat(path, &statBuf) != 0) { + if (errno == ENOENT) { + goto bundle; + } + + SC_log(LOG_INFO, "stat() failed: %s", strerror(errno)); + continue; + } + if (S_ISREG(statBuf.st_mode)) { + // if we have a valid CCL script + 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; + } + + SC_log(LOG_INFO, "stat() failed: %s", strerror(errno)); + continue; + } + } + if (S_ISDIR(statBuf.st_mode)) { + // if we have a valid CCL bundle + return TRUE; + } + } + + return FALSE; +} + + static Boolean -processSerialInterface(mach_port_t masterPort, - SCNetworkInterfacePrivateRef interfacePrivate, +processSerialInterface(SCNetworkInterfacePrivateRef interfacePrivate, io_registry_entry_t interface, CFDictionaryRef interface_dict, io_registry_entry_t controller, @@ -1167,28 +2264,52 @@ processSerialInterface(mach_port_t masterPort, io_registry_entry_t bus, CFDictionaryRef bus_dict) { + CFStringRef base = NULL; CFStringRef ift; - Boolean isModem = FALSE; - CFStringRef str; + Boolean isModem = FALSE; + Boolean isWWAN = FALSE; + CFStringRef modemCCL = NULL; + Boolean ok = FALSE; CFTypeRef val; - // check if hidden + // check if initializing + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + kSCNetworkInterfaceInitializingKey, + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if (val != NULL) { + Boolean initializing; + + initializing = isA_CFBoolean(val) && CFBooleanGetValue(val); + CFRelease(val); + if (initializing) { + return FALSE; // if this interface is still initializing + } + } + + // check if WWAN val = IORegistryEntrySearchCFProperty(interface, kIOServicePlane, - CFSTR("HiddenPort"), + CFSTR("WWAN"), NULL, kIORegistryIterateRecursively | kIORegistryIterateParents); if (val != NULL) { + isWWAN = isA_CFBoolean(val) && CFBooleanGetValue(val); CFRelease(val); - return FALSE; // if this interface should not be exposed } - // Type - str = CFDictionaryGetValue(interface_dict, CFSTR(kIOTTYBaseNameKey)); - if (str == NULL) { + // Entity (Device) + 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); + } + /* * From MoreSCF: * @@ -1197,39 +2318,35 @@ processSerialInterface(mach_port_t masterPort, * that only the rev A actually had an IrDA port, and Mac OS X doesn't * even support it, these ports definitely shouldn't be listed. */ - if (CFStringCompare(str, + if (CFStringCompare(base, CFSTR("irda"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - return FALSE; + goto done; } - if (IOStringValueHasPrefix(str, CFSTR("irda-ircomm"))) { - // IrDA - interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA; - interfacePrivate->sort_order = kSortIrDA; - } else if (IOStringValueHasPrefix(str, CFSTR("bluetooth"))) { + if (IOStringValueHasPrefix(base, CFSTR("bluetooth"))) { + Boolean haveController = FALSE; + // Bluetooth interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth; interfacePrivate->sort_order = kSortBluetooth; + interfacePrivate->builtin = isBluetoothBuiltin(&haveController); + if (!haveController) { + // if device with no controller present + goto done; + } + } else if (IOStringValueHasPrefix(base, CFSTR("irda-ircomm"))) { + // IrDA + interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA; + interfacePrivate->sort_order = kSortIrDA; + } else if (isWWAN) { + // WWAN + interfacePrivate->interface_type = kSCNetworkInterfaceTypeWWAN; + interfacePrivate->sort_order = kSortWWAN; } else { // Modem interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem; - - // DeviceOnHold support - val = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR(kIODeviceSupportsHoldKey), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - if (val != NULL) { - uint32_t supportsHold; - - if (isA_CFNumber(val) && - CFNumberGetValue(val, kCFNumberSInt32Type, &supportsHold)) { - interfacePrivate->supportsDeviceOnHold = (supportsHold == 1); - } - CFRelease(val); - } + interfacePrivate->sort_order = kSortModem; } // Entity (Type) @@ -1238,32 +2355,70 @@ processSerialInterface(mach_port_t masterPort, // Entity (Hardware) ift = CFDictionaryGetValue(interface_dict, CFSTR(kIOSerialBSDTypeKey)); if (!isA_CFString(ift)) { - return FALSE; + goto done; } if (CFEqual(ift, CFSTR(kIOSerialBSDModemType))) { // if modem isModem = TRUE; - interfacePrivate->entity_hardware = kSCEntNetModem; - if (CFEqual(str, CFSTR("modem"))) { + if (CFEqual(base, CFSTR("modem"))) { interfacePrivate->builtin = TRUE; interfacePrivate->sort_order = kSortInternalModem; - } else if (CFEqual(str, CFSTR("usbmodem"))) { + } else if (CFEqual(base, CFSTR("usbmodem"))) { interfacePrivate->sort_order = kSortUSBModem; - } else { - interfacePrivate->sort_order = kSortModem; } } else if (CFEqual(ift, CFSTR(kIOSerialBSDRS232Type))) { // if serial port - interfacePrivate->entity_hardware = kSCEntNetModem; interfacePrivate->sort_order = kSortSerialPort; } else { - return FALSE; + goto done; } - // Entity (Device) - interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOTTYDeviceKey)); + // configuration [PPP] template override (now deprecated, use NetworkConfigurationOverrides) + merge_override(interfacePrivate, interface, kSCNetworkInterfaceTypePPP); + + // configuration [Modem] template override (now deprecated, use NetworkConfigurationOverrides) + merge_override(interfacePrivate, interface, kSCNetworkInterfaceTypeModem); + + // look for modem CCL, unique identifier + if (interfacePrivate->overrides != NULL) { + val = CFDictionaryGetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem); + if (val != NULL) { + CFStringRef uniqueID; + + modemCCL = CFDictionaryGetValue(val, kSCPropNetModemConnectionScript); + modemCCL = isA_CFString(modemCCL); + + uniqueID = CFDictionaryGetValue(val, CFSTR("UniqueIdentifier")); + uniqueID = isA_CFString(uniqueID); + if (uniqueID != NULL) { + // retain the device's base name and the unique id + CFRelease(interfacePrivate->entity_device); + interfacePrivate->entity_device = CFRetain(base); + interfacePrivate->entity_device_unique = CFStringCreateCopy(NULL, uniqueID); + } + } + } + + // if not part of the NetworkConfigurationOverrides/DeviceModemOverrides, look + // a bit harder for the modem CCL + 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); + } + } // localized name if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIrDA)) { @@ -1271,20 +2426,38 @@ processSerialInterface(mach_port_t masterPort, } else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBluetooth)) { interfacePrivate->localized_key = CFSTR("bluetooth"); } else { - CFStringRef localized; + CFStringRef localized = NULL; + CFStringRef name = NULL; CFMutableStringRef port; - port = CFStringCreateMutableCopy(NULL, 0, str); + port = CFStringCreateMutableCopy(NULL, 0, base); CFStringLowercase(port, NULL); if (!isModem) { CFStringAppend(port, CFSTR("-port")); } - localized = CFBundleCopyLocalizedString(bundle, - port, - port, - NETWORKINTERFACE_LOCALIZATIONS); + // set non-localized name + if (bundle != NULL) { + name = copy_interface_string(bundle, port, FALSE); + } + if (name != NULL) { + if (!CFEqual(port, name)) { + // if [English] localization available + interfacePrivate->name = name; + } else { + // if no [English] localization available, use TTY base name + CFRelease(name); + interfacePrivate->name = CFStringCreateCopy(NULL, base); + } + } else { + interfacePrivate->name = CFStringCreateCopy(NULL, base); + } + + // set localized name + if (bundle != NULL) { + localized = copy_interface_string(bundle, port, TRUE); + } if (localized != NULL) { if (!CFEqual(port, localized)) { // if localization available @@ -1292,32 +2465,29 @@ processSerialInterface(mach_port_t masterPort, } else { // if no localization available, use TTY base name CFRelease(localized); - interfacePrivate->localized_name = CFStringCreateCopy(NULL, str); + interfacePrivate->localized_name = CFStringCreateCopy(NULL, base); } } else { - interfacePrivate->localized_name = CFStringCreateCopy(NULL, str); + interfacePrivate->localized_name = CFStringCreateCopy(NULL, base); } - if (!isModem || !CFEqual(str, CFSTR("modem"))) { - CFStringRef productName; - - // check if a "Product Name" has been provided - val = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR(kIOPropertyProductNameKey), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - if (val != NULL) { - productName = IOCopyCFStringValue(val); - CFRelease(val); - - if (productName != NULL) { - if (CFStringGetLength(productName) > 0) { - // if we have a [somewhat reasonable?] product name - CFRelease(interfacePrivate->localized_name); - interfacePrivate->localized_name = CFRetain(productName); - } - CFRelease(productName); + if (!isModem || !CFEqual(base, CFSTR("modem"))) { + // get USB info (if available) + processUSBInterface(interfacePrivate, + interface, + interface_dict, + controller, + controller_dict, + bus, + bus_dict); + + // set interface "name" + if (update_interface_name(interfacePrivate, interface, TRUE)) { + // if "ModemCCL" not provided, also check if the product/interface + // name matches a CCL script + if ((modemCCL == NULL) && + is_valid_connection_script(interfacePrivate->name)) { + set_connection_script(interfacePrivate, interfacePrivate->name); } } } @@ -1325,93 +2495,295 @@ processSerialInterface(mach_port_t masterPort, CFRelease(port); } - return TRUE; + 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 CFArrayRef -findMatchingInterfaces(mach_port_t masterPort, CFDictionaryRef matching, processInterface func) +static CFStringRef +__SC_IORegistryEntryCopyPath(io_registry_entry_t entry, const io_name_t plane) { - CFMutableArrayRef interfaces; - io_registry_entry_t interface; - kern_return_t kr; - io_iterator_t iterator = MACH_PORT_NULL; + /* + * Create a path for a registry entry. + */ + io_string_t path; + IOReturn status; + CFStringRef str = NULL; + + status = IORegistryEntryGetPath(entry, plane, path); + if (status == kIOReturnSuccess) { + str = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8); + } else if (status == kIOReturnBadArgument) { + io_registry_entry_t parent; - kr = IOServiceGetMatchingServices(masterPort, matching, &iterator); - if (kr != kIOReturnSuccess) { - SCPrint(TRUE, stderr, CFSTR("IOServiceGetMatchingServices() failed, kr = 0x%x\n"), kr); - return NULL; + status = IORegistryEntryGetParentEntry(entry, plane, &parent); + if (status == kIOReturnSuccess) { + CFStringRef str_parent; + + str_parent = __SC_IORegistryEntryCopyPath(parent, plane); + if (str_parent != NULL) { + io_name_t name; + + status = IORegistryEntryGetNameInPlane(entry, plane, name); + if (status == kIOReturnSuccess) { + io_name_t location; + + status = IORegistryEntryGetLocationInPlane(entry, plane, location); + if (status == kIOReturnSuccess) { + str = CFStringCreateWithFormat(NULL, + NULL, + CFSTR("%@/%s@%s"), + str_parent, + name, + location); + } else { + str = CFStringCreateWithFormat(NULL, + NULL, + CFSTR("%@/%s"), + str_parent, + name); + } + } + + CFRelease(str_parent); + } + + IOObjectRelease(parent); + } } - interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + return str; +} - while ((interface = IOIteratorNext(iterator)) != MACH_PORT_NULL) { - 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; - io_string_t path; - - kr = IORegistryEntryGetPath(interface, kIOServicePlane, path); - if (kr != kIOReturnSuccess) { - SCPrint(TRUE, stderr, CFSTR("IORegistryEntryGetPath() failed, kr = 0x%x"), kr); - goto done; +static CFMutableDictionaryRef +copyIORegistryProperties(io_registry_entry_t reg_ent, const CFStringRef *reg_keys, CFIndex numKeys) +{ + CFIndex idx = 0; + CFMutableDictionaryRef reg_dict = NULL; + CFTypeRef value = NULL; + + reg_dict = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks , + &kCFTypeDictionaryValueCallBacks); + + for (; idx < numKeys; idx++) { + value = IORegistryEntryCreateCFProperty(reg_ent, reg_keys[idx], NULL, 0); + if (value != NULL) { + CFDictionaryAddValue(reg_dict, reg_keys[idx], value); + CFRelease(value); } + } - kr = IORegistryEntryCreateCFProperties(interface, &interface_dict, NULL, kNilOptions); - if (kr != kIOReturnSuccess) { - SCPrint(TRUE, stderr, CFSTR("IORegistryEntryCreateCFProperties() failed, kr = 0x%x\n"), kr); - goto done; + return reg_dict; +} + +static SCNetworkInterfaceRef +createInterface(io_registry_entry_t interface, processInterface func, + CFStringRef hidden_key) +{ + io_registry_entry_t bus = MACH_PORT_NULL; + CFMutableDictionaryRef bus_dict = NULL; + io_registry_entry_t controller = MACH_PORT_NULL; + CFMutableDictionaryRef controller_dict = NULL; + uint64_t entryID = 0; + SCNetworkInterfacePrivateRef interfacePrivate = NULL; + CFMutableDictionaryRef interface_dict = NULL; + kern_return_t kr; + CFTypeRef val; + + // Keys of interest + const CFStringRef interface_dict_keys[] = { + CFSTR(kIOInterfaceType), + CFSTR(kIOBuiltin), + CFSTR(kIOBSDNameKey), + CFSTR(kIOPrimaryInterface), + CFSTR(kIOInterfaceNamePrefix), + CFSTR(kIOInterfaceUnit), + CFSTR(kIOTTYDeviceKey), + CFSTR(kIOTTYBaseNameKey), + CFSTR(kIOSerialBSDTypeKey), + CFSTR(kIOLocation) + }; + + const CFStringRef controller_dict_keys[] = { + CFSTR(kIOFeatures), + CFSTR(kIOMACAddress) + }; + + const CFStringRef bus_dict_keys[] = { + CFSTR("name") + }; + + if (hidden_key != NULL) { + // check if hidden + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + hidden_key, + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if (val != NULL) { + CFRelease(val); + goto done; // if this interface should not be exposed } + } - /* get the controller node */ - kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &controller); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr); - goto done; + interface_dict = copyIORegistryProperties(interface, + interface_dict_keys, + sizeof(interface_dict_keys)/sizeof(interface_dict_keys[0])); + + // get the controller node + kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &controller); + if (kr != kIOReturnSuccess) { + SC_log(LOG_INFO, "IORegistryEntryGetParentEntry() failed, kr = 0x%x", kr); + goto done; + } + + controller_dict = copyIORegistryProperties(controller, + controller_dict_keys, + sizeof(controller_dict_keys)/sizeof(controller_dict_keys[0])); + + // get the bus node + kr = IORegistryEntryGetParentEntry(controller, kIOServicePlane, &bus); + if (kr != kIOReturnSuccess) { + SC_log(LOG_INFO, "IORegistryEntryGetParentEntry() failed, kr = 0x%x", kr); + goto done; + } + + bus_dict = copyIORegistryProperties(bus, + bus_dict_keys, + sizeof(bus_dict_keys)/sizeof(bus_dict_keys[0])); + + // get the registry entry ID + kr = IORegistryEntryGetRegistryEntryID(interface, &entryID); + if (kr != kIOReturnSuccess) { + SC_log(LOG_INFO, "IORegistryEntryGetRegistryEntryID() failed, kr = 0x%x", kr); + goto done; + } + + interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); + assert(interfacePrivate != NULL); + interfacePrivate->path = __SC_IORegistryEntryCopyPath(interface, kIOServicePlane); + interfacePrivate->entryID = entryID; + + // configuration [PPP, Modem, DNS, IPv4, IPv6, Proxies, SMB] template overrides + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + kSCNetworkInterfaceNetworkConfigurationOverridesKey, + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if (val != NULL) { + if (isA_CFDictionary(val)) { + interfacePrivate->overrides = CFDictionaryCreateMutableCopy(NULL, 0, val); } + CFRelease(val); + } - /* get the dictionary associated with the node */ - kr = IORegistryEntryCreateCFProperties(controller, &controller_dict, NULL, kNilOptions); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr); - goto done; + if ((*func)(interfacePrivate, interface, interface_dict, controller, controller_dict, bus, bus_dict)) { + // get user-notification / auto-configuration preference + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + kSCNetworkInterfaceConfigurationActionKey, + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if (val != NULL) { + if (isA_CFString(val)) { + interfacePrivate->configurationAction = CFRetain(val); + } + CFRelease(val); } - /* get the bus node */ - kr = IORegistryEntryGetParentEntry(controller, kIOServicePlane, &bus); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr); - goto done; + // get HiddenConfiguration preference + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + kSCNetworkInterfaceHiddenConfigurationKey, + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if (val != NULL) { + interfacePrivate->hidden = TRUE; + CFRelease(val); } - /* get the dictionary associated with the node */ - kr = IORegistryEntryCreateCFProperties(bus, &bus_dict, NULL, kNilOptions); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr); - goto done; +#if TARGET_OS_IPHONE + // get TrustRequired preference + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + kSCNetworkInterfaceTrustRequiredKey, + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if (val != NULL) { + if (isA_CFBoolean(val)) { + interfacePrivate->trustRequired = CFBooleanGetValue(val); + } + CFRelease(val); } +#endif // TARGET_OS_IPHONE + } else { + CFRelease(interfacePrivate); + interfacePrivate = NULL; + } + + done : - interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, path); + if (interface_dict != NULL) CFRelease(interface_dict); - if ((*func)(masterPort, interfacePrivate, interface, interface_dict, controller, controller_dict, bus, bus_dict)) { - CFArrayAppendValue(interfaces, (SCNetworkInterfaceRef)interfacePrivate); - } + if (controller != MACH_PORT_NULL) IOObjectRelease(controller); + if (controller_dict != NULL) CFRelease(controller_dict); - CFRelease(interfacePrivate); + if (bus != MACH_PORT_NULL) IOObjectRelease(bus); + if (bus_dict != NULL) CFRelease(bus_dict); + + return (SCNetworkInterfaceRef)interfacePrivate; +} + + +static CF_RETURNS_RETAINED CFArrayRef +findMatchingInterfaces(CFDictionaryRef matching, + processInterface func, + CFStringRef hidden_key, + Boolean keep_pre_configured) +{ + CFMutableArrayRef interfaces; + io_registry_entry_t interface; + kern_return_t kr; + io_iterator_t iterator = MACH_PORT_NULL; + + /* + * A reference to the "matching" dictionary will be consumed by the + * the call to IOServiceGetMatchingServices so we bump up the retain + * count. + */ + CFRetain(matching); - done: + kr = IOServiceGetMatchingServices(masterPort, matching, &iterator); + if (kr != kIOReturnSuccess) { + SC_log(LOG_INFO, "IOServiceGetMatchingServices() failed, kr = 0x%x", kr); + return NULL; + } - if (interface != MACH_PORT_NULL) IOObjectRelease(interface); - if (interface_dict != NULL) CFRelease(interface_dict); + interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + while ((interface = IOIteratorNext(iterator)) != MACH_PORT_NULL) { + SCNetworkInterfaceRef match; - if (controller != MACH_PORT_NULL) IOObjectRelease(controller); - if (controller_dict != NULL) CFRelease(controller_dict); + match = createInterface(interface, func, hidden_key); + if (match != NULL) { + if (keep_pre_configured || !_SCNetworkInterfaceIsApplePreconfigured(match)) { + CFArrayAppendValue(interfaces, match); + } + CFRelease(match); + } - if (bus != MACH_PORT_NULL) IOObjectRelease(bus); - if (bus_dict != NULL) CFRelease(bus_dict); + IOObjectRelease(interface); } IOObjectRelease(iterator); @@ -1420,1022 +2792,5713 @@ findMatchingInterfaces(mach_port_t masterPort, CFDictionaryRef matching, process } -/* ---------- Bond configuration ---------- */ +#pragma mark - +#pragma mark helper functions -Boolean -SCNetworkInterfaceSupportsBonding(SCNetworkInterfaceRef interface) + +static CFIndex +findConfiguration(CFStringRef interface_type) { - return ((SCNetworkInterfacePrivateRef)interface)->supportsBond; + for (size_t i = 0; i < sizeof(configurations)/sizeof(configurations[0]); i++) { + if (CFEqual(interface_type, *configurations[i].interface_type)) { + return i; + } + } + + return kCFNotFound; } -SCNetworkInterfaceRef -SCNetworkInterfaceCreateWithBond(BondInterfaceRef bond) +__private_extern__ +CFStringRef +__SCNetworkInterfaceGetDefaultConfigurationType(SCNetworkInterfaceRef interface) { - SCNetworkInterfacePrivateRef interfacePrivate; - CFStringRef bond_if; + CFIndex interfaceIndex; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; - bond_if = BondInterfaceGetInterface(bond); - if (bond_if == NULL) { + if (interfacePrivate->serviceID == NULL) { + // if not associated with a service (yet) + _SCErrorSet(kSCStatusInvalidArgument); return NULL; } - interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); - if (interfacePrivate == NULL) { - return NULL; + interfaceIndex = findConfiguration(interfacePrivate->interface_type); + if (interfaceIndex == kCFNotFound) { + // unknown interface type, use per-service configuration preferences + return interfacePrivate->interface_type; // entity } - interfacePrivate->interface_type = kSCNetworkInterfaceTypeBond; - interfacePrivate->entity_type = kSCEntNetEthernet; - interfacePrivate->entity_hardware = kSCEntNetEthernet; - interfacePrivate->entity_device = CFStringCreateCopy(NULL, bond_if); - interfacePrivate->builtin = TRUE; - interfacePrivate->sort_order = kSortBond; - - interfacePrivate->localized_key = CFSTR("bond"); - interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device); + if (configurations[interfaceIndex].entity_hardware != NULL) { + // if configuration information can be associated with this interface type + return *configurations[interfaceIndex].entity_hardware; + } - return (SCNetworkInterfaceRef)interfacePrivate; + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; } -static CFArrayRef -findBondInterfaces(CFStringRef match) +__private_extern__ +Boolean +__SCNetworkInterfaceIsValidExtendedConfigurationType(SCNetworkInterfaceRef interface, + CFStringRef extendedType, + Boolean requirePerInterface) { - CFMutableArrayRef interfaces = NULL; - CFIndex i; - CFIndex n; - BondPreferencesRef prefs; - CFArrayRef bonds = NULL; + CFStringRef defaultType; + CFIndex extendedIndex; + CFIndex interfaceIndex; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + Boolean isL2TP = FALSE; + Boolean ok = FALSE; - prefs = BondPreferencesCreate(NULL); - if (prefs == NULL) { - // if no bonds - return NULL; + defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface); + if (defaultType == NULL) { + goto done; } - bonds = BondPreferencesCopyInterfaces(prefs); - if (bonds == NULL) { - // if no bonds + if (CFEqual(extendedType, defaultType)) { + // extended and default configuration types cannot conflict goto done; } - n = CFArrayGetCount(bonds); - if (n == 0) { - // if no bonds + interfaceIndex = findConfiguration(interfacePrivate->interface_type); + if (interfaceIndex == kCFNotFound) { + // configuration information for unknown interface type's + // are stored along with the service and we don't allow + // per-service extended configurations goto done; } - interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (CFEqual(extendedType, kSCEntNetIPSec)) { + CFStringRef interfaceType; - for (i = 0; i < n; i++) { - SCNetworkInterfaceRef interface; - BondInterfaceRef bond = CFArrayGetValueAtIndex(bonds, i); - CFStringRef bond_if; + interfaceType = SCNetworkInterfaceGetInterfaceType(interface); + if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) { + SCNetworkInterfaceRef child; - bond_if = BondInterfaceGetInterface(bond); - if (bond_if == NULL) { - continue; + child = SCNetworkInterfaceGetInterface(interface); + if (child != NULL) { + interfaceType = SCNetworkInterfaceGetInterfaceType(child); + if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) { + isL2TP = TRUE; + } + } } + } - if ((match != NULL) && !CFEqual(bond_if, match)) { - continue; - } + if (requirePerInterface && + !configurations[interfaceIndex].per_interface_config && + !isL2TP) { + // we don't allow per-service extended configurations (except + // that we do allow IPSec as an extended type for PPP->L2TP) + goto done; + } - interface = SCNetworkInterfaceCreateWithBond(bond); - CFArrayAppendValue(interfaces, interface); - CFRelease(interface); + extendedIndex = findConfiguration(extendedType); + if ((extendedIndex != kCFNotFound) && !isL2TP) { + // extended type cannot match a known interface type (except + // that we do allow IPSec as an extended type for PPP->L2TP) + goto done; } + /* + * ??? + * Should we check/match and specifically allow known extended + * configuration types (e.g. EAPOL)? + * + * Should we check/match and specifically block known internal + * configuration types (e.g. QoSMarking)? + * + * Lastly, should we ensure that any non-standard extended configuration + * types be of the form com.myCompany.myType? + * ??? + */ + + ok = TRUE; + done : - if (bonds != NULL) CFRelease(bonds); - CFRelease(prefs); - return interfaces; + if (!ok) { + _SCErrorSet(kSCStatusInvalidArgument); + } + return ok; } -/* ---------- VLAN configuration ---------- */ +typedef struct { + CFStringRef defaultType; + CFMutableArrayRef types; +} extendedConfiguration, *extendedConfigurationRef; -SCNetworkInterfaceRef -SCNetworkInterfaceCreateWithVLAN(VLANInterfaceRef vlan) + +static void +__addExtendedConfigurationType(const void *key, const void *value, void *context) { - SCNetworkInterfacePrivateRef interfacePrivate; - CFStringRef vlan_if; +#pragma unused(value) + CFStringRef extendedType = (CFStringRef)key; + extendedConfigurationRef myContextRef = (extendedConfigurationRef)context; - vlan_if = VLANInterfaceGetInterface(vlan); - if (vlan_if == NULL) { - return NULL; + if (CFEqual(extendedType, myContextRef->defaultType)) { + // do not include the default configuration type + return; } - interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); - if (interfacePrivate == NULL) { - return NULL; + if (CFArrayContainsValue(myContextRef->types, + CFRangeMake(0, CFArrayGetCount(myContextRef->types)), + extendedType)) { + // if extendedType already has already been added + return; } - interfacePrivate->interface_type = kSCNetworkInterfaceTypeVLAN; - interfacePrivate->entity_type = kSCEntNetEthernet; - interfacePrivate->entity_hardware = kSCEntNetEthernet; - interfacePrivate->entity_device = CFStringCreateCopy(NULL, vlan_if); - interfacePrivate->builtin = TRUE; - interfacePrivate->sort_order = kSortVLAN; - - interfacePrivate->localized_key = CFSTR("vlan"); - interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device); + CFArrayAppendValue(myContextRef->types, extendedType); - return (SCNetworkInterfaceRef)interfacePrivate; + return; } -static CFArrayRef -findVLANInterfaces(CFStringRef match) +static CFIndex +findPerInterfaceConfiguration(SCNetworkInterfaceRef interface) { - CFMutableArrayRef interfaces = NULL; - CFIndex i; - CFIndex n; - VLANPreferencesRef prefs; - CFArrayRef vlans = NULL; + CFIndex interfaceIndex; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; - prefs = VLANPreferencesCreate(NULL); - if (prefs == NULL) { - // if no VLANs - return NULL; + interfaceIndex = findConfiguration(interfacePrivate->interface_type); + if (interfaceIndex == kCFNotFound) { + // if per-service (not per interface) configuration + return kCFNotFound; + } + + if (!configurations[interfaceIndex].per_interface_config) { + // if per-interface configuration not allowed + return kCFNotFound; + } + + return interfaceIndex; +} + + +static CF_RETURNS_RETAINED 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; } - vlans = VLANPreferencesCopyInterfaces(prefs); - if (vlans == NULL) { - // if no VLANs + myContext.types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + if (interfacePrivate->serviceID == NULL) { + // if not associated with a service (yet) goto done; } - n = CFArrayGetCount(vlans); - if (n == 0) { - // if no VLANs + interfaceIndex = findPerInterfaceConfiguration(interface); + if (interfaceIndex == kCFNotFound) { + // if no per-interface configuration goto done; } - interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL, + interfacePrivate->prefs, + interfacePrivate->serviceID, + interface); - for (i = 0; i < n; i++) { - SCNetworkInterfaceRef interface; - VLANInterfaceRef vlan = CFArrayGetValueAtIndex(vlans, i); - CFStringRef vlan_if; + sets = SCNetworkSetCopyAll(interfacePrivate->prefs); + n = (sets != NULL) ? CFArrayGetCount(sets) : 0; - vlan_if = VLANInterfaceGetInterface(vlan); - if (vlan_if == NULL) { + for (i = 0; i < n; i++) { + CFDictionaryRef configs; + Boolean found; + CFStringRef path; + CFArrayRef services; + SCNetworkSetRef set; + + set = CFArrayGetValueAtIndex(sets, i); + services = SCNetworkSetCopyServices(set); + found = CFArrayContainsValue(services, + CFRangeMake(0, CFArrayGetCount(services)), + service); + CFRelease(services); + + if (!found) { continue; } - if ((match != NULL) && !CFEqual(vlan_if, match)) { - continue; + // add stored extended configuration types + path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator + SCNetworkSetGetSetID(set), // set + interfacePrivate->entity_device, // service + NULL); // entity + configs = __getPrefsConfiguration(interfacePrivate->prefs, path); + CFRelease(path); + if (isA_CFDictionary(configs)) { + CFDictionaryApplyFunction(configs, + __addExtendedConfigurationType, + &myContext); } - interface = SCNetworkInterfaceCreateWithVLAN(vlan); - CFArrayAppendValue(interfaces, interface); - CFRelease(interface); + // add not-yet-stored extended configuration types + if (interfacePrivate->unsaved != NULL) { + CFDictionaryApplyFunction(interfacePrivate->unsaved, + __addExtendedConfigurationType, + &myContext); + } + + break; } + CFRelease(service); + if (sets != NULL) CFRelease(sets); + done : - if (vlans != NULL) CFRelease(vlans); - CFRelease(prefs); - return interfaces; + return myContext.types; } +static CFArrayRef +stringCreateArray(CFStringRef str) +{ + return (CFArrayCreate(NULL, (const void **)&str, 1, &kCFTypeArrayCallBacks)); +} -/* ---------- interface from preferences ---------- */ - - -__private_extern__ SCNetworkInterfaceRef -__SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, - CFDictionaryRef interface_entity, - SCNetworkServiceRef service) +static CFArrayRef +copyPerInterfaceConfigurationPaths(SCNetworkInterfacePrivateRef interfacePrivate, + CFStringRef extendedType) { - SCNetworkInterfacePrivateRef interfacePrivate = NULL; - CFStringRef ifDevice; - CFStringRef ifSubType; - CFStringRef ifType; - static mach_port_t masterPort = MACH_PORT_NULL; - CFArrayRef matching_interfaces = NULL; + CFMutableArrayRef array = NULL; + CFIndex i; + CFIndex n; + CFStringRef path; + SCNetworkServiceRef service; + CFArrayRef sets; - if (masterPort == MACH_PORT_NULL) { - kern_return_t kr; + // known interface type, per-interface configuration preferences + // + // 1. look for all sets which contain the associated service + // 2. add a per-set path for the interface configuration for + // each set. - kr = IOMasterPort(MACH_PORT_NULL, &masterPort); - if (kr != KERN_SUCCESS) { - return NULL; - } - } + service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL, + interfacePrivate->prefs, + interfacePrivate->serviceID, + (SCNetworkInterfaceRef)interfacePrivate); - ifType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceType); - if (!isA_CFString(ifType)) { - return NULL; - } + sets = SCNetworkSetCopyAll(interfacePrivate->prefs); + n = (sets != NULL) ? CFArrayGetCount(sets) : 0; - ifSubType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceSubType); - if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { - if (!isA_CFString(ifSubType)) { - return NULL; + for (i = 0; i < n; i++) { + CFArrayRef services; + SCNetworkSetRef set; + + set = CFArrayGetValueAtIndex(sets, i); + services = SCNetworkSetCopyServices(set); + if (CFArrayContainsValue(services, + CFRangeMake(0, CFArrayGetCount(services)), + service)) { + path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator + SCNetworkSetGetSetID(set), // set + interfacePrivate->entity_device, // service + extendedType); // entity + if (array == NULL) { + array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + CFArrayAppendValue(array, path); + CFRelease(path); } + CFRelease(services); } - ifDevice = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceDeviceName); + CFRelease(service); + if (sets != NULL) CFRelease(sets); + return array; - if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet) || - CFEqual(ifType, kSCValNetInterfaceTypeFireWire) || - (CFEqual(ifType, kSCValNetInterfaceTypePPP) && CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE))) { - char bsdName[IFNAMSIZ + 1]; - CFMutableDictionaryRef matching; +} - if (!isA_CFString(ifDevice)) { - return NULL; - } +static CFArrayRef +copyConfigurationPaths(SCNetworkInterfacePrivateRef interfacePrivate, + CFStringRef extendedType) +{ + CFArrayRef array = NULL; + CFIndex interfaceIndex; + CFStringRef path; - if (_SC_cfstring_to_cstring(ifDevice, bsdName, sizeof(bsdName), kCFStringEncodingASCII) == NULL) { - goto done; - } + interfaceIndex = findConfiguration(interfacePrivate->interface_type); + if (interfaceIndex == kCFNotFound) { + // unknown interface type, use per-service configuration preferences + path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator + interfacePrivate->serviceID, // service + extendedType); // entity + array = stringCreateArray(path); + CFRelease(path); + } - matching = IOBSDNameMatching(masterPort, 0, bsdName); - if (matching == NULL) { - goto done; - } + else if (!configurations[interfaceIndex].per_interface_config) { + // known interface type, per-service configuration preferences + path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator + interfacePrivate->serviceID, // service + extendedType); // entity + array = stringCreateArray(path); + CFRelease(path); + } - // note: the "matching" dictionary will be consumed by the following - matching_interfaces = findMatchingInterfaces(masterPort, matching, processNetworkInterface); + else if (interfacePrivate->serviceID != NULL) { + array = copyPerInterfaceConfigurationPaths(interfacePrivate, extendedType); + } - } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { - if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) { - CFDictionaryRef matching; - CFStringRef match_keys[2]; - CFStringRef match_vals[2]; + return (array); +} - if (!isA_CFString(ifDevice)) { - return NULL; - } - match_keys[0] = CFSTR(kIOProviderClassKey); - match_vals[0] = CFSTR(kIOSerialBSDServiceValue); +#pragma mark - +#pragma mark SCNetworkInterface <--> preferences entity + - match_keys[1] = CFSTR(kIOTTYDeviceKey); - match_vals[1] = ifDevice; +__private_extern__ +CFDictionaryRef +__SCNetworkInterfaceCopyInterfaceEntity(SCNetworkInterfaceRef interface) +{ + CFMutableDictionaryRef entity; + CFIndex interfaceIndex; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; - matching = CFDictionaryCreate(NULL, - (const void **)match_keys, - (const void **)match_vals, - sizeof(match_keys)/sizeof(match_keys[0]), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + entity = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (interfacePrivate->entity_type != NULL) { + CFDictionarySetValue(entity, + kSCPropNetInterfaceType, + interfacePrivate->entity_type); + } + if (interfacePrivate->entity_subtype != NULL) { + CFDictionarySetValue(entity, + kSCPropNetInterfaceSubType, + interfacePrivate->entity_subtype); + } + if (interfacePrivate->entity_device != NULL) { + CFDictionarySetValue(entity, + kSCPropNetInterfaceDeviceName, + interfacePrivate->entity_device); + } + if (interfacePrivate->entity_device_unique != NULL) { + CFDictionarySetValue(entity, + CFSTR("DeviceUniqueIdentifier"), + interfacePrivate->entity_device_unique); + } + if (interfacePrivate->hidden) { + CFDictionarySetValue(entity, + kSCNetworkInterfaceHiddenConfigurationKey, + kCFBooleanTrue); + } +#if TARGET_OS_IPHONE + if (interfacePrivate->trustRequired) { + CFDictionarySetValue(entity, + kSCNetworkInterfaceTrustRequiredKey, + kCFBooleanTrue); + } +#endif // TARGET_OS_IPHONE - // note: the "matching" dictionary will be consumed by the following - matching_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface); + // match the "hardware" with the lowest layer + while (TRUE) { + SCNetworkInterfaceRef nextInterface; - } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypeL2TP)) { - interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, - kSCNetworkInterfaceTypeL2TP); - } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPTP)) { - interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, - kSCNetworkInterfaceTypePPTP); - } else { - // XXX do we allow non-Apple variants of PPP??? XXX - interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, - ifSubType); - } - } else if (CFEqual(ifType, kSCValNetInterfaceType6to4)) { - if (!isA_CFString(ifDevice)) { - return NULL; + nextInterface = SCNetworkInterfaceGetInterface(interface); + if (nextInterface == NULL) { + break; } - interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, - kSCNetworkInterfaceType6to4); + interface = nextInterface; } + interfacePrivate = (SCNetworkInterfacePrivateRef)interface; - if (matching_interfaces != NULL) { - CFIndex n; - - n = CFArrayGetCount(matching_interfaces); - switch (n) { - case 0 : - if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) { - CFArrayRef bonds; - CFArrayRef vlans; - - bonds = findBondInterfaces(ifDevice); - if (bonds != NULL) { - if (CFArrayGetCount(bonds) == 1) { - interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(bonds, 0); - CFRetain(interfacePrivate); - } - CFRelease(bonds); - break; - } + if (CFEqual(interface, kSCNetworkInterfaceIPv4)) { + return entity; + } - vlans = findVLANInterfaces(ifDevice); - if (vlans != NULL) { - if (CFArrayGetCount(vlans) == 1) { - interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(vlans, 0); - CFRetain(interfacePrivate); - } - CFRelease(vlans); - break; - } - } - break; - case 1 : - interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0); - CFRetain(interfacePrivate); - break; - default : - SCPrint(TRUE, stderr, CFSTR("more than one interface matches %@\n"), ifDevice); - if (matching_interfaces != NULL) CFRelease(matching_interfaces); - _SCErrorSet(kSCStatusFailed); - return NULL; + interfaceIndex = findConfiguration(interfacePrivate->interface_type); + if (interfaceIndex != kCFNotFound) { + if (configurations[interfaceIndex].entity_hardware != NULL) { + CFDictionarySetValue(entity, + kSCPropNetInterfaceHardware, + *configurations[interfaceIndex].entity_hardware); } - CFRelease(matching_interfaces); + } else { + CFDictionarySetValue(entity, + kSCPropNetInterfaceHardware, + interfacePrivate->interface_type); } - done : + // add the localized display name (which will only be used when/if the + // interface is removed from the system) + CFDictionarySetValue(entity, + kSCPropUserDefinedName, + SCNetworkInterfaceGetLocalizedDisplayName(interface)); - if (interfacePrivate == NULL) { - /* - * if device not present on this system - */ - interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); - interfacePrivate->entity_type = ifType; - interfacePrivate->entity_subtype = ifSubType; - interfacePrivate->entity_device = (ifDevice != NULL) ? CFStringCreateCopy(NULL, ifDevice) : NULL; - interfacePrivate->entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware); + return entity; +} - if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) { - if ((interfacePrivate->entity_hardware != NULL) && - CFEqual(interfacePrivate->entity_hardware, kSCEntNetAirPort)) { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211; - } else { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; - } - } else if (CFEqual(ifType, kSCValNetInterfaceTypeFireWire)) { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire; - } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { - if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE)) { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; - } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) { - if (CFStringHasPrefix(ifDevice, CFSTR("irda"))) { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA; - } else if (CFStringHasPrefix(ifDevice, CFSTR("Bluetooth"))) { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth; - } else { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem; - } - } else { - // PPTP, L2TP, ... - CFRelease(interfacePrivate); - interfacePrivate = (SCNetworkInterfacePrivateRef)kSCNetworkInterfaceIPv4; - CFRetain(interfacePrivate); - } - } else { - // unknown interface type - CFRelease(interfacePrivate); - interfacePrivate = NULL; - } - } - if ((interfacePrivate != NULL) && (service != NULL)) { - interfacePrivate->service = service; - } +static SCNetworkInterfaceRef +findInterface(CFArrayRef interfaces, CFStringRef match_if) +{ + CFIndex i; + CFIndex n; - if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { - SCNetworkInterfaceRef parent; + n = CFArrayGetCount(interfaces); + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef interface = CFArrayGetValueAtIndex(interfaces, i); + CFStringRef interfaceName; - parent = SCNetworkInterfaceCreateWithInterface((SCNetworkInterfaceRef)interfacePrivate, - kSCNetworkInterfaceTypePPP); - CFRelease(interfacePrivate); - interfacePrivate = (SCNetworkInterfacePrivateRef)parent; + interfaceName = SCNetworkInterfaceGetBSDName(interface); + if ((interfaceName != NULL) && CFEqual(interfaceName, match_if)) { + CFRetain(interface); + return interface; + } } - return (SCNetworkInterfaceRef)interfacePrivate; + return NULL; } +#if !TARGET_OS_IPHONE +static SCNetworkInterfaceRef +findBondInterface(SCPreferencesRef prefs, CFStringRef ifDevice) +{ + CFArrayRef bonds; + SCNetworkInterfaceRef interface = NULL; -/* ---------- helper functions ---------- */ + if (prefs == NULL) { + return (NULL); + } + // check if the interface is an Ethernet Bond + bonds = SCBondInterfaceCopyAll(prefs); + if (bonds != NULL) { + interface = findInterface(bonds, ifDevice); + CFRelease(bonds); + } + return interface; +} +#endif // !TARGET_OS_IPHONE -static CFIndex -findConfiguration(CFStringRef interface_type) +static SCNetworkInterfaceRef +findBridgeInterface(SCPreferencesRef prefs, CFStringRef ifDevice) { - CFIndex i; + CFArrayRef bridges; + SCNetworkInterfaceRef interface = NULL; - for (i = 0; i < sizeof(configurations)/sizeof(configurations[0]); i++) { - if (CFEqual(interface_type, *configurations[i].interface_type)) { - return i; - } + if (prefs == NULL) { + return (NULL); } - return kCFNotFound; + // check if the interface is an bridge + bridges = SCBridgeInterfaceCopyAll(prefs); + if (bridges != NULL) { + interface = findInterface(bridges, ifDevice); + CFRelease(bridges); + } + return interface; } - -static CFArrayRef -copyConfigurationPaths(SCNetworkInterfacePrivateRef interfacePrivate) +static SCNetworkInterfaceRef +findVLANInterface(SCPreferencesRef prefs, CFStringRef ifDevice) { - CFMutableArrayRef array = NULL; - CFIndex interfaceIndex; - CFStringRef path; - SCNetworkServicePrivateRef servicePrivate; + SCNetworkInterfaceRef interface = NULL; + CFArrayRef vlans; - interfaceIndex = findConfiguration(interfacePrivate->interface_type); - if (interfaceIndex == kCFNotFound) { - // if unknown interface type - return NULL; + if (prefs == NULL) { + return (NULL); } - servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service; - if (servicePrivate == NULL) { - // if not associated with a service (yet) - return NULL; + // check if the interface is a VLAN + vlans = SCVLANInterfaceCopyAll(prefs); + if (vlans != NULL) { + interface = findInterface(vlans, ifDevice); + CFRelease(vlans); } + return interface; +} - array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - if (configurations[interfaceIndex].per_interface_config) { - CFIndex i; - CFIndex n; - CFArrayRef sets; +#define N_QUICK 32 - /* - * per-interface configuration preferences - * - * 1. look for all sets which contain the associated service - * 2. add a per-set path for the interface configuration for - * each set. - */ - sets = SCNetworkSetCopyAll(servicePrivate->prefs); - n = (sets != NULL) ? CFArrayGetCount(sets) : 0; +static CFMutableDictionaryRef +copy_ppp_entity(CFStringRef bsdName) +{ + CFMutableDictionaryRef entity = NULL; + CFStringRef pattern; + CFMutableArrayRef patterns; + CFDictionaryRef dict; + + patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetPPP); + CFArrayAppendValue(patterns, pattern); + CFRelease(pattern); + pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface); + CFArrayAppendValue(patterns, pattern); + CFRelease(pattern); + dict = SCDynamicStoreCopyMultiple(NULL, NULL, patterns); + CFRelease(patterns); + if (dict != NULL) { + CFIndex i; + const void * keys_q[N_QUICK]; + const void ** keys = keys_q; + CFIndex n; + const void * vals_q[N_QUICK]; + const void ** vals = vals_q; + n = CFDictionaryGetCount(dict); + if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { + keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); + vals = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); + } + CFDictionaryGetKeysAndValues(dict, keys, vals); for (i = 0; i < n; i++) { - CFArrayRef services; - SCNetworkSetRef set; - - set = CFArrayGetValueAtIndex(sets, i); - services = SCNetworkSetCopyServices(set); - if (CFArrayContainsValue(services, - CFRangeMake(0, CFArrayGetCount(services)), - interfacePrivate->service)) { - path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator - SCNetworkSetGetSetID(set), // set - interfacePrivate->entity_device, // service - interfacePrivate->entity_type); // entity - CFArrayAppendValue(array, path); - CFRelease(path); + CFArrayRef components; + CFStringRef interfaceKey; + CFDictionaryRef interfaceVal; + CFStringRef ifName; + CFStringRef pppKey = (CFStringRef)keys[i]; + CFDictionaryRef pppVal = (CFDictionaryRef)vals[i]; + CFStringRef serviceID; + + if (!CFStringHasSuffix(pppKey, kSCEntNetPPP) || + !CFDictionaryGetValueIfPresent(pppVal, kSCPropInterfaceName, (const void **)&ifName) || + !CFEqual(bsdName, ifName)) { + // if not matching PPP interface + continue; } - CFRelease(services); - } - if (CFArrayGetCount(array) == 0) { - CFRelease(array); - array = NULL; + components = CFStringCreateArrayBySeparatingStrings(NULL, pppKey, CFSTR("/")); + serviceID = CFArrayGetValueAtIndex(components, 3); + interfaceKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, kSCEntNetInterface); + interfaceVal = CFDictionaryGetValue(dict, interfaceKey); + CFRelease(interfaceKey); + CFRelease(components); + if (interfaceVal != NULL) { + entity = CFDictionaryCreateMutableCopy(NULL, 0, interfaceVal); + break; + } + } + if (keys != keys_q) { + CFAllocatorDeallocate(NULL, keys); + CFAllocatorDeallocate(NULL, vals); } - CFRelease(sets); - } else { - // per-service configuration preferences - path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator - servicePrivate->serviceID, // service - interfacePrivate->entity_type); // entity - CFArrayAppendValue(array, path); - CFRelease(path); + CFRelease(dict); } - return array; + return entity; } -/* ---------- SCNetworkInterface APIs ---------- */ - - -CFArrayRef /* of SCNetworkInterfaceRef's */ -SCNetworkInterfaceCopyAll() +SCNetworkInterfaceRef +_SCNetworkInterfaceCreateWithBSDName(CFAllocatorRef allocator, + CFStringRef bsdName, + UInt32 flags) { - CFMutableArrayRef all_interfaces; - static mach_port_t masterPort = MACH_PORT_NULL; - CFDictionaryRef matching; - CFStringRef match_keys[2]; - CFStringRef match_vals[2]; - CFArrayRef new_interfaces; - - if (masterPort == MACH_PORT_NULL) { - kern_return_t kr; +#pragma unused(allocator) + CFMutableDictionaryRef entity = NULL; + struct ifreq ifr; + SCNetworkInterfaceRef interface; + + memset(&ifr, 0, sizeof(ifr)); + if (_SC_cfstring_to_cstring(bsdName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) != NULL) { + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s != -1) { + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) { + ifr.ifr_flags = 0; + } + close(s); + } - kr = IOMasterPort(MACH_PORT_NULL, &masterPort); - if (kr != KERN_SUCCESS) { - return NULL; + if ((ifr.ifr_flags & IFF_POINTOPOINT) != 0) { + // if PPP + entity = copy_ppp_entity(bsdName); } } - all_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (entity == NULL) { + entity = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(entity, kSCPropNetInterfaceDeviceName, bsdName); + } - // get Ethernet, Firewire, and AirPort interfaces +#if !TARGET_OS_IPHONE + if ((flags & kIncludeBondInterfaces) == 0) { + CFDictionarySetValue(entity, CFSTR("_NO_BOND_INTERFACES_"), kCFBooleanTrue); + } +#endif // !TARGET_OS_IPHONE - matching = IOServiceMatching(kIONetworkInterfaceClass); - new_interfaces = findMatchingInterfaces(masterPort, matching, processNetworkInterface); - if (new_interfaces != NULL) { - CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces))); - CFRelease(new_interfaces); + if ((flags & kIncludeBridgeInterfaces) == 0) { + CFDictionarySetValue(entity, CFSTR("_NO_BRIDGE_INTERFACES_"), kCFBooleanTrue); } - // get Modem interfaces + if ((flags & kIncludeVLANInterfaces) == 0) { + CFDictionarySetValue(entity, CFSTR("_NO_VLAN_INTERFACES_"), kCFBooleanTrue); + } - match_keys[0] = CFSTR(kIOProviderClassKey); - match_vals[0] = CFSTR(kIOSerialBSDServiceValue); + interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, NULL); + CFRelease(entity); - match_keys[1] = CFSTR(kIOSerialBSDTypeKey); - match_vals[1] = CFSTR(kIOSerialBSDModemType); + return interface; +} - matching = CFDictionaryCreate(NULL, - (const void **)match_keys, - (const void **)match_vals, - sizeof(match_keys)/sizeof(match_keys[0]), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - new_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface); - if (new_interfaces != NULL) { - CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces))); - CFRelease(new_interfaces); + +static CFStringRef +_SCNetworkInterfaceCopyPrefixFromBSDName(CFStringRef bsdName) +{ + CFMutableStringRef interfacePrefix = NULL; + UniChar lastChar; + CFIndex length = 0; + + if (isA_CFString(bsdName) == NULL) { + SC_log(LOG_DEBUG, "no BSD name"); + goto done; } - // get serial (RS232) interfaces + interfacePrefix = CFStringCreateMutableCopy(NULL, 0, bsdName); + length = CFStringGetLength(interfacePrefix); - match_keys[0] = CFSTR(kIOProviderClassKey); - match_vals[0] = CFSTR(kIOSerialBSDServiceValue); + while (length > 0) { + lastChar = CFStringGetCharacterAtIndex(interfacePrefix, length - 1); + if (lastChar >= '0' && lastChar <= '9') { + CFStringDelete(interfacePrefix, + CFRangeMake(length-1, 1)); + } + else { + break; + } + length = CFStringGetLength(interfacePrefix); + } +done: + return interfacePrefix; +} - match_keys[1] = CFSTR(kIOSerialBSDTypeKey); - match_vals[1] = CFSTR(kIOSerialBSDRS232Type); - matching = CFDictionaryCreate(NULL, - (const void **)match_keys, - (const void **)match_vals, - sizeof(match_keys)/sizeof(match_keys[0]), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - new_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface); - if (new_interfaces != NULL) { - CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces))); - CFRelease(new_interfaces); +static void +__SCNetworkInterfaceSetIOInterfacePrefix(SCNetworkInterfaceRef interface, + CFStringRef prefix); + + +static Boolean +__SCNetworkInterfaceUpdateBSDName(SCNetworkInterfaceRef interface, CFStringRef currentBSDName, CFStringRef newBSDName) +{ + Boolean success = FALSE; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (isA_SCNetworkInterface(interface) == NULL) { + SC_log(LOG_INFO, "No interface"); + goto done; } - new_interfaces = findBondInterfaces(NULL); - if (new_interfaces != NULL) { - CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces))); - CFRelease(new_interfaces); + if (CFEqual(currentBSDName, newBSDName)) { + // if no change + goto done; } - new_interfaces = findVLANInterfaces(NULL); - if (new_interfaces != NULL) { - CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces))); - CFRelease(new_interfaces); + if (interfacePrivate->entity_device != NULL) { + CFRelease(interfacePrivate->entity_device); } + interfacePrivate->entity_device = CFRetain(newBSDName); + success = TRUE; +done: + return success; +} - sort_interfaces(all_interfaces); - return all_interfaces; +static Boolean +__SCNetworkInterfaceUpdateIOPath(SCNetworkInterfaceRef interface) +{ + Boolean success = FALSE; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + CFStringRef oldPath = NULL; + CFStringRef newPath = NULL; + + // Using the BSD Name update the path + oldPath = interfacePrivate->path; + if (isA_CFString(oldPath) == NULL) { + goto done; + } + newPath = CFStringCreateWithFormat(NULL, NULL, CFSTR("Migrated_From: %@"), oldPath); + if (interfacePrivate->path != NULL) { + CFRelease(interfacePrivate->path); + } + interfacePrivate->path = CFRetain(newPath); + success = TRUE; + +done: + if (newPath != NULL) { + CFRelease(newPath); + } + return success; } -CFArrayRef /* of kSCNetworkInterfaceTypeXXX CFStringRef's */ -SCNetworkInterfaceGetSupportedInterfaceTypes(SCNetworkInterfaceRef interface) +static void +__SCNetworkInterfaceSetIOInterfacePrefix (SCNetworkInterfaceRef interface, + CFStringRef prefix) { - CFIndex i; - SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + SCNetworkInterfacePrivateRef interfacePrivate; - if (interfacePrivate->supported_interface_types != NULL) { - goto done; + if (isA_CFString(prefix) == NULL) { + return; } - /* initialize runtime (and kSCNetworkInterfaceIPv4) */ - pthread_once(&initialized, __SCNetworkInterfaceInitialize); + interfacePrivate = (SCNetworkInterfacePrivateRef) interface; - i = findConfiguration(interfacePrivate->interface_type); - if (i != kCFNotFound) { - if (configurations[i].supported_interfaces != doNone) { - interfacePrivate->supported_interface_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - if (configurations[i].supported_interfaces & do6to4) { - CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceType6to4); - } - if (configurations[i].supported_interfaces & doL2TP) { - CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeL2TP); - } - if (configurations[i].supported_interfaces & doPPP) { - CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPP); + CFRetain(prefix); + + if (interfacePrivate->prefix != NULL) { + CFRelease(interfacePrivate->prefix); + } + + interfacePrivate->prefix = prefix; + return; +} + + +__private_extern__ +void +__SCNetworkInterfaceSetIOInterfaceUnit(SCNetworkInterfaceRef interface, + CFNumberRef unit) +{ + SCNetworkInterfacePrivateRef interfacePrivate; + CFStringRef newBSDName = NULL; + CFStringRef oldBSDName = NULL; + + if (isA_CFNumber(unit) == NULL) { + return; + } + interfacePrivate = (SCNetworkInterfacePrivateRef) interface; + + oldBSDName = SCNetworkInterfaceGetBSDName(interface); + + if (interfacePrivate->prefix == NULL) { + if (isA_CFString(interfacePrivate->entity_device) != NULL) { + CFStringRef interfaceNamePrefix = _SCNetworkInterfaceCopyPrefixFromBSDName(interfacePrivate->entity_device); + if (interfaceNamePrefix == NULL) { + SC_log(LOG_INFO, "interfaceNamePrefix is NULL"); } - if (configurations[i].supported_interfaces & doPPTP) { - CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPTP); + else { + __SCNetworkInterfaceSetIOInterfacePrefix(interface, interfaceNamePrefix); + CFRelease(interfaceNamePrefix); } } } - done : + if (interfacePrivate->prefix != NULL) { + newBSDName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), interfacePrivate->prefix, unit); + } - return interfacePrivate->supported_interface_types; + // Update the BSD Name + if ((newBSDName == NULL) || + (!__SCNetworkInterfaceUpdateBSDName(interface, oldBSDName, newBSDName))) { + SC_log(LOG_INFO, "BSD name update failed"); + } + + // Update the path + if (!__SCNetworkInterfaceUpdateIOPath(interface)) { + SC_log(LOG_INFO, "IOPath update failed"); + } + + CFRetain(unit); + if (interfacePrivate->unit != NULL) { + CFRelease(interfacePrivate->unit); + } + interfacePrivate->unit = unit; + + + if (newBSDName != NULL) { + CFRelease(newBSDName); + } + return; } -CFArrayRef /* of kSCNetworkProtocolTypeXXX CFStringRef's */ -SCNetworkInterfaceGetSupportedProtocolTypes(SCNetworkInterfaceRef interface) +__private_extern__ +CFDictionaryRef +__SCNetworkInterfaceCopyStorageEntity(SCNetworkInterfaceRef interface) { - CFIndex i; - SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + CFMutableDictionaryRef interface_entity = NULL; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + CFBooleanRef active = NULL; + CFStringRef bsdName = NULL; + CFBooleanRef builtin = NULL; + CFStringRef interfaceNamePrefix = NULL; + CFNumberRef interfaceType = NULL; + CFNumberRef interfaceUnit = NULL; + CFDataRef macAddress = NULL; + CFStringRef pathMatch = NULL; + CFDictionaryRef info = NULL; + CFStringRef type = NULL; + + if (interfacePrivate->active) { + active = kCFBooleanTrue; + } - if (interfacePrivate->supported_protocol_types != NULL) { + bsdName = SCNetworkInterfaceGetBSDName(interface); + if (!isA_CFString(bsdName)) { goto done; } - /* initialize runtime (and kSCNetworkInterfaceIPv4) */ - pthread_once(&initialized, __SCNetworkInterfaceInitialize); + builtin = interfacePrivate->builtin ? kCFBooleanTrue : kCFBooleanFalse; + interfaceNamePrefix = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface); + if (!isA_CFString(interfaceNamePrefix)) { + goto done; + } - i = findConfiguration(interfacePrivate->interface_type); - if (i != kCFNotFound) { - if (configurations[i].supported_protocols != doNone) { - interfacePrivate->supported_protocol_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - if (configurations[i].supported_protocols & doAppleTalk) { - CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeAppleTalk); - } - if (configurations[i].supported_protocols & doDNS) { - CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeDNS); - } - if (configurations[i].supported_protocols & doIPv4) { - CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv4); - } - if (configurations[i].supported_protocols & doIPv6) { - CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv6); - } - if (configurations[i].supported_protocols & doProxies) { - CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeProxies); - } - } + interfaceType = _SCNetworkInterfaceGetIOInterfaceType(interface); + if (!isA_CFNumber(interfaceType)) { + goto done; } - done : + interfaceUnit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); + if (!isA_CFNumber(interfaceUnit)) { + goto done; + } - return interfacePrivate->supported_protocol_types; + macAddress = _SCNetworkInterfaceGetHardwareAddress(interface); + if (!isA_CFData(macAddress)) { + goto done; + } + + pathMatch = _SCNetworkInterfaceGetIOPath(interface); + if (!isA_CFString(pathMatch)) { + goto done; + } + + info = _SCNetworkInterfaceCopyInterfaceInfo(interface); + if (!isA_CFDictionary(info)) { + goto done; + } + + type = SCNetworkInterfaceGetInterfaceType(interface); + if (!isA_CFString(type)) { + goto done; + } + + interface_entity = CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + if (isA_CFBoolean(active) != NULL) { + CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceActive), active); + } + + CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceBSDName), bsdName); + CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOBuiltin), builtin); + CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceNamePrefix), interfaceNamePrefix); + CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceType), interfaceType); + CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceUnit), interfaceUnit); + CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOMACAddress), macAddress); + CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOPathMatch), pathMatch); + CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceInfo), info); + CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceType), type); +done: + if (info != NULL) { + CFRelease(info); + } + return interface_entity; } -SCNetworkInterfaceRef -SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef interfaceType) +static void +__SCNetworkInterfaceSetService(SCNetworkInterfaceRef interface, + SCNetworkServiceRef service) { - SCNetworkInterfacePrivateRef childPrivate = (SCNetworkInterfacePrivateRef)child; - CFIndex childIndex; - SCNetworkInterfacePrivateRef parentPrivate; + SCNetworkInterfacePrivateRef interfacePrivate; + SCNetworkServicePrivateRef servicePrivate; - /* initialize runtime (and kSCNetworkInterfaceIPv4) */ - pthread_once(&initialized, __SCNetworkInterfaceInitialize); + interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + if (interfacePrivate->prefs != NULL) { + CFRelease(interfacePrivate->prefs); + interfacePrivate->prefs = NULL; + } + if (interfacePrivate->serviceID != NULL) { + CFRelease(interfacePrivate->serviceID); + interfacePrivate->serviceID = NULL; + } - childIndex = findConfiguration(childPrivate->interface_type); + servicePrivate = (SCNetworkServicePrivateRef)service; + if (servicePrivate->prefs != NULL) { + interfacePrivate->prefs = CFRetain(servicePrivate->prefs); + } + if (servicePrivate->serviceID != NULL) { + interfacePrivate->serviceID = CFRetain(servicePrivate->serviceID); + } - parentPrivate = __SCNetworkInterfaceCreatePrivate(NULL, child, childPrivate->service, NULL); - if (parentPrivate == NULL) { - _SCErrorSet(kSCStatusFailed); - return NULL; + return; +} + + +__private_extern__ +Boolean +__SCNetworkInterfaceMatchesName(CFStringRef name, CFStringRef key) +{ + Boolean match; + CFStringRef str; + + if (bundle == NULL) { + SC_log(LOG_NOTICE, "no bundle information to compare interface names"); + return FALSE; } - if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) { - parentPrivate->interface_type = kSCNetworkInterfaceTypePPP; - parentPrivate->entity_type = kSCEntNetPPP; + if (!isA_CFString(name)) { + // if no interface "name" + return FALSE; + } - // entity subtype - if (childIndex != kCFNotFound) { - if (configurations[childIndex].ppp_subtype != NULL) { - parentPrivate->entity_subtype = *configurations[childIndex].ppp_subtype; - } else { - // sorry, the child interface does not support PPP - goto fail; - } - } else { - // if the child's interface type not known, use the child entities "Type" - parentPrivate->entity_subtype = childPrivate->entity_type; + // check non-localized name for a match + str = copy_interface_string(bundle, key, FALSE); + if (str != NULL) { + match = CFEqual(name, str); + CFRelease(str); + if (match) { + return TRUE; } + } - if (childPrivate->entity_device != NULL) { - parentPrivate->entity_device = CFStringCreateCopy(NULL, childPrivate->entity_device); - } - } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) { - if ((childIndex == kCFNotFound) || - ((configurations[childIndex].supported_interfaces & doL2TP) != doL2TP)) { - // if the child interface does not support L2TP - goto fail; - } - parentPrivate->interface_type = kSCNetworkInterfaceTypeL2TP; - parentPrivate->entity_type = kSCValNetInterfaceSubTypeL2TP; // interface config goes into "L2TP" - } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) { - if ((childIndex == kCFNotFound) || - ((configurations[childIndex].supported_interfaces & doPPTP) != doPPTP)) { - // if the child interface does not support PPTP - goto fail; + // check localized name for a match + str = copy_interface_string(bundle, key, TRUE); + if (str != NULL) { + match = CFEqual(name, str); + CFRelease(str); + if (match) { + return TRUE; } - parentPrivate->interface_type = kSCNetworkInterfaceTypePPTP; - parentPrivate->entity_type = kSCValNetInterfaceSubTypePPTP; // interface config goes into "PPTP" - } else if (CFEqual(interfaceType, kSCNetworkInterfaceType6to4)) { - if ((childIndex == kCFNotFound) || - ((configurations[childIndex].supported_interfaces & do6to4) != do6to4)) { - // if the child interface does not support 6to4 - goto fail; + } + + return FALSE; +} + + +#define kInterfaceTypeEthernetValue 6 +#define kInterfaceTypeFirewireValue 144 + + +static SCNetworkInterfaceRef +__SCNetworkInterfaceCreateWithStorageEntity(CFAllocatorRef allocator, + CFDictionaryRef interface_entity) +{ +#pragma unused(allocator) + SCNetworkInterfacePrivateRef interfacePrivate = NULL; + CFBooleanRef active = NULL; + CFStringRef bsdName = NULL; + CFBooleanRef ioBuiltin = NULL; + CFStringRef ioInterfaceNamePrefix = NULL; + CFNumberRef ioInterfaceType = NULL; + int ioInterfaceTypeNum; + CFNumberRef ioInterfaceUnit = NULL; + CFDataRef ioMACAddress = NULL; + CFStringRef ioPathMatch = NULL; + CFDictionaryRef SCNetworkInterfaceInfo = NULL; + CFStringRef userDefinedName = NULL; + CFStringRef usbProductName = NULL; + CFNumberRef idProduct = NULL; + CFNumberRef idVendor = NULL; + CFStringRef type = NULL; + + /* initialize runtime */ + pthread_once(&initialized, __SCNetworkInterfaceInitialize); + + if (isA_CFDictionary(interface_entity) == NULL) { + SC_log(LOG_INFO, "No interface entity"); + goto done; + } + active = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceActive)); + if (isA_CFBoolean(active) == NULL) { + active = kCFBooleanFalse; + } + bsdName = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceBSDName)); + if (isA_CFString(bsdName) == NULL) { + SC_log(LOG_INFO, "No BSD name"); + goto done; + } + ioBuiltin = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOBuiltin)); + if (isA_CFBoolean(ioBuiltin) == NULL) { + SC_log(LOG_INFO, "No IOBuiltin property"); + goto done; + } + ioInterfaceNamePrefix = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceNamePrefix)); + if (isA_CFString(ioInterfaceNamePrefix) == NULL) { + ioInterfaceNamePrefix = _SCNetworkInterfaceCopyPrefixFromBSDName(bsdName); + if (ioInterfaceNamePrefix == NULL) { + SC_log(LOG_INFO, "No BSD interface name prefix"); + goto done; } + } else { + CFRetain(ioInterfaceNamePrefix); + } + ioInterfaceType = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceType)); + if (isA_CFNumber(ioInterfaceType) == NULL) { + SC_log(LOG_INFO, "No IOInterfaceType"); + goto done; + } + if (!CFNumberGetValue(ioInterfaceType, kCFNumberIntType, &ioInterfaceTypeNum)) { + SC_log(LOG_NOTICE, "Count not extract value from ioInterfaceType"); + } + ioInterfaceUnit = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceUnit)); + if (isA_CFNumber(ioInterfaceUnit) == NULL) { + SC_log(LOG_INFO, "No IOInterfaceUnit"); - parentPrivate->interface_type = kSCNetworkInterfaceType6to4; - parentPrivate->entity_type = kSCEntNet6to4; - parentPrivate->entity_device = CFRetain(CFSTR("stf0")); - CFRetain(parentPrivate->entity_device); + goto done; + } + ioMACAddress = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOMACAddress)); + if (isA_CFData(ioMACAddress) == NULL) { + SC_log(LOG_INFO, "No IOMACAddress"); + goto done; + } + ioPathMatch = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOPathMatch)); + if (isA_CFString(ioPathMatch) == NULL) { + SC_log(LOG_INFO, "No IOPathMatch"); + goto done; } else { - // unknown interface type - goto fail; + // Check if Path contains the BSD Name in the end + } + SCNetworkInterfaceInfo = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceInfo)); + if (isA_CFDictionary(SCNetworkInterfaceInfo) == NULL) { + SC_log(LOG_INFO, "No SCNetworkInterfaceInfo"); + goto done; + } + userDefinedName = CFDictionaryGetValue(SCNetworkInterfaceInfo, kSCPropUserDefinedName); +#if !TARGET_OS_SIMULATOR + usbProductName = CFDictionaryGetValue(SCNetworkInterfaceInfo, CFSTR(kUSBProductString)); + idProduct = CFDictionaryGetValue(SCNetworkInterfaceInfo, CFSTR(kUSBProductID)); + idVendor = CFDictionaryGetValue(SCNetworkInterfaceInfo, CFSTR(kUSBVendorID)); +#endif // !TARGET_OS_SIMULATOR + + type = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceType)); + if (isA_CFString(type) == NULL) { + SC_log(LOG_INFO, "No SCNetworkInterfaceType"); + goto done; } - parentPrivate->entity_hardware = childPrivate->entity_hardware; - parentPrivate->sort_order = childPrivate->sort_order; + interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); + interfacePrivate->active = CFBooleanGetValue(active); + interfacePrivate->entity_device = CFRetain(bsdName); + interfacePrivate->builtin = CFBooleanGetValue(ioBuiltin); + interfacePrivate->prefix = CFRetain(ioInterfaceNamePrefix); + interfacePrivate->type = CFRetain(ioInterfaceType); + interfacePrivate->unit = CFRetain(ioInterfaceUnit); + interfacePrivate->address = CFRetain(ioMACAddress); + interfacePrivate->path = CFRetain(ioPathMatch); + interfacePrivate->name = ((userDefinedName != NULL) ? CFRetain(userDefinedName) : NULL); + interfacePrivate->localized_name = ((userDefinedName != NULL) ? CFRetain(userDefinedName) : NULL); + interfacePrivate->usb.name = ((usbProductName != NULL) ? CFRetain(usbProductName) : NULL); + interfacePrivate->usb.pid = ((idProduct != NULL) ? CFRetain(idProduct) : NULL); + interfacePrivate->usb.vid = ((idVendor != NULL) ? CFRetain(idVendor) : NULL); + + // Handling interface types to be seen in NetworkInterfaces.plist + CFIndex interfaceIndex; + + interfaceIndex = findConfiguration(type); + if (interfaceIndex != kCFNotFound) { + interfacePrivate->interface_type = *configurations[interfaceIndex].interface_type; + } else { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + } + + // Extracting entity type from value of interface type + if (ioInterfaceTypeNum == kInterfaceTypeEthernetValue) { + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; // kSCNetworkInterfaceTypeEthernet; + } else if (ioInterfaceTypeNum == kInterfaceTypeFirewireValue) { + interfacePrivate->entity_type = kSCValNetInterfaceTypeFireWire; + } +done: + if (ioInterfaceNamePrefix != NULL) { + CFRelease(ioInterfaceNamePrefix); + } + + return (SCNetworkInterfaceRef)interfacePrivate; +} + + +__private_extern__ +void +_SCNetworkInterfaceCacheOpen(void) +{ + if (!__SCNetworkInterfaceCacheIsOpen()) { + S_interface_cache = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + SC_log(LOG_DEBUG, "SCNetworkInterface cache (%p): open", S_interface_cache); + } +} + + +__private_extern__ +void +_SCNetworkInterfaceCacheClose(void) +{ + if (__SCNetworkInterfaceCacheIsOpen()) { + SC_log(LOG_DEBUG, "SCNetworkInterface cache (%p): close", S_interface_cache); + CFRelease(S_interface_cache); + S_interface_cache = NULL; + } +} + + +static void +__SCNetworkInterfaceCacheAdd(CFStringRef bsdName, CFArrayRef matchingInterfaces) +{ + if (__SCNetworkInterfaceCacheIsOpen() && + bsdName != NULL && + matchingInterfaces != NULL) { + SC_log(LOG_DEBUG, "SCNetworkInterface cache (%p): add %@", S_interface_cache, bsdName); + CFDictionaryAddValue(S_interface_cache, bsdName, matchingInterfaces); + } +} + + +static inline Boolean +__SCNetworkInterfaceCacheIsOpen(void) +{ + return (S_interface_cache != NULL); +} + + +static CFArrayRef +__SCNetworkInterfaceCacheCopy(CFStringRef bsdName) +{ + if (__SCNetworkInterfaceCacheIsOpen() && + bsdName != NULL) { + CFArrayRef matchingInterfaces = CFDictionaryGetValue(S_interface_cache, bsdName); + if (matchingInterfaces) { + CFRetain(matchingInterfaces); + SC_log(LOG_DEBUG, "SCNetworkInterface cache (%p): copy w/ match for %@", S_interface_cache, bsdName); + } else { + SC_log(LOG_DEBUG, "SCNetworkInterface cache (%p): copy w/ no match for %@", S_interface_cache, bsdName); + } + + return matchingInterfaces; + } + + return NULL; +} + + +SCNetworkInterfaceRef +_SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, + CFDictionaryRef interface_entity, + SCNetworkServiceRef service) +{ +#pragma unused(allocator) + SCNetworkInterfacePrivateRef interfacePrivate = NULL; + CFStringRef ifDevice; + CFStringRef ifName = NULL; + CFStringRef ifSubType; + CFStringRef ifType; + CFStringRef ifUnique; + CFArrayRef matching_interfaces = NULL; + SCPreferencesRef servicePref = NULL; + Boolean useSystemInterfaces = TRUE; + + /* initialize runtime (and kSCNetworkInterfaceIPv4) */ + pthread_once(&initialized, __SCNetworkInterfaceInitialize); + + if (service != NULL) { + servicePref = ((SCNetworkServicePrivateRef)service)->prefs; + useSystemInterfaces = ((__SCPreferencesUsingDefaultPrefs(servicePref)) && + (!__SCPreferencesGetLimitSCNetworkConfiguration(servicePref))); + } + + ifType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceType); + if (ifType == NULL) { + /* + * The interface "Type" was not specified. We'll make an + * assumption that this is an "Ethernet" interface. If a + * real interface exists with the provided interface name + * then the actual type will be set accordingly. If not, we'll + * end up crafting an "Ethernet" SCNetworkInterface that + * will keep the rest of the configuration APIs happy. + */ + ifType = kSCValNetInterfaceTypeEthernet; + } + + if (!isA_CFString(ifType)) { + return NULL; + } + + ifSubType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceSubType); + if (CFEqual(ifType, kSCValNetInterfaceTypePPP) || + CFEqual(ifType, kSCValNetInterfaceTypeVPN)) { + if (!isA_CFString(ifSubType)) { + return NULL; + } + } + + ifDevice = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceDeviceName); + ifUnique = CFDictionaryGetValue(interface_entity, CFSTR("DeviceUniqueIdentifier")); + + if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet) || + CFEqual(ifType, kSCValNetInterfaceTypeFireWire) || + (CFEqual(ifType, kSCValNetInterfaceTypePPP) && CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE))) { + char bsdName[IFNAMSIZ]; + CFMutableDictionaryRef matching; + + if (!isA_CFString(ifDevice)) { + return NULL; + } + + if (CFEqual(ifDevice, CFSTR("lo0"))) { // for _SCNetworkInterfaceCreateWithBSDName + interfacePrivate = __SCNetworkInterfaceCreateCopy(NULL, kSCNetworkInterfaceLoopback, NULL, NULL); + goto done; + } + if (useSystemInterfaces) { + // Check to see if we already have the info in the cache + matching_interfaces = __SCNetworkInterfaceCacheCopy(ifDevice); + if (matching_interfaces == NULL) { + if (_SC_cfstring_to_cstring(ifDevice, bsdName, sizeof(bsdName), kCFStringEncodingASCII) == NULL) { + goto done; + } + + matching = IOBSDNameMatching(masterPort, 0, bsdName); + if (matching == NULL) { + goto done; + } + matching_interfaces = findMatchingInterfaces(matching, + processNetworkInterface, + kSCNetworkInterfaceHiddenInterfaceKey, + TRUE); + + __SCNetworkInterfaceCacheAdd(ifDevice, matching_interfaces); + CFRelease(matching); + } + } + } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { + if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) { + CFDictionaryRef matching; + CFStringRef match_keys[2]; + CFStringRef match_vals[2]; + + if (!isA_CFString(ifDevice)) { + return NULL; + } + + if (useSystemInterfaces) { + match_keys[0] = CFSTR(kIOProviderClassKey); + match_vals[0] = CFSTR(kIOSerialBSDServiceValue); + + match_keys[1] = CFSTR(kIOTTYBaseNameKey); + match_vals[1] = ifDevice; + + matching = CFDictionaryCreate(NULL, + (const void **)match_keys, + (const void **)match_vals, + sizeof(match_keys)/sizeof(match_keys[0]), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + matching_interfaces = findMatchingInterfaces(matching, + processSerialInterface, + kSCNetworkInterfaceHiddenPortKey, + TRUE); + CFRelease(matching); + } + if (ifUnique == NULL) { + CFIndex n; + Boolean useDeviceName = TRUE; + + n = (matching_interfaces != NULL) ? CFArrayGetCount(matching_interfaces) : 0; + if (n > 0) { + CFIndex i; + + for (i = 0; i < n; i++) { + SCNetworkInterfacePrivateRef scanPrivate; + + scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i); + if (scanPrivate->entity_device_unique != NULL) { + useDeviceName = FALSE; + break; + } + } + } + + if (useDeviceName && useSystemInterfaces) { + if (matching_interfaces != NULL) { + CFRelease(matching_interfaces); + } + + match_keys[1] = CFSTR(kIOTTYDeviceKey); + matching = CFDictionaryCreate(NULL, + (const void **)match_keys, + (const void **)match_vals, + sizeof(match_keys)/sizeof(match_keys[0]), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + matching_interfaces = findMatchingInterfaces(matching, + processSerialInterface, + kSCNetworkInterfaceHiddenPortKey, + TRUE); + CFRelease(matching); + } + } + } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypeL2TP)) { + interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, + kSCNetworkInterfaceTypeL2TP); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated" + } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPTP)) { + interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, + kSCNetworkInterfaceTypePPTP); +#pragma GCC diagnostic pop + } else { + // XXX do we allow non-Apple variants of PPP??? XXX + interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, + ifSubType); + } + } else if (CFEqual(ifType, kSCValNetInterfaceType6to4)) { + if (!isA_CFString(ifDevice)) { + return NULL; + } + + interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, + kSCNetworkInterfaceType6to4); + } else if (CFEqual(ifType, kSCValNetInterfaceTypeIPSec)) { + interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, + kSCNetworkInterfaceTypeIPSec); + } else if (CFEqual(ifType, kSCValNetInterfaceTypeLoopback)) { + interfacePrivate = __SCNetworkInterfaceCreateCopy(NULL, kSCNetworkInterfaceLoopback, NULL, NULL); + } else if (CFEqual(ifType, kSCValNetInterfaceTypeVPN)) { + if (CFStringFind(ifSubType, CFSTR("."), 0).location != kCFNotFound) { + interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, + ifSubType); + } + } else if ((CFStringFind(ifType, CFSTR("."), 0).location != kCFNotFound) && (ifDevice == NULL)) { + interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, + ifType); + } + + if (matching_interfaces != NULL) { + CFIndex n; + SCPreferencesRef prefs; + Boolean temp_preferences = FALSE; + + n = CFArrayGetCount(matching_interfaces); + switch (n) { + case 1 : + interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0); + if (_SC_CFEqual(ifUnique, interfacePrivate->entity_device_unique)) { + // if the unique ID's match + CFRetain(interfacePrivate); + break; + } + + interfacePrivate = NULL; + // fall through + case 0 : + if (!CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) { + break; + } + + if (CFDictionaryGetValueIfPresent(interface_entity, + kSCPropUserDefinedName, + (const void **)&ifName) && + CFEqual(ifName, CFSTR(BT_PAN_NAME))) { + break; + } + + prefs = (service != NULL) ? ((SCNetworkServicePrivateRef)service)->prefs : NULL; + if (prefs == NULL) { + prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterface"), NULL); + if (prefs != NULL) { + temp_preferences = TRUE; + } + } + if (prefs == NULL) { + break; + } +#if !TARGET_OS_IPHONE + if (!CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BOND_INTERFACES_"))) { + interfacePrivate = (SCNetworkInterfacePrivateRef)findBondInterface(prefs, ifDevice); + } +#endif // !TARGET_OS_IPHONE + if ((interfacePrivate == NULL) + && !CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BRIDGE_INTERFACES_"))) { + interfacePrivate = (SCNetworkInterfacePrivateRef)findBridgeInterface(prefs, ifDevice); + } + + if ((interfacePrivate == NULL) + && !CFDictionaryContainsKey(interface_entity, CFSTR("_NO_VLAN_INTERFACES_"))) { + interfacePrivate = (SCNetworkInterfacePrivateRef)findVLANInterface(prefs, ifDevice); + } + if (temp_preferences) CFRelease(prefs); + break; + default : + if (ifUnique != NULL) { + CFIndex i; + + // we are looking for an interface with a unique ID + // so let's try to focus our choices + for (i = 0; i < n; i++) { + SCNetworkInterfacePrivateRef scanPrivate; + + scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i); + if (_SC_CFEqual(ifUnique, scanPrivate->entity_device_unique)) { + if (interfacePrivate != NULL) { + // if we've matched more than one interface + interfacePrivate = NULL; + break; + } + interfacePrivate = scanPrivate; + } + } + } else if (CFDictionaryGetValueIfPresent(interface_entity, + kSCPropUserDefinedName, + (const void **)&ifName)) { + CFIndex i; + + // we don't have a unique ID but do have an interface + // name. If the matching interfaces do have IDs than + // we can try to focus our choices using the name + for (i = 0; i < n; i++) { + SCNetworkInterfacePrivateRef scanPrivate; + + scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i); + if (scanPrivate->entity_device_unique != NULL) { + SCNetworkInterfaceRef scan = (SCNetworkInterfaceRef)scanPrivate; + CFStringRef scanName; + + scanName = __SCNetworkInterfaceGetNonLocalizedDisplayName(scan); + if ((scanName != NULL) && !_SC_CFEqual(ifName, scanName)) { + continue; // if not the same display name + } + } + + if (interfacePrivate != NULL) { + // if we've matched more than one interface + interfacePrivate = NULL; + break; + } + interfacePrivate = scanPrivate; + } + } + if (interfacePrivate == NULL) { + SC_log(LOG_NOTICE, "more than one interface matches %@", ifDevice); + interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0); + } + CFRetain(interfacePrivate); + break; + } + CFRelease(matching_interfaces); + } + + done : + + if ((interfacePrivate == NULL) || !useSystemInterfaces) { + /* + * if device not present on this system + */ + if (!useSystemInterfaces) { + if (interfacePrivate != NULL) { + CFRelease(interfacePrivate); + } + } + + interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); + interfacePrivate->entity_type = (ifType != NULL) ? ifType : NULL; + interfacePrivate->entity_subtype = (ifSubType != NULL) ? ifSubType : NULL; + interfacePrivate->entity_device = (ifDevice != NULL) ? CFStringCreateCopy(NULL, ifDevice) : NULL; + interfacePrivate->entity_device_unique = (ifUnique != NULL) ? CFStringCreateCopy(NULL, ifUnique) : NULL; + + // Using UserDefinedName to check the validity of preferences file + // when useSystemInterfaces is FALSE + if (!useSystemInterfaces) { + CFStringRef userDefinedName = CFDictionaryGetValue(interface_entity, kSCPropUserDefinedName); + if (isA_CFString(userDefinedName) != NULL) { + CFRetain(userDefinedName); + if (interfacePrivate->name != NULL) { + CFRelease(interfacePrivate->name); + } + interfacePrivate->name = userDefinedName; + + CFRetain(userDefinedName); + if (interfacePrivate->localized_name != NULL) { + CFRelease(interfacePrivate->localized_name); + } + interfacePrivate->localized_name = userDefinedName; + } + } + + if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) { + CFStringRef entity_hardware; + SCNetworkInterfaceRef virtualInterface; + + if (!useSystemInterfaces && + (((virtualInterface = findBridgeInterface(servicePref, ifDevice)) != NULL) || +#if !TARGET_OS_IPHONE + ((virtualInterface = findBondInterface(servicePref, ifDevice)) != NULL) || +#endif // !TARGET_OS_IPHONE + ((virtualInterface = findVLANInterface(servicePref, ifDevice)) != NULL))) { + CFRelease(interfacePrivate); + interfacePrivate = (SCNetworkInterfacePrivateRef)virtualInterface; + } else { + entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware); + if (isA_CFString((entity_hardware)) && + CFEqual(entity_hardware, kSCEntNetAirPort)) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211; + interfacePrivate->localized_key = CFSTR("airport"); + interfacePrivate->sort_order = kSortAirPort; + } else { + CFStringRef name; + + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + + name = CFDictionaryGetValue(interface_entity, kSCPropUserDefinedName); + if (__SCNetworkInterfaceMatchesName(name, CFSTR("iPhone"))) { + interfacePrivate->localized_key = CFSTR("iPhone"); + interfacePrivate->sort_order = kSortTethered; + } else if (__SCNetworkInterfaceMatchesName(name, CFSTR("iPad"))) { + interfacePrivate->localized_key = CFSTR("iPad"); + interfacePrivate->sort_order = kSortTethered; + } else if (__SCNetworkInterfaceMatchesName(name, CFSTR("thunderbolt"))) { + interfacePrivate->localized_key = CFSTR("thunderbolt"); + interfacePrivate->sort_order = kSortThunderbolt; + } else if (__SCNetworkInterfaceMatchesName(name, CFSTR("bluetooth-pan-gn"))) { + interfacePrivate->localized_key = CFSTR("bluetooth-pan-gn"); + interfacePrivate->sort_order = kSortBluetoothPAN_GN; + } else if (__SCNetworkInterfaceMatchesName(name, CFSTR("bluetooth-pan-nap"))) { + interfacePrivate->localized_key = CFSTR("bluetooth-pan-nap"); + interfacePrivate->sort_order = kSortBluetoothPAN_NAP; + } else if (__SCNetworkInterfaceMatchesName(name, CFSTR("bluetooth-pan-u"))) { + interfacePrivate->localized_key = CFSTR("bluetooth-pan-u"); + interfacePrivate->sort_order = kSortBluetoothPAN_U; + } else { + interfacePrivate->sort_order = kSortEthernet; + } + } + } + } else if (CFEqual(ifType, kSCValNetInterfaceTypeFireWire)) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire; + interfacePrivate->sort_order = kSortFireWire; + } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP) && (ifSubType != NULL)) { + if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE)) { + CFStringRef entity_hardware; + + entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware); + if (isA_CFString((entity_hardware)) && + CFEqual(entity_hardware, kSCEntNetAirPort)) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211; + interfacePrivate->sort_order = kSortAirPort; + } else { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortEthernet; + } + } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) { + if (CFStringHasPrefix(ifDevice, CFSTR("Bluetooth"))) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth; + interfacePrivate->sort_order = kSortBluetooth; + } else if (CFStringHasPrefix(ifDevice, CFSTR("irda"))) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA; + interfacePrivate->sort_order = kSortIrDA; + } else if (CFStringHasPrefix(ifDevice, CFSTR("wwan"))) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeWWAN; + interfacePrivate->sort_order = kSortWWAN; + } else { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem; + interfacePrivate->sort_order = kSortModem; + } + } else { + SCNetworkInterfaceRef child; + // PPTP, L2TP, ... + CFRelease(interfacePrivate); + child = SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, ifSubType); + interfacePrivate = (SCNetworkInterfacePrivateRef)child; + if (interfacePrivate == NULL) { + return NULL; + } + } + } else if (CFEqual(ifType, kSCValNetInterfaceTypeVPN) && (ifSubType != NULL)) { + SCNetworkInterfaceRef child; + CFRelease(interfacePrivate); + child = SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, ifSubType); + interfacePrivate = (SCNetworkInterfacePrivateRef)child; + if (interfacePrivate == NULL) { + return NULL; + } + } else if (CFEqual(ifType, kSCValNetInterfaceTypeIPSec)) { + CFRelease(interfacePrivate); + interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, + kSCNetworkInterfaceTypeIPSec); + } else if (CFEqual(ifType, kSCValNetInterfaceType6to4)) { + CFRelease(interfacePrivate); + if (!isA_CFString(ifDevice)) { + return NULL; + } + interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, + kSCNetworkInterfaceType6to4); + } else if (CFEqual(ifType, kSCValNetInterfaceTypeLoopback)) { + CFRelease(interfacePrivate); + interfacePrivate = __SCNetworkInterfaceCreateCopy(NULL, kSCNetworkInterfaceLoopback, NULL, NULL); + } else if (CFStringFind(ifType, CFSTR("."), 0).location != kCFNotFound) { + // if vendor interface + pthread_mutex_lock(&lock); + if (vendor_interface_types == NULL) { + vendor_interface_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); + } + CFSetAddValue(vendor_interface_types, ifType); + interfacePrivate->interface_type = CFSetGetValue(vendor_interface_types, ifType); + pthread_mutex_unlock(&lock); + } else { + // if unknown interface + CFRelease(interfacePrivate); + interfacePrivate = NULL; + return NULL; + } + + if (CFDictionaryContainsKey(interface_entity, kSCNetworkInterfaceHiddenConfigurationKey)) { + interfacePrivate->hidden = TRUE; + } +#if TARGET_OS_IPHONE + if (CFDictionaryContainsKey(interface_entity, kSCNetworkInterfaceTrustRequiredKey)) { + interfacePrivate->trustRequired = TRUE; + } +#endif // TARGET_OS_IPHONE + } + + if (service != NULL) { + __SCNetworkInterfaceSetService((SCNetworkInterfaceRef)interfacePrivate, + service); + +#if !TARGET_OS_IPHONE + // set prefs & serviceID to Bond member interfaces + if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBond)) { + CFIndex i; + CFArrayRef members; + CFIndex n; + + members = SCBondInterfaceGetMemberInterfaces((SCNetworkInterfaceRef)interfacePrivate); + n = (members != NULL) ? CFArrayGetCount(members) : 0; + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef member; + + member = CFArrayGetValueAtIndex(members, i); + __SCNetworkInterfaceSetService(member, service); + } + } +#endif // !TARGET_OS_IPHONE + + // set prefs & serviceID to Bridge member interfaces + if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBridge)) { + CFIndex i; + CFArrayRef members; + CFIndex n; + + members = SCBridgeInterfaceGetMemberInterfaces((SCNetworkInterfaceRef)interfacePrivate); + n = (members != NULL) ? CFArrayGetCount(members) : 0; + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef member; + + member = CFArrayGetValueAtIndex(members, i); + __SCNetworkInterfaceSetService(member, service); + } + } + // set prefs & serviceID to VLAN pyhsical interface + if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeVLAN)) { + SCNetworkInterfaceRef vlan_physical; + + vlan_physical = SCVLANInterfaceGetPhysicalInterface((SCNetworkInterfaceRef)interfacePrivate); + if (vlan_physical != NULL) { + __SCNetworkInterfaceSetService(vlan_physical, service); + } + } + } + + if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { + SCNetworkInterfaceRef parent; + + // create parent + parent = SCNetworkInterfaceCreateWithInterface((SCNetworkInterfaceRef)interfacePrivate, + kSCNetworkInterfaceTypePPP); + CFRelease(interfacePrivate); + interfacePrivate = (SCNetworkInterfacePrivateRef)parent; + } else if (CFEqual(ifType, kSCValNetInterfaceTypeVPN)) { + SCNetworkInterfaceRef parent; + + // create parent + parent = SCNetworkInterfaceCreateWithInterface((SCNetworkInterfaceRef)interfacePrivate, + kSCNetworkInterfaceTypeVPN); + CFRelease(interfacePrivate); + interfacePrivate = (SCNetworkInterfacePrivateRef)parent; + } + + return (SCNetworkInterfaceRef)interfacePrivate; +} + + +#pragma mark - +#pragma mark SCNetworkInterface APIs + + +__private_extern__ +CFArrayRef +__SCNetworkInterfaceCopyAll_IONetworkInterface(Boolean keep_pre_configured) +{ + CFDictionaryRef matching; + CFArrayRef new_interfaces; + + // get Ethernet, Firewire, Thunderbolt, and AirPort interfaces + + matching = IOServiceMatching(kIONetworkInterfaceClass); + new_interfaces = findMatchingInterfaces(matching, + processNetworkInterface, + kSCNetworkInterfaceHiddenInterfaceKey, + keep_pre_configured); + CFRelease(matching); + + return new_interfaces; +} + + +static +CFArrayRef +__SCNetworkInterfaceCopyAll_Modem() +{ + CFDictionaryRef matching; + CFStringRef match_keys[2]; + CFStringRef match_vals[2]; + CFArrayRef new_interfaces; + + match_keys[0] = CFSTR(kIOProviderClassKey); + match_vals[0] = CFSTR(kIOSerialBSDServiceValue); + + match_keys[1] = CFSTR(kIOSerialBSDTypeKey); + match_vals[1] = CFSTR(kIOSerialBSDModemType); + + matching = CFDictionaryCreate(NULL, + (const void **)match_keys, + (const void **)match_vals, + sizeof(match_keys)/sizeof(match_keys[0]), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + new_interfaces = findMatchingInterfaces(matching, + processSerialInterface, + kSCNetworkInterfaceHiddenPortKey, + FALSE); + CFRelease(matching); + + return new_interfaces; +} + + +static +CFArrayRef +__SCNetworkInterfaceCopyAll_RS232() +{ + CFDictionaryRef matching; + CFStringRef match_keys[2]; + CFStringRef match_vals[2]; + CFArrayRef new_interfaces; + + match_keys[0] = CFSTR(kIOProviderClassKey); + match_vals[0] = CFSTR(kIOSerialBSDServiceValue); + + match_keys[1] = CFSTR(kIOSerialBSDTypeKey); + match_vals[1] = CFSTR(kIOSerialBSDRS232Type); + + matching = CFDictionaryCreate(NULL, + (const void **)match_keys, + (const void **)match_vals, + sizeof(match_keys)/sizeof(match_keys[0]), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + new_interfaces = findMatchingInterfaces(matching, + processSerialInterface, + kSCNetworkInterfaceHiddenPortKey, + FALSE); + CFRelease(matching); + + return new_interfaces; +} + + +#if !TARGET_OS_IPHONE +static void +addBTPANInterface(CFMutableArrayRef all_interfaces) +{ + CFIndex i; + SCNetworkInterfaceRef interface; + CFIndex n; + + n = CFArrayGetCount(all_interfaces); + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef interface; + + interface = CFArrayGetValueAtIndex(all_interfaces, i); + if (_SCNetworkInterfaceIsBluetoothPAN(interface)) { + // if we already have a BT-PAN interface + return; + } + } + + interface = _SCNetworkInterfaceCopyBTPANInterface(); + if (interface != NULL) { + // include BT-PAN interface + CFArrayAppendValue(all_interfaces, interface); + CFRelease(interface); + } + + return; +} +#endif // !TARGET_OS_IPHONE + + +static void +add_interfaces(CFMutableArrayRef all_interfaces, CFArrayRef new_interfaces) +{ + CFIndex i; + CFIndex n; + + n = CFArrayGetCount(new_interfaces); + for (i = 0; i < n; i++) { + CFStringRef bsdName; + SCNetworkInterfaceRef interface; + + interface = CFArrayGetValueAtIndex(new_interfaces, i); + bsdName = SCNetworkInterfaceGetBSDName(interface); + if (bsdName != NULL) { + CFArrayAppendValue(all_interfaces, interface); + } + } + + return; +} + + +static void +__waitForInterfaces() +{ + CFStringRef key = NULL; + CFArrayRef keys; + Boolean ok; + SCDynamicStoreRef store = NULL; + + CRSetCrashLogMessage("Waiting for IOKit to quiesce (or timeout)"); + + store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkInterfaceCopyAll"), NULL, NULL); + if (store == NULL) { + goto done; + } + + key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" "InterfaceNamer"), kSCDynamicStoreDomainPlugin); + keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks); + ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL); + CFRelease(keys); + if (!ok) { + SC_log(LOG_NOTICE, "SCDynamicStoreSetNotificationKeys() failed: %s", SCErrorString(SCError())); + goto done; + } + + while (TRUE) { + CFArrayRef changedKeys; + CFDictionaryRef dict; + Boolean quiet = FALSE; + + // check if quiet + dict = SCDynamicStoreCopyValue(store, key); + if (dict != NULL) { + if (isA_CFDictionary(dict) && + (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Quiet) || + CFDictionaryContainsKey(dict, kInterfaceNamerKey_Timeout))) { + quiet = TRUE; + } + CFRelease(dict); + } + if (quiet) { + break; + } + + ok = SCDynamicStoreNotifyWait(store); + if (!ok) { + SC_log(LOG_NOTICE, "SCDynamicStoreNotifyWait() failed: %s", SCErrorString(SCError())); + goto done; + } + + changedKeys = SCDynamicStoreCopyNotifiedKeys(store); + if (changedKeys != NULL) { + CFRelease(changedKeys); + } + } + + done : + + CRSetCrashLogMessage(NULL); + + if (key != NULL) CFRelease(key); + if (store != NULL) CFRelease(store); + return; +} + + +CFArrayRef /* of SCNetworkInterfaceRef's */ +_SCNetworkInterfaceCopyAllWithPreferences(SCPreferencesRef prefs) +{ + CFMutableArrayRef all_interfaces; + CFArrayRef new_interfaces; + Boolean temp_preferences = FALSE; + + /* initialize runtime */ + pthread_once(&initialized, __SCNetworkInterfaceInitialize); + + /* wait for IOKit to quiesce */ + pthread_once(&iokit_quiet, __waitForInterfaces); + + all_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + // get Ethernet, Firewire, Thunderbolt, and AirPort interfaces + new_interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(FALSE); + if (new_interfaces != NULL) { + add_interfaces(all_interfaces, new_interfaces); + CFRelease(new_interfaces); + } + + // get Modem interfaces + new_interfaces = __SCNetworkInterfaceCopyAll_Modem(); + if (new_interfaces != NULL) { + add_interfaces(all_interfaces, new_interfaces); + CFRelease(new_interfaces); + } + + // get serial (RS232) interfaces + new_interfaces = __SCNetworkInterfaceCopyAll_RS232(); + if (new_interfaces != NULL) { + add_interfaces(all_interfaces, new_interfaces); + CFRelease(new_interfaces); + } + + // get virtual network interfaces (Bond, Bridge, VLAN) + if (prefs == NULL) { + prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterfaceCopyAll"), NULL); + if (prefs != NULL) { + temp_preferences = TRUE; + } + } + if (prefs != NULL) { +#if !TARGET_OS_IPHONE + new_interfaces = SCBondInterfaceCopyAll(prefs); + if (new_interfaces != NULL) { + add_interfaces(all_interfaces, new_interfaces); + CFRelease(new_interfaces); + } +#endif // !TARGET_OS_IPHONE + + new_interfaces = SCBridgeInterfaceCopyAll(prefs); + if (new_interfaces != NULL) { + add_interfaces(all_interfaces, new_interfaces); + CFRelease(new_interfaces); + } + + new_interfaces = SCVLANInterfaceCopyAll(prefs); + if (new_interfaces != NULL) { + add_interfaces(all_interfaces, new_interfaces); + CFRelease(new_interfaces); + } + +#if !TARGET_OS_IPHONE + // add BT-PAN interface + addBTPANInterface(all_interfaces); +#endif // !TARGET_OS_IPHONE + + if (temp_preferences) CFRelease(prefs); + } + + // all interfaces have been identified, order and return + sort_interfaces(all_interfaces); + + return all_interfaces; +} + + +CFArrayRef /* of SCNetworkInterfaceRef's */ +SCNetworkInterfaceCopyAll() +{ + CFArrayRef all_interfaces; + + all_interfaces = _SCNetworkInterfaceCopyAllWithPreferences(NULL); + return all_interfaces; +} + + +CFArrayRef /* of kSCNetworkInterfaceTypeXXX CFStringRef's */ +SCNetworkInterfaceGetSupportedInterfaceTypes(SCNetworkInterfaceRef interface) +{ + CFIndex i; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + if (interfacePrivate->supported_interface_types != NULL) { + goto done; + } + + i = findConfiguration(interfacePrivate->interface_type); + if (i != kCFNotFound) { + if (configurations[i].supported_interfaces != doNone) { + interfacePrivate->supported_interface_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (configurations[i].supported_interfaces & do6to4) { + CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceType6to4); + } + if (configurations[i].supported_interfaces & doL2TP) { + CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeL2TP); + } + if (configurations[i].supported_interfaces & doPPP) { + CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPP); + } + if (configurations[i].supported_interfaces & doIPSec) { + CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeIPSec); + } + } + } else { + SCNetworkInterfaceRef child; + + child = SCNetworkInterfaceGetInterface(interface); + if ((child != NULL) && CFEqual(child, kSCNetworkInterfaceIPv4)) { + interfacePrivate->supported_interface_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeVPN); + } + } + + done : + + return interfacePrivate->supported_interface_types; +} + + +CFArrayRef /* of kSCNetworkProtocolTypeXXX CFStringRef's */ +SCNetworkInterfaceGetSupportedProtocolTypes(SCNetworkInterfaceRef interface) +{ + CFIndex i; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + if (interfacePrivate->supported_protocol_types != NULL) { + goto done; + } + + i = findConfiguration(interfacePrivate->interface_type); + if (i != kCFNotFound) { + if (configurations[i].supported_protocols != doNone) { + interfacePrivate->supported_protocol_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (configurations[i].supported_protocols & doDNS) { + CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeDNS); + } + if (configurations[i].supported_protocols & doIPv4) { + CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv4); + } + if (configurations[i].supported_protocols & doIPv6) { + CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv6); + } + if (configurations[i].supported_protocols & doProxies) { + CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeProxies); + } +#if !TARGET_OS_IPHONE + if (configurations[i].supported_protocols & doSMB) { + CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeSMB); + } +#endif // !TARGET_OS_IPHONE + } + } + + done : + + return interfacePrivate->supported_protocol_types; +} + + +SCNetworkInterfaceRef +SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef interfaceType) +{ + SCNetworkInterfacePrivateRef childPrivate = (SCNetworkInterfacePrivateRef)child; + CFIndex childIndex; + SCNetworkInterfacePrivateRef parentPrivate; + + if (!isA_SCNetworkInterface(child)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + if (!isA_CFString(interfaceType)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + if (CFEqual(child, kSCNetworkInterfaceLoopback)) { + // can't layer on top of loopback + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + childIndex = findConfiguration(childPrivate->interface_type); + + parentPrivate = __SCNetworkInterfaceCreatePrivate(NULL, + child, + childPrivate->prefs, + childPrivate->serviceID); + if (parentPrivate == NULL) { + _SCErrorSet(kSCStatusFailed); + return NULL; + } + + if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) { + parentPrivate->interface_type = kSCNetworkInterfaceTypePPP; + parentPrivate->entity_type = kSCValNetInterfaceTypePPP; + + // entity subtype + if (childIndex != kCFNotFound) { + if (configurations[childIndex].ppp_subtype != NULL) { + parentPrivate->entity_subtype = *configurations[childIndex].ppp_subtype; + } else { + // sorry, the child interface does not support PPP + goto fail; + } + } else { + // if the child's interface type not known, use the child entities "Type" + parentPrivate->entity_subtype = childPrivate->entity_type; + } + + if (childPrivate->entity_device != NULL) { + parentPrivate->entity_device = CFStringCreateCopy(NULL, childPrivate->entity_device); + } + + if (childPrivate->entity_device_unique != NULL) { + parentPrivate->entity_device_unique = CFStringCreateCopy(NULL, childPrivate->entity_device_unique); + } + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) { + if ((childIndex == kCFNotFound) || + ((configurations[childIndex].supported_interfaces & doL2TP) != doL2TP)) { + // if the child interface does not support L2TP + goto fail; + } + parentPrivate->interface_type = kSCNetworkInterfaceTypeL2TP; + parentPrivate->localized_key = CFSTR("l2tp"); + parentPrivate->entity_type = kSCEntNetL2TP; // interface config goes into "L2TP" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated" + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) { + if ((childIndex == kCFNotFound) || + ((configurations[childIndex].supported_interfaces & doPPTP) != doPPTP)) { + // if the child interface does not support PPTP + goto fail; + } + parentPrivate->interface_type = kSCNetworkInterfaceTypePPTP; + parentPrivate->localized_key = CFSTR("pptp"); + parentPrivate->entity_type = kSCEntNetPPTP; // interface config goes into "PPTP" +#pragma GCC diagnostic pop + } else if (CFEqual(interfaceType, kSCNetworkInterfaceType6to4)) { + if ((childIndex == kCFNotFound) || + ((configurations[childIndex].supported_interfaces & do6to4) != do6to4)) { + // if the child interface does not support 6to4 + goto fail; + } + + parentPrivate->interface_type = kSCNetworkInterfaceType6to4; + parentPrivate->localized_key = CFSTR("6to4"); + parentPrivate->entity_type = kSCValNetInterfaceType6to4; + parentPrivate->entity_device = CFRetain(CFSTR("stf0")); + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) { + if ((childIndex == kCFNotFound) || + ((configurations[childIndex].supported_interfaces & doIPSec) != doIPSec)) { + // if the child interface does not support IPSec + goto fail; + } + parentPrivate->interface_type = kSCNetworkInterfaceTypeIPSec; + parentPrivate->localized_key = CFSTR("ipsec"); + parentPrivate->entity_type = kSCValNetInterfaceTypeIPSec; + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) { + if (childIndex != kCFNotFound) { + // if not a "vendor" child interface + goto fail; + } + + parentPrivate->interface_type = kSCNetworkInterfaceTypeVPN; + parentPrivate->localized_key = CFSTR("vpn"); + parentPrivate->localized_arg1 = CFRetain(childPrivate->entity_type); + parentPrivate->entity_type = kSCValNetInterfaceTypeVPN; + parentPrivate->entity_subtype = childPrivate->entity_type; + if (childPrivate->entity_device != NULL) { + parentPrivate->entity_device = CFStringCreateCopy(NULL, childPrivate->entity_device); + } + if (parentPrivate->entity_subtype != NULL) { + CFArrayRef components; + CFIndex n; + CFStringRef vpnType; + + // + // the "default" interface name is derived from the VPN type + // + // e.g. + // com.apple.Apple-VPN.vpnplugin --> "Apple VPN" + // ^^^^^^^^^ + // + vpnType = parentPrivate->entity_subtype; + components = CFStringCreateArrayBySeparatingStrings(NULL, vpnType, CFSTR(".")); + n = CFArrayGetCount(components); + if ((n >= 4) && + CFEqual(CFArrayGetValueAtIndex(components, n - 1), CFSTR("vpnplugin"))) { + CFMutableStringRef str; + + str = CFStringCreateMutableCopy(NULL, + 0, + CFArrayGetValueAtIndex(components, n - 2)); + (void) CFStringFindAndReplace(str, + CFSTR("-"), + CFSTR(" "), + CFRangeMake(0, CFStringGetLength(str)), + 0); + parentPrivate->localized_name = str; + } + CFRelease(components); + } + } else if (CFStringFind(interfaceType, CFSTR("."), 0).location != kCFNotFound) { + // if custom interface type + pthread_mutex_lock(&lock); + if (vendor_interface_types == NULL) { + vendor_interface_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); + } + CFSetAddValue(vendor_interface_types, interfaceType); + parentPrivate->interface_type = CFSetGetValue(vendor_interface_types, interfaceType); + pthread_mutex_unlock(&lock); + + parentPrivate->entity_type = parentPrivate->interface_type; // interface config goes into a + // a dictionary with the same + // name as the interfaceType + } else { + // unknown interface type + goto fail; + } + + parentPrivate->hidden = childPrivate->hidden; + +#if TARGET_OS_IPHONE + parentPrivate->trustRequired = childPrivate->trustRequired; +#endif // TARGET_OS_IPHONE + + if (childPrivate->overrides != NULL) { + parentPrivate->overrides = CFDictionaryCreateMutableCopy(NULL, 0, childPrivate->overrides); + } + + // The following change handles the case where a user has both an Ethernet and + // PPPoE network service. Because a PPPoE service is typically associated with + // an ISP we want it to be sorted higher in the service order. + if ((parentPrivate->entity_subtype != NULL) && + (CFEqual(parentPrivate->entity_subtype, kSCValNetInterfaceSubTypePPPoE))) { + if ((childPrivate->interface_type != NULL) && + (CFEqual(childPrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211))) { + parentPrivate->sort_order = kSortAirportPPP; + } else { + parentPrivate->sort_order = kSortEthernetPPP; + } + } else { + // set sort order of the parent to match the child interface + parentPrivate->sort_order = childPrivate->sort_order; + } + + return (SCNetworkInterfaceRef)parentPrivate; + + fail : + + CFRelease(parentPrivate); + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; +} + + +__private_extern__ +CFDictionaryRef +__SCNetworkInterfaceGetDefaultConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface) +{ + CFDictionaryRef config = NULL; + CFStringRef defaultType; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + /* initialize runtime (and kSCNetworkInterfaceIPv4) */ + pthread_once(&initialized, __SCNetworkInterfaceInitialize); + + defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface); + if (defaultType != NULL) { + if (set != NULL) { + CFStringRef path; + + path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator + SCNetworkSetGetSetID(set), // set + interfacePrivate->entity_device, // interface + defaultType); // entity + if (path != NULL) { + config = __getPrefsConfiguration(interfacePrivate->prefs, path); + CFRelease(path); + + if (config == NULL) { + // if the "set" does not have a saved configuration, use + // the [template] "interface" configuration + if (interfacePrivate->unsaved != NULL) { + config = CFDictionaryGetValue(interfacePrivate->unsaved, defaultType); + if (config == (CFDictionaryRef)kCFNull) { + config = NULL; + } + } + } + if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) { + config = NULL; + } + } + } + } + + return config; +} + + +static CFDictionaryRef +__SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface, + CFStringRef extendedType) +{ + CFDictionaryRef config = NULL; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + CFArrayRef paths; + + /* initialize runtime (and kSCNetworkInterfaceIPv4) */ + pthread_once(&initialized, __SCNetworkInterfaceInitialize); + + paths = copyConfigurationPaths(interfacePrivate, extendedType); + if (paths != NULL) { + CFStringRef path; + + path = CFArrayGetValueAtIndex(paths, 0); + config = __getPrefsConfiguration(interfacePrivate->prefs, path); + + CFRelease(paths); + } else { + if (interfacePrivate->unsaved != NULL) { + config = CFDictionaryGetValue(interfacePrivate->unsaved, extendedType); + if (config == (CFDictionaryRef)kCFNull) { + config = NULL; + } + } + } + + if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) { + config = NULL; + } + + return config; +} + + +CFDictionaryRef +SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface) +{ + CFDictionaryRef config; + CFStringRef defaultType; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface); + if (defaultType == NULL) { + return NULL; + } + + config = __SCNetworkInterfaceGetConfiguration(interface, defaultType); + if (config == NULL) { + if (CFEqual(defaultType, kSCEntNetAirPort)) { + SCNetworkInterfacePrivateRef interfacePrivate; + CFStringRef path; + + // if AirPort interface, check for a per-service config + interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator + interfacePrivate->serviceID, // service + kSCEntNetAirPort); // entity + config = __getPrefsConfiguration(interfacePrivate->prefs, path); + CFRelease(path); + } + } + if (config == NULL) { + _SCErrorSet(kSCStatusOK); + } + + return config; +} + + +CFDictionaryRef +SCNetworkInterfaceGetExtendedConfiguration(SCNetworkInterfaceRef interface, + CFStringRef extendedType) +{ + CFDictionaryRef config; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, TRUE)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + config = __SCNetworkInterfaceGetConfiguration(interface, extendedType); + if (config == NULL) { + _SCErrorSet(kSCStatusOK); + } + + return config; +} + + +__private_extern__ +CFStringRef +__SCNetworkInterfaceGetEntityType(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->entity_type; +} + + +__private_extern__ +CFStringRef +__SCNetworkInterfaceGetEntitySubType(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef) interface; + + return interfacePrivate->entity_subtype; +} + + +CFStringRef +SCNetworkInterfaceGetBSDName(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + if ((interfacePrivate->interface != NULL) && + (interfacePrivate->interface != kSCNetworkInterfaceIPv4)) { + _SCErrorSet(kSCStatusOK); + return NULL; + } + + return interfacePrivate->entity_device; +} + + +CFStringRef +SCNetworkInterfaceGetHardwareAddressString(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + if ((interfacePrivate->address != NULL) && + (interfacePrivate->addressString == NULL)) { + uint8_t *bp; + char *cp; + size_t n; + char mac[sizeof("xx:xx:xx:xx:xx:xx:xx:xx")]; + char *mac_p = mac; + + bp = (uint8_t *)CFDataGetBytePtr(interfacePrivate->address); + n = CFDataGetLength(interfacePrivate->address) * 3; + + if (n > sizeof(mac)) { + mac_p = CFAllocatorAllocate(NULL, n, 0); + } + + for (cp = mac_p; n > 0; n -= 3) { + cp += snprintf(cp, n, "%2.2x:", *bp++); + } + + interfacePrivate->addressString = CFStringCreateWithCString(NULL, mac_p, kCFStringEncodingUTF8); + if (mac_p != mac) CFAllocatorDeallocate(NULL, mac_p); + } + + return interfacePrivate->addressString; +} + + +SCNetworkInterfaceRef +SCNetworkInterfaceGetInterface(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + return interfacePrivate->interface; +} + + +CFStringRef +SCNetworkInterfaceGetInterfaceType(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + return interfacePrivate->interface_type; +} + + +static CFStringRef +copy_string_from_bundle(CFBundleRef bundle, CFStringRef key, Boolean localized) +{ + CFStringRef str = NULL; + + if (localized) { + str = CFBundleCopyLocalizedString(bundle, + key, + key, + NETWORKINTERFACE_LOCALIZATIONS); + } else { + str = _SC_CFBundleCopyNonLocalizedString(bundle, + key, + key, + NETWORKINTERFACE_LOCALIZATIONS); + } + + return str; +} + + +static CFStringRef +copy_interface_string(CFBundleRef bundle, CFStringRef key, Boolean localized) +{ + static Boolean reported = FALSE; + CFStringRef str = NULL; + + str = copy_string_from_bundle(bundle, key, localized); + + if (str == NULL) { + SC_log(LOG_ERR, "Received NULL string for the interface key: {Bundle: %@, key: %@, localized: %d}", bundle, + key, + localized); + goto done; + } + + if (CFEqual(str, key) && !reported) { + const CFStringRef knownStrKey = CFSTR("airport"); + CFStringRef knownStrValue = NULL; + + knownStrValue = copy_string_from_bundle(bundle, knownStrKey, localized); + if (knownStrValue == NULL || CFEqual(knownStrValue, knownStrKey)) { + /* We are here because we requested for a localized/non-localized string + based on the localization key, but we were given the same key/NULL back, + implying a bad...bad thing! + */ + SC_log(LOG_ERR, "Failed to retrieve the interface string: {Bundle: %@, key: %@, localized: %d}", bundle, + knownStrKey, + localized); + +#if TARGET_OS_IPHONE + /* ...and we want to know about it! */ + _SC_crash("Failed to retrieve interface string", NULL, NULL); +#endif //TARGET_OS_IPHONE + reported = TRUE; + } + + if (knownStrValue != NULL) { + CFRelease(knownStrValue); + } + } + +done: + return str; +} + + +static CFStringRef +copy_display_name(SCNetworkInterfaceRef interface, Boolean localized, Boolean oldLocalization) +{ + CFMutableStringRef local; + CFStringRef name; + + local = CFStringCreateMutable(NULL, 0); + + while (interface != NULL) { + Boolean added = FALSE; + SCNetworkInterfaceRef child = NULL; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if ((interfacePrivate->interface != NULL) && + (interfacePrivate->interface != kSCNetworkInterfaceIPv4) && + !CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeVPN)) { + child = interfacePrivate->interface; + } + + if ((bundle != NULL) && (interfacePrivate->localized_key != NULL)) { + CFStringRef fmt; + CFStringRef key = interfacePrivate->localized_key; + + if (oldLocalization) { + key = CFStringCreateWithFormat(NULL, NULL, CFSTR("X-%@"), + interfacePrivate->localized_key); + } + fmt = copy_interface_string(bundle, key, localized); + if (fmt != NULL) { + CFStringAppendFormat(local, + NULL, + fmt, + interfacePrivate->localized_arg1, + interfacePrivate->localized_arg2); + CFRelease(fmt); + added = TRUE; + } + if (oldLocalization) { + CFRelease(key); + } + } + + if (!added && + (interfacePrivate->prefs != NULL) && + (interfacePrivate->serviceID != NULL) && + (child == NULL)) { + CFDictionaryRef entity; + CFStringRef path; + + // check for (and use) the name of the interface when it + // was last available + path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, + interfacePrivate->serviceID, + kSCEntNetInterface); + entity = SCPreferencesPathGetValue(interfacePrivate->prefs, path); + CFRelease(path); + if (isA_CFDictionary(entity)) { + CFStringRef name; + + name = CFDictionaryGetValue(entity, kSCPropUserDefinedName); + if (isA_CFString(name)) { + CFStringAppend(local, name); + added = TRUE; + } + } + } + + if (!added) { + // create (non-)localized name based on the interface type + CFStringAppend(local, interfacePrivate->interface_type); + + // ... and, if this is a leaf node, the interface device + if ((interfacePrivate->entity_device != NULL) && (child == NULL)) { + CFStringAppendFormat(local, NULL, CFSTR(" (%@)"), interfacePrivate->entity_device); + } + } + + if (child != NULL) { + // if this interface is layered over another + CFStringAppend(local, CFSTR(" --> ")); + } + + interface = child; + } + + name = CFStringCreateCopy(NULL, local); + CFRelease(local); + + return name; +} + + +#if !TARGET_OS_IPHONE +__private_extern__ +CFStringRef +__SCNetworkInterfaceCopyXLocalizedDisplayName(SCNetworkInterfaceRef interface) +{ + CFStringRef name; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + name = copy_display_name(interface, TRUE, TRUE); + return name; +} + + +__private_extern__ +CFStringRef +__SCNetworkInterfaceCopyXNonLocalizedDisplayName(SCNetworkInterfaceRef interface) +{ + CFStringRef localized_name; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + localized_name = copy_display_name(interface, FALSE, TRUE); + return localized_name; +} +#endif // !TARGET_OS_IPHONE + +__private_extern__ +void +__SCNetworkInterfaceSetUserDefinedName(SCNetworkInterfaceRef interface, CFStringRef name) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + return; + } + if (name != NULL) { + CFRetain(name); + } + if (interfacePrivate->name != NULL) { + CFRelease(interfacePrivate->name); + } + interfacePrivate->name = name; + + if (name != NULL) { + CFRetain(name); + } + if (interfacePrivate->localized_name != NULL) { + CFRelease(interfacePrivate->localized_name); + } + interfacePrivate->localized_name = name; +} + +__private_extern__ +CFStringRef +__SCNetworkInterfaceGetUserDefinedName(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + return NULL; + } + + return interfacePrivate->name; +} + + +__private_extern__ +CFStringRef +__SCNetworkInterfaceGetNonLocalizedDisplayName(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + if (interfacePrivate->name == NULL) { + interfacePrivate->name = copy_display_name(interface, FALSE, FALSE); + } + + return interfacePrivate->name; +} + + +CFStringRef +SCNetworkInterfaceGetLocalizedDisplayName(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + if (interfacePrivate->localized_name == NULL) { + interfacePrivate->localized_name = copy_display_name(interface, TRUE, FALSE); + } + + return interfacePrivate->localized_name; +} + + +__private_extern__ +CFPropertyListRef +__SCNetworkInterfaceGetTemplateOverrides(SCNetworkInterfaceRef interface, CFStringRef overrideType) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + CFPropertyListRef overrides = NULL; + + if (interfacePrivate->overrides != NULL) { + overrides = CFDictionaryGetValue(interfacePrivate->overrides, overrideType); + } + + return overrides; +} + + +CFTypeID +SCNetworkInterfaceGetTypeID(void) +{ + pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* initialize runtime */ + return __kSCNetworkInterfaceTypeID; +} + + +__private_extern__ +Boolean +__SCNetworkInterfaceSetDefaultConfiguration(SCNetworkSetRef set, + SCNetworkInterfaceRef interface, + CFStringRef defaultType, + CFDictionaryRef config, + Boolean okToHold) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + Boolean ok = FALSE; + + /* initialize runtime (and kSCNetworkInterfaceIPv4) */ + pthread_once(&initialized, __SCNetworkInterfaceInitialize); + + if (defaultType == NULL) { + defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface); + if (defaultType == NULL) { + return FALSE; + } + } + + if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) { + config = NULL; + } + + if (set != NULL) { + CFStringRef path; + + path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator + SCNetworkSetGetSetID(set), // set + interfacePrivate->entity_device, // interface + defaultType); // entity + if (path != NULL) { + ok = __setPrefsConfiguration(interfacePrivate->prefs, path, config, FALSE); + CFRelease(path); + if (ok) { + // if configuration has been saved + if (interfacePrivate->unsaved != NULL) { + CFDictionaryRemoveValue(interfacePrivate->unsaved, defaultType); + if (CFDictionaryGetCount(interfacePrivate->unsaved) == 0) { + CFRelease(interfacePrivate->unsaved); + interfacePrivate->unsaved = NULL; + } + } + } + } else { + if (okToHold) { + if (config == NULL) { + // remember that we are clearing the configuration + config = (CFDictionaryRef)kCFNull; + } + + if (interfacePrivate->unsaved == NULL) { + interfacePrivate->unsaved = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + CFDictionarySetValue(interfacePrivate->unsaved, defaultType, config); + ok = TRUE; + } else { + _SCErrorSet(kSCStatusNoKey); + } + } + } + + return ok; +} + + +__private_extern__ +Boolean +__SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, + CFStringRef extendedType, + CFDictionaryRef config, + Boolean okToHold) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + Boolean ok = FALSE; + CFArrayRef paths; + + /* initialize runtime (and kSCNetworkInterfaceIPv4) */ + pthread_once(&initialized, __SCNetworkInterfaceInitialize); + + if (extendedType == NULL) { + extendedType = __SCNetworkInterfaceGetDefaultConfigurationType(interface); + if (extendedType == NULL) { + return FALSE; + } + } + + if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) { + config = NULL; + } + + paths = copyConfigurationPaths(interfacePrivate, extendedType); + if (paths != NULL) { + CFIndex i; + CFIndex n; + + n = CFArrayGetCount(paths); + for (i = 0; i < n; i++) { + CFStringRef path; + + path = CFArrayGetValueAtIndex(paths, i); + ok = __setPrefsConfiguration(interfacePrivate->prefs, path, config, FALSE); + if (!ok) { + break; + } + } + + if (ok) { + // if configuration has been saved + if (interfacePrivate->unsaved != NULL) { + CFDictionaryRemoveValue(interfacePrivate->unsaved, extendedType); + if (CFDictionaryGetCount(interfacePrivate->unsaved) == 0) { + CFRelease(interfacePrivate->unsaved); + interfacePrivate->unsaved = NULL; + } + } + } + + CFRelease(paths); + } else { + if (okToHold) { + if (config == NULL) { + // remember that we are clearing the configuration + config = (CFDictionaryRef)kCFNull; + } + + if (interfacePrivate->unsaved == NULL) { + interfacePrivate->unsaved = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + CFDictionarySetValue(interfacePrivate->unsaved, extendedType, config); + ok = TRUE; + } else { + _SCErrorSet(kSCStatusNoKey); + } + } + + return ok; +} + + +Boolean +SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config) +{ + CFStringRef defaultType; + Boolean ok; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface); + if (defaultType == NULL) { + return FALSE; + } + + ok = __SCNetworkInterfaceSetConfiguration(interface, defaultType, config, FALSE); + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkInterfaceSetConfiguration(): %@ -> %@", + interface, + config != NULL ? config : (CFDictionaryRef)CFSTR("NULL")); + } + + return ok; +} + + +Boolean +SCNetworkInterfaceSetExtendedConfiguration(SCNetworkInterfaceRef interface, + CFStringRef extendedType, + CFDictionaryRef config) +{ + Boolean ok; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, TRUE)) { + return FALSE; + } + + ok = __SCNetworkInterfaceSetConfiguration(interface, extendedType, config, FALSE); + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkInterfaceSetExtendedConfiguration(): %@ -> %@", + interface, + config != NULL ? config : (CFDictionaryRef)CFSTR("NULL")); + } + + return ok; +} + + +#pragma mark - +#pragma mark SCNetworkInterface [Refresh Configuration] API + + +Boolean +_SCNetworkInterfaceForceConfigurationRefresh(CFStringRef ifName) +{ + CFStringRef key; + Boolean ok = FALSE; + + if (!isA_CFString(ifName)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, + kSCDynamicStoreDomainState, + ifName, + kSCEntNetRefreshConfiguration); + ok = SCDynamicStoreNotifyValue(NULL, key); + CFRelease(key); + return ok; +} + + +static Boolean +__SCNetworkInterfaceForceConfigurationRefresh_helper(SCPreferencesRef prefs, CFStringRef ifName) +{ + CFDataRef data = NULL; + Boolean ok; + SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; + uint32_t status = kSCStatusOK; + CFDataRef reply = NULL; + + if (prefsPrivate->helper_port == MACH_PORT_NULL) { + ok = __SCPreferencesCreate_helper(prefs); + if (!ok) { + return FALSE; + } + } + + // serialize the interface name + ok = _SCSerializeString(ifName, &data, NULL, NULL); + if (!ok) { + goto fail; + } + + // have the helper "refresh" the configuration + status = kSCStatusOK; + reply = NULL; + ok = _SCHelperExec(prefsPrivate->helper_port, + SCHELPER_MSG_INTERFACE_REFRESH, + data, + &status, + NULL); + if (data != NULL) CFRelease(data); + if (!ok) { + goto fail; + } + + if (status != kSCStatusOK) { + goto error; + } + + return TRUE; + + fail : + + // close helper + if (prefsPrivate->helper_port != MACH_PORT_NULL) { + _SCHelperClose(&prefsPrivate->helper_port); + } + + status = kSCStatusAccessError; + + error : + + // return error + _SCErrorSet(status); + return FALSE; +} + + +Boolean +SCNetworkInterfaceForceConfigurationRefresh(SCNetworkInterfaceRef interface) +{ + CFStringRef ifName; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + ifName = SCNetworkInterfaceGetBSDName(interface); + if (ifName == NULL) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + if (interfacePrivate->prefs != NULL) { + SCPreferencesRef prefs = interfacePrivate->prefs; + SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; + + if (prefsPrivate->authorizationData != NULL) { + return __SCNetworkInterfaceForceConfigurationRefresh_helper(prefs, ifName); + } + } + + return _SCNetworkInterfaceForceConfigurationRefresh(ifName); +} + + +#if !TARGET_OS_IPHONE +Boolean +SCNetworkInterfaceRefreshConfiguration(CFStringRef ifName) +{ + return _SCNetworkInterfaceForceConfigurationRefresh(ifName); +} +#endif // !TARGET_OS_IPHONE + + +#pragma mark - +#pragma mark SCNetworkInterface Password APIs + + +static CFStringRef +getPasswordID(CFDictionaryRef config, CFStringRef serviceID) +{ + CFStringRef unique_id = NULL; + + if (config != NULL) { + CFStringRef encryption; + + encryption = CFDictionaryGetValue(config, kSCPropNetPPPAuthPasswordEncryption); + if (isA_CFString(encryption) && + CFEqual(encryption, kSCValNetPPPAuthPasswordEncryptionKeychain)) { + unique_id = CFDictionaryGetValue(config, kSCPropNetPPPAuthPassword); + } + } + if (unique_id == NULL) { + unique_id = serviceID; + } + + return unique_id; +} + + +static CFStringRef +copySharedSecretID(CFDictionaryRef config, CFStringRef serviceID) +{ + CFMutableStringRef shared_id = NULL; + + if (config != NULL) { + CFStringRef encryption; + + encryption = CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecretEncryption); + if (isA_CFString(encryption) && + CFEqual(encryption, kSCValNetIPSecSharedSecretEncryptionKeychain)) { + shared_id = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecret); + if (shared_id != NULL) { + CFRetain(shared_id); + } + } + } + + if (shared_id == NULL) { + CFStringRef unique_id; + + unique_id = getPasswordID(config, serviceID); + shared_id = CFStringCreateMutableCopy(NULL, 0, unique_id); + CFStringAppend(shared_id, CFSTR(".SS")); + } + + return shared_id; +} + + +static CFStringRef +copyXAuthID(CFDictionaryRef config, CFStringRef serviceID) +{ + CFMutableStringRef xauth_id = NULL; + + if (config != NULL) { + CFStringRef encryption; + + encryption = CFDictionaryGetValue(config, kSCPropNetIPSecXAuthPasswordEncryption); + if (isA_CFString(encryption) && + CFEqual(encryption, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) { + xauth_id = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecXAuthPassword); + if (xauth_id != NULL) { + CFRetain(xauth_id); + } + } + } + + if (xauth_id == NULL) { + CFStringRef unique_id; + + unique_id = getPasswordID(config, serviceID); + xauth_id = CFStringCreateMutableCopy(NULL, 0, unique_id); + CFStringAppend(xauth_id, CFSTR(".XAUTH")); + } + + return xauth_id; +} + + +static Boolean +checkInterfacePassword(SCNetworkInterfaceRef interface, + SCNetworkInterfacePasswordType passwordType, + SCPreferencesRef *prefs, + CFStringRef *serviceID) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!isA_SCNetworkInterface(interface)) { + goto error; + } + + *serviceID = interfacePrivate->serviceID; + if (*serviceID == NULL) { + goto error; + } + + *prefs = interfacePrivate->prefs; + if (*prefs == NULL) { + goto error; + } + + switch (passwordType) { + case kSCNetworkInterfacePasswordTypePPP : { + CFStringRef interfaceType; + + interfaceType = SCNetworkInterfaceGetInterfaceType(interface); + if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) { + // if PPP + break; + } + + goto error; + } + + case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : { + CFStringRef interfaceType; + + interfaceType = SCNetworkInterfaceGetInterfaceType(interface); + if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) { + interface = SCNetworkInterfaceGetInterface(interface); + if (interface != NULL) { + interfaceType = SCNetworkInterfaceGetInterfaceType(interface); + if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) { + // if PPP->L2TP interface + break; + } + } + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) { + // if IPSec interface + break; + } + + goto error; + } + + case kSCNetworkInterfacePasswordTypeEAPOL : { + break; + } + + case kSCNetworkInterfacePasswordTypeIPSecXAuth : { + CFStringRef interfaceType; + + interfaceType = SCNetworkInterfaceGetInterfaceType(interface); + if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) { + // if IPSec interface + break; + } + + goto error; + } + + case kSCNetworkInterfacePasswordTypeVPN : { + CFStringRef interfaceType; + + interfaceType = SCNetworkInterfaceGetInterfaceType(interface); + if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) { + // if VPN interface + break; + } + + goto error; + } + + default : + break; + } + + return TRUE; + + error : + + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; +} + + +Boolean +SCNetworkInterfaceCheckPassword(SCNetworkInterfaceRef interface, + SCNetworkInterfacePasswordType passwordType) +{ + Boolean exists = FALSE; + SCPreferencesRef prefs = NULL; + CFStringRef serviceID = NULL; + + if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) { + return FALSE; + } + + switch (passwordType) { + case kSCNetworkInterfacePasswordTypePPP : { + CFDictionaryRef config; + CFStringRef unique_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get serviceID + unique_id = getPasswordID(config, serviceID); + + // check + exists = __extract_password(prefs, + config, + kSCPropNetPPPAuthPassword, + kSCPropNetPPPAuthPasswordEncryption, + kSCValNetPPPAuthPasswordEncryptionKeychain, + unique_id, + NULL); + break; + } + + case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : { + CFDictionaryRef config; + Boolean extended; + CFStringRef shared_id; + + // get configuration + extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP); + if (extended) { + config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec); + } else { + config = SCNetworkInterfaceGetConfiguration(interface); + } + + // get sharedSecret ID + shared_id = copySharedSecretID(config, serviceID); + + // check + exists = __extract_password(prefs, + config, + kSCPropNetIPSecSharedSecret, + kSCPropNetIPSecSharedSecretEncryption, + kSCValNetIPSecSharedSecretEncryptionKeychain, + shared_id, + NULL); + CFRelease(shared_id); + break; + } + + case kSCNetworkInterfacePasswordTypeEAPOL : { + CFDictionaryRef config; + CFStringRef unique_id = NULL; + + // get configuration + config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL); + + // get 802.1X identifier + if (config != NULL) { + unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID); + } + if (!isA_CFString(unique_id)) { + return FALSE; + } + + // check password + exists = _SCPreferencesSystemKeychainPasswordItemExists(prefs, unique_id); + break; + } + + case kSCNetworkInterfacePasswordTypeIPSecXAuth : { + CFDictionaryRef config; + CFStringRef xauth_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get XAuth ID + xauth_id = copyXAuthID(config, serviceID); + + // check + exists = __extract_password(prefs, + config, + kSCPropNetIPSecXAuthPassword, + kSCPropNetIPSecXAuthPasswordEncryption, + kSCValNetIPSecXAuthPasswordEncryptionKeychain, + xauth_id, + NULL); + CFRelease(xauth_id); + break; + } + + case kSCNetworkInterfacePasswordTypeVPN : { + CFDictionaryRef config; + CFStringRef vpn_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get serviceID + vpn_id = getPasswordID(config, serviceID); + + // check + exists = __extract_password(prefs, + config, + kSCPropNetVPNAuthPassword, + kSCPropNetVPNAuthPasswordEncryption, + kSCValNetVPNAuthPasswordEncryptionKeychain, + vpn_id, + NULL); + break; + } + + default : + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + return exists; +} + + +CFDataRef +SCNetworkInterfaceCopyPassword(SCNetworkInterfaceRef interface, + SCNetworkInterfacePasswordType passwordType) +{ + CFDataRef password = NULL; + SCPreferencesRef prefs = NULL; + CFStringRef serviceID = NULL; + + if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) { + return NULL; + } + + switch (passwordType) { + case kSCNetworkInterfacePasswordTypePPP : { + CFDictionaryRef config; + CFStringRef unique_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get serviceID + unique_id = getPasswordID(config, serviceID); + + // extract + (void) __extract_password(prefs, + config, + kSCPropNetPPPAuthPassword, + kSCPropNetPPPAuthPasswordEncryption, + kSCValNetPPPAuthPasswordEncryptionKeychain, + unique_id, + &password); + break; + } + + case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : { + CFDictionaryRef config; + Boolean extended; + CFStringRef shared_id; + + // get configuration + extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP); + if (extended) { + config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec); + } else { + config = SCNetworkInterfaceGetConfiguration(interface); + } + + // get sharedSecret ID + shared_id = copySharedSecretID(config, serviceID); + + // extract + (void) __extract_password(prefs, + config, + kSCPropNetIPSecSharedSecret, + kSCPropNetIPSecSharedSecretEncryption, + kSCValNetIPSecSharedSecretEncryptionKeychain, + shared_id, + &password); + + CFRelease(shared_id); + break; + } + + case kSCNetworkInterfacePasswordTypeEAPOL : { + CFDictionaryRef config; + CFStringRef unique_id = NULL; + + // get configuration + config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL); + + // get 802.1X identifier + if (config != NULL) { + unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID); + } + if (!isA_CFString(unique_id)) { + _SCErrorSet(kSCStatusFailed); + return NULL; + } + + // copy password + password = _SCPreferencesSystemKeychainPasswordItemCopy(prefs, unique_id); + break; + } + + case kSCNetworkInterfacePasswordTypeIPSecXAuth : { + CFDictionaryRef config; + CFStringRef xauth_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get XAuth ID + xauth_id = copyXAuthID(config, serviceID); + + // extract + (void) __extract_password(prefs, + config, + kSCPropNetIPSecXAuthPassword, + kSCPropNetIPSecXAuthPasswordEncryption, + kSCValNetIPSecXAuthPasswordEncryptionKeychain, + xauth_id, + &password); + CFRelease(xauth_id); + break; + } + + case kSCNetworkInterfacePasswordTypeVPN : { + CFDictionaryRef config; + CFStringRef vpn_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get serviceID + vpn_id = getPasswordID(config, serviceID); + + // extract + (void) __extract_password(prefs, + config, + kSCPropNetVPNAuthPassword, + kSCPropNetVPNAuthPasswordEncryption, + kSCValNetVPNAuthPasswordEncryptionKeychain, + vpn_id, + &password); + break; + } + + default : + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + return password; +} + + +Boolean +SCNetworkInterfaceRemovePassword(SCNetworkInterfaceRef interface, + SCNetworkInterfacePasswordType passwordType) +{ + Boolean ok = FALSE; + SCPreferencesRef prefs = NULL; + CFStringRef serviceID = NULL; + + if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) { + return FALSE; + } + + switch (passwordType) { + case kSCNetworkInterfacePasswordTypePPP : { + CFDictionaryRef config; + CFDictionaryRef newConfig = NULL; + CFStringRef unique_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get serviceID + unique_id = getPasswordID(config, serviceID); + + // remove password + ok = __remove_password(prefs, + config, + kSCPropNetPPPAuthPassword, + kSCPropNetPPPAuthPasswordEncryption, + kSCValNetPPPAuthPasswordEncryptionKeychain, + unique_id, + &newConfig); + if (ok) { + ok = SCNetworkInterfaceSetConfiguration(interface, newConfig); + if (newConfig != NULL) CFRelease(newConfig); + } + + break; + } + + case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : { + CFDictionaryRef config; + Boolean extended; + CFDictionaryRef newConfig = NULL; + CFStringRef shared_id; + + // get configuration + extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP); + if (extended) { + config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec); + } else { + config = SCNetworkInterfaceGetConfiguration(interface); + } + + // get sharedSecret ID + shared_id = copySharedSecretID(config, serviceID); + + // remove password + ok = __remove_password(prefs, + config, + kSCPropNetIPSecSharedSecret, + kSCPropNetIPSecSharedSecretEncryption, + kSCValNetIPSecSharedSecretEncryptionKeychain, + shared_id, + &newConfig); + if (ok) { + if (extended) { + ok = SCNetworkInterfaceSetExtendedConfiguration(interface, + kSCEntNetIPSec, + newConfig); + } else { + ok = SCNetworkInterfaceSetConfiguration(interface, + newConfig); + } + if (newConfig != NULL) CFRelease(newConfig); + } + + CFRelease(shared_id); + break; + } + + case kSCNetworkInterfacePasswordTypeEAPOL : { + CFDictionaryRef config; + CFStringRef unique_id = NULL; + + // get configuration + config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL); + + // get 802.1X identifier + if (config != NULL) { + unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID); + } + if (!isA_CFString(unique_id)) { + _SCErrorSet(kSCStatusFailed); + return FALSE; + } + + // remove password + ok = _SCPreferencesSystemKeychainPasswordItemRemove(prefs, unique_id); + break; + } + + case kSCNetworkInterfacePasswordTypeIPSecXAuth : { + CFDictionaryRef config; + CFDictionaryRef newConfig = NULL; + CFStringRef xauth_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get XAuth ID + xauth_id = copyXAuthID(config, serviceID); + + // remove password + ok = __remove_password(prefs, + config, + kSCPropNetIPSecXAuthPassword, + kSCPropNetIPSecXAuthPasswordEncryption, + kSCValNetIPSecXAuthPasswordEncryptionKeychain, + xauth_id, + &newConfig); + if (ok) { + ok = SCNetworkInterfaceSetConfiguration(interface, newConfig); + if (newConfig != NULL) CFRelease(newConfig); + } + + CFRelease(xauth_id); + break; + } + + case kSCNetworkInterfacePasswordTypeVPN : { + CFDictionaryRef config; + CFDictionaryRef newConfig = NULL; + CFStringRef vpn_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get serviceID + vpn_id = getPasswordID(config, serviceID); + + // remove password + ok = __remove_password(prefs, + config, + kSCPropNetVPNAuthPassword, + kSCPropNetVPNAuthPasswordEncryption, + kSCValNetVPNAuthPasswordEncryptionKeychain, + vpn_id, + &newConfig); + if (ok) { + ok = SCNetworkInterfaceSetConfiguration(interface, newConfig); + if (newConfig != NULL) CFRelease(newConfig); + } + break; + } + + default : + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + return ok; +} + + +Boolean +SCNetworkInterfaceSetPassword(SCNetworkInterfaceRef interface, + SCNetworkInterfacePasswordType passwordType, + CFDataRef password, + CFDictionaryRef options) +{ + CFStringRef account = NULL; + CFDictionaryRef config; + CFStringRef description = NULL; + CFStringRef label = NULL; + Boolean ok = FALSE; + SCPreferencesRef prefs = NULL; + CFStringRef serviceID = NULL; + + if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) { + return FALSE; + } + + switch (passwordType) { + case kSCNetworkInterfacePasswordTypePPP : { + SCNetworkServiceRef service = NULL; + CFStringRef unique_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get serviceID + unique_id = getPasswordID(config, serviceID); + + // get "Account", "Name", "Kind" + if (config != NULL) { + // auth name --> keychain "Account" + account = CFDictionaryGetValue(config, kSCPropNetPPPAuthName); + + // PPP [user defined] "name" --> keychain "Name" + label = CFDictionaryGetValue(config, kSCPropUserDefinedName); + } + + if (label == NULL) { + // service name --> keychain "Name" + service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL, + prefs, + serviceID, + interface); + + label = SCNetworkServiceGetName(service); + if (label == NULL) { + // interface name --> keychain "Name" + label = SCNetworkInterfaceGetLocalizedDisplayName(interface); + } + } + + if (bundle != NULL) { + // "PPP Password" --> keychain "Kind" + description = CFBundleCopyLocalizedString(bundle, + CFSTR("KEYCHAIN_KIND_PPP_PASSWORD"), + CFSTR("PPP Password"), + NULL); + } + + // store password + ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs, + unique_id, + (label != NULL) ? label : CFSTR("Network Connection"), + (description != NULL) ? description : CFSTR("PPP Password"), + account, + password, + options); + if (ok) { + CFMutableDictionaryRef newConfig; + + if (config != NULL) { + newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config); + } else { + newConfig = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + CFDictionarySetValue(newConfig, + kSCPropNetPPPAuthPassword, + unique_id); + CFDictionarySetValue(newConfig, + kSCPropNetPPPAuthPasswordEncryption, + kSCValNetPPPAuthPasswordEncryptionKeychain); + ok = SCNetworkInterfaceSetConfiguration(interface, newConfig); + CFRelease(newConfig); + } + + if (description != NULL) CFRelease(description); + if (service != NULL) CFRelease(service); + break; + } + + case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : { + CFDictionaryRef baseConfig = NULL; + Boolean extended; + SCNetworkServiceRef service = NULL; + CFStringRef shared_id; + + // get configuration + extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP); + config = SCNetworkInterfaceGetConfiguration(interface); + if (extended) { + baseConfig = config; + config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec); + } + + // get sharedSecret ID + shared_id = copySharedSecretID(config, serviceID); + + // get "Account", "Name", "Kind" + if (config != NULL) { + CFStringRef localIdentifier; + CFStringRef localIdentifierType; + + if (CFDictionaryGetValueIfPresent(config, + kSCPropNetIPSecLocalIdentifierType, + (const void **)&localIdentifierType) + && CFEqual(localIdentifierType, kSCValNetIPSecLocalIdentifierTypeKeyID) + && CFDictionaryGetValueIfPresent(config, + kSCPropNetIPSecLocalIdentifier, + (const void **)&localIdentifier) + && isA_CFString(localIdentifier)) { + // local identifier --> keychain "Account" + account = localIdentifier; + } + + // PPP [user defined] "name" --> keychain "Name" + if (!extended) { + label = CFDictionaryGetValue(config, kSCPropUserDefinedName); + } else { + if (baseConfig != NULL) { + label = CFDictionaryGetValue(baseConfig, kSCPropUserDefinedName); + } + } + } + + if (label == NULL) { + // service name --> keychain "Name" + service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL, + prefs, + serviceID, + interface); + + label = SCNetworkServiceGetName(service); + if (label == NULL) { + // interface name --> keychain "Name" + label = SCNetworkInterfaceGetLocalizedDisplayName(interface); + } + } + + if (bundle != NULL) { + // "IPSec Shared Secret" --> keychain "Kind" + description = CFBundleCopyLocalizedString(bundle, + CFSTR("KEYCHAIN_KIND_IPSEC_SHARED_SECRET"), + CFSTR("IPSec Shared Secret"), + NULL); + } + + // set password + ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs, + shared_id, + (label != NULL) ? label : CFSTR("Network Connection"), + (description != NULL) ? description : CFSTR("IPSec Shared Secret"), + account, + password, + options); + if (ok) { + CFMutableDictionaryRef newConfig = NULL; + + if (config != NULL) { + newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config); + } else { + newConfig = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + CFDictionarySetValue(newConfig, + kSCPropNetIPSecSharedSecret, + shared_id); + CFDictionarySetValue(newConfig, + kSCPropNetIPSecSharedSecretEncryption, + kSCValNetIPSecSharedSecretEncryptionKeychain); + if (extended) { + ok = SCNetworkInterfaceSetExtendedConfiguration(interface, + kSCEntNetIPSec, + newConfig); + } else { + ok = SCNetworkInterfaceSetConfiguration(interface, newConfig); + } + CFRelease(newConfig); + } + + if (description != NULL) CFRelease(description); + if (service != NULL) CFRelease(service); + CFRelease(shared_id); + break; + } + + case kSCNetworkInterfacePasswordTypeEAPOL : { + CFStringRef account = NULL; + CFStringRef unique_id = NULL; + + // get configuration + config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL); + + // get 802.1X identifier + if (config != NULL) { + unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID); + unique_id = isA_CFString(unique_id); + } + if (unique_id != NULL) { + CFRetain(unique_id); + } else { + CFUUIDRef uuid; + + uuid = CFUUIDCreate(NULL); + unique_id = CFUUIDCreateString(NULL, uuid); + CFRelease(uuid); + } + + // 802.1x UserName --> keychain "Account" + if (config != NULL) { + account = CFDictionaryGetValue(config, kEAPClientPropUserName); + } + + // get "Name", "Kind" + if (bundle != NULL) { + CFStringRef interface_name; + + // "Network Connection (%@)" --> keychain "Name" + interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface); + if (interface_name != NULL) { + CFStringRef label_fmt; + + label_fmt = CFBundleCopyLocalizedString(bundle, + CFSTR("KEYCHAIN_DESCRIPTION_EAPOL_INTERFACE"), + CFSTR("Network Connection (%@)"), + NULL); + label = CFStringCreateWithFormat(NULL, NULL, label_fmt, interface_name); + CFRelease(label_fmt); + } else { + label = CFBundleCopyLocalizedString(bundle, + CFSTR("KEYCHAIN_DESCRIPTION_EAPOL"), + CFSTR("Network Connection"), + NULL); + } + + // "802.1X Password" --> keychain "Kind" + description = CFBundleCopyLocalizedString(bundle, + CFSTR("KEYCHAIN_KIND_EAPOL"), + CFSTR("802.1X Password"), + NULL); + } + + // set password + ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs, + unique_id, + (label != NULL) ? label : CFSTR("Network Connection"), + (description != NULL) ? description : CFSTR("802.1X Password"), + account, + password, + options); + if (ok) { + CFMutableDictionaryRef newConfig = NULL; + + if (config != NULL) { + newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config); + } else { + newConfig = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + CFDictionarySetValue(newConfig, + kEAPClientPropUserPasswordKeychainItemID, + unique_id); + ok = SCNetworkInterfaceSetExtendedConfiguration(interface, + kSCEntNetEAPOL, + newConfig); + CFRelease(newConfig); + } + + CFRelease(unique_id); + if (label != NULL) CFRelease(label); + if (description != NULL) CFRelease(description); + break; + } + + case kSCNetworkInterfacePasswordTypeIPSecXAuth : { + SCNetworkServiceRef service = NULL; + CFStringRef xauth_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get XAuth ID + xauth_id = copyXAuthID(config, serviceID); + + // get "Account", "Name", "Kind" + if (config != NULL) { + // auth name --> keychain "Account" + account = CFDictionaryGetValue(config, kSCPropNetIPSecXAuthName); + + // IPSec [user defined] "name" --> keychain "Name" + label = CFDictionaryGetValue(config, kSCPropUserDefinedName); + } + + if (label == NULL) { + // service name --> keychain "Name" + service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL, + prefs, + serviceID, + interface); + + label = SCNetworkServiceGetName(service); + if (label == NULL) { + // interface name --> keychain "Name" + label = SCNetworkInterfaceGetLocalizedDisplayName(interface); + } + } + + if (bundle != NULL) { + // "IPSec XAuth Password" --> keychain "Kind" + description = CFBundleCopyLocalizedString(bundle, + CFSTR("KEYCHAIN_KIND_IPSEC_XAUTH_PASSWORD"), + CFSTR("IPSec XAuth Password"), + NULL); + } + + // store password + ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs, + xauth_id, + (label != NULL) ? label : CFSTR("Network Connection"), + (description != NULL) ? description : CFSTR("IPSec XAuth Password"), + account, + password, + options); + if (ok) { + CFMutableDictionaryRef newConfig; + + if (config != NULL) { + newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config); + } else { + newConfig = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + CFDictionarySetValue(newConfig, + kSCPropNetIPSecXAuthPassword, + xauth_id); + CFDictionarySetValue(newConfig, + kSCPropNetIPSecXAuthPasswordEncryption, + kSCValNetIPSecXAuthPasswordEncryptionKeychain); + ok = SCNetworkInterfaceSetConfiguration(interface, newConfig); + CFRelease(newConfig); + } + + CFRelease(xauth_id); + if (description != NULL) CFRelease(description); + if (service != NULL) CFRelease(service); + break; + } + + case kSCNetworkInterfacePasswordTypeVPN : { + SCNetworkServiceRef service = NULL; + CFStringRef vpn_id; + + // get configuration + config = SCNetworkInterfaceGetConfiguration(interface); + + // get serviceID + vpn_id = getPasswordID(config, serviceID); + + // get "Account", "Name", "Kind" + if (config != NULL) { + // auth name --> keychain "Account" + account = CFDictionaryGetValue(config, kSCPropNetVPNAuthName); + + // VPN [user defined] "name" --> keychain "Name" + label = CFDictionaryGetValue(config, kSCPropUserDefinedName); + } + + if (label == NULL) { + // service name --> keychain "Name" + service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL, + prefs, + serviceID, + interface); + + label = SCNetworkServiceGetName(service); + if (label == NULL) { + // interface name --> keychain "Name" + label = SCNetworkInterfaceGetLocalizedDisplayName(interface); + } + } + + if (bundle != NULL) { + // "VPN Password" --> keychain "Kind" + description = CFBundleCopyLocalizedString(bundle, + CFSTR("KEYCHAIN_KIND_VPN_PASSWORD"), + CFSTR("VPN Password"), + NULL); + } + + // store password + ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs, + vpn_id, + (label != NULL) ? label : CFSTR("Network Connection"), + (description != NULL) ? description : CFSTR("VPN Password"), + account, + password, + options); + if (ok) { + CFMutableDictionaryRef newConfig; + + if (config != NULL) { + newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config); + } else { + newConfig = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + CFDictionarySetValue(newConfig, + kSCPropNetVPNAuthPassword, + vpn_id); + CFDictionarySetValue(newConfig, + kSCPropNetVPNAuthPasswordEncryption, + kSCValNetVPNAuthPasswordEncryptionKeychain); + ok = SCNetworkInterfaceSetConfiguration(interface, newConfig); + CFRelease(newConfig); + } + + if (description != NULL) CFRelease(description); + if (service != NULL) CFRelease(service); + break; + } + + default : + _SCErrorSet(kSCStatusInvalidArgument); + break; + } + + return ok; +} + +#pragma mark - +#pragma mark SCNetworkInterface [Advisory] SPIs +#if TARGET_OS_SIMULATOR +Boolean +SCNetworkInterfaceSetAdvisory(SCNetworkInterfaceRef interface, + SCNetworkInterfaceAdvisory advisory, + CFStringRef reason) +{ +#pragma unused(interface) +#pragma unused(advisory) +#pragma unused(reason) + return (FALSE); +} + +Boolean +SCNetworkInterfaceAdvisoryIsSet(SCNetworkInterfaceRef interface) +{ +#pragma unused(interface) + return (FALSE); +} + +CFStringRef +SCNetworkInterfaceCopyAdvisoryNotificationKey(SCNetworkInterfaceRef interface) +{ +#pragma unused(interface) + return (NULL); +} + +#else /* TARGET_OS_SIMULATOR */ +Boolean +SCNetworkInterfaceSetAdvisory(SCNetworkInterfaceRef interface, + SCNetworkInterfaceAdvisory advisory, + CFStringRef reason) +{ + IPMonitorControlRef control; + SCNetworkInterfacePrivateRef interfacePrivate = + (SCNetworkInterfacePrivateRef)interface; + CFStringRef ifName; + + ifName = SCNetworkInterfaceGetBSDName(interface); + if (ifName == NULL) { + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); + } + control = interfacePrivate->IPMonitorControl; + if (control == NULL) { + control = IPMonitorControlCreate(); + if (control == NULL) { + _SCErrorSet(kSCStatusFailed); + return (FALSE); + } + interfacePrivate->IPMonitorControl = control; + } + return IPMonitorControlSetInterfaceAdvisory(control, + ifName, + advisory, + reason); +} + +Boolean +SCNetworkInterfaceAdvisoryIsSet(SCNetworkInterfaceRef interface) +{ + IPMonitorControlRef control; + SCNetworkInterfacePrivateRef interfacePrivate = + (SCNetworkInterfacePrivateRef)interface; + CFStringRef ifName; + + ifName = SCNetworkInterfaceGetBSDName(interface); + if (ifName == NULL) { + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); + } + control = interfacePrivate->IPMonitorControl; + if (control == NULL) { + control = IPMonitorControlCreate(); + if (control == NULL) { + _SCErrorSet(kSCStatusFailed); + return (FALSE); + } + interfacePrivate->IPMonitorControl = control; + } + return IPMonitorControlInterfaceAdvisoryIsSet(control, ifName); +} + +CFStringRef +SCNetworkInterfaceCopyAdvisoryNotificationKey(SCNetworkInterfaceRef interface) +{ + CFStringRef ifName; + + ifName = SCNetworkInterfaceGetBSDName(interface); + if (ifName == NULL) { + _SCErrorSet(kSCStatusInvalidArgument); + return (NULL); + } + return IPMonitorControlCopyInterfaceAdvisoryNotificationKey(ifName); +} +#endif /* TARGET_OS_SIMULATOR */ + +#pragma mark - +#pragma mark SCNetworkInterface [InterfaceNamer] SPIs + + +CFDictionaryRef +_SCNetworkInterfaceCopyInterfaceInfo(SCNetworkInterfaceRef interface) +{ + CFMutableDictionaryRef info; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + CFStringRef name; + + if (interface == NULL) { + return NULL; + } + + info = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + // add non-localized interface name + name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface); + if (name != NULL) { + CFDictionaryAddValue(info, kSCPropUserDefinedName, name); + } + + // add USB info + if ((interfacePrivate->usb.vid != NULL) || (interfacePrivate->usb.pid != NULL)) { +#if !TARGET_OS_SIMULATOR + if (interfacePrivate->usb.name != NULL) { + CFDictionaryAddValue(info, CFSTR(kUSBProductString), interfacePrivate->usb.name); + } + if (interfacePrivate->usb.vid != NULL) { + CFDictionaryAddValue(info, CFSTR(kUSBVendorID), interfacePrivate->usb.vid); + } + if (interfacePrivate->usb.pid != NULL) { + CFDictionaryAddValue(info, CFSTR(kUSBProductID), interfacePrivate->usb.pid); + } +#endif // !TARGET_OS_SIMULATOR + } + + if (CFDictionaryGetCount(info) == 0) { + // do not return an empty dictionary + CFRelease(info); + info = NULL; + } + + return info; +} + + +SCNetworkInterfaceRef +_SCNetworkInterfaceCreateWithIONetworkInterfaceObject(io_object_t if_obj) +{ + SCNetworkInterfaceRef interface = NULL; + + /* initialize runtime */ + pthread_once(&initialized, __SCNetworkInterfaceInitialize); + + if (IOObjectConformsTo(if_obj, kIONetworkInterfaceClass)) { + interface = createInterface(if_obj, processNetworkInterface, NULL); + } else if (IOObjectConformsTo(if_obj, kIOSerialBSDServiceValue)) { + interface = createInterface(if_obj, processSerialInterface, kSCNetworkInterfaceHiddenPortKey); + } + + return interface; +} + + +CFStringRef +_SCNetworkInterfaceGetConfigurationAction(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->configurationAction; +} + + +CFDataRef +_SCNetworkInterfaceGetHardwareAddress(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->address; +} + + +CFStringRef +_SCNetworkInterfaceGetIOInterfaceNamePrefix(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->prefix; +} + + +CFNumberRef +_SCNetworkInterfaceGetIOInterfaceType(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->type; +} + + +CFNumberRef +_SCNetworkInterfaceGetIOInterfaceUnit(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->unit; +} + + +static void +update_ift_family(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + // note: family/subfamily are not in IORegistry, fetch with ioctl() + + if ((interfacePrivate->family == NULL) && (interfacePrivate->subfamily == NULL)) { + CFStringRef bsdName = SCNetworkInterfaceGetBSDName(interface); + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + if ((bsdName != NULL) && + _SC_cfstring_to_cstring(bsdName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) != NULL) { + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s != -1) { + if (ioctl(s, SIOCGIFTYPE, (caddr_t)&ifr) == -1) { + ifr.ifr_type.ift_family = 0; + ifr.ifr_type.ift_subfamily = 0; + } + close(s); + } + } + + interfacePrivate->family = CFNumberCreate(NULL, + kCFNumberSInt32Type, + &ifr.ifr_type.ift_family); + interfacePrivate->subfamily = CFNumberCreate(NULL, + kCFNumberSInt32Type, + &ifr.ifr_type.ift_subfamily); + } +} + + +CFNumberRef +_SCNetworkInterfaceGetFamilyType(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + // note: family not in IORegistry, fetch with ioctl() + + if (interfacePrivate->family == NULL) { + update_ift_family(interface); + } + + return interfacePrivate->family; +} + + +CFNumberRef +_SCNetworkInterfaceGetFamilySubType(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + // note: subfamily not in IORegistry, fetch with ioctl() + + if (interfacePrivate->subfamily == NULL) { + update_ift_family(interface); + } + + return interfacePrivate->subfamily; +} + + +CFStringRef +_SCNetworkInterfaceGetIOPath(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->path; +} + + +uint64_t +_SCNetworkInterfaceGetIORegistryEntryID(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->entryID; +} + + +__private_extern__ +Boolean +__SCNetworkInterfaceIsActive (SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->active; +} + + +Boolean +_SCNetworkInterfaceIsBuiltin(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->builtin; +} + + +Boolean +_SCNetworkInterfaceIsTrustRequired(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->trustRequired; +} + + +#pragma mark - +#pragma mark SCNetworkInterface SPIs + + +#if TARGET_OS_OSX + +SCNetworkInterfaceRef +_SCNetworkInterfaceCopyBTPANInterface(void) +{ + CFDictionaryRef dict; + SCNetworkInterfaceRef interface = NULL; + CFStringRef key; + + key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" "InterfaceNamer"), kSCDynamicStoreDomainPlugin); + dict = SCDynamicStoreCopyValue(NULL, key); + CFRelease(key); + if (dict != NULL) { + CFDataRef addr; + CFStringRef if_name; + SCNetworkInterfacePrivateRef interfacePrivate; + + if (isA_CFDictionary(dict) && + CFDictionaryGetValueIfPresent(dict, + kInterfaceNamerKey_BT_PAN_Name, + (const void **)&if_name) && + isA_CFString(if_name)) { + CFMutableDictionaryRef entity; + + entity = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(entity, + kSCPropNetInterfaceType, + kSCValNetInterfaceTypeEthernet); + CFDictionarySetValue(entity, + kSCPropNetInterfaceDeviceName, + if_name); + CFDictionarySetValue(entity, + kSCPropUserDefinedName, + CFSTR(BT_PAN_NAME)); + interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, NULL); + CFRelease(entity); + } + + interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if ((interfacePrivate != NULL) && + (interfacePrivate->address == NULL) && + CFDictionaryGetValueIfPresent(dict, + kInterfaceNamerKey_BT_PAN_Mac, + (const void **)&addr) && + isA_CFData(addr)) { + interfacePrivate->address = CFRetain(addr); + } + + CFRelease(dict); + } + + return interface; +} +#endif // TARGET_OS_OSX + + +CFStringRef +_SCNetworkInterfaceCopySlashDevPath(SCNetworkInterfaceRef interface) +{ + io_registry_entry_t device; + io_iterator_t device_iterator = MACH_PORT_NULL; + CFStringRef device_path = NULL; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + kern_return_t kr; + CFStringRef match_keys[2]; + CFTypeRef match_vals[2]; + CFDictionaryRef match_dict; + CFDictionaryRef matching; + + if (interfacePrivate->entity_device == NULL) { + return NULL; + } + + if (interfacePrivate->entity_device_unique == NULL) { + goto done; + } + + match_keys[0] = CFSTR(kIOTTYBaseNameKey); + match_vals[0] = interfacePrivate->entity_device; + match_dict = CFDictionaryCreate(NULL, + (const void **)match_keys, + (const void **)match_vals, + 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + match_keys[0] = CFSTR(kIOProviderClassKey); + match_vals[0] = CFSTR(kIOSerialBSDServiceValue); + 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); + + // note: this "matching" dictionary will be consumed by the call to IOServiceGetMatchingServices + kr = IOServiceGetMatchingServices(masterPort, matching, &device_iterator); + if (kr != kIOReturnSuccess) { + SC_log(LOG_INFO, "IOServiceGetMatchingServices() failed, kr = 0x%x", kr); + goto done; + } + + while ((device_path == NULL) && + ((device = IOIteratorNext(device_iterator)) != MACH_PORT_NULL)) { + CFDictionaryRef overrides; + + overrides = IORegistryEntrySearchCFProperty(device, + kIOServicePlane, + kSCNetworkInterfaceNetworkConfigurationOverridesKey, + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if (overrides != NULL) { + CFDictionaryRef modemOverrides; + + modemOverrides = CFDictionaryGetValue(overrides, kSCEntNetModem); + if (modemOverrides != NULL) { + CFRetain(modemOverrides); + } + CFRelease(overrides); + overrides = modemOverrides; + } + if (overrides == NULL) { + overrides = IORegistryEntrySearchCFProperty(device, + kIOServicePlane, + CFSTR("DeviceModemOverrides"), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + } + if (overrides != NULL) { + if (isA_CFDictionary(overrides)) { + CFStringRef matchIdentifier; + + matchIdentifier = CFDictionaryGetValue(overrides, CFSTR("UniqueIdentifier")); + if (isA_CFString(matchIdentifier) && + CFEqual(interfacePrivate->entity_device_unique, matchIdentifier)) { + device_path = IORegistryEntryCreateCFProperty(device, + CFSTR(kIOTTYDeviceKey), + NULL, + 0); + } + } + CFRelease(overrides); + } + IOObjectRelease(device); + } + + IOObjectRelease(device_iterator); + + done : + + if (device_path == NULL) { + // if we haven't found an exact match to our UniqueIdentifier + // so we simply return the base name. + device_path = SCNetworkInterfaceGetBSDName(interface); + if (device_path != NULL) { + CFRetain(device_path); + } + } + + return device_path; +} + + +#pragma mark - + + +Boolean +_SCNetworkInterfaceIsApplePreconfigured(SCNetworkInterfaceRef interface) +{ +#if TARGET_OS_SIMULATOR +#pragma unused(interface) +#else // TARGET_OS_SIMULATOR + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + if (!_SCNetworkInterfaceIsHiddenConfiguration(interface)) { + // if not HiddenConfiguration + return FALSE; + } + + if ((interfacePrivate->overrides == NULL) || + (!CFDictionaryContainsKey(interfacePrivate->overrides, kSCNetworkProtocolTypeIPv4) && + !CFDictionaryContainsKey(interfacePrivate->overrides, kSCNetworkProtocolTypeIPv6))) { + // if no [IPv4/IPv6] configuration overrides + return FALSE; + } + + if (_SCNetworkInterfaceIsBuiltin(interface)) { + // if built-in (and overrides are present) + return TRUE; + } + + if (_SCNetworkInterfaceIsCarPlay(interface)) { + // if CarPlay (and overrides are present) + return TRUE; + } + + if (isA_CFNumber(interfacePrivate->usb.vid)) { + int vid; + + if (CFNumberGetValue(interfacePrivate->usb.vid, kCFNumberIntType, &vid) && + (vid == kIOUSBVendorIDAppleComputer)) { + // if Apple interface (and overrides are present) + return TRUE; + } + } +#endif // TARGET_OS_SIMULATOR + + return FALSE; +} + + +Boolean +_SCNetworkInterfaceIsBluetoothPAN(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return (interfacePrivate->sort_order == kSortBluetoothPAN_GN); +} + + +Boolean +_SCNetworkInterfaceIsBluetoothPAN_NAP(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return (interfacePrivate->sort_order == kSortBluetoothPAN_NAP); +} + + +Boolean +_SCNetworkInterfaceIsBluetoothP2P(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return (interfacePrivate->sort_order == kSortBluetoothPAN_U); +} + + +Boolean +_SCNetworkInterfaceIsCarPlay(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return (interfacePrivate->sort_order == kSortCarPlay); +} + + +Boolean +_SCNetworkInterfaceIsHiddenConfiguration(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->hidden; +} + + +Boolean +_SCNetworkInterfaceIsTethered(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return (interfacePrivate->sort_order == kSortTethered); +} + + +Boolean +_SCNetworkInterfaceIsThunderbolt(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + CFStringRef interfaceType; + + if (!isA_SCNetworkInterface(interface)) { + return FALSE; + } + + interfaceType = SCNetworkInterfaceGetInterfaceType(interface); + if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) { + CFIndex i; + CFArrayRef members; + CFIndex n; + + members = SCBridgeInterfaceGetMemberInterfaces(interface); + n = (members != NULL) ? CFArrayGetCount(members) : 0; + if (n == 0) { + // if an empty bridge + return FALSE; + } + + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef member; + SCNetworkInterfacePrivateRef memberPrivate; + + member = CFArrayGetValueAtIndex(members, i); + memberPrivate = (SCNetworkInterfacePrivateRef)member; + if (memberPrivate->sort_order != kSortThunderbolt) { + return FALSE; + } + } + + // if Ethernet Bridge interface with only Thunderbolt [IP] members + return TRUE; + } + + return (interfacePrivate->sort_order == kSortThunderbolt); +} + + +#pragma mark - + + +CFDictionaryRef +SCNetworkInterfaceGetQoSMarkingPolicy(SCNetworkInterfaceRef interface) +{ + CFDictionaryRef policy; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + policy = __SCNetworkInterfaceGetConfiguration(interface, kSCEntNetQoSMarkingPolicy); + if (policy == NULL) { + _SCErrorSet(kSCStatusOK); + } + + return policy; +} + +Boolean +SCNetworkInterfaceSetQoSMarkingPolicy(SCNetworkInterfaceRef interface, CFDictionaryRef policy) +{ + Boolean ok; + + if (!isA_SCNetworkInterface(interface)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + ok = __SCNetworkInterfaceSetConfiguration(interface, kSCEntNetQoSMarkingPolicy, policy, FALSE); + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkInterfaceSetQoSMarkingPolicy(): %@ -> %@", + interface, + policy != NULL ? policy : (CFDictionaryRef)CFSTR("NULL")); + } + + return ok; +} + + +#pragma mark - +#pragma mark SCNetworkInterface [internal] SPIs + + +__private_extern__ +SCNetworkInterfacePrivateRef +__SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator, + SCNetworkInterfaceRef interface, + SCPreferencesRef prefs, + CFStringRef serviceID) +{ +#pragma unused(allocator) + SCNetworkInterfacePrivateRef oldPrivate = (SCNetworkInterfacePrivateRef)interface; + SCNetworkInterfacePrivateRef newPrivate; + + /* initialize runtime (and kSCNetworkInterfaceIPv4) */ + pthread_once(&initialized, __SCNetworkInterfaceInitialize); + + if (interface == kSCNetworkInterfaceIPv4) { + return (SCNetworkInterfacePrivateRef)CFRetain(interface); + } + + newPrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, prefs, serviceID); + newPrivate->interface_type = oldPrivate->interface_type; + if (oldPrivate->interface != NULL) { + newPrivate->interface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL, // allocator + oldPrivate->interface, // interface + prefs, // [new] prefs + serviceID); // [new] serviceID + } + if (oldPrivate->name != NULL) { + newPrivate->name = CFRetain(oldPrivate->name); + } + if (oldPrivate->prefix != NULL) { + newPrivate->prefix = CFRetain(oldPrivate->prefix); + } + if (oldPrivate->localized_name != NULL) { + newPrivate->localized_name = CFRetain(oldPrivate->localized_name); + } + newPrivate->localized_key = oldPrivate->localized_key; + if (oldPrivate->localized_arg1 != NULL) { + newPrivate->localized_arg1 = CFRetain(oldPrivate->localized_arg1); + } + if (oldPrivate->localized_arg2 != NULL) { + newPrivate->localized_arg2 = CFRetain(oldPrivate->localized_arg2); + } + if (oldPrivate->unsaved != NULL) { + newPrivate->unsaved = CFDictionaryCreateMutableCopy(NULL, 0, oldPrivate->unsaved); + } + if (oldPrivate->entity_device != NULL) { + newPrivate->entity_device = CFRetain(oldPrivate->entity_device); + } + if (oldPrivate->entity_device_unique != NULL) { + newPrivate->entity_device_unique = CFRetain(oldPrivate->entity_device_unique); + } + newPrivate->entity_type = oldPrivate->entity_type; + newPrivate->entity_subtype = oldPrivate->entity_subtype; + if (oldPrivate->supported_interface_types != NULL) { + newPrivate->supported_interface_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_interface_types); + } + if (oldPrivate->supported_protocol_types != NULL) { + newPrivate->supported_protocol_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_protocol_types); + } + if (oldPrivate->address != NULL) { + newPrivate->address = CFRetain(oldPrivate->address); + } + newPrivate->builtin = oldPrivate->builtin; + if (oldPrivate->configurationAction != NULL) { + newPrivate->configurationAction = CFRetain(oldPrivate->configurationAction); + } + newPrivate->hidden = oldPrivate->hidden; +#if TARGET_OS_IPHONE + newPrivate->trustRequired = oldPrivate->trustRequired; +#endif // TARGET_OS_IPHONE + if (oldPrivate->location != NULL) { + newPrivate->location = CFRetain(oldPrivate->location); + } + if (oldPrivate->path != NULL) { + newPrivate->path = CFRetain(oldPrivate->path); + } + newPrivate->entryID = oldPrivate->entryID; + if (oldPrivate->overrides != NULL) { + newPrivate->overrides = CFDictionaryCreateMutableCopy(NULL, 0, oldPrivate->overrides); + } + if (oldPrivate->type != NULL) { + newPrivate->type = CFRetain(oldPrivate->type); + } + if (oldPrivate->unit != NULL) { + newPrivate->unit = CFRetain(oldPrivate->unit); + } + if (oldPrivate->family != NULL) { + newPrivate->family = CFRetain(oldPrivate->family); + } + if (oldPrivate->subfamily != NULL) { + newPrivate->subfamily = CFRetain(oldPrivate->subfamily); + } + if (oldPrivate->usb.name != NULL) { + newPrivate->usb.name = CFRetain(oldPrivate->usb.name); + } + if (oldPrivate->usb.vid != NULL) { + newPrivate->usb.vid = CFRetain(oldPrivate->usb.vid); + } + if (oldPrivate->usb.pid != NULL) { + newPrivate->usb.pid = CFRetain(oldPrivate->usb.pid); + } + newPrivate->sort_order = oldPrivate->sort_order; + + newPrivate->supportsBond = oldPrivate->supportsBond; + if (oldPrivate->bond.interfaces != NULL) { + newPrivate->bond.interfaces = CFRetain(oldPrivate->bond.interfaces); + } + if (oldPrivate->bond.mode != NULL) { + newPrivate->bond.mode = CFRetain(oldPrivate->bond.mode); + } + if (oldPrivate->bond.options != NULL) { + newPrivate->bond.options = CFRetain(oldPrivate->bond.options); + } + + newPrivate->supportsBridge = oldPrivate->supportsBridge; + if (oldPrivate->bridge.interfaces != NULL) { + newPrivate->bridge.interfaces = CFRetain(oldPrivate->bridge.interfaces); + } + if (oldPrivate->bridge.options != NULL) { + newPrivate->bridge.options = CFRetain(oldPrivate->bridge.options); + } + + newPrivate->supportsVLAN = oldPrivate->supportsVLAN; + if (oldPrivate->vlan.interface != NULL) { + newPrivate->vlan.interface = CFRetain(oldPrivate->vlan.interface); + } + if (oldPrivate->vlan.tag != NULL) { + newPrivate->vlan.tag = CFRetain(oldPrivate->vlan.tag); + } + if (oldPrivate->vlan.options != NULL) { + newPrivate->vlan.options = CFRetain(oldPrivate->vlan.options); + } + + return newPrivate; +} + + +__private_extern__ +CFArrayRef +__SCNetworkInterfaceCopyDeepConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface) +{ + CFMutableArrayRef configs; + + configs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + while (interface != NULL) { + CFStringRef defaultType; + CFMutableDictionaryRef interfaceConfiguration; + + interfaceConfiguration = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface); + if (defaultType != NULL) { + CFDictionaryRef config; + CFArrayRef extendedTypes; + + if (set == NULL) { + config = __SCNetworkInterfaceGetConfiguration(interface, defaultType); + } else { + config = __SCNetworkInterfaceGetDefaultConfiguration(set, interface); + } + if (config == NULL) { + config = (CFDictionaryRef)kCFNull; + } + CFDictionarySetValue(interfaceConfiguration, defaultType, config); + + extendedTypes = extendedConfigurationTypes(interface); + if (extendedTypes != NULL) { + CFIndex i; + CFIndex n; + + n = CFArrayGetCount(extendedTypes); + for (i = 0; i < n; i++) { + CFStringRef extendedType; + + extendedType = CFArrayGetValueAtIndex(extendedTypes, i); + config = __SCNetworkInterfaceGetConfiguration(interface, extendedType); + if (config == NULL) { + config = (CFDictionaryRef)kCFNull; + } + CFDictionarySetValue(interfaceConfiguration, extendedType, config); + } + + CFRelease(extendedTypes); + } + } - return (SCNetworkInterfaceRef)parentPrivate; + CFArrayAppendValue(configs, interfaceConfiguration); + CFRelease(interfaceConfiguration); - fail : + interface = SCNetworkInterfaceGetInterface(interface); + } - CFRelease(parentPrivate); - _SCErrorSet(kSCStatusInvalidArgument); - return NULL; + return configs; } -static CFDictionaryRef -__SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface, Boolean okToHold) +__private_extern__ Boolean +__SCNetworkInterfaceIsMember(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) { - CFDictionaryRef config = NULL; - SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; - CFArrayRef paths; + CFArrayRef interfaces; + Boolean match = FALSE; + CFMutableSetRef members; - /* initialize runtime (and kSCNetworkInterfaceIPv4) */ - pthread_once(&initialized, __SCNetworkInterfaceInitialize); + members = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); - paths = copyConfigurationPaths(interfacePrivate); - if (paths != NULL) { - CFStringRef path; - SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service; +#if !TARGET_OS_IPHONE + // add Bond [member] interfaces + interfaces = SCBondInterfaceCopyAll(prefs); + if (interfaces != NULL) { + __SCBondInterfaceListCollectMembers(interfaces, members); + CFRelease(interfaces); + } +#endif // !TARGET_OS_IPHONE - path = CFArrayGetValueAtIndex(paths, 0); - config = __getPrefsConfiguration(servicePrivate->prefs, path); + // add Bridge [member] interfaces + interfaces = SCBridgeInterfaceCopyAll(prefs); + if (interfaces != NULL) { + __SCBridgeInterfaceListCollectMembers(interfaces, members); + CFRelease(interfaces); + } - CFRelease(paths); - } else if (okToHold) { - config = interfacePrivate->unsaved; + if (CFSetGetCount(members) == 0) { + goto done; } - return config; -} + while (interface != NULL) { + match = CFSetContainsValue(members, interface); + if (match) { + // if the interface is a member of an + // Ethernet Bond or Bridge + break; + } + interface = SCNetworkInterfaceGetInterface(interface); + } -CFDictionaryRef -SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface) -{ - return __SCNetworkInterfaceGetConfiguration(interface, FALSE); + done : + + CFRelease(members); + return match; } -CFStringRef -SCNetworkInterfaceGetBSDName(SCNetworkInterfaceRef interface) +__private_extern__ +void +__SCNetworkInterfaceSetDeepConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface, CFArrayRef configs) { - SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; - - if (interfacePrivate->interface != NULL) { - return NULL; - } + CFIndex i; - return interfacePrivate->entity_device; -} + for (i = 0; interface != NULL; i++) { + CFStringRef defaultType; + CFDictionaryRef interfaceConfiguration; + Boolean ok; + interfaceConfiguration = (configs != NULL) ? CFArrayGetValueAtIndex(configs, i) : NULL; -CFStringRef -SCNetworkInterfaceGetHardwareAddressString(SCNetworkInterfaceRef interface) -{ - SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface); + if (defaultType != NULL) { + CFDictionaryRef config; + CFArrayRef extendedTypes; - return interfacePrivate->address; -} + config = (interfaceConfiguration != NULL) ? CFDictionaryGetValue(interfaceConfiguration, defaultType) + : NULL; + if (config == (CFDictionaryRef)kCFNull) { + config = NULL; + } + if (set == NULL) { + // if service is not associated with the set + ok = __SCNetworkInterfaceSetConfiguration(interface, defaultType, config, TRUE); + } else { + // apply default configuration to this set + ok = __SCNetworkInterfaceSetDefaultConfiguration(set, interface, defaultType, config, TRUE); + } + if (ok) { + SC_log(LOG_DEBUG, "__SCNetworkInterfaceSetDeepConfiguration(): %@, %@ -> %@", + interface, + defaultType, + config != NULL ? config : (CFDictionaryRef)CFSTR("NULL")); + } else { + SC_log(LOG_INFO, "__SCNetworkInterfaceSetDeepConfiguration() failed, interface=%@, type=%@", + interface, + defaultType); + } -SCNetworkInterfaceRef -SCNetworkInterfaceGetInterface(SCNetworkInterfaceRef interface) -{ - SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + extendedTypes = extendedConfigurationTypes(interface); + if (extendedTypes != NULL) { + CFIndex j; + CFIndex n; - return interfacePrivate->interface; -} + n = CFArrayGetCount(extendedTypes); + for (j = 0; j < n; j++) { + CFStringRef extendedType; + extendedType = CFArrayGetValueAtIndex(extendedTypes, j); + config = (interfaceConfiguration != NULL) ? CFDictionaryGetValue(interfaceConfiguration, extendedType) + : NULL; + if (config == (CFDictionaryRef)kCFNull) { + config = NULL; + } + ok = __SCNetworkInterfaceSetConfiguration(interface, extendedType, config, TRUE); + if (ok) { + SC_log(LOG_DEBUG, "__SCNetworkInterfaceSetDeepConfiguration(): %@, %@ -> %@", + interface, + extendedType, + config != NULL ? config : (CFDictionaryRef)CFSTR("NULL")); + } else { + SC_log(LOG_INFO, "__SCNetworkInterfaceSetDeepConfiguration() failed, interface=%@, type=%@", + interface, + extendedType); + } + } -CFStringRef -SCNetworkInterfaceGetInterfaceType(SCNetworkInterfaceRef interface) -{ - SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + CFRelease(extendedTypes); + } + } - /* initialize runtime (and kSCNetworkInterfaceIPv4) */ - pthread_once(&initialized, __SCNetworkInterfaceInitialize); + interface = SCNetworkInterfaceGetInterface(interface); + } - return interfacePrivate->interface_type; + return; } -CFStringRef -SCNetworkInterfaceGetLocalizedDisplayName(SCNetworkInterfaceRef interface) +SCNetworkInterfaceRef +_SCNetworkInterfaceCopyActive(SCDynamicStoreRef store, CFStringRef bsdName) { - SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + SCNetworkInterfaceRef interface; - if (interfacePrivate->localized_name == NULL) { - CFStringRef child = NULL; - CFMutableStringRef local = NULL; + interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeAllVirtualInterfaces); + if (interface == NULL) { + return NULL; + } - pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* initialize runtime */ + if (store != NULL) { + SCNetworkInterfacePrivateRef interfacePrivate = + (SCNetworkInterfacePrivateRef)interface; - if (interfacePrivate->interface != NULL) { - child = SCNetworkInterfaceGetLocalizedDisplayName(interfacePrivate->interface); - } + CFRetain(store); + interfacePrivate->store = store; + } - if (interfacePrivate->localized_key != NULL) { - CFStringRef fmt; + return interface; +} - fmt = CFBundleCopyLocalizedString(bundle, - interfacePrivate->localized_key, - interfacePrivate->localized_key, - NETWORKINTERFACE_LOCALIZATIONS); - if (fmt != NULL) { - local = CFStringCreateMutable(NULL, 0); - CFStringAppendFormat(local, - NULL, - fmt, - interfacePrivate->localized_arg1, - interfacePrivate->localized_arg2); - CFRelease(fmt); - } + +#if !TARGET_OS_SIMULATOR +SCNetworkServicePrimaryRank +SCNetworkInterfaceGetPrimaryRank(SCNetworkInterfaceRef interface) +{ + IPMonitorControlRef control; + SCNetworkInterfacePrivateRef interfacePrivate = + (SCNetworkInterfacePrivateRef)interface; + SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault; + + control = interfacePrivate->IPMonitorControl; + if (control != NULL) { + CFStringRef ifName; + + ifName = SCNetworkInterfaceGetBSDName(interface); + if (ifName != NULL) { + rank = IPMonitorControlGetInterfacePrimaryRank(control, + ifName); + } + else { + _SCErrorSet(kSCStatusInvalidArgument); } + } + return rank; +} - if (local == NULL) { - // create (non-)localized name based on the interface type - local = CFStringCreateMutableCopy(NULL, 0, interfacePrivate->interface_type); +Boolean +SCNetworkInterfaceSetPrimaryRank(SCNetworkInterfaceRef interface, + SCNetworkServicePrimaryRank newRank) +{ + IPMonitorControlRef control; + SCNetworkInterfacePrivateRef interfacePrivate = + (SCNetworkInterfacePrivateRef)interface; + CFStringRef ifName; + + ifName = SCNetworkInterfaceGetBSDName(interface); + if (ifName == NULL) { + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); + } + control = interfacePrivate->IPMonitorControl; + if (control == NULL) { + control = IPMonitorControlCreate(); + if (control == NULL) { + _SCErrorSet(kSCStatusFailed); + return (FALSE); + } + interfacePrivate->IPMonitorControl = control; + } + return IPMonitorControlSetInterfacePrimaryRank(control, + ifName, + newRank); +} - // ... and, if this is a leaf node, the interface device - if ((interfacePrivate->entity_device != NULL) && (child == NULL)) { - CFStringAppendFormat(local, NULL, CFSTR(" (%@)"), interfacePrivate->entity_device); +Boolean +SCNetworkInterfaceGetDisableUntilNeeded(SCNetworkInterfaceRef interface) +{ + Boolean disable_until_needed = FALSE; + CFNumberRef disable_prop = NULL; + CFIndex interfaceIndex; + SCNetworkInterfacePrivateRef interfacePrivate + = (SCNetworkInterfacePrivateRef)interface; + CFArrayRef path_list; + + if (interfacePrivate->prefs == NULL) { + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); + } + interfaceIndex = findPerInterfaceConfiguration(interface); + if (interfaceIndex == kCFNotFound) { + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); + } + path_list = copyPerInterfaceConfigurationPaths(interfacePrivate, NULL); + if (path_list != NULL) { + CFDictionaryRef config; + CFStringRef path = CFArrayGetValueAtIndex(path_list, 0); + + config = __getPrefsConfiguration(interfacePrivate->prefs, path); + CFRelease(path_list); + if (config != NULL) { + int disable = 0; + + disable_prop = CFDictionaryGetValue(config, kSCPropDisableUntilNeeded); + disable_prop = isA_CFNumber(disable_prop); + if (disable_prop != NULL) { + if (CFNumberGetValue(disable_prop, kCFNumberIntType, &disable)) { + disable_until_needed = (disable != 0) ? TRUE : FALSE; + } + else { + /* invalid property, ignore it */ + disable_prop = NULL; + } } } + } + if (disable_prop == NULL) { + disable_until_needed + = _SCNetworkInterfaceIsTethered(interface); + } + _SCErrorSet(kSCStatusOK); + return (disable_until_needed); +} - if (child == NULL) { - // no child, show just this interfaces localized name - interfacePrivate->localized_name = CFStringCreateCopy(NULL, local); +Boolean +__SCNetworkInterfaceSetDisableUntilNeededValue(SCNetworkInterfaceRef interface, CFTypeRef disable) +{ + CFIndex count; + CFIndex i; + CFIndex interfaceIndex; + SCNetworkInterfacePrivateRef interfacePrivate + = (SCNetworkInterfacePrivateRef)interface; + Boolean ok = TRUE; + CFArrayRef path_list; + + if (interfacePrivate->prefs == NULL) { + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); + } + if ((disable != NULL) && !isA_CFNumber(disable)) { + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); + } + interfaceIndex = findPerInterfaceConfiguration(interface); + if (interfaceIndex == kCFNotFound) { + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); + } + path_list = copyPerInterfaceConfigurationPaths(interfacePrivate, NULL); + if (path_list == NULL) { + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); + } + count = CFArrayGetCount(path_list); + for (i = 0; i < count; i++) { + CFDictionaryRef config; + CFMutableDictionaryRef new_config; + CFStringRef path = CFArrayGetValueAtIndex(path_list, i); + + config = __getPrefsConfiguration(interfacePrivate->prefs, path); + if (config != NULL) { + new_config + = CFDictionaryCreateMutableCopy(NULL, 0, config); + } else { + new_config + = CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + if (disable != NULL) { + CFDictionarySetValue(new_config, kSCPropDisableUntilNeeded, disable); } else { - // show localized interface name layered over child - interfacePrivate->localized_name = CFStringCreateWithFormat(NULL, - NULL, - CFSTR("%@ --> %@"), - local, - child); + CFDictionaryRemoveValue(new_config, kSCPropDisableUntilNeeded); + } + ok = __setPrefsConfiguration(interfacePrivate->prefs, + path, + (CFDictionaryGetCount(new_config) > 0) ? new_config : NULL, + FALSE); + CFRelease(new_config); + if (!ok) { + break; } - CFRelease(local); } + CFRelease(path_list); + return (ok); +} - return interfacePrivate->localized_name; +Boolean +SCNetworkInterfaceSetDisableUntilNeeded(SCNetworkInterfaceRef interface, Boolean disable) +{ + Boolean ok; + const int one = 1; + CFNumberRef num; + const int zero = 0; + + num = CFNumberCreate(NULL, kCFNumberIntType, disable ? &one : &zero); + ok = __SCNetworkInterfaceSetDisableUntilNeededValue(interface, num); + CFRelease(num); + + return ok; } +#else // !TARGET_OS_SIMULATOR -CFTypeID -SCNetworkInterfaceGetTypeID(void) +SCNetworkServicePrimaryRank +SCNetworkInterfaceGetPrimaryRank(SCNetworkInterfaceRef interface) { - pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* initialize runtime */ - return __kSCNetworkInterfaceTypeID; +#pragma unused(interface) + return (kSCNetworkServicePrimaryRankDefault); } +Boolean +SCNetworkInterfaceSetPrimaryRank(SCNetworkInterfaceRef interface, + SCNetworkServicePrimaryRank newRank) +{ +#pragma unused(interface) +#pragma unused(newRank) + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); +} -__private_extern__ Boolean -__SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config, Boolean okToHold) +Boolean +SCNetworkInterfaceGetDisableUntilNeeded(SCNetworkInterfaceRef interface) { - SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; - Boolean ok = FALSE; - CFArrayRef paths; +#pragma unused(interface) + return (FALSE); +} - /* initialize runtime (and kSCNetworkInterfaceIPv4) */ +Boolean +__SCNetworkInterfaceSetDisableUntilNeededValue(SCNetworkInterfaceRef interface, CFTypeRef disable) +{ +#pragma unused(interface) +#pragma unused(disable) + return (FALSE); +} + +Boolean +SCNetworkInterfaceSetDisableUntilNeeded(SCNetworkInterfaceRef interface, Boolean disable) +{ +#pragma unused(interface) +#pragma unused(disable) + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); +} + +#endif // !TARGET_OS_SIMULATOR + + +__private_extern__ +CFArrayRef // SCNetworkInterfaceRef +__SCNetworkInterfaceCopyStoredWithPreferences(SCPreferencesRef ni_prefs) +{ + CFStringRef defaultNetworkInterfacePath = NULL; + CFArrayRef if_list; + CFMutableArrayRef interfaceList = NULL; + SCNetworkInterfaceRef interfaceNamer = NULL; + + /* initialize runtime */ pthread_once(&initialized, __SCNetworkInterfaceInitialize); - paths = copyConfigurationPaths(interfacePrivate); - if (paths != NULL) { - CFIndex i; - CFIndex n; - SCPreferencesRef prefs; - SCNetworkServicePrivateRef servicePrivate; + if (ni_prefs == NULL) { + defaultNetworkInterfacePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), PREFS_DEFAULT_DIR, NETWORK_INTERFACES_PREFS); + assert(defaultNetworkInterfacePath != NULL); + ni_prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterface"), defaultNetworkInterfacePath); + } - servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service; - prefs = servicePrivate->prefs; + if_list = SCPreferencesGetValue(ni_prefs, INTERFACES); + if (isA_CFArray(if_list)) { + CFIndex i; + CFIndex n = CFArrayGetCount(if_list); - n = CFArrayGetCount(paths); + interfaceList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); for (i = 0; i < n; i++) { - CFStringRef path; + CFDictionaryRef dict; - path = CFArrayGetValueAtIndex(paths, i); - ok = __setPrefsConfiguration(prefs, path, config, FALSE); - if (!ok) { - break; + dict = CFArrayGetValueAtIndex(if_list, i); + if (isA_CFDictionary(dict) != NULL) { + interfaceNamer = __SCNetworkInterfaceCreateWithStorageEntity(NULL, dict); + + if (interfaceNamer != NULL) { + CFArrayAppendValue(interfaceList, interfaceNamer); + CFRelease(interfaceNamer); + } } } - - CFRelease(paths); - } else if (okToHold) { - interfacePrivate->unsaved = config; - ok = TRUE; - } else { - _SCErrorSet(kSCStatusNoKey); } - return ok; + if (defaultNetworkInterfacePath != NULL) { + CFRelease(defaultNetworkInterfacePath); + // prefs were created in the function, and hence need to be released + CFRelease(ni_prefs); + } + return interfaceList; } +__private_extern__ Boolean -SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config) +__SCNetworkInterfaceSaveStoredWithPreferences(SCPreferencesRef prefs, CFArrayRef interfacesToSave) { - return __SCNetworkInterfaceSetConfiguration(interface, config, FALSE); -} + CFStringRef defaultNetworkInterfacePath = NULL; + Boolean success = FALSE; + if (prefs == NULL) { // TODO: Get the default preferences on the system + defaultNetworkInterfacePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), PREFS_DEFAULT_DIR, NETWORK_INTERFACES_PREFS); + assert(defaultNetworkInterfacePath != NULL); + prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterface"), defaultNetworkInterfacePath); + } -/* ---------- SCNetworkInterface internal SPIs ---------- */ + if (isA_CFArray(interfacesToSave) == NULL) { + SC_log(LOG_INFO, "No interfaces to save"); + goto done; + } + SCPreferencesSetValue(prefs, INTERFACES, interfacesToSave); + success = TRUE; +done: + if (defaultNetworkInterfacePath != NULL) { + CFRelease(defaultNetworkInterfacePath); + // prefs were created in the function, and hence need to be released + CFRelease(prefs); + } + return success; +} -__private_extern__ SCNetworkInterfacePrivateRef -__SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator, - SCNetworkInterfaceRef interface, - SCNetworkServiceRef service) +__private_extern__ +SCNetworkInterfaceRef +__SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(CFAllocatorRef allocator, SCPreferencesRef ni_prefs, CFStringRef bsdName) { - SCNetworkInterfacePrivateRef oldPrivate = (SCNetworkInterfacePrivateRef)interface; - SCNetworkInterfacePrivateRef newPrivate; + CFArrayRef if_list; + SCNetworkInterfaceRef interface = NULL; + CFStringRef defaultNetworkInterfacePath; - newPrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); - newPrivate->interface_type = CFRetain(oldPrivate->interface_type); - if (oldPrivate->interface != NULL) { - newPrivate->interface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL, // allocator - oldPrivate->interface, // interface - service); // [new] service - } - newPrivate->localized_name = (oldPrivate->localized_name != NULL) ? CFRetain(oldPrivate->localized_name) : NULL; - newPrivate->service = service; - newPrivate->unsaved = (oldPrivate->unsaved != NULL) ? CFRetain(oldPrivate->unsaved) : NULL; - newPrivate->entity_device = (oldPrivate->entity_device != NULL) ? CFRetain(oldPrivate->entity_device) : NULL; - newPrivate->entity_hardware = CFRetain(oldPrivate->entity_hardware); - newPrivate->entity_type = oldPrivate->entity_type; - newPrivate->entity_subtype = oldPrivate->entity_subtype; - if (oldPrivate->supported_interface_types != NULL) { - newPrivate->supported_interface_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_interface_types); + /* initialize runtime */ + pthread_once(&initialized, __SCNetworkInterfaceInitialize); + + if (ni_prefs == NULL) { + defaultNetworkInterfacePath = CFStringCreateWithFormat(allocator, NULL, CFSTR("%@/%@"), PREFS_DEFAULT_DIR, NETWORK_INTERFACES_PREFS); + ni_prefs = SCPreferencesCreate(allocator, CFSTR("SCNetworkInterface"), defaultNetworkInterfacePath); + CFRelease(defaultNetworkInterfacePath); } - if (oldPrivate->supported_protocol_types != NULL) { - newPrivate->supported_protocol_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_protocol_types); + else { + CFRetain(ni_prefs); } - newPrivate->address = (oldPrivate->address != NULL) ? CFRetain(oldPrivate->address) : NULL; - newPrivate->builtin = oldPrivate->builtin; - newPrivate->path = (oldPrivate->path != NULL) ? CFRetain(oldPrivate->path) : NULL; - newPrivate->location = (oldPrivate->location != NULL) ? CFRetain(oldPrivate->location) : NULL; - newPrivate->supportsDeviceOnHold = oldPrivate->supportsDeviceOnHold; - newPrivate->supportsBond = oldPrivate->supportsBond; - newPrivate->supportsVLAN = oldPrivate->supportsVLAN; - newPrivate->sort_order = oldPrivate->sort_order; - return newPrivate; -} + if_list = SCPreferencesGetValue(ni_prefs, INTERFACES); + if (isA_CFArray(if_list) != NULL) { + CFIndex idx; + CFIndex count = CFArrayGetCount(if_list); -__private_extern__ CFArrayRef -__SCNetworkInterfaceCopyDeepConfiguration(SCNetworkInterfaceRef interface) -{ - CFDictionaryRef config; - CFMutableArrayRef configs; + for (idx = 0; idx < count; idx++) { + CFDictionaryRef dict; + CFStringRef tmp_bsdName; - configs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + dict = CFArrayGetValueAtIndex(if_list, idx); + if (isA_CFDictionary(dict) == NULL) { + continue; + } - while (interface != NULL) { - config = __SCNetworkInterfaceGetConfiguration(interface, TRUE); - CFArrayAppendValue(configs, - (config != NULL) ? config : (CFDictionaryRef)kCFNull); - interface = SCNetworkInterfaceGetInterface(interface); + tmp_bsdName = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceBSDName)); + if (tmp_bsdName == NULL) { + continue; + } + if (CFEqual(bsdName, tmp_bsdName)) { + interface = __SCNetworkInterfaceCreateWithStorageEntity(allocator, dict); + break; + } + } } - return configs; + CFRelease(ni_prefs); + return interface; } - -__private_extern__ void -__SCNetworkInterfaceSetDeepConfiguration(SCNetworkInterfaceRef interface, CFArrayRef configs) +__private_extern__ +CFDictionaryRef +__SCNetworkInterfaceCreateMappingUsingBSDName(CFArrayRef interfaces) { - CFIndex i; + CFMutableDictionaryRef mappingBSDToInterface = NULL; + CFStringRef bsdName = NULL; + SCNetworkInterfaceRef interface = NULL; + CFIndex count; + + count = CFArrayGetCount(interfaces); + if (count == 0) { + SC_log(LOG_INFO, "No interfaces"); + return NULL; + } + mappingBSDToInterface = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - for (i = 0; interface != NULL; i++) { - CFDictionaryRef config; + for (CFIndex idx = 0; idx < count; idx++) { + interface = (SCNetworkInterfaceRef) CFArrayGetValueAtIndex(interfaces, idx); - config = (configs != NULL) ? CFArrayGetValueAtIndex(configs, i) : NULL; - if (!isA_CFDictionary(config) || (CFDictionaryGetCount(config) == 0)) { - config = NULL; + bsdName = SCNetworkInterfaceGetBSDName(interface); + if (isA_CFString(bsdName) == NULL) { + SC_log(LOG_INFO, "No BSD name"); + continue; } + CFDictionaryAddValue(mappingBSDToInterface, bsdName, interface); + } + if (CFDictionaryGetCount(mappingBSDToInterface) == 0) { + CFRelease(mappingBSDToInterface); + mappingBSDToInterface = NULL; + SC_log(LOG_INFO, "No mappings"); + } - (void) __SCNetworkInterfaceSetConfiguration(interface, config, TRUE); - interface = SCNetworkInterfaceGetInterface(interface); + return mappingBSDToInterface; +} + +__private_extern__ Boolean +__SCNetworkInterfaceEntityIsPPTP(CFDictionaryRef entity) +{ + CFStringRef intfSubtype; + + if (entity == NULL) { + return FALSE; } - return; + intfSubtype = CFDictionaryGetValue(entity, kSCPropNetInterfaceSubType); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated" + if (intfSubtype != NULL && CFEqual(intfSubtype, kSCValNetInterfaceSubTypePPTP)) { + return TRUE; + } +#pragma GCC diagnostic pop + + return FALSE; }