]> git.saurik.com Git - apple/configd.git/blobdiff - SystemConfiguration.fproj/SCNetworkSet.c
configd-204.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkSet.c
index 72653fac7337aa351131e6eab80ef289e1385fce..922f7e01cb6e887b1a80c7cb61cb582c3644d843 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <CoreFoundation/CoreFoundation.h>
 #include <CoreFoundation/CFRuntime.h>
 #include <SystemConfiguration/SystemConfiguration.h>
-#include <SystemConfiguration/SCNetworkConfigurationInternal.h>
+#include "SCNetworkConfigurationInternal.h"
 #include <SystemConfiguration/SCValidation.h>
 #include <SystemConfiguration/SCPrivate.h>
 
-#include "SCNetworkConfiguration.h"
-#include "SCNetworkConfigurationInternal.h"
-
 #include <pthread.h>
 
 
 static CFStringRef     __SCNetworkSetCopyDescription           (CFTypeRef cf);
 static void            __SCNetworkSetDeallocate                (CFTypeRef cf);
 static Boolean         __SCNetworkSetEqual                     (CFTypeRef cf1, CFTypeRef cf2);
+static CFHashCode      __SCNetworkSetHash                      (CFTypeRef cf);
 
 
 static CFTypeID __kSCNetworkSetTypeID  = _kCFRuntimeNotATypeID;
@@ -57,7 +55,7 @@ static const CFRuntimeClass __SCNetworkSetClass = {
        NULL,                           // copy
        __SCNetworkSetDeallocate,       // dealloc
        __SCNetworkSetEqual,            // equal
-       NULL,                           // hash
+       __SCNetworkSetHash,             // hash
        NULL,                           // copyFormattingDesc
        __SCNetworkSetCopyDescription   // copyDebugDesc
 };
@@ -66,13 +64,6 @@ static const CFRuntimeClass __SCNetworkSetClass = {
 static pthread_once_t          initialized     = PTHREAD_ONCE_INIT;
 
 
-static __inline__ CFTypeRef
-isA_SCNetworkSet(CFTypeRef obj)
-{
-       return (isA_CFType(obj, SCNetworkSetGetTypeID()));
-}
-
-
 static CFStringRef
 __SCNetworkSetCopyDescription(CFTypeRef cf)
 {
@@ -81,10 +72,13 @@ __SCNetworkSetCopyDescription(CFTypeRef cf)
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)cf;
 
        result = CFStringCreateMutable(allocator, 0);
-       CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkSet %p [%p]> { "), cf, allocator);
-       CFStringAppendFormat(result, NULL, CFSTR("id=%@"), setPrivate->setID);
-//     CFStringAppendFormat(result, NULL, CFSTR(", prefs=%@"), setPrivate->prefs);
-       CFStringAppendFormat(result, NULL, CFSTR(" }"));
+       CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkSet %p [%p]> {"), cf, allocator);
+       CFStringAppendFormat(result, NULL, CFSTR("id = %@"), setPrivate->setID);
+       CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), setPrivate->prefs);
+       if (setPrivate->name != NULL) {
+               CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), setPrivate->name);
+       }
+       CFStringAppendFormat(result, NULL, CFSTR("}"));
 
        return result;
 }
@@ -95,12 +89,12 @@ __SCNetworkSetDeallocate(CFTypeRef cf)
 {
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)cf;
 
-       SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCNetworkSetDeallocate:"));
-
        /* release resources */
 
        CFRelease(setPrivate->setID);
        CFRelease(setPrivate->prefs);
+       if (setPrivate->name != NULL)
+               CFRelease(setPrivate->name);
 
        return;
 }
@@ -125,6 +119,15 @@ __SCNetworkSetEqual(CFTypeRef cf1, CFTypeRef cf2)
 }
 
 
+static CFHashCode
+__SCNetworkSetHash(CFTypeRef cf)
+{
+       SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)cf;
+
+       return CFHash(setPrivate->setID);
+}
+
+
 static void
 __SCNetworkSetInitialize(void)
 {
@@ -144,8 +147,6 @@ __SCNetworkSetCreatePrivate(CFAllocatorRef      allocator,
        /* initialize runtime */
        pthread_once(&initialized, __SCNetworkSetInitialize);
 
-       SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCNetworkSetCreatePrivate:"));
-
        /* allocate target */
        size            = sizeof(SCNetworkSetPrivate) - sizeof(CFRuntimeBase);
        setPrivate = (SCNetworkSetPrivateRef)_CFRuntimeCreateInstance(allocator,
@@ -158,11 +159,192 @@ __SCNetworkSetCreatePrivate(CFAllocatorRef      allocator,
 
        setPrivate->setID       = CFStringCreateCopy(NULL, setID);
        setPrivate->prefs       = CFRetain(prefs);
+       setPrivate->name        = NULL;
 
        return setPrivate;
 }
 
 
+#pragma mark -
+
+
+static Boolean
+_serviceIsPPP(SCNetworkServiceRef service)
+{
+       SCNetworkInterfaceRef   interface;
+       CFStringRef             interfaceType;
+
+       interface = SCNetworkServiceGetInterface(service);
+       if (interface == NULL) {
+               return FALSE;
+       }
+
+       interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+       return CFEqual(interfaceType, kSCNetworkInterfaceTypePPP);
+}
+
+
+static Boolean
+_serviceIsVPN(SCNetworkServiceRef service)
+{
+       SCNetworkInterfaceRef   interface;
+       CFStringRef             interfaceType;
+
+//     if (!_serviceIsPPP(service)) {
+//             return FALSE;
+//     }
+
+       interface = SCNetworkServiceGetInterface(service);
+//     if (interface == NULL) {
+//             return FALSE;
+//     }
+
+       interface = SCNetworkInterfaceGetInterface(interface);
+       if (interface == NULL) {
+               return FALSE;
+       }
+
+       interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+       return (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP) ||
+               CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP));
+}
+
+
+static int
+_serviceOrder(SCNetworkServiceRef service)
+{
+       SCNetworkInterfaceRef   interface;
+
+       interface = SCNetworkServiceGetInterface(service);
+       if (interface == NULL) {
+               return 100000;  // sort last
+       }
+
+       return __SCNetworkInterfaceOrder(interface);
+}
+
+
+static void
+_serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service)
+{
+       CFIndex                 i;
+       CFIndex                 n;
+       CFMutableArrayRef       newOrder;
+       CFArrayRef              order;
+       CFStringRef             serviceID;
+       SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
+       CFIndex                 slot;
+
+       order = SCNetworkSetGetServiceOrder(set);
+       if (order != NULL) {
+               newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
+       } else {
+               newOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       }
+       n = CFArrayGetCount(newOrder);
+
+       serviceID = SCNetworkServiceGetServiceID(service);
+       if (CFArrayContainsValue(newOrder, CFRangeMake(0, n), serviceID)) {
+               // if serviceID already present
+               goto done;
+       }
+
+       if (_serviceIsPPP(service) && !_serviceIsVPN(service)) {
+               int     serviceOrder;
+
+               /*
+                * we add [non-VPN] PPP interfaces to the head of the
+                * service order but ensure that "modem" devices are
+                * in front of "Bluetooth" & "IrDA" devices.
+                */
+               slot = 0;
+
+               serviceOrder = _serviceOrder(service);
+
+               for (i = 0; i < n; i++) {
+                       int                     slotOrder;
+                       CFStringRef             slotServiceID;
+                       SCNetworkServiceRef     slotService;
+
+                       slotServiceID = CFArrayGetValueAtIndex(newOrder, i);
+                       if (!isA_CFString(slotServiceID)) {
+                               // if bad prefs
+                               continue;
+                       }
+
+                       slotService = SCNetworkServiceCopy(setPrivate->prefs, slotServiceID);
+                       if (slotService == NULL) {
+                               // if serviceID not valid
+                               continue;
+                       }
+
+                       if (_serviceIsPPP(slotService)) {
+                               // if  PPP service
+                               slotOrder = _serviceOrder(slotService);
+                               if (serviceOrder >= slotOrder) {
+                                       // add the service *after* this one
+                                       slot = i + 1;
+                               }
+                       }
+
+                       CFRelease(slotService);
+               }
+       } else {
+               /*
+                * non-PPP interfaces are added to the end of the list.
+                */
+               slot = n;
+       }
+
+       CFArrayInsertValueAtIndex(newOrder, slot, serviceID);
+       (void) SCNetworkSetSetServiceOrder(set, newOrder);
+
+    done :
+
+       CFRelease(newOrder);
+
+       return;
+}
+
+
+static void
+_serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service)
+{
+       CFMutableArrayRef       newOrder;
+       CFArrayRef              order;
+       CFStringRef             serviceID;
+
+       order = SCNetworkSetGetServiceOrder(set);
+       if (order == NULL) {
+               return;
+       }
+
+       serviceID = SCNetworkServiceGetServiceID(service);
+
+       newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
+       while (TRUE) {
+               CFIndex i;
+
+               i = CFArrayGetFirstIndexOfValue(newOrder,
+                                               CFRangeMake(0, CFArrayGetCount(newOrder)),
+                                               serviceID);
+               if (i == kCFNotFound) {
+                       break;
+               }
+
+               CFArrayRemoveValueAtIndex(newOrder, i);
+       }
+       (void) SCNetworkSetSetServiceOrder(set, newOrder);
+       CFRelease(newOrder);
+
+       return;
+}
+
+
+#pragma mark -
+#pragma mark SCNetworkSet APIs
+
+
 #define        N_QUICK 16
 
 
@@ -177,12 +359,57 @@ SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
        SCNetworkServicePrivateRef      servicePrivate          = (SCNetworkServicePrivateRef)service;
        SCNetworkSetPrivateRef          setPrivate              = (SCNetworkSetPrivateRef)set;
 
-#define PREVENT_DUPLICATE_SETS
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if (!isA_SCNetworkService(service)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+#define PREVENT_DUPLICATE_SERVICE_NAMES
+#ifdef  PREVENT_DUPLICATE_SERVICE_NAMES
+       CFStringRef     name;
+
+       name = SCNetworkServiceGetName(service);
+       if (name != NULL) {
+               CFArrayRef      services;
+
+               services = SCNetworkSetCopyServices(set);
+               if (services != NULL) {
+                       CFIndex i;
+                       CFIndex n;
+
+                       n = CFArrayGetCount(services);
+                       for (i = 0; i < n; i++) {
+                               CFStringRef             otherName;
+                               SCNetworkServiceRef     otherService;
+
+                               otherService = CFArrayGetValueAtIndex(services, i);
+                               otherName = SCNetworkServiceGetName(otherService);
+                               if ((otherName != NULL) && CFEqual(name, otherName)) {
+                                       /*
+                                        * if a service with the same "name" is
+                                        * already a member of the set.
+                                        */
+                                       CFRelease(services);
+                                       _SCErrorSet(kSCStatusKeyExists);
+                                       return FALSE;
+                               }
+                       }
+               }
+
+               CFRelease(services);
+       }
+#endif // PREVENT_DUPLICATE_SERVICE_NAMES
+
+//#define PREVENT_DUPLICATE_SETS
 #ifdef  PREVENT_DUPLICATE_SETS
-       CFArrayRef                      sets;
+       CFArrayRef      sets;
 
        // ensure that each service is only a member of ONE set
-
        sets = SCNetworkSetCopyAll(setPrivate->prefs);
        if (sets != NULL) {
                CFIndex         i;
@@ -229,7 +456,7 @@ SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
        CFRelease(path);
        CFRelease(link);
        if (!ok) {
-               return ok;
+               goto done;
        }
 
        // push the [deep] interface configuration into all sets which contain this service.
@@ -237,6 +464,12 @@ SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
                __SCNetworkInterfaceSetDeepConfiguration(interface, interface_config);
        }
 
+       // add service to ServiceOrder
+       _serviceOrder_add(set, service);
+
+    done :
+
+       if (interface_config != NULL)   CFRelease(interface_config);
        return ok;
 }
 
@@ -248,6 +481,11 @@ SCNetworkSetCopy(SCPreferencesRef prefs, CFStringRef setID)
        CFStringRef             path;
        SCNetworkSetPrivateRef  setPrivate;
 
+       if (!isA_CFString(setID)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
        path = SCPreferencesPathKeyCreateSet(NULL, setID);
        entity = SCPreferencesPathGetValue(prefs, path);
        CFRelease(path);
@@ -262,7 +500,50 @@ SCNetworkSetCopy(SCPreferencesRef prefs, CFStringRef setID)
 }
 
 
-CFArrayRef /* of SCNetworkServiceRef's */
+static 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;
+}
+
+
+Boolean
+SCNetworkSetContainsInterface(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
+{
+       Boolean         found   = FALSE;
+       CFArrayRef      services;
+
+       services = SCNetworkSetCopyServices(set);
+       if (services != NULL) {
+               found = _SCNetworkServiceExistsForInterface(services, interface);
+               CFRelease(services);
+       }
+
+       return found;
+}
+
+
+CFArrayRef /* of SCNetworkSetRef's */
 SCNetworkSetCopyAll(SCPreferencesRef prefs)
 {
        CFMutableArrayRef       array;
@@ -359,6 +640,11 @@ SCNetworkSetCopyServices(SCNetworkSetRef set)
        CFStringRef             path;
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
 
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
        path = SCPreferencesPathKeyCreateSetNetworkService(NULL, setPrivate->setID, NULL);
        dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
        CFRelease(path);
@@ -409,9 +695,9 @@ SCNetworkSetCopyServices(SCNetworkSetRef set)
                                        SCNetworkServicePrivateRef      servicePrivate;
 
                                        servicePrivate = __SCNetworkServiceCreatePrivate(NULL,
+                                                                                        setPrivate->prefs,
                                                                                         serviceID,
-                                                                                        NULL,
-                                                                                        setPrivate->prefs);
+                                                                                        NULL);
                                        CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
                                        CFRelease(servicePrivate);
                                }
@@ -438,7 +724,8 @@ SCNetworkSetCreate(SCPreferencesRef prefs)
        SCNetworkSetPrivateRef  setPrivate;
 
        prefix = SCPreferencesPathKeyCreateSets(NULL);
-       path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
+       path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
+       if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
        CFRelease(prefix);
        if (path == NULL) {
                return NULL;
@@ -460,6 +747,11 @@ SCNetworkSetGetSetID(SCNetworkSetRef set)
 {
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
 
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
        return setPrivate->setID;
 }
 
@@ -467,20 +759,63 @@ SCNetworkSetGetSetID(SCNetworkSetRef set)
 CFStringRef
 SCNetworkSetGetName(SCNetworkSetRef set)
 {
+       CFBundleRef             bundle;
        CFDictionaryRef         entity;
-       CFStringRef             name            = NULL;
        CFStringRef             path;
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
 
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
+       if (setPrivate->name != NULL) {
+               return setPrivate->name;;
+       }
+
        path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
        entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
        CFRelease(path);
 
        if (isA_CFDictionary(entity)) {
+               CFStringRef     name;
+
                name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
+               if (isA_CFString(name)) {
+                       setPrivate->name = CFRetain(name);
+               }
        }
 
-       return isA_CFString(name) ? name : NULL;
+       bundle = _SC_CFBundleGet();
+       if (bundle != NULL) {
+               if (setPrivate->name != NULL) {
+                       CFStringRef     non_localized;
+
+                       non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
+                                                                          CFSTR("DEFAULT_SET_NAME"),
+                                                                          CFSTR("Automatic"),
+                                                                          NULL);
+                       if (non_localized != NULL) {
+                               if (CFEqual(setPrivate->name, non_localized)) {
+                                       CFStringRef     localized;
+
+                                       // if "Automatic", return localized name
+                                       localized = CFBundleCopyLocalizedString(bundle,
+                                                                               CFSTR("DEFAULT_SET_NAME"),
+                                                                               CFSTR("Automatic"),
+                                                                               NULL);
+                                       if (localized != NULL) {
+                                               CFRelease(setPrivate->name);
+                                               setPrivate->name = localized;
+                                       }
+                               }
+
+                               CFRelease(non_localized);
+                       }
+               }
+       }
+
+       return setPrivate->name;
 }
 
 
@@ -492,6 +827,11 @@ SCNetworkSetGetServiceOrder(SCNetworkSetRef set)
        CFArrayRef              serviceOrder;
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
 
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
        path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
        if (path == NULL) {
                return NULL;
@@ -526,6 +866,11 @@ SCNetworkSetRemove(SCNetworkSetRef set)
        CFStringRef             path;
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
 
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
        currentPath = SCPreferencesGetValue(setPrivate->prefs, kSCPrefCurrentSet);
        path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
        if (!isA_CFString(currentPath) || !CFEqual(currentPath, path)) {
@@ -547,6 +892,19 @@ SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service)
        SCNetworkServicePrivateRef      servicePrivate          = (SCNetworkServicePrivateRef)service;
        SCNetworkSetPrivateRef          setPrivate              = (SCNetworkSetPrivateRef)set;
 
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if (!isA_SCNetworkService(service)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       // remove service from ServiceOrder
+       _serviceOrder_remove(set, service);
+
        // get the [deep] interface configuration settings
        interface = SCNetworkServiceGetInterface(service);
        if (interface != NULL) {
@@ -587,6 +945,11 @@ SCNetworkSetSetCurrent(SCNetworkSetRef set)
        CFStringRef             path;
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
 
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
        path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
        ok = SCPreferencesSetValue(setPrivate->prefs, kSCPrefCurrentSet, path);
        CFRelease(path);
@@ -597,14 +960,50 @@ SCNetworkSetSetCurrent(SCNetworkSetRef set)
 Boolean
 SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
 {
+       CFBundleRef             bundle          = NULL;
        CFDictionaryRef         entity;
+       CFStringRef             localized       = NULL;
+       CFStringRef             non_localized   = NULL;
        Boolean                 ok              = FALSE;
        CFStringRef             path;
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
 
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if ((name != NULL) && !isA_CFString(name)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       // if known, compare against localized name
+
+       if (name != NULL) {
+               bundle = _SC_CFBundleGet();
+               if (bundle != NULL) {
+                       non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
+                                                                          CFSTR("DEFAULT_SET_NAME"),
+                                                                          CFSTR("Automatic"),
+                                                                          NULL);
+                       if (non_localized != NULL) {
+                               if (CFEqual(name, non_localized)) {
+                                       localized = CFBundleCopyLocalizedString(bundle,
+                                                                               CFSTR("DEFAULT_SET_NAME"),
+                                                                               CFSTR("Automatic"),
+                                                                               NULL);
+                                       if (localized != NULL) {
+                                               name = localized;
+                                       }
+                               }
+                       }
+               }
+       }
+
 #define PREVENT_DUPLICATE_SET_NAMES
 #ifdef  PREVENT_DUPLICATE_SET_NAMES
-       if (isA_CFString(name)) {
+       if (name != NULL) {
                CFArrayRef      sets;
 
                // ensure that each set is uniquely named
@@ -630,7 +1029,7 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
                                        // if "name" not unique
                                        CFRelease(sets);
                                        _SCErrorSet(kSCStatusKeyExists);
-                                       return FALSE;
+                                       goto done;
                                }
                        }
                        CFRelease(sets);
@@ -638,6 +1037,23 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
        }
 #endif  /* PREVENT_DUPLICATE_SET_NAMES */
 
+       // if known, store non-localized name
+
+       if ((name != NULL) && (bundle != NULL) && (non_localized != NULL)) {
+               if (localized == NULL) {
+                       localized = CFBundleCopyLocalizedString(bundle,
+                                                               CFSTR("DEFAULT_SET_NAME"),
+                                                               CFSTR("Automatic"),
+                                                               NULL);
+               }
+
+               if (localized != NULL) {
+                       if (CFEqual(name, localized)) {
+                               name = non_localized;
+                       }
+               }
+       }
+
        // update the "name"
 
        path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
@@ -654,7 +1070,7 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
                CFMutableDictionaryRef  newEntity;
 
                newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
-               if (isA_CFString(name)) {
+               if (name != NULL) {
                        CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name);
                } else {
                        CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
@@ -664,6 +1080,10 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
        }
        CFRelease(path);
 
+    done :
+
+       if (localized != NULL)          CFRelease(localized);
+       if (non_localized != NULL)      CFRelease(non_localized);
        return ok;
 }
 
@@ -677,6 +1097,29 @@ SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
        CFStringRef             path;
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
 
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if (isA_CFArray(newOrder)) {
+               CFIndex i;
+               CFIndex n       = CFArrayGetCount(newOrder);
+
+               for (i = 0; i < n; i++) {
+                       CFStringRef     serviceID;
+
+                       serviceID = CFArrayGetValueAtIndex(newOrder, i);
+                       if (!isA_CFString(serviceID)) {
+                               _SCErrorSet(kSCStatusInvalidArgument);
+                               return FALSE;
+                       }
+               }
+       } else {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
        path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
        if (path == NULL) {
                return FALSE;
@@ -699,3 +1142,141 @@ SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
 
        return ok;
 }
+
+
+#pragma mark -
+#pragma mark SCNetworkSet SPIs
+
+
+static void
+add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef interface)
+{
+       CFIndex         i;
+       CFArrayRef      interface_types;
+       CFIndex         n;
+
+       interface_types = SCNetworkInterfaceGetSupportedInterfaceTypes(interface);
+       n = (interface_types != NULL) ? CFArrayGetCount(interface_types) : 0;
+       for (i = 0; i < n; i++) {
+               SCNetworkInterfaceRef   parent;
+               CFStringRef             interface_type;
+
+               interface_type = CFArrayGetValueAtIndex(interface_types, i);
+               parent = SCNetworkInterfaceCreateWithInterface(interface, interface_type);
+               if (parent != NULL) {
+                       CFArrayAppendValue(interface_list, parent);
+                       CFRelease(parent);
+               }
+       }
+
+       return;
+}
+
+
+Boolean
+SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set)
+{
+       CFIndex                 i;
+       CFArrayRef              interfaces;
+       CFIndex                 n;
+       Boolean                 ok              = TRUE;
+       CFArrayRef              services;
+       Boolean                 setUpdated      = FALSE;
+       SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
+
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       // first, assume that we only want to add new services
+       // for those interfaces that are not represented in the
+       // current set.
+       services = SCNetworkSetCopyServices(set);
+       if ((services != NULL) && (CFArrayGetCount(services) > 0)) {
+               // but, if we are starting off with a non-empty
+               // set than we only want to add new services for
+               // those interfaces that are not represented in
+               // *any* set.
+               CFRelease(services);
+               services = SCNetworkServiceCopyAll(setPrivate->prefs);
+       }
+
+       interfaces = SCNetworkInterfaceCopyAll();
+       n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
+       for (i = 0; i < n; i++) {
+               SCNetworkInterfaceRef   interface;
+               CFMutableArrayRef       interface_list;
+
+               interface = CFArrayGetValueAtIndex(interfaces, i);
+               if (_SCNetworkServiceExistsForInterface(services, interface)) {
+                       // if this is not a new interface
+                       continue;
+               }
+
+               interface_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+               CFArrayAppendValue(interface_list, interface);
+
+               while (ok && (CFArrayGetCount(interface_list) > 0)) {
+                       CFArrayRef              protocol_types;
+
+                       interface = CFArrayGetValueAtIndex(interface_list, 0);
+
+                       protocol_types = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
+                       if ((protocol_types != NULL) && (CFArrayGetCount(protocol_types) > 0)) {
+                               SCNetworkServiceRef     service;
+
+                               service = SCNetworkServiceCreate(setPrivate->prefs, interface);
+                               if (service == NULL) {
+                                       SCLog(TRUE, LOG_DEBUG,
+                                             CFSTR("could not create service for \"%@\": %s\n"),
+                                             SCNetworkInterfaceGetLocalizedDisplayName(interface),
+                                             SCErrorString(SCError()));
+                                       ok = FALSE;
+                                       goto nextInterface;
+                               }
+
+                               ok = SCNetworkServiceEstablishDefaultConfiguration(service);
+                               if (!ok) {
+                                       SCLog(TRUE, LOG_DEBUG,
+                                             CFSTR("could not estabish default configuration for \"%@\": %s\n"),
+                                             SCNetworkInterfaceGetLocalizedDisplayName(interface),
+                                             SCErrorString(SCError()));
+                                       SCNetworkServiceRemove(service);
+                                       CFRelease(service);
+                                       goto nextInterface;
+                               }
+
+                               ok = SCNetworkSetAddService(set, service);
+                               if (!ok) {
+                                       SCLog(TRUE, LOG_DEBUG,
+                                             CFSTR("could not add service for \"%@\": %s\n"),
+                                             SCNetworkInterfaceGetLocalizedDisplayName(interface),
+                                             SCErrorString(SCError()));
+                                       SCNetworkServiceRemove(service);
+                                       CFRelease(service);
+                                       goto nextInterface;
+                               }
+
+                               CFRelease(service);
+                               setUpdated = TRUE;
+                       } else {
+                               add_supported_interfaces(interface_list, interface);
+                       }
+
+                   nextInterface :
+
+                       CFArrayRemoveValueAtIndex(interface_list, 0);
+               }
+               CFRelease(interface_list);
+       }
+       if (interfaces != NULL) CFRelease(interfaces);
+       if (services != NULL)   CFRelease(services);
+
+       if (ok && !setUpdated) {
+               // if no changes were made
+               _SCErrorSet(kSCStatusOK);
+       }
+
+       return setUpdated;
+}