]> git.saurik.com Git - apple/configd.git/blobdiff - SystemConfiguration.fproj/SCNetworkService.c
configd-130.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkService.c
diff --git a/SystemConfiguration.fproj/SCNetworkService.c b/SystemConfiguration.fproj/SCNetworkService.c
new file mode 100644 (file)
index 0000000..db30ae7
--- /dev/null
@@ -0,0 +1,862 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Modification History
+ *
+ * May 13, 2004                Allan Nathanson <ajn@apple.com>
+ * - initial revision
+ */
+
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFRuntime.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <SystemConfiguration/SCNetworkConfigurationInternal.h>
+#include <SystemConfiguration/SCValidation.h>
+#include <SystemConfiguration/SCPrivate.h>
+
+#include <pthread.h>
+
+
+static CFStringRef     __SCNetworkServiceCopyDescription       (CFTypeRef cf);
+static void            __SCNetworkServiceDeallocate            (CFTypeRef cf);
+static Boolean         __SCNetworkServiceEqual                 (CFTypeRef cf1, CFTypeRef cf2);
+
+
+static CFTypeID __kSCNetworkServiceTypeID      = _kCFRuntimeNotATypeID;
+
+
+static const CFRuntimeClass __SCNetworkServiceClass = {
+       0,                                      // version
+       "SCNetworkService",                     // className
+       NULL,                                   // init
+       NULL,                                   // copy
+       __SCNetworkServiceDeallocate,           // dealloc
+       __SCNetworkServiceEqual,                // equal
+       NULL,                                   // hash
+       NULL,                                   // copyFormattingDesc
+       __SCNetworkServiceCopyDescription       // copyDebugDesc
+};
+
+
+static pthread_once_t          initialized     = PTHREAD_ONCE_INIT;
+
+
+static __inline__ CFTypeRef
+isA_SCNetworkService(CFTypeRef obj)
+{
+       return (isA_CFType(obj, SCNetworkServiceGetTypeID()));
+}
+
+
+static CFStringRef
+__SCNetworkServiceCopyDescription(CFTypeRef cf)
+{
+       CFAllocatorRef                  allocator       = CFGetAllocator(cf);
+       CFMutableStringRef              result;
+       SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)cf;
+
+       result = CFStringCreateMutable(allocator, 0);
+       CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkService %p [%p]> { "), cf, allocator);
+       CFStringAppendFormat(result, NULL, CFSTR("id=%@"), servicePrivate->serviceID);
+//     CFStringAppendFormat(result, NULL, CFSTR(", prefs=%@"), servicePrivate->prefs);
+       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);
+       CFRelease(servicePrivate->prefs);
+
+       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 void
+__SCNetworkServiceInitialize(void)
+{
+       __kSCNetworkServiceTypeID = _CFRuntimeRegisterClass(&__SCNetworkServiceClass);
+       return;
+}
+
+
+__private_extern__ SCNetworkServicePrivateRef
+__SCNetworkServiceCreatePrivate(CFAllocatorRef         allocator,
+                               CFStringRef             serviceID,
+                               SCNetworkInterfaceRef   interface,
+                               SCPreferencesRef        prefs)
+{
+       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           = CFRetain(prefs);
+       servicePrivate->serviceID       = CFStringCreateCopy(NULL, serviceID);
+       servicePrivate->interface       = (interface != NULL) ? CFRetain(interface) : NULL;
+
+       return servicePrivate;
+}
+
+
+/* ---------- SCNetworkService APIs ---------- */
+
+
+#define        N_QUICK 64
+
+
+Boolean
+SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
+{
+       CFDictionaryRef                 entity;
+       CFDictionaryRef                 newEntity       = NULL;
+       Boolean                         ok              = FALSE;
+       CFStringRef                     path;
+       SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)service;
+
+       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;
+       }
+
+       if (servicePrivate->interface != NULL) {
+               SCNetworkInterfaceRef   childInterface;
+               CFStringRef             childInterfaceType      = NULL;
+               CFStringRef             interfaceType;
+
+               interfaceType = SCNetworkInterfaceGetInterfaceType(servicePrivate->interface);
+               childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface);
+               if (childInterface != NULL) {
+                       childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
+               }
+
+               newEntity = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType);
+       }
+
+       if (newEntity == NULL) {
+               newEntity = CFDictionaryCreate(NULL,
+                                              NULL,
+                                              NULL,
+                                              0,
+                                              &kCFTypeDictionaryKeyCallBacks,
+                                              &kCFTypeDictionaryValueCallBacks);
+       }
+
+       ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
+       CFRelease(newEntity);
+
+    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, keys[i], NULL, prefs);
+                       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;
+
+       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, serviceID, NULL, prefs);
+       return (SCNetworkServiceRef)servicePrivate;
+}
+
+
+SCNetworkProtocolRef
+SCNetworkServiceCopyProtocol(SCNetworkServiceRef service, CFStringRef protocolType)
+{
+       CFSetRef                        non_protocol_entities;
+       CFStringRef                     path;
+       CFDictionaryRef                 protocols;
+       SCNetworkProtocolPrivateRef     protocolPrivate = NULL;
+       SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)service;
+
+       path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,                             // allocator
+                                                             servicePrivate->serviceID,        // service
+                                                             NULL);                            // entity
+       protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
+       CFRelease(path);
+
+       if ((protocols != NULL) && !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;
+
+       path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,                             // allocator
+                                                             servicePrivate->serviceID,        // service
+                                                             NULL);                            // entity
+       protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
+       CFRelease(path);
+
+       if (!isA_CFDictionary(protocols)) {
+               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)
+{
+       CFMutableDictionaryRef          entity;
+       SCNetworkInterfacePrivateRef    interfacePrivate        = (SCNetworkInterfacePrivateRef)interface;
+       Boolean                         ok;
+       CFStringRef                     path;
+       SCNetworkServicePrivateRef      servicePrivate          = (SCNetworkServicePrivateRef)service;
+
+       path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,                             // allocator
+                                                             servicePrivate->serviceID,        // service
+                                                             kSCEntNetInterface);              // entity
+       entity = CFDictionaryCreateMutable(NULL,
+                                          0,
+                                          &kCFTypeDictionaryKeyCallBacks,
+                                          &kCFTypeDictionaryValueCallBacks);
+       if (interfacePrivate->entity_type != NULL) {
+               CFDictionarySetValue(entity,
+                                    kSCPropNetInterfaceType,
+                                    interfacePrivate->entity_type);
+       }
+       if (interfacePrivate->entity_subtype != NULL) {
+               CFDictionarySetValue(entity,
+                                    kSCPropNetInterfaceSubType,
+                                    interfacePrivate->entity_subtype);
+       }
+       if (interfacePrivate->entity_device != NULL) {
+               CFDictionarySetValue(entity,
+                                    kSCPropNetInterfaceDeviceName,
+                                    interfacePrivate->entity_device);
+       }
+       if (interfacePrivate->entity_hardware != NULL) {
+               CFDictionarySetValue(entity,
+                                    kSCPropNetInterfaceHardware,
+                                    interfacePrivate->entity_hardware);
+       }
+       if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeModem) &&
+           interfacePrivate->supportsDeviceOnHold) {
+               int             one     = 1;
+               CFNumberRef     num;
+
+               num = CFNumberCreate(NULL, kCFNumberIntType, &one);
+               CFDictionarySetValue(entity,
+                                    kSCPropNetInterfaceSupportsModemOnHold,
+                                    num);
+               CFRelease(num);
+       }
+       ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, entity);
+       CFRelease(entity);
+       CFRelease(path);
+
+       return ok;
+}
+
+
+SCNetworkServiceRef
+SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface)
+{
+       CFArrayRef                      components;
+       CFArrayRef                      interface_config;
+       SCNetworkInterfaceRef           newInterface;
+       CFStringRef                     path;
+       CFStringRef                     prefix;
+       CFStringRef                     serviceID;
+       SCNetworkServicePrivateRef      servicePrivate;
+
+       // establish the service
+       prefix = SCPreferencesPathKeyCreateNetworkServices(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, serviceID, NULL, prefs);
+       CFRelease(components);
+
+       // duplicate the interface and associate the copy with the new service
+       newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL,
+                                                                            interface,
+                                                                            (SCNetworkServiceRef)servicePrivate);
+       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(servicePrivate->interface);
+               if (childInterface != NULL) {
+                       childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
+               }
+
+               config = __copyInterfaceTemplate(interfaceType, childInterfaceType);
+               if (config != NULL) {
+                       (void) __SCNetworkInterfaceSetConfiguration(interface, config, TRUE);
+                       CFRelease(config);
+               }
+       }
+
+       // add the interface [entity] to the service
+       (void) __SCNetworkServiceSetInterfaceEntity((SCNetworkServiceRef)servicePrivate,
+                                                   servicePrivate->interface);
+
+       // push the [deep] interface configuration into into the service.
+       interface_config = __SCNetworkInterfaceCopyDeepConfiguration(servicePrivate->interface);
+       __SCNetworkInterfaceSetDeepConfiguration(servicePrivate->interface, interface_config);
+
+       return (SCNetworkServiceRef)servicePrivate;
+}
+
+
+Boolean
+SCNetworkServiceGetEnabled(SCNetworkServiceRef service)
+{
+       Boolean                         enabled;
+       CFStringRef                     path;
+       SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)service;
+
+       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 (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;
+       SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)service;
+       CFStringRef                     name            = NULL;
+       CFStringRef                     path;
+
+       path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,                             // allocator
+                                                             servicePrivate->serviceID,        // service
+                                                             NULL);                            // entity
+       entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
+       CFRelease(path);
+
+       if (isA_CFDictionary(entity)) {
+               name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
+       }
+
+       return isA_CFString(name) ? name : NULL;
+}
+
+
+CFStringRef
+SCNetworkServiceGetServiceID(SCNetworkServiceRef service)
+{
+       SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)service;
+
+       return servicePrivate->serviceID;
+}
+
+
+CFTypeID
+SCNetworkServiceGetTypeID(void)
+{
+       pthread_once(&initialized, __SCNetworkServiceInitialize);       /* initialize runtime */
+       return __kSCNetworkServiceTypeID;
+}
+
+
+Boolean
+SCNetworkServiceRemove(SCNetworkServiceRef service)
+{
+       Boolean                         ok              = FALSE;
+       SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)service;
+       CFArrayRef                      sets;
+       CFStringRef                     path;
+
+       // 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)) {
+                               break;
+                       }
+               }
+               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;
+
+       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;
+
+       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;
+       SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)service;
+
+#define PREVENT_DUPLICATE_SERVICE_NAMES
+#ifdef  PREVENT_DUPLICATE_SERVICE_NAMES
+       if (isA_CFString(name)) {
+               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);
+                                       _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 ((entity == NULL) && (name != NULL)) {
+               entity = CFDictionaryCreate(NULL,
+                                           NULL,
+                                           NULL,
+                                           0,
+                                           &kCFTypeDictionaryKeyCallBacks,
+                                           &kCFTypeDictionaryValueCallBacks);
+       }
+       if (isA_CFDictionary(entity)) {
+               CFMutableDictionaryRef  newEntity;
+
+               newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
+               if (isA_CFString(name)) {
+                       CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name);
+               } else {
+                       CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
+               }
+               ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
+               CFRelease(newEntity);
+       }
+       CFRelease(path);
+
+       return ok;
+}