/* * Copyright (c) 2004, 2005 Apple Computer, 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, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * 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@ */ /* * Modification History * * May 13, 2004 Allan Nathanson * - initial revision * which includes code originally authored by * Robert Ulrich * Elizaabeth Douglas * Quinn */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for kIOEthernetInterfaceClass #include #include #include "dy_framework.h" #ifndef kIODeviceSupportsHoldKey #define kIODeviceSupportsHoldKey "V92Modem" #endif #include "SCNetworkConfiguration.h" #include "SCNetworkConfigurationInternal.h" #include #include #include #include static CFStringRef __SCNetworkInterfaceCopyDescription (CFTypeRef cf); static void __SCNetworkInterfaceDeallocate (CFTypeRef cf); static Boolean __SCNetworkInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2); enum { kSortInternalModem, kSortUSBModem, kSortModem, kSortBluetooth, kSortIrDA, kSortSerialPort, kSortEthernet, kSortFireWire, kSortAirPort, kSortOtherWireless, kSortBond, kSortVLAN, kSortUnknown }; const CFStringRef kSCNetworkInterfaceType6to4 = CFSTR("6to4"); const CFStringRef kSCNetworkInterfaceTypeBluetooth = CFSTR("Bluetooth"); const CFStringRef kSCNetworkInterfaceTypeBond = CFSTR("Bond"); const CFStringRef kSCNetworkInterfaceTypeEthernet = CFSTR("Ethernet"); const CFStringRef kSCNetworkInterfaceTypeFireWire = CFSTR("FireWire"); const CFStringRef kSCNetworkInterfaceTypeIEEE80211 = CFSTR("IEEE80211"); // IEEE 802.11, AirPort const CFStringRef kSCNetworkInterfaceTypeIrDA = CFSTR("IrDA"); const CFStringRef kSCNetworkInterfaceTypeL2TP = CFSTR("L2TP"); const CFStringRef kSCNetworkInterfaceTypeModem = CFSTR("Modem"); const CFStringRef kSCNetworkInterfaceTypePPP = CFSTR("PPP"); const CFStringRef kSCNetworkInterfaceTypePPTP = CFSTR("PPTP"); const CFStringRef kSCNetworkInterfaceTypeSerial = CFSTR("Serial"); const CFStringRef kSCNetworkInterfaceTypeVLAN = CFSTR("VLAN"); const CFStringRef kSCNetworkInterfaceTypeIPv4 = CFSTR("IPv4"); static SCNetworkInterfacePrivate __kSCNetworkInterfaceIPv4 = { INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), // cfBase NULL, // interface type NULL, // localized name NULL, // localization key NULL, // localization arg1 NULL, // localization arg2 NULL, // [layered] interface NULL, // service NULL, // unsaved NULL, // entity_device NULL, // entity_hardware NULL, // entity_type NULL, // entity_subtype NULL, // supported_interface_types NULL, // supported_protocol_types NULL, // address FALSE, // builtin NULL, // location NULL, // path FALSE, // supportsDeviceOnHold FALSE, // supportsBond FALSE, // supportsVLAN kSortUnknown // sort_order }; const SCNetworkInterfaceRef kSCNetworkInterfaceIPv4 = (SCNetworkInterfaceRef)&__kSCNetworkInterfaceIPv4; #define doNone 0 #define do6to4 1<<0 #define doL2TP 1<<1 #define doPPP 1<<2 #define doPPTP 1<<3 #define doAppleTalk 1<<0 #define doDNS 1<<1 #define doIPv4 1<<2 #define doIPv6 1<<3 #define doProxies 1<<4 static const struct { const CFStringRef *interface_type; Boolean per_interface_config; uint32_t supported_interfaces; const CFStringRef *ppp_subtype; uint32_t supported_protocols; } configurations[] = { // interface type if config? interface types PPP sub-type interface protocols // ===================================== ========== ======================= ======================================= ========================================= { &kSCNetworkInterfaceType6to4 , FALSE, doNone, NULL, doIPv6 }, { &kSCNetworkInterfaceTypeBluetooth , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, { &kSCNetworkInterfaceTypeBond , TRUE, doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies }, { &kSCNetworkInterfaceTypeEthernet , TRUE, doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies }, { &kSCNetworkInterfaceTypeFireWire , TRUE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies }, { &kSCNetworkInterfaceTypeIEEE80211 , TRUE, doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies }, { &kSCNetworkInterfaceTypeIrDA , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, { &kSCNetworkInterfaceTypeL2TP , FALSE, doPPP, &kSCValNetInterfaceSubTypeL2TP, doNone }, { &kSCNetworkInterfaceTypeModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, { &kSCNetworkInterfaceTypePPP , FALSE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies }, { &kSCNetworkInterfaceTypePPTP , FALSE, doPPP, &kSCValNetInterfaceSubTypePPTP, doNone }, { &kSCNetworkInterfaceTypeSerial , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone }, { &kSCNetworkInterfaceTypeVLAN , TRUE, doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies }, // ===================================== ========== ======================= ======================================= ========================================= { &kSCNetworkInterfaceTypeIPv4 , FALSE, do6to4|doPPTP|doL2TP, NULL, doNone } }; #define SYSTEMCONFIGURATION_BUNDLE_ID CFSTR("com.apple.SystemConfiguration") #define NETWORKINTERFACE_LOCALIZATIONS CFSTR("NetworkInterface") static CFBundleRef bundle = NULL; static CFTypeID __kSCNetworkInterfaceTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __SCNetworkInterfaceClass = { 0, // version "SCNetworkInterface", // className NULL, // init NULL, // copy __SCNetworkInterfaceDeallocate, // dealloc __SCNetworkInterfaceEqual, // equal NULL, // hash NULL, // copyFormattingDesc __SCNetworkInterfaceCopyDescription // copyDebugDesc }; static pthread_once_t initialized = PTHREAD_ONCE_INIT; static __inline__ CFTypeRef isA_SCNetworkInterface(CFTypeRef obj) { return (isA_CFType(obj, SCNetworkInterfaceGetTypeID())); } static CFStringRef __SCNetworkInterfaceCopyDescription(CFTypeRef cf) { CFAllocatorRef allocator = CFGetAllocator(cf); CFMutableStringRef result; SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)cf; result = CFStringCreateMutable(allocator, 0); CFStringAppendFormat(result, NULL, CFSTR(" { "), cf, allocator); CFStringAppendFormat(result, NULL, CFSTR("type = %@"), interfacePrivate->interface_type); CFStringAppendFormat(result, NULL, CFSTR(", entity = %@ / %@ / %@"), interfacePrivate->entity_device, interfacePrivate->entity_hardware, interfacePrivate->entity_type); if (interfacePrivate->entity_subtype != NULL) { CFStringAppendFormat(result, NULL, CFSTR(" / %@"), interfacePrivate->entity_subtype); } if (interfacePrivate->localized_name != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), interfacePrivate->localized_name); } else { if (interfacePrivate->localized_key != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", name = \"%@\""), interfacePrivate->localized_key); if (interfacePrivate->localized_arg1 != NULL) { CFStringAppendFormat(result, NULL, CFSTR("+\"%@\""), interfacePrivate->localized_arg1); } if (interfacePrivate->localized_arg2 != NULL) { CFStringAppendFormat(result, NULL, CFSTR("+\"%@\""), interfacePrivate->localized_arg2); } } } if (interfacePrivate->address != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", address = %@"), interfacePrivate->address); } CFStringAppendFormat(result, NULL, CFSTR(", builtin = %s"), interfacePrivate->builtin ? "TRUE" : "FALSE"); if (interfacePrivate->location != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", location = %@"), interfacePrivate->location); } CFStringAppendFormat(result, NULL, CFSTR(", path = %@"), interfacePrivate->path); CFStringAppendFormat(result, NULL, CFSTR(", order = %d"), interfacePrivate->sort_order); if (interfacePrivate->service != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", service=%@"), interfacePrivate->service); } if (interfacePrivate->interface != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", interface=%@"), interfacePrivate->interface); } if (interfacePrivate->unsaved != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", unsaved=%@"), interfacePrivate->unsaved); } CFStringAppendFormat(result, NULL, CFSTR(" }")); return result; } static void __SCNetworkInterfaceDeallocate(CFTypeRef cf) { SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)cf; /* release resources */ if (interfacePrivate->interface != NULL) CFRelease(interfacePrivate->interface); if (interfacePrivate->localized_name != NULL) CFRelease(interfacePrivate->localized_name); if (interfacePrivate->localized_arg1 != NULL) CFRelease(interfacePrivate->localized_arg1); if (interfacePrivate->localized_arg2 != NULL) CFRelease(interfacePrivate->localized_arg2); if (interfacePrivate->unsaved != NULL) CFRelease(interfacePrivate->unsaved); if (interfacePrivate->entity_device != NULL) CFRelease(interfacePrivate->entity_device); if (interfacePrivate->supported_interface_types != NULL) CFRelease(interfacePrivate->supported_interface_types); if (interfacePrivate->supported_protocol_types != NULL) CFRelease(interfacePrivate->supported_protocol_types); if (interfacePrivate->address != NULL) CFRelease(interfacePrivate->address); if (interfacePrivate->location != NULL) CFRelease(interfacePrivate->location); if (interfacePrivate->path != NULL) CFRelease(interfacePrivate->path); return; } static Boolean __SCNetworkInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2) { SCNetworkInterfacePrivateRef if1 = (SCNetworkInterfacePrivateRef)cf1; SCNetworkInterfacePrivateRef if2 = (SCNetworkInterfacePrivateRef)cf2; if (if1 == if2) return TRUE; if (!CFEqual(if1->interface_type, if2->interface_type)) { return FALSE; // if not the same interface type } if (if1->entity_device != if2->entity_device) { if ((if1->entity_device != NULL) && (if2->entity_device != NULL)) { if (!CFEqual(if1->entity_device, if2->entity_device)) { return FALSE; // if not the same device } } else { return FALSE; // if only one interface has a device } } return TRUE; } static void __SCNetworkInterfaceInitialize(void) { // register w/CF __kSCNetworkInterfaceTypeID = _CFRuntimeRegisterClass(&__SCNetworkInterfaceClass); // initialize __kSCNetworkInterfaceIPv4 _CFRuntimeSetInstanceTypeID(&__kSCNetworkInterfaceIPv4, __kSCNetworkInterfaceTypeID); __kSCNetworkInterfaceIPv4.interface_type = kSCNetworkInterfaceTypeIPv4; __kSCNetworkInterfaceIPv4.localized_key = CFSTR("ipv4"); // get CFBundleRef for SystemConfiguration.framework bundle = CFBundleGetBundleWithIdentifier(SYSTEMCONFIGURATION_BUNDLE_ID); if (bundle == NULL) { // try a bit harder CFURLRef url; url = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/Frameworks/SystemConfiguration.framework"), kCFURLPOSIXPathStyle, TRUE); bundle = CFBundleCreate(NULL, url); CFRelease(url); } return; } __private_extern__ SCNetworkInterfacePrivateRef __SCNetworkInterfaceCreatePrivate(CFAllocatorRef allocator, SCNetworkInterfaceRef interface, SCNetworkServiceRef service, io_string_t path) { SCNetworkInterfacePrivateRef interfacePrivate; uint32_t size; /* initialize runtime */ pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* allocate target */ size = sizeof(SCNetworkInterfacePrivate) - sizeof(CFRuntimeBase); interfacePrivate = (SCNetworkInterfacePrivateRef)_CFRuntimeCreateInstance(allocator, __kSCNetworkInterfaceTypeID, size, NULL); if (interfacePrivate == NULL) { return NULL; } interfacePrivate->interface_type = NULL; interfacePrivate->localized_name = NULL; interfacePrivate->localized_key = NULL; interfacePrivate->localized_arg1 = NULL; interfacePrivate->localized_arg2 = NULL; interfacePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL; interfacePrivate->service = service; interfacePrivate->unsaved = NULL; interfacePrivate->entity_device = NULL; interfacePrivate->entity_hardware = NULL; interfacePrivate->entity_type = NULL; interfacePrivate->entity_subtype = NULL; interfacePrivate->supported_interface_types = NULL; interfacePrivate->supported_protocol_types = NULL; interfacePrivate->address = NULL; interfacePrivate->builtin = FALSE; interfacePrivate->path = (path != NULL) ? CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8) : NULL; interfacePrivate->location = NULL; interfacePrivate->supportsDeviceOnHold = FALSE; interfacePrivate->supportsBond = FALSE; interfacePrivate->supportsVLAN = FALSE; interfacePrivate->sort_order = kSortUnknown; return interfacePrivate; } /* ---------- ordering ---------- */ static CFArrayRef split_path(CFStringRef path) { CFArrayRef components; CFMutableStringRef nPath; // turn '@'s into '/'s nPath = CFStringCreateMutableCopy(NULL, 0, path); (void) CFStringFindAndReplace(nPath, CFSTR("@"), CFSTR("/"), CFRangeMake(0, CFStringGetLength(nPath)), 0); // split path into components to be compared components = CFStringCreateArrayBySeparatingStrings(NULL, nPath, CFSTR("/")); CFRelease(nPath); return components; } static CFComparisonResult compare_interfaces(const void *val1, const void *val2, void *context) { SCNetworkInterfacePrivateRef dev1 = (SCNetworkInterfacePrivateRef)val1; SCNetworkInterfacePrivateRef dev2 = (SCNetworkInterfacePrivateRef)val2; CFComparisonResult res = kCFCompareEqualTo; /* sort by interface type */ if (dev1->sort_order != dev2->sort_order) { if (dev1->sort_order < dev2->sort_order) { res = kCFCompareLessThan; } else { res = kCFCompareGreaterThan; } return (res); } /* built-in interfaces sort first */ if (dev1->builtin != dev2->builtin) { if (dev1->builtin) { res = kCFCompareLessThan; } else { res = kCFCompareGreaterThan; } return (res); } /* ... and then, sort built-in interfaces by "location" */ if (dev1->builtin) { if (dev1->location != dev2->location) { if (isA_CFString(dev1->location)) { if (isA_CFString(dev2->location)) { res = CFStringCompare(dev1->location, dev2->location, 0); } else { res = kCFCompareLessThan; } } else { res = kCFCompareGreaterThan; } if (res != kCFCompareEqualTo) { return (res); } } } /* ... and, then sort by IOPathMatch */ if ((dev1->path != NULL) && (dev2->path != NULL)) { CFArrayRef elements1; CFArrayRef elements2; CFIndex i; CFIndex n; CFIndex n1; CFIndex n2; elements1 = split_path(dev1->path); n1 = CFArrayGetCount(elements1); elements2 = split_path(dev2->path); n2 = CFArrayGetCount(elements2); n = (n1 <= n2) ? n1 : n2; for (i = 0; i < n; i++) { CFStringRef e1; CFStringRef e2; char *end; quad_t q1; quad_t q2; char *str; Boolean isNum; e1 = CFArrayGetValueAtIndex(elements1, i); e2 = CFArrayGetValueAtIndex(elements2, i); str = _SC_cfstring_to_cstring(e1, NULL, 0, kCFStringEncodingUTF8); errno = 0; q1 = strtoq(str, &end, 16); isNum = ((*str != '\0') && (*end == '\0') && (errno == 0)); CFAllocatorDeallocate(NULL, str); if (isNum) { // if e1 is a valid numeric string str = _SC_cfstring_to_cstring(e2, NULL, 0, kCFStringEncodingUTF8); errno = 0; q2 = strtoq(str, &end, 16); isNum = ((*str != '\0') && (*end == '\0') && (errno == 0)); CFAllocatorDeallocate(NULL, str); if (isNum) { // if e2 is also a valid numeric string if (q1 == q2) { res = kCFCompareEqualTo; continue; } else if (q1 < q2) { res = kCFCompareLessThan; } else { res = kCFCompareGreaterThan; } break; } } res = CFStringCompare(e1, e2, 0); if (res != kCFCompareEqualTo) { break; } } if (res == kCFCompareEqualTo) { if (n1 < n2) { res = kCFCompareLessThan; } else if (n1 < n2) { res = kCFCompareGreaterThan; } } CFRelease(elements1); CFRelease(elements2); if (res != kCFCompareEqualTo) { return (res); } } /* ... and lastly, sort by BSD interface name */ if ((dev1->entity_device != NULL) && (dev2->entity_device != NULL)) { res = CFStringCompare(dev1->entity_device, dev2->entity_device, 0); } return res; } static void sort_interfaces(CFMutableArrayRef all_interfaces) { int n = CFArrayGetCount(all_interfaces); if (n < 2) { return; } CFArraySortValues(all_interfaces, CFRangeMake(0, n), compare_interfaces, NULL); return; } /* ---------- interface details ---------- */ static CFStringRef IOCopyCFStringValue(CFTypeRef ioVal) { if (isA_CFString(ioVal)) { return CFStringCreateCopy(NULL, ioVal); } if (isA_CFData(ioVal)) { return CFStringCreateWithCString(NULL, (const char *)CFDataGetBytePtr(ioVal), kCFStringEncodingUTF8); } return NULL; } static CFStringRef IODictionaryCopyCFStringValue(CFDictionaryRef io_dict, CFStringRef io_key) { CFTypeRef ioVal; ioVal = CFDictionaryGetValue(io_dict, io_key); return IOCopyCFStringValue(ioVal); } static Boolean IOStringValueHasPrefix(CFTypeRef ioVal, CFStringRef prefix) { Boolean match = FALSE; CFIndex prefixLen = CFStringGetLength(prefix); CFStringRef str = ioVal; if (!isA_CFString(ioVal)) { if (isA_CFData(ioVal)) { str = CFStringCreateWithCStringNoCopy(NULL, (const char *)CFDataGetBytePtr(ioVal), kCFStringEncodingUTF8, kCFAllocatorNull); } else { return FALSE; } } if ((str != NULL) && (CFStringGetLength(str) >= prefixLen) && (CFStringCompareWithOptions(str, prefix, CFRangeMake(0, prefixLen), kCFCompareCaseInsensitive) == kCFCompareEqualTo)) { match = TRUE; } if (str != ioVal) CFRelease(str); return match; } static CFStringRef copyMACAddress(CFDictionaryRef controller_dict) { CFStringRef address = NULL; uint8_t *bp; char *cp; CFDataRef data; CFIndex n; char mac[sizeof("xx:xx:xx:xx:xx:xx:xx:xx")]; char *mac_p = mac; data = CFDictionaryGetValue(controller_dict, CFSTR(kIOMACAddress)); if (data == NULL) { return NULL; } bp = (uint8_t *)CFDataGetBytePtr(data); n = CFDataGetLength(data) * 3; if (n > sizeof(mac)) { mac_p = CFAllocatorAllocate(NULL, 0, n); } for (cp = mac_p; n > 0; n -= 3) { cp += snprintf(cp, n, "%2.2x:", *bp++); } address = CFStringCreateWithCString(NULL, mac_p, kCFStringEncodingUTF8); if (mac_p != mac) CFAllocatorDeallocate(NULL, mac_p); return address; } static const struct { const CFStringRef name; const CFStringRef slot; } slot_mappings[] = { // Beige G3 { CFSTR("A1") , CFSTR("1") }, { CFSTR("B1") , CFSTR("2") }, { CFSTR("C1") , CFSTR("3") }, // Blue&White G3, Yikes G4 { CFSTR("J12"), CFSTR("1") }, { CFSTR("J11"), CFSTR("2") }, { CFSTR("J10"), CFSTR("3") }, { CFSTR("J9"), CFSTR("4") }, // AGP G4 { CFSTR("A") , CFSTR("1") }, { CFSTR("B") , CFSTR("2") }, { CFSTR("C") , CFSTR("3") }, { CFSTR("D") , CFSTR("4") }, // Digital Audio G4 (and later models) { CFSTR("1") , CFSTR("1") }, { CFSTR("2") , CFSTR("2") }, { CFSTR("3") , CFSTR("3") }, { CFSTR("4") , CFSTR("4") }, { CFSTR("5") , CFSTR("5") } }; static CFStringRef pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name) { kern_return_t kr; io_registry_entry_t slot = interface; if (pci_slot_name != NULL) *pci_slot_name = NULL; while (slot != MACH_PORT_NULL) { io_registry_entry_t parent; CFTypeRef slot_name; slot_name = IORegistryEntryCreateCFProperty(slot, CFSTR("AAPL,slot-name"), NULL, 0); if (slot_name != NULL) { Boolean found; found = IOStringValueHasPrefix(slot_name, CFSTR("slot")); if (found) { CFIndex i; CFMutableStringRef name; // if we found a slot # name = CFStringCreateMutable(NULL, 0); if (isA_CFString(slot_name)) { if (pci_slot_name != NULL) *pci_slot_name = CFStringCreateCopy(NULL, slot_name); CFStringAppend(name, slot_name); } else if (isA_CFData(slot_name)) { if (pci_slot_name != NULL) *pci_slot_name = CFDataCreateCopy(NULL, slot_name); CFStringAppendCString(name, (const char *)CFDataGetBytePtr(slot_name), kCFStringEncodingUTF8); } (void) CFStringFindAndReplace(name, CFSTR("slot-"), CFSTR(""), CFRangeMake(0, 5), kCFCompareCaseInsensitive|kCFCompareAnchored); for (i = 0; i < sizeof(slot_mappings)/sizeof(slot_mappings[0]); i++) { if (CFStringCompareWithOptions(name, slot_mappings[i].name, CFRangeMake(0, CFStringGetLength(slot_mappings[i].name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { CFRelease(name); name = (CFMutableStringRef)CFRetain(slot_mappings[i].slot); break; } } CFRelease(slot_name); if (slot != interface) IOObjectRelease(slot); return name; } CFRelease(slot_name); } kr = IORegistryEntryGetParentEntry(slot, kIOServicePlane, &parent); if (slot != interface) IOObjectRelease(slot); switch (kr) { case kIOReturnSuccess : slot = parent; break; case kIOReturnNoDevice : // if we have hit the root node without finding a slot # goto done; default : SCLog(TRUE, LOG_INFO, CFSTR("pci_slot IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr); goto done; } } done : return NULL; } static CFComparisonResult compare_bsdNames(const void *val1, const void *val2, void *context) { CFStringRef bsd1 = (CFStringRef)val1; CFStringRef bsd2 = (CFStringRef)val2; return CFStringCompare(bsd1, bsd2, 0); } static CFStringRef pci_port(mach_port_t masterPort, CFTypeRef slot_name, CFStringRef bsdName) { CFIndex n; CFStringRef port_name = NULL; CFMutableArrayRef port_names; kern_return_t kr; CFStringRef match_keys[2]; CFTypeRef match_vals[2]; CFDictionaryRef match_dict; CFDictionaryRef matching; io_registry_entry_t slot; io_iterator_t slot_iterator = MACH_PORT_NULL; match_keys[0] = CFSTR("AAPL,slot-name"); match_vals[0] = slot_name; match_dict = CFDictionaryCreate(NULL, (const void **)match_keys, (const void **)match_vals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); match_keys[0] = CFSTR(kIOProviderClassKey); match_vals[0] = CFSTR("IOPCIDevice"); match_keys[1] = CFSTR(kIOPropertyMatchKey); match_vals[1] = match_dict; // note: the "matching" dictionary will be consumed by the following matching = CFDictionaryCreate(NULL, (const void **)match_keys, (const void **)match_vals, sizeof(match_keys)/sizeof(match_keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease(match_dict); kr = IOServiceGetMatchingServices(masterPort, matching, &slot_iterator); if (kr != kIOReturnSuccess) { SCPrint(TRUE, stderr, CFSTR("IOServiceGetMatchingServices() failed, kr = 0x%x\n"), kr); return MACH_PORT_NULL; } port_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); while ((slot = IOIteratorNext(slot_iterator)) != MACH_PORT_NULL) { io_registry_entry_t child; io_iterator_t child_iterator = MACH_PORT_NULL; kr = IORegistryEntryCreateIterator(slot, kIOServicePlane, kIORegistryIterateRecursively, &child_iterator); if (kr != kIOReturnSuccess) { SCPrint(TRUE, stderr, CFSTR("IORegistryEntryCreateIterator() failed, kr = 0x%x\n"), kr); return MACH_PORT_NULL; } while ((child = IOIteratorNext(child_iterator)) != MACH_PORT_NULL) { if (IOObjectConformsTo(child, kIONetworkInterfaceClass)) { CFStringRef if_bsdName; if_bsdName = IORegistryEntryCreateCFProperty(child, CFSTR(kIOBSDNameKey), NULL, 0); if (if_bsdName != NULL) { CFArrayAppendValue(port_names, if_bsdName); CFRelease(if_bsdName); } } IOObjectRelease(child); } IOObjectRelease(child_iterator); IOObjectRelease(slot); } IOObjectRelease(slot_iterator); n = CFArrayGetCount(port_names); if (n > 1) { CFArraySortValues(port_names, CFRangeMake(0, n), compare_bsdNames, NULL); n = CFArrayGetFirstIndexOfValue(port_names, CFRangeMake(0, n), bsdName); if (n != kCFNotFound) { port_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), n + 1); } } CFRelease(port_names); return port_name; } static Boolean pci_slot_info(mach_port_t masterPort, io_registry_entry_t interface, CFStringRef *slot_name, CFStringRef *port_name) { CFStringRef bsd_name; Boolean ok = FALSE; CFTypeRef pci_slot_name; *slot_name = NULL; *port_name = NULL; bsd_name = IORegistryEntryCreateCFProperty(interface, CFSTR(kIOBSDNameKey), NULL, 0); if (bsd_name == NULL) { return FALSE; } *slot_name = pci_slot(interface, &pci_slot_name); if (*slot_name != NULL) { if (pci_slot_name != NULL) { *port_name = pci_port(masterPort, pci_slot_name, bsd_name); CFRelease(pci_slot_name); } ok = TRUE; } CFRelease(bsd_name); return ok; } static Boolean isBuiltIn(io_registry_entry_t interface) { kern_return_t kr; io_registry_entry_t slot = interface; while (slot != MACH_PORT_NULL) { io_registry_entry_t parent; CFTypeRef slot_name; slot_name = IORegistryEntryCreateCFProperty(slot, CFSTR("AAPL,slot-name"), NULL, 0); if (slot_name != NULL) { Boolean found; found = IOStringValueHasPrefix(slot_name, CFSTR("slot")); CFRelease(slot_name); if (found) { // if we found a slot # then this is not a built-in interface if (slot != interface) IOObjectRelease(slot); return FALSE; } } kr = IORegistryEntryGetParentEntry(slot, kIOServicePlane, &parent); if (slot != interface) IOObjectRelease(slot); switch (kr) { case kIOReturnSuccess : slot = parent; break; case kIOReturnNoDevice : // if we have hit the root node without finding a slot # return TRUE; default : SCLog(TRUE, LOG_INFO, CFSTR("isBuiltIn IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr); return FALSE; } } return FALSE; } /* ---------- interface enumeration ---------- */ typedef Boolean (*processInterface)(mach_port_t masterPort, SCNetworkInterfacePrivateRef interfacePrivate, io_registry_entry_t interface, CFDictionaryRef interface_dict, io_registry_entry_t controller, CFDictionaryRef controller_dict, io_registry_entry_t bus, CFDictionaryRef bus_dict); static Boolean processNetworkInterface(mach_port_t masterPort, 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) { CFBooleanRef bVal; io_name_t c_IOClass; io_name_t c_IOName; io_name_t i_IOClass; int ift = -1; int iVal; CFNumberRef num; CFStringRef str; // get the interface type num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceType)); if (!isA_CFNumber(num) || !CFNumberGetValue(num, kCFNumberIntType, &ift)) { SCPrint(TRUE, stderr, CFSTR("Could not get interface type\n")); return FALSE; } switch (ift) { case IFT_ETHER : // Type, Hardware if (IOObjectGetClass(interface, i_IOClass) != KERN_SUCCESS) { i_IOClass[0] = '\0'; } if (IOObjectGetClass(controller, c_IOClass) != KERN_SUCCESS) { c_IOClass[0] = '\0'; } if (IORegistryEntryGetName(controller, c_IOName) != KERN_SUCCESS) { c_IOName[0] = '\0'; } if ((strcmp(i_IOClass, "IO80211Interface" ) == 0) || (strcmp(c_IOClass, "AirPortPCI" ) == 0) || (strcmp(c_IOClass, "AirPortDriver" ) == 0) || (strcmp(c_IOName , "AppleWireless80211") == 0)) { interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211; interfacePrivate->entity_type = kSCEntNetEthernet; interfacePrivate->entity_hardware = kSCEntNetAirPort; interfacePrivate->sort_order = kSortAirPort; } else { str = IODictionaryCopyCFStringValue(bus_dict, CFSTR("name")); if ((str != NULL) && CFEqual(str, CFSTR("radio"))) { interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; // ?? interfacePrivate->entity_type = kSCEntNetEthernet; interfacePrivate->entity_hardware = kSCEntNetEthernet; // ?? interfacePrivate->sort_order = kSortOtherWireless; } else { interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; interfacePrivate->entity_type = kSCEntNetEthernet; interfacePrivate->entity_hardware = kSCEntNetEthernet; interfacePrivate->sort_order = kSortEthernet; // BOND support only enabled for ethernet devices interfacePrivate->supportsBond = TRUE; } if (str != NULL) CFRelease(str); } // built-in bVal = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOBuiltin))); if ((bVal == NULL) || !CFBooleanGetValue(bVal)) { bVal = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOPrimaryInterface))); } if (bVal != NULL) { interfacePrivate->builtin = CFBooleanGetValue(bVal); } else { interfacePrivate->builtin = isBuiltIn(interface); } // location interfacePrivate->location = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOLocation)); // VLAN support num = CFDictionaryGetValue(controller_dict, CFSTR(kIOFeatures)); if (isA_CFNumber(num) && CFNumberGetValue(num, kCFNumberIntType, & iVal)) { if (iVal & (kIONetworkFeatureHardwareVlan | kIONetworkFeatureSoftwareVlan)) { interfacePrivate->supportsVLAN = TRUE; } } // localized name if (interfacePrivate->builtin) { if ((interfacePrivate->location == NULL) || (CFStringGetLength(interfacePrivate->location) == 0)) { interfacePrivate->localized_key = CFSTR("ether"); } else { interfacePrivate->localized_key = CFSTR("multiether"); interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->location); } } else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) { interfacePrivate->localized_key = CFSTR("airport"); } else if (interfacePrivate->sort_order == kSortOtherWireless) { interfacePrivate->localized_key = CFSTR("wireless"); interfacePrivate->localized_arg1 = CFRetain(CFSTR("")); // ?? } else { CFStringRef provider; // check provider class provider = IORegistryEntrySearchCFProperty(interface, kIOServicePlane, CFSTR(kIOProviderClassKey), NULL, kIORegistryIterateRecursively | kIORegistryIterateParents); if (provider != NULL) { if (CFEqual(provider, CFSTR("IOPCIDevice"))) { CFStringRef port_name; CFStringRef slot_name; if (pci_slot_info(masterPort, interface, &slot_name, &port_name)) { if (port_name == NULL) { interfacePrivate->localized_key = CFSTR("pci-ether"); interfacePrivate->localized_arg1 = slot_name; } else { interfacePrivate->localized_key = CFSTR("pci-multiether"); interfacePrivate->localized_arg1 = slot_name; interfacePrivate->localized_arg2 = port_name; } } } 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)); } } break; case IFT_IEEE1394 : // Type interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire; // Entity interfacePrivate->entity_type = kSCEntNetFireWire; interfacePrivate->entity_hardware = kSCEntNetFireWire; // built-in interfacePrivate->builtin = isBuiltIn(interface); // sort order interfacePrivate->sort_order = kSortFireWire; // localized name if (interfacePrivate->builtin) { interfacePrivate->localized_key = CFSTR("firewire"); } else { CFStringRef slot_name; slot_name = pci_slot(interface, NULL); if (slot_name != NULL) { interfacePrivate->localized_key = CFSTR("pci-firewire"); interfacePrivate->localized_arg1 = slot_name; } } break; default : SCPrint(TRUE, stderr, CFSTR("Unknown interface type = %d\n"), ift); return FALSE; } // Device interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey)); // Hardware (MAC) address interfacePrivate->address = copyMACAddress(controller_dict); return TRUE; } static Boolean processSerialInterface(mach_port_t masterPort, SCNetworkInterfacePrivateRef interfacePrivate, io_registry_entry_t interface, CFDictionaryRef interface_dict, io_registry_entry_t controller, CFDictionaryRef controller_dict, io_registry_entry_t bus, CFDictionaryRef bus_dict) { CFStringRef ift; Boolean isModem = FALSE; CFStringRef str; 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 } // Type str = CFDictionaryGetValue(interface_dict, CFSTR(kIOTTYBaseNameKey)); if (str == NULL) { return FALSE; } /* * From MoreSCF: * * Exclude ports named "irda" because otherwise the IrDA ports on the * original iMac (rev's A through D) show up as serial ports. Given * that only the rev A actually had an IrDA port, and Mac OS X doesn't * even support it, these ports definitely shouldn't be listed. */ if (CFStringCompare(str, CFSTR("irda"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { return FALSE; } if (IOStringValueHasPrefix(str, CFSTR("irda-ircomm"))) { // IrDA interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA; interfacePrivate->sort_order = kSortIrDA; } else if (IOStringValueHasPrefix(str, CFSTR("bluetooth"))) { // Bluetooth interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth; interfacePrivate->sort_order = kSortBluetooth; } else { // Modem interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem; // DeviceOnHold support val = IORegistryEntrySearchCFProperty(interface, kIOServicePlane, CFSTR(kIODeviceSupportsHoldKey), NULL, kIORegistryIterateRecursively | kIORegistryIterateParents); if (val != NULL) { uint32_t supportsHold; if (isA_CFNumber(val) && CFNumberGetValue(val, kCFNumberSInt32Type, &supportsHold)) { interfacePrivate->supportsDeviceOnHold = (supportsHold == 1); } CFRelease(val); } } // Entity (Type) interfacePrivate->entity_type = kSCEntNetModem; // Entity (Hardware) ift = CFDictionaryGetValue(interface_dict, CFSTR(kIOSerialBSDTypeKey)); if (!isA_CFString(ift)) { return FALSE; } if (CFEqual(ift, CFSTR(kIOSerialBSDModemType))) { // if modem isModem = TRUE; interfacePrivate->entity_hardware = kSCEntNetModem; if (CFEqual(str, CFSTR("modem"))) { interfacePrivate->builtin = TRUE; interfacePrivate->sort_order = kSortInternalModem; } else if (CFEqual(str, CFSTR("usbmodem"))) { interfacePrivate->sort_order = kSortUSBModem; } else { interfacePrivate->sort_order = kSortModem; } } else if (CFEqual(ift, CFSTR(kIOSerialBSDRS232Type))) { // if serial port interfacePrivate->entity_hardware = kSCEntNetModem; interfacePrivate->sort_order = kSortSerialPort; } else { return FALSE; } // Entity (Device) interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOTTYDeviceKey)); // localized name if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIrDA)) { interfacePrivate->localized_key = CFSTR("irda"); } else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBluetooth)) { interfacePrivate->localized_key = CFSTR("bluetooth"); } else { CFStringRef localized; CFMutableStringRef port; port = CFStringCreateMutableCopy(NULL, 0, str); CFStringLowercase(port, NULL); if (!isModem) { CFStringAppend(port, CFSTR("-port")); } localized = CFBundleCopyLocalizedString(bundle, port, port, NETWORKINTERFACE_LOCALIZATIONS); if (localized != NULL) { if (!CFEqual(port, localized)) { // if localization available interfacePrivate->localized_name = localized; } else { // if no localization available, use TTY base name CFRelease(localized); interfacePrivate->localized_name = CFStringCreateCopy(NULL, str); } } else { interfacePrivate->localized_name = CFStringCreateCopy(NULL, str); } if (!isModem || !CFEqual(str, CFSTR("modem"))) { CFStringRef productName; // check if a "Product Name" has been provided val = IORegistryEntrySearchCFProperty(interface, kIOServicePlane, CFSTR(kIOPropertyProductNameKey), NULL, kIORegistryIterateRecursively | kIORegistryIterateParents); if (val != NULL) { productName = IOCopyCFStringValue(val); CFRelease(val); if (productName != NULL) { if (CFStringGetLength(productName) > 0) { // if we have a [somewhat reasonable?] product name CFRelease(interfacePrivate->localized_name); interfacePrivate->localized_name = CFRetain(productName); } CFRelease(productName); } } } CFRelease(port); } return TRUE; } static CFArrayRef findMatchingInterfaces(mach_port_t masterPort, CFDictionaryRef matching, processInterface func) { CFMutableArrayRef interfaces; io_registry_entry_t interface; kern_return_t kr; io_iterator_t iterator = MACH_PORT_NULL; kr = IOServiceGetMatchingServices(masterPort, matching, &iterator); if (kr != kIOReturnSuccess) { SCPrint(TRUE, stderr, CFSTR("IOServiceGetMatchingServices() failed, kr = 0x%x\n"), kr); return NULL; } interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); while ((interface = IOIteratorNext(iterator)) != MACH_PORT_NULL) { io_registry_entry_t bus = MACH_PORT_NULL; CFMutableDictionaryRef bus_dict = NULL; io_registry_entry_t controller = MACH_PORT_NULL; CFMutableDictionaryRef controller_dict = NULL; SCNetworkInterfacePrivateRef interfacePrivate = NULL; CFMutableDictionaryRef interface_dict = NULL; io_string_t path; kr = IORegistryEntryGetPath(interface, kIOServicePlane, path); if (kr != kIOReturnSuccess) { SCPrint(TRUE, stderr, CFSTR("IORegistryEntryGetPath() failed, kr = 0x%x"), kr); goto done; } kr = IORegistryEntryCreateCFProperties(interface, &interface_dict, NULL, kNilOptions); if (kr != kIOReturnSuccess) { SCPrint(TRUE, stderr, CFSTR("IORegistryEntryCreateCFProperties() failed, kr = 0x%x\n"), kr); goto done; } /* get the controller node */ kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &controller); if (kr != KERN_SUCCESS) { SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr); goto done; } /* get the dictionary associated with the node */ kr = IORegistryEntryCreateCFProperties(controller, &controller_dict, NULL, kNilOptions); if (kr != KERN_SUCCESS) { SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr); goto done; } /* get the bus node */ kr = IORegistryEntryGetParentEntry(controller, kIOServicePlane, &bus); if (kr != KERN_SUCCESS) { SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr); goto done; } /* get the dictionary associated with the node */ kr = IORegistryEntryCreateCFProperties(bus, &bus_dict, NULL, kNilOptions); if (kr != KERN_SUCCESS) { SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr); goto done; } interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, path); if ((*func)(masterPort, interfacePrivate, interface, interface_dict, controller, controller_dict, bus, bus_dict)) { CFArrayAppendValue(interfaces, (SCNetworkInterfaceRef)interfacePrivate); } CFRelease(interfacePrivate); done: if (interface != MACH_PORT_NULL) IOObjectRelease(interface); if (interface_dict != NULL) CFRelease(interface_dict); if (controller != MACH_PORT_NULL) IOObjectRelease(controller); if (controller_dict != NULL) CFRelease(controller_dict); if (bus != MACH_PORT_NULL) IOObjectRelease(bus); if (bus_dict != NULL) CFRelease(bus_dict); } IOObjectRelease(iterator); return interfaces; } /* ---------- Bond configuration ---------- */ Boolean SCNetworkInterfaceSupportsBonding(SCNetworkInterfaceRef interface) { return ((SCNetworkInterfacePrivateRef)interface)->supportsBond; } SCNetworkInterfaceRef SCNetworkInterfaceCreateWithBond(BondInterfaceRef bond) { SCNetworkInterfacePrivateRef interfacePrivate; CFStringRef bond_if; bond_if = BondInterfaceGetInterface(bond); if (bond_if == NULL) { return NULL; } interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); if (interfacePrivate == NULL) { return NULL; } interfacePrivate->interface_type = kSCNetworkInterfaceTypeBond; interfacePrivate->entity_type = kSCEntNetEthernet; interfacePrivate->entity_hardware = kSCEntNetEthernet; interfacePrivate->entity_device = CFStringCreateCopy(NULL, bond_if); interfacePrivate->builtin = TRUE; interfacePrivate->sort_order = kSortBond; interfacePrivate->localized_key = CFSTR("bond"); interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device); return (SCNetworkInterfaceRef)interfacePrivate; } static CFArrayRef findBondInterfaces(CFStringRef match) { CFMutableArrayRef interfaces = NULL; CFIndex i; CFIndex n; BondPreferencesRef prefs; CFArrayRef bonds = NULL; prefs = BondPreferencesCreate(NULL); if (prefs == NULL) { // if no bonds return NULL; } bonds = BondPreferencesCopyInterfaces(prefs); if (bonds == NULL) { // if no bonds goto done; } n = CFArrayGetCount(bonds); if (n == 0) { // if no bonds goto done; } interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); for (i = 0; i < n; i++) { SCNetworkInterfaceRef interface; BondInterfaceRef bond = CFArrayGetValueAtIndex(bonds, i); CFStringRef bond_if; bond_if = BondInterfaceGetInterface(bond); if (bond_if == NULL) { continue; } if ((match != NULL) && !CFEqual(bond_if, match)) { continue; } interface = SCNetworkInterfaceCreateWithBond(bond); CFArrayAppendValue(interfaces, interface); CFRelease(interface); } done : if (bonds != NULL) CFRelease(bonds); CFRelease(prefs); return interfaces; } /* ---------- VLAN configuration ---------- */ SCNetworkInterfaceRef SCNetworkInterfaceCreateWithVLAN(VLANInterfaceRef vlan) { SCNetworkInterfacePrivateRef interfacePrivate; CFStringRef vlan_if; vlan_if = VLANInterfaceGetInterface(vlan); if (vlan_if == NULL) { return NULL; } interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); if (interfacePrivate == NULL) { return NULL; } interfacePrivate->interface_type = kSCNetworkInterfaceTypeVLAN; interfacePrivate->entity_type = kSCEntNetEthernet; interfacePrivate->entity_hardware = kSCEntNetEthernet; interfacePrivate->entity_device = CFStringCreateCopy(NULL, vlan_if); interfacePrivate->builtin = TRUE; interfacePrivate->sort_order = kSortVLAN; interfacePrivate->localized_key = CFSTR("vlan"); interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device); return (SCNetworkInterfaceRef)interfacePrivate; } static CFArrayRef findVLANInterfaces(CFStringRef match) { CFMutableArrayRef interfaces = NULL; CFIndex i; CFIndex n; VLANPreferencesRef prefs; CFArrayRef vlans = NULL; prefs = VLANPreferencesCreate(NULL); if (prefs == NULL) { // if no VLANs return NULL; } vlans = VLANPreferencesCopyInterfaces(prefs); if (vlans == NULL) { // if no VLANs goto done; } n = CFArrayGetCount(vlans); if (n == 0) { // if no VLANs goto done; } interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); for (i = 0; i < n; i++) { SCNetworkInterfaceRef interface; VLANInterfaceRef vlan = CFArrayGetValueAtIndex(vlans, i); CFStringRef vlan_if; vlan_if = VLANInterfaceGetInterface(vlan); if (vlan_if == NULL) { continue; } if ((match != NULL) && !CFEqual(vlan_if, match)) { continue; } interface = SCNetworkInterfaceCreateWithVLAN(vlan); CFArrayAppendValue(interfaces, interface); CFRelease(interface); } done : if (vlans != NULL) CFRelease(vlans); CFRelease(prefs); return interfaces; } /* ---------- interface from preferences ---------- */ __private_extern__ SCNetworkInterfaceRef __SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, CFDictionaryRef interface_entity, SCNetworkServiceRef service) { SCNetworkInterfacePrivateRef interfacePrivate = NULL; CFStringRef ifDevice; CFStringRef ifSubType; CFStringRef ifType; static mach_port_t masterPort = MACH_PORT_NULL; CFArrayRef matching_interfaces = NULL; if (masterPort == MACH_PORT_NULL) { kern_return_t kr; kr = IOMasterPort(MACH_PORT_NULL, &masterPort); if (kr != KERN_SUCCESS) { return NULL; } } ifType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceType); if (!isA_CFString(ifType)) { return NULL; } ifSubType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceSubType); if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { if (!isA_CFString(ifSubType)) { return NULL; } } ifDevice = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceDeviceName); if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet) || CFEqual(ifType, kSCValNetInterfaceTypeFireWire) || (CFEqual(ifType, kSCValNetInterfaceTypePPP) && CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE))) { char bsdName[IFNAMSIZ + 1]; CFMutableDictionaryRef matching; if (!isA_CFString(ifDevice)) { return NULL; } if (_SC_cfstring_to_cstring(ifDevice, bsdName, sizeof(bsdName), kCFStringEncodingASCII) == NULL) { goto done; } matching = IOBSDNameMatching(masterPort, 0, bsdName); if (matching == NULL) { goto done; } // note: the "matching" dictionary will be consumed by the following matching_interfaces = findMatchingInterfaces(masterPort, matching, processNetworkInterface); } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) { CFDictionaryRef matching; CFStringRef match_keys[2]; CFStringRef match_vals[2]; if (!isA_CFString(ifDevice)) { return NULL; } match_keys[0] = CFSTR(kIOProviderClassKey); match_vals[0] = CFSTR(kIOSerialBSDServiceValue); match_keys[1] = CFSTR(kIOTTYDeviceKey); match_vals[1] = ifDevice; matching = CFDictionaryCreate(NULL, (const void **)match_keys, (const void **)match_vals, sizeof(match_keys)/sizeof(match_keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // note: the "matching" dictionary will be consumed by the following matching_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface); } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypeL2TP)) { interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, kSCNetworkInterfaceTypeL2TP); } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPTP)) { interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, kSCNetworkInterfaceTypePPTP); } else { // XXX do we allow non-Apple variants of PPP??? XXX interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, ifSubType); } } else if (CFEqual(ifType, kSCValNetInterfaceType6to4)) { if (!isA_CFString(ifDevice)) { return NULL; } interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, kSCNetworkInterfaceType6to4); } if (matching_interfaces != NULL) { CFIndex n; n = CFArrayGetCount(matching_interfaces); switch (n) { case 0 : if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) { CFArrayRef bonds; CFArrayRef vlans; bonds = findBondInterfaces(ifDevice); if (bonds != NULL) { if (CFArrayGetCount(bonds) == 1) { interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(bonds, 0); CFRetain(interfacePrivate); } CFRelease(bonds); break; } vlans = findVLANInterfaces(ifDevice); if (vlans != NULL) { if (CFArrayGetCount(vlans) == 1) { interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(vlans, 0); CFRetain(interfacePrivate); } CFRelease(vlans); break; } } break; case 1 : interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0); CFRetain(interfacePrivate); break; default : SCPrint(TRUE, stderr, CFSTR("more than one interface matches %@\n"), ifDevice); if (matching_interfaces != NULL) CFRelease(matching_interfaces); _SCErrorSet(kSCStatusFailed); return NULL; } CFRelease(matching_interfaces); } done : if (interfacePrivate == NULL) { /* * if device not present on this system */ interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); interfacePrivate->entity_type = ifType; interfacePrivate->entity_subtype = ifSubType; interfacePrivate->entity_device = (ifDevice != NULL) ? CFStringCreateCopy(NULL, ifDevice) : NULL; interfacePrivate->entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware); if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) { if ((interfacePrivate->entity_hardware != NULL) && CFEqual(interfacePrivate->entity_hardware, kSCEntNetAirPort)) { interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211; } else { interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; } } else if (CFEqual(ifType, kSCValNetInterfaceTypeFireWire)) { interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire; } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE)) { interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) { if (CFStringHasPrefix(ifDevice, CFSTR("irda"))) { interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA; } else if (CFStringHasPrefix(ifDevice, CFSTR("Bluetooth"))) { interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth; } else { interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem; } } else { // PPTP, L2TP, ... CFRelease(interfacePrivate); interfacePrivate = (SCNetworkInterfacePrivateRef)kSCNetworkInterfaceIPv4; CFRetain(interfacePrivate); } } else { // unknown interface type CFRelease(interfacePrivate); interfacePrivate = NULL; } } if ((interfacePrivate != NULL) && (service != NULL)) { interfacePrivate->service = service; } if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) { SCNetworkInterfaceRef parent; parent = SCNetworkInterfaceCreateWithInterface((SCNetworkInterfaceRef)interfacePrivate, kSCNetworkInterfaceTypePPP); CFRelease(interfacePrivate); interfacePrivate = (SCNetworkInterfacePrivateRef)parent; } return (SCNetworkInterfaceRef)interfacePrivate; } /* ---------- helper functions ---------- */ static CFIndex findConfiguration(CFStringRef interface_type) { CFIndex i; for (i = 0; i < sizeof(configurations)/sizeof(configurations[0]); i++) { if (CFEqual(interface_type, *configurations[i].interface_type)) { return i; } } return kCFNotFound; } static CFArrayRef copyConfigurationPaths(SCNetworkInterfacePrivateRef interfacePrivate) { CFMutableArrayRef array = NULL; CFIndex interfaceIndex; CFStringRef path; SCNetworkServicePrivateRef servicePrivate; interfaceIndex = findConfiguration(interfacePrivate->interface_type); if (interfaceIndex == kCFNotFound) { // if unknown interface type return NULL; } servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service; if (servicePrivate == NULL) { // if not associated with a service (yet) return NULL; } array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (configurations[interfaceIndex].per_interface_config) { CFIndex i; CFIndex n; CFArrayRef sets; /* * per-interface configuration preferences * * 1. look for all sets which contain the associated service * 2. add a per-set path for the interface configuration for * each set. */ sets = SCNetworkSetCopyAll(servicePrivate->prefs); n = (sets != NULL) ? CFArrayGetCount(sets) : 0; for (i = 0; i < n; i++) { CFArrayRef services; SCNetworkSetRef set; set = CFArrayGetValueAtIndex(sets, i); services = SCNetworkSetCopyServices(set); if (CFArrayContainsValue(services, CFRangeMake(0, CFArrayGetCount(services)), interfacePrivate->service)) { path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator SCNetworkSetGetSetID(set), // set interfacePrivate->entity_device, // service interfacePrivate->entity_type); // entity CFArrayAppendValue(array, path); CFRelease(path); } CFRelease(services); } if (CFArrayGetCount(array) == 0) { CFRelease(array); array = NULL; } CFRelease(sets); } else { // per-service configuration preferences path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service interfacePrivate->entity_type); // entity CFArrayAppendValue(array, path); CFRelease(path); } return array; } /* ---------- SCNetworkInterface APIs ---------- */ CFArrayRef /* of SCNetworkInterfaceRef's */ SCNetworkInterfaceCopyAll() { CFMutableArrayRef all_interfaces; static mach_port_t masterPort = MACH_PORT_NULL; CFDictionaryRef matching; CFStringRef match_keys[2]; CFStringRef match_vals[2]; CFArrayRef new_interfaces; if (masterPort == MACH_PORT_NULL) { kern_return_t kr; kr = IOMasterPort(MACH_PORT_NULL, &masterPort); if (kr != KERN_SUCCESS) { return NULL; } } all_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); // get Ethernet, Firewire, and AirPort interfaces matching = IOServiceMatching(kIONetworkInterfaceClass); new_interfaces = findMatchingInterfaces(masterPort, matching, processNetworkInterface); if (new_interfaces != NULL) { CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces))); CFRelease(new_interfaces); } // get Modem interfaces match_keys[0] = CFSTR(kIOProviderClassKey); match_vals[0] = CFSTR(kIOSerialBSDServiceValue); match_keys[1] = CFSTR(kIOSerialBSDTypeKey); match_vals[1] = CFSTR(kIOSerialBSDModemType); matching = CFDictionaryCreate(NULL, (const void **)match_keys, (const void **)match_vals, sizeof(match_keys)/sizeof(match_keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); new_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface); if (new_interfaces != NULL) { CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces))); CFRelease(new_interfaces); } // get serial (RS232) interfaces match_keys[0] = CFSTR(kIOProviderClassKey); match_vals[0] = CFSTR(kIOSerialBSDServiceValue); match_keys[1] = CFSTR(kIOSerialBSDTypeKey); match_vals[1] = CFSTR(kIOSerialBSDRS232Type); matching = CFDictionaryCreate(NULL, (const void **)match_keys, (const void **)match_vals, sizeof(match_keys)/sizeof(match_keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); new_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface); if (new_interfaces != NULL) { CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces))); CFRelease(new_interfaces); } new_interfaces = findBondInterfaces(NULL); if (new_interfaces != NULL) { CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces))); CFRelease(new_interfaces); } new_interfaces = findVLANInterfaces(NULL); if (new_interfaces != NULL) { CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces))); CFRelease(new_interfaces); } sort_interfaces(all_interfaces); return all_interfaces; } CFArrayRef /* of kSCNetworkInterfaceTypeXXX CFStringRef's */ SCNetworkInterfaceGetSupportedInterfaceTypes(SCNetworkInterfaceRef interface) { CFIndex i; SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; if (interfacePrivate->supported_interface_types != NULL) { goto done; } /* initialize runtime (and kSCNetworkInterfaceIPv4) */ pthread_once(&initialized, __SCNetworkInterfaceInitialize); i = findConfiguration(interfacePrivate->interface_type); if (i != kCFNotFound) { if (configurations[i].supported_interfaces != doNone) { interfacePrivate->supported_interface_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (configurations[i].supported_interfaces & do6to4) { CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceType6to4); } if (configurations[i].supported_interfaces & doL2TP) { CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeL2TP); } if (configurations[i].supported_interfaces & doPPP) { CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPP); } if (configurations[i].supported_interfaces & doPPTP) { CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPTP); } } } done : return interfacePrivate->supported_interface_types; } CFArrayRef /* of kSCNetworkProtocolTypeXXX CFStringRef's */ SCNetworkInterfaceGetSupportedProtocolTypes(SCNetworkInterfaceRef interface) { CFIndex i; SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; if (interfacePrivate->supported_protocol_types != NULL) { goto done; } /* initialize runtime (and kSCNetworkInterfaceIPv4) */ pthread_once(&initialized, __SCNetworkInterfaceInitialize); i = findConfiguration(interfacePrivate->interface_type); if (i != kCFNotFound) { if (configurations[i].supported_protocols != doNone) { interfacePrivate->supported_protocol_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (configurations[i].supported_protocols & doAppleTalk) { CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeAppleTalk); } if (configurations[i].supported_protocols & doDNS) { CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeDNS); } if (configurations[i].supported_protocols & doIPv4) { CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv4); } if (configurations[i].supported_protocols & doIPv6) { CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv6); } if (configurations[i].supported_protocols & doProxies) { CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeProxies); } } } done : return interfacePrivate->supported_protocol_types; } SCNetworkInterfaceRef SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef interfaceType) { SCNetworkInterfacePrivateRef childPrivate = (SCNetworkInterfacePrivateRef)child; CFIndex childIndex; SCNetworkInterfacePrivateRef parentPrivate; /* initialize runtime (and kSCNetworkInterfaceIPv4) */ pthread_once(&initialized, __SCNetworkInterfaceInitialize); childIndex = findConfiguration(childPrivate->interface_type); parentPrivate = __SCNetworkInterfaceCreatePrivate(NULL, child, childPrivate->service, NULL); if (parentPrivate == NULL) { _SCErrorSet(kSCStatusFailed); return NULL; } if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) { parentPrivate->interface_type = kSCNetworkInterfaceTypePPP; parentPrivate->entity_type = kSCEntNetPPP; // entity subtype if (childIndex != kCFNotFound) { if (configurations[childIndex].ppp_subtype != NULL) { parentPrivate->entity_subtype = *configurations[childIndex].ppp_subtype; } else { // sorry, the child interface does not support PPP goto fail; } } else { // if the child's interface type not known, use the child entities "Type" parentPrivate->entity_subtype = childPrivate->entity_type; } if (childPrivate->entity_device != NULL) { parentPrivate->entity_device = CFStringCreateCopy(NULL, childPrivate->entity_device); } } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) { if ((childIndex == kCFNotFound) || ((configurations[childIndex].supported_interfaces & doL2TP) != doL2TP)) { // if the child interface does not support L2TP goto fail; } parentPrivate->interface_type = kSCNetworkInterfaceTypeL2TP; parentPrivate->entity_type = kSCValNetInterfaceSubTypeL2TP; // interface config goes into "L2TP" } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) { if ((childIndex == kCFNotFound) || ((configurations[childIndex].supported_interfaces & doPPTP) != doPPTP)) { // if the child interface does not support PPTP goto fail; } parentPrivate->interface_type = kSCNetworkInterfaceTypePPTP; parentPrivate->entity_type = kSCValNetInterfaceSubTypePPTP; // interface config goes into "PPTP" } else if (CFEqual(interfaceType, kSCNetworkInterfaceType6to4)) { if ((childIndex == kCFNotFound) || ((configurations[childIndex].supported_interfaces & do6to4) != do6to4)) { // if the child interface does not support 6to4 goto fail; } parentPrivate->interface_type = kSCNetworkInterfaceType6to4; parentPrivate->entity_type = kSCEntNet6to4; parentPrivate->entity_device = CFRetain(CFSTR("stf0")); CFRetain(parentPrivate->entity_device); } else { // unknown interface type goto fail; } parentPrivate->entity_hardware = childPrivate->entity_hardware; parentPrivate->sort_order = childPrivate->sort_order; return (SCNetworkInterfaceRef)parentPrivate; fail : CFRelease(parentPrivate); _SCErrorSet(kSCStatusInvalidArgument); return NULL; } static CFDictionaryRef __SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface, Boolean okToHold) { CFDictionaryRef config = NULL; SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; CFArrayRef paths; /* initialize runtime (and kSCNetworkInterfaceIPv4) */ pthread_once(&initialized, __SCNetworkInterfaceInitialize); paths = copyConfigurationPaths(interfacePrivate); if (paths != NULL) { CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service; path = CFArrayGetValueAtIndex(paths, 0); config = __getPrefsConfiguration(servicePrivate->prefs, path); CFRelease(paths); } else if (okToHold) { config = interfacePrivate->unsaved; } return config; } CFDictionaryRef SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface) { return __SCNetworkInterfaceGetConfiguration(interface, FALSE); } CFStringRef SCNetworkInterfaceGetBSDName(SCNetworkInterfaceRef interface) { SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; if (interfacePrivate->interface != NULL) { return NULL; } return interfacePrivate->entity_device; } CFStringRef SCNetworkInterfaceGetHardwareAddressString(SCNetworkInterfaceRef interface) { SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; return interfacePrivate->address; } SCNetworkInterfaceRef SCNetworkInterfaceGetInterface(SCNetworkInterfaceRef interface) { SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; return interfacePrivate->interface; } CFStringRef SCNetworkInterfaceGetInterfaceType(SCNetworkInterfaceRef interface) { SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; /* initialize runtime (and kSCNetworkInterfaceIPv4) */ pthread_once(&initialized, __SCNetworkInterfaceInitialize); return interfacePrivate->interface_type; } CFStringRef SCNetworkInterfaceGetLocalizedDisplayName(SCNetworkInterfaceRef interface) { SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; if (interfacePrivate->localized_name == NULL) { CFStringRef child = NULL; CFMutableStringRef local = NULL; pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* initialize runtime */ if (interfacePrivate->interface != NULL) { child = SCNetworkInterfaceGetLocalizedDisplayName(interfacePrivate->interface); } if (interfacePrivate->localized_key != NULL) { CFStringRef fmt; fmt = CFBundleCopyLocalizedString(bundle, interfacePrivate->localized_key, interfacePrivate->localized_key, NETWORKINTERFACE_LOCALIZATIONS); if (fmt != NULL) { local = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(local, NULL, fmt, interfacePrivate->localized_arg1, interfacePrivate->localized_arg2); CFRelease(fmt); } } if (local == NULL) { // create (non-)localized name based on the interface type local = CFStringCreateMutableCopy(NULL, 0, interfacePrivate->interface_type); // ... and, if this is a leaf node, the interface device if ((interfacePrivate->entity_device != NULL) && (child == NULL)) { CFStringAppendFormat(local, NULL, CFSTR(" (%@)"), interfacePrivate->entity_device); } } if (child == NULL) { // no child, show just this interfaces localized name interfacePrivate->localized_name = CFStringCreateCopy(NULL, local); } else { // show localized interface name layered over child interfacePrivate->localized_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ --> %@"), local, child); } CFRelease(local); } return interfacePrivate->localized_name; } CFTypeID SCNetworkInterfaceGetTypeID(void) { pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* initialize runtime */ return __kSCNetworkInterfaceTypeID; } __private_extern__ Boolean __SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config, Boolean okToHold) { SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; Boolean ok = FALSE; CFArrayRef paths; /* initialize runtime (and kSCNetworkInterfaceIPv4) */ pthread_once(&initialized, __SCNetworkInterfaceInitialize); paths = copyConfigurationPaths(interfacePrivate); if (paths != NULL) { CFIndex i; CFIndex n; SCPreferencesRef prefs; SCNetworkServicePrivateRef servicePrivate; servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service; prefs = servicePrivate->prefs; n = CFArrayGetCount(paths); for (i = 0; i < n; i++) { CFStringRef path; path = CFArrayGetValueAtIndex(paths, i); ok = __setPrefsConfiguration(prefs, path, config, FALSE); if (!ok) { break; } } CFRelease(paths); } else if (okToHold) { interfacePrivate->unsaved = config; ok = TRUE; } else { _SCErrorSet(kSCStatusNoKey); } return ok; } Boolean SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config) { return __SCNetworkInterfaceSetConfiguration(interface, config, FALSE); } /* ---------- SCNetworkInterface internal SPIs ---------- */ __private_extern__ SCNetworkInterfacePrivateRef __SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator, SCNetworkInterfaceRef interface, SCNetworkServiceRef service) { SCNetworkInterfacePrivateRef oldPrivate = (SCNetworkInterfacePrivateRef)interface; SCNetworkInterfacePrivateRef newPrivate; newPrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL); newPrivate->interface_type = CFRetain(oldPrivate->interface_type); if (oldPrivate->interface != NULL) { newPrivate->interface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL, // allocator oldPrivate->interface, // interface service); // [new] service } newPrivate->localized_name = (oldPrivate->localized_name != NULL) ? CFRetain(oldPrivate->localized_name) : NULL; newPrivate->service = service; newPrivate->unsaved = (oldPrivate->unsaved != NULL) ? CFRetain(oldPrivate->unsaved) : NULL; newPrivate->entity_device = (oldPrivate->entity_device != NULL) ? CFRetain(oldPrivate->entity_device) : NULL; newPrivate->entity_hardware = CFRetain(oldPrivate->entity_hardware); newPrivate->entity_type = oldPrivate->entity_type; newPrivate->entity_subtype = oldPrivate->entity_subtype; if (oldPrivate->supported_interface_types != NULL) { newPrivate->supported_interface_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_interface_types); } if (oldPrivate->supported_protocol_types != NULL) { newPrivate->supported_protocol_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_protocol_types); } newPrivate->address = (oldPrivate->address != NULL) ? CFRetain(oldPrivate->address) : NULL; newPrivate->builtin = oldPrivate->builtin; newPrivate->path = (oldPrivate->path != NULL) ? CFRetain(oldPrivate->path) : NULL; newPrivate->location = (oldPrivate->location != NULL) ? CFRetain(oldPrivate->location) : NULL; newPrivate->supportsDeviceOnHold = oldPrivate->supportsDeviceOnHold; newPrivate->supportsBond = oldPrivate->supportsBond; newPrivate->supportsVLAN = oldPrivate->supportsVLAN; newPrivate->sort_order = oldPrivate->sort_order; return newPrivate; } __private_extern__ CFArrayRef __SCNetworkInterfaceCopyDeepConfiguration(SCNetworkInterfaceRef interface) { CFDictionaryRef config; CFMutableArrayRef configs; configs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); while (interface != NULL) { config = __SCNetworkInterfaceGetConfiguration(interface, TRUE); CFArrayAppendValue(configs, (config != NULL) ? config : (CFDictionaryRef)kCFNull); interface = SCNetworkInterfaceGetInterface(interface); } return configs; } __private_extern__ void __SCNetworkInterfaceSetDeepConfiguration(SCNetworkInterfaceRef interface, CFArrayRef configs) { CFIndex i; for (i = 0; interface != NULL; i++) { CFDictionaryRef config; config = (configs != NULL) ? CFArrayGetValueAtIndex(configs, i) : NULL; if (!isA_CFDictionary(config) || (CFDictionaryGetCount(config) == 0)) { config = NULL; } (void) __SCNetworkInterfaceSetConfiguration(interface, config, TRUE); interface = SCNetworkInterfaceGetInterface(interface); } return; }