/*
- * 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;
NULL, // copy
__SCNetworkSetDeallocate, // dealloc
__SCNetworkSetEqual, // equal
- NULL, // hash
+ __SCNetworkSetHash, // hash
NULL, // copyFormattingDesc
__SCNetworkSetCopyDescription // copyDebugDesc
};
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)
{
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;
}
{
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;
}
}
+static CFHashCode
+__SCNetworkSetHash(CFTypeRef cf)
+{
+ SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
+
+ return CFHash(setPrivate->setID);
+}
+
+
static void
__SCNetworkSetInitialize(void)
{
/* initialize runtime */
pthread_once(&initialized, __SCNetworkSetInitialize);
- SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCNetworkSetCreatePrivate:"));
-
/* allocate target */
size = sizeof(SCNetworkSetPrivate) - sizeof(CFRuntimeBase);
setPrivate = (SCNetworkSetPrivateRef)_CFRuntimeCreateInstance(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
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;
CFRelease(path);
CFRelease(link);
if (!ok) {
- return ok;
+ goto done;
}
// push the [deep] interface configuration into all sets which contain this service.
__SCNetworkInterfaceSetDeepConfiguration(interface, interface_config);
}
+ // add service to ServiceOrder
+ _serviceOrder_add(set, service);
+
+ done :
+
+ if (interface_config != NULL) CFRelease(interface_config);
return ok;
}
CFStringRef path;
SCNetworkSetPrivateRef setPrivate;
+ if (!isA_CFString(setID)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
path = SCPreferencesPathKeyCreateSet(NULL, setID);
entity = SCPreferencesPathGetValue(prefs, path);
CFRelease(path);
}
-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;
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);
SCNetworkServicePrivateRef servicePrivate;
servicePrivate = __SCNetworkServiceCreatePrivate(NULL,
+ setPrivate->prefs,
serviceID,
- NULL,
- setPrivate->prefs);
+ NULL);
CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
CFRelease(servicePrivate);
}
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;
{
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
+ if (!isA_SCNetworkSet(set)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
return setPrivate->setID;
}
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;
}
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;
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)) {
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) {
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);
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
// if "name" not unique
CFRelease(sets);
_SCErrorSet(kSCStatusKeyExists);
- return FALSE;
+ goto done;
}
}
CFRelease(sets);
}
#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);
CFMutableDictionaryRef newEntity;
newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
- if (isA_CFString(name)) {
+ if (name != NULL) {
CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name);
} else {
CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
}
CFRelease(path);
+ done :
+
+ if (localized != NULL) CFRelease(localized);
+ if (non_localized != NULL) CFRelease(non_localized);
return ok;
}
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;
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;
+}