/* * Copyright (c) 2004-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Modification History * * May 13, 2004 Allan Nathanson * - initial revision */ #include #include #include #include "SCNetworkConfigurationInternal.h" #include #include #include static CFStringRef __SCNetworkServiceCopyDescription (CFTypeRef cf); static void __SCNetworkServiceDeallocate (CFTypeRef cf); static Boolean __SCNetworkServiceEqual (CFTypeRef cf1, CFTypeRef cf2); static CFHashCode __SCNetworkServiceHash (CFTypeRef cf); static CFTypeID __kSCNetworkServiceTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __SCNetworkServiceClass = { 0, // version "SCNetworkService", // className NULL, // init NULL, // copy __SCNetworkServiceDeallocate, // dealloc __SCNetworkServiceEqual, // equal __SCNetworkServiceHash, // hash NULL, // copyFormattingDesc __SCNetworkServiceCopyDescription // copyDebugDesc }; static pthread_once_t initialized = PTHREAD_ONCE_INIT; static CFStringRef __SCNetworkServiceCopyDescription(CFTypeRef cf) { CFAllocatorRef allocator = CFGetAllocator(cf); CFMutableStringRef result; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf; result = CFStringCreateMutable(allocator, 0); CFStringAppendFormat(result, NULL, CFSTR(" {"), cf, allocator); CFStringAppendFormat(result, NULL, CFSTR("id = %@"), servicePrivate->serviceID); if (servicePrivate->prefs != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), servicePrivate->prefs); } else if (servicePrivate->store != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", store = %p"), servicePrivate->store); } if (servicePrivate->name != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), servicePrivate->name); } CFStringAppendFormat(result, NULL, CFSTR("}")); return result; } static void __SCNetworkServiceDeallocate(CFTypeRef cf) { SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf; /* release resources */ CFRelease(servicePrivate->serviceID); if (servicePrivate->interface != NULL) CFRelease(servicePrivate->interface); if (servicePrivate->prefs != NULL) CFRelease(servicePrivate->prefs); if (servicePrivate->store != NULL) CFRelease(servicePrivate->store); if (servicePrivate->name != NULL) CFRelease(servicePrivate->name); return; } static Boolean __SCNetworkServiceEqual(CFTypeRef cf1, CFTypeRef cf2) { SCNetworkServicePrivateRef s1 = (SCNetworkServicePrivateRef)cf1; SCNetworkServicePrivateRef s2 = (SCNetworkServicePrivateRef)cf2; if (s1 == s2) return TRUE; if (s1->prefs != s2->prefs) return FALSE; // if not the same prefs if (!CFEqual(s1->serviceID, s2->serviceID)) return FALSE; // if not the same service identifier return TRUE; } static CFHashCode __SCNetworkServiceHash(CFTypeRef cf) { SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf; return CFHash(servicePrivate->serviceID); } static void __SCNetworkServiceInitialize(void) { __kSCNetworkServiceTypeID = _CFRuntimeRegisterClass(&__SCNetworkServiceClass); return; } __private_extern__ SCNetworkServicePrivateRef __SCNetworkServiceCreatePrivate(CFAllocatorRef allocator, SCPreferencesRef prefs, CFStringRef serviceID, SCNetworkInterfaceRef interface) { SCNetworkServicePrivateRef servicePrivate; uint32_t size; /* initialize runtime */ pthread_once(&initialized, __SCNetworkServiceInitialize); /* allocate target */ size = sizeof(SCNetworkServicePrivate) - sizeof(CFRuntimeBase); servicePrivate = (SCNetworkServicePrivateRef)_CFRuntimeCreateInstance(allocator, __kSCNetworkServiceTypeID, size, NULL); if (servicePrivate == NULL) { return NULL; } servicePrivate->prefs = (prefs != NULL) ? CFRetain(prefs): NULL; servicePrivate->serviceID = CFStringCreateCopy(NULL, serviceID); servicePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL; servicePrivate->name = NULL; return servicePrivate; } #pragma mark - #pragma mark Service ordering CFComparisonResult _SCNetworkServiceCompare(const void *val1, const void *val2, void *context) { CFStringRef id1; CFStringRef id2; CFArrayRef order = (CFArrayRef)context; SCNetworkServiceRef s1 = (SCNetworkServiceRef)val1; SCNetworkServiceRef s2 = (SCNetworkServiceRef)val2; id1 = SCNetworkServiceGetServiceID(s1); id2 = SCNetworkServiceGetServiceID(s2); if (order != NULL) { CFIndex o1; CFIndex o2; CFRange range; range = CFRangeMake(0, CFArrayGetCount(order)); o1 = CFArrayGetFirstIndexOfValue(order, range, id1); o2 = CFArrayGetFirstIndexOfValue(order, range, id2); if (o1 > o2) { return (o2 != kCFNotFound) ? kCFCompareGreaterThan : kCFCompareLessThan; } else if (o1 < o2) { return (o1 != kCFNotFound) ? kCFCompareLessThan : kCFCompareGreaterThan; } } return CFStringCompare(id1, id2, 0); } #pragma mark - #pragma mark SCNetworkService APIs #define N_QUICK 64 __private_extern__ CFArrayRef /* of SCNetworkServiceRef's */ __SCNetworkServiceCopyAllEnabled(SCPreferencesRef prefs) { CFMutableArrayRef array = NULL; CFIndex i_sets; CFIndex n_sets; CFArrayRef sets; sets = SCNetworkSetCopyAll(prefs); if (sets == NULL) { return NULL; } n_sets = CFArrayGetCount(sets); for (i_sets = 0; i_sets < n_sets; i_sets++) { CFIndex i_services; CFIndex n_services; CFArrayRef services; SCNetworkSetRef set; set = CFArrayGetValueAtIndex(sets, i_sets); services = SCNetworkSetCopyServices(set); if (services == NULL) { continue; } n_services = CFArrayGetCount(services); for (i_services = 0; i_services < n_services; i_services++) { SCNetworkServiceRef service; service = CFArrayGetValueAtIndex(services, i_services); if (!SCNetworkServiceGetEnabled(service)) { // if not enabled continue; } if ((array == NULL) || !CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), service)) { if (array == NULL) { array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } CFArrayAppendValue(array, service); } } CFRelease(services); } CFRelease(sets); return array; } __private_extern__ Boolean __SCNetworkServiceExistsForInterface(CFArrayRef services, SCNetworkInterfaceRef interface) { CFIndex i; CFIndex n; n = isA_CFArray(services) ? CFArrayGetCount(services) : 0; for (i = 0; i < n; i++) { SCNetworkServiceRef service; SCNetworkInterfaceRef service_interface; service = CFArrayGetValueAtIndex(services, i); service_interface = SCNetworkServiceGetInterface(service); while (service_interface != NULL) { if (CFEqual(interface, service_interface)) { return TRUE; } service_interface = SCNetworkInterfaceGetInterface(service_interface); } } return FALSE; } __private_extern__ CF_RETURNS_RETAINED CFStringRef __SCNetworkServiceNextName(SCNetworkServiceRef service) { CFArrayRef components; CFIndex n; CFStringRef name; CFMutableArrayRef newComponents; SInt32 suffix = 2; name = SCNetworkServiceGetName(service); if (name == NULL) { return NULL; } components = CFStringCreateArrayBySeparatingStrings(NULL, name, CFSTR(" ")); if (components != NULL) { newComponents = CFArrayCreateMutableCopy(NULL, 0, components); CFRelease(components); } else { newComponents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFArrayAppendValue(newComponents, name); } n = CFArrayGetCount(newComponents); if (n > 1) { CFStringRef str; str = CFArrayGetValueAtIndex(newComponents, n - 1); suffix = CFStringGetIntValue(str); if (suffix++ > 0) { CFArrayRemoveValueAtIndex(newComponents, n - 1); } else { suffix = 2; } } name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), suffix); CFArrayAppendValue(newComponents, name); CFRelease(name); name = CFStringCreateByCombiningStrings(NULL, newComponents, CFSTR(" ")); CFRelease(newComponents); return name; } static void mergeDict(const void *key, const void *value, void *context) { CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context; CFDictionarySetValue(newDict, key, value); return; } static CF_RETURNS_RETAINED CFDictionaryRef _protocolTemplate(SCNetworkServiceRef service, CFStringRef protocolType) { SCNetworkInterfaceRef interface; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; CFDictionaryRef template = NULL; interface = servicePrivate->interface; if (interface != NULL) { SCNetworkInterfaceRef childInterface; CFStringRef childInterfaceType = NULL; CFStringRef interfaceType; // get the template interfaceType = SCNetworkInterfaceGetInterfaceType(servicePrivate->interface); childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface); if (childInterface != NULL) { childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface); } template = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType); if (template != NULL) { CFDictionaryRef overrides; // move to the interface at the lowest layer while (childInterface != NULL) { interface = childInterface; childInterface = SCNetworkInterfaceGetInterface(interface); } overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, protocolType); if (overrides != NULL) { CFMutableDictionaryRef newTemplate; newTemplate = CFDictionaryCreateMutableCopy(NULL, 0, template); CFDictionaryApplyFunction(overrides, mergeDict, newTemplate); CFRelease(template); template = newTemplate; } } } if (template == NULL) { template = CFDictionaryCreate(NULL, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } return template; } Boolean SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protocolType) { CFDictionaryRef entity; CFDictionaryRef newEntity = NULL; Boolean ok = FALSE; CFStringRef path; SCNetworkProtocolRef protocol; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } if (!__SCNetworkProtocolIsValidType(protocolType)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service protocolType); // entity entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); if (entity != NULL) { // if "protocol" already exists _SCErrorSet(kSCStatusKeyExists); goto done; } newEntity = CFDictionaryCreate(NULL, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity); CFRelease(newEntity); if (!ok) { goto done; } protocol = SCNetworkServiceCopyProtocol(service, protocolType); newEntity = _protocolTemplate(service, protocolType); ok = SCNetworkProtocolSetConfiguration(protocol, newEntity); CFRelease(newEntity); CFRelease(protocol); done : CFRelease(path); return ok; } CFArrayRef /* of SCNetworkServiceRef's */ SCNetworkServiceCopyAll(SCPreferencesRef prefs) { CFMutableArrayRef array; CFIndex n; CFStringRef path; CFDictionaryRef services; path = SCPreferencesPathKeyCreateNetworkServices(NULL); services = SCPreferencesPathGetValue(prefs, path); CFRelease(path); if ((services != NULL) && !isA_CFDictionary(services)) { return NULL; } array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); n = (services != NULL) ? CFDictionaryGetCount(services) : 0; if (n > 0) { CFIndex i; const void * keys_q[N_QUICK]; const void ** keys = keys_q; const void * vals_q[N_QUICK]; const void ** vals = vals_q; if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0); } CFDictionaryGetKeysAndValues(services, keys, vals); for (i = 0; i < n; i++) { CFDictionaryRef entity; SCNetworkServicePrivateRef servicePrivate; if (!isA_CFDictionary(vals[i])) { SCLog(TRUE, LOG_INFO, CFSTR("SCNetworkServiceCopyAll(): error w/service \"%@\"\n"), keys[i]); continue; } entity = CFDictionaryGetValue(vals[i], kSCEntNetInterface); if (!isA_CFDictionary(entity)) { // if no "interface" SCLog(TRUE, LOG_INFO, CFSTR("SCNetworkServiceCopyAll(): no \"%@\" entity for service \"%@\"\n"), kSCEntNetInterface, keys[i]); continue; } servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, keys[i], NULL); CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate); CFRelease(servicePrivate); } if (keys != keys_q) { CFAllocatorDeallocate(NULL, keys); CFAllocatorDeallocate(NULL, vals); } } return array; } /* * build a list of all of a servives entity types that are associated * with the services interface. The list will include : * * - entity types associated with the interface type (Ethernet, FireWire, PPP, ...) * - entity types associated with the interface sub-type (PPPSerial, PPPoE, L2TP, PPTP, ...) * - entity types associated with the hardware device (Ethernet, AirPort, FireWire, Modem, ...) */ static CFSetRef _copyInterfaceEntityTypes(CFDictionaryRef protocols) { CFDictionaryRef interface; CFMutableSetRef interface_entity_types; interface_entity_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); interface = CFDictionaryGetValue(protocols, kSCEntNetInterface); if (isA_CFDictionary(interface)) { CFStringRef entities[] = { kSCPropNetInterfaceType, kSCPropNetInterfaceSubType, kSCPropNetInterfaceHardware }; int i; // include the "Interface" entity itself CFSetAddValue(interface_entity_types, kSCEntNetInterface); // include the entities associated with the interface for (i = 0; i < sizeof(entities)/sizeof(entities[0]); i++) { CFStringRef entity; entity = CFDictionaryGetValue(interface, entities[i]); if (isA_CFString(entity)) { CFSetAddValue(interface_entity_types, entity); } } /* * and, because we've found some misguided network preference code * developers leaving [PPP] entity dictionaries around even though * they are unused and/or unneeded... */ CFSetAddValue(interface_entity_types, kSCEntNetPPP); } return interface_entity_types; } SCNetworkServiceRef SCNetworkServiceCopy(SCPreferencesRef prefs, CFStringRef serviceID) { CFDictionaryRef entity; CFStringRef path; SCNetworkServicePrivateRef servicePrivate; if (!isA_CFString(serviceID)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator serviceID, // service kSCEntNetInterface); // entity entity = SCPreferencesPathGetValue(prefs, path); CFRelease(path); if (!isA_CFDictionary(entity)) { // a "service" must have an "interface" _SCErrorSet(kSCStatusNoKey); return NULL; } servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL); return (SCNetworkServiceRef)servicePrivate; } SCNetworkServiceRef _SCNetworkServiceCopyActive(SCDynamicStoreRef store, CFStringRef serviceID) { SCNetworkServicePrivateRef servicePrivate; if (!isA_CFString(serviceID)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } servicePrivate = __SCNetworkServiceCreatePrivate(NULL, NULL, serviceID, NULL); if (store != NULL) { servicePrivate->store = CFRetain(store); } return (SCNetworkServiceRef)servicePrivate; } SCNetworkProtocolRef SCNetworkServiceCopyProtocol(SCNetworkServiceRef service, CFStringRef protocolType) { CFSetRef non_protocol_entities; CFStringRef path; CFDictionaryRef protocols; SCNetworkProtocolPrivateRef protocolPrivate = NULL; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } if (!isA_CFString(protocolType)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); if (!isA_CFDictionary(protocols)) { // if corrupt prefs _SCErrorSet(kSCStatusFailed); return NULL; } non_protocol_entities = _copyInterfaceEntityTypes(protocols); if (CFSetContainsValue(non_protocol_entities, protocolType)) { // if the "protocolType" matches an interface entity type _SCErrorSet(kSCStatusInvalidArgument); goto done; } if (!CFDictionaryContainsKey(protocols, protocolType)) { // if the "protocolType" entity does not exist _SCErrorSet(kSCStatusNoKey); goto done; } protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, protocolType, service); done : CFRelease(non_protocol_entities); return (SCNetworkProtocolRef)protocolPrivate; } CFArrayRef /* of SCNetworkProtocolRef's */ SCNetworkServiceCopyProtocols(SCNetworkServiceRef service) { CFMutableArrayRef array; CFIndex n; CFSetRef non_protocol_entities; CFStringRef path; CFDictionaryRef protocols; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); if (!isA_CFDictionary(protocols)) { // if corrupt prefs _SCErrorSet(kSCStatusFailed); return NULL; } non_protocol_entities = _copyInterfaceEntityTypes(protocols); array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); n = CFDictionaryGetCount(protocols); if (n > 0) { CFIndex i; const void * keys_q[N_QUICK]; const void ** keys = keys_q; const void * vals_q[N_QUICK]; const void ** vals = vals_q; if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0); } CFDictionaryGetKeysAndValues(protocols, keys, vals); for (i = 0; i < n; i++) { SCNetworkProtocolPrivateRef protocolPrivate; if (!isA_CFDictionary(vals[i])) { // if it's not a dictionary then it can't be a protocol entity continue; } if (CFSetContainsValue(non_protocol_entities, keys[i])) { // skip any non-protocol (interface) entities continue; } protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, keys[i], service); CFArrayAppendValue(array, (SCNetworkProtocolRef)protocolPrivate); CFRelease(protocolPrivate); } if (keys != keys_q) { CFAllocatorDeallocate(NULL, keys); CFAllocatorDeallocate(NULL, vals); } } CFRelease(non_protocol_entities); return array; } static Boolean __SCNetworkServiceSetInterfaceEntity(SCNetworkServiceRef service, SCNetworkInterfaceRef interface) { CFDictionaryRef entity; Boolean ok; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service kSCEntNetInterface); // entity entity = __SCNetworkInterfaceCopyInterfaceEntity(interface); ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, entity); CFRelease(entity); CFRelease(path); return ok; } SCNetworkServiceRef SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) { CFArrayRef components; CFArrayRef interface_config; CFStringRef interface_name; SCNetworkInterfaceRef newInterface; CFStringRef path; CFStringRef prefix; CFStringRef serviceID; SCNetworkServicePrivateRef servicePrivate; CFArrayRef supported_protocols; if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } // only allow network interfaces which support one or more protocols // to be added to a service. The one exception is that we allow // third-party interface types to be configured. supported_protocols = SCNetworkInterfaceGetSupportedProtocolTypes(interface); if (supported_protocols == NULL) { CFStringRef interface_type; interface_type = SCNetworkInterfaceGetInterfaceType(interface); if (CFStringFind(interface_type, CFSTR("."), 0).location == kCFNotFound) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } } // do not allow creation of a network service if the interface is a // member of a bond or bridge if (__SCNetworkInterfaceIsMember(prefs, interface)) { _SCErrorSet(kSCStatusKeyExists); return NULL; } // establish the service prefix = SCPreferencesPathKeyCreateNetworkServices(NULL); path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix); if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix); CFRelease(prefix); if (path == NULL) { return NULL; } components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/")); CFRelease(path); serviceID = CFArrayGetValueAtIndex(components, 2); servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL); CFRelease(components); // duplicate the interface and associate the copy with the new service newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL, interface, prefs, serviceID); servicePrivate->interface = newInterface; // establish "default" configuration(s) for the interface for (interface = newInterface; interface != NULL; interface = SCNetworkInterfaceGetInterface(interface)) { SCNetworkInterfaceRef childInterface; CFStringRef childInterfaceType = NULL; CFDictionaryRef config; CFStringRef interfaceType; interfaceType = SCNetworkInterfaceGetInterfaceType(interface); childInterface = SCNetworkInterfaceGetInterface(interface); if (childInterface != NULL) { childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface); } config = __copyInterfaceTemplate(interfaceType, childInterfaceType); if (config != NULL) { if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBluetooth) || CFEqual(interfaceType, kSCNetworkInterfaceTypeIrDA ) || CFEqual(interfaceType, kSCNetworkInterfaceTypeModem ) || CFEqual(interfaceType, kSCNetworkInterfaceTypeSerial ) || CFEqual(interfaceType, kSCNetworkInterfaceTypeWWAN )) { CFDictionaryRef overrides; overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypeModem); // a ConnectionScript (and related keys) from the interface // should trump the settings from the configuration template. if (overrides != NULL) { CFMutableDictionaryRef newConfig; newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config); if (CFDictionaryContainsKey(overrides, kSCPropNetModemConnectionScript)) { CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionPersonality); CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionScript); CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceVendor); CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceModel); } CFDictionaryApplyFunction(overrides, mergeDict, newConfig); CFRelease(config); config = newConfig; } } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP) || CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) { CFDictionaryRef overrides; overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypePPP); if (overrides != NULL) { CFMutableDictionaryRef newConfig; newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config); CFDictionaryApplyFunction(overrides, mergeDict, newConfig); CFRelease(config); config = newConfig; } } if (!__SCNetworkInterfaceSetConfiguration(interface, NULL, config, TRUE)) { SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkService __SCNetworkInterfaceSetConfiguration failed(), interface=%@, type=NULL"), interface); } CFRelease(config); } } // add the interface [entity] to the service (void) __SCNetworkServiceSetInterfaceEntity((SCNetworkServiceRef)servicePrivate, servicePrivate->interface); // push the [deep] interface configuration into the service. interface_config = __SCNetworkInterfaceCopyDeepConfiguration(NULL, servicePrivate->interface); __SCNetworkInterfaceSetDeepConfiguration(NULL, servicePrivate->interface, interface_config); if (interface_config != NULL) CFRelease(interface_config); // set the service name to match that of the associated interface // // Note: It might seem a bit odd to call SCNetworkServiceGetName // followed by an immediate call to SCNetworkServiceSetName. The // trick here is that if no name has previously been set, the // "get" function will return the name of the associated interface. // // ... and we "set" a name to ensure that applications that do // not use the APIs will still find a UserDefinedName property // in the SCDynamicStore. // interface_name = SCNetworkServiceGetName((SCNetworkServiceRef)servicePrivate); if (interface_name != NULL) { (void) SCNetworkServiceSetName((SCNetworkServiceRef)servicePrivate, interface_name); } return (SCNetworkServiceRef)servicePrivate; } Boolean SCNetworkServiceEstablishDefaultConfiguration(SCNetworkServiceRef service) { CFIndex i; SCNetworkInterfaceRef interface; CFIndex n; CFArrayRef protocolTypes; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } interface = SCNetworkServiceGetInterface(service); if (interface == NULL) { return FALSE; } protocolTypes = SCNetworkInterfaceGetSupportedProtocolTypes(interface); n = (protocolTypes != NULL) ? CFArrayGetCount(protocolTypes) : 0; for (i = 0; i < n; i++) { Boolean enabled; CFDictionaryRef newEntity = NULL; Boolean ok; SCNetworkProtocolRef protocol = NULL; CFStringRef protocolType; protocolType = CFArrayGetValueAtIndex(protocolTypes, i); ok = SCNetworkServiceAddProtocolType(service, protocolType); if (!ok && (SCError() != kSCStatusKeyExists)) { // could not add protocol goto nextProtocol; } protocol = SCNetworkServiceCopyProtocol(service, protocolType); if (protocol == NULL) { // oops, somethings wrong (should never happen) goto nextProtocol; } newEntity = _protocolTemplate(service, protocolType); ok = SCNetworkProtocolSetConfiguration(protocol, newEntity); if (!ok) { // could not set default configuration goto nextProtocol; } enabled = !CFDictionaryContainsKey(newEntity, kSCResvInactive); ok = SCNetworkProtocolSetEnabled(protocol, enabled); if (!ok) { // could not enable/disable protocol goto nextProtocol; } nextProtocol : if (newEntity != NULL) CFRelease(newEntity); if (protocol != NULL) CFRelease(protocol); } return TRUE; } Boolean SCNetworkServiceGetEnabled(SCNetworkServiceRef service) { Boolean enabled; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity enabled = __getPrefsEnabled(servicePrivate->prefs, path); CFRelease(path); return enabled; } SCNetworkInterfaceRef SCNetworkServiceGetInterface(SCNetworkServiceRef service) { SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } if (servicePrivate->interface == NULL) { CFDictionaryRef entity; CFStringRef path; path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service kSCEntNetInterface); // entity entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); if (isA_CFDictionary(entity)) { servicePrivate->interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, service); } } return servicePrivate->interface; } CFStringRef SCNetworkServiceGetName(SCNetworkServiceRef service) { CFDictionaryRef entity; SCNetworkInterfaceRef interface; CFStringRef name = NULL; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } if (servicePrivate->name != NULL) { return servicePrivate->name; } path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); if (isA_CFDictionary(entity)) { name = CFDictionaryGetValue(entity, kSCPropUserDefinedName); if (isA_CFString(name)) { servicePrivate->name = CFRetain(name); } } interface = SCNetworkServiceGetInterface(service); while (interface != NULL) { SCNetworkInterfaceRef childInterface; CFStringRef interfaceType; interfaceType = SCNetworkInterfaceGetInterfaceType(interface); if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) { break; } childInterface = SCNetworkInterfaceGetInterface(interface); if ((childInterface == NULL) || CFEqual(childInterface, kSCNetworkInterfaceIPv4)) { break; } interface = childInterface; } if (interface != NULL) { int i; CFStringRef interface_name = NULL; CFStringRef suffix = NULL; // // check if the [stored] service name matches the non-localized interface // name. If so, return the localized name. // // Also, the older "Built-in XXX" interface names are too long for the // current UI. If we find that the [stored] service name matches the older // name, return the newer (and shorter) localized name. // // Note: the user/admin will no longer be able to set the service name // to "Built-in Ethernet". // for (i = 0; i < 3; i++) { if (servicePrivate->name == NULL) { // if no [stored] service name to compare break; } switch (i) { case 0 : // compare the non-localized interface name interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface); if (interface_name != NULL) { CFRetain(interface_name); } break; #if !TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR case 1 : // compare the older "Built-in XXX" localized name interface_name = __SCNetworkInterfaceCopyXLocalizedDisplayName(interface); break; case 2 : // compare the older "Built-in XXX" non-localized name interface_name = __SCNetworkInterfaceCopyXNonLocalizedDisplayName(interface); break; #endif // !TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR default : continue; } if (interface_name != NULL) { Boolean match = FALSE; if (CFEqual(name, interface_name)) { // if service name matches the OLD localized // interface name match = TRUE; } else if (CFStringHasPrefix(name, interface_name)) { CFIndex prefixLen = CFStringGetLength(interface_name); CFIndex suffixLen = CFStringGetLength(name); suffix = CFStringCreateWithSubstring(NULL, name, CFRangeMake(prefixLen, suffixLen - prefixLen)); match = TRUE; } CFRelease(interface_name); if (match) { CFRelease(servicePrivate->name); servicePrivate->name = NULL; break; } } } // // if the service name has not been set, use the localized interface name // if (servicePrivate->name == NULL) { interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface); if (interface_name != NULL) { if (suffix != NULL) { servicePrivate->name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), interface_name, suffix); } else { servicePrivate->name = CFRetain(interface_name); } } } if (suffix != NULL) CFRelease(suffix); } return servicePrivate->name; } CFStringRef SCNetworkServiceGetServiceID(SCNetworkServiceRef service) { SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } return servicePrivate->serviceID; } CFTypeID SCNetworkServiceGetTypeID(void) { pthread_once(&initialized, __SCNetworkServiceInitialize); /* initialize runtime */ return __kSCNetworkServiceTypeID; } Boolean SCNetworkServiceRemove(SCNetworkServiceRef service) { Boolean ok = FALSE; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; CFArrayRef sets; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } // remove service from all sets sets = SCNetworkSetCopyAll(servicePrivate->prefs); if (sets != NULL) { CFIndex i; CFIndex n; n = CFArrayGetCount(sets); for (i = 0; i < n; i++) { SCNetworkSetRef set; set = CFArrayGetValueAtIndex(sets, i); ok = SCNetworkSetRemoveService(set, service); if (!ok && (SCError() != kSCStatusNoKey)) { CFRelease(sets); return ok; } } CFRelease(sets); } // remove service path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path); CFRelease(path); return ok; } Boolean SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service, CFStringRef protocolType) { CFDictionaryRef entity; Boolean ok = FALSE; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } if (!__SCNetworkProtocolIsValidType(protocolType)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service protocolType); // entity entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); if (entity == NULL) { // if "protocol" does not exist _SCErrorSet(kSCStatusNoKey); goto done; } ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path); done : CFRelease(path); return ok; } Boolean SCNetworkServiceSetEnabled(SCNetworkServiceRef service, Boolean enabled) { Boolean ok; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } // make sure that we do not enable a network service if the // associated interface is a member of a bond or bridge. if (enabled) { SCNetworkInterfaceRef interface; interface = SCNetworkServiceGetInterface(service); if ((interface != NULL) && __SCNetworkInterfaceIsMember(servicePrivate->prefs, interface)) { _SCErrorSet(kSCStatusKeyExists); return FALSE; } } path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity ok = __setPrefsEnabled(servicePrivate->prefs, path, enabled); CFRelease(path); return ok; } Boolean SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name) { CFDictionaryRef entity; Boolean ok = FALSE; CFStringRef path; CFStringRef saveName = NULL; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } if (name != NULL) { if (!isA_CFString(name)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } saveName = CFRetain(name); } if (name != NULL) { SCNetworkInterfaceRef interface; interface = SCNetworkServiceGetInterface(service); while (interface != NULL) { SCNetworkInterfaceRef childInterface; childInterface = SCNetworkInterfaceGetInterface(interface); if (childInterface == NULL) { break; } interface = childInterface; } if (interface != NULL) { CFStringRef interface_name; interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface); if (interface_name != NULL) { if (CFEqual(name, interface_name)) { // if service name matches the localized interface name // then store the non-localized name. interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface); if (interface_name != NULL) { CFRelease(saveName); saveName = CFRetain(interface_name); } } else if (CFStringHasPrefix(name, interface_name)) { CFIndex prefixLen = CFStringGetLength(interface_name); CFStringRef suffix; CFIndex suffixLen = CFStringGetLength(name); // if service name matches the localized interface name plus // a few extra characters) then store the non-localized name with // the same suffix. suffix = CFStringCreateWithSubstring(NULL, name, CFRangeMake(prefixLen, suffixLen - prefixLen)); interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface); if (interface_name != NULL) { CFRelease(saveName); saveName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), interface_name, suffix); } CFRelease(suffix); } } } } #define PREVENT_DUPLICATE_SERVICE_NAMES #ifdef PREVENT_DUPLICATE_SERVICE_NAMES if (name != NULL) { CFArrayRef sets; // ensure that each service is uniquely named within its sets sets = SCNetworkSetCopyAll(servicePrivate->prefs); if (sets != NULL) { CFIndex set_index; CFIndex set_count; set_count = CFArrayGetCount(sets); for (set_index = 0; set_index < set_count; set_index++) { CFIndex service_index; Boolean isDup = FALSE; Boolean isMember = FALSE; CFIndex service_count; CFArrayRef services; SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, set_index); services = SCNetworkSetCopyServices(set); service_count = CFArrayGetCount(services); for (service_index = 0; service_index < service_count; service_index++) { CFStringRef otherID; CFStringRef otherName; SCNetworkServiceRef otherService; otherService = CFArrayGetValueAtIndex(services, service_index); otherID = SCNetworkServiceGetServiceID(otherService); if (CFEqual(servicePrivate->serviceID, otherID)) { // if the service is a member of this set isMember = TRUE; continue; } otherName = SCNetworkServiceGetName(otherService); if ((otherName != NULL) && CFEqual(name, otherName)) { isDup = TRUE; continue; } } CFRelease(services); if (isMember && isDup) { /* * if this service is a member of the set and * the "name" is not unique. */ CFRelease(sets); if (saveName != NULL) CFRelease(saveName); _SCErrorSet(kSCStatusKeyExists); return FALSE; } } CFRelease(sets); } } #endif /* PREVENT_DUPLICATE_SERVICE_NAMES */ path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); if (isA_CFDictionary(entity) || ((entity == NULL) && (name != NULL))) { CFMutableDictionaryRef newEntity; if (entity != NULL) { newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity); } else { newEntity = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if (saveName != NULL) { CFDictionarySetValue(newEntity, kSCPropUserDefinedName, saveName); } else { CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName); } ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity); CFRelease(newEntity); } CFRelease(path); if (saveName != NULL) CFRelease(saveName); if (servicePrivate->name != NULL) CFRelease(servicePrivate->name); if (name != NULL) CFRetain(name); servicePrivate->name = name; return ok; } #pragma mark - #pragma mark SCNetworkService SPIs SCNetworkServicePrimaryRank SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service) { CFDictionaryRef entity; Boolean ok = TRUE; CFStringRef path; SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault; CFStringRef rankStr = NULL; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service)) { _SCErrorSet(kSCStatusInvalidArgument); return rank; } if (servicePrivate->prefs != NULL) { path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); if (isA_CFDictionary(entity)) { rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank); ok = __str_to_rank(rankStr, &rank); } } else if (servicePrivate->store != NULL) { path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, servicePrivate->serviceID, NULL); entity = SCDynamicStoreCopyValue(servicePrivate->store, path); CFRelease(path); if (entity != NULL) { if (isA_CFDictionary(entity)) { rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank); ok = __str_to_rank(rankStr, &rank); } CFRelease(entity); } } else { _SCErrorSet(kSCStatusInvalidArgument); return rank; } if (!ok) { rank = kSCNetworkServicePrimaryRankDefault; _SCErrorSet(kSCStatusInvalidArgument); } else if (rank == kSCNetworkServicePrimaryRankDefault) { _SCErrorSet(kSCStatusOK); } return rank; } Boolean SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service, SCNetworkServicePrimaryRank newRank) { Boolean ok; CFDictionaryRef entity; CFMutableDictionaryRef newEntity; CFStringRef path = NULL; CFStringRef rankStr = NULL; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } ok = __rank_to_str(newRank, &rankStr); if (!ok) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } if (servicePrivate->prefs != NULL) { if ((newRank == kSCNetworkServicePrimaryRankDefault) || (newRank == kSCNetworkServicePrimaryRankNever)) { path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); if (entity != NULL) { if (!isA_CFDictionary(entity)) { // if corrupt prefs _SCErrorSet(kSCStatusFailed); goto done; } newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity); } else { newEntity = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if (rankStr != NULL) { CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr); } else { CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank); } if (CFDictionaryGetCount(newEntity) > 0) { ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity); } else { ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path); } CFRelease(newEntity); if (!ok) { goto done; } } else { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } } else if (servicePrivate->store != NULL) { path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, servicePrivate->serviceID, NULL); entity = SCDynamicStoreCopyValue(servicePrivate->store, path); if (entity != NULL) { if (!isA_CFDictionary(entity)) { // if corrupt prefs CFRelease(entity); _SCErrorSet(kSCStatusFailed); goto done; } newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity); CFRelease(entity); } else { newEntity = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if (rankStr != NULL) { CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr); } else { CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank); } if (CFDictionaryGetCount(newEntity) > 0) { ok = SCDynamicStoreSetValue(servicePrivate->store, path, newEntity); } else { ok = SCDynamicStoreRemoveValue(servicePrivate->store, path); } CFRelease(newEntity); if (!ok) { goto done; } } else { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } done : if (path != NULL) CFRelease(path); return ok; } Boolean _SCNetworkServiceIsVPN(SCNetworkServiceRef service) { SCNetworkInterfaceRef interface; CFStringRef interfaceType; interface = SCNetworkServiceGetInterface(service); if (interface == NULL) { return FALSE; } interfaceType = SCNetworkInterfaceGetInterfaceType(interface); if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) { interface = SCNetworkInterfaceGetInterface(interface); if (interface == NULL) { return FALSE; } interfaceType = SCNetworkInterfaceGetInterfaceType(interface); if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) { return TRUE; } if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) { return TRUE; } } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) { return TRUE; } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) { return TRUE; } return FALSE; }