2 * Copyright (c) 2004-2021 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * May 13, 2004 Allan Nathanson <ajn@apple.com>
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFRuntime.h>
34 #include "SCNetworkConfigurationInternal.h"
39 static CFStringRef
__SCNetworkSetCopyDescription (CFTypeRef cf
);
40 static void __SCNetworkSetDeallocate (CFTypeRef cf
);
41 static Boolean
__SCNetworkSetEqual (CFTypeRef cf1
, CFTypeRef cf2
);
42 static CFHashCode
__SCNetworkSetHash (CFTypeRef cf
);
45 static CFTypeID __kSCNetworkSetTypeID
= _kCFRuntimeNotATypeID
;
48 static const CFRuntimeClass __SCNetworkSetClass
= {
50 "SCNetworkSet", // className
53 __SCNetworkSetDeallocate
, // dealloc
54 __SCNetworkSetEqual
, // equal
55 __SCNetworkSetHash
, // hash
56 NULL
, // copyFormattingDesc
57 __SCNetworkSetCopyDescription
// copyDebugDesc
61 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
65 __SCNetworkSetCopyDescription(CFTypeRef cf
)
67 CFAllocatorRef allocator
= CFGetAllocator(cf
);
68 CFMutableStringRef result
;
69 SCNetworkSetRef set
= (SCNetworkSetRef
)cf
;
70 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
72 result
= CFStringCreateMutable(allocator
, 0);
73 CFStringAppendFormat(result
, NULL
, CFSTR("<SCNetworkSet %p [%p]> {"), set
, allocator
);
74 CFStringAppendFormat(result
, NULL
, CFSTR("id = %@"), setPrivate
->setID
);
75 CFStringAppendFormat(result
, NULL
, CFSTR(", prefs = %p"), setPrivate
->prefs
);
76 if (setPrivate
->name
!= NULL
) {
77 CFStringAppendFormat(result
, NULL
, CFSTR(", name = %@"), setPrivate
->name
);
79 if (setPrivate
->established
) {
80 CFStringAppendFormat(result
, NULL
, CFSTR(", new"));
82 if (!__SCNetworkSetExists(set
)) {
83 CFStringAppendFormat(result
, NULL
, CFSTR(", REMOVED"));
85 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
92 __SCNetworkSetDeallocate(CFTypeRef cf
)
94 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)cf
;
96 /* release resources */
98 CFRelease(setPrivate
->setID
);
99 CFRelease(setPrivate
->prefs
);
100 if (setPrivate
->name
!= NULL
)
101 CFRelease(setPrivate
->name
);
108 __SCNetworkSetEqual(CFTypeRef cf1
, CFTypeRef cf2
)
110 SCNetworkSetPrivateRef s1
= (SCNetworkSetPrivateRef
)cf1
;
111 SCNetworkSetPrivateRef s2
= (SCNetworkSetPrivateRef
)cf2
;
116 if (s1
->prefs
!= s2
->prefs
)
117 return FALSE
; // if not the same prefs
119 if (!CFEqual(s1
->setID
, s2
->setID
))
120 return FALSE
; // if not the same set identifier
127 __SCNetworkSetHash(CFTypeRef cf
)
129 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)cf
;
131 return CFHash(setPrivate
->setID
);
136 __SCNetworkSetInitialize(void)
138 __kSCNetworkSetTypeID
= _CFRuntimeRegisterClass(&__SCNetworkSetClass
);
143 static SCNetworkSetPrivateRef
144 __SCNetworkSetCreatePrivate(CFAllocatorRef allocator
,
145 SCPreferencesRef prefs
,
148 SCNetworkSetPrivateRef setPrivate
;
151 /* initialize runtime */
152 pthread_once(&initialized
, __SCNetworkSetInitialize
);
154 /* allocate target */
155 size
= sizeof(SCNetworkSetPrivate
) - sizeof(CFRuntimeBase
);
156 setPrivate
= (SCNetworkSetPrivateRef
)_CFRuntimeCreateInstance(allocator
,
157 __kSCNetworkSetTypeID
,
160 if (setPrivate
== NULL
) {
164 /* initialize non-zero/NULL members */
165 setPrivate
->setID
= CFStringCreateCopy(NULL
, setID
);
166 setPrivate
->prefs
= CFRetain(prefs
);
176 _serviceOrder(SCNetworkServiceRef service
)
178 SCNetworkInterfaceRef interface
;
180 interface
= SCNetworkServiceGetInterface(service
);
181 if ((interface
== NULL
) || _SCNetworkServiceIsVPN(service
)) {
182 return 100000; // if unknown or VPN interface, sort last
185 return __SCNetworkInterfaceOrder(interface
);
190 _serviceOrder_clear(CFMutableArrayRef order
, CFStringRef serviceID
)
192 CFIndex f
; // # of serviceID's found
198 n
= CFArrayGetCount(order
);
200 CFStringRef thisServiceID
= CFArrayGetValueAtIndex(order
, i
);
202 if (CFEqual(thisServiceID
, serviceID
)) {
203 // remove the serviceID
204 CFArrayRemoveValueAtIndex(order
, i
);
210 i
++; // move to the next serviceID
218 _serviceOrder_add(SCNetworkSetRef set
, SCNetworkServiceRef service
)
221 CFMutableArrayRef newOrder
;
224 CFStringRef serviceID
= SCNetworkServiceGetServiceID(service
);
225 CFIndex serviceOrder
= _serviceOrder(service
);
226 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
228 order
= SCNetworkSetGetServiceOrder(set
);
230 newOrder
= CFArrayCreateMutableCopy(NULL
, 0, order
);
232 newOrder
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
234 assert(newOrder
!= NULL
);
236 n
= _serviceOrder_clear(newOrder
, serviceID
);
238 SC_log(LOG_ERR
, "SCNetworkSetAddService() w/service already in ServiceOrder\n service = %@\n matched = %ld",
241 _SC_crash_once("SCNetworkSetAddService() w/service already in ServiceOrder", NULL
, NULL
);
245 n
= CFArrayGetCount(newOrder
);
246 for (CFIndex i
= 0; i
< n
; i
++) {
248 SCNetworkServiceRef slotService
;
249 CFStringRef slotServiceID
;
251 slotServiceID
= CFArrayGetValueAtIndex(newOrder
, i
);
252 if (!isA_CFString(slotServiceID
)) {
257 slotService
= SCNetworkServiceCopy(setPrivate
->prefs
, slotServiceID
);
258 if (slotService
== NULL
) {
259 // if serviceID not valid
263 slotOrder
= _serviceOrder(slotService
);
264 if (serviceOrder
>= slotOrder
) {
265 // add the service *after* this one
269 CFRelease(slotService
);
272 CFArrayInsertValueAtIndex(newOrder
, newSlot
, serviceID
);
273 (void) SCNetworkSetSetServiceOrder(set
, newOrder
);
281 _serviceOrder_remove(SCNetworkSetRef set
, SCNetworkServiceRef service
)
284 CFMutableArrayRef newOrder
;
286 CFStringRef serviceID
;
288 order
= SCNetworkSetGetServiceOrder(set
);
292 newOrder
= CFArrayCreateMutableCopy(NULL
, 0, order
);
294 serviceID
= SCNetworkServiceGetServiceID(service
);
296 n
= _serviceOrder_clear(newOrder
, serviceID
);
298 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/multiple instances of service in ServiceOrder\n service = %@\n count = %ld",
303 (void) SCNetworkSetSetServiceOrder(set
, newOrder
);
311 #pragma mark SCNetworkSet APIs
314 #define DEFAULT_SET_NAME CFSTR("Automatic")
319 copy_default_set_name(Boolean loc
)
322 static CFStringRef non_localized
= NULL
;
323 static CFStringRef localized
= NULL
;
326 static dispatch_once_t once
;
328 dispatch_once(&once
, ^{
331 bundle
= _SC_CFBundleGet();
332 if (bundle
!= NULL
) {
333 non_localized
= _SC_CFBundleCopyNonLocalizedString(bundle
,
334 CFSTR("DEFAULT_SET_NAME"),
339 name
= non_localized
;
341 static dispatch_once_t once
;
343 dispatch_once(&once
, ^{
346 bundle
= _SC_CFBundleGet();
347 if (bundle
!= NULL
) {
348 localized
= CFBundleCopyLocalizedString(bundle
,
349 CFSTR("DEFAULT_SET_NAME"),
358 // if bundle or localized names not available
359 name
= DEFAULT_SET_NAME
;
367 #define PREVENT_DUPLICATE_SERVICE_NAMES
368 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
370 copy_next_name(CFStringRef name
)
372 CFArrayRef components
;
374 CFMutableArrayRef newComponents
;
381 components
= CFStringCreateArrayBySeparatingStrings(NULL
, name
, CFSTR(" "));
382 if (components
!= NULL
) {
383 newComponents
= CFArrayCreateMutableCopy(NULL
, 0, components
);
384 CFRelease(components
);
386 newComponents
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
387 CFArrayAppendValue(newComponents
, name
);
390 n
= CFArrayGetCount(newComponents
);
394 str
= CFArrayGetValueAtIndex(newComponents
, n
- 1);
395 suffix
= CFStringGetIntValue(str
);
397 CFArrayRemoveValueAtIndex(newComponents
, n
- 1);
403 name
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), (int)suffix
);
404 CFArrayAppendValue(newComponents
, name
);
407 name
= CFStringCreateByCombiningStrings(NULL
, newComponents
, CFSTR(" "));
408 CFRelease(newComponents
);
415 ensure_unique_service_name(SCNetworkServiceRef service
)
417 SCNetworkInterfaceRef interface
;
421 interface
= SCNetworkServiceGetInterface(service
);
423 name
= SCNetworkServiceGetName(service
);
431 ok
= SCNetworkServiceSetName(service
, name
);
436 if (SCError() != kSCStatusKeyExists
) {
437 SC_log(LOG_INFO
, "could not update service name for \"%@\": %s",
438 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
439 SCErrorString(SCError()));
443 newName
= copy_next_name(name
);
444 if (newName
== NULL
) {
445 SC_log(LOG_INFO
, "could not create unique name for \"%@\": %s",
446 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
447 SCErrorString(SCError()));
451 // try again with the "new" name
464 #endif // PREVENT_DUPLICATE_SERVICE_NAMES
468 SCNetworkSetAddService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
470 SCNetworkInterfaceRef interface
;
471 CFArrayRef interface_config
= NULL
;
475 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
476 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
478 if (!isA_SCNetworkSet(set
)) {
479 _SCErrorSet(kSCStatusInvalidArgument
);
483 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
484 _SCErrorSet(kSCStatusInvalidArgument
);
488 if (!__SCNetworkSetExists(set
)) {
489 SC_log(LOG_ERR
, "SCNetworkSetAddService() w/removed set\n set = %@\n service = %@",
492 _SC_crash_once("SCNetworkSetAddService() w/removed set", NULL
, NULL
);
493 _SCErrorSet(kSCStatusInvalidArgument
);
497 if (!__SCNetworkServiceExists(service
)) {
498 SC_log(LOG_ERR
, "SCNetworkSetAddService() w/removed service\n set = %@\n service = %@",
501 _SC_crash_once("SCNetworkSetAddService() w/removed service", NULL
, NULL
);
502 _SCErrorSet(kSCStatusInvalidArgument
);
506 // make sure that we do not add an orphaned network service if its
507 // associated interface is a member of a bond or bridge.
508 interface
= SCNetworkServiceGetInterface(service
);
509 if ((interface
!= NULL
) &&
510 __SCNetworkInterfaceIsMember(servicePrivate
->prefs
, interface
)) {
511 _SCErrorSet(kSCStatusKeyExists
);
515 //#define PREVENT_DUPLICATE_SETS
516 #ifdef PREVENT_DUPLICATE_SETS
519 // ensure that each service is only a member of ONE set
520 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
525 n
= CFArrayGetCount(sets
);
526 for (i
= 0; i
< n
; i
++) {
531 set
= CFArrayGetValueAtIndex(sets
, i
);
532 services
= SCNetworkSetCopyServices(set
);
533 found
= CFArrayContainsValue(services
,
534 CFRangeMake(0, CFArrayGetCount(services
)),
540 _SCErrorSet(kSCStatusKeyExists
);
546 #endif /* PREVENT_DUPLICATE_SETS */
548 // get the [deep] interface configuration settings
549 interface
= SCNetworkServiceGetInterface(service
);
550 if (interface
!= NULL
) {
551 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(set
, interface
);
554 // create the link between "set" and the "service"
555 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
, // allocator
556 setPrivate
->setID
, // set
557 servicePrivate
->serviceID
, // service
559 link
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
560 servicePrivate
->serviceID
, // service
562 ok
= SCPreferencesPathSetLink(setPrivate
->prefs
, path
, link
);
563 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
565 // We use the interface cache here to not reach into the
566 // IORegistry for every service we go through
567 _SCNetworkInterfaceCacheOpen();
568 ok
= ensure_unique_service_name(service
);
569 _SCNetworkInterfaceCacheClose();
572 // if we could not ensure a unique name, remove the (just added)
573 // link between the "set" and the "service"
574 (void) SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
577 #endif // PREVENT_DUPLICATE_SERVICE_NAMES
584 // push the [deep] interface configuration into all sets which contain this service.
585 if (interface
!= NULL
) {
586 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, interface_config
);
589 // add service to ServiceOrder
590 _serviceOrder_add(set
, service
);
592 // mark set as no longer "new"
593 setPrivate
->established
= TRUE
;
598 SC_log(LOG_DEBUG
, "SCNetworkSetAddService(): %@, %@", set
, service
);
601 if (interface_config
!= NULL
) CFRelease(interface_config
);
607 SCNetworkSetCopy(SCPreferencesRef prefs
, CFStringRef setID
)
609 CFDictionaryRef entity
;
611 SCNetworkSetPrivateRef setPrivate
;
613 if (!isA_CFString(setID
)) {
614 _SCErrorSet(kSCStatusInvalidArgument
);
618 path
= SCPreferencesPathKeyCreateSet(NULL
, setID
);
619 entity
= SCPreferencesPathGetValue(prefs
, path
);
622 if (!isA_CFDictionary(entity
)) {
623 _SCErrorSet(kSCStatusNoKey
);
627 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
628 assert(setPrivate
!= NULL
);
630 // mark set as "old" (already established)
631 setPrivate
->established
= TRUE
;
633 return (SCNetworkSetRef
)setPrivate
;
638 SCNetworkSetContainsInterface(SCNetworkSetRef set
, SCNetworkInterfaceRef interface
)
640 Boolean found
= FALSE
;
643 services
= SCNetworkSetCopyServices(set
);
644 if (services
!= NULL
) {
645 found
= __SCNetworkServiceExistsForInterface(services
, interface
);
653 CFArrayRef
/* of SCNetworkSetRef's */
654 SCNetworkSetCopyAll(SCPreferencesRef prefs
)
656 CFMutableArrayRef array
;
659 CFDictionaryRef sets
;
661 path
= SCPreferencesPathKeyCreateSets(NULL
);
662 sets
= SCPreferencesPathGetValue(prefs
, path
);
665 if ((sets
!= NULL
) && !isA_CFDictionary(sets
)) {
669 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
671 n
= (sets
!= NULL
) ? CFDictionaryGetCount(sets
) : 0;
674 const void * keys_q
[N_QUICK
];
675 const void ** keys
= keys_q
;
676 const void * vals_q
[N_QUICK
];
677 const void ** vals
= vals_q
;
679 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
680 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
681 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
683 CFDictionaryGetKeysAndValues(sets
, keys
, vals
);
684 for (i
= 0; i
< n
; i
++) {
685 SCNetworkSetPrivateRef setPrivate
;
687 if (!isA_CFDictionary(vals
[i
])) {
688 SC_log(LOG_INFO
, "error w/set \"%@\"", keys
[i
]);
692 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, keys
[i
]);
693 assert(setPrivate
!= NULL
);
695 // mark set as "old" (already established)
696 setPrivate
->established
= TRUE
;
698 CFArrayAppendValue(array
, (SCNetworkSetRef
)setPrivate
);
699 CFRelease(setPrivate
);
701 if (keys
!= keys_q
) {
702 CFAllocatorDeallocate(NULL
, keys
);
703 CFAllocatorDeallocate(NULL
, vals
);
711 CFArrayRef
/* of SCNetworkInterfaceRef's */
712 SCNetworkSetCopyAvailableInterfaces(SCNetworkSetRef set
)
714 CFMutableArrayRef available
;
715 CFMutableSetRef excluded
= NULL
;
717 CFArrayRef interfaces
;
718 CFIndex n_interfaces
;
719 CFIndex n_exclusions
= 0;
720 SCPreferencesRef prefs
;
721 SCNetworkSetPrivateRef setPrivate
;
723 setPrivate
= (SCNetworkSetPrivateRef
)set
;
724 prefs
= setPrivate
->prefs
;
726 interfaces
= _SCNetworkInterfaceCopyAllWithPreferences(prefs
);
727 n_interfaces
= CFArrayGetCount(interfaces
);
728 if (n_interfaces
== 0) {
733 CFArrayRef bridges
= NULL
;
735 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
737 #if !TARGET_OS_IPHONE
738 CFArrayRef bonds
= NULL
;
740 bonds
= SCBondInterfaceCopyAll(prefs
);
742 __SCBondInterfaceListCollectMembers(bonds
, excluded
);
745 #endif /* !TARGET_OS_IPHONE */
747 bridges
= SCBridgeInterfaceCopyAll(prefs
);
748 if (bridges
!= NULL
) {
749 __SCBridgeInterfaceListCollectMembers(bridges
, excluded
);
753 n_exclusions
= CFSetGetCount(excluded
);
756 if (n_exclusions
== 0) {
757 if (excluded
!= NULL
) {
764 available
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
766 for (i
= 0; i
< n_interfaces
; i
++) {
767 SCNetworkInterfaceRef interface
;
769 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
770 if (CFSetContainsValue(excluded
, interface
)) {
775 CFArrayAppendValue(available
, interface
);
778 CFRelease(interfaces
);
786 SCNetworkSetCopyCurrent(SCPreferencesRef prefs
)
788 CFArrayRef components
;
789 CFStringRef currentID
;
790 SCNetworkSetPrivateRef setPrivate
= NULL
;
792 currentID
= SCPreferencesGetValue(prefs
, kSCPrefCurrentSet
);
793 if (!isA_CFString(currentID
)) {
797 components
= CFStringCreateArrayBySeparatingStrings(NULL
, currentID
, CFSTR("/"));
798 if (CFArrayGetCount(components
) == 3) {
802 setID
= CFArrayGetValueAtIndex(components
, 2);
803 path
= SCPreferencesPathKeyCreateSet(NULL
, setID
);
804 if (CFEqual(path
, currentID
)) {
805 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
806 assert(setPrivate
!= NULL
);
808 // mark set as "old" (already established)
809 setPrivate
->established
= TRUE
;
811 SC_log(LOG_NOTICE
, "SCNetworkSetCopyCurrent(): preferences are non-conformant");
815 CFRelease(components
);
817 return (SCNetworkSetRef
)setPrivate
;
821 CFArrayRef
/* of SCNetworkServiceRef's */
822 SCNetworkSetCopyServices(SCNetworkSetRef set
)
824 CFMutableArrayRef array
;
825 CFDictionaryRef dict
;
828 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
830 if (!isA_SCNetworkSet(set
)) {
831 _SCErrorSet(kSCStatusInvalidArgument
);
836 path
= SCPreferencesPathKeyCreateSetNetworkService(NULL
, setPrivate
->setID
, NULL
);
837 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
839 if ((dict
!= NULL
) && !isA_CFDictionary(dict
)) {
843 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
845 n
= (dict
!= NULL
) ? CFDictionaryGetCount(dict
) : 0;
848 const void * keys_q
[N_QUICK
];
849 const void ** keys
= keys_q
;
851 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
852 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
854 CFDictionaryGetKeysAndValues(dict
, keys
, NULL
);
855 for (i
= 0; i
< n
; i
++) {
856 CFArrayRef components
;
859 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
861 (CFStringRef
)keys
[i
],
863 link
= SCPreferencesPathGetLink(setPrivate
->prefs
, path
);
866 SC_log(LOG_INFO
, "service \"%@\" for set \"%@\" is not a link",
869 continue; // if the service is not a link
871 if (SCPreferencesPathGetValue(setPrivate
->prefs
, link
) == NULL
) {
872 SC_log(LOG_INFO
, "service \"%@\" for set \"%@\" broken link \"%@\"",
876 continue; // the link is broken
878 components
= CFStringCreateArrayBySeparatingStrings(NULL
, link
, CFSTR("/"));
879 if (CFArrayGetCount(components
) == 3) {
880 CFStringRef serviceID
;
882 serviceID
= CFArrayGetValueAtIndex(components
, 2);
883 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
884 serviceID
, // service
886 if (CFEqual(path
, link
)) {
887 CFDictionaryRef entity
;
888 CFStringRef interfacePath
;
889 Boolean skip
= FALSE
;
891 interfacePath
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
892 serviceID
, // service
893 kSCEntNetInterface
); // entity
894 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, interfacePath
);
895 CFRelease(interfacePath
);
897 if (__SCNetworkInterfaceEntityIsPPTP(entity
)) {
898 SC_log(LOG_INFO
, "PPTP services are no longer supported");
903 SCNetworkServicePrivateRef servicePrivate
;
905 servicePrivate
= __SCNetworkServiceCreatePrivate(NULL
,
909 CFArrayAppendValue(array
, (SCNetworkServiceRef
)servicePrivate
);
910 CFRelease(servicePrivate
);
915 CFRelease(components
);
917 if (keys
!= keys_q
) {
918 CFAllocatorDeallocate(NULL
, keys
);
927 SCNetworkSetCreate(SCPreferencesRef prefs
)
929 CFArrayRef components
;
930 CFDictionaryRef entity
;
935 SCNetworkSetPrivateRef setPrivate
;
937 prefix
= SCPreferencesPathKeyCreateSets(NULL
);
938 path
= __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs
, prefix
);
939 if (path
== NULL
) path
= SCPreferencesPathCreateUniqueChild(prefs
, prefix
);
945 components
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
946 setID
= CFArrayGetValueAtIndex(components
, 2);
947 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
948 assert(setPrivate
!= NULL
);
949 CFRelease(components
);
951 // mark set as "new" (not yet established)
952 setPrivate
->established
= FALSE
;
954 // establish the set in the preferences
955 entity
= CFDictionaryCreate(NULL
,
957 &kCFTypeDictionaryKeyCallBacks
,
958 &kCFTypeDictionaryValueCallBacks
);
959 ok
= SCPreferencesPathSetValue(prefs
, path
, entity
);
963 CFRelease(setPrivate
);
967 if (setPrivate
!= NULL
) {
968 SC_log(LOG_DEBUG
, "SCNetworkSetCreate(): %@", setPrivate
);
971 return (SCNetworkSetRef
)setPrivate
;
976 _SCNetworkSetCreateDefault(SCPreferencesRef prefs
)
981 CFStringRef setName
= NULL
;
984 set
= SCNetworkSetCopyCurrent(prefs
);
986 SC_log(LOG_NOTICE
, "creating default set w/already existing set");
988 _SCErrorSet(kSCStatusKeyExists
);
992 // create a new ("Automatic") set
993 set
= SCNetworkSetCreate(prefs
);
995 SC_log(LOG_NOTICE
, "could not create \"new\" set: %s",
996 SCErrorString(SCError()));
1000 setName
= copy_default_set_name(TRUE
);
1001 ok
= SCNetworkSetSetName(set
, setName
);
1004 // if we could not save the new set's "name"
1005 SC_log(LOG_NOTICE
, "could not save the new set's name: %s",
1006 SCErrorString(SCError()));
1010 ok
= SCNetworkSetSetCurrent(set
);
1012 // if we could not make this the "current" set
1013 SC_log(LOG_NOTICE
, "could not establish new set as current: %s",
1014 SCErrorString(SCError()));
1018 model
= SCPreferencesGetValue(prefs
, MODEL
);
1019 if (model
== NULL
) {
1020 model
= _SC_hw_model(FALSE
);
1021 SCPreferencesSetValue(prefs
, MODEL
, model
);
1024 version
= SCPreferencesGetValue(prefs
, kSCPrefVersion
);
1025 if (version
== NULL
) {
1026 const int new_version
= NETWORK_CONFIGURATION_VERSION
;
1028 version
= CFNumberCreate(NULL
, kCFNumberIntType
, &new_version
);
1029 SCPreferencesSetValue(prefs
, kSCPrefVersion
, version
);
1035 if (!ok
&& (set
!= NULL
)) {
1036 SCNetworkSetRemove(set
);
1045 SCNetworkSetGetSetID(SCNetworkSetRef set
)
1047 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1049 if (!isA_SCNetworkSet(set
)) {
1050 _SCErrorSet(kSCStatusInvalidArgument
);
1054 return setPrivate
->setID
;
1059 SCNetworkSetGetName(SCNetworkSetRef set
)
1061 CFDictionaryRef entity
;
1063 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1065 if (!isA_SCNetworkSet(set
)) {
1066 _SCErrorSet(kSCStatusInvalidArgument
);
1070 if (setPrivate
->name
!= NULL
) {
1071 return setPrivate
->name
;
1074 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1075 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1078 if (isA_CFDictionary(entity
)) {
1081 name
= CFDictionaryGetValue(entity
, kSCPropUserDefinedName
);
1082 if (isA_CFString(name
)) {
1083 setPrivate
->name
= CFRetain(name
);
1087 if (setPrivate
->name
!= NULL
) {
1088 CFStringRef non_localized
;
1090 non_localized
= copy_default_set_name(FALSE
);
1091 if (CFEqual(setPrivate
->name
, non_localized
)) {
1092 CFStringRef localized
;
1094 // if "Automatic", return localized name
1095 localized
= copy_default_set_name(TRUE
);
1096 CFRelease(setPrivate
->name
);
1097 setPrivate
->name
= localized
;
1100 CFRelease(non_localized
);
1103 return setPrivate
->name
;
1107 CFArrayRef
/* of serviceID CFStringRef's */
1108 SCNetworkSetGetServiceOrder(SCNetworkSetRef set
)
1110 CFDictionaryRef dict
;
1112 CFArrayRef serviceOrder
;
1113 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1115 if (!isA_SCNetworkSet(set
)) {
1116 _SCErrorSet(kSCStatusInvalidArgument
);
1120 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1125 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1127 if (!isA_CFDictionary(dict
)) {
1131 serviceOrder
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
);
1132 serviceOrder
= isA_CFArray(serviceOrder
);
1134 return serviceOrder
;
1139 SCNetworkSetGetTypeID(void)
1141 pthread_once(&initialized
, __SCNetworkSetInitialize
); /* initialize runtime */
1142 return __kSCNetworkSetTypeID
;
1146 #if TARGET_OS_IPHONE
1148 isDefaultSet(SCNetworkSetRef set
)
1150 CFStringRef defaultName
;
1151 Boolean isDefault
= FALSE
;
1152 CFStringRef setName
;
1154 defaultName
= copy_default_set_name(TRUE
);
1155 setName
= SCNetworkSetGetName(set
);
1156 isDefault
= _SC_CFEqual(setName
, defaultName
);
1157 CFRelease(defaultName
);
1161 #endif // TARGET_OS_IPHONE
1165 SCNetworkSetRemove(SCNetworkSetRef set
)
1167 CFStringRef currentPath
;
1170 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1172 if (!isA_SCNetworkSet(set
)) {
1173 _SCErrorSet(kSCStatusInvalidArgument
);
1177 if (!__SCNetworkSetExists(set
)) {
1178 SC_log(LOG_ERR
, "SCNetworkSetRemove() w/removed set\n set = %@", set
);
1179 _SC_crash_once("SCNetworkSetRemove() w/removed set", NULL
, NULL
);
1180 _SCErrorSet(kSCStatusInvalidArgument
);
1184 #if TARGET_OS_IPHONE
1185 if (isDefaultSet(set
) && (geteuid() != 0)) {
1186 SC_log(LOG_ERR
, "SCNetworkSetRemove() failed, cannot remove set : %@", set
);
1187 _SC_crash("The \"Automatic\" network set cannot be removed", NULL
, NULL
);
1188 _SCErrorSet(kSCStatusInvalidArgument
);
1191 #endif // TARGET_OS_IPHONE
1193 currentPath
= SCPreferencesGetValue(setPrivate
->prefs
, kSCPrefCurrentSet
);
1194 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1195 if (!isA_CFString(currentPath
) || !CFEqual(currentPath
, path
)) {
1196 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
1198 SC_log(LOG_DEBUG
, "SCNetworkSetRemove() failed, currently active: %@", setPrivate
->setID
);
1199 _SCErrorSet(kSCStatusInvalidArgument
);
1204 SC_log(LOG_DEBUG
, "SCNetworkSetRemove(): %@", set
);
1212 SCNetworkSetRemoveService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
1214 SCNetworkInterfaceRef interface
;
1215 CFArrayRef interface_config
= NULL
;
1218 int sc_status
= kSCStatusOK
;
1219 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1220 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1222 if (!isA_SCNetworkSet(set
)) {
1223 _SCErrorSet(kSCStatusInvalidArgument
);
1227 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
1228 _SCErrorSet(kSCStatusInvalidArgument
);
1232 if (!__SCNetworkSetExists(set
)) {
1233 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/removed set\n set = %@\n service = %@",
1236 _SC_crash_once("SCNetworkSetRemoveService() w/removed set", NULL
, NULL
);
1237 _SCErrorSet(kSCStatusInvalidArgument
);
1241 if (!__SCNetworkServiceExists(service
)) {
1242 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/removed service\n set = %@\n service = %@",
1245 _SC_crash_once("SCNetworkSetRemoveService() w/removed service", NULL
, NULL
);
1246 _SCErrorSet(kSCStatusInvalidArgument
);
1250 // remove service from ServiceOrder
1251 _serviceOrder_remove(set
, service
);
1253 // get the [deep] interface configuration settings
1254 interface
= SCNetworkServiceGetInterface(service
);
1255 if (interface
!= NULL
) {
1256 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(set
, interface
);
1257 if (interface_config
!= NULL
) {
1258 // remove the interface configuration from all sets which contain this service.
1259 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, NULL
);
1263 // remove the link between "set" and the "service"
1264 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
1266 servicePrivate
->serviceID
,
1268 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
1270 sc_status
= SCError(); // preserve the error
1274 // push the [deep] interface configuration [back] into all sets which contain the service.
1275 if (interface_config
!= NULL
) {
1276 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, interface_config
);
1277 CFRelease(interface_config
);
1281 SC_log(LOG_DEBUG
, "SCNetworkSetRemoveService(): %@, %@", set
, service
);
1283 _SCErrorSet(sc_status
);
1291 SCNetworkSetSetCurrent(SCNetworkSetRef set
)
1295 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1297 if (!isA_SCNetworkSet(set
)) {
1298 _SCErrorSet(kSCStatusInvalidArgument
);
1302 if (!__SCNetworkSetExists(set
)) {
1303 SC_log(LOG_ERR
, "SCNetworkSetSetCurrent() w/removed set\n set = %@", set
);
1304 _SC_crash_once("SCNetworkSetSetCurrent() w/removed set", NULL
, NULL
);
1305 _SCErrorSet(kSCStatusInvalidArgument
);
1309 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1310 ok
= SCPreferencesSetValue(setPrivate
->prefs
, kSCPrefCurrentSet
, path
);
1314 SC_log(LOG_DEBUG
, "SCNetworkSetSetCurrent(): %@", set
);
1322 SCNetworkSetSetName(SCNetworkSetRef set
, CFStringRef name
)
1324 CFDictionaryRef entity
;
1325 #if TARGET_OS_IPHONE
1326 Boolean isDefaultName
= FALSE
;
1327 #endif // TARGET_OS_IPHONE
1328 CFStringRef localized
= NULL
;
1329 CFStringRef non_localized
= NULL
;
1332 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1334 if (!isA_SCNetworkSet(set
)) {
1335 _SCErrorSet(kSCStatusInvalidArgument
);
1339 if (!__SCNetworkSetExists(set
)) {
1340 SC_log(LOG_ERR
, "SCNetworkSetSetName() w/removed set\n set = %@\n name = %@",
1342 name
!= NULL
? name
: CFSTR("<NULL>"));
1343 _SC_crash_once("SCNetworkSetSetName() w/removed set", NULL
, NULL
);
1344 _SCErrorSet(kSCStatusInvalidArgument
);
1348 if ((name
!= NULL
) && !isA_CFString(name
)) {
1349 _SCErrorSet(kSCStatusInvalidArgument
);
1353 // if known, compare against localized name
1356 non_localized
= copy_default_set_name(FALSE
);
1357 if (CFEqual(name
, non_localized
)) {
1358 localized
= copy_default_set_name(TRUE
);
1360 #if TARGET_OS_IPHONE
1361 isDefaultName
= TRUE
;
1362 #endif // TARGET_OS_IPHONE
1364 #if TARGET_OS_IPHONE
1366 localized
= copy_default_set_name(TRUE
);
1367 isDefaultName
= CFEqual(name
, non_localized
);
1369 #endif // TARGET_OS_IPHONE
1372 #if TARGET_OS_IPHONE
1373 if (!isDefaultName
&& isDefaultSet(set
) && (geteuid() != 0)) {
1374 // if we are trying to change the name of the "Automatic" set
1375 SC_log(LOG_ERR
, "SCNetworkSetSetName() failed, cannot rename : %@", set
);
1376 _SC_crash("The \"Automatic\" network set cannot be renamed", NULL
, NULL
);
1377 _SCErrorSet(kSCStatusInvalidArgument
);
1380 #endif // TARGET_OS_IPHONE
1382 #define PREVENT_DUPLICATE_SET_NAMES
1383 #ifdef PREVENT_DUPLICATE_SET_NAMES
1385 #if TARGET_OS_IPHONE
1386 if (!isDefaultName
) {
1387 // On iOS, only block naming multiple sets with the name
1388 // "Automatic". Others names are OK.
1390 #endif // TARGET_OS_IPHONE
1395 // ensure that each set is uniquely named
1397 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1402 n
= CFArrayGetCount(sets
);
1403 for (i
= 0; i
< n
; i
++) {
1404 CFStringRef otherID
;
1405 CFStringRef otherName
;
1406 SCNetworkSetRef set
= CFArrayGetValueAtIndex(sets
, i
);
1408 otherID
= SCNetworkSetGetSetID(set
);
1409 if (CFEqual(setPrivate
->setID
, otherID
)) {
1410 continue; // skip current set
1413 otherName
= SCNetworkSetGetName(set
);
1414 if ((otherName
!= NULL
) && CFEqual(name
, otherName
)) {
1415 // if "name" not unique
1417 _SCErrorSet(kSCStatusKeyExists
);
1424 #endif /* PREVENT_DUPLICATE_SET_NAMES */
1426 // if known, store non-localized name
1428 if ((name
!= NULL
) && (non_localized
!= NULL
)) {
1429 if (localized
== NULL
) {
1430 localized
= copy_default_set_name(TRUE
);
1432 if (CFEqual(name
, localized
)) {
1433 name
= non_localized
;
1437 // update the "name"
1439 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1440 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1441 if (isA_CFDictionary(entity
) ||
1442 ((entity
== NULL
) && (name
!= NULL
))) {
1443 CFMutableDictionaryRef newEntity
;
1445 if (entity
!= NULL
) {
1446 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1448 newEntity
= CFDictionaryCreateMutable(NULL
,
1450 &kCFTypeDictionaryKeyCallBacks
,
1451 &kCFTypeDictionaryValueCallBacks
);
1454 CFDictionarySetValue(newEntity
, kSCPropUserDefinedName
, name
);
1456 CFDictionaryRemoveValue(newEntity
, kSCPropUserDefinedName
);
1458 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newEntity
);
1459 CFRelease(newEntity
);
1466 SC_log(LOG_DEBUG
, "SCNetworkSetSetName(): %@", set
);
1469 if (localized
!= NULL
) CFRelease(localized
);
1470 if (non_localized
!= NULL
) CFRelease(non_localized
);
1476 SCNetworkSetSetServiceOrder(SCNetworkSetRef set
, CFArrayRef newOrder
)
1478 CFMutableArrayRef cleanOrder
;
1479 CFDictionaryRef dict
;
1482 CFMutableDictionaryRef newDict
;
1485 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1487 if (!isA_SCNetworkSet(set
)) {
1488 _SCErrorSet(kSCStatusInvalidArgument
);
1492 if (!__SCNetworkSetExists(set
)) {
1493 SC_log(LOG_ERR
, "SCNetworkSetSetServiceOrder() w/removed set\n set = %@", set
);
1494 _SC_crash_once("SCNetworkSetSetServiceOrder() w/removed set", NULL
, NULL
);
1495 _SCErrorSet(kSCStatusInvalidArgument
);
1499 if (isA_CFArray(newOrder
)) {
1500 n
= CFArrayGetCount(newOrder
);
1501 for (i
= 0; i
< n
; i
++) {
1502 CFStringRef serviceID
;
1504 serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1505 if (!isA_CFString(serviceID
)) {
1506 _SCErrorSet(kSCStatusInvalidArgument
);
1511 _SCErrorSet(kSCStatusInvalidArgument
);
1515 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1520 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1522 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
1524 newDict
= CFDictionaryCreateMutable(NULL
,
1526 &kCFTypeDictionaryKeyCallBacks
,
1527 &kCFTypeDictionaryValueCallBacks
);
1530 cleanOrder
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1531 n
= CFArrayGetCount(newOrder
);
1532 for (i
= 0; i
< n
; i
++) {
1533 CFIndex nClean
= CFArrayGetCount(cleanOrder
);
1534 CFStringRef serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1536 if ((nClean
== 0) ||
1537 !CFArrayContainsValue(cleanOrder
, CFRangeMake(0, nClean
), serviceID
)) {
1538 // if first reference to this serviceID
1539 CFArrayAppendValue(cleanOrder
, serviceID
);
1541 // skip duplicate serviceID
1542 SC_log(LOG_ERR
, "SCNetworkSetSetServiceOrder() found duplicate serviceID: removed %@\n", serviceID
);
1545 CFDictionarySetValue(newDict
, kSCPropNetServiceOrder
, cleanOrder
);
1546 CFRelease(cleanOrder
);
1548 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newDict
);
1557 #pragma mark SCNetworkSet SPIs
1562 __SCNetworkSetExists(SCNetworkSetRef set
)
1564 CFDictionaryRef entity
;
1566 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1568 if (setPrivate
->prefs
== NULL
) {
1572 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1573 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1576 if (!isA_CFDictionary(entity
)) {
1586 add_supported_interfaces(CFMutableArrayRef interface_list
, SCNetworkInterfaceRef interface
)
1589 CFArrayRef interface_types
;
1592 interface_types
= SCNetworkInterfaceGetSupportedInterfaceTypes(interface
);
1593 n
= (interface_types
!= NULL
) ? CFArrayGetCount(interface_types
) : 0;
1594 for (i
= 0; i
< n
; i
++) {
1595 SCNetworkInterfaceRef parent
;
1596 CFStringRef interface_type
;
1598 interface_type
= CFArrayGetValueAtIndex(interface_types
, i
);
1599 parent
= SCNetworkInterfaceCreateWithInterface(interface
, interface_type
);
1600 if (parent
!= NULL
) {
1601 CFArrayAppendValue(interface_list
, parent
);
1610 static CFSetRef
/* of SCNetworkInterfaceRef's */
1611 copyExcludedInterfaces(SCPreferencesRef prefs
)
1613 CFMutableSetRef excluded
;
1614 CFArrayRef interfaces
;
1616 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1618 #if !TARGET_OS_IPHONE
1619 // exclude Bond [member] interfaces
1620 interfaces
= SCBondInterfaceCopyAll(prefs
);
1621 if (interfaces
!= NULL
) {
1622 __SCBondInterfaceListCollectMembers(interfaces
, excluded
);
1623 CFRelease(interfaces
);
1625 #endif // !TARGET_OS_IPHONE
1627 // exclude Bridge [member] interfaces
1628 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
1629 if (interfaces
!= NULL
) {
1630 __SCBridgeInterfaceListCollectMembers(interfaces
, excluded
);
1631 CFRelease(interfaces
);
1638 #if !TARGET_OS_IPHONE
1639 static SCBridgeInterfaceRef
1640 copyAutoBridgeInterface(SCPreferencesRef prefs
, CFStringRef bridgeName
)
1642 SCBridgeInterfaceRef bridge
= NULL
;
1643 CFArrayRef interfaces
;
1645 // exclude Bridge [member] interfaces
1646 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
1647 if (interfaces
!= NULL
) {
1651 n
= CFArrayGetCount(interfaces
);
1652 for (i
= 0; i
< n
; i
++) {
1653 SCBridgeInterfaceRef interface
;
1654 CFStringRef name
= NULL
;
1655 CFDictionaryRef options
;
1657 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1658 options
= SCBridgeInterfaceGetOptions(interface
);
1659 if ((options
!= NULL
) &&
1660 CFDictionaryGetValueIfPresent(options
,
1662 (const void **)&name
) &&
1663 _SC_CFEqual(name
, bridgeName
)) {
1670 CFRelease(interfaces
);
1673 if (bridge
== NULL
) {
1674 bridge
= SCBridgeInterfaceCreate(prefs
);
1675 if (bridge
!= NULL
) {
1676 CFMutableDictionaryRef newOptions
;
1679 newOptions
= CFDictionaryCreateMutable(NULL
, 0,
1680 &kCFTypeDictionaryKeyCallBacks
,
1681 &kCFTypeDictionaryValueCallBacks
);
1682 CFDictionarySetValue(newOptions
, CFSTR("__AUTO__"), bridgeName
);
1683 ok
= SCBridgeInterfaceSetOptions(bridge
, newOptions
);
1684 CFRelease(newOptions
);
1694 #endif // !TARGET_OS_IPHONE
1698 copyServices(SCNetworkSetRef set
)
1700 CFArrayRef services
;
1701 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1703 // first, assume that we only want to add new services
1704 // for those interfaces that are not represented in the
1706 services
= SCNetworkSetCopyServices(set
);
1707 if ((services
!= NULL
) && setPrivate
->established
) {
1708 // but, if we are given an existing (or "established") set
1709 // than we only want to add new services for those interfaces
1710 // that are not represented in *any* set.
1711 CFRelease(services
);
1712 services
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1719 #if !TARGET_OS_IPHONE
1720 static CF_RETURNS_RETAINED CFArrayRef
1721 updateServices(CFArrayRef services
, SCNetworkInterfaceRef interface
)
1723 CFStringRef bsdName
;
1726 CFMutableArrayRef newServices
;
1728 if (services
== NULL
) {
1732 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
1734 newServices
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1736 n
= CFArrayGetCount(services
);
1737 for (i
= 0; i
< n
; i
++) {
1738 SCNetworkInterfaceRef interface
;
1739 CFStringRef interfaceName
;
1740 SCNetworkServiceRef newService
;
1741 SCNetworkServiceRef service
;
1742 CFStringRef serviceID
;
1743 SCNetworkServicePrivateRef servicePrivate
;
1745 service
= CFArrayGetValueAtIndex(services
, i
);
1746 interface
= SCNetworkServiceGetInterface(service
);
1747 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
1748 if (!_SC_CFEqual(interfaceName
, bsdName
)) {
1749 // if not a match, retain
1750 CFArrayAppendValue(newServices
, service
);
1754 // if a match, update
1755 serviceID
= SCNetworkServiceGetServiceID(service
);
1756 servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1757 newService
= SCNetworkServiceCopy(servicePrivate
->prefs
, serviceID
);
1758 if (newService
!= NULL
) {
1759 CFArrayAppendValue(newServices
, newService
);
1760 CFRelease(newService
);
1766 #endif // !TARGET_OS_IPHONE
1769 static __inline__ Boolean
1770 skipInterface(SCNetworkInterfaceRef interface
)
1774 action
= _SCNetworkInterfaceGetConfigurationAction(interface
);
1775 if (isA_CFString(action
) &&
1776 CFEqual(action
, kSCNetworkInterfaceConfigurationActionValueNone
)) {
1785 _SCNetworkSetCompare(const void *val1
, const void *val2
, void *context
)
1787 #pragma unused(context)
1792 SCNetworkSetRef s1
= (SCNetworkSetRef
)val1
;
1793 SCNetworkSetRef s2
= (SCNetworkSetRef
)val2
;
1795 name1
= SCNetworkSetGetName(s1
);
1796 name2
= SCNetworkSetGetName(s2
);
1798 if (name1
!= NULL
) {
1799 if (name2
!= NULL
) {
1800 return CFStringCompare(name1
, name2
, 0);
1802 return kCFCompareLessThan
;
1806 if (name2
!= NULL
) {
1807 return kCFCompareGreaterThan
;
1810 id1
= SCNetworkSetGetSetID(s1
);
1811 id2
= SCNetworkSetGetSetID(s2
);
1812 return CFStringCompare(id1
, id2
, 0);
1817 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set
, CFArrayRef interfaces
, Boolean excludeHidden
)
1823 CFArrayRef services
;
1824 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1825 Boolean updated
= FALSE
;
1826 #if !TARGET_OS_IPHONE
1827 Boolean updatedIFs
= FALSE
;
1828 #endif // !TARGET_OS_IPHONE
1830 #if TARGET_OS_IPHONE
1831 CFArrayRef orphans
= NULL
;
1834 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1836 if (CFArrayGetCount(sets
) == 1) {
1837 services
= SCNetworkSetCopyServices(set
);
1838 if (services
!= NULL
) {
1839 n
= CFArrayGetCount(services
);
1840 CFRelease(services
);
1843 if ((n
== 0) && CFEqual(set
, CFArrayGetValueAtIndex(sets
, 0))) {
1844 // after a "Reset Network Settings" we need to find (and
1845 // add back) any VPN services that were orphaned.
1846 orphans
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1852 #endif // TARGET_OS_IPHONE
1854 // copy network services
1855 services
= copyServices(set
);
1857 // copy network interfaces to be excluded
1858 excluded
= copyExcludedInterfaces(setPrivate
->prefs
);
1860 #if !TARGET_OS_IPHONE
1861 // look for interfaces that should auto-magically be added
1862 // to an Ethernet bridge
1863 n
= ((services
!= NULL
) && (interfaces
!= NULL
)) ? CFArrayGetCount(interfaces
) : 0;
1864 for (i
= 0; i
< n
; i
++) {
1865 SCBridgeInterfaceRef bridge
= NULL
;
1866 SCNetworkInterfaceRef interface
;
1868 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1870 if (excludeHidden
&& skipInterface(interface
)) {
1871 // if not auto-configure
1875 if (CFSetContainsValue(excluded
, interface
)) {
1876 // if this interface is a member of a Bond or Bridge
1880 if (__SCNetworkServiceExistsForInterface(services
, interface
)) {
1881 // if this is not a new interface
1885 if (_SCNetworkInterfaceIsBuiltin(interface
) &&
1886 _SCNetworkInterfaceIsThunderbolt(interface
) &&
1887 !isA_SCBridgeInterface(interface
)) {
1888 // add built-in Thunderbolt interfaces to bridge
1889 bridge
= copyAutoBridgeInterface(setPrivate
->prefs
, CFSTR("thunderbolt-bridge"));
1892 if (bridge
!= NULL
) {
1893 CFIndex bridgeIndex
;
1895 CFMutableArrayRef newMembers
;
1896 CFMutableSetRef newExcluded
;
1897 CFMutableArrayRef newInterfaces
;
1898 CFArrayRef newServices
;
1900 // track the bridge interface (if it's in our list)
1901 bridgeIndex
= CFArrayGetFirstIndexOfValue(interfaces
,
1902 CFRangeMake(0, CFArrayGetCount(interfaces
)),
1905 // add new member interface
1906 members
= SCBridgeInterfaceGetMemberInterfaces(bridge
);
1907 if ((members
!= NULL
) && (CFArrayGetCount(members
) > 0)) {
1908 newMembers
= CFArrayCreateMutableCopy(NULL
, 0, members
);
1909 updated
= TRUE
; // if we're updating an existing bridge
1911 newMembers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1913 CFArrayAppendValue(newMembers
, interface
);
1914 ok
= SCBridgeInterfaceSetMemberInterfaces(bridge
, newMembers
);
1915 CFRelease(newMembers
);
1917 SC_log(LOG_INFO
, "could not update bridge with \"%@\": %s",
1918 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1919 SCErrorString(SCError()));
1924 // exclude the new member interface
1925 newExcluded
= CFSetCreateMutableCopy(NULL
, 0, excluded
);
1926 CFRelease(excluded
);
1927 CFSetAddValue(newExcluded
, interface
);
1928 excluded
= newExcluded
;
1930 // update the list of interfaces to include the [new or updated] bridge
1931 newInterfaces
= CFArrayCreateMutableCopy(NULL
, 0, interfaces
);
1932 if (bridgeIndex
!= kCFNotFound
) {
1933 CFArraySetValueAtIndex(newInterfaces
, bridgeIndex
, bridge
);
1935 CFArrayAppendValue(newInterfaces
, bridge
);
1938 CFRelease(interfaces
);
1940 interfaces
= newInterfaces
;
1943 // refresh [existing] services
1944 newServices
= updateServices(services
, bridge
);
1945 if (newServices
!= NULL
) {
1946 CFRelease(services
);
1947 services
= newServices
;
1953 #endif // !TARGET_OS_IPHONE
1955 n
= ((services
!= NULL
) && (interfaces
!= NULL
)) ? CFArrayGetCount(interfaces
) : 0;
1956 for (i
= 0; i
< n
; i
++) {
1957 SCNetworkInterfaceRef interface
;
1958 CFMutableArrayRef interface_list
;
1960 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1962 if (excludeHidden
&& skipInterface(interface
)) {
1963 // if not auto-configure
1967 if (CFSetContainsValue(excluded
, interface
)) {
1968 // if this interface is a member of a Bond or Bridge
1972 if (__SCNetworkServiceExistsForInterface(services
, interface
)) {
1973 // if this is not a new interface
1977 interface_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1978 CFArrayAppendValue(interface_list
, interface
);
1980 while (ok
&& (CFArrayGetCount(interface_list
) > 0)) {
1981 CFArrayRef protocol_types
;
1983 interface
= CFArrayGetValueAtIndex(interface_list
, 0);
1985 protocol_types
= SCNetworkInterfaceGetSupportedProtocolTypes(interface
);
1986 if ((protocol_types
!= NULL
) && (CFArrayGetCount(protocol_types
) > 0)) {
1987 SCNetworkServiceRef service
;
1989 service
= SCNetworkServiceCreate(setPrivate
->prefs
, interface
);
1990 if (service
== NULL
) {
1991 SC_log(LOG_ERR
, "could not create service for \"%@\": %s",
1992 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1993 SCErrorString(SCError()));
1998 ok
= SCNetworkServiceEstablishDefaultConfiguration(service
);
2000 SC_log(LOG_ERR
, "could not estabish default configuration for \"%@\": %s",
2001 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
2002 SCErrorString(SCError()));
2003 SCNetworkServiceRemove(service
);
2008 ok
= SCNetworkSetAddService(set
, service
);
2010 SC_log(LOG_ERR
, "could not add service for \"%@\": %s",
2011 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
2012 SCErrorString(SCError()));
2013 SCNetworkServiceRemove(service
);
2021 add_supported_interfaces(interface_list
, interface
);
2026 CFArrayRemoveValueAtIndex(interface_list
, 0);
2028 CFRelease(interface_list
);
2030 #if !TARGET_OS_IPHONE
2031 if (updatedIFs
&& (interfaces
!= NULL
)) {
2032 CFRelease(interfaces
);
2034 #endif // !TARGET_OS_IPHONE
2035 if (services
!= NULL
) CFRelease(services
);
2036 CFRelease(excluded
);
2038 #if TARGET_OS_IPHONE
2039 if (orphans
!= NULL
) {
2040 if (ok
&& updated
) {
2042 CFIndex n
= CFArrayGetCount(orphans
);
2044 for (i
= 0; i
< n
; i
++) {
2045 SCNetworkServiceRef service
;
2047 service
= CFArrayGetValueAtIndex(orphans
, i
);
2048 if (_SCNetworkServiceIsVPN(service
)) {
2049 ok
= SCNetworkSetAddService(set
, service
);
2059 #endif // TARGET_OS_IPHONE
2065 model
= SCPreferencesGetValue(setPrivate
->prefs
, MODEL
);
2066 if (model
== NULL
) {
2067 model
= _SC_hw_model(FALSE
);
2068 SCPreferencesSetValue(setPrivate
->prefs
, MODEL
, model
);
2071 // if no changes were made
2072 _SCErrorSet(kSCStatusOK
);
2081 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set
)
2083 CFArrayRef interfaces
;
2084 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
2085 Boolean updated
= FALSE
;
2087 if (!isA_SCNetworkSet(set
)) {
2088 _SCErrorSet(kSCStatusInvalidArgument
);
2092 interfaces
= _SCNetworkInterfaceCopyAllWithPreferences(setPrivate
->prefs
);
2093 if (interfaces
!= NULL
) {
2094 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
, TRUE
);
2095 CFRelease(interfaces
);
2103 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set
, SCNetworkInterfaceRef interface
)
2105 CFArrayRef interfaces
;
2108 if (!isA_SCNetworkSet(set
)) {
2109 _SCErrorSet(kSCStatusInvalidArgument
);
2113 if (!isA_SCNetworkInterface(interface
)) {
2114 _SCErrorSet(kSCStatusInvalidArgument
);
2118 interfaces
= CFArrayCreate(NULL
, (const void **)&interface
, 1, &kCFTypeArrayCallBacks
);
2119 assert(interfaces
!= NULL
);
2120 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
, FALSE
);
2121 CFRelease(interfaces
);
2128 SCNetworkSetCopySelectedVPNService(SCNetworkSetRef set
)
2132 SCNetworkServiceRef selected
= NULL
;
2133 CFArrayRef services
;
2134 CFMutableArrayRef services_vpn
= NULL
;
2136 if (!isA_SCNetworkSet(set
)) {
2137 _SCErrorSet(kSCStatusInvalidArgument
);
2141 services
= SCNetworkSetCopyServices(set
);
2142 if (services
!= NULL
) {
2143 n
= CFArrayGetCount(services
);
2144 for (i
= 0; i
< n
; i
++) {
2145 SCNetworkServiceRef service
;
2147 service
= CFArrayGetValueAtIndex(services
, i
);
2148 if (!SCNetworkServiceGetEnabled(service
)) {
2153 if (!_SCNetworkServiceIsVPN(service
)) {
2154 // if not VPN service
2158 if (services_vpn
== NULL
) {
2159 services_vpn
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2161 CFArrayAppendValue(services_vpn
, service
);
2164 CFRelease(services
);
2167 if (services_vpn
== NULL
) {
2168 // if no VPN services
2172 n
= CFArrayGetCount(services_vpn
);
2175 CFMutableArrayRef sorted
;
2177 order
= SCNetworkSetGetServiceOrder(set
);
2178 sorted
= CFArrayCreateMutableCopy(NULL
, 0, services_vpn
);
2179 CFArraySortValues(sorted
,
2180 CFRangeMake(0, CFArrayGetCount(sorted
)),
2181 _SCNetworkServiceCompare
,
2183 CFRelease(services_vpn
);
2184 services_vpn
= sorted
;
2187 #if TARGET_OS_IPHONE
2189 CFStringRef serviceID_prefs
;
2191 #define VPN_PREFERENCES CFSTR("com.apple.mobilevpn")
2192 #define VPN_SERVICE_ID CFSTR("activeVPNID")
2194 CFPreferencesAppSynchronize(VPN_PREFERENCES
);
2195 serviceID_prefs
= CFPreferencesCopyAppValue(VPN_SERVICE_ID
, VPN_PREFERENCES
);
2196 if (serviceID_prefs
!= NULL
) {
2197 for (i
= 0; i
< n
; i
++) {
2198 SCNetworkServiceRef service
;
2199 CFStringRef serviceID
;
2201 service
= CFArrayGetValueAtIndex(services_vpn
, i
);
2202 serviceID
= SCNetworkServiceGetServiceID(service
);
2203 if (CFEqual(serviceID
, serviceID_prefs
)) {
2211 CFRelease(serviceID_prefs
);
2214 #endif // TARGET_OS_IPHONE
2216 if (selected
== NULL
) {
2217 selected
= CFArrayGetValueAtIndex(services_vpn
, 0);
2221 CFRelease(services_vpn
);
2227 SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
2230 CFArrayRef services
;
2232 if (!isA_SCNetworkSet(set
)) {
2233 _SCErrorSet(kSCStatusInvalidArgument
);
2237 if (!isA_SCNetworkService(service
) || !_SCNetworkServiceIsVPN(service
)) {
2238 _SCErrorSet(kSCStatusInvalidArgument
);
2242 services
= SCNetworkSetCopyServices(set
);
2243 if (services
!= NULL
) {
2245 CFIndex n
= CFArrayGetCount(services
);
2247 if (!CFArrayContainsValue(services
, CFRangeMake(0, n
), service
)) {
2248 // if selected service not a member of the current set
2249 _SCErrorSet(kSCStatusInvalidArgument
);
2254 for (i
= 0; ok
&& (i
< n
); i
++) {
2255 SCNetworkServiceRef vpn
;
2257 vpn
= CFArrayGetValueAtIndex(services
, i
);
2258 if (!_SCNetworkServiceIsVPN(vpn
)) {
2259 // if not VPN service
2263 ok
= SCNetworkServiceSetEnabled(vpn
, CFEqual(service
, vpn
));
2269 if (services
!= NULL
) CFRelease(services
);
2275 _SCNetworkSetSetSetID(SCNetworkSetRef set
, CFStringRef newSetID
)
2277 SCNetworkSetRef currentSet
= NULL
;
2278 SCNetworkSetPrivateRef currentSetPrivate
= NULL
;
2279 CFDictionaryRef entity
;
2280 CFStringRef newPath
;
2282 CFStringRef oldPath
= NULL
;
2283 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
2284 Boolean updateCurrentSet
= FALSE
;
2286 if (!isA_SCNetworkSet(set
)) {
2287 _SCErrorSet(kSCStatusInvalidArgument
);
2291 if (!isA_CFString(newSetID
)) {
2292 _SCErrorSet(kSCStatusInvalidArgument
);
2296 if (!__SCNetworkSetExists(set
)) {
2297 SC_log(LOG_ERR
, "_SCNetworkSetSetSetID() w/removed set\n set = %@\n setID = %@",
2300 _SC_crash_once("_SCNetworkSetSetSetID() w/removed set", NULL
, NULL
);
2301 _SCErrorSet(kSCStatusInvalidArgument
);
2305 // If newSetID is equal to current setID, our work is done
2306 if (CFEqual(newSetID
, setPrivate
->setID
)) {
2310 newPath
= SCPreferencesPathKeyCreateSet(NULL
, newSetID
);
2311 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, newPath
);
2312 if (isA_CFDictionary(entity
)) {
2313 // if the new set already exists
2314 _SCErrorSet(kSCStatusKeyExists
);
2318 oldPath
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
2319 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, oldPath
);
2320 if (!isA_CFDictionary(entity
)) {
2321 // if the set has already been removed
2322 _SCErrorSet(kSCStatusNoKey
);
2326 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, newPath
, entity
);
2331 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, oldPath
);
2336 // update current set (if needed)
2337 currentSet
= SCNetworkSetCopyCurrent(setPrivate
->prefs
);
2338 if (currentSet
!= NULL
) {
2339 currentSetPrivate
= (SCNetworkSetPrivateRef
)currentSet
;
2340 if (CFEqual(currentSetPrivate
->setID
, setPrivate
->setID
)) {
2341 updateCurrentSet
= TRUE
;
2343 CFRelease(currentSet
);
2346 SC_log(LOG_DEBUG
, "_SCNetworkSetSetID(): %@ --> %@", set
, newSetID
);
2348 // replace setID with new one
2350 CFRelease(setPrivate
->setID
);
2351 setPrivate
->setID
= newSetID
;
2353 if (updateCurrentSet
) {
2354 SCNetworkSetSetCurrent(set
);
2359 if (oldPath
!= NULL
) {
2362 if (newPath
!= NULL
) {