/*
- * Copyright (c) 2004-2007, 2009 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,
* 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>
{
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;
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;
}
#pragma mark -
-static Boolean
-_serviceIsVPN(SCNetworkServiceRef service)
+static int
+_serviceOrder(SCNetworkServiceRef service)
{
SCNetworkInterfaceRef interface;
- CFStringRef interfaceType;
interface = SCNetworkServiceGetInterface(service);
- if (interface == NULL) {
- return FALSE;
- }
-
- interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
- if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
- interface = SCNetworkInterfaceGetInterface(interface);
- if (interface == NULL) {
- return FALSE;
- }
-
- interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
- if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
- return TRUE;
- }
- if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) {
- return TRUE;
- }
- return FALSE;
- }
- if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
- return TRUE;
+ if ((interface == NULL) || _SCNetworkServiceIsVPN(service)) {
+ return 100000; // if unknown or VPN interface, sort last
}
- return FALSE;
+ return __SCNetworkInterfaceOrder(interface);
}
-static int
-_serviceOrder(SCNetworkServiceRef service)
+static CFIndex
+_serviceOrder_clear(CFMutableArrayRef order, CFStringRef serviceID)
{
- SCNetworkInterfaceRef interface;
+ CFIndex f; // # of serviceID's found
+ CFIndex i;
+ CFIndex n;
- interface = SCNetworkServiceGetInterface(service);
- if ((interface == NULL) || _serviceIsVPN(service)) {
- return 100000; // if unknown or VPN interface, sort last
+ 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 __SCNetworkInterfaceOrder(interface);
+ 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;
} 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;
CFArrayInsertValueAtIndex(newOrder, slot, serviceID);
(void) SCNetworkSetSetServiceOrder(set, newOrder);
-
- done :
-
CFRelease(newOrder);
return;
static void
_serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service)
{
+ CFIndex n;
CFMutableArrayRef newOrder;
CFArrayRef order;
CFStringRef serviceID;
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);
#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)
{
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;
+ 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);
+ }
- 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;
- }
- }
- }
+ 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;
+ }
- CFRelease(services);
+ // 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);
+ if ((interface != NULL) &&
+ __SCNetworkInterfaceIsMember(servicePrivate->prefs, interface)) {
+ _SCErrorSet(kSCStatusKeyExists);
+ return FALSE;
}
-#endif // PREVENT_DUPLICATE_SERVICE_NAMES
//#define PREVENT_DUPLICATE_SETS
#ifdef PREVENT_DUPLICATE_SETS
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) {
done :
+ if (ok) {
+ SC_log(LOG_DEBUG, "SCNetworkSetAddService(): %@, %@", set, service);
+ }
+
if (interface_config != NULL) CFRelease(interface_config);
return ok;
}
}
setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
+ assert(setPrivate != NULL);
// mark set as "old" (already established)
setPrivate->established = TRUE;
}
-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)
{
services = SCNetworkSetCopyServices(set);
if (services != NULL) {
- found = _SCNetworkServiceExistsForInterface(services, interface);
+ found = __SCNetworkServiceExistsForInterface(services, interface);
CFRelease(services);
}
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;
}
+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)
{
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);
}
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
}
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);
}
SCNetworkSetCreate(SCPreferencesRef prefs)
{
CFArrayRef components;
+ CFDictionaryRef entity;
+ Boolean ok;
CFStringRef path;
CFStringRef prefix;
CFStringRef setID;
}
components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
- CFRelease(path);
-
setID = CFArrayGetValueAtIndex(components, 2);
setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
+ assert(setPrivate != NULL);
CFRelease(components);
// mark set as "new" (not yet established)
setPrivate->established = FALSE;
+ // establish the set in the preferences
+ entity = CFDictionaryCreate(NULL,
+ NULL, NULL, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ ok = SCPreferencesPathSetValue(prefs, path, entity);
+ CFRelease(path);
+ CFRelease(entity);
+ if (!ok) {
+ CFRelease(setPrivate);
+ setPrivate = NULL;
+ }
+
+ if (setPrivate != NULL) {
+ SC_log(LOG_DEBUG, "SCNetworkSetCreate(): %@", setPrivate);
+ }
+
return (SCNetworkSetRef)setPrivate;
}
-CFStringRef
-SCNetworkSetGetSetID(SCNetworkSetRef set)
+SCNetworkSetRef
+_SCNetworkSetCreateDefault(SCPreferencesRef prefs)
{
- SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
-
- if (!isA_SCNetworkSet(set)) {
- _SCErrorSet(kSCStatusInvalidArgument);
+ 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;
}
- return setPrivate->setID;
-}
-
+ // 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)
+{
+ SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
+
+ if (!isA_SCNetworkSet(set)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ return setPrivate->setID;
+}
+
CFStringRef
SCNetworkSetGetName(SCNetworkSetRef set)
{
- CFBundleRef bundle;
CFDictionaryRef entity;
CFStringRef path;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)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;
}
+#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)
{
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;
}
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);
// 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;
}
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;
}
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;
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;
// 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;
// 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;
}
}
done :
+ if (ok) {
+ SC_log(LOG_DEBUG, "SCNetworkSetSetName(): %@", set);
+ }
+
if (localized != NULL) CFRelease(localized);
if (non_localized != NULL) CFRelease(non_localized);
return ok;
Boolean
SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
{
+ CFMutableArrayRef cleanOrder;
CFDictionaryRef dict;
+ CFIndex i;
+ CFIndex n;
CFMutableDictionaryRef newDict;
Boolean ok;
CFStringRef path;
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;
&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);
#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)
{
}
-static CFStringRef
-next_service_name(SCNetworkServiceRef service)
+static CFSetRef /* of SCNetworkInterfaceRef's */
+copyExcludedInterfaces(SCPreferencesRef prefs)
{
- CFArrayRef components;
- CFIndex n;
- CFStringRef name;
- CFMutableArrayRef newComponents;
- SInt32 suffix = 2;
+ CFMutableSetRef excluded;
+ CFArrayRef interfaces;
- name = SCNetworkServiceGetName(service);
- if (name == NULL) {
- return NULL;
+ excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+
+#if !TARGET_OS_IPHONE
+ // exclude Bond [member] interfaces
+ interfaces = SCBondInterfaceCopyAll(prefs);
+ if (interfaces != NULL) {
+ __SCBondInterfaceListCollectMembers(interfaces, excluded);
+ CFRelease(interfaces);
}
+#endif // !TARGET_OS_IPHONE
- components = CFStringCreateArrayBySeparatingStrings(NULL, name, CFSTR(" "));
- if (components != NULL) {
- newComponents = CFArrayCreateMutableCopy(NULL, 0, components);
- CFRelease(components);
- } else {
- newComponents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- CFArrayAppendValue(newComponents, name);
+ // exclude Bridge [member] interfaces
+ interfaces = SCBridgeInterfaceCopyAll(prefs);
+ if (interfaces != NULL) {
+ __SCBridgeInterfaceListCollectMembers(interfaces, excluded);
+ CFRelease(interfaces);
}
- n = CFArrayGetCount(newComponents);
- if (n > 1) {
- CFStringRef str;
+ return excluded;
+}
- str = CFArrayGetValueAtIndex(newComponents, n - 1);
- suffix = CFStringGetIntValue(str);
- if (suffix++ > 0) {
- CFArrayRemoveValueAtIndex(newComponents, n - 1);
- } else {
- suffix = 2;
+
+#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);
}
- name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), suffix);
- CFArrayAppendValue(newComponents, name);
- CFRelease(name);
+ if (bridge == NULL) {
+ bridge = SCBridgeInterfaceCreate(prefs);
+ if (bridge != NULL) {
+ CFMutableDictionaryRef newOptions;
+ Boolean ok;
- name = CFStringCreateByCombiningStrings(NULL, newComponents, CFSTR(" "));
- CFRelease(newComponents);
+ newOptions = CFDictionaryCreateMutable(NULL, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFDictionarySetValue(newOptions, CFSTR("__AUTO__"), bridgeName);
+ ok = SCBridgeInterfaceSetOptions(bridge, newOptions);
+ CFRelease(newOptions);
+ if (!ok) {
+ CFRelease(bridge);
+ bridge = NULL;
+ }
+ }
+ }
- return name;
+ return bridge;
}
+#endif // !TARGET_OS_IPHONE
-static Boolean
-__SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces)
+static CFArrayRef
+copyServices(SCNetworkSetRef set)
{
- CFIndex i;
- CFIndex n;
- Boolean ok = TRUE;
CFArrayRef services;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
- Boolean updated = FALSE;
// first, assume that we only want to add new services
// for those interfaces that are not represented in the
services = SCNetworkServiceCopyAll(setPrivate->prefs);
}
- n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
+ 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, Boolean excludeHidden)
+{
+ 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;
+ CFArrayRef sets;
+
+ sets = SCNetworkSetCopyAll(setPrivate->prefs);
+ if (sets != NULL) {
+ if (CFArrayGetCount(sets) == 1) {
+ services = SCNetworkSetCopyServices(set);
+ if (services != NULL) {
+ n = CFArrayGetCount(services);
+ CFRelease(services);
+ }
+
+ if ((n == 0) && CFEqual(set, CFArrayGetValueAtIndex(sets, 0))) {
+ // after a "Reset Network Settings" we need to find (and
+ // add back) any VPN services that were orphaned.
+ orphans = SCNetworkServiceCopyAll(setPrivate->prefs);
+ }
+ }
+
+ CFRelease(sets);
+ }
+#endif // TARGET_OS_IPHONE
+
+ // copy network services
+ services = copyServices(set);
+
+ // copy network interfaces to be excluded
+ excluded = copyExcludedInterfaces(setPrivate->prefs);
+
+#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 (_SCNetworkServiceExistsForInterface(services, 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;
+ }
+
+ if (__SCNetworkServiceExistsForInterface(services, interface)) {
// if this is not a new interface
continue;
}
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 = next_service_name(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);
}
CFRelease(interface_list);
}
+#if !TARGET_OS_IPHONE
+ if (updatedIFs && (interfaces != NULL)) {
+ CFRelease(interfaces);
+ }
+#endif // !TARGET_OS_IPHONE
if (services != NULL) CFRelease(services);
+ CFRelease(excluded);
+
+#if TARGET_OS_IPHONE
+ if (orphans != NULL) {
+ if (ok && updated) {
+ CFIndex i;
+ CFIndex n = CFArrayGetCount(orphans);
+
+ for (i = 0; i < n; i++) {
+ SCNetworkServiceRef service;
- if (ok && !updated) {
- // if no changes were made
- _SCErrorSet(kSCStatusOK);
+ service = CFArrayGetValueAtIndex(orphans, i);
+ if (_SCNetworkServiceIsVPN(service)) {
+ ok = SCNetworkSetAddService(set, service);
+ if (!ok) {
+ break;
+ }
+ }
+ }
+ }
+
+ CFRelease(orphans);
+ }
+#endif // TARGET_OS_IPHONE
+
+ 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;
Boolean
SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set)
{
- CFArrayRef interfaces;
- Boolean updated;
+ CFArrayRef interfaces;
+ SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
+ Boolean updated = FALSE;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
- interfaces = SCNetworkInterfaceCopyAll();
- updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
- if (interfaces != NULL) CFRelease(interfaces);
+ interfaces = _SCNetworkInterfaceCopyAllWithPreferences(setPrivate->prefs);
+ if (interfaces != NULL) {
+ updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, TRUE);
+ CFRelease(interfaces);
+ }
return updated;
}
Boolean
SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
{
- CFMutableArrayRef interfaces;
- Boolean updated;
+ CFArrayRef interfaces;
+ Boolean updated;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
- interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- CFArrayAppendValue(interfaces, interface);
- updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
+ interfaces = CFArrayCreate(NULL, (const void **)&interface, 1, &kCFTypeArrayCallBacks);
+ assert(interfaces != NULL);
+ updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, FALSE);
CFRelease(interfaces);
return updated;
}
+
+
+SCNetworkServiceRef
+SCNetworkSetCopySelectedVPNService(SCNetworkSetRef set)
+{
+ CFIndex i;
+ CFIndex n;
+ SCNetworkServiceRef selected = NULL;
+ CFArrayRef services;
+ CFMutableArrayRef services_vpn = NULL;
+
+ if (!isA_SCNetworkSet(set)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ services = SCNetworkSetCopyServices(set);
+ if (services != NULL) {
+ n = CFArrayGetCount(services);
+ for (i = 0; i < n; i++) {
+ SCNetworkServiceRef service;
+
+ service = CFArrayGetValueAtIndex(services, i);
+ if (!SCNetworkServiceGetEnabled(service)) {
+ // if not enabled
+ continue;
+ }
+
+ if (!_SCNetworkServiceIsVPN(service)) {
+ // if not VPN service
+ continue;
+ }
+
+ if (services_vpn == NULL) {
+ services_vpn = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+ CFArrayAppendValue(services_vpn, service);
+ }
+
+ CFRelease(services);
+ }
+
+ if (services_vpn == NULL) {
+ // if no VPN services
+ return NULL;
+ }
+
+ n = CFArrayGetCount(services_vpn);
+ if (n > 1) {
+ CFArrayRef order;
+ CFMutableArrayRef sorted;
+
+ order = SCNetworkSetGetServiceOrder(set);
+ sorted = CFArrayCreateMutableCopy(NULL, 0, services_vpn);
+ CFArraySortValues(sorted,
+ CFRangeMake(0, CFArrayGetCount(sorted)),
+ _SCNetworkServiceCompare,
+ (void *)order);
+ CFRelease(services_vpn);
+ services_vpn = sorted;
+ }
+
+#if TARGET_OS_IPHONE
+ if (n > 1) {
+ CFStringRef serviceID_prefs;
+
+#define VPN_PREFERENCES CFSTR("com.apple.mobilevpn")
+#define VPN_SERVICE_ID CFSTR("activeVPNID")
+
+ CFPreferencesAppSynchronize(VPN_PREFERENCES);
+ serviceID_prefs = CFPreferencesCopyAppValue(VPN_SERVICE_ID, VPN_PREFERENCES);
+ if (serviceID_prefs != NULL) {
+ for (i = 0; i < n; i++) {
+ SCNetworkServiceRef service;
+ CFStringRef serviceID;
+
+ service = CFArrayGetValueAtIndex(services_vpn, i);
+ serviceID = SCNetworkServiceGetServiceID(service);
+ if (CFEqual(serviceID, serviceID_prefs)) {
+ selected = service;
+ CFRetain(selected);
+ break;
+ }
+
+ }
+
+ CFRelease(serviceID_prefs);
+ }
+ }
+#endif // TARGET_OS_IPHONE
+
+ if (selected == NULL) {
+ selected = CFArrayGetValueAtIndex(services_vpn, 0);
+ CFRetain(selected);
+ }
+
+ CFRelease(services_vpn);
+ return selected;
+}
+
+
+Boolean
+SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set, SCNetworkServiceRef service)
+{
+ Boolean ok = TRUE;
+ CFArrayRef services;
+
+ if (!isA_SCNetworkSet(set)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (!isA_SCNetworkService(service) || !_SCNetworkServiceIsVPN(service)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ services = SCNetworkSetCopyServices(set);
+ if (services != NULL) {
+ CFIndex i;
+ CFIndex n = CFArrayGetCount(services);
+
+ if (!CFArrayContainsValue(services, CFRangeMake(0, n), service)) {
+ // if selected service not a member of the current set
+ _SCErrorSet(kSCStatusInvalidArgument);
+ ok = FALSE;
+ goto done;
+ }
+
+ for (i = 0; ok && (i < n); i++) {
+ SCNetworkServiceRef vpn;
+
+ vpn = CFArrayGetValueAtIndex(services, i);
+ if (!_SCNetworkServiceIsVPN(vpn)) {
+ // if not VPN service
+ continue;
+ }
+
+ ok = SCNetworkServiceSetEnabled(vpn, CFEqual(service, vpn));
+ }
+ }
+
+ done :
+
+ 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;
+}