]> git.saurik.com Git - apple/configd.git/blobdiff - SystemConfiguration.fproj/SCNetworkSet.c
configd-1061.40.2.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkSet.c
index 126300fe820bea67e1ac3a1ee4f036a62b85dda8..bfcf499e614a4e9e2c0592070ac49ff67927aa66 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2004-2007, 2009-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2019 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,
@@ -17,7 +17,7 @@
  * 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@
  */
 
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <CoreFoundation/CFRuntime.h>
-#include <SystemConfiguration/SystemConfiguration.h>
 #include "SCNetworkConfigurationInternal.h"
-#include <SystemConfiguration/SCValidation.h>
-#include <SystemConfiguration/SCPrivate.h>
 
 #include <pthread.h>
 
@@ -69,15 +66,19 @@ __SCNetworkSetCopyDescription(CFTypeRef cf)
 {
        CFAllocatorRef          allocator       = CFGetAllocator(cf);
        CFMutableStringRef      result;
-       SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)cf;
+       SCNetworkSetRef         set             = (SCNetworkSetRef)cf;
+       SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
 
        result = CFStringCreateMutable(allocator, 0);
-       CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkSet %p [%p]> {"), cf, allocator);
+       CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkSet %p [%p]> {"), set, 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);
        }
+       if (!__SCNetworkSetExists(set)) {
+               CFStringAppendFormat(result, NULL, CFSTR(", REMOVED"));
+       }
        CFStringAppendFormat(result, NULL, CFSTR("}"));
 
        return result;
@@ -157,10 +158,9 @@ __SCNetworkSetCreatePrivate(CFAllocatorRef      allocator,
                return NULL;
        }
 
+       /* initialize non-zero/NULL members */
        setPrivate->setID       = CFStringCreateCopy(NULL, setID);
        setPrivate->prefs       = CFRetain(prefs);
-       setPrivate->name        = NULL;
-       setPrivate->established = FALSE;        // "new" (not yet established) set
 
        return setPrivate;
 }
@@ -183,15 +183,42 @@ _serviceOrder(SCNetworkServiceRef service)
 }
 
 
+static CFIndex
+_serviceOrder_clear(CFMutableArrayRef order, CFStringRef serviceID)
+{
+       CFIndex f;      // # of serviceID's found
+       CFIndex i;
+       CFIndex n;
+
+       f = 0;
+       i = 0;
+       n = CFArrayGetCount(order);
+       while (i < n) {
+               CFStringRef     thisServiceID   = CFArrayGetValueAtIndex(order, i);
+
+               if (CFEqual(thisServiceID, serviceID)) {
+                       // remove the serviceID
+                       CFArrayRemoveValueAtIndex(order, i);
+                       n--;
+                       f++;
+                       continue;
+               }
+
+               i++;    // move to the next serviceID
+       }
+
+       return f;
+}
+
+
 static void
 _serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service)
 {
-       CFIndex                 i;
        CFIndex                 n;
        CFMutableArrayRef       newOrder;
        CFArrayRef              order;
-       CFStringRef             serviceID;
-       CFIndex                 serviceOrder;
+       CFStringRef             serviceID       = SCNetworkServiceGetServiceID(service);
+       CFIndex                 serviceOrder    = _serviceOrder(service);
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
        CFIndex                 slot;
 
@@ -201,18 +228,19 @@ _serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service)
        } else {
                newOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
        }
-       n = CFArrayGetCount(newOrder);
+       assert(newOrder != NULL);
 
-       serviceID = SCNetworkServiceGetServiceID(service);
-       if (CFArrayContainsValue(newOrder, CFRangeMake(0, n), serviceID)) {
-               // if serviceID already present
-               goto done;
+       n = _serviceOrder_clear(newOrder, serviceID);
+       if (n > 0) {
+               SC_log(LOG_ERR, "SCNetworkSetAddService() w/service already in ServiceOrder\n  service = %@\n  matched = %ld",
+                      service,
+                      n);
+               _SC_crash_once("SCNetworkSetAddService() w/service already in ServiceOrder", NULL, NULL);
        }
 
-       serviceOrder = _serviceOrder(service);
-
        slot = 0;
-       for (i = 0; i < n; i++) {
+       n = CFArrayGetCount(newOrder);
+       for (CFIndex i = 0; i < n; i++) {
                int                     slotOrder;
                SCNetworkServiceRef     slotService;
                CFStringRef             slotServiceID;
@@ -240,9 +268,6 @@ _serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service)
 
        CFArrayInsertValueAtIndex(newOrder, slot, serviceID);
        (void) SCNetworkSetSetServiceOrder(set, newOrder);
-
-    done :
-
        CFRelease(newOrder);
 
        return;
@@ -252,6 +277,7 @@ _serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service)
 static void
 _serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service)
 {
+       CFIndex                 n;
        CFMutableArrayRef       newOrder;
        CFArrayRef              order;
        CFStringRef             serviceID;
@@ -260,22 +286,17 @@ _serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service)
        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;
-               }
+       serviceID = SCNetworkServiceGetServiceID(service);
 
-               CFArrayRemoveValueAtIndex(newOrder, i);
+       n = _serviceOrder_clear(newOrder, serviceID);
+       if (n > 1) {
+               SC_log(LOG_ERR, "SCNetworkSetRemoveService() w/multiple instances of service in ServiceOrder\n  service = %@\n  count = %ld",
+                      service,
+                      n);
        }
+
        (void) SCNetworkSetSetServiceOrder(set, newOrder);
        CFRelease(newOrder);
 
@@ -287,9 +308,159 @@ _serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service)
 #pragma mark SCNetworkSet APIs
 
 
+#define DEFAULT_SET_NAME       CFSTR("Automatic")
 #define        N_QUICK 16
 
 
+static CFStringRef
+copy_default_set_name(Boolean loc)
+{
+       CFStringRef             name;
+       static CFStringRef      non_localized   = NULL;
+       static CFStringRef      localized       = NULL;
+
+       if (!loc) {
+               static dispatch_once_t  once;
+
+               dispatch_once(&once, ^{
+                       CFBundleRef     bundle;
+
+                       bundle = _SC_CFBundleGet();
+                       if (bundle != NULL) {
+                               non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
+                                                                                  CFSTR("DEFAULT_SET_NAME"),
+                                                                                  DEFAULT_SET_NAME,
+                                                                                  NULL);
+                       }
+               });
+               name = non_localized;
+       } else {
+               static dispatch_once_t  once;
+
+               dispatch_once(&once, ^{
+                       CFBundleRef     bundle;
+
+                       bundle = _SC_CFBundleGet();
+                       if (bundle != NULL) {
+                               localized = CFBundleCopyLocalizedString(bundle,
+                                                                       CFSTR("DEFAULT_SET_NAME"),
+                                                                       DEFAULT_SET_NAME,
+                                                                       NULL);
+                       }
+               });
+               name = localized;
+       }
+
+       if (name == NULL) {
+               // if bundle or localized names not available
+               name = DEFAULT_SET_NAME;
+       }
+
+       CFRetain(name);
+       return name;
+}
+
+
+#define        PREVENT_DUPLICATE_SERVICE_NAMES
+#ifdef PREVENT_DUPLICATE_SERVICE_NAMES
+static CFStringRef
+copy_next_name(CFStringRef name)
+{
+       CFArrayRef              components;
+       CFIndex                 n;
+       CFMutableArrayRef       newComponents;
+       SInt32                  suffix  = 2;
+
+       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"), (int)suffix);
+       CFArrayAppendValue(newComponents, name);
+       CFRelease(name);
+
+       name = CFStringCreateByCombiningStrings(NULL, newComponents, CFSTR(" "));
+       CFRelease(newComponents);
+
+       return name;
+}
+
+
+static Boolean
+ensure_unique_service_name(SCNetworkServiceRef service)
+{
+       SCNetworkInterfaceRef   interface;
+       CFStringRef             name;
+       Boolean                 ok      = TRUE;
+
+       interface = SCNetworkServiceGetInterface(service);
+
+       name = SCNetworkServiceGetName(service);
+       if (name != NULL) {
+               CFRetain(name);
+       }
+
+       while (TRUE) {
+               CFStringRef     newName;
+
+               ok = SCNetworkServiceSetName(service, name);
+               if (ok) {
+                       break;
+               }
+
+               if (SCError() != kSCStatusKeyExists) {
+                       SC_log(LOG_INFO, "could not update service name for \"%@\": %s",
+                             SCNetworkInterfaceGetLocalizedDisplayName(interface),
+                             SCErrorString(SCError()));
+                       break;
+               }
+
+               newName = copy_next_name(name);
+               if (newName == NULL) {
+                       SC_log(LOG_INFO, "could not create unique name for \"%@\": %s",
+                             SCNetworkInterfaceGetLocalizedDisplayName(interface),
+                             SCErrorString(SCError()));
+                       break;
+               }
+
+               // try again with the "new" name
+               if (name != NULL) {
+                       CFRelease(name);
+               }
+               name = newName;
+       }
+
+       if (name != NULL) {
+               CFRelease(name);
+       }
+
+       return ok;
+}
+#endif // PREVENT_DUPLICATE_SERVICE_NAMES
+
+
 Boolean
 SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
 {
@@ -311,6 +482,23 @@ SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
                return FALSE;
        }
 
+       if (!__SCNetworkSetExists(set)) {
+               SC_log(LOG_ERR, "SCNetworkSetAddService() w/removed set\n  set = %@\n  service = %@",
+                      set,
+                      service);
+               _SC_crash_once("SCNetworkSetAddService() w/removed set", NULL, NULL);
+               _SCErrorSet(kSCStatusInvalidArgument);
+       }
+
+       if (!__SCNetworkServiceExists(service)) {
+               SC_log(LOG_ERR, "SCNetworkSetAddService() w/removed service\n  set = %@\n  service =  %@",
+                      set,
+                      service);
+               _SC_crash_once("SCNetworkSetAddService() w/removed service", NULL, NULL);
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
        // make sure that we do not add an orphaned network service if its
        // associated interface is a member of a bond or bridge.
        interface = SCNetworkServiceGetInterface(service);
@@ -320,42 +508,6 @@ SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
                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;
@@ -404,6 +556,21 @@ SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
                                                              servicePrivate->serviceID,        // service
                                                              NULL);                            // entity
        ok = SCPreferencesPathSetLink(setPrivate->prefs, path, link);
+#ifdef PREVENT_DUPLICATE_SERVICE_NAMES
+       if (ok) {
+               // We use the interface cache here to not reach into the
+               // IORegistry for every service we go through
+               _SCNetworkInterfaceCacheOpen();
+               ok = ensure_unique_service_name(service);
+               _SCNetworkInterfaceCacheClose();
+
+               if (!ok) {
+                       // if we could not ensure a unique name, remove the (just added)
+                       // link between the "set" and the "service"
+                       (void) SCPreferencesPathRemoveValue(setPrivate->prefs, path);
+               }
+       }
+#endif // PREVENT_DUPLICATE_SERVICE_NAMES
        CFRelease(path);
        CFRelease(link);
        if (!ok) {
@@ -423,6 +590,10 @@ SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
 
     done :
 
+       if (ok) {
+               SC_log(LOG_DEBUG, "SCNetworkSetAddService(): %@, %@", set, service);
+       }
+
        if (interface_config != NULL)   CFRelease(interface_config);
        return ok;
 }
@@ -450,6 +621,7 @@ SCNetworkSetCopy(SCPreferencesRef prefs, CFStringRef setID)
        }
 
        setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
+       assert(setPrivate != NULL);
 
        // mark set as "old" (already established)
        setPrivate->established = TRUE;
@@ -509,14 +681,12 @@ SCNetworkSetCopyAll(SCPreferencesRef prefs)
                        SCNetworkSetPrivateRef  setPrivate;
 
                        if (!isA_CFDictionary(vals[i])) {
-                               SCLog(TRUE,
-                                     LOG_INFO,
-                                     CFSTR("SCNetworkSetCopyAll(): error w/set \"%@\"\n"),
-                                     keys[i]);
+                               SC_log(LOG_INFO, "error w/set \"%@\"", keys[i]);
                                continue;
                        }
 
                        setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, keys[i]);
+                       assert(setPrivate != NULL);
 
                        // mark set as "old" (already established)
                        setPrivate->established = TRUE;
@@ -534,6 +704,80 @@ SCNetworkSetCopyAll(SCPreferencesRef prefs)
 }
 
 
+CFArrayRef /* of SCNetworkInterfaceRef's */
+SCNetworkSetCopyAvailableInterfaces(SCNetworkSetRef set)
+{
+       CFMutableArrayRef       available;
+       CFMutableSetRef         excluded        = NULL;
+       int                     i;
+       CFArrayRef              interfaces;
+       CFIndex                 n_interfaces;
+       CFIndex                 n_exclusions    = 0;
+       SCPreferencesRef        prefs;
+       SCNetworkSetPrivateRef  setPrivate;
+
+       setPrivate = (SCNetworkSetPrivateRef)set;
+       prefs = setPrivate->prefs;
+
+       interfaces = _SCNetworkInterfaceCopyAllWithPreferences(prefs);
+       n_interfaces = CFArrayGetCount(interfaces);
+       if (n_interfaces == 0) {
+               return interfaces;
+       }
+
+       if (prefs != NULL) {
+               CFArrayRef      bridges = NULL;
+
+               excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+
+#if    !TARGET_OS_IPHONE
+               CFArrayRef      bonds   = NULL;
+
+               bonds = SCBondInterfaceCopyAll(prefs);
+               if (bonds != NULL) {
+                       __SCBondInterfaceListCollectMembers(bonds, excluded);
+                       CFRelease(bonds);
+               }
+#endif /* !TARGET_OS_IPHONE */
+
+               bridges = SCBridgeInterfaceCopyAll(prefs);
+               if (bridges != NULL) {
+                       __SCBridgeInterfaceListCollectMembers(bridges, excluded);
+                       CFRelease(bridges);
+               }
+
+               n_exclusions = CFSetGetCount(excluded);
+       }
+
+       if (n_exclusions == 0) {
+               if (excluded != NULL) {
+                       CFRelease(excluded);
+               }
+
+               return interfaces;
+       }
+
+       available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+       for (i = 0; i < n_interfaces; i++) {
+               SCNetworkInterfaceRef   interface;
+
+               interface = CFArrayGetValueAtIndex(interfaces, i);
+               if (CFSetContainsValue(excluded, interface)) {
+                       // if excluded
+                       continue;
+               }
+
+               CFArrayAppendValue(available, interface);
+       }
+
+       CFRelease(interfaces);
+       CFRelease(excluded);
+
+       return available;
+}
+
+
 SCNetworkSetRef
 SCNetworkSetCopyCurrent(SCPreferencesRef prefs)
 {
@@ -555,11 +799,12 @@ SCNetworkSetCopyCurrent(SCPreferencesRef prefs)
                path = SCPreferencesPathKeyCreateSet(NULL, setID);
                if (CFEqual(path, currentID)) {
                        setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
+                       assert(setPrivate != NULL);
 
                        // mark set as "old" (already established)
                        setPrivate->established = TRUE;
                } else {
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkSetCopyCurrent(): preferences are non-conformant"));
+                       SC_log(LOG_NOTICE, "SCNetworkSetCopyCurrent(): preferences are non-conformant");
                }
                CFRelease(path);
        }
@@ -613,11 +858,9 @@ SCNetworkSetCopyServices(SCNetworkSetRef set)
                        link = SCPreferencesPathGetLink(setPrivate->prefs, path);
                        CFRelease(path);
                        if (link == NULL) {
-                               SCLog(TRUE,
-                                     LOG_INFO,
-                                     CFSTR("SCNetworkSetCopyServices(): service \"%@\" for set \"%@\" is not a link\n"),
-                                     keys[i],
-                                     setPrivate->setID);
+                               SC_log(LOG_INFO, "service \"%@\" for set \"%@\" is not a link",
+                                      keys[i],
+                                      setPrivate->setID);
                                continue;        // if the service is not a link
                        }
 
@@ -630,14 +873,31 @@ SCNetworkSetCopyServices(SCNetworkSetRef set)
                                                                                      serviceID,        // service
                                                                                      NULL);            // entity
                                if (CFEqual(path, link)) {
-                                       SCNetworkServicePrivateRef      servicePrivate;
-
-                                       servicePrivate = __SCNetworkServiceCreatePrivate(NULL,
-                                                                                        setPrivate->prefs,
-                                                                                        serviceID,
-                                                                                        NULL);
-                                       CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
-                                       CFRelease(servicePrivate);
+                                       CFDictionaryRef entity;
+                                       CFStringRef     interfacePath;
+                                       Boolean         skip            = FALSE;
+
+                                       interfacePath = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,                    // allocator
+                                                                                                      serviceID,               // service
+                                                                                                      kSCEntNetInterface);     // entity
+                                       entity = SCPreferencesPathGetValue(setPrivate->prefs, interfacePath);
+                                       CFRelease(interfacePath);
+
+                                       if (__SCNetworkInterfaceEntityIsPPTP(entity)) {
+                                               SC_log(LOG_INFO, "PPTP services are no longer supported");
+                                               skip = TRUE;
+                                       }
+
+                                       if (!skip) {
+                                               SCNetworkServicePrivateRef      servicePrivate;
+
+                                               servicePrivate = __SCNetworkServiceCreatePrivate(NULL,
+                                                                                                setPrivate->prefs,
+                                                                                                serviceID,
+                                                                                                NULL);
+                                               CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
+                                               CFRelease(servicePrivate);
+                                       }
                                }
                                CFRelease(path);
                        }
@@ -674,6 +934,7 @@ SCNetworkSetCreate(SCPreferencesRef prefs)
        components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
        setID = CFArrayGetValueAtIndex(components, 2);
        setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
+       assert(setPrivate != NULL);
        CFRelease(components);
 
        // mark set as "new" (not yet established)
@@ -692,10 +953,73 @@ SCNetworkSetCreate(SCPreferencesRef prefs)
                setPrivate = NULL;
        }
 
+       if (setPrivate != NULL) {
+               SC_log(LOG_DEBUG, "SCNetworkSetCreate(): %@", setPrivate);
+       }
+
        return (SCNetworkSetRef)setPrivate;
 }
 
 
+SCNetworkSetRef
+_SCNetworkSetCreateDefault(SCPreferencesRef prefs)
+{
+       CFStringRef     model;
+       Boolean         ok              = TRUE;
+       SCNetworkSetRef set;
+       CFStringRef     setName         = NULL;
+
+       set = SCNetworkSetCopyCurrent(prefs);
+       if (set != NULL) {
+               SC_log(LOG_NOTICE, "creating default set w/already existing set");
+               CFRelease(set);
+               _SCErrorSet(kSCStatusKeyExists);
+               return NULL;
+       }
+
+       // create a new ("Automatic") set
+       set = SCNetworkSetCreate(prefs);
+       if (set == NULL) {
+               SC_log(LOG_NOTICE, "could not create \"new\" set: %s",
+                      SCErrorString(SCError()));
+               goto done;
+       }
+
+       setName = copy_default_set_name(TRUE);
+       ok = SCNetworkSetSetName(set, setName);
+       CFRelease(setName);
+       if (!ok) {
+               // if we could not save the new set's "name"
+               SC_log(LOG_NOTICE, "could not save the new set's name: %s",
+                      SCErrorString(SCError()));
+               goto done;
+       }
+
+       ok = SCNetworkSetSetCurrent(set);
+       if (!ok) {
+               // if we could not make this the "current" set
+               SC_log(LOG_NOTICE, "could not establish new set as current: %s",
+                      SCErrorString(SCError()));
+//             goto done;
+       }
+
+       model = SCPreferencesGetValue(prefs, MODEL);
+       if (model == NULL) {
+               model = _SC_hw_model(FALSE);
+               SCPreferencesSetValue(prefs, MODEL, model);
+       }
+
+    done :
+
+       if (!ok && (set != NULL)) {
+               SCNetworkSetRemove(set);
+               CFRelease(set);
+               set = NULL;
+       }
+       return set;
+}
+
+
 CFStringRef
 SCNetworkSetGetSetID(SCNetworkSetRef set)
 {
@@ -713,7 +1037,6 @@ SCNetworkSetGetSetID(SCNetworkSetRef set)
 CFStringRef
 SCNetworkSetGetName(SCNetworkSetRef set)
 {
-       CFBundleRef             bundle;
        CFDictionaryRef         entity;
        CFStringRef             path;
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
@@ -740,33 +1063,20 @@ SCNetworkSetGetName(SCNetworkSetRef set)
                }
        }
 
-       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;
-                                       }
-                               }
+       if (setPrivate->name != NULL) {
+               CFStringRef     non_localized;
 
-                               CFRelease(non_localized);
-                       }
+               non_localized = copy_default_set_name(FALSE);
+               if (CFEqual(setPrivate->name, non_localized)) {
+                       CFStringRef     localized;
+
+                       // if "Automatic", return localized name
+                       localized = copy_default_set_name(TRUE);
+                       CFRelease(setPrivate->name);
+                       setPrivate->name = localized;
                }
+
+               CFRelease(non_localized);
        }
 
        return setPrivate->name;
@@ -812,6 +1122,24 @@ SCNetworkSetGetTypeID(void)
 }
 
 
+#if    TARGET_OS_IPHONE
+static Boolean
+isDefaultSet(SCNetworkSetRef set)
+{
+       CFStringRef     defaultName;
+       Boolean         isDefault       = FALSE;
+       CFStringRef     setName;
+
+       defaultName = copy_default_set_name(TRUE);
+       setName = SCNetworkSetGetName(set);
+       isDefault = _SC_CFEqual(setName, defaultName);
+       CFRelease(defaultName);
+
+       return isDefault;
+}
+#endif // TARGET_OS_IPHONE
+
+
 Boolean
 SCNetworkSetRemove(SCNetworkSetRef set)
 {
@@ -825,15 +1153,35 @@ SCNetworkSetRemove(SCNetworkSetRef set)
                return FALSE;
        }
 
+       if (!__SCNetworkSetExists(set)) {
+               SC_log(LOG_ERR, "SCNetworkSetRemove() w/removed set\n  set = %@", set);
+               _SC_crash_once("SCNetworkSetRemove() w/removed set", NULL, NULL);
+               _SCErrorSet(kSCStatusInvalidArgument);
+       }
+
+#if    TARGET_OS_IPHONE
+       if (isDefaultSet(set) && (geteuid() != 0)) {
+               SC_log(LOG_ERR, "SCNetworkSetRemove() failed, cannot remove set : %@", set);
+               _SC_crash("The \"Automatic\" network set cannot be removed", NULL, NULL);
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+#endif // TARGET_OS_IPHONE
+
        currentPath = SCPreferencesGetValue(setPrivate->prefs, kSCPrefCurrentSet);
        path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
        if (!isA_CFString(currentPath) || !CFEqual(currentPath, path)) {
                ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
        } else {
+               SC_log(LOG_DEBUG, "SCNetworkSetRemove() failed, currently active: %@", setPrivate->setID);
                _SCErrorSet(kSCStatusInvalidArgument);
        }
        CFRelease(path);
 
+       if (ok) {
+               SC_log(LOG_DEBUG, "SCNetworkSetRemove(): %@", set);
+       }
+
        return ok;
 }
 
@@ -859,6 +1207,23 @@ SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service)
                return FALSE;
        }
 
+       if (!__SCNetworkSetExists(set)) {
+               SC_log(LOG_ERR, "SCNetworkSetRemoveService() w/removed set\n  set = %@\n  service = %@",
+                      set,
+                      service);
+               _SC_crash_once("SCNetworkSetRemoveService() w/removed set", NULL, NULL);
+               _SCErrorSet(kSCStatusInvalidArgument);
+       }
+
+       if (!__SCNetworkServiceExists(service)) {
+               SC_log(LOG_ERR, "SCNetworkSetRemoveService() w/removed service\n  set = %@\n  service = %@",
+                      set,
+                      service);
+               _SC_crash_once("SCNetworkSetRemoveService() w/removed service", NULL, NULL);
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
        // remove service from ServiceOrder
        _serviceOrder_remove(set, service);
 
@@ -886,12 +1251,15 @@ SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service)
        // push the [deep] interface configuration [back] into all sets which contain the service.
        if (interface_config != NULL) {
                __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config);
+               CFRelease(interface_config);
        }
 
-       if (interface_config != NULL)     CFRelease(interface_config);
-       if (!ok) {
+       if (ok) {
+               SC_log(LOG_DEBUG, "SCNetworkSetRemoveService(): %@, %@", set, service);
+       } else {
                _SCErrorSet(sc_status);
        }
+
        return ok;
 }
 
@@ -908,9 +1276,21 @@ SCNetworkSetSetCurrent(SCNetworkSetRef set)
                return FALSE;
        }
 
+       if (!__SCNetworkSetExists(set)) {
+               SC_log(LOG_ERR, "SCNetworkSetSetCurrent() w/removed set\n  set = %@", set);
+               _SC_crash_once("SCNetworkSetSetCurrent() w/removed set", NULL, NULL);
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
        path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
        ok = SCPreferencesSetValue(setPrivate->prefs, kSCPrefCurrentSet, path);
        CFRelease(path);
+
+       if (ok) {
+               SC_log(LOG_DEBUG, "SCNetworkSetSetCurrent(): %@", set);
+       }
+
        return ok;
 }
 
@@ -918,8 +1298,10 @@ SCNetworkSetSetCurrent(SCNetworkSetRef set)
 Boolean
 SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
 {
-       CFBundleRef             bundle          = NULL;
        CFDictionaryRef         entity;
+#if    TARGET_OS_IPHONE
+       Boolean                 isDefaultName   = FALSE;
+#endif // TARGET_OS_IPHONE
        CFStringRef             localized       = NULL;
        CFStringRef             non_localized   = NULL;
        Boolean                 ok              = FALSE;
@@ -931,6 +1313,15 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
                return FALSE;
        }
 
+       if (!__SCNetworkSetExists(set)) {
+               SC_log(LOG_ERR, "SCNetworkSetSetName() w/removed set\n  set = %@\n  name = %@",
+                      set,
+                      name != NULL ? name : CFSTR("<NULL>"));
+               _SC_crash_once("SCNetworkSetSetName() w/removed set", NULL, NULL);
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
        if ((name != NULL) && !isA_CFString(name)) {
                _SCErrorSet(kSCStatusInvalidArgument);
                return FALSE;
@@ -939,28 +1330,42 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
        // 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;
-                                       }
-                               }
-                       }
+               non_localized = copy_default_set_name(FALSE);
+               if (CFEqual(name, non_localized)) {
+                       localized = copy_default_set_name(TRUE);
+                       name = localized;
+#if    TARGET_OS_IPHONE
+                       isDefaultName = TRUE;
+#endif // TARGET_OS_IPHONE
                }
+#if    TARGET_OS_IPHONE
+               else {
+                       localized = copy_default_set_name(TRUE);
+                       isDefaultName = CFEqual(name, non_localized);
+               }
+#endif // TARGET_OS_IPHONE
        }
 
-#define PREVENT_DUPLICATE_SET_NAMES
-#ifdef  PREVENT_DUPLICATE_SET_NAMES
+#if    TARGET_OS_IPHONE
+       if (!isDefaultName && isDefaultSet(set) && (geteuid() != 0)) {
+               // if we are trying to change the name of the "Automatic" set
+               SC_log(LOG_ERR, "SCNetworkSetSetName() failed, cannot rename : %@", set);
+               _SC_crash("The \"Automatic\" network set cannot be renamed", NULL, NULL);
+               _SCErrorSet(kSCStatusInvalidArgument);
+               goto done;
+       }
+#endif // TARGET_OS_IPHONE
+
+#define        PREVENT_DUPLICATE_SET_NAMES
+#ifdef PREVENT_DUPLICATE_SET_NAMES
+
+#if    TARGET_OS_IPHONE
+       if (!isDefaultName) {
+               // On iOS, only block naming multiple sets with the name
+               // "Automatic".  Others names are OK.
+       } else
+#endif // TARGET_OS_IPHONE
+
        if (name != NULL) {
                CFArrayRef      sets;
 
@@ -997,18 +1402,12 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
 
        // if known, store non-localized name
 
-       if ((name != NULL) && (bundle != NULL) && (non_localized != NULL)) {
+       if ((name != NULL) && (non_localized != NULL)) {
                if (localized == NULL) {
-                       localized = CFBundleCopyLocalizedString(bundle,
-                                                               CFSTR("DEFAULT_SET_NAME"),
-                                                               CFSTR("Automatic"),
-                                                               NULL);
+                       localized = copy_default_set_name(TRUE);
                }
-
-               if (localized != NULL) {
-                       if (CFEqual(name, localized)) {
-                               name = non_localized;
-                       }
+               if (CFEqual(name, localized)) {
+                       name = non_localized;
                }
        }
 
@@ -1040,6 +1439,10 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
 
     done :
 
+       if (ok) {
+               SC_log(LOG_DEBUG, "SCNetworkSetSetName(): %@", set);
+       }
+
        if (localized != NULL)          CFRelease(localized);
        if (non_localized != NULL)      CFRelease(non_localized);
        return ok;
@@ -1049,7 +1452,10 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
 Boolean
 SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
 {
+       CFMutableArrayRef       cleanOrder;
        CFDictionaryRef         dict;
+       CFIndex                 i;
+       CFIndex                 n;
        CFMutableDictionaryRef  newDict;
        Boolean                 ok;
        CFStringRef             path;
@@ -1060,10 +1466,15 @@ SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
                return FALSE;
        }
 
-       if (isA_CFArray(newOrder)) {
-               CFIndex i;
-               CFIndex n       = CFArrayGetCount(newOrder);
+       if (!__SCNetworkSetExists(set)) {
+               SC_log(LOG_ERR, "SCNetworkSetSetServiceOrder() w/removed set\n  set = %@", set);
+               _SC_crash_once("SCNetworkSetSetServiceOrder() w/removed set", NULL, NULL);
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
 
+       if (isA_CFArray(newOrder)) {
+               n = CFArrayGetCount(newOrder);
                for (i = 0; i < n; i++) {
                        CFStringRef     serviceID;
 
@@ -1093,7 +1504,24 @@ SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
                                                    &kCFTypeDictionaryValueCallBacks);
        }
 
-       CFDictionarySetValue(newDict, kSCPropNetServiceOrder, newOrder);
+       cleanOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       n = CFArrayGetCount(newOrder);
+       for (i = 0; i < n; i++) {
+               CFIndex         nClean          = CFArrayGetCount(cleanOrder);
+               CFStringRef     serviceID       = CFArrayGetValueAtIndex(newOrder, i);
+
+               if ((nClean == 0) ||
+                   !CFArrayContainsValue(cleanOrder, CFRangeMake(0, nClean), serviceID)) {
+                       // if first reference to this serviceID
+                       CFArrayAppendValue(cleanOrder, serviceID);
+               } else {
+                       // skip duplicate serviceID
+                       SC_log(LOG_ERR, "SCNetworkSetSetServiceOrder() found duplicate serviceID: removed %@\n", serviceID);
+               }
+       }
+       CFDictionarySetValue(newDict, kSCPropNetServiceOrder, cleanOrder);
+       CFRelease(cleanOrder);
+
        ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newDict);
        CFRelease(newDict);
        CFRelease(path);
@@ -1106,6 +1534,31 @@ SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
 #pragma mark SCNetworkSet SPIs
 
 
+__private_extern__
+Boolean
+__SCNetworkSetExists(SCNetworkSetRef set)
+{
+       CFDictionaryRef                 entity;
+       CFStringRef                     path;
+       SCNetworkSetPrivateRef          setPrivate      = (SCNetworkSetPrivateRef)set;
+
+       if (setPrivate->prefs == NULL) {
+               return FALSE;
+       }
+
+       path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
+       entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
+       CFRelease(path);
+
+       if (!isA_CFDictionary(entity)) {
+               // if no "set"
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
 static void
 add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef interface)
 {
@@ -1130,6 +1583,7 @@ add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef
        return;
 }
 
+
 static CFSetRef        /* of SCNetworkInterfaceRef's */
 copyExcludedInterfaces(SCPreferencesRef prefs)
 {
@@ -1158,16 +1612,197 @@ copyExcludedInterfaces(SCPreferencesRef prefs)
 }
 
 
+#if    !TARGET_OS_IPHONE
+static SCBridgeInterfaceRef
+copyAutoBridgeInterface(SCPreferencesRef prefs, CFStringRef bridgeName)
+{
+       SCBridgeInterfaceRef    bridge          = NULL;
+       CFArrayRef              interfaces;
+
+       // exclude Bridge [member] interfaces
+       interfaces = SCBridgeInterfaceCopyAll(prefs);
+       if (interfaces != NULL) {
+               CFIndex         i;
+               CFIndex         n;
+
+               n = CFArrayGetCount(interfaces);
+               for (i = 0; i < n; i++) {
+                       SCBridgeInterfaceRef    interface;
+                       CFStringRef             name    = NULL;
+                       CFDictionaryRef         options;
+
+                       interface = CFArrayGetValueAtIndex(interfaces, i);
+                       options = SCBridgeInterfaceGetOptions(interface);
+                       if ((options != NULL) &&
+                           CFDictionaryGetValueIfPresent(options,
+                                                         CFSTR("__AUTO__"),
+                                                         (const void **)&name) &&
+                           _SC_CFEqual(name, bridgeName)) {
+                               bridge = interface;
+                               CFRetain(bridge);
+                               break;
+                       }
+               }
+
+               CFRelease(interfaces);
+       }
+
+       if (bridge == NULL) {
+               bridge = SCBridgeInterfaceCreate(prefs);
+               if (bridge != NULL) {
+                       CFMutableDictionaryRef  newOptions;
+                       Boolean                 ok;
+
+                       newOptions = CFDictionaryCreateMutable(NULL, 0,
+                                                              &kCFTypeDictionaryKeyCallBacks,
+                                                              &kCFTypeDictionaryValueCallBacks);
+                       CFDictionarySetValue(newOptions, CFSTR("__AUTO__"), bridgeName);
+                       ok = SCBridgeInterfaceSetOptions(bridge, newOptions);
+                       CFRelease(newOptions);
+                       if (!ok) {
+                               CFRelease(bridge);
+                               bridge = NULL;
+                       }
+               }
+       }
+
+       return bridge;
+}
+#endif // !TARGET_OS_IPHONE
+
+
+static CFArrayRef
+copyServices(SCNetworkSetRef set)
+{
+       CFArrayRef              services;
+       SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
+
+       // 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) && setPrivate->established) {
+               // but, if we are given an existing (or "established") 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);
+       }
+
+       return services;
+}
+
+
+#if    !TARGET_OS_IPHONE
+static CF_RETURNS_RETAINED CFArrayRef
+updateServices(CFArrayRef services, SCNetworkInterfaceRef interface)
+{
+       CFStringRef             bsdName;
+       CFIndex                 i;
+       CFIndex                 n;
+       CFMutableArrayRef       newServices;
+
+       if (services == NULL) {
+               return NULL;
+       }
+
+       bsdName = SCNetworkInterfaceGetBSDName(interface);
+
+       newServices = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+       n = CFArrayGetCount(services);
+       for (i = 0; i < n; i++) {
+               SCNetworkInterfaceRef           interface;
+               CFStringRef                     interfaceName;
+               SCNetworkServiceRef             newService;
+               SCNetworkServiceRef             service;
+               CFStringRef                     serviceID;
+               SCNetworkServicePrivateRef      servicePrivate;
+
+               service = CFArrayGetValueAtIndex(services, i);
+               interface = SCNetworkServiceGetInterface(service);
+               interfaceName = SCNetworkInterfaceGetBSDName(interface);
+               if (!_SC_CFEqual(interfaceName, bsdName)) {
+                       // if not a match, retain
+                       CFArrayAppendValue(newServices, service);
+                       continue;
+               }
+
+               // if a match, update
+               serviceID = SCNetworkServiceGetServiceID(service);
+               servicePrivate = (SCNetworkServicePrivateRef)service;
+               newService = SCNetworkServiceCopy(servicePrivate->prefs, serviceID);
+               if (newService != NULL) {
+                       CFArrayAppendValue(newServices, newService);
+                       CFRelease(newService);
+               }
+       }
+
+       return newServices;
+}
+#endif // !TARGET_OS_IPHONE
+
+
+static __inline__ Boolean
+skipInterface(SCNetworkInterfaceRef interface)
+{
+       CFStringRef     action;
+
+       action = _SCNetworkInterfaceGetConfigurationAction(interface);
+       if (isA_CFString(action) &&
+           CFEqual(action, kSCNetworkInterfaceConfigurationActionValueNone)) {
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+
+CFComparisonResult
+_SCNetworkSetCompare(const void *val1, const void *val2, void *context)
+{
+#pragma unused(context)
+       CFStringRef     id1;
+       CFStringRef     id2;
+       CFStringRef     name1;
+       CFStringRef     name2;
+       SCNetworkSetRef s1      = (SCNetworkSetRef)val1;
+       SCNetworkSetRef s2      = (SCNetworkSetRef)val2;
+
+       name1 = SCNetworkSetGetName(s1);
+       name2 = SCNetworkSetGetName(s2);
+
+       if (name1 != NULL) {
+               if (name2 != NULL) {
+                       return CFStringCompare(name1, name2, 0);
+               } else {
+                       return kCFCompareLessThan;
+               }
+       }
+
+       if (name2 != NULL) {
+               return kCFCompareGreaterThan;
+       }
+
+       id1 = SCNetworkSetGetSetID(s1);
+       id2 = SCNetworkSetGetSetID(s2);
+       return CFStringCompare(id1, id2, 0);
+}
+
+
 static Boolean
-__SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces)
+__SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces, Boolean excludeHidden)
 {
-       CFSetRef                excluded        = NULL;
+       CFSetRef                excluded;
        CFIndex                 i;
        CFIndex                 n               = 0;
        Boolean                 ok              = TRUE;
        CFArrayRef              services;
        SCNetworkSetPrivateRef  setPrivate      = (SCNetworkSetPrivateRef)set;
        Boolean                 updated         = FALSE;
+#if    !TARGET_OS_IPHONE
+       Boolean                 updatedIFs      = FALSE;
+#endif // !TARGET_OS_IPHONE
 
 #if    TARGET_OS_IPHONE
        CFArrayRef              orphans         = NULL;
@@ -1193,28 +1828,120 @@ __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CF
        }
 #endif // TARGET_OS_IPHONE
 
-       // 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) && setPrivate->established) {
-               // but, if we are given an existing (or "established") 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);
-       }
+       // copy network services
+       services = copyServices(set);
 
+       // copy network interfaces to be excluded
        excluded = copyExcludedInterfaces(setPrivate->prefs);
 
-       n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
+#if    !TARGET_OS_IPHONE
+       // look for interfaces that should auto-magically be added
+       // to an Ethernet bridge
+       n = ((services != NULL) && (interfaces != NULL)) ? CFArrayGetCount(interfaces) : 0;
+       for (i = 0; i < n; i++) {
+               SCBridgeInterfaceRef    bridge          = NULL;
+               SCNetworkInterfaceRef   interface;
+
+               interface = CFArrayGetValueAtIndex(interfaces, i);
+
+               if (excludeHidden && skipInterface(interface)) {
+                       // if not auto-configure
+                       continue;
+               }
+
+               if (CFSetContainsValue(excluded, interface)) {
+                       // if this interface is a member of a Bond or Bridge
+                       continue;
+               }
+
+               if (__SCNetworkServiceExistsForInterface(services, interface)) {
+                       // if this is not a new interface
+                       continue;
+               }
+
+               if (_SCNetworkInterfaceIsBuiltin(interface) &&
+                   _SCNetworkInterfaceIsThunderbolt(interface) &&
+                   !isA_SCBridgeInterface(interface)) {
+                       // add built-in Thunderbolt interfaces to bridge
+                       bridge = copyAutoBridgeInterface(setPrivate->prefs, CFSTR("thunderbolt-bridge"));
+               }
+
+               if (bridge != NULL) {
+                       CFIndex                 bridgeIndex;
+                       CFArrayRef              members;
+                       CFMutableArrayRef       newMembers;
+                       CFMutableSetRef         newExcluded;
+                       CFMutableArrayRef       newInterfaces;
+                       CFArrayRef              newServices;
+
+                       // track the bridge interface (if it's in our list)
+                       bridgeIndex = CFArrayGetFirstIndexOfValue(interfaces,
+                                                                 CFRangeMake(0, CFArrayGetCount(interfaces)),
+                                                                 bridge);
+
+                       // add new member interface
+                       members = SCBridgeInterfaceGetMemberInterfaces(bridge);
+                       if ((members != NULL) && (CFArrayGetCount(members) > 0)) {
+                               newMembers = CFArrayCreateMutableCopy(NULL, 0, members);
+                               updated = TRUE;         // if we're updating an existing bridge
+                       } else {
+                               newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+                       }
+                       CFArrayAppendValue(newMembers, interface);
+                       ok = SCBridgeInterfaceSetMemberInterfaces(bridge, newMembers);
+                       CFRelease(newMembers);
+                       if (!ok) {
+                               SC_log(LOG_INFO, "could not update bridge with \"%@\": %s",
+                                      SCNetworkInterfaceGetLocalizedDisplayName(interface),
+                                      SCErrorString(SCError()));
+                               CFRelease(bridge);
+                               continue;
+                       }
+
+                       // exclude the new member interface
+                       newExcluded = CFSetCreateMutableCopy(NULL, 0, excluded);
+                       CFRelease(excluded);
+                       CFSetAddValue(newExcluded, interface);
+                       excluded = newExcluded;
+
+                       // update the list of interfaces to include the [new or updated] bridge
+                       newInterfaces = CFArrayCreateMutableCopy(NULL, 0, interfaces);
+                       if (bridgeIndex != kCFNotFound) {
+                               CFArraySetValueAtIndex(newInterfaces, bridgeIndex, bridge);
+                       } else {
+                               CFArrayAppendValue(newInterfaces, bridge);
+                       }
+                       if (updatedIFs) {
+                               CFRelease(interfaces);
+                       }
+                       interfaces = newInterfaces;
+                       updatedIFs = TRUE;
+
+                       // refresh [existing] services
+                       newServices = updateServices(services, bridge);
+                       if (newServices != NULL) {
+                               CFRelease(services);
+                               services = newServices;
+                       }
+
+                       CFRelease(bridge);
+               }
+       }
+#endif // !TARGET_OS_IPHONE
+
+       n = ((services != NULL) && (interfaces != NULL)) ? CFArrayGetCount(interfaces) : 0;
        for (i = 0; i < n; i++) {
                SCNetworkInterfaceRef   interface;
                CFMutableArrayRef       interface_list;
 
                interface = CFArrayGetValueAtIndex(interfaces, i);
-               if ((excluded != NULL)
-                   && CFSetContainsValue(excluded, interface)) {
+
+               if (excludeHidden && skipInterface(interface)) {
+                       // if not auto-configure
+                       continue;
+               }
+
+               if (CFSetContainsValue(excluded, interface)) {
                        // if this interface is a member of a Bond or Bridge
                        continue;
                }
@@ -1238,72 +1965,31 @@ __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CF
 
                                service = SCNetworkServiceCreate(setPrivate->prefs, interface);
                                if (service == NULL) {
-                                       SCLog(TRUE, LOG_DEBUG,
-                                             CFSTR("could not create service for \"%@\": %s\n"),
-                                             SCNetworkInterfaceGetLocalizedDisplayName(interface),
-                                             SCErrorString(SCError()));
+                                       SC_log(LOG_ERR, "could not create service for \"%@\": %s",
+                                              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()));
+                                       SC_log(LOG_ERR, "could not estabish default configuration for \"%@\": %s",
+                                              SCNetworkInterfaceGetLocalizedDisplayName(interface),
+                                              SCErrorString(SCError()));
                                        SCNetworkServiceRemove(service);
                                        CFRelease(service);
                                        goto nextInterface;
                                }
 
-                               while (TRUE) {
-                                       CFStringRef     newName;
-
-                                       ok = SCNetworkSetAddService(set, service);
-                                       if (ok) {
-                                               break;
-                                       }
-
-                                       if (SCError() != kSCStatusKeyExists) {
-                                               SCLog(TRUE, LOG_DEBUG,
-                                                     CFSTR("could not add service for \"%@\": %s\n"),
-                                                     SCNetworkInterfaceGetLocalizedDisplayName(interface),
-                                                     SCErrorString(SCError()));
-                                               SCNetworkServiceRemove(service);
-                                               CFRelease(service);
-                                               goto nextInterface;
-                                       }
-
-                                       // we have two interfaces with the same service
-                                       // name, acquire a new, hopefully unique, name
-
-                                       newName = __SCNetworkServiceNextName(service);
-                                       if (newName == NULL) {
-                                               SCLog(TRUE, LOG_DEBUG,
-                                                     CFSTR("could not set unique name for \"%@\": %s\n"),
-                                                     SCNetworkInterfaceGetLocalizedDisplayName(interface),
-                                                     SCErrorString(SCError()));
-                                               SCNetworkServiceRemove(service);
-                                               CFRelease(service);
-                                               goto nextInterface;
-                                       }
-
-                                       ok = SCNetworkServiceSetName(service, newName);
-                                       CFRelease(newName);
-                                       if (ok) {
-                                               continue;
-                                       }
-
-                                       if (SCError() != kSCStatusKeyExists) {
-                                               SCLog(TRUE, LOG_DEBUG,
-                                                     CFSTR("could not set unique name for \"%@\": %s\n"),
-                                                     SCNetworkInterfaceGetLocalizedDisplayName(interface),
-                                                     SCErrorString(SCError()));
-                                               SCNetworkServiceRemove(service);
-                                               CFRelease(service);
-                                               goto nextInterface;
-                                       }
+                               ok = SCNetworkSetAddService(set, service);
+                               if (!ok) {
+                                       SC_log(LOG_ERR, "could not add service for \"%@\": %s",
+                                              SCNetworkInterfaceGetLocalizedDisplayName(interface),
+                                              SCErrorString(SCError()));
+                                       SCNetworkServiceRemove(service);
+                                       CFRelease(service);
+                                       goto nextInterface;
                                }
 
                                CFRelease(service);
@@ -1318,8 +2004,13 @@ __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CF
                }
                CFRelease(interface_list);
        }
+#if    !TARGET_OS_IPHONE
+       if (updatedIFs && (interfaces != NULL)) {
+               CFRelease(interfaces);
+       }
+#endif // !TARGET_OS_IPHONE
        if (services != NULL)   CFRelease(services);
-       if (excluded != NULL)   CFRelease(excluded);
+       CFRelease(excluded);
 
 #if    TARGET_OS_IPHONE
        if (orphans != NULL) {
@@ -1344,9 +2035,19 @@ __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CF
        }
 #endif // TARGET_OS_IPHONE
 
-       if (ok && !updated) {
-               // if no changes were made
-               _SCErrorSet(kSCStatusOK);
+       if (ok) {
+               if (updated) {
+                       CFStringRef     model;
+
+                       model = SCPreferencesGetValue(setPrivate->prefs, MODEL);
+                       if (model == NULL) {
+                               model = _SC_hw_model(FALSE);
+                               SCPreferencesSetValue(setPrivate->prefs, MODEL, model);
+                       }
+               } else {
+                       // if no changes were made
+                       _SCErrorSet(kSCStatusOK);
+               }
        }
 
        return updated;
@@ -1367,7 +2068,7 @@ SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set)
 
        interfaces = _SCNetworkInterfaceCopyAllWithPreferences(setPrivate->prefs);
        if (interfaces != NULL) {
-               updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
+               updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, TRUE);
                CFRelease(interfaces);
        }
 
@@ -1392,7 +2093,8 @@ SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set, SCNetwor
        }
 
        interfaces = CFArrayCreate(NULL, (const void **)&interface, 1, &kCFTypeArrayCallBacks);
-       updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
+       assert(interfaces != NULL);
+       updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, FALSE);
        CFRelease(interfaces);
 
        return updated;
@@ -1544,3 +2246,99 @@ SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set, SCNetworkServiceRef servi
        if (services != NULL) CFRelease(services);
        return ok;
 }
+
+
+Boolean
+_SCNetworkSetSetSetID(SCNetworkSetRef set, CFStringRef newSetID)
+{
+       SCNetworkSetRef         currentSet              = NULL;
+       SCNetworkSetPrivateRef  currentSetPrivate       = NULL;
+       CFDictionaryRef         entity;
+       CFStringRef             newPath;
+       Boolean                 ok                      = FALSE;
+       CFStringRef             oldPath                 = NULL;
+       SCNetworkSetPrivateRef  setPrivate              = (SCNetworkSetPrivateRef)set;
+       Boolean                 updateCurrentSet        = FALSE;
+
+       if (!isA_SCNetworkSet(set)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if (!isA_CFString(newSetID)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if (!__SCNetworkSetExists(set)) {
+               SC_log(LOG_ERR, "_SCNetworkSetSetSetID() w/removed set\n  set = %@\n  setID = %@",
+                      set,
+                      newSetID);
+               _SC_crash_once("_SCNetworkSetSetSetID() w/removed set", NULL, NULL);
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       // If newSetID is equal to current setID, our work is done
+       if (CFEqual(newSetID, setPrivate->setID)) {
+               return TRUE;
+       }
+
+       newPath = SCPreferencesPathKeyCreateSet(NULL, newSetID);
+       entity = SCPreferencesPathGetValue(setPrivate->prefs, newPath);
+       if (isA_CFDictionary(entity)) {
+               // if the new set already exists
+               _SCErrorSet(kSCStatusKeyExists);
+               goto done;
+       }
+
+       oldPath = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
+       entity = SCPreferencesPathGetValue(setPrivate->prefs, oldPath);
+       if (!isA_CFDictionary(entity)) {
+               // if the set has already been removed
+               _SCErrorSet(kSCStatusNoKey);
+               goto done;
+       }
+
+       ok = SCPreferencesPathSetValue(setPrivate->prefs, newPath, entity);
+       if (!ok) {
+               goto done;
+       }
+
+       ok = SCPreferencesPathRemoveValue(setPrivate->prefs, oldPath);
+       if (!ok) {
+               goto done;
+       }
+
+       // update current set (if needed)
+       currentSet = SCNetworkSetCopyCurrent(setPrivate->prefs);
+       if (currentSet != NULL) {
+               currentSetPrivate = (SCNetworkSetPrivateRef)currentSet;
+               if (CFEqual(currentSetPrivate->setID, setPrivate->setID)) {
+                       updateCurrentSet = TRUE;
+               }
+               CFRelease(currentSet);
+       }
+
+       SC_log(LOG_DEBUG, "_SCNetworkSetSetID(): %@ --> %@", set, newSetID);
+
+       // replace setID with new one
+       CFRetain(newSetID);
+       CFRelease(setPrivate->setID);
+       setPrivate->setID = newSetID;
+
+       if (updateCurrentSet) {
+               SCNetworkSetSetCurrent(set);
+       }
+
+    done:
+
+       if (oldPath != NULL) {
+               CFRelease(oldPath);
+       }
+       if (newPath != NULL) {
+               CFRelease(newPath);
+       }
+
+       return ok;
+}