+ interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
+ interfacePrivate->active = CFBooleanGetValue(active);
+ interfacePrivate->entity_device = CFRetain(bsdName);
+ interfacePrivate->builtin = CFBooleanGetValue(ioBuiltin);
+ interfacePrivate->prefix = CFRetain(ioInterfaceNamePrefix);
+ interfacePrivate->type = CFRetain(ioInterfaceType);
+ interfacePrivate->unit = CFRetain(ioInterfaceUnit);
+ interfacePrivate->address = CFRetain(ioMACAddress);
+ interfacePrivate->path = CFRetain(ioPathMatch);
+ interfacePrivate->name = ((userDefinedName != NULL) ? CFRetain(userDefinedName) : NULL);
+ interfacePrivate->localized_name = ((userDefinedName != NULL) ? CFRetain(userDefinedName) : NULL);
+ interfacePrivate->usb.name = ((usbProductName != NULL) ? CFRetain(usbProductName) : NULL);
+ interfacePrivate->usb.pid = ((idProduct != NULL) ? CFRetain(idProduct) : NULL);
+ interfacePrivate->usb.vid = ((idVendor != NULL) ? CFRetain(idVendor) : NULL);
+
+ // Handling interface types to be seen in NetworkInterfaces.plist
+ CFIndex interfaceIndex;
+
+ interfaceIndex = findConfiguration(type);
+ if (interfaceIndex != kCFNotFound) {
+ interfacePrivate->interface_type = *configurations[interfaceIndex].interface_type;
+ } else {
+ interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
+ }
+
+ // Extracting entity type from value of interface type
+ if (ioInterfaceTypeNum == kInterfaceTypeEthernetValue) {
+ interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; // kSCNetworkInterfaceTypeEthernet;
+ } else if (ioInterfaceTypeNum == kInterfaceTypeFirewireValue) {
+ interfacePrivate->entity_type = kSCValNetInterfaceTypeFireWire;
+ }
+done:
+ if (ioInterfaceNamePrefix != NULL) {
+ CFRelease(ioInterfaceNamePrefix);
+ }
+
+ return (SCNetworkInterfaceRef)interfacePrivate;
+}
+
+
+__private_extern__
+void
+_SCNetworkInterfaceCacheOpen(void)
+{
+ if (!__SCNetworkInterfaceCacheIsOpen()) {
+ S_interface_cache = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ SC_log(LOG_DEBUG, "SCNetworkInterface cache (%p): open", S_interface_cache);
+ }
+}
+
+
+__private_extern__
+void
+_SCNetworkInterfaceCacheClose(void)
+{
+ if (__SCNetworkInterfaceCacheIsOpen()) {
+ SC_log(LOG_DEBUG, "SCNetworkInterface cache (%p): close", S_interface_cache);
+ CFRelease(S_interface_cache);
+ S_interface_cache = NULL;
+ }
+}
+
+
+static void
+__SCNetworkInterfaceCacheAdd(CFStringRef bsdName, CFArrayRef matchingInterfaces)
+{
+ if (__SCNetworkInterfaceCacheIsOpen() &&
+ bsdName != NULL &&
+ matchingInterfaces != NULL) {
+ SC_log(LOG_DEBUG, "SCNetworkInterface cache (%p): add %@", S_interface_cache, bsdName);
+ CFDictionaryAddValue(S_interface_cache, bsdName, matchingInterfaces);
+ }
+}
+
+
+static inline Boolean
+__SCNetworkInterfaceCacheIsOpen(void)
+{
+ return (S_interface_cache != NULL);
+}
+
+
+static CFArrayRef
+__SCNetworkInterfaceCacheCopy(CFStringRef bsdName)
+{
+ if (__SCNetworkInterfaceCacheIsOpen() &&
+ bsdName != NULL) {
+ CFArrayRef matchingInterfaces = CFDictionaryGetValue(S_interface_cache, bsdName);
+ if (matchingInterfaces) {
+ CFRetain(matchingInterfaces);
+ SC_log(LOG_DEBUG, "SCNetworkInterface cache (%p): copy w/ match for %@", S_interface_cache, bsdName);
+ } else {
+ SC_log(LOG_DEBUG, "SCNetworkInterface cache (%p): copy w/ no match for %@", S_interface_cache, bsdName);
+ }
+
+ return matchingInterfaces;
+ }
+
+ return NULL;
+}
+
+
+SCNetworkInterfaceRef
+_SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator,
+ CFDictionaryRef interface_entity,
+ SCNetworkServiceRef service)
+{
+#pragma unused(allocator)
+ SCNetworkInterfacePrivateRef interfacePrivate = NULL;
+ CFStringRef ifDevice;
+ CFStringRef ifName = NULL;
+ CFStringRef ifSubType;
+ CFStringRef ifType;
+ CFStringRef ifUnique;
+ CFArrayRef matching_interfaces = NULL;
+ SCPreferencesRef servicePref = NULL;
+ Boolean useSystemInterfaces = TRUE;
+
+ /* initialize runtime (and kSCNetworkInterfaceIPv4) */
+ pthread_once(&initialized, __SCNetworkInterfaceInitialize);
+
+ if (service != NULL) {
+ servicePref = ((SCNetworkServicePrivateRef)service)->prefs;
+ useSystemInterfaces = ((__SCPreferencesUsingDefaultPrefs(servicePref)) &&
+ (!__SCPreferencesGetLimitSCNetworkConfiguration(servicePref)));
+ }
+
+ ifType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceType);
+ if (ifType == NULL) {
+ /*
+ * The interface "Type" was not specified. We'll make an
+ * assumption that this is an "Ethernet" interface. If a
+ * real interface exists with the provided interface name
+ * then the actual type will be set accordingly. If not, we'll
+ * end up crafting an "Ethernet" SCNetworkInterface that
+ * will keep the rest of the configuration APIs happy.
+ */
+ ifType = kSCValNetInterfaceTypeEthernet;
+ }
+
+ if (!isA_CFString(ifType)) {
+ return NULL;
+ }
+
+ ifSubType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceSubType);
+ if (CFEqual(ifType, kSCValNetInterfaceTypePPP) ||
+ CFEqual(ifType, kSCValNetInterfaceTypeVPN)) {
+ if (!isA_CFString(ifSubType)) {
+ return NULL;
+ }
+ }
+
+ ifDevice = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceDeviceName);
+ ifUnique = CFDictionaryGetValue(interface_entity, CFSTR("DeviceUniqueIdentifier"));
+
+ if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet) ||
+ CFEqual(ifType, kSCValNetInterfaceTypeFireWire) ||
+ (CFEqual(ifType, kSCValNetInterfaceTypePPP) && CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE))) {
+ char bsdName[IFNAMSIZ];
+ CFMutableDictionaryRef matching;
+
+ if (!isA_CFString(ifDevice)) {
+ return NULL;
+ }
+
+ if (CFEqual(ifDevice, CFSTR("lo0"))) { // for _SCNetworkInterfaceCreateWithBSDName
+ interfacePrivate = __SCNetworkInterfaceCreateCopy(NULL, kSCNetworkInterfaceLoopback, NULL, NULL);
+ goto done;
+ }
+ if (useSystemInterfaces) {
+ // Check to see if we already have the info in the cache
+ matching_interfaces = __SCNetworkInterfaceCacheCopy(ifDevice);
+ if (matching_interfaces == NULL) {
+ if (_SC_cfstring_to_cstring(ifDevice, bsdName, sizeof(bsdName), kCFStringEncodingASCII) == NULL) {
+ goto done;
+ }
+
+ matching = IOBSDNameMatching(masterPort, 0, bsdName);
+ if (matching == NULL) {
+ goto done;
+ }
+ matching_interfaces = findMatchingInterfaces(matching,
+ processNetworkInterface,
+ kSCNetworkInterfaceHiddenInterfaceKey,
+ TRUE);
+
+ __SCNetworkInterfaceCacheAdd(ifDevice, matching_interfaces);
+ CFRelease(matching);
+ }
+ }
+ } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
+ if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) {
+ CFDictionaryRef matching;
+ CFStringRef match_keys[2];
+ CFStringRef match_vals[2];
+
+ if (!isA_CFString(ifDevice)) {
+ return NULL;
+ }
+
+ if (useSystemInterfaces) {
+ match_keys[0] = CFSTR(kIOProviderClassKey);
+ match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
+
+ match_keys[1] = CFSTR(kIOTTYBaseNameKey);
+ match_vals[1] = ifDevice;
+
+ matching = CFDictionaryCreate(NULL,
+ (const void **)match_keys,
+ (const void **)match_vals,
+ sizeof(match_keys)/sizeof(match_keys[0]),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ matching_interfaces = findMatchingInterfaces(matching,
+ processSerialInterface,
+ kSCNetworkInterfaceHiddenPortKey,
+ TRUE);
+ CFRelease(matching);
+ }
+ if (ifUnique == NULL) {
+ CFIndex n;
+ Boolean useDeviceName = TRUE;
+
+ n = (matching_interfaces != NULL) ? CFArrayGetCount(matching_interfaces) : 0;
+ if (n > 0) {
+ CFIndex i;
+
+ for (i = 0; i < n; i++) {
+ SCNetworkInterfacePrivateRef scanPrivate;
+
+ scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i);
+ if (scanPrivate->entity_device_unique != NULL) {
+ useDeviceName = FALSE;
+ break;
+ }
+ }
+ }
+
+ if (useDeviceName && useSystemInterfaces) {
+ if (matching_interfaces != NULL) {
+ CFRelease(matching_interfaces);
+ }
+
+ match_keys[1] = CFSTR(kIOTTYDeviceKey);
+ matching = CFDictionaryCreate(NULL,
+ (const void **)match_keys,
+ (const void **)match_vals,
+ sizeof(match_keys)/sizeof(match_keys[0]),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ matching_interfaces = findMatchingInterfaces(matching,
+ processSerialInterface,
+ kSCNetworkInterfaceHiddenPortKey,
+ TRUE);
+ CFRelease(matching);
+ }
+ }
+ } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypeL2TP)) {
+ interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
+ kSCNetworkInterfaceTypeL2TP);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated"
+ } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPTP)) {
+ interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
+ kSCNetworkInterfaceTypePPTP);
+#pragma GCC diagnostic pop
+ } else {
+ // XXX do we allow non-Apple variants of PPP??? XXX
+ interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
+ ifSubType);
+ }
+ } else if (CFEqual(ifType, kSCValNetInterfaceType6to4)) {
+ if (!isA_CFString(ifDevice)) {
+ return NULL;
+ }
+
+ interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
+ kSCNetworkInterfaceType6to4);
+ } else if (CFEqual(ifType, kSCValNetInterfaceTypeIPSec)) {
+ interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
+ kSCNetworkInterfaceTypeIPSec);
+ } else if (CFEqual(ifType, kSCValNetInterfaceTypeLoopback)) {
+ interfacePrivate = __SCNetworkInterfaceCreateCopy(NULL, kSCNetworkInterfaceLoopback, NULL, NULL);
+ } else if (CFEqual(ifType, kSCValNetInterfaceTypeVPN)) {
+ if (CFStringFind(ifSubType, CFSTR("."), 0).location != kCFNotFound) {
+ interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
+ ifSubType);
+ }
+ } else if ((CFStringFind(ifType, CFSTR("."), 0).location != kCFNotFound) && (ifDevice == NULL)) {
+ interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
+ ifType);
+ }
+
+ if (matching_interfaces != NULL) {
+ CFIndex n;
+ SCPreferencesRef prefs;
+ Boolean temp_preferences = FALSE;
+
+ n = CFArrayGetCount(matching_interfaces);
+ switch (n) {
+ case 1 :
+ interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0);
+ if (_SC_CFEqual(ifUnique, interfacePrivate->entity_device_unique)) {
+ // if the unique ID's match
+ CFRetain(interfacePrivate);
+ break;
+ }
+
+ interfacePrivate = NULL;
+ // fall through
+ case 0 :
+ if (!CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) {
+ break;
+ }
+
+ if (CFDictionaryGetValueIfPresent(interface_entity,
+ kSCPropUserDefinedName,
+ (const void **)&ifName) &&
+ CFEqual(ifName, CFSTR(BT_PAN_NAME))) {
+ break;
+ }
+
+ prefs = (service != NULL) ? ((SCNetworkServicePrivateRef)service)->prefs : NULL;
+ if (prefs == NULL) {
+ prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterface"), NULL);
+ if (prefs != NULL) {
+ temp_preferences = TRUE;
+ }
+ }
+ if (prefs == NULL) {
+ break;
+ }
+#if !TARGET_OS_IPHONE
+ if (!CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BOND_INTERFACES_"))) {
+ interfacePrivate = (SCNetworkInterfacePrivateRef)findBondInterface(prefs, ifDevice);
+ }
+#endif // !TARGET_OS_IPHONE
+ if ((interfacePrivate == NULL)
+ && !CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BRIDGE_INTERFACES_"))) {
+ interfacePrivate = (SCNetworkInterfacePrivateRef)findBridgeInterface(prefs, ifDevice);
+ }
+
+ if ((interfacePrivate == NULL)
+ && !CFDictionaryContainsKey(interface_entity, CFSTR("_NO_VLAN_INTERFACES_"))) {
+ interfacePrivate = (SCNetworkInterfacePrivateRef)findVLANInterface(prefs, ifDevice);
+ }
+ if (temp_preferences) CFRelease(prefs);
+ break;
+ default :
+ if (ifUnique != NULL) {
+ CFIndex i;
+
+ // we are looking for an interface with a unique ID
+ // so let's try to focus our choices
+ for (i = 0; i < n; i++) {
+ SCNetworkInterfacePrivateRef scanPrivate;
+
+ scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i);
+ if (_SC_CFEqual(ifUnique, scanPrivate->entity_device_unique)) {
+ if (interfacePrivate != NULL) {
+ // if we've matched more than one interface
+ interfacePrivate = NULL;
+ break;
+ }
+ interfacePrivate = scanPrivate;
+ }
+ }
+ } else if (CFDictionaryGetValueIfPresent(interface_entity,
+ kSCPropUserDefinedName,
+ (const void **)&ifName)) {
+ CFIndex i;
+
+ // we don't have a unique ID but do have an interface
+ // name. If the matching interfaces do have IDs than
+ // we can try to focus our choices using the name
+ for (i = 0; i < n; i++) {
+ SCNetworkInterfacePrivateRef scanPrivate;
+
+ scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i);
+ if (scanPrivate->entity_device_unique != NULL) {
+ SCNetworkInterfaceRef scan = (SCNetworkInterfaceRef)scanPrivate;
+ CFStringRef scanName;
+
+ scanName = __SCNetworkInterfaceGetNonLocalizedDisplayName(scan);
+ if ((scanName != NULL) && !_SC_CFEqual(ifName, scanName)) {
+ continue; // if not the same display name
+ }
+ }
+
+ if (interfacePrivate != NULL) {
+ // if we've matched more than one interface
+ interfacePrivate = NULL;
+ break;
+ }
+ interfacePrivate = scanPrivate;
+ }
+ }
+ if (interfacePrivate == NULL) {
+ SC_log(LOG_NOTICE, "more than one interface matches %@", ifDevice);
+ interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0);
+ }
+ CFRetain(interfacePrivate);
+ break;
+ }
+ CFRelease(matching_interfaces);
+ }
+
+ done :
+
+ if ((interfacePrivate == NULL) || !useSystemInterfaces) {
+ /*
+ * if device not present on this system
+ */
+ if (!useSystemInterfaces) {
+ if (interfacePrivate != NULL) {
+ CFRelease(interfacePrivate);
+ }
+ }
+
+ interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
+ interfacePrivate->entity_type = (ifType != NULL) ? ifType : NULL;
+ interfacePrivate->entity_subtype = (ifSubType != NULL) ? ifSubType : NULL;
+ interfacePrivate->entity_device = (ifDevice != NULL) ? CFStringCreateCopy(NULL, ifDevice) : NULL;
+ interfacePrivate->entity_device_unique = (ifUnique != NULL) ? CFStringCreateCopy(NULL, ifUnique) : NULL;
+
+ // Using UserDefinedName to check the validity of preferences file
+ // when useSystemInterfaces is FALSE
+ if (!useSystemInterfaces) {
+ CFStringRef userDefinedName = CFDictionaryGetValue(interface_entity, kSCPropUserDefinedName);
+ if (isA_CFString(userDefinedName) != NULL) {
+ CFRetain(userDefinedName);
+ if (interfacePrivate->name != NULL) {
+ CFRelease(interfacePrivate->name);
+ }
+ interfacePrivate->name = userDefinedName;
+
+ CFRetain(userDefinedName);
+ if (interfacePrivate->localized_name != NULL) {
+ CFRelease(interfacePrivate->localized_name);
+ }
+ interfacePrivate->localized_name = userDefinedName;
+ }
+ }
+
+ if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) {
+ CFStringRef entity_hardware;
+ SCNetworkInterfaceRef virtualInterface;
+
+ if (!useSystemInterfaces &&
+ (((virtualInterface = findBridgeInterface(servicePref, ifDevice)) != NULL) ||
+#if !TARGET_OS_IPHONE
+ ((virtualInterface = findBondInterface(servicePref, ifDevice)) != NULL) ||
+#endif // !TARGET_OS_IPHONE
+ ((virtualInterface = findVLANInterface(servicePref, ifDevice)) != NULL))) {
+ CFRelease(interfacePrivate);
+ interfacePrivate = (SCNetworkInterfacePrivateRef)virtualInterface;
+ } else {
+ entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware);
+ if (isA_CFString((entity_hardware)) &&
+ CFEqual(entity_hardware, kSCEntNetAirPort)) {
+ interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
+ interfacePrivate->localized_key = CFSTR("airport");
+ interfacePrivate->sort_order = kSortAirPort;
+ } else {
+ CFStringRef name;
+
+ interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
+
+ name = CFDictionaryGetValue(interface_entity, kSCPropUserDefinedName);
+ if (__SCNetworkInterfaceMatchesName(name, CFSTR("iPhone"))) {
+ interfacePrivate->localized_key = CFSTR("iPhone");
+ interfacePrivate->sort_order = kSortTethered;
+ } else if (__SCNetworkInterfaceMatchesName(name, CFSTR("iPad"))) {
+ interfacePrivate->localized_key = CFSTR("iPad");
+ interfacePrivate->sort_order = kSortTethered;
+ } else if (__SCNetworkInterfaceMatchesName(name, CFSTR("thunderbolt"))) {
+ interfacePrivate->localized_key = CFSTR("thunderbolt");
+ interfacePrivate->sort_order = kSortThunderbolt;
+ } else if (__SCNetworkInterfaceMatchesName(name, CFSTR("bluetooth-pan-gn"))) {
+ interfacePrivate->localized_key = CFSTR("bluetooth-pan-gn");
+ interfacePrivate->sort_order = kSortBluetoothPAN_GN;
+ } else if (__SCNetworkInterfaceMatchesName(name, CFSTR("bluetooth-pan-nap"))) {
+ interfacePrivate->localized_key = CFSTR("bluetooth-pan-nap");
+ interfacePrivate->sort_order = kSortBluetoothPAN_NAP;
+ } else if (__SCNetworkInterfaceMatchesName(name, CFSTR("bluetooth-pan-u"))) {
+ interfacePrivate->localized_key = CFSTR("bluetooth-pan-u");
+ interfacePrivate->sort_order = kSortBluetoothPAN_U;
+ } else {
+ interfacePrivate->sort_order = kSortEthernet;
+ }
+ }
+ }
+ } else if (CFEqual(ifType, kSCValNetInterfaceTypeFireWire)) {
+ interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire;
+ interfacePrivate->sort_order = kSortFireWire;
+ } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP) && (ifSubType != NULL)) {
+ if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE)) {
+ CFStringRef entity_hardware;
+
+ entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware);
+ if (isA_CFString((entity_hardware)) &&
+ CFEqual(entity_hardware, kSCEntNetAirPort)) {
+ interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
+ interfacePrivate->sort_order = kSortAirPort;
+ } else {
+ interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
+ interfacePrivate->sort_order = kSortEthernet;
+ }
+ } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) {
+ if (CFStringHasPrefix(ifDevice, CFSTR("Bluetooth"))) {
+ interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth;
+ interfacePrivate->sort_order = kSortBluetooth;
+ } else if (CFStringHasPrefix(ifDevice, CFSTR("irda"))) {
+ interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA;
+ interfacePrivate->sort_order = kSortIrDA;
+ } else if (CFStringHasPrefix(ifDevice, CFSTR("wwan"))) {
+ interfacePrivate->interface_type = kSCNetworkInterfaceTypeWWAN;
+ interfacePrivate->sort_order = kSortWWAN;
+ } else {
+ interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem;
+ interfacePrivate->sort_order = kSortModem;
+ }
+ } else {
+ SCNetworkInterfaceRef child;
+ // PPTP, L2TP, ...
+ CFRelease(interfacePrivate);
+ child = SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, ifSubType);
+ interfacePrivate = (SCNetworkInterfacePrivateRef)child;
+ if (interfacePrivate == NULL) {
+ return NULL;
+ }
+ }
+ } else if (CFEqual(ifType, kSCValNetInterfaceTypeVPN) && (ifSubType != NULL)) {
+ SCNetworkInterfaceRef child;
+ CFRelease(interfacePrivate);
+ child = SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, ifSubType);
+ interfacePrivate = (SCNetworkInterfacePrivateRef)child;
+ if (interfacePrivate == NULL) {
+ return NULL;
+ }
+ } else if (CFEqual(ifType, kSCValNetInterfaceTypeIPSec)) {
+ CFRelease(interfacePrivate);
+ interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
+ kSCNetworkInterfaceTypeIPSec);
+ } else if (CFEqual(ifType, kSCValNetInterfaceType6to4)) {
+ CFRelease(interfacePrivate);
+ if (!isA_CFString(ifDevice)) {
+ return NULL;
+ }
+ interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
+ kSCNetworkInterfaceType6to4);
+ } else if (CFEqual(ifType, kSCValNetInterfaceTypeLoopback)) {
+ CFRelease(interfacePrivate);
+ interfacePrivate = __SCNetworkInterfaceCreateCopy(NULL, kSCNetworkInterfaceLoopback, NULL, NULL);
+ } else if (CFStringFind(ifType, CFSTR("."), 0).location != kCFNotFound) {
+ // if vendor interface
+ pthread_mutex_lock(&lock);
+ if (vendor_interface_types == NULL) {
+ vendor_interface_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+ }
+ CFSetAddValue(vendor_interface_types, ifType);
+ interfacePrivate->interface_type = CFSetGetValue(vendor_interface_types, ifType);
+ pthread_mutex_unlock(&lock);
+ } else {
+ // if unknown interface
+ CFRelease(interfacePrivate);
+ interfacePrivate = NULL;
+ return NULL;
+ }
+
+ if (CFDictionaryContainsKey(interface_entity, kSCNetworkInterfaceHiddenConfigurationKey)) {
+ interfacePrivate->hidden = TRUE;
+ }
+#if TARGET_OS_IPHONE
+ if (CFDictionaryContainsKey(interface_entity, kSCNetworkInterfaceTrustRequiredKey)) {
+ interfacePrivate->trustRequired = TRUE;
+ }
+#endif // TARGET_OS_IPHONE
+ }
+
+ if (service != NULL) {
+ __SCNetworkInterfaceSetService((SCNetworkInterfaceRef)interfacePrivate,
+ service);
+
+#if !TARGET_OS_IPHONE
+ // set prefs & serviceID to Bond member interfaces
+ if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBond)) {
+ CFIndex i;
+ CFArrayRef members;
+ CFIndex n;
+
+ members = SCBondInterfaceGetMemberInterfaces((SCNetworkInterfaceRef)interfacePrivate);
+ n = (members != NULL) ? CFArrayGetCount(members) : 0;
+ for (i = 0; i < n; i++) {
+ SCNetworkInterfaceRef member;
+
+ member = CFArrayGetValueAtIndex(members, i);
+ __SCNetworkInterfaceSetService(member, service);
+ }
+ }
+#endif // !TARGET_OS_IPHONE
+
+ // set prefs & serviceID to Bridge member interfaces
+ if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBridge)) {
+ CFIndex i;
+ CFArrayRef members;
+ CFIndex n;
+
+ members = SCBridgeInterfaceGetMemberInterfaces((SCNetworkInterfaceRef)interfacePrivate);
+ n = (members != NULL) ? CFArrayGetCount(members) : 0;
+ for (i = 0; i < n; i++) {
+ SCNetworkInterfaceRef member;
+
+ member = CFArrayGetValueAtIndex(members, i);
+ __SCNetworkInterfaceSetService(member, service);
+ }
+ }
+ // set prefs & serviceID to VLAN pyhsical interface
+ if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeVLAN)) {
+ SCNetworkInterfaceRef vlan_physical;
+
+ vlan_physical = SCVLANInterfaceGetPhysicalInterface((SCNetworkInterfaceRef)interfacePrivate);
+ if (vlan_physical != NULL) {
+ __SCNetworkInterfaceSetService(vlan_physical, service);
+ }
+ }
+ }
+
+ if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
+ SCNetworkInterfaceRef parent;
+
+ // create parent
+ parent = SCNetworkInterfaceCreateWithInterface((SCNetworkInterfaceRef)interfacePrivate,
+ kSCNetworkInterfaceTypePPP);
+ CFRelease(interfacePrivate);
+ interfacePrivate = (SCNetworkInterfacePrivateRef)parent;
+ } else if (CFEqual(ifType, kSCValNetInterfaceTypeVPN)) {
+ SCNetworkInterfaceRef parent;
+
+ // create parent
+ parent = SCNetworkInterfaceCreateWithInterface((SCNetworkInterfaceRef)interfacePrivate,
+ kSCNetworkInterfaceTypeVPN);
+ CFRelease(interfacePrivate);
+ interfacePrivate = (SCNetworkInterfacePrivateRef)parent;
+ }
+
+ return (SCNetworkInterfaceRef)interfacePrivate;
+}
+
+
+#pragma mark -
+#pragma mark SCNetworkInterface APIs
+
+
+__private_extern__
+CFArrayRef
+__SCNetworkInterfaceCopyAll_IONetworkInterface(Boolean keep_pre_configured)
+{
+ CFDictionaryRef matching;
+ CFArrayRef new_interfaces;
+
+ // get Ethernet, Firewire, Thunderbolt, and AirPort interfaces
+
+ matching = IOServiceMatching(kIONetworkInterfaceClass);
+ new_interfaces = findMatchingInterfaces(matching,
+ processNetworkInterface,
+ kSCNetworkInterfaceHiddenInterfaceKey,
+ keep_pre_configured);
+ CFRelease(matching);
+
+ return new_interfaces;
+}
+
+
+static
+CFArrayRef
+__SCNetworkInterfaceCopyAll_Modem()
+{
+ CFDictionaryRef matching;
+ CFStringRef match_keys[2];
+ CFStringRef match_vals[2];
+ CFArrayRef new_interfaces;
+
+ match_keys[0] = CFSTR(kIOProviderClassKey);
+ match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
+
+ match_keys[1] = CFSTR(kIOSerialBSDTypeKey);
+ match_vals[1] = CFSTR(kIOSerialBSDModemType);
+
+ matching = CFDictionaryCreate(NULL,
+ (const void **)match_keys,
+ (const void **)match_vals,
+ sizeof(match_keys)/sizeof(match_keys[0]),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ new_interfaces = findMatchingInterfaces(matching,
+ processSerialInterface,
+ kSCNetworkInterfaceHiddenPortKey,
+ FALSE);
+ CFRelease(matching);
+
+ return new_interfaces;
+}
+
+
+static
+CFArrayRef
+__SCNetworkInterfaceCopyAll_RS232()
+{
+ CFDictionaryRef matching;
+ CFStringRef match_keys[2];
+ CFStringRef match_vals[2];
+ CFArrayRef new_interfaces;
+
+ match_keys[0] = CFSTR(kIOProviderClassKey);
+ match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
+
+ match_keys[1] = CFSTR(kIOSerialBSDTypeKey);
+ match_vals[1] = CFSTR(kIOSerialBSDRS232Type);
+
+ matching = CFDictionaryCreate(NULL,
+ (const void **)match_keys,
+ (const void **)match_vals,
+ sizeof(match_keys)/sizeof(match_keys[0]),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ new_interfaces = findMatchingInterfaces(matching,
+ processSerialInterface,
+ kSCNetworkInterfaceHiddenPortKey,
+ FALSE);
+ CFRelease(matching);
+
+ return new_interfaces;
+}
+
+
+#if !TARGET_OS_IPHONE
+static void
+addBTPANInterface(CFMutableArrayRef all_interfaces)
+{
+ CFIndex i;
+ SCNetworkInterfaceRef interface;
+ CFIndex n;
+
+ n = CFArrayGetCount(all_interfaces);
+ for (i = 0; i < n; i++) {
+ SCNetworkInterfaceRef interface;
+
+ interface = CFArrayGetValueAtIndex(all_interfaces, i);
+ if (_SCNetworkInterfaceIsBluetoothPAN(interface)) {
+ // if we already have a BT-PAN interface
+ return;
+ }
+ }
+
+ interface = _SCNetworkInterfaceCopyBTPANInterface();
+ if (interface != NULL) {
+ // include BT-PAN interface
+ CFArrayAppendValue(all_interfaces, interface);
+ CFRelease(interface);
+ }
+
+ return;
+}
+#endif // !TARGET_OS_IPHONE
+
+
+static void
+add_interfaces(CFMutableArrayRef all_interfaces, CFArrayRef new_interfaces)
+{
+ CFIndex i;
+ CFIndex n;
+
+ n = CFArrayGetCount(new_interfaces);
+ for (i = 0; i < n; i++) {
+ CFStringRef bsdName;
+ SCNetworkInterfaceRef interface;
+
+ interface = CFArrayGetValueAtIndex(new_interfaces, i);
+ bsdName = SCNetworkInterfaceGetBSDName(interface);
+ if (bsdName != NULL) {
+ CFArrayAppendValue(all_interfaces, interface);
+ }
+ }
+
+ return;
+}
+
+
+static void
+__waitForInterfaces()
+{
+ CFStringRef key = NULL;
+ CFArrayRef keys;
+ Boolean ok;
+ SCDynamicStoreRef store = NULL;
+
+ CRSetCrashLogMessage("Waiting for IOKit to quiesce (or timeout)");
+
+ store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkInterfaceCopyAll"), NULL, NULL);
+ if (store == NULL) {
+ goto done;
+ }
+
+ key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" "InterfaceNamer"), kSCDynamicStoreDomainPlugin);
+ keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
+ ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
+ CFRelease(keys);
+ if (!ok) {
+ SC_log(LOG_NOTICE, "SCDynamicStoreSetNotificationKeys() failed: %s", SCErrorString(SCError()));
+ goto done;
+ }
+
+ while (TRUE) {
+ CFArrayRef changedKeys;
+ CFDictionaryRef dict;
+ Boolean quiet = FALSE;
+
+ // check if quiet
+ dict = SCDynamicStoreCopyValue(store, key);
+ if (dict != NULL) {
+ if (isA_CFDictionary(dict) &&
+ (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Quiet) ||
+ CFDictionaryContainsKey(dict, kInterfaceNamerKey_Timeout))) {
+ quiet = TRUE;
+ }
+ CFRelease(dict);
+ }
+ if (quiet) {
+ break;
+ }
+
+ ok = SCDynamicStoreNotifyWait(store);
+ if (!ok) {
+ SC_log(LOG_NOTICE, "SCDynamicStoreNotifyWait() failed: %s", SCErrorString(SCError()));
+ goto done;
+ }
+
+ changedKeys = SCDynamicStoreCopyNotifiedKeys(store);
+ if (changedKeys != NULL) {
+ CFRelease(changedKeys);
+ }
+ }
+
+ done :
+
+ CRSetCrashLogMessage(NULL);
+
+ if (key != NULL) CFRelease(key);
+ if (store != NULL) CFRelease(store);
+ return;
+}
+
+
+CFArrayRef /* of SCNetworkInterfaceRef's */
+_SCNetworkInterfaceCopyAllWithPreferences(SCPreferencesRef prefs)
+{
+ CFMutableArrayRef all_interfaces;
+ CFArrayRef new_interfaces;
+ Boolean temp_preferences = FALSE;
+
+ /* initialize runtime */
+ pthread_once(&initialized, __SCNetworkInterfaceInitialize);
+
+ /* wait for IOKit to quiesce */
+ pthread_once(&iokit_quiet, __waitForInterfaces);
+
+ all_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ // get Ethernet, Firewire, Thunderbolt, and AirPort interfaces
+ new_interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(FALSE);
+ if (new_interfaces != NULL) {
+ add_interfaces(all_interfaces, new_interfaces);
+ CFRelease(new_interfaces);
+ }
+
+ // get Modem interfaces
+ new_interfaces = __SCNetworkInterfaceCopyAll_Modem();
+ if (new_interfaces != NULL) {
+ add_interfaces(all_interfaces, new_interfaces);
+ CFRelease(new_interfaces);
+ }
+
+ // get serial (RS232) interfaces
+ new_interfaces = __SCNetworkInterfaceCopyAll_RS232();
+ if (new_interfaces != NULL) {
+ add_interfaces(all_interfaces, new_interfaces);
+ CFRelease(new_interfaces);
+ }
+
+ // get virtual network interfaces (Bond, Bridge, VLAN)
+ if (prefs == NULL) {
+ prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterfaceCopyAll"), NULL);
+ if (prefs != NULL) {
+ temp_preferences = TRUE;
+ }
+ }
+ if (prefs != NULL) {
+#if !TARGET_OS_IPHONE
+ new_interfaces = SCBondInterfaceCopyAll(prefs);
+ if (new_interfaces != NULL) {
+ add_interfaces(all_interfaces, new_interfaces);
+ CFRelease(new_interfaces);
+ }
+#endif // !TARGET_OS_IPHONE
+
+ new_interfaces = SCBridgeInterfaceCopyAll(prefs);
+ if (new_interfaces != NULL) {
+ add_interfaces(all_interfaces, new_interfaces);
+ CFRelease(new_interfaces);
+ }
+
+ new_interfaces = SCVLANInterfaceCopyAll(prefs);
+ if (new_interfaces != NULL) {
+ add_interfaces(all_interfaces, new_interfaces);
+ CFRelease(new_interfaces);
+ }
+
+#if !TARGET_OS_IPHONE
+ // add BT-PAN interface
+ addBTPANInterface(all_interfaces);
+#endif // !TARGET_OS_IPHONE
+
+ if (temp_preferences) CFRelease(prefs);
+ }
+
+ // all interfaces have been identified, order and return
+ sort_interfaces(all_interfaces);
+
+ return all_interfaces;
+}
+
+
+CFArrayRef /* of SCNetworkInterfaceRef's */
+SCNetworkInterfaceCopyAll()
+{
+ CFArrayRef all_interfaces;
+
+ all_interfaces = _SCNetworkInterfaceCopyAllWithPreferences(NULL);
+ return all_interfaces;
+}
+
+
+CFArrayRef /* of kSCNetworkInterfaceTypeXXX CFStringRef's */
+SCNetworkInterfaceGetSupportedInterfaceTypes(SCNetworkInterfaceRef interface)
+{
+ CFIndex i;
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ if (interfacePrivate->supported_interface_types != NULL) {
+ goto done;
+ }
+
+ i = findConfiguration(interfacePrivate->interface_type);
+ if (i != kCFNotFound) {
+ if (configurations[i].supported_interfaces != doNone) {
+ interfacePrivate->supported_interface_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ if (configurations[i].supported_interfaces & do6to4) {
+ CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceType6to4);
+ }
+ if (configurations[i].supported_interfaces & doL2TP) {
+ CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeL2TP);
+ }
+ if (configurations[i].supported_interfaces & doPPP) {
+ CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPP);
+ }
+ if (configurations[i].supported_interfaces & doIPSec) {
+ CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeIPSec);
+ }
+ }
+ } else {
+ SCNetworkInterfaceRef child;
+
+ child = SCNetworkInterfaceGetInterface(interface);
+ if ((child != NULL) && CFEqual(child, kSCNetworkInterfaceIPv4)) {
+ interfacePrivate->supported_interface_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeVPN);
+ }
+ }
+
+ done :
+
+ return interfacePrivate->supported_interface_types;
+}
+
+
+CFArrayRef /* of kSCNetworkProtocolTypeXXX CFStringRef's */
+SCNetworkInterfaceGetSupportedProtocolTypes(SCNetworkInterfaceRef interface)
+{
+ CFIndex i;
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ if (interfacePrivate->supported_protocol_types != NULL) {
+ goto done;
+ }
+
+ i = findConfiguration(interfacePrivate->interface_type);
+ if (i != kCFNotFound) {
+ if (configurations[i].supported_protocols != doNone) {
+ interfacePrivate->supported_protocol_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ if (configurations[i].supported_protocols & doDNS) {
+ CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeDNS);
+ }
+ if (configurations[i].supported_protocols & doIPv4) {
+ CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv4);
+ }
+ if (configurations[i].supported_protocols & doIPv6) {
+ CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv6);
+ }
+ if (configurations[i].supported_protocols & doProxies) {
+ CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeProxies);
+ }
+#if !TARGET_OS_IPHONE
+ if (configurations[i].supported_protocols & doSMB) {
+ CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeSMB);
+ }
+#endif // !TARGET_OS_IPHONE
+ }
+ }
+
+ done :
+
+ return interfacePrivate->supported_protocol_types;
+}
+
+
+SCNetworkInterfaceRef
+SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef interfaceType)
+{
+ SCNetworkInterfacePrivateRef childPrivate = (SCNetworkInterfacePrivateRef)child;
+ CFIndex childIndex;
+ SCNetworkInterfacePrivateRef parentPrivate;
+
+ if (!isA_SCNetworkInterface(child)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ if (!isA_CFString(interfaceType)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ if (CFEqual(child, kSCNetworkInterfaceLoopback)) {
+ // can't layer on top of loopback
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ childIndex = findConfiguration(childPrivate->interface_type);
+
+ parentPrivate = __SCNetworkInterfaceCreatePrivate(NULL,
+ child,
+ childPrivate->prefs,
+ childPrivate->serviceID);
+ if (parentPrivate == NULL) {
+ _SCErrorSet(kSCStatusFailed);
+ return NULL;
+ }
+
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
+ parentPrivate->interface_type = kSCNetworkInterfaceTypePPP;
+ parentPrivate->entity_type = kSCValNetInterfaceTypePPP;
+
+ // entity subtype
+ if (childIndex != kCFNotFound) {
+ if (configurations[childIndex].ppp_subtype != NULL) {
+ parentPrivate->entity_subtype = *configurations[childIndex].ppp_subtype;
+ } else {
+ // sorry, the child interface does not support PPP
+ goto fail;
+ }
+ } else {
+ // if the child's interface type not known, use the child entities "Type"
+ parentPrivate->entity_subtype = childPrivate->entity_type;
+ }
+
+ if (childPrivate->entity_device != NULL) {
+ parentPrivate->entity_device = CFStringCreateCopy(NULL, childPrivate->entity_device);
+ }
+
+ if (childPrivate->entity_device_unique != NULL) {
+ parentPrivate->entity_device_unique = CFStringCreateCopy(NULL, childPrivate->entity_device_unique);
+ }
+ } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
+ if ((childIndex == kCFNotFound) ||
+ ((configurations[childIndex].supported_interfaces & doL2TP) != doL2TP)) {
+ // if the child interface does not support L2TP
+ goto fail;
+ }
+ parentPrivate->interface_type = kSCNetworkInterfaceTypeL2TP;
+ parentPrivate->localized_key = CFSTR("l2tp");
+ parentPrivate->entity_type = kSCEntNetL2TP; // interface config goes into "L2TP"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated"
+ } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) {
+ if ((childIndex == kCFNotFound) ||
+ ((configurations[childIndex].supported_interfaces & doPPTP) != doPPTP)) {
+ // if the child interface does not support PPTP
+ goto fail;
+ }
+ parentPrivate->interface_type = kSCNetworkInterfaceTypePPTP;
+ parentPrivate->localized_key = CFSTR("pptp");
+ parentPrivate->entity_type = kSCEntNetPPTP; // interface config goes into "PPTP"
+#pragma GCC diagnostic pop
+ } else if (CFEqual(interfaceType, kSCNetworkInterfaceType6to4)) {
+ if ((childIndex == kCFNotFound) ||
+ ((configurations[childIndex].supported_interfaces & do6to4) != do6to4)) {
+ // if the child interface does not support 6to4
+ goto fail;
+ }
+
+ parentPrivate->interface_type = kSCNetworkInterfaceType6to4;
+ parentPrivate->localized_key = CFSTR("6to4");
+ parentPrivate->entity_type = kSCValNetInterfaceType6to4;
+ parentPrivate->entity_device = CFRetain(CFSTR("stf0"));
+ } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
+ if ((childIndex == kCFNotFound) ||
+ ((configurations[childIndex].supported_interfaces & doIPSec) != doIPSec)) {
+ // if the child interface does not support IPSec
+ goto fail;
+ }
+ parentPrivate->interface_type = kSCNetworkInterfaceTypeIPSec;
+ parentPrivate->localized_key = CFSTR("ipsec");
+ parentPrivate->entity_type = kSCValNetInterfaceTypeIPSec;
+ } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
+ if (childIndex != kCFNotFound) {
+ // if not a "vendor" child interface
+ goto fail;
+ }
+
+ parentPrivate->interface_type = kSCNetworkInterfaceTypeVPN;
+ parentPrivate->localized_key = CFSTR("vpn");
+ parentPrivate->localized_arg1 = CFRetain(childPrivate->entity_type);
+ parentPrivate->entity_type = kSCValNetInterfaceTypeVPN;
+ parentPrivate->entity_subtype = childPrivate->entity_type;
+ if (childPrivate->entity_device != NULL) {
+ parentPrivate->entity_device = CFStringCreateCopy(NULL, childPrivate->entity_device);
+ }
+ if (parentPrivate->entity_subtype != NULL) {
+ CFArrayRef components;
+ CFIndex n;
+ CFStringRef vpnType;
+
+ //
+ // the "default" interface name is derived from the VPN type
+ //
+ // e.g.
+ // com.apple.Apple-VPN.vpnplugin --> "Apple VPN"
+ // ^^^^^^^^^
+ //
+ vpnType = parentPrivate->entity_subtype;
+ components = CFStringCreateArrayBySeparatingStrings(NULL, vpnType, CFSTR("."));
+ n = CFArrayGetCount(components);
+ if ((n >= 4) &&
+ CFEqual(CFArrayGetValueAtIndex(components, n - 1), CFSTR("vpnplugin"))) {
+ CFMutableStringRef str;
+
+ str = CFStringCreateMutableCopy(NULL,
+ 0,
+ CFArrayGetValueAtIndex(components, n - 2));
+ (void) CFStringFindAndReplace(str,
+ CFSTR("-"),
+ CFSTR(" "),
+ CFRangeMake(0, CFStringGetLength(str)),
+ 0);
+ parentPrivate->localized_name = str;
+ }
+ CFRelease(components);
+ }
+ } else if (CFStringFind(interfaceType, CFSTR("."), 0).location != kCFNotFound) {
+ // if custom interface type
+ pthread_mutex_lock(&lock);
+ if (vendor_interface_types == NULL) {
+ vendor_interface_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+ }
+ CFSetAddValue(vendor_interface_types, interfaceType);
+ parentPrivate->interface_type = CFSetGetValue(vendor_interface_types, interfaceType);
+ pthread_mutex_unlock(&lock);
+
+ parentPrivate->entity_type = parentPrivate->interface_type; // interface config goes into a
+ // a dictionary with the same
+ // name as the interfaceType
+ } else {
+ // unknown interface type
+ goto fail;
+ }
+
+ parentPrivate->hidden = childPrivate->hidden;
+
+#if TARGET_OS_IPHONE
+ parentPrivate->trustRequired = childPrivate->trustRequired;
+#endif // TARGET_OS_IPHONE
+
+ if (childPrivate->overrides != NULL) {
+ parentPrivate->overrides = CFDictionaryCreateMutableCopy(NULL, 0, childPrivate->overrides);
+ }
+
+ // The following change handles the case where a user has both an Ethernet and
+ // PPPoE network service. Because a PPPoE service is typically associated with
+ // an ISP we want it to be sorted higher in the service order.
+ if ((parentPrivate->entity_subtype != NULL) &&
+ (CFEqual(parentPrivate->entity_subtype, kSCValNetInterfaceSubTypePPPoE))) {
+ if ((childPrivate->interface_type != NULL) &&
+ (CFEqual(childPrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211))) {
+ parentPrivate->sort_order = kSortAirportPPP;
+ } else {
+ parentPrivate->sort_order = kSortEthernetPPP;
+ }
+ } else {
+ // set sort order of the parent to match the child interface
+ parentPrivate->sort_order = childPrivate->sort_order;
+ }
+
+ return (SCNetworkInterfaceRef)parentPrivate;
+
+ fail :
+
+ CFRelease(parentPrivate);
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+}
+
+
+__private_extern__
+CFDictionaryRef
+__SCNetworkInterfaceGetDefaultConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
+{
+ CFDictionaryRef config = NULL;
+ CFStringRef defaultType;
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ /* initialize runtime (and kSCNetworkInterfaceIPv4) */
+ pthread_once(&initialized, __SCNetworkInterfaceInitialize);
+
+ defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
+ if (defaultType != NULL) {
+ if (set != NULL) {
+ CFStringRef path;
+
+ path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator
+ SCNetworkSetGetSetID(set), // set
+ interfacePrivate->entity_device, // interface
+ defaultType); // entity
+ if (path != NULL) {
+ config = __getPrefsConfiguration(interfacePrivate->prefs, path);
+ CFRelease(path);
+
+ if (config == NULL) {
+ // if the "set" does not have a saved configuration, use
+ // the [template] "interface" configuration
+ if (interfacePrivate->unsaved != NULL) {
+ config = CFDictionaryGetValue(interfacePrivate->unsaved, defaultType);
+ if (config == (CFDictionaryRef)kCFNull) {
+ config = NULL;
+ }
+ }
+ }
+ if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
+ config = NULL;
+ }
+ }
+ }
+ }
+
+ return config;
+}
+
+
+static CFDictionaryRef
+__SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface,
+ CFStringRef extendedType)
+{
+ CFDictionaryRef config = NULL;
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+ CFArrayRef paths;
+
+ /* initialize runtime (and kSCNetworkInterfaceIPv4) */
+ pthread_once(&initialized, __SCNetworkInterfaceInitialize);
+
+ paths = copyConfigurationPaths(interfacePrivate, extendedType);
+ if (paths != NULL) {
+ CFStringRef path;
+
+ path = CFArrayGetValueAtIndex(paths, 0);
+ config = __getPrefsConfiguration(interfacePrivate->prefs, path);
+
+ CFRelease(paths);
+ } else {
+ if (interfacePrivate->unsaved != NULL) {
+ config = CFDictionaryGetValue(interfacePrivate->unsaved, extendedType);
+ if (config == (CFDictionaryRef)kCFNull) {
+ config = NULL;
+ }
+ }
+ }
+
+ if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
+ config = NULL;
+ }
+
+ return config;
+}
+
+
+CFDictionaryRef
+SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface)
+{
+ CFDictionaryRef config;
+ CFStringRef defaultType;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
+ if (defaultType == NULL) {
+ return NULL;
+ }
+
+ config = __SCNetworkInterfaceGetConfiguration(interface, defaultType);
+ if (config == NULL) {
+ if (CFEqual(defaultType, kSCEntNetAirPort)) {
+ SCNetworkInterfacePrivateRef interfacePrivate;
+ CFStringRef path;
+
+ // if AirPort interface, check for a per-service config
+ interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+ path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
+ interfacePrivate->serviceID, // service
+ kSCEntNetAirPort); // entity
+ config = __getPrefsConfiguration(interfacePrivate->prefs, path);
+ CFRelease(path);
+ }
+ }
+ if (config == NULL) {
+ _SCErrorSet(kSCStatusOK);
+ }
+
+ return config;
+}
+
+
+CFDictionaryRef
+SCNetworkInterfaceGetExtendedConfiguration(SCNetworkInterfaceRef interface,
+ CFStringRef extendedType)
+{
+ CFDictionaryRef config;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, TRUE)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ config = __SCNetworkInterfaceGetConfiguration(interface, extendedType);
+ if (config == NULL) {
+ _SCErrorSet(kSCStatusOK);
+ }
+
+ return config;
+}
+
+
+__private_extern__
+CFStringRef
+__SCNetworkInterfaceGetEntityType(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->entity_type;
+}
+
+
+__private_extern__
+CFStringRef
+__SCNetworkInterfaceGetEntitySubType(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef) interface;
+
+ return interfacePrivate->entity_subtype;
+}
+
+
+CFStringRef
+SCNetworkInterfaceGetBSDName(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ if ((interfacePrivate->interface != NULL) &&
+ (interfacePrivate->interface != kSCNetworkInterfaceIPv4)) {
+ _SCErrorSet(kSCStatusOK);
+ return NULL;
+ }
+
+ return interfacePrivate->entity_device;
+}
+
+
+CFStringRef
+SCNetworkInterfaceGetHardwareAddressString(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ if ((interfacePrivate->address != NULL) &&
+ (interfacePrivate->addressString == NULL)) {
+ uint8_t *bp;
+ char *cp;
+ size_t n;
+ char mac[sizeof("xx:xx:xx:xx:xx:xx:xx:xx")];
+ char *mac_p = mac;
+
+ bp = (uint8_t *)CFDataGetBytePtr(interfacePrivate->address);
+ n = CFDataGetLength(interfacePrivate->address) * 3;
+
+ if (n > sizeof(mac)) {
+ mac_p = CFAllocatorAllocate(NULL, n, 0);
+ }
+
+ for (cp = mac_p; n > 0; n -= 3) {
+ cp += snprintf(cp, n, "%2.2x:", *bp++);
+ }
+
+ interfacePrivate->addressString = CFStringCreateWithCString(NULL, mac_p, kCFStringEncodingUTF8);
+ if (mac_p != mac) CFAllocatorDeallocate(NULL, mac_p);
+ }
+
+ return interfacePrivate->addressString;
+}
+
+
+SCNetworkInterfaceRef
+SCNetworkInterfaceGetInterface(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ return interfacePrivate->interface;
+}
+
+
+CFStringRef
+SCNetworkInterfaceGetInterfaceType(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ return interfacePrivate->interface_type;
+}
+
+
+static CFStringRef
+copy_string_from_bundle(CFBundleRef bundle, CFStringRef key, Boolean localized)
+{
+ CFStringRef str = NULL;
+
+ if (localized) {
+ str = CFBundleCopyLocalizedString(bundle,
+ key,
+ key,
+ NETWORKINTERFACE_LOCALIZATIONS);
+ } else {
+ str = _SC_CFBundleCopyNonLocalizedString(bundle,
+ key,
+ key,
+ NETWORKINTERFACE_LOCALIZATIONS);
+ }
+
+ return str;
+}
+
+
+static CFStringRef
+copy_interface_string(CFBundleRef bundle, CFStringRef key, Boolean localized)
+{
+ static Boolean reported = FALSE;
+ CFStringRef str = NULL;
+
+ str = copy_string_from_bundle(bundle, key, localized);
+
+ if (str == NULL) {
+ SC_log(LOG_ERR, "Received NULL string for the interface key: {Bundle: %@, key: %@, localized: %d}", bundle,
+ key,
+ localized);
+ goto done;
+ }
+
+ if (CFEqual(str, key) && !reported) {
+ const CFStringRef knownStrKey = CFSTR("airport");
+ CFStringRef knownStrValue = NULL;
+
+ knownStrValue = copy_string_from_bundle(bundle, knownStrKey, localized);
+ if (knownStrValue == NULL || CFEqual(knownStrValue, knownStrKey)) {
+ /* We are here because we requested for a localized/non-localized string
+ based on the localization key, but we were given the same key/NULL back,
+ implying a bad...bad thing!
+ */
+ SC_log(LOG_ERR, "Failed to retrieve the interface string: {Bundle: %@, key: %@, localized: %d}", bundle,
+ knownStrKey,
+ localized);
+
+#if TARGET_OS_IPHONE
+ /* ...and we want to know about it! */
+ _SC_crash("Failed to retrieve interface string", NULL, NULL);
+#endif //TARGET_OS_IPHONE
+ reported = TRUE;
+ }
+
+ if (knownStrValue != NULL) {
+ CFRelease(knownStrValue);
+ }
+ }
+
+done:
+ return str;
+}
+
+
+static CFStringRef
+copy_display_name(SCNetworkInterfaceRef interface, Boolean localized, Boolean oldLocalization)
+{
+ CFMutableStringRef local;
+ CFStringRef name;
+
+ local = CFStringCreateMutable(NULL, 0);
+
+ while (interface != NULL) {
+ Boolean added = FALSE;
+ SCNetworkInterfaceRef child = NULL;
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if ((interfacePrivate->interface != NULL) &&
+ (interfacePrivate->interface != kSCNetworkInterfaceIPv4) &&
+ !CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeVPN)) {
+ child = interfacePrivate->interface;
+ }
+
+ if ((bundle != NULL) && (interfacePrivate->localized_key != NULL)) {
+ CFStringRef fmt;
+ CFStringRef key = interfacePrivate->localized_key;
+
+ if (oldLocalization) {
+ key = CFStringCreateWithFormat(NULL, NULL, CFSTR("X-%@"),
+ interfacePrivate->localized_key);
+ }
+ fmt = copy_interface_string(bundle, key, localized);
+ if (fmt != NULL) {
+ CFStringAppendFormat(local,
+ NULL,
+ fmt,
+ interfacePrivate->localized_arg1,
+ interfacePrivate->localized_arg2);
+ CFRelease(fmt);
+ added = TRUE;
+ }
+ if (oldLocalization) {
+ CFRelease(key);
+ }
+ }
+
+ if (!added &&
+ (interfacePrivate->prefs != NULL) &&
+ (interfacePrivate->serviceID != NULL) &&
+ (child == NULL)) {
+ CFDictionaryRef entity;
+ CFStringRef path;
+
+ // check for (and use) the name of the interface when it
+ // was last available
+ path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
+ interfacePrivate->serviceID,
+ kSCEntNetInterface);
+ entity = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
+ CFRelease(path);
+ if (isA_CFDictionary(entity)) {
+ CFStringRef name;
+
+ name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
+ if (isA_CFString(name)) {
+ CFStringAppend(local, name);
+ added = TRUE;
+ }
+ }
+ }
+
+ if (!added) {
+ // create (non-)localized name based on the interface type
+ CFStringAppend(local, interfacePrivate->interface_type);
+
+ // ... and, if this is a leaf node, the interface device
+ if ((interfacePrivate->entity_device != NULL) && (child == NULL)) {
+ CFStringAppendFormat(local, NULL, CFSTR(" (%@)"), interfacePrivate->entity_device);
+ }
+ }
+
+ if (child != NULL) {
+ // if this interface is layered over another
+ CFStringAppend(local, CFSTR(" --> "));
+ }
+
+ interface = child;
+ }
+
+ name = CFStringCreateCopy(NULL, local);
+ CFRelease(local);
+
+ return name;
+}
+
+
+#if !TARGET_OS_IPHONE
+__private_extern__
+CFStringRef
+__SCNetworkInterfaceCopyXLocalizedDisplayName(SCNetworkInterfaceRef interface)
+{
+ CFStringRef name;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ name = copy_display_name(interface, TRUE, TRUE);
+ return name;
+}
+
+
+__private_extern__
+CFStringRef
+__SCNetworkInterfaceCopyXNonLocalizedDisplayName(SCNetworkInterfaceRef interface)
+{
+ CFStringRef localized_name;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ localized_name = copy_display_name(interface, FALSE, TRUE);
+ return localized_name;
+}
+#endif // !TARGET_OS_IPHONE
+
+__private_extern__
+void
+__SCNetworkInterfaceSetUserDefinedName(SCNetworkInterfaceRef interface, CFStringRef name)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ return;
+ }
+ if (name != NULL) {
+ CFRetain(name);
+ }
+ if (interfacePrivate->name != NULL) {
+ CFRelease(interfacePrivate->name);
+ }
+ interfacePrivate->name = name;
+
+ if (name != NULL) {
+ CFRetain(name);
+ }
+ if (interfacePrivate->localized_name != NULL) {
+ CFRelease(interfacePrivate->localized_name);
+ }
+ interfacePrivate->localized_name = name;
+}
+
+__private_extern__
+CFStringRef
+__SCNetworkInterfaceGetUserDefinedName(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ return NULL;
+ }
+
+ return interfacePrivate->name;
+}
+
+
+__private_extern__
+CFStringRef
+__SCNetworkInterfaceGetNonLocalizedDisplayName(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ if (interfacePrivate->name == NULL) {
+ interfacePrivate->name = copy_display_name(interface, FALSE, FALSE);
+ }
+
+ return interfacePrivate->name;
+}
+
+
+CFStringRef
+SCNetworkInterfaceGetLocalizedDisplayName(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ if (interfacePrivate->localized_name == NULL) {
+ interfacePrivate->localized_name = copy_display_name(interface, TRUE, FALSE);
+ }
+
+ return interfacePrivate->localized_name;
+}
+
+
+__private_extern__
+CFPropertyListRef
+__SCNetworkInterfaceGetTemplateOverrides(SCNetworkInterfaceRef interface, CFStringRef overrideType)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+ CFPropertyListRef overrides = NULL;
+
+ if (interfacePrivate->overrides != NULL) {
+ overrides = CFDictionaryGetValue(interfacePrivate->overrides, overrideType);
+ }
+
+ return overrides;
+}
+
+
+CFTypeID
+SCNetworkInterfaceGetTypeID(void)
+{
+ pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* initialize runtime */
+ return __kSCNetworkInterfaceTypeID;
+}
+
+
+__private_extern__
+Boolean
+__SCNetworkInterfaceSetDefaultConfiguration(SCNetworkSetRef set,
+ SCNetworkInterfaceRef interface,
+ CFStringRef defaultType,
+ CFDictionaryRef config,
+ Boolean okToHold)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+ Boolean ok = FALSE;
+
+ /* initialize runtime (and kSCNetworkInterfaceIPv4) */
+ pthread_once(&initialized, __SCNetworkInterfaceInitialize);
+
+ if (defaultType == NULL) {
+ defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
+ if (defaultType == NULL) {
+ return FALSE;
+ }
+ }
+
+ if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
+ config = NULL;
+ }
+
+ if (set != NULL) {
+ CFStringRef path;
+
+ path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator
+ SCNetworkSetGetSetID(set), // set
+ interfacePrivate->entity_device, // interface
+ defaultType); // entity
+ if (path != NULL) {
+ ok = __setPrefsConfiguration(interfacePrivate->prefs, path, config, FALSE);
+ CFRelease(path);
+ if (ok) {
+ // if configuration has been saved
+ if (interfacePrivate->unsaved != NULL) {
+ CFDictionaryRemoveValue(interfacePrivate->unsaved, defaultType);
+ if (CFDictionaryGetCount(interfacePrivate->unsaved) == 0) {
+ CFRelease(interfacePrivate->unsaved);
+ interfacePrivate->unsaved = NULL;
+ }
+ }
+ }
+ } else {
+ if (okToHold) {
+ if (config == NULL) {
+ // remember that we are clearing the configuration
+ config = (CFDictionaryRef)kCFNull;
+ }
+
+ if (interfacePrivate->unsaved == NULL) {
+ interfacePrivate->unsaved = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ CFDictionarySetValue(interfacePrivate->unsaved, defaultType, config);
+ ok = TRUE;
+ } else {
+ _SCErrorSet(kSCStatusNoKey);
+ }
+ }
+ }
+
+ return ok;
+}
+
+
+__private_extern__
+Boolean
+__SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface,
+ CFStringRef extendedType,
+ CFDictionaryRef config,
+ Boolean okToHold)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+ Boolean ok = FALSE;
+ CFArrayRef paths;
+
+ /* initialize runtime (and kSCNetworkInterfaceIPv4) */
+ pthread_once(&initialized, __SCNetworkInterfaceInitialize);
+
+ if (extendedType == NULL) {
+ extendedType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
+ if (extendedType == NULL) {
+ return FALSE;
+ }
+ }
+
+ if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
+ config = NULL;
+ }
+
+ paths = copyConfigurationPaths(interfacePrivate, extendedType);
+ if (paths != NULL) {
+ CFIndex i;
+ CFIndex n;
+
+ n = CFArrayGetCount(paths);
+ for (i = 0; i < n; i++) {
+ CFStringRef path;
+
+ path = CFArrayGetValueAtIndex(paths, i);
+ ok = __setPrefsConfiguration(interfacePrivate->prefs, path, config, FALSE);
+ if (!ok) {
+ break;
+ }
+ }
+
+ if (ok) {
+ // if configuration has been saved
+ if (interfacePrivate->unsaved != NULL) {
+ CFDictionaryRemoveValue(interfacePrivate->unsaved, extendedType);
+ if (CFDictionaryGetCount(interfacePrivate->unsaved) == 0) {
+ CFRelease(interfacePrivate->unsaved);
+ interfacePrivate->unsaved = NULL;
+ }
+ }
+ }
+
+ CFRelease(paths);
+ } else {
+ if (okToHold) {
+ if (config == NULL) {
+ // remember that we are clearing the configuration
+ config = (CFDictionaryRef)kCFNull;
+ }
+
+ if (interfacePrivate->unsaved == NULL) {
+ interfacePrivate->unsaved = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ CFDictionarySetValue(interfacePrivate->unsaved, extendedType, config);
+ ok = TRUE;
+ } else {
+ _SCErrorSet(kSCStatusNoKey);
+ }
+ }
+
+ return ok;
+}
+
+
+Boolean
+SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config)
+{
+ CFStringRef defaultType;
+ Boolean ok;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
+ if (defaultType == NULL) {
+ return FALSE;
+ }
+
+ ok = __SCNetworkInterfaceSetConfiguration(interface, defaultType, config, FALSE);
+ if (ok) {
+ SC_log(LOG_DEBUG, "SCNetworkInterfaceSetConfiguration(): %@ -> %@",
+ interface,
+ config != NULL ? config : (CFDictionaryRef)CFSTR("NULL"));
+ }
+
+ return ok;
+}
+
+
+Boolean
+SCNetworkInterfaceSetExtendedConfiguration(SCNetworkInterfaceRef interface,
+ CFStringRef extendedType,
+ CFDictionaryRef config)
+{
+ Boolean ok;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, TRUE)) {
+ return FALSE;
+ }
+
+ ok = __SCNetworkInterfaceSetConfiguration(interface, extendedType, config, FALSE);
+ if (ok) {
+ SC_log(LOG_DEBUG, "SCNetworkInterfaceSetExtendedConfiguration(): %@ -> %@",
+ interface,
+ config != NULL ? config : (CFDictionaryRef)CFSTR("NULL"));
+ }
+
+ return ok;
+}
+
+
+#pragma mark -
+#pragma mark SCNetworkInterface [Refresh Configuration] API
+
+
+Boolean
+_SCNetworkInterfaceForceConfigurationRefresh(CFStringRef ifName)
+{
+ CFStringRef key;
+ Boolean ok = FALSE;
+
+ if (!isA_CFString(ifName)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+ kSCDynamicStoreDomainState,
+ ifName,
+ kSCEntNetRefreshConfiguration);
+ ok = SCDynamicStoreNotifyValue(NULL, key);
+ CFRelease(key);
+ return ok;
+}
+
+
+static Boolean
+__SCNetworkInterfaceForceConfigurationRefresh_helper(SCPreferencesRef prefs, CFStringRef ifName)
+{
+ CFDataRef data = NULL;
+ Boolean ok;
+ SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
+ uint32_t status = kSCStatusOK;
+ CFDataRef reply = NULL;
+
+ if (prefsPrivate->helper_port == MACH_PORT_NULL) {
+ ok = __SCPreferencesCreate_helper(prefs);
+ if (!ok) {
+ return FALSE;
+ }
+ }
+
+ // serialize the interface name
+ ok = _SCSerializeString(ifName, &data, NULL, NULL);
+ if (!ok) {
+ goto fail;
+ }
+
+ // have the helper "refresh" the configuration
+ status = kSCStatusOK;
+ reply = NULL;
+ ok = _SCHelperExec(prefsPrivate->helper_port,
+ SCHELPER_MSG_INTERFACE_REFRESH,
+ data,
+ &status,
+ NULL);
+ if (data != NULL) CFRelease(data);
+ if (!ok) {
+ goto fail;
+ }
+
+ if (status != kSCStatusOK) {
+ goto error;
+ }
+
+ return TRUE;
+
+ fail :
+
+ // close helper
+ if (prefsPrivate->helper_port != MACH_PORT_NULL) {
+ _SCHelperClose(&prefsPrivate->helper_port);
+ }
+
+ status = kSCStatusAccessError;
+
+ error :
+
+ // return error
+ _SCErrorSet(status);
+ return FALSE;
+}
+
+
+Boolean
+SCNetworkInterfaceForceConfigurationRefresh(SCNetworkInterfaceRef interface)
+{
+ CFStringRef ifName;
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ ifName = SCNetworkInterfaceGetBSDName(interface);
+ if (ifName == NULL) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (interfacePrivate->prefs != NULL) {
+ SCPreferencesRef prefs = interfacePrivate->prefs;
+ SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
+
+ if (prefsPrivate->authorizationData != NULL) {
+ return __SCNetworkInterfaceForceConfigurationRefresh_helper(prefs, ifName);
+ }
+ }
+
+ return _SCNetworkInterfaceForceConfigurationRefresh(ifName);
+}
+
+
+#if !TARGET_OS_IPHONE
+Boolean
+SCNetworkInterfaceRefreshConfiguration(CFStringRef ifName)
+{
+ return _SCNetworkInterfaceForceConfigurationRefresh(ifName);
+}
+#endif // !TARGET_OS_IPHONE
+
+
+#pragma mark -
+#pragma mark SCNetworkInterface Password APIs
+
+
+static CFStringRef
+getPasswordID(CFDictionaryRef config, CFStringRef serviceID)
+{
+ CFStringRef unique_id = NULL;
+
+ if (config != NULL) {
+ CFStringRef encryption;
+
+ encryption = CFDictionaryGetValue(config, kSCPropNetPPPAuthPasswordEncryption);
+ if (isA_CFString(encryption) &&
+ CFEqual(encryption, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
+ unique_id = CFDictionaryGetValue(config, kSCPropNetPPPAuthPassword);
+ }
+ }
+ if (unique_id == NULL) {
+ unique_id = serviceID;
+ }
+
+ return unique_id;
+}
+
+
+static CFStringRef
+copySharedSecretID(CFDictionaryRef config, CFStringRef serviceID)
+{
+ CFMutableStringRef shared_id = NULL;
+
+ if (config != NULL) {
+ CFStringRef encryption;
+
+ encryption = CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecretEncryption);
+ if (isA_CFString(encryption) &&
+ CFEqual(encryption, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
+ shared_id = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecret);
+ if (shared_id != NULL) {
+ CFRetain(shared_id);
+ }
+ }
+ }
+
+ if (shared_id == NULL) {
+ CFStringRef unique_id;
+
+ unique_id = getPasswordID(config, serviceID);
+ shared_id = CFStringCreateMutableCopy(NULL, 0, unique_id);
+ CFStringAppend(shared_id, CFSTR(".SS"));
+ }
+
+ return shared_id;
+}
+
+
+static CFStringRef
+copyXAuthID(CFDictionaryRef config, CFStringRef serviceID)
+{
+ CFMutableStringRef xauth_id = NULL;
+
+ if (config != NULL) {
+ CFStringRef encryption;
+
+ encryption = CFDictionaryGetValue(config, kSCPropNetIPSecXAuthPasswordEncryption);
+ if (isA_CFString(encryption) &&
+ CFEqual(encryption, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) {
+ xauth_id = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecXAuthPassword);
+ if (xauth_id != NULL) {
+ CFRetain(xauth_id);
+ }
+ }
+ }
+
+ if (xauth_id == NULL) {
+ CFStringRef unique_id;
+
+ unique_id = getPasswordID(config, serviceID);
+ xauth_id = CFStringCreateMutableCopy(NULL, 0, unique_id);
+ CFStringAppend(xauth_id, CFSTR(".XAUTH"));
+ }
+
+ return xauth_id;
+}
+
+
+static Boolean
+checkInterfacePassword(SCNetworkInterfaceRef interface,
+ SCNetworkInterfacePasswordType passwordType,
+ SCPreferencesRef *prefs,
+ CFStringRef *serviceID)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ goto error;
+ }
+
+ *serviceID = interfacePrivate->serviceID;
+ if (*serviceID == NULL) {
+ goto error;
+ }
+
+ *prefs = interfacePrivate->prefs;
+ if (*prefs == NULL) {
+ goto error;
+ }
+
+ switch (passwordType) {
+ case kSCNetworkInterfacePasswordTypePPP : {
+ CFStringRef interfaceType;
+
+ interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
+ // if PPP
+ break;
+ }
+
+ goto error;
+ }
+
+ case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
+ CFStringRef interfaceType;
+
+ interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
+ interface = SCNetworkInterfaceGetInterface(interface);
+ if (interface != NULL) {
+ interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
+ // if PPP->L2TP interface
+ break;
+ }
+ }
+ } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
+ // if IPSec interface
+ break;
+ }
+
+ goto error;
+ }
+
+ case kSCNetworkInterfacePasswordTypeEAPOL : {
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
+ CFStringRef interfaceType;
+
+ interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
+ // if IPSec interface
+ break;
+ }
+
+ goto error;
+ }
+
+ case kSCNetworkInterfacePasswordTypeVPN : {
+ CFStringRef interfaceType;
+
+ interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
+ // if VPN interface
+ break;
+ }
+
+ goto error;
+ }
+
+ default :
+ break;
+ }
+
+ return TRUE;
+
+ error :
+
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+}
+
+
+Boolean
+SCNetworkInterfaceCheckPassword(SCNetworkInterfaceRef interface,
+ SCNetworkInterfacePasswordType passwordType)
+{
+ Boolean exists = FALSE;
+ SCPreferencesRef prefs = NULL;
+ CFStringRef serviceID = NULL;
+
+ if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
+ return FALSE;
+ }
+
+ switch (passwordType) {
+ case kSCNetworkInterfacePasswordTypePPP : {
+ CFDictionaryRef config;
+ CFStringRef unique_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get serviceID
+ unique_id = getPasswordID(config, serviceID);
+
+ // check
+ exists = __extract_password(prefs,
+ config,
+ kSCPropNetPPPAuthPassword,
+ kSCPropNetPPPAuthPasswordEncryption,
+ kSCValNetPPPAuthPasswordEncryptionKeychain,
+ unique_id,
+ NULL);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
+ CFDictionaryRef config;
+ Boolean extended;
+ CFStringRef shared_id;
+
+ // get configuration
+ extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
+ if (extended) {
+ config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
+ } else {
+ config = SCNetworkInterfaceGetConfiguration(interface);
+ }
+
+ // get sharedSecret ID
+ shared_id = copySharedSecretID(config, serviceID);
+
+ // check
+ exists = __extract_password(prefs,
+ config,
+ kSCPropNetIPSecSharedSecret,
+ kSCPropNetIPSecSharedSecretEncryption,
+ kSCValNetIPSecSharedSecretEncryptionKeychain,
+ shared_id,
+ NULL);
+ CFRelease(shared_id);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeEAPOL : {
+ CFDictionaryRef config;
+ CFStringRef unique_id = NULL;
+
+ // get configuration
+ config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
+
+ // get 802.1X identifier
+ if (config != NULL) {
+ unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
+ }
+ if (!isA_CFString(unique_id)) {
+ return FALSE;
+ }
+
+ // check password
+ exists = _SCPreferencesSystemKeychainPasswordItemExists(prefs, unique_id);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
+ CFDictionaryRef config;
+ CFStringRef xauth_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get XAuth ID
+ xauth_id = copyXAuthID(config, serviceID);
+
+ // check
+ exists = __extract_password(prefs,
+ config,
+ kSCPropNetIPSecXAuthPassword,
+ kSCPropNetIPSecXAuthPasswordEncryption,
+ kSCValNetIPSecXAuthPasswordEncryptionKeychain,
+ xauth_id,
+ NULL);
+ CFRelease(xauth_id);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeVPN : {
+ CFDictionaryRef config;
+ CFStringRef vpn_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get serviceID
+ vpn_id = getPasswordID(config, serviceID);
+
+ // check
+ exists = __extract_password(prefs,
+ config,
+ kSCPropNetVPNAuthPassword,
+ kSCPropNetVPNAuthPasswordEncryption,
+ kSCValNetVPNAuthPasswordEncryptionKeychain,
+ vpn_id,
+ NULL);
+ break;
+ }
+
+ default :
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ return exists;
+}
+
+
+CFDataRef
+SCNetworkInterfaceCopyPassword(SCNetworkInterfaceRef interface,
+ SCNetworkInterfacePasswordType passwordType)
+{
+ CFDataRef password = NULL;
+ SCPreferencesRef prefs = NULL;
+ CFStringRef serviceID = NULL;
+
+ if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
+ return NULL;
+ }
+
+ switch (passwordType) {
+ case kSCNetworkInterfacePasswordTypePPP : {
+ CFDictionaryRef config;
+ CFStringRef unique_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get serviceID
+ unique_id = getPasswordID(config, serviceID);
+
+ // extract
+ (void) __extract_password(prefs,
+ config,
+ kSCPropNetPPPAuthPassword,
+ kSCPropNetPPPAuthPasswordEncryption,
+ kSCValNetPPPAuthPasswordEncryptionKeychain,
+ unique_id,
+ &password);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
+ CFDictionaryRef config;
+ Boolean extended;
+ CFStringRef shared_id;
+
+ // get configuration
+ extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
+ if (extended) {
+ config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
+ } else {
+ config = SCNetworkInterfaceGetConfiguration(interface);
+ }
+
+ // get sharedSecret ID
+ shared_id = copySharedSecretID(config, serviceID);
+
+ // extract
+ (void) __extract_password(prefs,
+ config,
+ kSCPropNetIPSecSharedSecret,
+ kSCPropNetIPSecSharedSecretEncryption,
+ kSCValNetIPSecSharedSecretEncryptionKeychain,
+ shared_id,
+ &password);
+
+ CFRelease(shared_id);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeEAPOL : {
+ CFDictionaryRef config;
+ CFStringRef unique_id = NULL;
+
+ // get configuration
+ config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
+
+ // get 802.1X identifier
+ if (config != NULL) {
+ unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
+ }
+ if (!isA_CFString(unique_id)) {
+ _SCErrorSet(kSCStatusFailed);
+ return NULL;
+ }
+
+ // copy password
+ password = _SCPreferencesSystemKeychainPasswordItemCopy(prefs, unique_id);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
+ CFDictionaryRef config;
+ CFStringRef xauth_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get XAuth ID
+ xauth_id = copyXAuthID(config, serviceID);
+
+ // extract
+ (void) __extract_password(prefs,
+ config,
+ kSCPropNetIPSecXAuthPassword,
+ kSCPropNetIPSecXAuthPasswordEncryption,
+ kSCValNetIPSecXAuthPasswordEncryptionKeychain,
+ xauth_id,
+ &password);
+ CFRelease(xauth_id);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeVPN : {
+ CFDictionaryRef config;
+ CFStringRef vpn_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get serviceID
+ vpn_id = getPasswordID(config, serviceID);
+
+ // extract
+ (void) __extract_password(prefs,
+ config,
+ kSCPropNetVPNAuthPassword,
+ kSCPropNetVPNAuthPasswordEncryption,
+ kSCValNetVPNAuthPasswordEncryptionKeychain,
+ vpn_id,
+ &password);
+ break;
+ }
+
+ default :
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ return password;
+}
+
+
+Boolean
+SCNetworkInterfaceRemovePassword(SCNetworkInterfaceRef interface,
+ SCNetworkInterfacePasswordType passwordType)
+{
+ Boolean ok = FALSE;
+ SCPreferencesRef prefs = NULL;
+ CFStringRef serviceID = NULL;
+
+ if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
+ return FALSE;
+ }
+
+ switch (passwordType) {
+ case kSCNetworkInterfacePasswordTypePPP : {
+ CFDictionaryRef config;
+ CFDictionaryRef newConfig = NULL;
+ CFStringRef unique_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get serviceID
+ unique_id = getPasswordID(config, serviceID);
+
+ // remove password
+ ok = __remove_password(prefs,
+ config,
+ kSCPropNetPPPAuthPassword,
+ kSCPropNetPPPAuthPasswordEncryption,
+ kSCValNetPPPAuthPasswordEncryptionKeychain,
+ unique_id,
+ &newConfig);
+ if (ok) {
+ ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
+ if (newConfig != NULL) CFRelease(newConfig);
+ }
+
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
+ CFDictionaryRef config;
+ Boolean extended;
+ CFDictionaryRef newConfig = NULL;
+ CFStringRef shared_id;
+
+ // get configuration
+ extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
+ if (extended) {
+ config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
+ } else {
+ config = SCNetworkInterfaceGetConfiguration(interface);
+ }
+
+ // get sharedSecret ID
+ shared_id = copySharedSecretID(config, serviceID);
+
+ // remove password
+ ok = __remove_password(prefs,
+ config,
+ kSCPropNetIPSecSharedSecret,
+ kSCPropNetIPSecSharedSecretEncryption,
+ kSCValNetIPSecSharedSecretEncryptionKeychain,
+ shared_id,
+ &newConfig);
+ if (ok) {
+ if (extended) {
+ ok = SCNetworkInterfaceSetExtendedConfiguration(interface,
+ kSCEntNetIPSec,
+ newConfig);
+ } else {
+ ok = SCNetworkInterfaceSetConfiguration(interface,
+ newConfig);
+ }
+ if (newConfig != NULL) CFRelease(newConfig);
+ }
+
+ CFRelease(shared_id);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeEAPOL : {
+ CFDictionaryRef config;
+ CFStringRef unique_id = NULL;
+
+ // get configuration
+ config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
+
+ // get 802.1X identifier
+ if (config != NULL) {
+ unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
+ }
+ if (!isA_CFString(unique_id)) {
+ _SCErrorSet(kSCStatusFailed);
+ return FALSE;
+ }
+
+ // remove password
+ ok = _SCPreferencesSystemKeychainPasswordItemRemove(prefs, unique_id);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
+ CFDictionaryRef config;
+ CFDictionaryRef newConfig = NULL;
+ CFStringRef xauth_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get XAuth ID
+ xauth_id = copyXAuthID(config, serviceID);
+
+ // remove password
+ ok = __remove_password(prefs,
+ config,
+ kSCPropNetIPSecXAuthPassword,
+ kSCPropNetIPSecXAuthPasswordEncryption,
+ kSCValNetIPSecXAuthPasswordEncryptionKeychain,
+ xauth_id,
+ &newConfig);
+ if (ok) {
+ ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
+ if (newConfig != NULL) CFRelease(newConfig);
+ }
+
+ CFRelease(xauth_id);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeVPN : {
+ CFDictionaryRef config;
+ CFDictionaryRef newConfig = NULL;
+ CFStringRef vpn_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get serviceID
+ vpn_id = getPasswordID(config, serviceID);
+
+ // remove password
+ ok = __remove_password(prefs,
+ config,
+ kSCPropNetVPNAuthPassword,
+ kSCPropNetVPNAuthPasswordEncryption,
+ kSCValNetVPNAuthPasswordEncryptionKeychain,
+ vpn_id,
+ &newConfig);
+ if (ok) {
+ ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
+ if (newConfig != NULL) CFRelease(newConfig);
+ }
+ break;
+ }
+
+ default :
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ return ok;
+}
+
+
+Boolean
+SCNetworkInterfaceSetPassword(SCNetworkInterfaceRef interface,
+ SCNetworkInterfacePasswordType passwordType,
+ CFDataRef password,
+ CFDictionaryRef options)
+{
+ CFStringRef account = NULL;
+ CFDictionaryRef config;
+ CFStringRef description = NULL;
+ CFStringRef label = NULL;
+ Boolean ok = FALSE;
+ SCPreferencesRef prefs = NULL;
+ CFStringRef serviceID = NULL;
+
+ if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
+ return FALSE;
+ }
+
+ switch (passwordType) {
+ case kSCNetworkInterfacePasswordTypePPP : {
+ SCNetworkServiceRef service = NULL;
+ CFStringRef unique_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get serviceID
+ unique_id = getPasswordID(config, serviceID);
+
+ // get "Account", "Name", "Kind"
+ if (config != NULL) {
+ // auth name --> keychain "Account"
+ account = CFDictionaryGetValue(config, kSCPropNetPPPAuthName);
+
+ // PPP [user defined] "name" --> keychain "Name"
+ label = CFDictionaryGetValue(config, kSCPropUserDefinedName);
+ }
+
+ if (label == NULL) {
+ // service name --> keychain "Name"
+ service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
+ prefs,
+ serviceID,
+ interface);
+
+ label = SCNetworkServiceGetName(service);
+ if (label == NULL) {
+ // interface name --> keychain "Name"
+ label = SCNetworkInterfaceGetLocalizedDisplayName(interface);
+ }
+ }
+
+ if (bundle != NULL) {
+ // "PPP Password" --> keychain "Kind"
+ description = CFBundleCopyLocalizedString(bundle,
+ CFSTR("KEYCHAIN_KIND_PPP_PASSWORD"),
+ CFSTR("PPP Password"),
+ NULL);
+ }
+
+ // store password
+ ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
+ unique_id,
+ (label != NULL) ? label : CFSTR("Network Connection"),
+ (description != NULL) ? description : CFSTR("PPP Password"),
+ account,
+ password,
+ options);
+ if (ok) {
+ CFMutableDictionaryRef newConfig;
+
+ if (config != NULL) {
+ newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
+ } else {
+ newConfig = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ CFDictionarySetValue(newConfig,
+ kSCPropNetPPPAuthPassword,
+ unique_id);
+ CFDictionarySetValue(newConfig,
+ kSCPropNetPPPAuthPasswordEncryption,
+ kSCValNetPPPAuthPasswordEncryptionKeychain);
+ ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
+ CFRelease(newConfig);
+ }
+
+ if (description != NULL) CFRelease(description);
+ if (service != NULL) CFRelease(service);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
+ CFDictionaryRef baseConfig = NULL;
+ Boolean extended;
+ SCNetworkServiceRef service = NULL;
+ CFStringRef shared_id;
+
+ // get configuration
+ extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
+ config = SCNetworkInterfaceGetConfiguration(interface);
+ if (extended) {
+ baseConfig = config;
+ config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
+ }
+
+ // get sharedSecret ID
+ shared_id = copySharedSecretID(config, serviceID);
+
+ // get "Account", "Name", "Kind"
+ if (config != NULL) {
+ CFStringRef localIdentifier;
+ CFStringRef localIdentifierType;
+
+ if (CFDictionaryGetValueIfPresent(config,
+ kSCPropNetIPSecLocalIdentifierType,
+ (const void **)&localIdentifierType)
+ && CFEqual(localIdentifierType, kSCValNetIPSecLocalIdentifierTypeKeyID)
+ && CFDictionaryGetValueIfPresent(config,
+ kSCPropNetIPSecLocalIdentifier,
+ (const void **)&localIdentifier)
+ && isA_CFString(localIdentifier)) {
+ // local identifier --> keychain "Account"
+ account = localIdentifier;
+ }
+
+ // PPP [user defined] "name" --> keychain "Name"
+ if (!extended) {
+ label = CFDictionaryGetValue(config, kSCPropUserDefinedName);
+ } else {
+ if (baseConfig != NULL) {
+ label = CFDictionaryGetValue(baseConfig, kSCPropUserDefinedName);
+ }
+ }
+ }
+
+ if (label == NULL) {
+ // service name --> keychain "Name"
+ service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
+ prefs,
+ serviceID,
+ interface);
+
+ label = SCNetworkServiceGetName(service);
+ if (label == NULL) {
+ // interface name --> keychain "Name"
+ label = SCNetworkInterfaceGetLocalizedDisplayName(interface);
+ }
+ }
+
+ if (bundle != NULL) {
+ // "IPSec Shared Secret" --> keychain "Kind"
+ description = CFBundleCopyLocalizedString(bundle,
+ CFSTR("KEYCHAIN_KIND_IPSEC_SHARED_SECRET"),
+ CFSTR("IPSec Shared Secret"),
+ NULL);
+ }
+
+ // set password
+ ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
+ shared_id,
+ (label != NULL) ? label : CFSTR("Network Connection"),
+ (description != NULL) ? description : CFSTR("IPSec Shared Secret"),
+ account,
+ password,
+ options);
+ if (ok) {
+ CFMutableDictionaryRef newConfig = NULL;
+
+ if (config != NULL) {
+ newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
+ } else {
+ newConfig = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ CFDictionarySetValue(newConfig,
+ kSCPropNetIPSecSharedSecret,
+ shared_id);
+ CFDictionarySetValue(newConfig,
+ kSCPropNetIPSecSharedSecretEncryption,
+ kSCValNetIPSecSharedSecretEncryptionKeychain);
+ if (extended) {
+ ok = SCNetworkInterfaceSetExtendedConfiguration(interface,
+ kSCEntNetIPSec,
+ newConfig);
+ } else {
+ ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
+ }
+ CFRelease(newConfig);
+ }
+
+ if (description != NULL) CFRelease(description);
+ if (service != NULL) CFRelease(service);
+ CFRelease(shared_id);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeEAPOL : {
+ CFStringRef account = NULL;
+ CFStringRef unique_id = NULL;
+
+ // get configuration
+ config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
+
+ // get 802.1X identifier
+ if (config != NULL) {
+ unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
+ unique_id = isA_CFString(unique_id);
+ }
+ if (unique_id != NULL) {
+ CFRetain(unique_id);
+ } else {
+ CFUUIDRef uuid;
+
+ uuid = CFUUIDCreate(NULL);
+ unique_id = CFUUIDCreateString(NULL, uuid);
+ CFRelease(uuid);
+ }
+
+ // 802.1x UserName --> keychain "Account"
+ if (config != NULL) {
+ account = CFDictionaryGetValue(config, kEAPClientPropUserName);
+ }
+
+ // get "Name", "Kind"
+ if (bundle != NULL) {
+ CFStringRef interface_name;
+
+ // "Network Connection (%@)" --> keychain "Name"
+ interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
+ if (interface_name != NULL) {
+ CFStringRef label_fmt;
+
+ label_fmt = CFBundleCopyLocalizedString(bundle,
+ CFSTR("KEYCHAIN_DESCRIPTION_EAPOL_INTERFACE"),
+ CFSTR("Network Connection (%@)"),
+ NULL);
+ label = CFStringCreateWithFormat(NULL, NULL, label_fmt, interface_name);
+ CFRelease(label_fmt);
+ } else {
+ label = CFBundleCopyLocalizedString(bundle,
+ CFSTR("KEYCHAIN_DESCRIPTION_EAPOL"),
+ CFSTR("Network Connection"),
+ NULL);
+ }
+
+ // "802.1X Password" --> keychain "Kind"
+ description = CFBundleCopyLocalizedString(bundle,
+ CFSTR("KEYCHAIN_KIND_EAPOL"),
+ CFSTR("802.1X Password"),
+ NULL);
+ }
+
+ // set password
+ ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
+ unique_id,
+ (label != NULL) ? label : CFSTR("Network Connection"),
+ (description != NULL) ? description : CFSTR("802.1X Password"),
+ account,
+ password,
+ options);
+ if (ok) {
+ CFMutableDictionaryRef newConfig = NULL;
+
+ if (config != NULL) {
+ newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
+ } else {
+ newConfig = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ CFDictionarySetValue(newConfig,
+ kEAPClientPropUserPasswordKeychainItemID,
+ unique_id);
+ ok = SCNetworkInterfaceSetExtendedConfiguration(interface,
+ kSCEntNetEAPOL,
+ newConfig);
+ CFRelease(newConfig);
+ }
+
+ CFRelease(unique_id);
+ if (label != NULL) CFRelease(label);
+ if (description != NULL) CFRelease(description);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
+ SCNetworkServiceRef service = NULL;
+ CFStringRef xauth_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get XAuth ID
+ xauth_id = copyXAuthID(config, serviceID);
+
+ // get "Account", "Name", "Kind"
+ if (config != NULL) {
+ // auth name --> keychain "Account"
+ account = CFDictionaryGetValue(config, kSCPropNetIPSecXAuthName);
+
+ // IPSec [user defined] "name" --> keychain "Name"
+ label = CFDictionaryGetValue(config, kSCPropUserDefinedName);
+ }
+
+ if (label == NULL) {
+ // service name --> keychain "Name"
+ service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
+ prefs,
+ serviceID,
+ interface);
+
+ label = SCNetworkServiceGetName(service);
+ if (label == NULL) {
+ // interface name --> keychain "Name"
+ label = SCNetworkInterfaceGetLocalizedDisplayName(interface);
+ }
+ }
+
+ if (bundle != NULL) {
+ // "IPSec XAuth Password" --> keychain "Kind"
+ description = CFBundleCopyLocalizedString(bundle,
+ CFSTR("KEYCHAIN_KIND_IPSEC_XAUTH_PASSWORD"),
+ CFSTR("IPSec XAuth Password"),
+ NULL);
+ }
+
+ // store password
+ ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
+ xauth_id,
+ (label != NULL) ? label : CFSTR("Network Connection"),
+ (description != NULL) ? description : CFSTR("IPSec XAuth Password"),
+ account,
+ password,
+ options);
+ if (ok) {
+ CFMutableDictionaryRef newConfig;
+
+ if (config != NULL) {
+ newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
+ } else {
+ newConfig = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ CFDictionarySetValue(newConfig,
+ kSCPropNetIPSecXAuthPassword,
+ xauth_id);
+ CFDictionarySetValue(newConfig,
+ kSCPropNetIPSecXAuthPasswordEncryption,
+ kSCValNetIPSecXAuthPasswordEncryptionKeychain);
+ ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
+ CFRelease(newConfig);
+ }
+
+ CFRelease(xauth_id);
+ if (description != NULL) CFRelease(description);
+ if (service != NULL) CFRelease(service);
+ break;
+ }
+
+ case kSCNetworkInterfacePasswordTypeVPN : {
+ SCNetworkServiceRef service = NULL;
+ CFStringRef vpn_id;
+
+ // get configuration
+ config = SCNetworkInterfaceGetConfiguration(interface);
+
+ // get serviceID
+ vpn_id = getPasswordID(config, serviceID);
+
+ // get "Account", "Name", "Kind"
+ if (config != NULL) {
+ // auth name --> keychain "Account"
+ account = CFDictionaryGetValue(config, kSCPropNetVPNAuthName);
+
+ // VPN [user defined] "name" --> keychain "Name"
+ label = CFDictionaryGetValue(config, kSCPropUserDefinedName);
+ }
+
+ if (label == NULL) {
+ // service name --> keychain "Name"
+ service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
+ prefs,
+ serviceID,
+ interface);
+
+ label = SCNetworkServiceGetName(service);
+ if (label == NULL) {
+ // interface name --> keychain "Name"
+ label = SCNetworkInterfaceGetLocalizedDisplayName(interface);
+ }
+ }
+
+ if (bundle != NULL) {
+ // "VPN Password" --> keychain "Kind"
+ description = CFBundleCopyLocalizedString(bundle,
+ CFSTR("KEYCHAIN_KIND_VPN_PASSWORD"),
+ CFSTR("VPN Password"),
+ NULL);
+ }
+
+ // store password
+ ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
+ vpn_id,
+ (label != NULL) ? label : CFSTR("Network Connection"),
+ (description != NULL) ? description : CFSTR("VPN Password"),
+ account,
+ password,
+ options);
+ if (ok) {
+ CFMutableDictionaryRef newConfig;
+
+ if (config != NULL) {
+ newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
+ } else {
+ newConfig = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ CFDictionarySetValue(newConfig,
+ kSCPropNetVPNAuthPassword,
+ vpn_id);
+ CFDictionarySetValue(newConfig,
+ kSCPropNetVPNAuthPasswordEncryption,
+ kSCValNetVPNAuthPasswordEncryptionKeychain);
+ ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
+ CFRelease(newConfig);
+ }
+
+ if (description != NULL) CFRelease(description);
+ if (service != NULL) CFRelease(service);
+ break;
+ }
+
+ default :
+ _SCErrorSet(kSCStatusInvalidArgument);
+ break;
+ }
+
+ return ok;
+}
+
+#pragma mark -
+#pragma mark SCNetworkInterface [Advisory] SPIs
+#if TARGET_OS_SIMULATOR
+Boolean
+SCNetworkInterfaceSetAdvisory(SCNetworkInterfaceRef interface,
+ SCNetworkInterfaceAdvisory advisory,
+ CFStringRef reason)
+{
+#pragma unused(interface)
+#pragma unused(advisory)
+#pragma unused(reason)
+ return (FALSE);
+}
+
+Boolean
+SCNetworkInterfaceAdvisoryIsSet(SCNetworkInterfaceRef interface)
+{
+#pragma unused(interface)
+ return (FALSE);
+}
+
+CFStringRef
+SCNetworkInterfaceCopyAdvisoryNotificationKey(SCNetworkInterfaceRef interface)
+{
+#pragma unused(interface)
+ return (NULL);
+}
+
+#else /* TARGET_OS_SIMULATOR */
+Boolean
+SCNetworkInterfaceSetAdvisory(SCNetworkInterfaceRef interface,
+ SCNetworkInterfaceAdvisory advisory,
+ CFStringRef reason)
+{
+ IPMonitorControlRef control;
+ SCNetworkInterfacePrivateRef interfacePrivate =
+ (SCNetworkInterfacePrivateRef)interface;
+ CFStringRef ifName;
+
+ ifName = SCNetworkInterfaceGetBSDName(interface);
+ if (ifName == NULL) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return (FALSE);
+ }
+ control = interfacePrivate->IPMonitorControl;
+ if (control == NULL) {
+ control = IPMonitorControlCreate();
+ if (control == NULL) {
+ _SCErrorSet(kSCStatusFailed);
+ return (FALSE);
+ }
+ interfacePrivate->IPMonitorControl = control;
+ }
+ return IPMonitorControlSetInterfaceAdvisory(control,
+ ifName,
+ advisory,
+ reason);
+}
+
+Boolean
+SCNetworkInterfaceAdvisoryIsSet(SCNetworkInterfaceRef interface)
+{
+ IPMonitorControlRef control;
+ SCNetworkInterfacePrivateRef interfacePrivate =
+ (SCNetworkInterfacePrivateRef)interface;
+ CFStringRef ifName;
+
+ ifName = SCNetworkInterfaceGetBSDName(interface);
+ if (ifName == NULL) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return (FALSE);
+ }
+ control = interfacePrivate->IPMonitorControl;
+ if (control == NULL) {
+ control = IPMonitorControlCreate();
+ if (control == NULL) {
+ _SCErrorSet(kSCStatusFailed);
+ return (FALSE);
+ }
+ interfacePrivate->IPMonitorControl = control;
+ }
+ return IPMonitorControlInterfaceAdvisoryIsSet(control, ifName);
+}
+
+CFStringRef
+SCNetworkInterfaceCopyAdvisoryNotificationKey(SCNetworkInterfaceRef interface)
+{
+ CFStringRef ifName;
+
+ ifName = SCNetworkInterfaceGetBSDName(interface);
+ if (ifName == NULL) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return (NULL);
+ }
+ return IPMonitorControlCopyInterfaceAdvisoryNotificationKey(ifName);
+}
+#endif /* TARGET_OS_SIMULATOR */
+
+#pragma mark -
+#pragma mark SCNetworkInterface [InterfaceNamer] SPIs
+
+
+CFDictionaryRef
+_SCNetworkInterfaceCopyInterfaceInfo(SCNetworkInterfaceRef interface)
+{
+ CFMutableDictionaryRef info;
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+ CFStringRef name;
+
+ if (interface == NULL) {
+ return NULL;
+ }
+
+ info = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ // add non-localized interface name
+ name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
+ if (name != NULL) {
+ CFDictionaryAddValue(info, kSCPropUserDefinedName, name);
+ }
+
+ // add USB info
+ if ((interfacePrivate->usb.vid != NULL) || (interfacePrivate->usb.pid != NULL)) {
+#if !TARGET_OS_SIMULATOR
+ if (interfacePrivate->usb.name != NULL) {
+ CFDictionaryAddValue(info, CFSTR(kUSBProductString), interfacePrivate->usb.name);
+ }
+ if (interfacePrivate->usb.vid != NULL) {
+ CFDictionaryAddValue(info, CFSTR(kUSBVendorID), interfacePrivate->usb.vid);
+ }
+ if (interfacePrivate->usb.pid != NULL) {
+ CFDictionaryAddValue(info, CFSTR(kUSBProductID), interfacePrivate->usb.pid);
+ }
+#endif // !TARGET_OS_SIMULATOR
+ }
+
+ if (CFDictionaryGetCount(info) == 0) {
+ // do not return an empty dictionary
+ CFRelease(info);
+ info = NULL;
+ }
+
+ return info;
+}
+
+
+SCNetworkInterfaceRef
+_SCNetworkInterfaceCreateWithIONetworkInterfaceObject(io_object_t if_obj)
+{
+ SCNetworkInterfaceRef interface = NULL;
+
+ /* initialize runtime */
+ pthread_once(&initialized, __SCNetworkInterfaceInitialize);
+
+ if (IOObjectConformsTo(if_obj, kIONetworkInterfaceClass)) {
+ interface = createInterface(if_obj, processNetworkInterface, NULL);
+ } else if (IOObjectConformsTo(if_obj, kIOSerialBSDServiceValue)) {
+ interface = createInterface(if_obj, processSerialInterface, kSCNetworkInterfaceHiddenPortKey);
+ }
+
+ return interface;
+}
+
+
+CFStringRef
+_SCNetworkInterfaceGetConfigurationAction(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->configurationAction;
+}
+
+
+CFDataRef
+_SCNetworkInterfaceGetHardwareAddress(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->address;
+}
+
+
+CFStringRef
+_SCNetworkInterfaceGetIOInterfaceNamePrefix(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->prefix;
+}
+
+
+CFNumberRef
+_SCNetworkInterfaceGetIOInterfaceType(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->type;
+}
+
+
+CFNumberRef
+_SCNetworkInterfaceGetIOInterfaceUnit(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->unit;
+}
+
+
+static void
+update_ift_family(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ // note: family/subfamily are not in IORegistry, fetch with ioctl()
+
+ if ((interfacePrivate->family == NULL) && (interfacePrivate->subfamily == NULL)) {
+ CFStringRef bsdName = SCNetworkInterfaceGetBSDName(interface);
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ if ((bsdName != NULL) &&
+ _SC_cfstring_to_cstring(bsdName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) != NULL) {
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s != -1) {
+ if (ioctl(s, SIOCGIFTYPE, (caddr_t)&ifr) == -1) {
+ ifr.ifr_type.ift_family = 0;
+ ifr.ifr_type.ift_subfamily = 0;
+ }
+ close(s);
+ }
+ }
+
+ interfacePrivate->family = CFNumberCreate(NULL,
+ kCFNumberSInt32Type,
+ &ifr.ifr_type.ift_family);
+ interfacePrivate->subfamily = CFNumberCreate(NULL,
+ kCFNumberSInt32Type,
+ &ifr.ifr_type.ift_subfamily);
+ }
+}
+
+
+CFNumberRef
+_SCNetworkInterfaceGetFamilyType(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ // note: family not in IORegistry, fetch with ioctl()
+
+ if (interfacePrivate->family == NULL) {
+ update_ift_family(interface);
+ }
+
+ return interfacePrivate->family;
+}
+
+
+CFNumberRef
+_SCNetworkInterfaceGetFamilySubType(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ // note: subfamily not in IORegistry, fetch with ioctl()
+
+ if (interfacePrivate->subfamily == NULL) {
+ update_ift_family(interface);
+ }
+
+ return interfacePrivate->subfamily;
+}
+
+
+CFStringRef
+_SCNetworkInterfaceGetIOPath(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->path;
+}
+
+
+uint64_t
+_SCNetworkInterfaceGetIORegistryEntryID(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->entryID;
+}
+
+
+__private_extern__
+Boolean
+__SCNetworkInterfaceIsActive (SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->active;
+}
+
+
+Boolean
+_SCNetworkInterfaceIsBuiltin(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->builtin;
+}
+
+
+Boolean
+_SCNetworkInterfaceIsTrustRequired(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->trustRequired;
+}
+
+
+#pragma mark -
+#pragma mark SCNetworkInterface SPIs
+
+
+#if TARGET_OS_OSX
+
+SCNetworkInterfaceRef
+_SCNetworkInterfaceCopyBTPANInterface(void)
+{
+ CFDictionaryRef dict;
+ SCNetworkInterfaceRef interface = NULL;
+ CFStringRef key;
+
+ key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" "InterfaceNamer"), kSCDynamicStoreDomainPlugin);
+ dict = SCDynamicStoreCopyValue(NULL, key);
+ CFRelease(key);
+ if (dict != NULL) {
+ CFDataRef addr;
+ CFStringRef if_name;
+ SCNetworkInterfacePrivateRef interfacePrivate;
+
+ if (isA_CFDictionary(dict) &&
+ CFDictionaryGetValueIfPresent(dict,
+ kInterfaceNamerKey_BT_PAN_Name,
+ (const void **)&if_name) &&
+ isA_CFString(if_name)) {
+ CFMutableDictionaryRef entity;
+
+ entity = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFDictionarySetValue(entity,
+ kSCPropNetInterfaceType,
+ kSCValNetInterfaceTypeEthernet);
+ CFDictionarySetValue(entity,
+ kSCPropNetInterfaceDeviceName,
+ if_name);
+ CFDictionarySetValue(entity,
+ kSCPropUserDefinedName,
+ CFSTR(BT_PAN_NAME));
+ interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, NULL);
+ CFRelease(entity);
+ }
+
+ interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if ((interfacePrivate != NULL) &&
+ (interfacePrivate->address == NULL) &&
+ CFDictionaryGetValueIfPresent(dict,
+ kInterfaceNamerKey_BT_PAN_Mac,
+ (const void **)&addr) &&
+ isA_CFData(addr)) {
+ interfacePrivate->address = CFRetain(addr);
+ }
+
+ CFRelease(dict);
+ }
+
+ return interface;
+}
+#endif // TARGET_OS_OSX
+
+
+CFStringRef
+_SCNetworkInterfaceCopySlashDevPath(SCNetworkInterfaceRef interface)
+{
+ io_registry_entry_t device;
+ io_iterator_t device_iterator = MACH_PORT_NULL;
+ CFStringRef device_path = NULL;
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+ kern_return_t kr;
+ CFStringRef match_keys[2];
+ CFTypeRef match_vals[2];
+ CFDictionaryRef match_dict;
+ CFDictionaryRef matching;
+
+ if (interfacePrivate->entity_device == NULL) {
+ return NULL;
+ }
+
+ if (interfacePrivate->entity_device_unique == NULL) {
+ goto done;
+ }
+
+ match_keys[0] = CFSTR(kIOTTYBaseNameKey);
+ match_vals[0] = interfacePrivate->entity_device;
+ match_dict = CFDictionaryCreate(NULL,
+ (const void **)match_keys,
+ (const void **)match_vals,
+ 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ match_keys[0] = CFSTR(kIOProviderClassKey);
+ match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
+ match_keys[1] = CFSTR(kIOPropertyMatchKey);
+ match_vals[1] = match_dict;
+ matching = CFDictionaryCreate(NULL,
+ (const void **)match_keys,
+ (const void **)match_vals,
+ sizeof(match_keys)/sizeof(match_keys[0]),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFRelease(match_dict);
+
+ // note: this "matching" dictionary will be consumed by the call to IOServiceGetMatchingServices
+ kr = IOServiceGetMatchingServices(masterPort, matching, &device_iterator);
+ if (kr != kIOReturnSuccess) {
+ SC_log(LOG_INFO, "IOServiceGetMatchingServices() failed, kr = 0x%x", kr);
+ goto done;
+ }
+
+ while ((device_path == NULL) &&
+ ((device = IOIteratorNext(device_iterator)) != MACH_PORT_NULL)) {
+ CFDictionaryRef overrides;
+
+ overrides = IORegistryEntrySearchCFProperty(device,
+ kIOServicePlane,
+ kSCNetworkInterfaceNetworkConfigurationOverridesKey,
+ NULL,
+ kIORegistryIterateRecursively | kIORegistryIterateParents);
+ if (overrides != NULL) {
+ CFDictionaryRef modemOverrides;
+
+ modemOverrides = CFDictionaryGetValue(overrides, kSCEntNetModem);
+ if (modemOverrides != NULL) {
+ CFRetain(modemOverrides);
+ }
+ CFRelease(overrides);
+ overrides = modemOverrides;
+ }
+ if (overrides == NULL) {
+ overrides = IORegistryEntrySearchCFProperty(device,
+ kIOServicePlane,
+ CFSTR("DeviceModemOverrides"),
+ NULL,
+ kIORegistryIterateRecursively | kIORegistryIterateParents);
+ }
+ if (overrides != NULL) {
+ if (isA_CFDictionary(overrides)) {
+ CFStringRef matchIdentifier;
+
+ matchIdentifier = CFDictionaryGetValue(overrides, CFSTR("UniqueIdentifier"));
+ if (isA_CFString(matchIdentifier) &&
+ CFEqual(interfacePrivate->entity_device_unique, matchIdentifier)) {
+ device_path = IORegistryEntryCreateCFProperty(device,
+ CFSTR(kIOTTYDeviceKey),
+ NULL,
+ 0);
+ }
+ }
+ CFRelease(overrides);
+ }
+ IOObjectRelease(device);
+ }
+
+ IOObjectRelease(device_iterator);
+
+ done :
+
+ if (device_path == NULL) {
+ // if we haven't found an exact match to our UniqueIdentifier
+ // so we simply return the base name.
+ device_path = SCNetworkInterfaceGetBSDName(interface);
+ if (device_path != NULL) {
+ CFRetain(device_path);
+ }
+ }
+
+ return device_path;
+}
+
+
+#pragma mark -
+
+
+Boolean
+_SCNetworkInterfaceIsApplePreconfigured(SCNetworkInterfaceRef interface)
+{
+#if TARGET_OS_SIMULATOR
+#pragma unused(interface)
+#else // TARGET_OS_SIMULATOR
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ if (!_SCNetworkInterfaceIsHiddenConfiguration(interface)) {
+ // if not HiddenConfiguration
+ return FALSE;
+ }
+
+ if ((interfacePrivate->overrides == NULL) ||
+ (!CFDictionaryContainsKey(interfacePrivate->overrides, kSCNetworkProtocolTypeIPv4) &&
+ !CFDictionaryContainsKey(interfacePrivate->overrides, kSCNetworkProtocolTypeIPv6))) {
+ // if no [IPv4/IPv6] configuration overrides
+ return FALSE;
+ }
+
+ if (_SCNetworkInterfaceIsBuiltin(interface)) {
+ // if built-in (and overrides are present)
+ return TRUE;
+ }
+
+ if (_SCNetworkInterfaceIsCarPlay(interface)) {
+ // if CarPlay (and overrides are present)
+ return TRUE;
+ }
+
+ if (isA_CFNumber(interfacePrivate->usb.vid)) {
+ int vid;
+
+ if (CFNumberGetValue(interfacePrivate->usb.vid, kCFNumberIntType, &vid) &&
+ (vid == kIOUSBVendorIDAppleComputer)) {
+ // if Apple interface (and overrides are present)
+ return TRUE;
+ }
+ }
+#endif // TARGET_OS_SIMULATOR
+
+ return FALSE;
+}
+
+
+Boolean
+_SCNetworkInterfaceIsBluetoothPAN(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return (interfacePrivate->sort_order == kSortBluetoothPAN_GN);
+}
+
+
+Boolean
+_SCNetworkInterfaceIsBluetoothPAN_NAP(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return (interfacePrivate->sort_order == kSortBluetoothPAN_NAP);
+}
+
+
+Boolean
+_SCNetworkInterfaceIsBluetoothP2P(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return (interfacePrivate->sort_order == kSortBluetoothPAN_U);
+}
+
+
+Boolean
+_SCNetworkInterfaceIsCarPlay(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return (interfacePrivate->sort_order == kSortCarPlay);
+}
+
+
+Boolean
+_SCNetworkInterfaceIsHiddenConfiguration(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return interfacePrivate->hidden;
+}
+
+
+Boolean
+_SCNetworkInterfaceIsTethered(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+
+ return (interfacePrivate->sort_order == kSortTethered);
+}
+
+
+Boolean
+_SCNetworkInterfaceIsThunderbolt(SCNetworkInterfaceRef interface)
+{
+ SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
+ CFStringRef interfaceType;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ return FALSE;
+ }
+
+ interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) {
+ CFIndex i;
+ CFArrayRef members;
+ CFIndex n;
+
+ members = SCBridgeInterfaceGetMemberInterfaces(interface);
+ n = (members != NULL) ? CFArrayGetCount(members) : 0;
+ if (n == 0) {
+ // if an empty bridge
+ return FALSE;
+ }
+
+ for (i = 0; i < n; i++) {
+ SCNetworkInterfaceRef member;
+ SCNetworkInterfacePrivateRef memberPrivate;
+
+ member = CFArrayGetValueAtIndex(members, i);
+ memberPrivate = (SCNetworkInterfacePrivateRef)member;
+ if (memberPrivate->sort_order != kSortThunderbolt) {
+ return FALSE;
+ }
+ }
+
+ // if Ethernet Bridge interface with only Thunderbolt [IP] members
+ return TRUE;
+ }
+
+ return (interfacePrivate->sort_order == kSortThunderbolt);
+}
+
+
+#pragma mark -
+
+
+CFDictionaryRef
+SCNetworkInterfaceGetQoSMarkingPolicy(SCNetworkInterfaceRef interface)
+{
+ CFDictionaryRef policy;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ policy = __SCNetworkInterfaceGetConfiguration(interface, kSCEntNetQoSMarkingPolicy);
+ if (policy == NULL) {
+ _SCErrorSet(kSCStatusOK);
+ }
+
+ return policy;
+}
+
+Boolean
+SCNetworkInterfaceSetQoSMarkingPolicy(SCNetworkInterfaceRef interface, CFDictionaryRef policy)
+{
+ Boolean ok;
+
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ ok = __SCNetworkInterfaceSetConfiguration(interface, kSCEntNetQoSMarkingPolicy, policy, FALSE);
+ if (ok) {
+ SC_log(LOG_DEBUG, "SCNetworkInterfaceSetQoSMarkingPolicy(): %@ -> %@",
+ interface,
+ policy != NULL ? policy : (CFDictionaryRef)CFSTR("NULL"));
+ }
+
+ return ok;
+}
+
+
+#pragma mark -
+#pragma mark SCNetworkInterface [internal] SPIs
+
+
+__private_extern__
+SCNetworkInterfacePrivateRef
+__SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator,
+ SCNetworkInterfaceRef interface,
+ SCPreferencesRef prefs,
+ CFStringRef serviceID)
+{
+#pragma unused(allocator)
+ SCNetworkInterfacePrivateRef oldPrivate = (SCNetworkInterfacePrivateRef)interface;
+ SCNetworkInterfacePrivateRef newPrivate;
+
+ /* initialize runtime (and kSCNetworkInterfaceIPv4) */
+ pthread_once(&initialized, __SCNetworkInterfaceInitialize);
+
+ if (interface == kSCNetworkInterfaceIPv4) {
+ return (SCNetworkInterfacePrivateRef)CFRetain(interface);
+ }
+
+ newPrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, prefs, serviceID);
+ newPrivate->interface_type = oldPrivate->interface_type;
+ if (oldPrivate->interface != NULL) {
+ newPrivate->interface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL, // allocator
+ oldPrivate->interface, // interface
+ prefs, // [new] prefs
+ serviceID); // [new] serviceID
+ }
+ if (oldPrivate->name != NULL) {
+ newPrivate->name = CFRetain(oldPrivate->name);
+ }
+ if (oldPrivate->prefix != NULL) {
+ newPrivate->prefix = CFRetain(oldPrivate->prefix);
+ }
+ if (oldPrivate->localized_name != NULL) {
+ newPrivate->localized_name = CFRetain(oldPrivate->localized_name);
+ }
+ newPrivate->localized_key = oldPrivate->localized_key;
+ if (oldPrivate->localized_arg1 != NULL) {
+ newPrivate->localized_arg1 = CFRetain(oldPrivate->localized_arg1);
+ }
+ if (oldPrivate->localized_arg2 != NULL) {
+ newPrivate->localized_arg2 = CFRetain(oldPrivate->localized_arg2);
+ }
+ if (oldPrivate->unsaved != NULL) {
+ newPrivate->unsaved = CFDictionaryCreateMutableCopy(NULL, 0, oldPrivate->unsaved);
+ }
+ if (oldPrivate->entity_device != NULL) {
+ newPrivate->entity_device = CFRetain(oldPrivate->entity_device);
+ }
+ if (oldPrivate->entity_device_unique != NULL) {
+ newPrivate->entity_device_unique = CFRetain(oldPrivate->entity_device_unique);
+ }
+ newPrivate->entity_type = oldPrivate->entity_type;
+ newPrivate->entity_subtype = oldPrivate->entity_subtype;
+ if (oldPrivate->supported_interface_types != NULL) {
+ newPrivate->supported_interface_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_interface_types);
+ }
+ if (oldPrivate->supported_protocol_types != NULL) {
+ newPrivate->supported_protocol_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_protocol_types);
+ }
+ if (oldPrivate->address != NULL) {
+ newPrivate->address = CFRetain(oldPrivate->address);
+ }
+ newPrivate->builtin = oldPrivate->builtin;
+ if (oldPrivate->configurationAction != NULL) {
+ newPrivate->configurationAction = CFRetain(oldPrivate->configurationAction);
+ }
+ newPrivate->hidden = oldPrivate->hidden;
+#if TARGET_OS_IPHONE
+ newPrivate->trustRequired = oldPrivate->trustRequired;
+#endif // TARGET_OS_IPHONE
+ if (oldPrivate->location != NULL) {
+ newPrivate->location = CFRetain(oldPrivate->location);
+ }
+ if (oldPrivate->path != NULL) {
+ newPrivate->path = CFRetain(oldPrivate->path);
+ }
+ newPrivate->entryID = oldPrivate->entryID;
+ if (oldPrivate->overrides != NULL) {
+ newPrivate->overrides = CFDictionaryCreateMutableCopy(NULL, 0, oldPrivate->overrides);
+ }
+ if (oldPrivate->type != NULL) {
+ newPrivate->type = CFRetain(oldPrivate->type);
+ }
+ if (oldPrivate->unit != NULL) {
+ newPrivate->unit = CFRetain(oldPrivate->unit);
+ }
+ if (oldPrivate->family != NULL) {
+ newPrivate->family = CFRetain(oldPrivate->family);
+ }
+ if (oldPrivate->subfamily != NULL) {
+ newPrivate->subfamily = CFRetain(oldPrivate->subfamily);
+ }
+ if (oldPrivate->usb.name != NULL) {
+ newPrivate->usb.name = CFRetain(oldPrivate->usb.name);
+ }
+ if (oldPrivate->usb.vid != NULL) {
+ newPrivate->usb.vid = CFRetain(oldPrivate->usb.vid);
+ }
+ if (oldPrivate->usb.pid != NULL) {
+ newPrivate->usb.pid = CFRetain(oldPrivate->usb.pid);
+ }
+ newPrivate->sort_order = oldPrivate->sort_order;
+
+ newPrivate->supportsBond = oldPrivate->supportsBond;
+ if (oldPrivate->bond.interfaces != NULL) {
+ newPrivate->bond.interfaces = CFRetain(oldPrivate->bond.interfaces);
+ }
+ if (oldPrivate->bond.mode != NULL) {
+ newPrivate->bond.mode = CFRetain(oldPrivate->bond.mode);
+ }
+ if (oldPrivate->bond.options != NULL) {
+ newPrivate->bond.options = CFRetain(oldPrivate->bond.options);
+ }
+
+ newPrivate->supportsBridge = oldPrivate->supportsBridge;
+ if (oldPrivate->bridge.interfaces != NULL) {
+ newPrivate->bridge.interfaces = CFRetain(oldPrivate->bridge.interfaces);
+ }
+ if (oldPrivate->bridge.options != NULL) {
+ newPrivate->bridge.options = CFRetain(oldPrivate->bridge.options);
+ }
+
+ newPrivate->supportsVLAN = oldPrivate->supportsVLAN;
+ if (oldPrivate->vlan.interface != NULL) {
+ newPrivate->vlan.interface = CFRetain(oldPrivate->vlan.interface);
+ }
+ if (oldPrivate->vlan.tag != NULL) {
+ newPrivate->vlan.tag = CFRetain(oldPrivate->vlan.tag);
+ }
+ if (oldPrivate->vlan.options != NULL) {
+ newPrivate->vlan.options = CFRetain(oldPrivate->vlan.options);
+ }
+
+ return newPrivate;
+}
+
+
+__private_extern__
+CFArrayRef
+__SCNetworkInterfaceCopyDeepConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
+{
+ CFMutableArrayRef configs;
+
+ configs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ while (interface != NULL) {
+ CFStringRef defaultType;
+ CFMutableDictionaryRef interfaceConfiguration;
+
+ interfaceConfiguration = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
+ if (defaultType != NULL) {
+ CFDictionaryRef config;
+ CFArrayRef extendedTypes;
+
+ if (set == NULL) {
+ config = __SCNetworkInterfaceGetConfiguration(interface, defaultType);
+ } else {
+ config = __SCNetworkInterfaceGetDefaultConfiguration(set, interface);
+ }
+ if (config == NULL) {
+ config = (CFDictionaryRef)kCFNull;
+ }
+ CFDictionarySetValue(interfaceConfiguration, defaultType, config);
+
+ extendedTypes = extendedConfigurationTypes(interface);
+ if (extendedTypes != NULL) {
+ CFIndex i;
+ CFIndex n;
+
+ n = CFArrayGetCount(extendedTypes);
+ for (i = 0; i < n; i++) {
+ CFStringRef extendedType;
+
+ extendedType = CFArrayGetValueAtIndex(extendedTypes, i);
+ config = __SCNetworkInterfaceGetConfiguration(interface, extendedType);
+ if (config == NULL) {
+ config = (CFDictionaryRef)kCFNull;
+ }
+ CFDictionarySetValue(interfaceConfiguration, extendedType, config);
+ }
+
+ CFRelease(extendedTypes);
+ }
+ }