+ 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;