2 * Copyright (c) 2004-2007, 2009-2011 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 <SystemConfiguration/SystemConfiguration.h>
35 #include "SCNetworkConfigurationInternal.h"
36 #include <SystemConfiguration/SCValidation.h>
37 #include <SystemConfiguration/SCPrivate.h>
42 static CFStringRef
__SCNetworkSetCopyDescription (CFTypeRef cf
);
43 static void __SCNetworkSetDeallocate (CFTypeRef cf
);
44 static Boolean
__SCNetworkSetEqual (CFTypeRef cf1
, CFTypeRef cf2
);
45 static CFHashCode
__SCNetworkSetHash (CFTypeRef cf
);
48 static CFTypeID __kSCNetworkSetTypeID
= _kCFRuntimeNotATypeID
;
51 static const CFRuntimeClass __SCNetworkSetClass
= {
53 "SCNetworkSet", // className
56 __SCNetworkSetDeallocate
, // dealloc
57 __SCNetworkSetEqual
, // equal
58 __SCNetworkSetHash
, // hash
59 NULL
, // copyFormattingDesc
60 __SCNetworkSetCopyDescription
// copyDebugDesc
64 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
68 __SCNetworkSetCopyDescription(CFTypeRef cf
)
70 CFAllocatorRef allocator
= CFGetAllocator(cf
);
71 CFMutableStringRef result
;
72 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)cf
;
74 result
= CFStringCreateMutable(allocator
, 0);
75 CFStringAppendFormat(result
, NULL
, CFSTR("<SCNetworkSet %p [%p]> {"), cf
, allocator
);
76 CFStringAppendFormat(result
, NULL
, CFSTR("id = %@"), setPrivate
->setID
);
77 CFStringAppendFormat(result
, NULL
, CFSTR(", prefs = %p"), setPrivate
->prefs
);
78 if (setPrivate
->name
!= NULL
) {
79 CFStringAppendFormat(result
, NULL
, CFSTR(", name = %@"), setPrivate
->name
);
81 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
88 __SCNetworkSetDeallocate(CFTypeRef cf
)
90 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)cf
;
92 /* release resources */
94 CFRelease(setPrivate
->setID
);
95 CFRelease(setPrivate
->prefs
);
96 if (setPrivate
->name
!= NULL
)
97 CFRelease(setPrivate
->name
);
104 __SCNetworkSetEqual(CFTypeRef cf1
, CFTypeRef cf2
)
106 SCNetworkSetPrivateRef s1
= (SCNetworkSetPrivateRef
)cf1
;
107 SCNetworkSetPrivateRef s2
= (SCNetworkSetPrivateRef
)cf2
;
112 if (s1
->prefs
!= s2
->prefs
)
113 return FALSE
; // if not the same prefs
115 if (!CFEqual(s1
->setID
, s2
->setID
))
116 return FALSE
; // if not the same set identifier
123 __SCNetworkSetHash(CFTypeRef cf
)
125 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)cf
;
127 return CFHash(setPrivate
->setID
);
132 __SCNetworkSetInitialize(void)
134 __kSCNetworkSetTypeID
= _CFRuntimeRegisterClass(&__SCNetworkSetClass
);
139 static SCNetworkSetPrivateRef
140 __SCNetworkSetCreatePrivate(CFAllocatorRef allocator
,
141 SCPreferencesRef prefs
,
144 SCNetworkSetPrivateRef setPrivate
;
147 /* initialize runtime */
148 pthread_once(&initialized
, __SCNetworkSetInitialize
);
150 /* allocate target */
151 size
= sizeof(SCNetworkSetPrivate
) - sizeof(CFRuntimeBase
);
152 setPrivate
= (SCNetworkSetPrivateRef
)_CFRuntimeCreateInstance(allocator
,
153 __kSCNetworkSetTypeID
,
156 if (setPrivate
== NULL
) {
160 setPrivate
->setID
= CFStringCreateCopy(NULL
, setID
);
161 setPrivate
->prefs
= CFRetain(prefs
);
162 setPrivate
->name
= NULL
;
163 setPrivate
->established
= FALSE
; // "new" (not yet established) set
173 _serviceOrder(SCNetworkServiceRef service
)
175 SCNetworkInterfaceRef interface
;
177 interface
= SCNetworkServiceGetInterface(service
);
178 if ((interface
== NULL
) || _SCNetworkServiceIsVPN(service
)) {
179 return 100000; // if unknown or VPN interface, sort last
182 return __SCNetworkInterfaceOrder(interface
);
187 _serviceOrder_add(SCNetworkSetRef set
, SCNetworkServiceRef service
)
191 CFMutableArrayRef newOrder
;
193 CFStringRef serviceID
;
194 CFIndex serviceOrder
;
195 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
198 order
= SCNetworkSetGetServiceOrder(set
);
200 newOrder
= CFArrayCreateMutableCopy(NULL
, 0, order
);
202 newOrder
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
204 n
= CFArrayGetCount(newOrder
);
206 serviceID
= SCNetworkServiceGetServiceID(service
);
207 if (CFArrayContainsValue(newOrder
, CFRangeMake(0, n
), serviceID
)) {
208 // if serviceID already present
212 serviceOrder
= _serviceOrder(service
);
215 for (i
= 0; i
< n
; i
++) {
217 SCNetworkServiceRef slotService
;
218 CFStringRef slotServiceID
;
220 slotServiceID
= CFArrayGetValueAtIndex(newOrder
, i
);
221 if (!isA_CFString(slotServiceID
)) {
226 slotService
= SCNetworkServiceCopy(setPrivate
->prefs
, slotServiceID
);
227 if (slotService
== NULL
) {
228 // if serviceID not valid
232 slotOrder
= _serviceOrder(slotService
);
233 if (serviceOrder
>= slotOrder
) {
234 // add the service *after* this one
238 CFRelease(slotService
);
241 CFArrayInsertValueAtIndex(newOrder
, slot
, serviceID
);
242 (void) SCNetworkSetSetServiceOrder(set
, newOrder
);
253 _serviceOrder_remove(SCNetworkSetRef set
, SCNetworkServiceRef service
)
255 CFMutableArrayRef newOrder
;
257 CFStringRef serviceID
;
259 order
= SCNetworkSetGetServiceOrder(set
);
264 serviceID
= SCNetworkServiceGetServiceID(service
);
266 newOrder
= CFArrayCreateMutableCopy(NULL
, 0, order
);
270 i
= CFArrayGetFirstIndexOfValue(newOrder
,
271 CFRangeMake(0, CFArrayGetCount(newOrder
)),
273 if (i
== kCFNotFound
) {
277 CFArrayRemoveValueAtIndex(newOrder
, i
);
279 (void) SCNetworkSetSetServiceOrder(set
, newOrder
);
287 #pragma mark SCNetworkSet APIs
294 SCNetworkSetAddService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
296 SCNetworkInterfaceRef interface
;
297 CFArrayRef interface_config
= NULL
;
301 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
302 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
304 if (!isA_SCNetworkSet(set
)) {
305 _SCErrorSet(kSCStatusInvalidArgument
);
309 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
310 _SCErrorSet(kSCStatusInvalidArgument
);
314 // make sure that we do not add an orphaned network service if its
315 // associated interface is a member of a bond or bridge.
316 interface
= SCNetworkServiceGetInterface(service
);
317 if ((interface
!= NULL
) &&
318 __SCNetworkInterfaceIsMember(servicePrivate
->prefs
, interface
)) {
319 _SCErrorSet(kSCStatusKeyExists
);
323 #define PREVENT_DUPLICATE_SERVICE_NAMES
324 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
327 name
= SCNetworkServiceGetName(service
);
331 services
= SCNetworkSetCopyServices(set
);
332 if (services
!= NULL
) {
336 n
= CFArrayGetCount(services
);
337 for (i
= 0; i
< n
; i
++) {
338 CFStringRef otherName
;
339 SCNetworkServiceRef otherService
;
341 otherService
= CFArrayGetValueAtIndex(services
, i
);
342 otherName
= SCNetworkServiceGetName(otherService
);
343 if ((otherName
!= NULL
) && CFEqual(name
, otherName
)) {
345 * if a service with the same "name" is
346 * already a member of the set.
349 _SCErrorSet(kSCStatusKeyExists
);
357 #endif // PREVENT_DUPLICATE_SERVICE_NAMES
359 //#define PREVENT_DUPLICATE_SETS
360 #ifdef PREVENT_DUPLICATE_SETS
363 // ensure that each service is only a member of ONE set
364 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
369 n
= CFArrayGetCount(sets
);
370 for (i
= 0; i
< n
; i
++) {
375 set
= CFArrayGetValueAtIndex(sets
, i
);
376 services
= SCNetworkSetCopyServices(set
);
377 found
= CFArrayContainsValue(services
,
378 CFRangeMake(0, CFArrayGetCount(services
)),
384 _SCErrorSet(kSCStatusKeyExists
);
390 #endif /* PREVENT_DUPLICATE_SETS */
392 // get the [deep] interface configuration settings
393 interface
= SCNetworkServiceGetInterface(service
);
394 if (interface
!= NULL
) {
395 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(set
, interface
);
398 // create the link between "set" and the "service"
399 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
, // allocator
400 setPrivate
->setID
, // set
401 servicePrivate
->serviceID
, // service
403 link
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
404 servicePrivate
->serviceID
, // service
406 ok
= SCPreferencesPathSetLink(setPrivate
->prefs
, path
, link
);
413 // push the [deep] interface configuration into all sets which contain this service.
414 if (interface
!= NULL
) {
415 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, interface_config
);
418 // add service to ServiceOrder
419 _serviceOrder_add(set
, service
);
421 // mark set as no longer "new"
422 setPrivate
->established
= TRUE
;
426 if (interface_config
!= NULL
) CFRelease(interface_config
);
432 SCNetworkSetCopy(SCPreferencesRef prefs
, CFStringRef setID
)
434 CFDictionaryRef entity
;
436 SCNetworkSetPrivateRef setPrivate
;
438 if (!isA_CFString(setID
)) {
439 _SCErrorSet(kSCStatusInvalidArgument
);
443 path
= SCPreferencesPathKeyCreateSet(NULL
, setID
);
444 entity
= SCPreferencesPathGetValue(prefs
, path
);
447 if (!isA_CFDictionary(entity
)) {
448 _SCErrorSet(kSCStatusNoKey
);
452 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
454 // mark set as "old" (already established)
455 setPrivate
->established
= TRUE
;
457 return (SCNetworkSetRef
)setPrivate
;
462 SCNetworkSetContainsInterface(SCNetworkSetRef set
, SCNetworkInterfaceRef interface
)
464 Boolean found
= FALSE
;
467 services
= SCNetworkSetCopyServices(set
);
468 if (services
!= NULL
) {
469 found
= __SCNetworkServiceExistsForInterface(services
, interface
);
477 CFArrayRef
/* of SCNetworkSetRef's */
478 SCNetworkSetCopyAll(SCPreferencesRef prefs
)
480 CFMutableArrayRef array
;
483 CFDictionaryRef sets
;
485 path
= SCPreferencesPathKeyCreateSets(NULL
);
486 sets
= SCPreferencesPathGetValue(prefs
, path
);
489 if ((sets
!= NULL
) && !isA_CFDictionary(sets
)) {
493 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
495 n
= (sets
!= NULL
) ? CFDictionaryGetCount(sets
) : 0;
498 const void * keys_q
[N_QUICK
];
499 const void ** keys
= keys_q
;
500 const void * vals_q
[N_QUICK
];
501 const void ** vals
= vals_q
;
503 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
504 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
505 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
507 CFDictionaryGetKeysAndValues(sets
, keys
, vals
);
508 for (i
= 0; i
< n
; i
++) {
509 SCNetworkSetPrivateRef setPrivate
;
511 if (!isA_CFDictionary(vals
[i
])) {
514 CFSTR("SCNetworkSetCopyAll(): error w/set \"%@\"\n"),
519 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, keys
[i
]);
521 // mark set as "old" (already established)
522 setPrivate
->established
= TRUE
;
524 CFArrayAppendValue(array
, (SCNetworkSetRef
)setPrivate
);
525 CFRelease(setPrivate
);
527 if (keys
!= keys_q
) {
528 CFAllocatorDeallocate(NULL
, keys
);
529 CFAllocatorDeallocate(NULL
, vals
);
538 SCNetworkSetCopyCurrent(SCPreferencesRef prefs
)
540 CFArrayRef components
;
541 CFStringRef currentID
;
542 SCNetworkSetPrivateRef setPrivate
= NULL
;
544 currentID
= SCPreferencesGetValue(prefs
, kSCPrefCurrentSet
);
545 if (!isA_CFString(currentID
)) {
549 components
= CFStringCreateArrayBySeparatingStrings(NULL
, currentID
, CFSTR("/"));
550 if (CFArrayGetCount(components
) == 3) {
554 setID
= CFArrayGetValueAtIndex(components
, 2);
555 path
= SCPreferencesPathKeyCreateSet(NULL
, setID
);
556 if (CFEqual(path
, currentID
)) {
557 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
559 // mark set as "old" (already established)
560 setPrivate
->established
= TRUE
;
562 SCLog(TRUE
, LOG_ERR
, CFSTR("SCNetworkSetCopyCurrent(): preferences are non-conformant"));
566 CFRelease(components
);
568 return (SCNetworkSetRef
)setPrivate
;
572 CFArrayRef
/* of SCNetworkServiceRef's */
573 SCNetworkSetCopyServices(SCNetworkSetRef set
)
575 CFMutableArrayRef array
;
576 CFDictionaryRef dict
;
579 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
581 if (!isA_SCNetworkSet(set
)) {
582 _SCErrorSet(kSCStatusInvalidArgument
);
586 path
= SCPreferencesPathKeyCreateSetNetworkService(NULL
, setPrivate
->setID
, NULL
);
587 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
589 if ((dict
!= NULL
) && !isA_CFDictionary(dict
)) {
593 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
595 n
= (dict
!= NULL
) ? CFDictionaryGetCount(dict
) : 0;
598 const void * keys_q
[N_QUICK
];
599 const void ** keys
= keys_q
;
601 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
602 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
604 CFDictionaryGetKeysAndValues(dict
, keys
, NULL
);
605 for (i
= 0; i
< n
; i
++) {
606 CFArrayRef components
;
609 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
611 (CFStringRef
)keys
[i
],
613 link
= SCPreferencesPathGetLink(setPrivate
->prefs
, path
);
618 CFSTR("SCNetworkSetCopyServices(): service \"%@\" for set \"%@\" is not a link\n"),
621 continue; // if the service is not a link
624 components
= CFStringCreateArrayBySeparatingStrings(NULL
, link
, CFSTR("/"));
625 if (CFArrayGetCount(components
) == 3) {
626 CFStringRef serviceID
;
628 serviceID
= CFArrayGetValueAtIndex(components
, 2);
629 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
630 serviceID
, // service
632 if (CFEqual(path
, link
)) {
633 SCNetworkServicePrivateRef servicePrivate
;
635 servicePrivate
= __SCNetworkServiceCreatePrivate(NULL
,
639 CFArrayAppendValue(array
, (SCNetworkServiceRef
)servicePrivate
);
640 CFRelease(servicePrivate
);
644 CFRelease(components
);
646 if (keys
!= keys_q
) {
647 CFAllocatorDeallocate(NULL
, keys
);
656 SCNetworkSetCreate(SCPreferencesRef prefs
)
658 CFArrayRef components
;
659 CFDictionaryRef entity
;
664 SCNetworkSetPrivateRef setPrivate
;
666 prefix
= SCPreferencesPathKeyCreateSets(NULL
);
667 path
= __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs
, prefix
);
668 if (path
== NULL
) path
= SCPreferencesPathCreateUniqueChild(prefs
, prefix
);
674 components
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
675 setID
= CFArrayGetValueAtIndex(components
, 2);
676 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
677 CFRelease(components
);
679 // mark set as "new" (not yet established)
680 setPrivate
->established
= FALSE
;
682 // establish the set in the preferences
683 entity
= CFDictionaryCreate(NULL
,
685 &kCFTypeDictionaryKeyCallBacks
,
686 &kCFTypeDictionaryValueCallBacks
);
687 ok
= SCPreferencesPathSetValue(prefs
, path
, entity
);
691 CFRelease(setPrivate
);
695 return (SCNetworkSetRef
)setPrivate
;
700 SCNetworkSetGetSetID(SCNetworkSetRef set
)
702 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
704 if (!isA_SCNetworkSet(set
)) {
705 _SCErrorSet(kSCStatusInvalidArgument
);
709 return setPrivate
->setID
;
714 SCNetworkSetGetName(SCNetworkSetRef set
)
717 CFDictionaryRef entity
;
719 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
721 if (!isA_SCNetworkSet(set
)) {
722 _SCErrorSet(kSCStatusInvalidArgument
);
726 if (setPrivate
->name
!= NULL
) {
727 return setPrivate
->name
;
730 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
731 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
734 if (isA_CFDictionary(entity
)) {
737 name
= CFDictionaryGetValue(entity
, kSCPropUserDefinedName
);
738 if (isA_CFString(name
)) {
739 setPrivate
->name
= CFRetain(name
);
743 bundle
= _SC_CFBundleGet();
744 if (bundle
!= NULL
) {
745 if (setPrivate
->name
!= NULL
) {
746 CFStringRef non_localized
;
748 non_localized
= _SC_CFBundleCopyNonLocalizedString(bundle
,
749 CFSTR("DEFAULT_SET_NAME"),
752 if (non_localized
!= NULL
) {
753 if (CFEqual(setPrivate
->name
, non_localized
)) {
754 CFStringRef localized
;
756 // if "Automatic", return localized name
757 localized
= CFBundleCopyLocalizedString(bundle
,
758 CFSTR("DEFAULT_SET_NAME"),
761 if (localized
!= NULL
) {
762 CFRelease(setPrivate
->name
);
763 setPrivate
->name
= localized
;
767 CFRelease(non_localized
);
772 return setPrivate
->name
;
776 CFArrayRef
/* of serviceID CFStringRef's */
777 SCNetworkSetGetServiceOrder(SCNetworkSetRef set
)
779 CFDictionaryRef dict
;
781 CFArrayRef serviceOrder
;
782 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
784 if (!isA_SCNetworkSet(set
)) {
785 _SCErrorSet(kSCStatusInvalidArgument
);
789 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
794 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
796 if (!isA_CFDictionary(dict
)) {
800 serviceOrder
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
);
801 serviceOrder
= isA_CFArray(serviceOrder
);
808 SCNetworkSetGetTypeID(void)
810 pthread_once(&initialized
, __SCNetworkSetInitialize
); /* initialize runtime */
811 return __kSCNetworkSetTypeID
;
816 SCNetworkSetRemove(SCNetworkSetRef set
)
818 CFStringRef currentPath
;
821 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
823 if (!isA_SCNetworkSet(set
)) {
824 _SCErrorSet(kSCStatusInvalidArgument
);
828 currentPath
= SCPreferencesGetValue(setPrivate
->prefs
, kSCPrefCurrentSet
);
829 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
830 if (!isA_CFString(currentPath
) || !CFEqual(currentPath
, path
)) {
831 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
833 _SCErrorSet(kSCStatusInvalidArgument
);
842 SCNetworkSetRemoveService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
844 SCNetworkInterfaceRef interface
;
845 CFArrayRef interface_config
= NULL
;
848 int sc_status
= kSCStatusOK
;
849 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
850 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
852 if (!isA_SCNetworkSet(set
)) {
853 _SCErrorSet(kSCStatusInvalidArgument
);
857 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
858 _SCErrorSet(kSCStatusInvalidArgument
);
862 // remove service from ServiceOrder
863 _serviceOrder_remove(set
, service
);
865 // get the [deep] interface configuration settings
866 interface
= SCNetworkServiceGetInterface(service
);
867 if (interface
!= NULL
) {
868 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(set
, interface
);
869 if (interface_config
!= NULL
) {
870 // remove the interface configuration from all sets which contain this service.
871 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, NULL
);
875 // remove the link between "set" and the "service"
876 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
878 servicePrivate
->serviceID
,
880 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
882 sc_status
= SCError(); // preserve the error
886 // push the [deep] interface configuration [back] into all sets which contain the service.
887 if (interface_config
!= NULL
) {
888 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, interface_config
);
891 if (interface_config
!= NULL
) CFRelease(interface_config
);
893 _SCErrorSet(sc_status
);
900 SCNetworkSetSetCurrent(SCNetworkSetRef set
)
904 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
906 if (!isA_SCNetworkSet(set
)) {
907 _SCErrorSet(kSCStatusInvalidArgument
);
911 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
912 ok
= SCPreferencesSetValue(setPrivate
->prefs
, kSCPrefCurrentSet
, path
);
919 SCNetworkSetSetName(SCNetworkSetRef set
, CFStringRef name
)
921 CFBundleRef bundle
= NULL
;
922 CFDictionaryRef entity
;
923 CFStringRef localized
= NULL
;
924 CFStringRef non_localized
= NULL
;
927 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
929 if (!isA_SCNetworkSet(set
)) {
930 _SCErrorSet(kSCStatusInvalidArgument
);
934 if ((name
!= NULL
) && !isA_CFString(name
)) {
935 _SCErrorSet(kSCStatusInvalidArgument
);
939 // if known, compare against localized name
942 bundle
= _SC_CFBundleGet();
943 if (bundle
!= NULL
) {
944 non_localized
= _SC_CFBundleCopyNonLocalizedString(bundle
,
945 CFSTR("DEFAULT_SET_NAME"),
948 if (non_localized
!= NULL
) {
949 if (CFEqual(name
, non_localized
)) {
950 localized
= CFBundleCopyLocalizedString(bundle
,
951 CFSTR("DEFAULT_SET_NAME"),
954 if (localized
!= NULL
) {
962 #define PREVENT_DUPLICATE_SET_NAMES
963 #ifdef PREVENT_DUPLICATE_SET_NAMES
967 // ensure that each set is uniquely named
969 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
974 n
= CFArrayGetCount(sets
);
975 for (i
= 0; i
< n
; i
++) {
977 CFStringRef otherName
;
978 SCNetworkSetRef set
= CFArrayGetValueAtIndex(sets
, i
);
980 otherID
= SCNetworkSetGetSetID(set
);
981 if (CFEqual(setPrivate
->setID
, otherID
)) {
982 continue; // skip current set
985 otherName
= SCNetworkSetGetName(set
);
986 if ((otherName
!= NULL
) && CFEqual(name
, otherName
)) {
987 // if "name" not unique
989 _SCErrorSet(kSCStatusKeyExists
);
996 #endif /* PREVENT_DUPLICATE_SET_NAMES */
998 // if known, store non-localized name
1000 if ((name
!= NULL
) && (bundle
!= NULL
) && (non_localized
!= NULL
)) {
1001 if (localized
== NULL
) {
1002 localized
= CFBundleCopyLocalizedString(bundle
,
1003 CFSTR("DEFAULT_SET_NAME"),
1008 if (localized
!= NULL
) {
1009 if (CFEqual(name
, localized
)) {
1010 name
= non_localized
;
1015 // update the "name"
1017 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1018 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1019 if (isA_CFDictionary(entity
) ||
1020 ((entity
== NULL
) && (name
!= NULL
))) {
1021 CFMutableDictionaryRef newEntity
;
1023 if (entity
!= NULL
) {
1024 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1026 newEntity
= CFDictionaryCreateMutable(NULL
,
1028 &kCFTypeDictionaryKeyCallBacks
,
1029 &kCFTypeDictionaryValueCallBacks
);
1032 CFDictionarySetValue(newEntity
, kSCPropUserDefinedName
, name
);
1034 CFDictionaryRemoveValue(newEntity
, kSCPropUserDefinedName
);
1036 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newEntity
);
1037 CFRelease(newEntity
);
1043 if (localized
!= NULL
) CFRelease(localized
);
1044 if (non_localized
!= NULL
) CFRelease(non_localized
);
1050 SCNetworkSetSetServiceOrder(SCNetworkSetRef set
, CFArrayRef newOrder
)
1052 CFDictionaryRef dict
;
1053 CFMutableDictionaryRef newDict
;
1056 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1058 if (!isA_SCNetworkSet(set
)) {
1059 _SCErrorSet(kSCStatusInvalidArgument
);
1063 if (isA_CFArray(newOrder
)) {
1065 CFIndex n
= CFArrayGetCount(newOrder
);
1067 for (i
= 0; i
< n
; i
++) {
1068 CFStringRef serviceID
;
1070 serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1071 if (!isA_CFString(serviceID
)) {
1072 _SCErrorSet(kSCStatusInvalidArgument
);
1077 _SCErrorSet(kSCStatusInvalidArgument
);
1081 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1086 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1088 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
1090 newDict
= CFDictionaryCreateMutable(NULL
,
1092 &kCFTypeDictionaryKeyCallBacks
,
1093 &kCFTypeDictionaryValueCallBacks
);
1096 CFDictionarySetValue(newDict
, kSCPropNetServiceOrder
, newOrder
);
1097 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newDict
);
1106 #pragma mark SCNetworkSet SPIs
1110 add_supported_interfaces(CFMutableArrayRef interface_list
, SCNetworkInterfaceRef interface
)
1113 CFArrayRef interface_types
;
1116 interface_types
= SCNetworkInterfaceGetSupportedInterfaceTypes(interface
);
1117 n
= (interface_types
!= NULL
) ? CFArrayGetCount(interface_types
) : 0;
1118 for (i
= 0; i
< n
; i
++) {
1119 SCNetworkInterfaceRef parent
;
1120 CFStringRef interface_type
;
1122 interface_type
= CFArrayGetValueAtIndex(interface_types
, i
);
1123 parent
= SCNetworkInterfaceCreateWithInterface(interface
, interface_type
);
1124 if (parent
!= NULL
) {
1125 CFArrayAppendValue(interface_list
, parent
);
1133 static CFSetRef
/* of SCNetworkInterfaceRef's */
1134 copyExcludedInterfaces(SCPreferencesRef prefs
)
1136 CFMutableSetRef excluded
;
1137 CFArrayRef interfaces
;
1139 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1141 // exclude Bond [member] interfaces
1142 interfaces
= SCBondInterfaceCopyAll(prefs
);
1143 if (interfaces
!= NULL
) {
1144 __SCBondInterfaceListCollectMembers(interfaces
, excluded
);
1145 CFRelease(interfaces
);
1148 // exclude Bridge [member] interfaces
1149 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
1150 if (interfaces
!= NULL
) {
1151 __SCBridgeInterfaceListCollectMembers(interfaces
, excluded
);
1152 CFRelease(interfaces
);
1160 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set
, CFArrayRef interfaces
)
1162 CFSetRef excluded
= NULL
;
1166 CFArrayRef services
;
1167 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1168 Boolean updated
= FALSE
;
1170 #if TARGET_OS_IPHONE
1171 CFArrayRef orphans
= NULL
;
1174 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1176 if (CFArrayGetCount(sets
) == 1) {
1177 services
= SCNetworkSetCopyServices(set
);
1178 if (services
!= NULL
) {
1179 n
= CFArrayGetCount(services
);
1180 CFRelease(services
);
1183 if ((n
== 0) && CFEqual(set
, CFArrayGetValueAtIndex(sets
, 0))) {
1184 // after a "Reset Network Settings" we need to find (and
1185 // add back) any VPN services that were orphaned.
1186 orphans
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1192 #endif // TARGET_OS_IPHONE
1194 // first, assume that we only want to add new services
1195 // for those interfaces that are not represented in the
1197 services
= SCNetworkSetCopyServices(set
);
1198 if ((services
!= NULL
) && setPrivate
->established
) {
1199 // but, if we are given an existing (or "established") set
1200 // than we only want to add new services for those interfaces
1201 // that are not represented in *any* set.
1202 CFRelease(services
);
1203 services
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1206 excluded
= copyExcludedInterfaces(setPrivate
->prefs
);
1208 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
1209 for (i
= 0; i
< n
; i
++) {
1210 SCNetworkInterfaceRef interface
;
1211 CFMutableArrayRef interface_list
;
1213 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1214 if ((excluded
!= NULL
)
1215 && CFSetContainsValue(excluded
, interface
)) {
1216 // if this interface is a member of a Bond or Bridge
1220 if (__SCNetworkServiceExistsForInterface(services
, interface
)) {
1221 // if this is not a new interface
1225 interface_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1226 CFArrayAppendValue(interface_list
, interface
);
1228 while (ok
&& (CFArrayGetCount(interface_list
) > 0)) {
1229 CFArrayRef protocol_types
;
1231 interface
= CFArrayGetValueAtIndex(interface_list
, 0);
1233 protocol_types
= SCNetworkInterfaceGetSupportedProtocolTypes(interface
);
1234 if ((protocol_types
!= NULL
) && (CFArrayGetCount(protocol_types
) > 0)) {
1235 SCNetworkServiceRef service
;
1237 service
= SCNetworkServiceCreate(setPrivate
->prefs
, interface
);
1238 if (service
== NULL
) {
1239 SCLog(TRUE
, LOG_DEBUG
,
1240 CFSTR("could not create service for \"%@\": %s\n"),
1241 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1242 SCErrorString(SCError()));
1247 ok
= SCNetworkServiceEstablishDefaultConfiguration(service
);
1249 SCLog(TRUE
, LOG_DEBUG
,
1250 CFSTR("could not estabish default configuration for \"%@\": %s\n"),
1251 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1252 SCErrorString(SCError()));
1253 SCNetworkServiceRemove(service
);
1259 CFStringRef newName
;
1261 ok
= SCNetworkSetAddService(set
, service
);
1266 if (SCError() != kSCStatusKeyExists
) {
1267 SCLog(TRUE
, LOG_DEBUG
,
1268 CFSTR("could not add service for \"%@\": %s\n"),
1269 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1270 SCErrorString(SCError()));
1271 SCNetworkServiceRemove(service
);
1276 // we have two interfaces with the same service
1277 // name, acquire a new, hopefully unique, name
1279 newName
= __SCNetworkServiceNextName(service
);
1280 if (newName
== NULL
) {
1281 SCLog(TRUE
, LOG_DEBUG
,
1282 CFSTR("could not set unique name for \"%@\": %s\n"),
1283 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1284 SCErrorString(SCError()));
1285 SCNetworkServiceRemove(service
);
1290 ok
= SCNetworkServiceSetName(service
, newName
);
1296 if (SCError() != kSCStatusKeyExists
) {
1297 SCLog(TRUE
, LOG_DEBUG
,
1298 CFSTR("could not set unique name for \"%@\": %s\n"),
1299 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1300 SCErrorString(SCError()));
1301 SCNetworkServiceRemove(service
);
1310 add_supported_interfaces(interface_list
, interface
);
1315 CFArrayRemoveValueAtIndex(interface_list
, 0);
1317 CFRelease(interface_list
);
1319 if (services
!= NULL
) CFRelease(services
);
1320 if (excluded
!= NULL
) CFRelease(excluded
);
1322 #if TARGET_OS_IPHONE
1323 if (orphans
!= NULL
) {
1324 if (ok
&& updated
) {
1326 CFIndex n
= CFArrayGetCount(orphans
);
1328 for (i
= 0; i
< n
; i
++) {
1329 SCNetworkServiceRef service
;
1331 service
= CFArrayGetValueAtIndex(orphans
, i
);
1332 if (_SCNetworkServiceIsVPN(service
)) {
1333 ok
= SCNetworkSetAddService(set
, service
);
1343 #endif // TARGET_OS_IPHONE
1345 if (ok
&& !updated
) {
1346 // if no changes were made
1347 _SCErrorSet(kSCStatusOK
);
1355 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set
)
1357 CFArrayRef interfaces
;
1358 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1359 Boolean updated
= FALSE
;
1361 if (!isA_SCNetworkSet(set
)) {
1362 _SCErrorSet(kSCStatusInvalidArgument
);
1366 interfaces
= _SCNetworkInterfaceCopyAllWithPreferences(setPrivate
->prefs
);
1367 if (interfaces
!= NULL
) {
1368 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
);
1369 CFRelease(interfaces
);
1377 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set
, SCNetworkInterfaceRef interface
)
1379 CFArrayRef interfaces
;
1382 if (!isA_SCNetworkSet(set
)) {
1383 _SCErrorSet(kSCStatusInvalidArgument
);
1387 if (!isA_SCNetworkInterface(interface
)) {
1388 _SCErrorSet(kSCStatusInvalidArgument
);
1392 interfaces
= CFArrayCreate(NULL
, (const void **)&interface
, 1, &kCFTypeArrayCallBacks
);
1393 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
);
1394 CFRelease(interfaces
);
1401 SCNetworkSetCopySelectedVPNService(SCNetworkSetRef set
)
1405 SCNetworkServiceRef selected
= NULL
;
1406 CFArrayRef services
;
1407 CFMutableArrayRef services_vpn
= NULL
;
1409 if (!isA_SCNetworkSet(set
)) {
1410 _SCErrorSet(kSCStatusInvalidArgument
);
1414 services
= SCNetworkSetCopyServices(set
);
1415 if (services
!= NULL
) {
1416 n
= CFArrayGetCount(services
);
1417 for (i
= 0; i
< n
; i
++) {
1418 SCNetworkServiceRef service
;
1420 service
= CFArrayGetValueAtIndex(services
, i
);
1421 if (!SCNetworkServiceGetEnabled(service
)) {
1426 if (!_SCNetworkServiceIsVPN(service
)) {
1427 // if not VPN service
1431 if (services_vpn
== NULL
) {
1432 services_vpn
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1434 CFArrayAppendValue(services_vpn
, service
);
1437 CFRelease(services
);
1440 if (services_vpn
== NULL
) {
1441 // if no VPN services
1445 n
= CFArrayGetCount(services_vpn
);
1448 CFMutableArrayRef sorted
;
1450 order
= SCNetworkSetGetServiceOrder(set
);
1451 sorted
= CFArrayCreateMutableCopy(NULL
, 0, services_vpn
);
1452 CFArraySortValues(sorted
,
1453 CFRangeMake(0, CFArrayGetCount(sorted
)),
1454 _SCNetworkServiceCompare
,
1456 CFRelease(services_vpn
);
1457 services_vpn
= sorted
;
1460 #if TARGET_OS_IPHONE
1462 CFStringRef serviceID_prefs
;
1464 #define VPN_PREFERENCES CFSTR("com.apple.mobilevpn")
1465 #define VPN_SERVICE_ID CFSTR("activeVPNID")
1467 CFPreferencesAppSynchronize(VPN_PREFERENCES
);
1468 serviceID_prefs
= CFPreferencesCopyAppValue(VPN_SERVICE_ID
, VPN_PREFERENCES
);
1469 if (serviceID_prefs
!= NULL
) {
1470 for (i
= 0; i
< n
; i
++) {
1471 SCNetworkServiceRef service
;
1472 CFStringRef serviceID
;
1474 service
= CFArrayGetValueAtIndex(services_vpn
, i
);
1475 serviceID
= SCNetworkServiceGetServiceID(service
);
1476 if (CFEqual(serviceID
, serviceID_prefs
)) {
1484 CFRelease(serviceID_prefs
);
1487 #endif // TARGET_OS_IPHONE
1489 if (selected
== NULL
) {
1490 selected
= CFArrayGetValueAtIndex(services_vpn
, 0);
1494 CFRelease(services_vpn
);
1500 SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
1503 CFArrayRef services
;
1505 if (!isA_SCNetworkSet(set
)) {
1506 _SCErrorSet(kSCStatusInvalidArgument
);
1510 if (!isA_SCNetworkService(service
) || !_SCNetworkServiceIsVPN(service
)) {
1511 _SCErrorSet(kSCStatusInvalidArgument
);
1515 services
= SCNetworkSetCopyServices(set
);
1516 if (services
!= NULL
) {
1518 CFIndex n
= CFArrayGetCount(services
);
1520 if (!CFArrayContainsValue(services
, CFRangeMake(0, n
), service
)) {
1521 // if selected service not a member of the current set
1522 _SCErrorSet(kSCStatusInvalidArgument
);
1527 for (i
= 0; ok
&& (i
< n
); i
++) {
1528 SCNetworkServiceRef vpn
;
1530 vpn
= CFArrayGetValueAtIndex(services
, i
);
1531 if (!_SCNetworkServiceIsVPN(vpn
)) {
1532 // if not VPN service
1536 ok
= SCNetworkServiceSetEnabled(vpn
, CFEqual(service
, vpn
));
1542 if (services
!= NULL
) CFRelease(services
);