X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/a40a14f8bcc57d8bed0203ddee43e8d64db39796..d94708881e41bd90afd74b1a1dd0524d039ba3f7:/SystemConfiguration.fproj/SCNetworkInterface.c?ds=sidebyside diff --git a/SystemConfiguration.fproj/SCNetworkInterface.c b/SystemConfiguration.fproj/SCNetworkInterface.c index 4424aaa..32c6c61 100644 --- a/SystemConfiguration.fproj/SCNetworkInterface.c +++ b/SystemConfiguration.fproj/SCNetworkInterface.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2004-2009 Apple 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@ */ @@ -33,16 +33,13 @@ */ -#include #include #include #include -#include #include "SCNetworkConfigurationInternal.h" -#include -#include #include "SCPreferencesInternal.h" #include "SCHelper_client.h" +#include "plugin_shared.h" #if !TARGET_OS_IPHONE #include @@ -63,41 +60,63 @@ #include // for kIOEthernetInterfaceClass #include #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 + +#if TARGET_OS_OSX +#ifndef kUSBSupportsIPhoneOS +#define kUSBSupportsIPhoneOS "SupportsIPhoneOS" +#endif // !kUSBSupportsIPhoneOS +#endif // TARGET_OS_OSX + +#ifndef kIOUserEthernetInterfaceRoleKey +#define kIOUserEthernetInterfaceRoleKey "InterfaceRole" #endif -#ifndef kUSBProductString -#define kUSBProductString "USB Product Name" +#ifndef kIOUSBHostInterfaceClassName +#define kIOUSBHostInterfaceClassName "IOUSBHostInterface" #endif #include +#include #include #include #include +#include #include +#include #include #include #include #include #include #include -#include +#include +/* CrashReporter "Application Specific Information" */ +#include -static CFStringRef copy_interface_string (CFBundleRef bundle, CFStringRef key, Boolean localized); -static CFStringRef __SCNetworkInterfaceCopyDescription (CFTypeRef cf); -static void __SCNetworkInterfaceDeallocate (CFTypeRef cf); -static Boolean __SCNetworkInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2); -static CFHashCode __SCNetworkInterfaceHash (CFTypeRef cf); + +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, @@ -112,75 +131,87 @@ enum { kSortOtherWireless, kSortTethered, kSortWWANEthernet, - kSortBluetoothPAN, -#if !TARGET_OS_IPHONE + kSortBluetoothPAN_GN, + kSortBluetoothPAN_NAP, + kSortBluetoothPAN_U, + kSortThunderbolt, + kSortCarPlay, kSortBond, + kSortBridge, kSortVLAN, -#endif // !TARGET_OS_IPHONE 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"); -#if !TARGET_OS_IPHONE const CFStringRef kSCNetworkInterfaceTypeBond = CFSTR("Bond"); -#endif // !TARGET_OS_IPHONE +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"); -#if !TARGET_OS_IPHONE const CFStringRef kSCNetworkInterfaceTypeVLAN = CFSTR("VLAN"); -#endif // !TARGET_OS_IPHONE +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, // name - NULL, // localized name - NULL, // localization key - NULL, // localization arg1 - NULL, // localization arg2 - NULL, // [layered] interface - NULL, // prefs - NULL, // serviceID - NULL, // unsaved - NULL, // entity_device - NULL, // entity_device_unique - NULL, // entity_type - NULL, // entity_subtype - NULL, // supported_interface_types - NULL, // supported_protocol_types - NULL, // address - NULL, // addressString - FALSE, // builtin - NULL, // configurationAction - NULL, // location - NULL, // path - NULL, // overrides - FALSE, // modemIsV92 - NULL, // type - NULL, // unit - kSortUnknown, // sort_order -#if !TARGET_OS_IPHONE - FALSE, // supportsBond - { NULL, NULL}, // bond { interfaces, options } - FALSE, // supportsVLAN - { NULL, NULL, NULL } // vlan { interface, tag, options } -#endif // !TARGET_OS_IPHONE +static SCNetworkInterfacePrivate __kSCNetworkInterfaceIPv4 = { + .cfBase = INIT_CFRUNTIME_BASE(), // cfBase + .sort_order = kSortUnknown, // sort_order +}; + +const SCNetworkInterfaceRef kSCNetworkInterfaceIPv4 = (SCNetworkInterfaceRef)&__kSCNetworkInterfaceIPv4; + +static SCNetworkInterfacePrivate __kSCNetworkInterfaceLoopback = { + .cfBase = INIT_CFRUNTIME_BASE(), // cfBase + .sort_order = kSortUnknown, // sort_order }; -const SCNetworkInterfaceRef kSCNetworkInterfaceIPv4 = (SCNetworkInterfaceRef)&__kSCNetworkInterfaceIPv4; +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 @@ -194,11 +225,6 @@ const SCNetworkInterfaceRef kSCNetworkInterfaceIPv4 = (SCNetworkInterfaceRef #define doIPSec 1<<4 #define doOverIP do6to4|doL2TP|doPPTP|doIPSec -#if !TARGET_OS_IPHONE -#define doAppleTalk 1<<0 -#else // !TARGET_OS_IPHONE -#define doAppleTalk 0 -#endif // !TARGET_OS_IPHONE #define doDNS 1<<1 #define doIPv4 1<<2 #define doIPv6 1<<3 @@ -217,32 +243,47 @@ static const struct { const CFStringRef *ppp_subtype; uint32_t supported_protocols; } configurations[] = { - // 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 }, -#if !TARGET_OS_IPHONE - { &kSCNetworkInterfaceTypeBond , &kSCEntNetEthernet, TRUE , doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB }, -#endif // !TARGET_OS_IPHONE - { &kSCNetworkInterfaceTypeEthernet , &kSCEntNetEthernet, TRUE , doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB }, - { &kSCNetworkInterfaceTypeFireWire , &kSCEntNetFireWire, TRUE , doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB }, - { &kSCNetworkInterfaceTypeIEEE80211 , &kSCEntNetAirPort , TRUE , doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB }, - { &kSCNetworkInterfaceTypeIPSec , &kSCEntNetIPSec , FALSE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB }, - { &kSCNetworkInterfaceTypeIrDA , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, - { &kSCNetworkInterfaceTypeL2TP , NULL , FALSE, doPPP, &kSCValNetInterfaceSubTypeL2TP, doNone }, - { &kSCNetworkInterfaceTypeModem , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, - { &kSCNetworkInterfaceTypePPP , &kSCEntNetPPP , FALSE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB }, - { &kSCNetworkInterfaceTypePPTP , NULL , FALSE, doPPP, &kSCValNetInterfaceSubTypePPTP, doNone }, - { &kSCNetworkInterfaceTypeSerial , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, -#if !TARGET_OS_IPHONE - { &kSCNetworkInterfaceTypeVLAN , &kSCEntNetEthernet, TRUE , doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB }, -#endif // !TARGET_OS_IPHONE - { &kSCNetworkInterfaceTypeWWAN , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, - // ===================================== ================= ========== =============== ======================================= ========================================= - { &kSCNetworkInterfaceTypeIPv4 , NULL , FALSE, doOverIP, NULL, doNone } + // 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 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; @@ -251,27 +292,33 @@ static CFTypeID __kSCNetworkInterfaceTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __SCNetworkInterfaceClass = { - 0, // version - "SCNetworkInterface", // className - NULL, // init - NULL, // copy - __SCNetworkInterfaceDeallocate, // dealloc - __SCNetworkInterfaceEqual, // equal - __SCNetworkInterfaceHash, // 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 mach_port_t masterPort = MACH_PORT_NULL; - static CFStringRef __SCNetworkInterfaceCopyDescription(CFTypeRef cf) +{ + return __SCNetworkInterfaceCopyFormattingDescription(cf, NULL); +} + +static CFStringRef +__SCNetworkInterfaceCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { CFAllocatorRef allocator = CFGetAllocator(cf); CFMutableStringRef result; @@ -309,37 +356,81 @@ __SCNetworkInterfaceCopyDescription(CFTypeRef cf) CFIndex dataLen; CFIndex i; - CFStringAppendFormat(result, NULL, CFSTR(", address = 0x")); + CFStringAppendFormat(result, NULL, CFSTR(", address = ")); data = CFDataGetBytePtr(interfacePrivate->address); dataLen = CFDataGetLength(interfacePrivate->address); for (i = 0; i < dataLen; i++) { - CFStringAppendFormat(result, NULL, CFSTR("%02x"), data[i]); + CFStringAppendFormat(result, NULL, CFSTR("%s%02x"), + (i > 0) ? ":" : "", + data[i]); } } CFStringAppendFormat(result, NULL, CFSTR(", builtin = %s"), interfacePrivate->builtin ? "TRUE" : "FALSE"); - if (interfacePrivate->modemIsV92) { - CFStringAppendFormat(result, NULL, CFSTR(", v.92")); + 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); } + 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->path != NULL) { - CFStringAppendFormat(result, NULL, CFSTR(", path = %@"), interfacePrivate->path); + 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 (!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) { - CFStringAppendFormat(result, NULL, CFSTR(", overrides = %p"), interfacePrivate->overrides); + CFStringRef str; + + str = _SCCopyDescription(interfacePrivate->overrides, formatOptions); + CFStringAppendFormat(result, formatOptions, CFSTR(", overrides = %@"), str); + CFRelease(str); } - CFStringAppendFormat(result, NULL, CFSTR(", order = %d"), interfacePrivate->sort_order); + 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); } @@ -350,9 +441,9 @@ __SCNetworkInterfaceCopyDescription(CFTypeRef cf) 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 !TARGET_OS_IPHONE + if (interfacePrivate->bond.interfaces != NULL) { CFIndex i; CFIndex n; @@ -364,7 +455,7 @@ __SCNetworkInterfaceCopyDescription(CFTypeRef cf) member = CFArrayGetValueAtIndex(interfacePrivate->bond.interfaces, i); CFStringAppendFormat(result, NULL, CFSTR("%s%@"), - (i == 0) ? ", interfaces = " : ", ", + (i == 0) ? ", interfaces = " : ",", SCNetworkInterfaceGetBSDName(member)); } } @@ -372,11 +463,36 @@ __SCNetworkInterfaceCopyDescription(CFTypeRef cf) CFStringAppendFormat(result, NULL, CFSTR(", mode = %@"), interfacePrivate->bond.mode); } if (interfacePrivate->bond.options != NULL) { - CFStringAppendFormat(result, NULL, CFSTR(", options = %@"), interfacePrivate->bond.options); + CFStringRef str; + + str = _SCCopyDescription(interfacePrivate->bond.options, formatOptions); + CFStringAppendFormat(result, formatOptions, CFSTR(", options = %@"), str); + CFRelease(str); } - if (interfacePrivate->bond.mode != NULL) { - CFStringAppendFormat(result, NULL, CFSTR(", mode = %@"), interfacePrivate->bond.mode); + + 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 = %@"), @@ -386,9 +502,13 @@ __SCNetworkInterfaceCopyDescription(CFTypeRef cf) CFStringAppendFormat(result, NULL, CFSTR(", tag = %@"), interfacePrivate->vlan.tag); } if (interfacePrivate->vlan.options != NULL) { - CFStringAppendFormat(result, NULL, CFSTR(", options = %@"), interfacePrivate->vlan.options); + CFStringRef str; + + str = _SCCopyDescription(interfacePrivate->vlan.options, formatOptions); + CFStringAppendFormat(result, formatOptions, CFSTR(", options = %@"), str); + CFRelease(str); } -#endif // !TARGET_OS_IPHONE + CFStringAppendFormat(result, NULL, CFSTR("}")); return result; @@ -402,9 +522,6 @@ __SCNetworkInterfaceDeallocate(CFTypeRef cf) /* release resources */ - if (interfacePrivate->interface != NULL) - CFRelease(interfacePrivate->interface); - if (interfacePrivate->name != NULL) CFRelease(interfacePrivate->name); @@ -417,9 +534,15 @@ __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); @@ -444,25 +567,42 @@ __SCNetworkInterfaceDeallocate(CFTypeRef cf) 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->configurationAction != NULL) - CFRelease(interfacePrivate->configurationAction); - 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 !TARGET_OS_IPHONE + 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); @@ -472,6 +612,12 @@ __SCNetworkInterfaceDeallocate(CFTypeRef cf) 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); @@ -480,8 +626,10 @@ __SCNetworkInterfaceDeallocate(CFTypeRef cf) if (interfacePrivate->vlan.options != NULL) CFRelease(interfacePrivate->vlan.options); -#endif // !TARGET_OS_IPHONE - +#if !TARGET_OS_SIMULATOR + if (interfacePrivate->IPMonitorControl != NULL) + CFRelease(interfacePrivate->IPMonitorControl); +#endif // !TARGET_OS_SIMULATOR return; } @@ -503,11 +651,21 @@ __SCNetworkInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2) return FALSE; // if not the same device } - if (!_SC_CFEqual(if1->entity_device_unique, if2->entity_device_unique)) { - return FALSE; // if not the same device unique identifier + 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 !TARGET_OS_IPHONE if (CFEqual(if1->interface_type, kSCNetworkInterfaceTypeBond)) { if (!_SC_CFEqual(if1->bond.interfaces, if2->bond.interfaces)) { return FALSE; // if not the same interfaces @@ -517,6 +675,12 @@ __SCNetworkInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2) } } + 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 @@ -525,7 +689,6 @@ __SCNetworkInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2) return FALSE; // if not the same tag } } -#endif // !TARGET_OS_IPHONE if (!_SC_CFEqual(if1->interface, if2->interface)) { return FALSE; // if not the same layering @@ -568,19 +731,24 @@ __SCNetworkInterfaceInitialize(void) __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 = _SC_CFBundleGet(); // get mach port used to communication with IOKit kr = IOMasterPort(MACH_PORT_NULL, &masterPort); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_DEBUG, - CFSTR("__SCNetworkInterfaceInitialize(), could not get IOMasterPort, kr = 0x%x"), - kr); + if (kr != kIOReturnSuccess) { + SC_log(LOG_NOTICE, "could not get IOMasterPort, kr = 0x%x", kr); } return; @@ -592,8 +760,7 @@ SCNetworkInterfacePrivateRef __SCNetworkInterfaceCreatePrivate(CFAllocatorRef allocator, SCNetworkInterfaceRef interface, SCPreferencesRef prefs, - CFStringRef serviceID, - io_string_t path) + CFStringRef serviceID) { SCNetworkInterfacePrivateRef interfacePrivate; uint32_t size; @@ -611,50 +778,16 @@ __SCNetworkInterfaceCreatePrivate(CFAllocatorRef allocator, return NULL; } - interfacePrivate->interface_type = NULL; - interfacePrivate->name = NULL; - interfacePrivate->localized_name = NULL; - interfacePrivate->localized_key = NULL; - interfacePrivate->localized_arg1 = NULL; - interfacePrivate->localized_arg2 = NULL; - interfacePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL; - interfacePrivate->prefs = (prefs != NULL) ? CFRetain(prefs) : NULL; - interfacePrivate->serviceID = (serviceID != NULL) ? CFRetain(serviceID) : NULL; - interfacePrivate->unsaved = NULL; - interfacePrivate->entity_device = NULL; - interfacePrivate->entity_device_unique = NULL; - interfacePrivate->entity_type = NULL; - interfacePrivate->entity_subtype = NULL; - interfacePrivate->supported_interface_types = NULL; - interfacePrivate->supported_protocol_types = NULL; - interfacePrivate->address = NULL; - interfacePrivate->addressString = NULL; - interfacePrivate->builtin = FALSE; - interfacePrivate->configurationAction = NULL; - interfacePrivate->path = (path != NULL) ? CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8) - : NULL; - interfacePrivate->location = NULL; - interfacePrivate->overrides = NULL; - interfacePrivate->modemIsV92 = FALSE; - interfacePrivate->type = NULL; - interfacePrivate->unit = NULL; - interfacePrivate->sort_order = kSortUnknown; -#if !TARGET_OS_IPHONE - interfacePrivate->supportsBond = FALSE; - interfacePrivate->bond.interfaces = NULL; - interfacePrivate->bond.mode = NULL; - interfacePrivate->bond.options = NULL; - interfacePrivate->supportsVLAN = FALSE; - interfacePrivate->vlan.interface = NULL; - interfacePrivate->vlan.tag = NULL; - interfacePrivate->vlan.options = NULL; -#endif // !TARGET_OS_IPHONE + /* 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; } -#if !TARGET_OS_IPHONE __private_extern__ Boolean __SCNetworkInterfaceSupportsVLAN(CFStringRef bsd_if) @@ -686,17 +819,18 @@ __SCNetworkInterfaceSupportsVLAN(CFStringRef bsd_if) mib[5] = if_index; /* ask for exactly one interface */ if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) == -1) { - SCLog(TRUE, LOG_ERR, CFSTR("sysctl() size failed: %s"), strerror(errno)); + 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) { - SCLog(TRUE, LOG_ERR, CFSTR("sysctl() failed: %s"), strerror(errno)); + SC_log(LOG_NOTICE, "sysctl() failed: %s", strerror(errno)); goto done; } // check the link type and hwassist flags - ifm = (struct if_msghdr *)buf; + // 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) @@ -719,6 +853,48 @@ __SCNetworkInterfaceSupportsVLAN(CFStringRef bsd_if) } +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, @@ -726,7 +902,7 @@ _SCBondInterfaceCreatePrivate(CFAllocatorRef allocator, { SCNetworkInterfacePrivateRef interfacePrivate; - interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL, NULL); + interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL); if (interfacePrivate == NULL) { return NULL; } @@ -734,6 +910,7 @@ _SCBondInterfaceCreatePrivate(CFAllocatorRef allocator, 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; @@ -749,6 +926,36 @@ _SCBondInterfaceCreatePrivate(CFAllocatorRef allocator, } +__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, @@ -756,7 +963,7 @@ _SCVLANInterfaceCreatePrivate(CFAllocatorRef allocator, { SCNetworkInterfacePrivateRef interfacePrivate; - interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL, NULL); + interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL); if (interfacePrivate == NULL) { return NULL; } @@ -764,6 +971,7 @@ _SCVLANInterfaceCreatePrivate(CFAllocatorRef allocator, 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; @@ -776,14 +984,13 @@ _SCVLANInterfaceCreatePrivate(CFAllocatorRef allocator, return interfacePrivate; } -#endif // !TARGET_OS_IPHONE #pragma mark - #pragma mark Interface ordering -static CFArrayRef +static CF_RETURNS_RETAINED CFArrayRef split_path(CFStringRef path) { CFArrayRef components; @@ -808,6 +1015,7 @@ split_path(CFStringRef path) CFComparisonResult _SCNetworkInterfaceCompare(const void *val1, const void *val2, void *context) { +#pragma unused(context) SCNetworkInterfacePrivateRef dev1 = (SCNetworkInterfacePrivateRef)val1; SCNetworkInterfacePrivateRef dev2 = (SCNetworkInterfacePrivateRef)val2; CFComparisonResult res = kCFCompareEqualTo; @@ -953,8 +1161,9 @@ _SCNetworkInterfaceCompare(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; } @@ -995,6 +1204,34 @@ IOCopyCFStringValue(CFTypeRef ioVal) } +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) { @@ -1068,7 +1305,14 @@ 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; @@ -1081,8 +1325,6 @@ pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name) slot_name = IORegistryEntryCreateCFProperty(interface, CFSTR("AAPL,slot-name"), NULL, 0); if (slot_name != NULL) { - CFIndex i; - slot = CFStringCreateMutable(NULL, 0); if (isA_CFString(slot_name)) { if (pci_slot_name != NULL) *pci_slot_name = CFStringCreateCopy(NULL, slot_name); @@ -1094,15 +1336,20 @@ pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name) kCFStringEncodingUTF8); } - if (CFStringGetLength(slot) > 5) { - (void) CFStringFindAndReplace(slot, - CFSTR("slot-"), - CFSTR(""), - CFRangeMake(0, 5), - kCFCompareCaseInsensitive|kCFCompareAnchored); + for (size_t i = 0; i < sizeof(slot_prefixes)/sizeof(slot_prefixes[0]); i++) { + CFIndex len; + + len = CFStringGetLength(slot_prefixes[i]); + if (CFStringGetLength(slot) > len) { + (void) CFStringFindAndReplace(slot, + slot_prefixes[i], + CFSTR(""), + CFRangeMake(0, len), + kCFCompareCaseInsensitive|kCFCompareAnchored); + } } - for (i = 0; i < sizeof(slot_mappings)/sizeof(slot_mappings[0]); i++) { + for (size_t i = 0; i < sizeof(slot_mappings)/sizeof(slot_mappings[0]); i++) { if (CFStringCompare(slot, slot_mappings[i].name, kCFCompareCaseInsensitive) == kCFCompareEqualTo) { @@ -1130,7 +1377,7 @@ pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name) if (*pci_slot_name != NULL) CFRelease(*pci_slot_name); *pci_slot_name = parent_pci_slot_name; } else { - CFRelease(parent_pci_slot_name); + if (parent_pci_slot_name != NULL) CFRelease(parent_pci_slot_name); } } @@ -1141,7 +1388,7 @@ pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name) // if we have hit the root node break; default : - SCLog(TRUE, LOG_DEBUG, CFSTR("pci_slot IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr); + SC_log(LOG_INFO, "IORegistryEntryGetParentEntry() failed, kr = 0x%x", kr); break; } @@ -1152,6 +1399,7 @@ pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name) static CFComparisonResult compare_bsdNames(const void *val1, const void *val2, void *context) { +#pragma unused(context) CFStringRef bsd1 = (CFStringRef)val1; CFStringRef bsd2 = (CFStringRef)val2; @@ -1159,8 +1407,8 @@ compare_bsdNames(const void *val1, const void *val2, void *context) } -static CFStringRef -pci_port(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; @@ -1201,7 +1449,7 @@ pci_port(CFTypeRef slot_name, CFStringRef bsdName) kr = IOServiceGetMatchingServices(masterPort, matching, &slot_iterator); if (kr != kIOReturnSuccess) { - SCLog(TRUE, LOG_DEBUG, CFSTR("pci_port IOServiceGetMatchingServices() failed, kr = 0x%x"), kr); + SC_log(LOG_INFO, "IOServiceGetMatchingServices() failed, kr = 0x%x", kr); return MACH_PORT_NULL; } @@ -1216,22 +1464,40 @@ pci_port(CFTypeRef slot_name, CFStringRef bsdName) kIORegistryIterateRecursively, &child_iterator); if (kr != kIOReturnSuccess) { - SCLog(TRUE, LOG_DEBUG, CFSTR("pci_port IORegistryEntryCreateIterator() failed, kr = 0x%x"), 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); @@ -1246,7 +1512,7 @@ pci_port(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); } } @@ -1256,16 +1522,22 @@ pci_port(CFTypeRef slot_name, CFStringRef bsdName) static Boolean -pci_slot_info(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; } @@ -1273,7 +1545,7 @@ pci_slot_info(io_registry_entry_t interface, CFStringRef *slot_name, CFStringRef *slot_name = pci_slot(interface, &pci_slot_name); if (*slot_name != NULL) { if (pci_slot_name != NULL) { - *port_name = pci_port(pci_slot_name, bsd_name); + *port_name = pci_port(pci_slot_name, ift, bsd_name); CFRelease(pci_slot_name); } ok = TRUE; @@ -1313,7 +1585,7 @@ isBluetoothBuiltin(Boolean *haveController) &iter); if ((kr != kIOReturnSuccess) || (iter == MACH_PORT_NULL)) { if (kr != kIOReturnSuccess) { - SCLog(TRUE, LOG_DEBUG, CFSTR("isBluetoothBuiltin IOServiceGetMatchingServices() failed, kr = 0x%x"), kr); + SC_log(LOG_INFO, "IOServiceGetMatchingServices() failed, kr = 0x%x", kr); } *haveController = FALSE; return FALSE; @@ -1323,6 +1595,7 @@ isBluetoothBuiltin(Boolean *haveController) hciController = IOIteratorNext(iter); IOObjectRelease(iter); if(hciController != MACH_PORT_NULL) { +#if !TARGET_OS_SIMULATOR CFNumberRef idVendor; idVendor = IORegistryEntryCreateCFProperty(hciController, CFSTR(kUSBVendorID), NULL, 0); @@ -1337,6 +1610,7 @@ isBluetoothBuiltin(Boolean *haveController) CFRelease(idVendor); } +#endif // !TARGET_OS_SIMULATOR IOObjectRelease(hciController); } @@ -1345,6 +1619,122 @@ isBluetoothBuiltin(Boolean *haveController) } +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; +} + + +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 @@ -1358,29 +1748,61 @@ typedef Boolean (*processInterface)(SCNetworkInterfacePrivateRef interfacePrivat CFDictionaryRef bus_dict); -static Boolean -processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate, - io_registry_entry_t interface, - CFDictionaryRef interface_dict, - io_registry_entry_t controller, - CFDictionaryRef controller_dict, - io_registry_entry_t bus, - CFDictionaryRef bus_dict) +static void +merge_override(SCNetworkInterfacePrivateRef interfacePrivate, + io_registry_entry_t interface, + CFStringRef override) { - CFDataRef data; - int ift = -1; - int iVal; - CFNumberRef num; - CFStringRef str; - CFBooleanRef val; + CFStringRef key; + CFTypeRef val; - // interface type + 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(SCNetworkInterfacePrivateRef interfacePrivate, + io_registry_entry_t interface, + CFDictionaryRef interface_dict, + io_registry_entry_t controller, + CFDictionaryRef controller_dict, + io_registry_entry_t bus, + CFDictionaryRef bus_dict) +{ + CFDataRef data; + int ift = -1; + int iVal; + CFNumberRef num; + CFStringRef str; + CFBooleanRef val; + + // interface type num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceType)); if (isA_CFNumber(num) && CFNumberGetValue(num, kCFNumberIntType, &ift)) { interfacePrivate->type = CFRetain(num); } else { - SCLog(TRUE, LOG_DEBUG, CFSTR("processNetworkInterface() failed, no interface type")); + SC_log(LOG_INFO, "no interface type: %@", interface_dict); return FALSE; } @@ -1388,43 +1810,105 @@ processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate, case IFT_ETHER : // Type, Hardware - if ((IOObjectConformsTo(controller, "IO80211Controller")) || - (IOObjectConformsTo(controller, "AirPortPCI" )) || - (IOObjectConformsTo(controller, "AirPortDriver" ))) { + 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; - } else { - str = IODictionaryCopyCFStringValue(bus_dict, CFSTR("name")); - if ((str != NULL) && CFEqual(str, CFSTR("radio"))) { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; // ?? - interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; - interfacePrivate->sort_order = kSortOtherWireless; - } else { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; - interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; - interfacePrivate->sort_order = kSortEthernet; + 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 !TARGET_OS_IPHONE - // BOND support only enabled for ethernet devices - interfacePrivate->supportsBond = TRUE; -#endif // !TARGET_OS_IPHONE + 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 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 (str != NULL) CFRelease(str); + if (interfacePrivate->interface_type == NULL) { + str = IODictionaryCopyCFStringValue(bus_dict, CFSTR("name")); + if (str != NULL) { + if (CFEqual(str, CFSTR("radio"))) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; // ?? + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortOtherWireless; + } + + CFRelease(str); + } } - // check if WWAN Ethernet - if (IOObjectConformsTo(controller, "AppleUSBEthernetHost")) { - interfacePrivate->sort_order = kSortTethered; - } else if (IOObjectConformsTo(controller, "AppleUSBCDCECMData")) { - interfacePrivate->sort_order = kSortWWANEthernet; + if (interfacePrivate->interface_type == NULL) { + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; + interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; + interfacePrivate->sort_order = kSortEthernet; + + // BOND support only enabled for ethernet devices + interfacePrivate->supportsBond = TRUE; } + // enable Bridge support + interfacePrivate->supportsBridge = TRUE; + // built-in val = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOBuiltin))); if (val == NULL) { @@ -1444,8 +1928,12 @@ processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate, // location interfacePrivate->location = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOLocation)); + if ((interfacePrivate->location != NULL) && + (CFStringGetLength(interfacePrivate->location) == 0)) { + CFRelease(interfacePrivate->location); + interfacePrivate->location = NULL; + } -#if !TARGET_OS_IPHONE // VLAN support num = CFDictionaryGetValue(controller_dict, CFSTR(kIOFeatures)); if (isA_CFNumber(num) && @@ -1454,13 +1942,24 @@ processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate, interfacePrivate->supportsVLAN = TRUE; } } -#endif // !TARGET_OS_IPHONE // localized name if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) { interfacePrivate->localized_key = CFSTR("airport"); - } else if (interfacePrivate->sort_order == kSortBluetoothPAN) { - interfacePrivate->localized_key = CFSTR("bluetooth-pan"); + } else if (interfacePrivate->sort_order == kSortThunderbolt) { + if ((interfacePrivate->location == NULL) || + (CFStringGetLength(interfacePrivate->location) == 0)) { + interfacePrivate->localized_key = CFSTR("thunderbolt"); + } else { + interfacePrivate->localized_key = CFSTR("multithunderbolt"); + interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->location); + } + } 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("")); // ?? @@ -1486,65 +1985,84 @@ processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate, CFStringRef port_name; CFStringRef slot_name; - if (pci_slot_info(interface, &slot_name, &port_name)) { - if (port_name == NULL) { - interfacePrivate->localized_key = CFSTR("pci-ether"); - interfacePrivate->localized_arg1 = slot_name; + // 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 { - interfacePrivate->localized_key = CFSTR("pci-multiether"); - interfacePrivate->localized_arg1 = slot_name; - interfacePrivate->localized_arg2 = port_name; + if (port_name == NULL) { + interfacePrivate->localized_key = CFSTR("pci-ether"); + interfacePrivate->localized_arg1 = slot_name; + } else { + interfacePrivate->localized_key = CFSTR("pci-multiether"); + interfacePrivate->localized_arg1 = slot_name; + interfacePrivate->localized_arg2 = port_name; + } } } - } else if (CFEqual(provider, CFSTR("IOUSBDevice")) || - CFEqual(provider, CFSTR("IOUSBInterface"))) { - // check if a "Product Name" has been provided - val = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR(kIOPropertyProductNameKey), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - if (val == NULL) { - // check if a "USB Product Name" has been provided - val = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR(kUSBProductString), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - } - if (val != NULL) { - CFStringRef productName; - - productName = IOCopyCFStringValue(val); - CFRelease(val); - - if (productName != NULL) { - if (CFStringGetLength(productName) > 0) { - // if 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 = copy_interface_string(bundle, productName, TRUE); + } 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 - CFRelease(productName); + if (node == interface) { + node = controller; + } else if (node == controller ) { + node = bus; + } else { + break; } - } else { - interfacePrivate->localized_key = CFSTR("usb-ether"); - interfacePrivate->localized_arg1 = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey)); + + 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); } } @@ -1566,23 +2084,42 @@ processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate, 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 : - SCLog(TRUE, LOG_DEBUG, CFSTR("processNetworkInterface() failed, unknown interface type = %d"), 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 data = CFDictionaryGetValue(controller_dict, CFSTR(kIOMACAddress)); @@ -1590,6 +2127,12 @@ processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate, 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) && @@ -1597,6 +2140,9 @@ processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate, interfacePrivate->unit = CFRetain(num); } + // configuration [PPP] template override (now deprecated, use NetworkConfigurationOverrides) + merge_override(interfacePrivate, interface, kSCNetworkInterfaceTypePPP); + return TRUE; } @@ -1646,18 +2192,18 @@ set_connection_script(SCNetworkInterfacePrivateRef interfacePrivate, CFStringRef static Boolean is_valid_connection_script(CFStringRef script) { - char ccl[MAXPATHLEN]; - char path[MAXPATHLEN]; - NSSearchPathEnumerationState state; + char ccl[MAXPATHLEN]; + char path[MAXPATHLEN]; + sysdir_search_path_enumeration_state state; (void) _SC_cfstring_to_cstring(script, ccl, sizeof(ccl), kCFStringEncodingUTF8); - state = NSStartSearchPathEnumeration(NSLibraryDirectory, - NSLocalDomainMask|NSSystemDomainMask); - while ((state = NSGetNextSearchPathEnumeration(state, path))) { + 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; @@ -1673,9 +2219,7 @@ is_valid_connection_script(CFStringRef script) goto bundle; } - SCLog(TRUE, LOG_DEBUG, - CFSTR("processSerialInterface stat() failed: %s"), - strerror(errno)); + SC_log(LOG_INFO, "stat() failed: %s", strerror(errno)); continue; } if (S_ISREG(statBuf.st_mode)) { @@ -1697,9 +2241,7 @@ is_valid_connection_script(CFStringRef script) continue; } - SCLog(TRUE, LOG_DEBUG, - CFSTR("processSerialInterface stat() failed: %s"), - strerror(errno)); + SC_log(LOG_INFO, "stat() failed: %s", strerror(errno)); continue; } } @@ -1730,21 +2272,10 @@ processSerialInterface(SCNetworkInterfacePrivateRef interfacePrivate, Boolean ok = FALSE; CFTypeRef val; - // check if hidden - val = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR("HiddenPort"), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - if (val != NULL) { - CFRelease(val); - return FALSE; // if this interface should not be exposed - } - // check if initializing val = IORegistryEntrySearchCFProperty(interface, kIOServicePlane, - CFSTR("Initializing"), + kSCNetworkInterfaceInitializingKey, NULL, kIORegistryIterateRecursively | kIORegistryIterateParents); if (val != NULL) { @@ -1816,22 +2347,6 @@ processSerialInterface(SCNetworkInterfacePrivateRef interfacePrivate, // Modem interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem; interfacePrivate->sort_order = kSortModem; - - // V.92 support - val = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR(kIODeviceSupportsHoldKey), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - if (val != NULL) { - uint32_t v92; - - if (isA_CFNumber(val) && - CFNumberGetValue(val, kCFNumberSInt32Type, &v92)) { - interfacePrivate->modemIsV92 = (v92 == 1); - } - CFRelease(val); - } } // Entity (Type) @@ -1860,41 +2375,17 @@ processSerialInterface(SCNetworkInterfacePrivateRef interfacePrivate, goto done; } - // configuration template overrides - val = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR("DevicePPPOverrides"), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - if (val != NULL) { - if (isA_CFDictionary(val)) { - if (interfacePrivate->overrides == NULL) { - interfacePrivate->overrides = CFDictionaryCreateMutable(NULL, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - } - CFDictionarySetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypePPP, val); - } - CFRelease(val); - } + // configuration [PPP] template override (now deprecated, use NetworkConfigurationOverrides) + merge_override(interfacePrivate, interface, kSCNetworkInterfaceTypePPP); - val = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR("DeviceModemOverrides"), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - if (val != NULL) { - if (isA_CFDictionary(val)) { - CFStringRef uniqueID; + // configuration [Modem] template override (now deprecated, use NetworkConfigurationOverrides) + merge_override(interfacePrivate, interface, kSCNetworkInterfaceTypeModem); - if (interfacePrivate->overrides == NULL) { - interfacePrivate->overrides = CFDictionaryCreateMutable(NULL, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - } - CFDictionarySetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem, val); + // 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); @@ -1908,10 +2399,10 @@ processSerialInterface(SCNetworkInterfacePrivateRef interfacePrivate, interfacePrivate->entity_device_unique = CFStringCreateCopy(NULL, uniqueID); } } - CFRelease(val); } - // if not part of the DeviceModemOverrides, look harder for the modem CCL + // if not part of the NetworkConfigurationOverrides/DeviceModemOverrides, look + // a bit harder for the modem CCL if (modemCCL == NULL) { val = IORegistryEntrySearchCFProperty(interface, kIOServicePlane, @@ -1981,47 +2472,22 @@ processSerialInterface(SCNetworkInterfacePrivateRef interfacePrivate, } if (!isModem || !CFEqual(base, CFSTR("modem"))) { - CFStringRef productName; - - // check if a "Product Name" has been provided - val = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR(kIOPropertyProductNameKey), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - if (val == NULL) { - // check if a "USB Product Name" has been provided - val = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR(kUSBProductString), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - } - if (val != NULL) { - productName = IOCopyCFStringValue(val); - CFRelease(val); - - if (productName != NULL) { - if (CFStringGetLength(productName) > 0) { - // if 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 = copy_interface_string(bundle, productName, TRUE); - - // if not provided, also check if the product name - // matches a CCL script - if ((modemCCL == NULL) && - is_valid_connection_script(productName)) { - set_connection_script(interfacePrivate, productName); - } - } - - CFRelease(productName); + // 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); } } } @@ -2043,64 +2509,187 @@ processSerialInterface(SCNetworkInterfacePrivateRef interfacePrivate, } +static CFStringRef +__SC_IORegistryEntryCopyPath(io_registry_entry_t entry, const io_name_t plane) +{ + /* + * 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; + + 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); + } + } + + return str; +} + +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); + } + } + + return reg_dict; +} + static SCNetworkInterfaceRef -createInterface(io_registry_entry_t interface, processInterface func) +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; - io_string_t path; - - kr = IORegistryEntryGetPath(interface, kIOServicePlane, path); - if (kr != kIOReturnSuccess) { - SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetPath() failed, kr = 0x%x"), kr); - goto done; + 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 + } } - kr = IORegistryEntryCreateCFProperties(interface, &interface_dict, NULL, kNilOptions); - if (kr != kIOReturnSuccess) { - SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() 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 */ + // get the controller node kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &controller); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr); + if (kr != kIOReturnSuccess) { + SC_log(LOG_INFO, "IORegistryEntryGetParentEntry() failed, kr = 0x%x", kr); goto done; } - /* get the dictionary associated with the node */ - kr = IORegistryEntryCreateCFProperties(controller, &controller_dict, NULL, kNilOptions); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr); - goto done; - } + controller_dict = copyIORegistryProperties(controller, + controller_dict_keys, + sizeof(controller_dict_keys)/sizeof(controller_dict_keys[0])); - /* get the bus node */ + // get the bus node kr = IORegistryEntryGetParentEntry(controller, kIOServicePlane, &bus); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr); + if (kr != kIOReturnSuccess) { + SC_log(LOG_INFO, "IORegistryEntryGetParentEntry() failed, kr = 0x%x", kr); goto done; } - /* get the dictionary associated with the node */ - kr = IORegistryEntryCreateCFProperties(bus, &bus_dict, NULL, kNilOptions); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr); + 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, path); + interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); + assert(interfacePrivate != NULL); + interfacePrivate->path = __SC_IORegistryEntryCopyPath(interface, kIOServicePlane); + interfacePrivate->entryID = entryID; - if ((*func)(interfacePrivate, interface, interface_dict, controller, controller_dict, bus, bus_dict)) { - CFTypeRef val; + // 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); + } - /* check user-notification / auto-configuration preferences */ + if ((*func)(interfacePrivate, interface, interface_dict, controller, controller_dict, bus, bus_dict)) { + // get user-notification / auto-configuration preference val = IORegistryEntrySearchCFProperty(interface, kIOServicePlane, kSCNetworkInterfaceConfigurationActionKey, @@ -2112,6 +2701,32 @@ createInterface(io_registry_entry_t interface, processInterface func) } CFRelease(val); } + + // get HiddenConfiguration preference + val = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + kSCNetworkInterfaceHiddenConfigurationKey, + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + if (val != NULL) { + interfacePrivate->hidden = TRUE; + CFRelease(val); + } + +#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; @@ -2131,17 +2746,27 @@ createInterface(io_registry_entry_t interface, processInterface func) } -static CFArrayRef -findMatchingInterfaces(CFDictionaryRef matching, processInterface func) +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); + kr = IOServiceGetMatchingServices(masterPort, matching, &iterator); if (kr != kIOReturnSuccess) { - SCLog(TRUE, LOG_DEBUG, CFSTR("findMatchingInterfaces IOServiceGetMatchingServices() failed, kr = 0x%x"), kr); + SC_log(LOG_INFO, "IOServiceGetMatchingServices() failed, kr = 0x%x", kr); return NULL; } @@ -2150,9 +2775,11 @@ findMatchingInterfaces(CFDictionaryRef matching, processInterface func) while ((interface = IOIteratorNext(iterator)) != MACH_PORT_NULL) { SCNetworkInterfaceRef match; - match = createInterface(interface, func); + match = createInterface(interface, func, hidden_key); if (match != NULL) { - CFArrayAppendValue(interfaces, match); + if (keep_pre_configured || !_SCNetworkInterfaceIsApplePreconfigured(match)) { + CFArrayAppendValue(interfaces, match); + } CFRelease(match); } @@ -2172,9 +2799,7 @@ findMatchingInterfaces(CFDictionaryRef matching, processInterface func) static CFIndex findConfiguration(CFStringRef interface_type) { - CFIndex i; - - for (i = 0; i < sizeof(configurations)/sizeof(configurations[0]); i++) { + for (size_t i = 0; i < sizeof(configurations)/sizeof(configurations[0]); i++) { if (CFEqual(interface_type, *configurations[i].interface_type)) { return i; } @@ -2278,9 +2903,14 @@ __SCNetworkInterfaceIsValidExtendedConfigurationType(SCNetworkInterfaceRef inter /* * ??? - * Do we match specific/known extended configuration types (e.g. EAPOL) - * and ensure that any non-standard extended configuration types be of - * the form com.myCompany.myType? + * 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? * ??? */ @@ -2304,6 +2934,7 @@ typedef struct { static void __addExtendedConfigurationType(const void *key, const void *value, void *context) { +#pragma unused(value) CFStringRef extendedType = (CFStringRef)key; extendedConfigurationRef myContextRef = (extendedConfigurationRef)context; @@ -2325,8 +2956,29 @@ __addExtendedConfigurationType(const void *key, const void *value, void *context } -static CFArrayRef -extendedConfigurationTypes(SCNetworkInterfaceRef interface) +static CFIndex +findPerInterfaceConfiguration(SCNetworkInterfaceRef interface) +{ + CFIndex interfaceIndex; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + 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; @@ -2349,15 +3001,9 @@ extendedConfigurationTypes(SCNetworkInterfaceRef interface) goto done; } - interfaceIndex = findConfiguration(interfacePrivate->interface_type); + interfaceIndex = findPerInterfaceConfiguration(interface); if (interfaceIndex == kCFNotFound) { - // we don't allow per-service extended configurations - goto done; - } - - if (!configurations[interfaceIndex].per_interface_config) { - // known interface type but we still don't allow - // per-service extended configurations + // if no per-interface configuration goto done; } @@ -2418,42 +3064,23 @@ extendedConfigurationTypes(SCNetworkInterfaceRef interface) return myContext.types; } +static CFArrayRef +stringCreateArray(CFStringRef str) +{ + return (CFArrayCreate(NULL, (const void **)&str, 1, &kCFTypeArrayCallBacks)); +} static CFArrayRef -copyConfigurationPaths(SCNetworkInterfacePrivateRef interfacePrivate, - CFStringRef extendedType) +copyPerInterfaceConfigurationPaths(SCNetworkInterfacePrivateRef interfacePrivate, + CFStringRef extendedType) { - CFMutableArrayRef array; + CFMutableArrayRef array = NULL; CFIndex i; - CFIndex interfaceIndex; CFIndex n; CFStringRef path; SCNetworkServiceRef service; CFArrayRef sets; - array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - - 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 - CFArrayAppendValue(array, path); - CFRelease(path); - return array; - } - - if (!configurations[interfaceIndex].per_interface_config) { - // known interface type, per-service configuration preferences - path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator - interfacePrivate->serviceID, // service - extendedType); // entity - CFArrayAppendValue(array, path); - CFRelease(path); - return array; - } - // known interface type, per-interface configuration preferences // // 1. look for all sets which contain the associated service @@ -2481,20 +3108,53 @@ copyConfigurationPaths(SCNetworkInterfacePrivateRef interfacePrivate, SCNetworkSetGetSetID(set), // set interfacePrivate->entity_device, // service extendedType); // entity + if (array == NULL) { + array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } CFArrayAppendValue(array, path); CFRelease(path); } CFRelease(services); } - if (CFArrayGetCount(array) == 0) { - CFRelease(array); - array = NULL; - } - CFRelease(service); if (sets != NULL) CFRelease(sets); return array; + +} + +static CFArrayRef +copyConfigurationPaths(SCNetworkInterfacePrivateRef interfacePrivate, + CFStringRef extendedType) +{ + CFArrayRef array = NULL; + CFIndex interfaceIndex; + CFStringRef path; + + 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); + } + + 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); + } + + else if (interfacePrivate->serviceID != NULL) { + array = copyPerInterfaceConfigurationPaths(interfacePrivate, extendedType); + } + + return (array); } @@ -2534,6 +3194,18 @@ __SCNetworkInterfaceCopyInterfaceEntity(SCNetworkInterfaceRef interface) 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 // match the "hardware" with the lowest layer while (TRUE) { @@ -2571,24 +3243,10 @@ __SCNetworkInterfaceCopyInterfaceEntity(SCNetworkInterfaceRef interface) kSCPropUserDefinedName, SCNetworkInterfaceGetLocalizedDisplayName(interface)); - // note that this is a V.92 capable modem - if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeModem) && - interfacePrivate->modemIsV92) { - int one = 1; - CFNumberRef num; - - num = CFNumberCreate(NULL, kCFNumberIntType, &one); - CFDictionarySetValue(entity, - kSCPropNetInterfaceSupportsModemOnHold, - num); - CFRelease(num); - } - return entity; } -#if !TARGET_OS_IPHONE static SCNetworkInterfaceRef findInterface(CFArrayRef interfaces, CFStringRef match_if) { @@ -2610,7 +3268,7 @@ findInterface(CFArrayRef interfaces, CFStringRef match_if) return NULL; } - +#if !TARGET_OS_IPHONE static SCNetworkInterfaceRef findBondInterface(SCPreferencesRef prefs, CFStringRef ifDevice) { @@ -2629,6 +3287,26 @@ findBondInterface(SCPreferencesRef prefs, CFStringRef ifDevice) } return interface; } +#endif // !TARGET_OS_IPHONE + +static SCNetworkInterfaceRef +findBridgeInterface(SCPreferencesRef prefs, CFStringRef ifDevice) +{ + CFArrayRef bridges; + SCNetworkInterfaceRef interface = NULL; + + if (prefs == NULL) { + return (NULL); + } + + // check if the interface is an bridge + bridges = SCBridgeInterfaceCopyAll(prefs); + if (bridges != NULL) { + interface = findInterface(bridges, ifDevice); + CFRelease(bridges); + } + return interface; +} static SCNetworkInterfaceRef findVLANInterface(SCPreferencesRef prefs, CFStringRef ifDevice) @@ -2648,30 +3326,131 @@ findVLANInterface(SCPreferencesRef prefs, CFStringRef ifDevice) } return interface; } -#endif // !TARGET_OS_IPHONE + + +#define N_QUICK 32 + + +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 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; + } + + 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(dict); + } + + return entity; +} SCNetworkInterfaceRef -_SCNetworkInterfaceCreateWithBSDName(CFAllocatorRef allocator, - CFStringRef bsdName, - UInt32 flags) +_SCNetworkInterfaceCreateWithBSDName(CFAllocatorRef allocator, + CFStringRef bsdName, + UInt32 flags) { - CFMutableDictionaryRef entity; +#pragma unused(allocator) + CFMutableDictionaryRef entity = NULL; + struct ifreq ifr; SCNetworkInterfaceRef interface; - entity = CFDictionaryCreateMutable(NULL, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue(entity, kSCPropNetInterfaceDeviceName, bsdName); + 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); + } + + if ((ifr.ifr_flags & IFF_POINTOPOINT) != 0) { + // if PPP + entity = copy_ppp_entity(bsdName); + } + } + + if (entity == NULL) { + entity = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(entity, kSCPropNetInterfaceDeviceName, bsdName); + } + #if !TARGET_OS_IPHONE if ((flags & kIncludeBondInterfaces) == 0) { CFDictionarySetValue(entity, CFSTR("_NO_BOND_INTERFACES_"), kCFBooleanTrue); } +#endif // !TARGET_OS_IPHONE + + if ((flags & kIncludeBridgeInterfaces) == 0) { + CFDictionarySetValue(entity, CFSTR("_NO_BRIDGE_INTERFACES_"), kCFBooleanTrue); + } + if ((flags & kIncludeVLANInterfaces) == 0) { CFDictionarySetValue(entity, CFSTR("_NO_VLAN_INTERFACES_"), kCFBooleanTrue); } -#endif // !TARGET_OS_IPHONE + interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, NULL); CFRelease(entity); @@ -2679,139 +3458,628 @@ _SCNetworkInterfaceCreateWithBSDName(CFAllocatorRef allocator, } -static void -__SCNetworkInterfaceSetService(SCNetworkInterfaceRef interface, - SCNetworkServiceRef service) +static CFStringRef +_SCNetworkInterfaceCopyPrefixFromBSDName(CFStringRef bsdName) { - SCNetworkInterfacePrivateRef interfacePrivate; - SCNetworkServicePrivateRef servicePrivate; + CFMutableStringRef interfacePrefix = NULL; + UniChar lastChar; + CFIndex length = 0; - interfacePrivate = (SCNetworkInterfacePrivateRef)interface; - if (interfacePrivate->prefs != NULL) { - CFRelease(interfacePrivate->prefs); - interfacePrivate->prefs = NULL; - } - if (interfacePrivate->serviceID != NULL) { - CFRelease(interfacePrivate->serviceID); - interfacePrivate->serviceID = NULL; + if (isA_CFString(bsdName) == NULL) { + SC_log(LOG_DEBUG, "no BSD name"); + goto done; } - servicePrivate = (SCNetworkServicePrivateRef)service; - if (servicePrivate->prefs != NULL) { - interfacePrivate->prefs = CFRetain(servicePrivate->prefs); - } - if (servicePrivate->serviceID != NULL) { - interfacePrivate->serviceID = CFRetain(servicePrivate->serviceID); - } + interfacePrefix = CFStringCreateMutableCopy(NULL, 0, bsdName); + length = CFStringGetLength(interfacePrefix); - return; + 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; } +static void +__SCNetworkInterfaceSetIOInterfacePrefix(SCNetworkInterfaceRef interface, + CFStringRef prefix); + + static Boolean -_SCNetworkInterfaceMatchesName(CFStringRef name, CFStringRef key) +__SCNetworkInterfaceUpdateBSDName(SCNetworkInterfaceRef interface, CFStringRef currentBSDName, CFStringRef newBSDName) { - Boolean match; - CFStringRef str; + Boolean success = FALSE; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; - if (bundle == NULL) { - // if no bundle - return FALSE; + if (isA_SCNetworkInterface(interface) == NULL) { + SC_log(LOG_INFO, "No interface"); + goto done; } - if (!isA_CFString(name)) { - // if no interface "name" - return FALSE; + if (CFEqual(currentBSDName, newBSDName)) { + // if no change + goto done; } - // 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 (interfacePrivate->entity_device != NULL) { + CFRelease(interfacePrivate->entity_device); } + interfacePrivate->entity_device = CFRetain(newBSDName); + success = TRUE; +done: + return success; +} - // 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; - } + +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; - return FALSE; +done: + if (newPath != NULL) { + CFRelease(newPath); + } + return success; } -SCNetworkInterfaceRef -_SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, - CFDictionaryRef interface_entity, - SCNetworkServiceRef service) +static void +__SCNetworkInterfaceSetIOInterfacePrefix (SCNetworkInterfaceRef interface, + CFStringRef prefix) { - SCNetworkInterfacePrivateRef interfacePrivate = NULL; - CFStringRef ifDevice; - CFStringRef ifUnique; - CFStringRef ifSubType; - CFStringRef ifType; - CFArrayRef matching_interfaces = NULL; + SCNetworkInterfacePrivateRef interfacePrivate; - /* initialize runtime (and kSCNetworkInterfaceIPv4) */ - pthread_once(&initialized, __SCNetworkInterfaceInitialize); + if (isA_CFString(prefix) == NULL) { + return; + } - 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 which - * will keep the rest of the configuration APIs happy. - */ - ifType = kSCValNetInterfaceTypeEthernet; + interfacePrivate = (SCNetworkInterfacePrivateRef) interface; + + CFRetain(prefix); + + if (interfacePrivate->prefix != NULL) { + CFRelease(interfacePrivate->prefix); } - if (!isA_CFString(ifType)) { - return NULL; + 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; - ifSubType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceSubType); - if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { - if (!isA_CFString(ifSubType)) { - return NULL; + 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"); + } + else { + __SCNetworkInterfaceSetIOInterfacePrefix(interface, interfaceNamePrefix); + CFRelease(interfaceNamePrefix); + } } } - ifDevice = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceDeviceName); - ifUnique = CFDictionaryGetValue(interface_entity, CFSTR("DeviceUniqueIdentifier")); + if (interfacePrivate->prefix != NULL) { + newBSDName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), interfacePrivate->prefix, unit); + } - if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet) || + // 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; +} + + +__private_extern__ +CFDictionaryRef +__SCNetworkInterfaceCopyStorageEntity(SCNetworkInterfaceRef 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; + } + + bsdName = SCNetworkInterfaceGetBSDName(interface); + if (!isA_CFString(bsdName)) { + goto done; + } + + builtin = interfacePrivate->builtin ? kCFBooleanTrue : kCFBooleanFalse; + interfaceNamePrefix = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface); + if (!isA_CFString(interfaceNamePrefix)) { + goto done; + } + + interfaceType = _SCNetworkInterfaceGetIOInterfaceType(interface); + if (!isA_CFNumber(interfaceType)) { + goto done; + } + + interfaceUnit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); + if (!isA_CFNumber(interfaceUnit)) { + goto done; + } + + 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; +} + + +static void +__SCNetworkInterfaceSetService(SCNetworkInterfaceRef interface, + SCNetworkServiceRef service) +{ + SCNetworkInterfacePrivateRef interfacePrivate; + SCNetworkServicePrivateRef servicePrivate; + + interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + if (interfacePrivate->prefs != NULL) { + CFRelease(interfacePrivate->prefs); + interfacePrivate->prefs = NULL; + } + if (interfacePrivate->serviceID != NULL) { + CFRelease(interfacePrivate->serviceID); + interfacePrivate->serviceID = NULL; + } + + servicePrivate = (SCNetworkServicePrivateRef)service; + if (servicePrivate->prefs != NULL) { + interfacePrivate->prefs = CFRetain(servicePrivate->prefs); + } + if (servicePrivate->serviceID != NULL) { + interfacePrivate->serviceID = CFRetain(servicePrivate->serviceID); + } + + 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 (!isA_CFString(name)) { + // if no interface "name" + return FALSE; + } + + // 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; + } + } + + // 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; + } + } + + 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"); + + 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 { + // 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; + } + + 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 + 1]; + char bsdName[IFNAMSIZ]; CFMutableDictionaryRef matching; if (!isA_CFString(ifDevice)) { return NULL; } - if (_SC_cfstring_to_cstring(ifDevice, bsdName, sizeof(bsdName), kCFStringEncodingASCII) == NULL) { - goto done; - } - - matching = IOBSDNameMatching(masterPort, 0, bsdName); - if (matching == 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; + } - // note: the "matching" dictionary will be consumed by the following - matching_interfaces = findMatchingInterfaces(matching, processNetworkInterface); + 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; @@ -2822,28 +4090,72 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, return NULL; } - match_keys[0] = CFSTR(kIOProviderClassKey); - match_vals[0] = CFSTR(kIOSerialBSDServiceValue); + 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; - match_keys[1] = CFSTR(kIOTTYBaseNameKey); - match_vals[1] = ifDevice; + n = (matching_interfaces != NULL) ? CFArrayGetCount(matching_interfaces) : 0; + if (n > 0) { + CFIndex i; + + for (i = 0; i < n; i++) { + SCNetworkInterfacePrivateRef scanPrivate; - matching = CFDictionaryCreate(NULL, - (const void **)match_keys, - (const void **)match_vals, - sizeof(match_keys)/sizeof(match_keys[0]), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i); + if (scanPrivate->entity_device_unique != NULL) { + useDeviceName = FALSE; + break; + } + } + } - // note: the "matching" dictionary will be consumed by the following - matching_interfaces = findMatchingInterfaces(matching, processSerialInterface); + 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, @@ -2859,6 +4171,13 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, } 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); @@ -2867,6 +4186,7 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, if (matching_interfaces != NULL) { CFIndex n; SCPreferencesRef prefs; + Boolean temp_preferences = FALSE; n = CFArrayGetCount(matching_interfaces); switch (n) { @@ -2884,41 +4204,91 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, if (!CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) { break; } - prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterface"), NULL); + + 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_VLAN_INTERFACES_"))) { - interfacePrivate = (SCNetworkInterfacePrivateRef)findVLANInterface(prefs, ifDevice); - } - if ((interfacePrivate == NULL) - && !CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BOND_INTERFACES_"))) { + if (!CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BOND_INTERFACES_"))) { interfacePrivate = (SCNetworkInterfacePrivateRef)findBondInterface(prefs, ifDevice); } #endif // !TARGET_OS_IPHONE - CFRelease(prefs); + 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 scan; + SCNetworkInterfacePrivateRef scanPrivate; - scan = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i); - if (_SC_CFEqual(ifUnique, scan->entity_device_unique)) { + 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 = scan; + 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) { - SCLog(TRUE, LOG_ERR, CFSTR("_SCNetworkInterfaceCreateWithEntity() failed, more than one interface matches %@"), ifDevice); + SC_log(LOG_NOTICE, "more than one interface matches %@", ifDevice); interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0); } CFRetain(interfacePrivate); @@ -2929,42 +4299,93 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, done : - if (interfacePrivate == NULL) { + if ((interfacePrivate == NULL) || !useSystemInterfaces) { /* * if device not present on this system */ - interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL, NULL); - interfacePrivate->entity_type = ifType; - interfacePrivate->entity_subtype = ifSubType; + 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; - entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware); - if (isA_CFString((entity_hardware)) && - CFEqual(entity_hardware, kSCEntNetAirPort)) { - interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211; - interfacePrivate->sort_order = kSortAirPort; + 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 { - CFStringRef name; + 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; + interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; - name = CFDictionaryGetValue(interface_entity, kSCPropUserDefinedName); - if (_SCNetworkInterfaceMatchesName(name, CFSTR("iPhone"))) { - interfacePrivate->sort_order = kSortTethered; - } else if (_SCNetworkInterfaceMatchesName(name, CFSTR("bluetooth-pan"))) { - interfacePrivate->sort_order = kSortBluetoothPAN; - } else { - interfacePrivate->sort_order = kSortEthernet; + 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)) { + } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP) && (ifSubType != NULL)) { if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE)) { CFStringRef entity_hardware; @@ -2992,26 +4413,69 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, interfacePrivate->sort_order = kSortModem; } } else { + SCNetworkInterfaceRef child; // PPTP, L2TP, ... CFRelease(interfacePrivate); - interfacePrivate = (SCNetworkInterfacePrivateRef)kSCNetworkInterfaceIPv4; - CFRetain(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 - interfacePrivate->interface_type = ifType; + 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 ((interfacePrivate != NULL) && (service != NULL)) { + if (service != NULL) { __SCNetworkInterfaceSetService((SCNetworkInterfaceRef)interfacePrivate, service); + #if !TARGET_OS_IPHONE - // set prefs & serviceID to VLANs and Bonds + // set prefs & serviceID to Bond member interfaces if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBond)) { CFIndex i; CFArrayRef members; @@ -3025,7 +4489,26 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, member = CFArrayGetValueAtIndex(members, i); __SCNetworkInterfaceSetService(member, service); } - } else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeVLAN)) { + } +#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); @@ -3033,7 +4516,6 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, __SCNetworkInterfaceSetService(vlan_physical, service); } } -#endif // !TARGET_OS_IPHONE } if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { @@ -3044,6 +4526,14 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, 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; @@ -3056,15 +4546,19 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, __private_extern__ CFArrayRef -__SCNetworkInterfaceCopyAll_IONetworkInterface(void) +__SCNetworkInterfaceCopyAll_IONetworkInterface(Boolean keep_pre_configured) { CFDictionaryRef matching; CFArrayRef new_interfaces; - // get Ethernet, Firewire, and AirPort interfaces + // get Ethernet, Firewire, Thunderbolt, and AirPort interfaces matching = IOServiceMatching(kIONetworkInterfaceClass); - new_interfaces = findMatchingInterfaces(matching, processNetworkInterface); + new_interfaces = findMatchingInterfaces(matching, + processNetworkInterface, + kSCNetworkInterfaceHiddenInterfaceKey, + keep_pre_configured); + CFRelease(matching); return new_interfaces; } @@ -3091,7 +4585,11 @@ __SCNetworkInterfaceCopyAll_Modem() sizeof(match_keys)/sizeof(match_keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - new_interfaces = findMatchingInterfaces(matching, processSerialInterface); + new_interfaces = findMatchingInterfaces(matching, + processSerialInterface, + kSCNetworkInterfaceHiddenPortKey, + FALSE); + CFRelease(matching); return new_interfaces; } @@ -3118,12 +4616,47 @@ __SCNetworkInterfaceCopyAll_RS232() sizeof(match_keys)/sizeof(match_keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - new_interfaces = findMatchingInterfaces(matching, processSerialInterface); + 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) { @@ -3149,14 +4682,16 @@ add_interfaces(CFMutableArrayRef all_interfaces, CFArrayRef new_interfaces) static void __waitForInterfaces() { - CFStringRef key; + CFStringRef key = NULL; CFArrayRef keys; Boolean ok; - SCDynamicStoreRef store; + SCDynamicStoreRef store = NULL; + + CRSetCrashLogMessage("Waiting for IOKit to quiesce (or timeout)"); store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkInterfaceCopyAll"), NULL, NULL); if (store == NULL) { - return; + goto done; } key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" "InterfaceNamer"), kSCDynamicStoreDomainPlugin); @@ -3164,8 +4699,7 @@ __waitForInterfaces() ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL); CFRelease(keys); if (!ok) { - SCLog(TRUE, LOG_ERR, - CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"), SCErrorString(SCError())); + SC_log(LOG_NOTICE, "SCDynamicStoreSetNotificationKeys() failed: %s", SCErrorString(SCError())); goto done; } @@ -3178,8 +4712,8 @@ __waitForInterfaces() dict = SCDynamicStoreCopyValue(store, key); if (dict != NULL) { if (isA_CFDictionary(dict) && - (CFDictionaryContainsKey(dict, CFSTR("*QUIET*")) || - CFDictionaryContainsKey(dict, CFSTR("*TIMEOUT*")))) { + (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Quiet) || + CFDictionaryContainsKey(dict, kInterfaceNamerKey_Timeout))) { quiet = TRUE; } CFRelease(dict); @@ -3190,8 +4724,7 @@ __waitForInterfaces() ok = SCDynamicStoreNotifyWait(store); if (!ok) { - SCLog(TRUE, LOG_ERR, - CFSTR("SCDynamicStoreNotifyWait() failed: %s"), SCErrorString(SCError())); + SC_log(LOG_NOTICE, "SCDynamicStoreNotifyWait() failed: %s", SCErrorString(SCError())); goto done; } @@ -3203,20 +4736,20 @@ __waitForInterfaces() done : - CFRelease(key); - CFRelease(store); + CRSetCrashLogMessage(NULL); + + if (key != NULL) CFRelease(key); + if (store != NULL) CFRelease(store); return; } CFArrayRef /* of SCNetworkInterfaceRef's */ -SCNetworkInterfaceCopyAll() +_SCNetworkInterfaceCopyAllWithPreferences(SCPreferencesRef prefs) { CFMutableArrayRef all_interfaces; CFArrayRef new_interfaces; -#if !TARGET_OS_IPHONE - SCPreferencesRef prefs; -#endif // !TARGET_OS_IPHONE + Boolean temp_preferences = FALSE; /* initialize runtime */ pthread_once(&initialized, __SCNetworkInterfaceInitialize); @@ -3226,8 +4759,8 @@ SCNetworkInterfaceCopyAll() all_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - // get Ethernet, Firewire, and AirPort interfaces - new_interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(); + // 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); @@ -3247,15 +4780,27 @@ SCNetworkInterfaceCopyAll() CFRelease(new_interfaces); } -#if !TARGET_OS_IPHONE - // get virtual network interfaces (Bond, VLAN) - prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterfaceCopyAll"), NULL); + // 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) { @@ -3263,10 +4808,14 @@ SCNetworkInterfaceCopyAll() CFRelease(new_interfaces); } - CFRelease(prefs); - } +#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); @@ -3274,6 +4823,16 @@ SCNetworkInterfaceCopyAll() } +CFArrayRef /* of SCNetworkInterfaceRef's */ +SCNetworkInterfaceCopyAll() +{ + CFArrayRef all_interfaces; + + all_interfaces = _SCNetworkInterfaceCopyAllWithPreferences(NULL); + return all_interfaces; +} + + CFArrayRef /* of kSCNetworkInterfaceTypeXXX CFStringRef's */ SCNetworkInterfaceGetSupportedInterfaceTypes(SCNetworkInterfaceRef interface) { @@ -3302,13 +4861,18 @@ SCNetworkInterfaceGetSupportedInterfaceTypes(SCNetworkInterfaceRef interface) if (configurations[i].supported_interfaces & doPPP) { CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPP); } - if (configurations[i].supported_interfaces & doPPTP) { - CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPTP); - } 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 : @@ -3336,11 +4900,6 @@ SCNetworkInterfaceGetSupportedProtocolTypes(SCNetworkInterfaceRef interface) if (i != kCFNotFound) { if (configurations[i].supported_protocols != doNone) { interfacePrivate->supported_protocol_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); -#if !TARGET_OS_IPHONE - if (configurations[i].supported_protocols & doAppleTalk) { - CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeAppleTalk); - } -#endif // !TARGET_OS_IPHONE if (configurations[i].supported_protocols & doDNS) { CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeDNS); } @@ -3384,13 +4943,18 @@ SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef i 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, - NULL); + childPrivate->serviceID); if (parentPrivate == NULL) { _SCErrorSet(kSCStatusFailed); return NULL; @@ -3429,6 +4993,8 @@ SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef i 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)) { @@ -3438,6 +5004,7 @@ SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef i 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)) { @@ -3458,10 +5025,62 @@ SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef i 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 - parentPrivate->interface_type = interfaceType; - parentPrivate->entity_type = interfaceType; // interface config goes into a + 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 { @@ -3469,6 +5088,12 @@ SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef i 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); } @@ -3644,6 +5269,26 @@ SCNetworkInterfaceGetExtendedConfiguration(SCNetworkInterfaceRef interface, } +__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) { @@ -3678,7 +5323,7 @@ SCNetworkInterfaceGetHardwareAddressString(SCNetworkInterfaceRef interface) (interfacePrivate->addressString == NULL)) { uint8_t *bp; char *cp; - CFIndex n; + size_t n; char mac[sizeof("xx:xx:xx:xx:xx:xx:xx:xx")]; char *mac_p = mac; @@ -3686,7 +5331,7 @@ SCNetworkInterfaceGetHardwareAddressString(SCNetworkInterfaceRef interface) n = CFDataGetLength(interfacePrivate->address) * 3; if (n > sizeof(mac)) { - mac_p = CFAllocatorAllocate(NULL, 0, n); + mac_p = CFAllocatorAllocate(NULL, n, 0); } for (cp = mac_p; n > 0; n -= 3) { @@ -3730,7 +5375,7 @@ SCNetworkInterfaceGetInterfaceType(SCNetworkInterfaceRef interface) static CFStringRef -copy_interface_string(CFBundleRef bundle, CFStringRef key, Boolean localized) +copy_string_from_bundle(CFBundleRef bundle, CFStringRef key, Boolean localized) { CFStringRef str = NULL; @@ -3750,6 +5395,52 @@ copy_interface_string(CFBundleRef bundle, CFStringRef key, Boolean localized) } +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) { @@ -3764,7 +5455,8 @@ copy_display_name(SCNetworkInterfaceRef interface, Boolean localized, Boolean ol SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; if ((interfacePrivate->interface != NULL) && - (interfacePrivate->interface != kSCNetworkInterfaceIPv4)) { + (interfacePrivate->interface != kSCNetworkInterfaceIPv4) && + !CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeVPN)) { child = interfacePrivate->interface; } @@ -3841,6 +5533,7 @@ copy_display_name(SCNetworkInterfaceRef interface, Boolean localized, Boolean ol } +#if !TARGET_OS_IPHONE __private_extern__ CFStringRef __SCNetworkInterfaceCopyXLocalizedDisplayName(SCNetworkInterfaceRef interface) @@ -3852,24 +5545,64 @@ __SCNetworkInterfaceCopyXLocalizedDisplayName(SCNetworkInterfaceRef interface) return NULL; } - name = copy_display_name(interface, TRUE, TRUE); - return name; + 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 -__SCNetworkInterfaceCopyXNonLocalizedDisplayName(SCNetworkInterfaceRef interface) +__SCNetworkInterfaceGetUserDefinedName(SCNetworkInterfaceRef interface) { - CFStringRef localized_name; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; if (!isA_SCNetworkInterface(interface)) { - _SCErrorSet(kSCStatusInvalidArgument); return NULL; } - localized_name = copy_display_name(interface, FALSE, TRUE); - return localized_name; + return interfacePrivate->name; } @@ -3911,14 +5644,14 @@ SCNetworkInterfaceGetLocalizedDisplayName(SCNetworkInterfaceRef interface) __private_extern__ -CFDictionaryRef -__SCNetworkInterfaceGetTemplateOverrides(SCNetworkInterfaceRef interface, CFStringRef interfaceType) +CFPropertyListRef +__SCNetworkInterfaceGetTemplateOverrides(SCNetworkInterfaceRef interface, CFStringRef overrideType) { SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; - CFDictionaryRef overrides = NULL; + CFPropertyListRef overrides = NULL; if (interfacePrivate->overrides != NULL) { - overrides = CFDictionaryGetValue(interfacePrivate->overrides, interfaceType); + overrides = CFDictionaryGetValue(interfacePrivate->overrides, overrideType); } return overrides; @@ -4084,6 +5817,7 @@ Boolean SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config) { CFStringRef defaultType; + Boolean ok; if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); @@ -4095,7 +5829,14 @@ SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionary return FALSE; } - return __SCNetworkInterfaceSetConfiguration(interface, defaultType, config, FALSE); + ok = __SCNetworkInterfaceSetConfiguration(interface, defaultType, config, FALSE); + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkInterfaceSetConfiguration(): %@ -> %@", + interface, + config != NULL ? config : (CFDictionaryRef)CFSTR("NULL")); + } + + return ok; } @@ -4104,6 +5845,8 @@ SCNetworkInterfaceSetExtendedConfiguration(SCNetworkInterfaceRef interface, CFStringRef extendedType, CFDictionaryRef config) { + Boolean ok; + if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; @@ -4113,7 +5856,14 @@ SCNetworkInterfaceSetExtendedConfiguration(SCNetworkInterfaceRef interface, return FALSE; } - return __SCNetworkInterfaceSetConfiguration(interface, extendedType, config, FALSE); + ok = __SCNetworkInterfaceSetConfiguration(interface, extendedType, config, FALSE); + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkInterfaceSetExtendedConfiguration(): %@ -> %@", + interface, + config != NULL ? config : (CFDictionaryRef)CFSTR("NULL")); + } + + return ok; } @@ -4121,34 +5871,23 @@ SCNetworkInterfaceSetExtendedConfiguration(SCNetworkInterfaceRef interface, #pragma mark SCNetworkInterface [Refresh Configuration] API -#ifndef kSCEntNetRefreshConfiguration -#define kSCEntNetRefreshConfiguration CFSTR("RefreshConfiguration") -#endif // kSCEntNetRefreshConfiguration - Boolean _SCNetworkInterfaceForceConfigurationRefresh(CFStringRef ifName) { CFStringRef key; Boolean ok = FALSE; - SCDynamicStoreRef store; if (!isA_CFString(ifName)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } - store = SCDynamicStoreCreate(NULL, CFSTR("_SCNetworkInterfaceForceConfigurationRefresh"), NULL, NULL); - if (store == NULL) { - return FALSE; - } - key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, ifName, kSCEntNetRefreshConfiguration); - ok = SCDynamicStoreNotifyValue(store, key); + ok = SCDynamicStoreNotifyValue(NULL, key); CFRelease(key); - CFRelease(store); return ok; } @@ -4162,7 +5901,7 @@ __SCNetworkInterfaceForceConfigurationRefresh_helper(SCPreferencesRef prefs, CFS uint32_t status = kSCStatusOK; CFDataRef reply = NULL; - if (prefsPrivate->helper == -1) { + if (prefsPrivate->helper_port == MACH_PORT_NULL) { ok = __SCPreferencesCreate_helper(prefs); if (!ok) { return FALSE; @@ -4178,7 +5917,7 @@ __SCNetworkInterfaceForceConfigurationRefresh_helper(SCPreferencesRef prefs, CFS // have the helper "refresh" the configuration status = kSCStatusOK; reply = NULL; - ok = _SCHelperExec(prefsPrivate->helper, + ok = _SCHelperExec(prefsPrivate->helper_port, SCHELPER_MSG_INTERFACE_REFRESH, data, &status, @@ -4197,9 +5936,8 @@ __SCNetworkInterfaceForceConfigurationRefresh_helper(SCPreferencesRef prefs, CFS fail : // close helper - if (prefsPrivate->helper != -1) { - _SCHelperClose(prefsPrivate->helper); - prefsPrivate->helper = -1; + if (prefsPrivate->helper_port != MACH_PORT_NULL) { + _SCHelperClose(&prefsPrivate->helper_port); } status = kSCStatusAccessError; @@ -4242,11 +5980,13 @@ SCNetworkInterfaceForceConfigurationRefresh(SCNetworkInterfaceRef interface) } +#if !TARGET_OS_IPHONE Boolean SCNetworkInterfaceRefreshConfiguration(CFStringRef ifName) { return _SCNetworkInterfaceForceConfigurationRefresh(ifName); } +#endif // !TARGET_OS_IPHONE #pragma mark - @@ -4407,6 +6147,18 @@ checkInterfacePassword(SCNetworkInterfaceRef interface, goto error; } + case kSCNetworkInterfacePasswordTypeVPN : { + CFStringRef interfaceType; + + interfaceType = SCNetworkInterfaceGetInterfaceType(interface); + if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) { + // if VPN interface + break; + } + + goto error; + } + default : break; } @@ -4524,6 +6276,27 @@ SCNetworkInterfaceCheckPassword(SCNetworkInterfaceRef interface, 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; @@ -4639,6 +6412,27 @@ SCNetworkInterfaceCopyPassword(SCNetworkInterfaceRef interface, 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; @@ -4778,6 +6572,32 @@ SCNetworkInterfaceRemovePassword(SCNetworkInterfaceRef interface, 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; @@ -4950,7 +6770,7 @@ SCNetworkInterfaceSetPassword(SCNetworkInterfaceRef interface, // set password ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs, shared_id, - (label != NULL) ? label : CFSTR("VPN Connection"), + (label != NULL) ? label : CFSTR("Network Connection"), (description != NULL) ? description : CFSTR("IPSec Shared Secret"), account, password, @@ -4998,13 +6818,14 @@ SCNetworkInterfaceSetPassword(SCNetworkInterfaceRef interface, // get 802.1X identifier if (config != NULL) { unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID); + unique_id = isA_CFString(unique_id); } - if (isA_CFString(unique_id)) { + if (unique_id != NULL) { CFRetain(unique_id); } else { CFUUIDRef uuid; - uuid = CFUUIDCreate(NULL); + uuid = CFUUIDCreate(NULL); unique_id = CFUUIDCreateString(NULL, uuid); CFRelease(uuid); } @@ -5103,69 +6924,288 @@ SCNetworkInterfaceSetPassword(SCNetworkInterfaceRef interface, serviceID, interface); - label = SCNetworkServiceGetName(service); - if (label == NULL) { - // interface name --> keychain "Name" - label = SCNetworkInterfaceGetLocalizedDisplayName(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 + - if (bundle != NULL) { - // "IPSec XAuth Password" --> keychain "Kind" - description = CFBundleCopyLocalizedString(bundle, - CFSTR("KEYCHAIN_KIND_IPSEC_XAUTH_PASSWORD"), - CFSTR("IPSec XAuth Password"), - NULL); - } +CFDictionaryRef +_SCNetworkInterfaceCopyInterfaceInfo(SCNetworkInterfaceRef interface) +{ + CFMutableDictionaryRef info; + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + CFStringRef name; - // store password - ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs, - xauth_id, - (label != NULL) ? label : CFSTR("VPN Connection"), - (description != NULL) ? description : CFSTR("IPSec XAuth Password"), - account, - password, - options); - if (ok) { - CFMutableDictionaryRef newConfig; + if (interface == NULL) { + return NULL; + } - 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); - } + info = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); - CFRelease(xauth_id); - if (description != NULL) CFRelease(description); - if (service != NULL) CFRelease(service); - break; + // 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 + } - default : - _SCErrorSet(kSCStatusInvalidArgument); - break; + if (CFDictionaryGetCount(info) == 0) { + // do not return an empty dictionary + CFRelease(info); + info = NULL; } - return ok; + return info; } -#pragma mark - -#pragma mark SCNetworkInterface [InterfaceNamer] SPIs - - SCNetworkInterfaceRef _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(io_object_t if_obj) { @@ -5175,9 +7215,9 @@ _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(io_object_t if_obj) pthread_once(&initialized, __SCNetworkInterfaceInitialize); if (IOObjectConformsTo(if_obj, kIONetworkInterfaceClass)) { - interface = createInterface(if_obj, processNetworkInterface); + interface = createInterface(if_obj, processNetworkInterface, NULL); } else if (IOObjectConformsTo(if_obj, kIOSerialBSDServiceValue)) { - interface = createInterface(if_obj, processSerialInterface); + interface = createInterface(if_obj, processSerialInterface, kSCNetworkInterfaceHiddenPortKey); } return interface; @@ -5202,6 +7242,15 @@ _SCNetworkInterfaceGetHardwareAddress(SCNetworkInterfaceRef interface) } +CFStringRef +_SCNetworkInterfaceGetIOInterfaceNamePrefix(SCNetworkInterfaceRef interface) +{ + SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + + return interfacePrivate->prefix; +} + + CFNumberRef _SCNetworkInterfaceGetIOInterfaceType(SCNetworkInterfaceRef interface) { @@ -5220,6 +7269,72 @@ _SCNetworkInterfaceGetIOInterfaceUnit(SCNetworkInterfaceRef interface) } +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) { @@ -5229,6 +7344,25 @@ _SCNetworkInterfaceGetIOPath(SCNetworkInterfaceRef interface) } +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) { @@ -5238,10 +7372,79 @@ _SCNetworkInterfaceIsBuiltin(SCNetworkInterfaceRef interface) } +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) { @@ -5287,7 +7490,7 @@ _SCNetworkInterfaceCopySlashDevPath(SCNetworkInterfaceRef interface) // note: this "matching" dictionary will be consumed by the call to IOServiceGetMatchingServices kr = IOServiceGetMatchingServices(masterPort, matching, &device_iterator); if (kr != kIOReturnSuccess) { - SCLog(TRUE, LOG_DEBUG, CFSTR("IOServiceGetMatchingServices() failed, kr = 0x%x"), kr); + SC_log(LOG_INFO, "IOServiceGetMatchingServices() failed, kr = 0x%x", kr); goto done; } @@ -5297,9 +7500,26 @@ _SCNetworkInterfaceCopySlashDevPath(SCNetworkInterfaceRef interface) overrides = IORegistryEntrySearchCFProperty(device, kIOServicePlane, - CFSTR("DeviceModemOverrides"), + 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; @@ -5335,30 +7555,189 @@ _SCNetworkInterfaceCopySlashDevPath(SCNetworkInterfaceRef interface) } +#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); + 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 -_SCNetworkInterfaceIsModemV92(SCNetworkInterfaceRef interface) +_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 interfacePrivate->modemIsV92; + return policy; } - Boolean -_SCNetworkInterfaceIsTethered(SCNetworkInterfaceRef interface) +SCNetworkInterfaceSetQoSMarkingPolicy(SCNetworkInterfaceRef interface, CFDictionaryRef policy) { - SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; + Boolean ok; - return (interfacePrivate->sort_order == kSortTethered); + 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; } @@ -5373,6 +7752,7 @@ __SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator, SCPreferencesRef prefs, CFStringRef serviceID) { +#pragma unused(allocator) SCNetworkInterfacePrivateRef oldPrivate = (SCNetworkInterfacePrivateRef)interface; SCNetworkInterfacePrivateRef newPrivate; @@ -5383,7 +7763,7 @@ __SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator, return (SCNetworkInterfacePrivateRef)CFRetain(interface); } - newPrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, prefs, serviceID, NULL); + newPrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, prefs, serviceID); newPrivate->interface_type = oldPrivate->interface_type; if (oldPrivate->interface != NULL) { newPrivate->interface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL, // allocator @@ -5394,6 +7774,9 @@ __SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator, 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); } @@ -5428,24 +7811,43 @@ __SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator, 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); } - newPrivate->modemIsV92 = oldPrivate->modemIsV92; 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; -#if !TARGET_OS_IPHONE + newPrivate->supportsBond = oldPrivate->supportsBond; if (oldPrivate->bond.interfaces != NULL) { newPrivate->bond.interfaces = CFRetain(oldPrivate->bond.interfaces); @@ -5456,6 +7858,15 @@ __SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator, 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); @@ -5466,7 +7877,6 @@ __SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator, if (oldPrivate->vlan.options != NULL) { newPrivate->vlan.options = CFRetain(oldPrivate->vlan.options); } -#endif // !TARGET_OS_IPHONE return newPrivate; } @@ -5535,6 +7945,53 @@ __SCNetworkInterfaceCopyDeepConfiguration(SCNetworkSetRef set, SCNetworkInterfac } +__private_extern__ Boolean +__SCNetworkInterfaceIsMember(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) +{ + CFArrayRef interfaces; + Boolean match = FALSE; + CFMutableSetRef members; + + members = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); + +#if !TARGET_OS_IPHONE + // add Bond [member] interfaces + interfaces = SCBondInterfaceCopyAll(prefs); + if (interfaces != NULL) { + __SCBondInterfaceListCollectMembers(interfaces, members); + CFRelease(interfaces); + } +#endif // !TARGET_OS_IPHONE + + // add Bridge [member] interfaces + interfaces = SCBridgeInterfaceCopyAll(prefs); + if (interfaces != NULL) { + __SCBridgeInterfaceListCollectMembers(interfaces, members); + CFRelease(interfaces); + } + + if (CFSetGetCount(members) == 0) { + goto done; + } + + 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); + } + + done : + + CFRelease(members); + return match; +} + + __private_extern__ void __SCNetworkInterfaceSetDeepConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface, CFArrayRef configs) @@ -5544,6 +8001,7 @@ __SCNetworkInterfaceSetDeepConfiguration(SCNetworkSetRef set, SCNetworkInterface for (i = 0; interface != NULL; i++) { CFStringRef defaultType; CFDictionaryRef interfaceConfiguration; + Boolean ok; interfaceConfiguration = (configs != NULL) ? CFArrayGetValueAtIndex(configs, i) : NULL; @@ -5559,20 +8017,20 @@ __SCNetworkInterfaceSetDeepConfiguration(SCNetworkSetRef set, SCNetworkInterface } if (set == NULL) { // if service is not associated with the set - if (!__SCNetworkInterfaceSetConfiguration(interface, defaultType, config, TRUE)) { - SCLog(TRUE, LOG_DEBUG, - CFSTR("__SCNetworkInterfaceSetDeepConfiguration __SCNetworkInterfaceSetConfiguration() failed, interface=%@, type=%@"), - interface, - defaultType); - } + ok = __SCNetworkInterfaceSetConfiguration(interface, defaultType, config, TRUE); } else { // apply default configuration to this set - if (!__SCNetworkInterfaceSetDefaultConfiguration(set, interface, defaultType, config, TRUE)) { - SCLog(TRUE, LOG_DEBUG, - CFSTR("__SCNetworkInterfaceSetDeepConfiguration __SCNetworkInterfaceSetDefaultConfiguration() failed, interface=%@, type=%@"), - interface, - defaultType); - } + 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); } extendedTypes = extendedConfigurationTypes(interface); @@ -5586,15 +8044,20 @@ __SCNetworkInterfaceSetDeepConfiguration(SCNetworkSetRef set, SCNetworkInterface extendedType = CFArrayGetValueAtIndex(extendedTypes, j); config = (interfaceConfiguration != NULL) ? CFDictionaryGetValue(interfaceConfiguration, extendedType) - : NULL; + : NULL; if (config == (CFDictionaryRef)kCFNull) { config = NULL; } - if (!__SCNetworkInterfaceSetConfiguration(interface, extendedType, config, TRUE)) { - SCLog(TRUE, LOG_DEBUG, - CFSTR("__SCNetworkInterfaceSetDeepConfiguration __SCNetworkInterfaceSetConfiguration() failed, interface=%@, type=%@"), - interface, - defaultType); + 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); } } @@ -5607,3 +8070,435 @@ __SCNetworkInterfaceSetDeepConfiguration(SCNetworkSetRef set, SCNetworkInterface return; } + + +SCNetworkInterfaceRef +_SCNetworkInterfaceCopyActive(SCDynamicStoreRef store, CFStringRef bsdName) +{ + SCNetworkInterfaceRef interface; + + interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeAllVirtualInterfaces); + if (interface == NULL) { + return NULL; + } + + if (store != NULL) { + SCNetworkInterfacePrivateRef interfacePrivate = + (SCNetworkInterfacePrivateRef)interface; + + CFRetain(store); + interfacePrivate->store = store; + } + + return interface; +} + + +#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; +} + +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); +} + +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); +} + +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 { + CFDictionaryRemoveValue(new_config, kSCPropDisableUntilNeeded); + } + ok = __setPrefsConfiguration(interfacePrivate->prefs, + path, + (CFDictionaryGetCount(new_config) > 0) ? new_config : NULL, + FALSE); + CFRelease(new_config); + if (!ok) { + break; + } + } + CFRelease(path_list); + return (ok); +} + +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 + +SCNetworkServicePrimaryRank +SCNetworkInterfaceGetPrimaryRank(SCNetworkInterfaceRef interface) +{ +#pragma unused(interface) + return (kSCNetworkServicePrimaryRankDefault); +} + +Boolean +SCNetworkInterfaceSetPrimaryRank(SCNetworkInterfaceRef interface, + SCNetworkServicePrimaryRank newRank) +{ +#pragma unused(interface) +#pragma unused(newRank) + _SCErrorSet(kSCStatusInvalidArgument); + return (FALSE); +} + +Boolean +SCNetworkInterfaceGetDisableUntilNeeded(SCNetworkInterfaceRef interface) +{ +#pragma unused(interface) + return (FALSE); +} + +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); + + 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); + } + + if_list = SCPreferencesGetValue(ni_prefs, INTERFACES); + if (isA_CFArray(if_list)) { + CFIndex i; + CFIndex n = CFArrayGetCount(if_list); + + interfaceList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + for (i = 0; i < n; i++) { + CFDictionaryRef dict; + + dict = CFArrayGetValueAtIndex(if_list, i); + if (isA_CFDictionary(dict) != NULL) { + interfaceNamer = __SCNetworkInterfaceCreateWithStorageEntity(NULL, dict); + + if (interfaceNamer != NULL) { + CFArrayAppendValue(interfaceList, interfaceNamer); + CFRelease(interfaceNamer); + } + } + } + } + + 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 +__SCNetworkInterfaceSaveStoredWithPreferences(SCPreferencesRef prefs, CFArrayRef interfacesToSave) +{ + 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); + } + + 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__ +SCNetworkInterfaceRef +__SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(CFAllocatorRef allocator, SCPreferencesRef ni_prefs, CFStringRef bsdName) +{ + CFArrayRef if_list; + SCNetworkInterfaceRef interface = NULL; + CFStringRef defaultNetworkInterfacePath; + + /* 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); + } + else { + CFRetain(ni_prefs); + } + + if_list = SCPreferencesGetValue(ni_prefs, INTERFACES); + + if (isA_CFArray(if_list) != NULL) { + CFIndex idx; + CFIndex count = CFArrayGetCount(if_list); + + for (idx = 0; idx < count; idx++) { + CFDictionaryRef dict; + CFStringRef tmp_bsdName; + + dict = CFArrayGetValueAtIndex(if_list, idx); + if (isA_CFDictionary(dict) == NULL) { + continue; + } + + tmp_bsdName = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceBSDName)); + if (tmp_bsdName == NULL) { + continue; + } + if (CFEqual(bsdName, tmp_bsdName)) { + interface = __SCNetworkInterfaceCreateWithStorageEntity(allocator, dict); + break; + } + } + } + + CFRelease(ni_prefs); + return interface; +} + +__private_extern__ +CFDictionaryRef +__SCNetworkInterfaceCreateMappingUsingBSDName(CFArrayRef interfaces) +{ + 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 (CFIndex idx = 0; idx < count; idx++) { + interface = (SCNetworkInterfaceRef) CFArrayGetValueAtIndex(interfaces, idx); + + 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"); + } + + return mappingBSDToInterface; +} + +__private_extern__ Boolean +__SCNetworkInterfaceEntityIsPPTP(CFDictionaryRef entity) +{ + CFStringRef intfSubtype; + + if (entity == NULL) { + return FALSE; + } + + 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; +}