2 * Copyright (c) 2004-2007, 2009 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 _serviceIsVPN(SCNetworkServiceRef service
)
175 SCNetworkInterfaceRef interface
;
176 CFStringRef interfaceType
;
178 interface
= SCNetworkServiceGetInterface(service
);
179 if (interface
== NULL
) {
183 interfaceType
= SCNetworkInterfaceGetInterfaceType(interface
);
184 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypePPP
)) {
185 interface
= SCNetworkInterfaceGetInterface(interface
);
186 if (interface
== NULL
) {
190 interfaceType
= SCNetworkInterfaceGetInterfaceType(interface
);
191 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypeL2TP
)) {
194 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypePPTP
)) {
199 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypeIPSec
)) {
208 _serviceOrder(SCNetworkServiceRef service
)
210 SCNetworkInterfaceRef interface
;
212 interface
= SCNetworkServiceGetInterface(service
);
213 if ((interface
== NULL
) || _serviceIsVPN(service
)) {
214 return 100000; // if unknown or VPN interface, sort last
217 return __SCNetworkInterfaceOrder(interface
);
222 _serviceOrder_add(SCNetworkSetRef set
, SCNetworkServiceRef service
)
226 CFMutableArrayRef newOrder
;
228 CFStringRef serviceID
;
229 CFIndex serviceOrder
;
230 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
233 order
= SCNetworkSetGetServiceOrder(set
);
235 newOrder
= CFArrayCreateMutableCopy(NULL
, 0, order
);
237 newOrder
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
239 n
= CFArrayGetCount(newOrder
);
241 serviceID
= SCNetworkServiceGetServiceID(service
);
242 if (CFArrayContainsValue(newOrder
, CFRangeMake(0, n
), serviceID
)) {
243 // if serviceID already present
247 serviceOrder
= _serviceOrder(service
);
250 for (i
= 0; i
< n
; i
++) {
252 SCNetworkServiceRef slotService
;
253 CFStringRef slotServiceID
;
255 slotServiceID
= CFArrayGetValueAtIndex(newOrder
, i
);
256 if (!isA_CFString(slotServiceID
)) {
261 slotService
= SCNetworkServiceCopy(setPrivate
->prefs
, slotServiceID
);
262 if (slotService
== NULL
) {
263 // if serviceID not valid
267 slotOrder
= _serviceOrder(slotService
);
268 if (serviceOrder
>= slotOrder
) {
269 // add the service *after* this one
273 CFRelease(slotService
);
276 CFArrayInsertValueAtIndex(newOrder
, slot
, serviceID
);
277 (void) SCNetworkSetSetServiceOrder(set
, newOrder
);
288 _serviceOrder_remove(SCNetworkSetRef set
, SCNetworkServiceRef service
)
290 CFMutableArrayRef newOrder
;
292 CFStringRef serviceID
;
294 order
= SCNetworkSetGetServiceOrder(set
);
299 serviceID
= SCNetworkServiceGetServiceID(service
);
301 newOrder
= CFArrayCreateMutableCopy(NULL
, 0, order
);
305 i
= CFArrayGetFirstIndexOfValue(newOrder
,
306 CFRangeMake(0, CFArrayGetCount(newOrder
)),
308 if (i
== kCFNotFound
) {
312 CFArrayRemoveValueAtIndex(newOrder
, i
);
314 (void) SCNetworkSetSetServiceOrder(set
, newOrder
);
322 #pragma mark SCNetworkSet APIs
329 SCNetworkSetAddService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
331 SCNetworkInterfaceRef interface
;
332 CFArrayRef interface_config
= NULL
;
336 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
337 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
339 if (!isA_SCNetworkSet(set
)) {
340 _SCErrorSet(kSCStatusInvalidArgument
);
344 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
345 _SCErrorSet(kSCStatusInvalidArgument
);
349 #define PREVENT_DUPLICATE_SERVICE_NAMES
350 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
353 name
= SCNetworkServiceGetName(service
);
357 services
= SCNetworkSetCopyServices(set
);
358 if (services
!= NULL
) {
362 n
= CFArrayGetCount(services
);
363 for (i
= 0; i
< n
; i
++) {
364 CFStringRef otherName
;
365 SCNetworkServiceRef otherService
;
367 otherService
= CFArrayGetValueAtIndex(services
, i
);
368 otherName
= SCNetworkServiceGetName(otherService
);
369 if ((otherName
!= NULL
) && CFEqual(name
, otherName
)) {
371 * if a service with the same "name" is
372 * already a member of the set.
375 _SCErrorSet(kSCStatusKeyExists
);
383 #endif // PREVENT_DUPLICATE_SERVICE_NAMES
385 //#define PREVENT_DUPLICATE_SETS
386 #ifdef PREVENT_DUPLICATE_SETS
389 // ensure that each service is only a member of ONE set
390 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
395 n
= CFArrayGetCount(sets
);
396 for (i
= 0; i
< n
; i
++) {
401 set
= CFArrayGetValueAtIndex(sets
, i
);
402 services
= SCNetworkSetCopyServices(set
);
403 found
= CFArrayContainsValue(services
,
404 CFRangeMake(0, CFArrayGetCount(services
)),
410 _SCErrorSet(kSCStatusKeyExists
);
416 #endif /* PREVENT_DUPLICATE_SETS */
418 // get the [deep] interface configuration settings
419 interface
= SCNetworkServiceGetInterface(service
);
420 if (interface
!= NULL
) {
421 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(set
, interface
);
424 // create the link between "set" and the "service"
425 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
, // allocator
426 setPrivate
->setID
, // set
427 servicePrivate
->serviceID
, // service
429 link
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
430 servicePrivate
->serviceID
, // service
432 ok
= SCPreferencesPathSetLink(setPrivate
->prefs
, path
, link
);
439 // push the [deep] interface configuration into all sets which contain this service.
440 if (interface
!= NULL
) {
441 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, interface_config
);
444 // add service to ServiceOrder
445 _serviceOrder_add(set
, service
);
447 // mark set as no longer "new"
448 setPrivate
->established
= TRUE
;
452 if (interface_config
!= NULL
) CFRelease(interface_config
);
458 SCNetworkSetCopy(SCPreferencesRef prefs
, CFStringRef setID
)
460 CFDictionaryRef entity
;
462 SCNetworkSetPrivateRef setPrivate
;
464 if (!isA_CFString(setID
)) {
465 _SCErrorSet(kSCStatusInvalidArgument
);
469 path
= SCPreferencesPathKeyCreateSet(NULL
, setID
);
470 entity
= SCPreferencesPathGetValue(prefs
, path
);
473 if (!isA_CFDictionary(entity
)) {
474 _SCErrorSet(kSCStatusNoKey
);
478 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
480 // mark set as "old" (already established)
481 setPrivate
->established
= TRUE
;
483 return (SCNetworkSetRef
)setPrivate
;
488 _SCNetworkServiceExistsForInterface(CFArrayRef services
, SCNetworkInterfaceRef interface
)
493 n
= isA_CFArray(services
) ? CFArrayGetCount(services
) : 0;
494 for (i
= 0; i
< n
; i
++) {
495 SCNetworkServiceRef service
;
496 SCNetworkInterfaceRef service_interface
;
498 service
= CFArrayGetValueAtIndex(services
, i
);
500 service_interface
= SCNetworkServiceGetInterface(service
);
501 while (service_interface
!= NULL
) {
502 if (CFEqual(interface
, service_interface
)) {
506 service_interface
= SCNetworkInterfaceGetInterface(service_interface
);
515 SCNetworkSetContainsInterface(SCNetworkSetRef set
, SCNetworkInterfaceRef interface
)
517 Boolean found
= FALSE
;
520 services
= SCNetworkSetCopyServices(set
);
521 if (services
!= NULL
) {
522 found
= _SCNetworkServiceExistsForInterface(services
, interface
);
530 CFArrayRef
/* of SCNetworkSetRef's */
531 SCNetworkSetCopyAll(SCPreferencesRef prefs
)
533 CFMutableArrayRef array
;
536 CFDictionaryRef sets
;
538 path
= SCPreferencesPathKeyCreateSets(NULL
);
539 sets
= SCPreferencesPathGetValue(prefs
, path
);
542 if ((sets
!= NULL
) && !isA_CFDictionary(sets
)) {
546 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
548 n
= (sets
!= NULL
) ? CFDictionaryGetCount(sets
) : 0;
551 const void * keys_q
[N_QUICK
];
552 const void ** keys
= keys_q
;
553 const void * vals_q
[N_QUICK
];
554 const void ** vals
= vals_q
;
556 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
557 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
558 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
560 CFDictionaryGetKeysAndValues(sets
, keys
, vals
);
561 for (i
= 0; i
< n
; i
++) {
562 SCNetworkSetPrivateRef setPrivate
;
564 if (!isA_CFDictionary(vals
[i
])) {
567 CFSTR("SCNetworkSetCopyAll(): error w/set \"%@\"\n"),
572 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, keys
[i
]);
574 // mark set as "old" (already established)
575 setPrivate
->established
= TRUE
;
577 CFArrayAppendValue(array
, (SCNetworkSetRef
)setPrivate
);
578 CFRelease(setPrivate
);
580 if (keys
!= keys_q
) {
581 CFAllocatorDeallocate(NULL
, keys
);
582 CFAllocatorDeallocate(NULL
, vals
);
591 SCNetworkSetCopyCurrent(SCPreferencesRef prefs
)
593 CFArrayRef components
;
594 CFStringRef currentID
;
595 SCNetworkSetPrivateRef setPrivate
= NULL
;
597 currentID
= SCPreferencesGetValue(prefs
, kSCPrefCurrentSet
);
598 if (!isA_CFString(currentID
)) {
602 components
= CFStringCreateArrayBySeparatingStrings(NULL
, currentID
, CFSTR("/"));
603 if (CFArrayGetCount(components
) == 3) {
607 setID
= CFArrayGetValueAtIndex(components
, 2);
608 path
= SCPreferencesPathKeyCreateSet(NULL
, setID
);
609 if (CFEqual(path
, currentID
)) {
610 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
612 // mark set as "old" (already established)
613 setPrivate
->established
= TRUE
;
615 SCLog(TRUE
, LOG_ERR
, CFSTR("SCNetworkSetCopyCurrent(): preferences are non-conformant"));
619 CFRelease(components
);
621 return (SCNetworkSetRef
)setPrivate
;
625 CFArrayRef
/* of SCNetworkServiceRef's */
626 SCNetworkSetCopyServices(SCNetworkSetRef set
)
628 CFMutableArrayRef array
;
629 CFDictionaryRef dict
;
632 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
634 if (!isA_SCNetworkSet(set
)) {
635 _SCErrorSet(kSCStatusInvalidArgument
);
639 path
= SCPreferencesPathKeyCreateSetNetworkService(NULL
, setPrivate
->setID
, NULL
);
640 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
642 if ((dict
!= NULL
) && !isA_CFDictionary(dict
)) {
646 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
648 n
= (dict
!= NULL
) ? CFDictionaryGetCount(dict
) : 0;
651 const void * keys_q
[N_QUICK
];
652 const void ** keys
= keys_q
;
654 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
655 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
657 CFDictionaryGetKeysAndValues(dict
, keys
, NULL
);
658 for (i
= 0; i
< n
; i
++) {
659 CFArrayRef components
;
662 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
664 (CFStringRef
)keys
[i
],
666 link
= SCPreferencesPathGetLink(setPrivate
->prefs
, path
);
671 CFSTR("SCNetworkSetCopyServices(): service \"%@\" for set \"%@\" is not a link\n"),
674 continue; // if the service is not a link
677 components
= CFStringCreateArrayBySeparatingStrings(NULL
, link
, CFSTR("/"));
678 if (CFArrayGetCount(components
) == 3) {
679 CFStringRef serviceID
;
681 serviceID
= CFArrayGetValueAtIndex(components
, 2);
682 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
683 serviceID
, // service
685 if (CFEqual(path
, link
)) {
686 SCNetworkServicePrivateRef servicePrivate
;
688 servicePrivate
= __SCNetworkServiceCreatePrivate(NULL
,
692 CFArrayAppendValue(array
, (SCNetworkServiceRef
)servicePrivate
);
693 CFRelease(servicePrivate
);
697 CFRelease(components
);
699 if (keys
!= keys_q
) {
700 CFAllocatorDeallocate(NULL
, keys
);
709 SCNetworkSetCreate(SCPreferencesRef prefs
)
711 CFArrayRef components
;
715 SCNetworkSetPrivateRef setPrivate
;
717 prefix
= SCPreferencesPathKeyCreateSets(NULL
);
718 path
= __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs
, prefix
);
719 if (path
== NULL
) path
= SCPreferencesPathCreateUniqueChild(prefs
, prefix
);
725 components
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
728 setID
= CFArrayGetValueAtIndex(components
, 2);
729 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
730 CFRelease(components
);
732 // mark set as "new" (not yet established)
733 setPrivate
->established
= FALSE
;
735 return (SCNetworkSetRef
)setPrivate
;
740 SCNetworkSetGetSetID(SCNetworkSetRef set
)
742 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
744 if (!isA_SCNetworkSet(set
)) {
745 _SCErrorSet(kSCStatusInvalidArgument
);
749 return setPrivate
->setID
;
754 SCNetworkSetGetName(SCNetworkSetRef set
)
757 CFDictionaryRef entity
;
759 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
761 if (!isA_SCNetworkSet(set
)) {
762 _SCErrorSet(kSCStatusInvalidArgument
);
766 if (setPrivate
->name
!= NULL
) {
767 return setPrivate
->name
;
770 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
771 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
774 if (isA_CFDictionary(entity
)) {
777 name
= CFDictionaryGetValue(entity
, kSCPropUserDefinedName
);
778 if (isA_CFString(name
)) {
779 setPrivate
->name
= CFRetain(name
);
783 bundle
= _SC_CFBundleGet();
784 if (bundle
!= NULL
) {
785 if (setPrivate
->name
!= NULL
) {
786 CFStringRef non_localized
;
788 non_localized
= _SC_CFBundleCopyNonLocalizedString(bundle
,
789 CFSTR("DEFAULT_SET_NAME"),
792 if (non_localized
!= NULL
) {
793 if (CFEqual(setPrivate
->name
, non_localized
)) {
794 CFStringRef localized
;
796 // if "Automatic", return localized name
797 localized
= CFBundleCopyLocalizedString(bundle
,
798 CFSTR("DEFAULT_SET_NAME"),
801 if (localized
!= NULL
) {
802 CFRelease(setPrivate
->name
);
803 setPrivate
->name
= localized
;
807 CFRelease(non_localized
);
812 return setPrivate
->name
;
816 CFArrayRef
/* of serviceID CFStringRef's */
817 SCNetworkSetGetServiceOrder(SCNetworkSetRef set
)
819 CFDictionaryRef dict
;
821 CFArrayRef serviceOrder
;
822 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
824 if (!isA_SCNetworkSet(set
)) {
825 _SCErrorSet(kSCStatusInvalidArgument
);
829 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
834 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
836 if (!isA_CFDictionary(dict
)) {
840 serviceOrder
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
);
841 serviceOrder
= isA_CFArray(serviceOrder
);
848 SCNetworkSetGetTypeID(void)
850 pthread_once(&initialized
, __SCNetworkSetInitialize
); /* initialize runtime */
851 return __kSCNetworkSetTypeID
;
856 SCNetworkSetRemove(SCNetworkSetRef set
)
858 CFStringRef currentPath
;
861 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
863 if (!isA_SCNetworkSet(set
)) {
864 _SCErrorSet(kSCStatusInvalidArgument
);
868 currentPath
= SCPreferencesGetValue(setPrivate
->prefs
, kSCPrefCurrentSet
);
869 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
870 if (!isA_CFString(currentPath
) || !CFEqual(currentPath
, path
)) {
871 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
880 SCNetworkSetRemoveService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
882 SCNetworkInterfaceRef interface
;
883 CFArrayRef interface_config
= NULL
;
886 int sc_status
= kSCStatusOK
;
887 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
888 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
890 if (!isA_SCNetworkSet(set
)) {
891 _SCErrorSet(kSCStatusInvalidArgument
);
895 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
896 _SCErrorSet(kSCStatusInvalidArgument
);
900 // remove service from ServiceOrder
901 _serviceOrder_remove(set
, service
);
903 // get the [deep] interface configuration settings
904 interface
= SCNetworkServiceGetInterface(service
);
905 if (interface
!= NULL
) {
906 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(set
, interface
);
907 if (interface_config
!= NULL
) {
908 // remove the interface configuration from all sets which contain this service.
909 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, NULL
);
913 // remove the link between "set" and the "service"
914 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
916 servicePrivate
->serviceID
,
918 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
920 sc_status
= SCError(); // preserve the error
924 // push the [deep] interface configuration [back] into all sets which contain the service.
925 if (interface_config
!= NULL
) {
926 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, interface_config
);
929 if (interface_config
!= NULL
) CFRelease(interface_config
);
931 _SCErrorSet(sc_status
);
938 SCNetworkSetSetCurrent(SCNetworkSetRef set
)
942 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
944 if (!isA_SCNetworkSet(set
)) {
945 _SCErrorSet(kSCStatusInvalidArgument
);
949 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
950 ok
= SCPreferencesSetValue(setPrivate
->prefs
, kSCPrefCurrentSet
, path
);
957 SCNetworkSetSetName(SCNetworkSetRef set
, CFStringRef name
)
959 CFBundleRef bundle
= NULL
;
960 CFDictionaryRef entity
;
961 CFStringRef localized
= NULL
;
962 CFStringRef non_localized
= NULL
;
965 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
967 if (!isA_SCNetworkSet(set
)) {
968 _SCErrorSet(kSCStatusInvalidArgument
);
972 if ((name
!= NULL
) && !isA_CFString(name
)) {
973 _SCErrorSet(kSCStatusInvalidArgument
);
977 // if known, compare against localized name
980 bundle
= _SC_CFBundleGet();
981 if (bundle
!= NULL
) {
982 non_localized
= _SC_CFBundleCopyNonLocalizedString(bundle
,
983 CFSTR("DEFAULT_SET_NAME"),
986 if (non_localized
!= NULL
) {
987 if (CFEqual(name
, non_localized
)) {
988 localized
= CFBundleCopyLocalizedString(bundle
,
989 CFSTR("DEFAULT_SET_NAME"),
992 if (localized
!= NULL
) {
1000 #define PREVENT_DUPLICATE_SET_NAMES
1001 #ifdef PREVENT_DUPLICATE_SET_NAMES
1005 // ensure that each set is uniquely named
1007 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1012 n
= CFArrayGetCount(sets
);
1013 for (i
= 0; i
< n
; i
++) {
1014 CFStringRef otherID
;
1015 CFStringRef otherName
;
1016 SCNetworkSetRef set
= CFArrayGetValueAtIndex(sets
, i
);
1018 otherID
= SCNetworkSetGetSetID(set
);
1019 if (CFEqual(setPrivate
->setID
, otherID
)) {
1020 continue; // skip current set
1023 otherName
= SCNetworkSetGetName(set
);
1024 if ((otherName
!= NULL
) && CFEqual(name
, otherName
)) {
1025 // if "name" not unique
1027 _SCErrorSet(kSCStatusKeyExists
);
1034 #endif /* PREVENT_DUPLICATE_SET_NAMES */
1036 // if known, store non-localized name
1038 if ((name
!= NULL
) && (bundle
!= NULL
) && (non_localized
!= NULL
)) {
1039 if (localized
== NULL
) {
1040 localized
= CFBundleCopyLocalizedString(bundle
,
1041 CFSTR("DEFAULT_SET_NAME"),
1046 if (localized
!= NULL
) {
1047 if (CFEqual(name
, localized
)) {
1048 name
= non_localized
;
1053 // update the "name"
1055 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1056 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1057 if (isA_CFDictionary(entity
) ||
1058 ((entity
== NULL
) && (name
!= NULL
))) {
1059 CFMutableDictionaryRef newEntity
;
1061 if (entity
!= NULL
) {
1062 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1064 newEntity
= CFDictionaryCreateMutable(NULL
,
1066 &kCFTypeDictionaryKeyCallBacks
,
1067 &kCFTypeDictionaryValueCallBacks
);
1070 CFDictionarySetValue(newEntity
, kSCPropUserDefinedName
, name
);
1072 CFDictionaryRemoveValue(newEntity
, kSCPropUserDefinedName
);
1074 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newEntity
);
1075 CFRelease(newEntity
);
1081 if (localized
!= NULL
) CFRelease(localized
);
1082 if (non_localized
!= NULL
) CFRelease(non_localized
);
1088 SCNetworkSetSetServiceOrder(SCNetworkSetRef set
, CFArrayRef newOrder
)
1090 CFDictionaryRef dict
;
1091 CFMutableDictionaryRef newDict
;
1094 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1096 if (!isA_SCNetworkSet(set
)) {
1097 _SCErrorSet(kSCStatusInvalidArgument
);
1101 if (isA_CFArray(newOrder
)) {
1103 CFIndex n
= CFArrayGetCount(newOrder
);
1105 for (i
= 0; i
< n
; i
++) {
1106 CFStringRef serviceID
;
1108 serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1109 if (!isA_CFString(serviceID
)) {
1110 _SCErrorSet(kSCStatusInvalidArgument
);
1115 _SCErrorSet(kSCStatusInvalidArgument
);
1119 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1124 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1126 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
1128 newDict
= CFDictionaryCreateMutable(NULL
,
1130 &kCFTypeDictionaryKeyCallBacks
,
1131 &kCFTypeDictionaryValueCallBacks
);
1134 CFDictionarySetValue(newDict
, kSCPropNetServiceOrder
, newOrder
);
1135 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newDict
);
1144 #pragma mark SCNetworkSet SPIs
1148 add_supported_interfaces(CFMutableArrayRef interface_list
, SCNetworkInterfaceRef interface
)
1151 CFArrayRef interface_types
;
1154 interface_types
= SCNetworkInterfaceGetSupportedInterfaceTypes(interface
);
1155 n
= (interface_types
!= NULL
) ? CFArrayGetCount(interface_types
) : 0;
1156 for (i
= 0; i
< n
; i
++) {
1157 SCNetworkInterfaceRef parent
;
1158 CFStringRef interface_type
;
1160 interface_type
= CFArrayGetValueAtIndex(interface_types
, i
);
1161 parent
= SCNetworkInterfaceCreateWithInterface(interface
, interface_type
);
1162 if (parent
!= NULL
) {
1163 CFArrayAppendValue(interface_list
, parent
);
1173 next_service_name(SCNetworkServiceRef service
)
1175 CFArrayRef components
;
1178 CFMutableArrayRef newComponents
;
1181 name
= SCNetworkServiceGetName(service
);
1186 components
= CFStringCreateArrayBySeparatingStrings(NULL
, name
, CFSTR(" "));
1187 if (components
!= NULL
) {
1188 newComponents
= CFArrayCreateMutableCopy(NULL
, 0, components
);
1189 CFRelease(components
);
1191 newComponents
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1192 CFArrayAppendValue(newComponents
, name
);
1195 n
= CFArrayGetCount(newComponents
);
1199 str
= CFArrayGetValueAtIndex(newComponents
, n
- 1);
1200 suffix
= CFStringGetIntValue(str
);
1202 CFArrayRemoveValueAtIndex(newComponents
, n
- 1);
1208 name
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), suffix
);
1209 CFArrayAppendValue(newComponents
, name
);
1212 name
= CFStringCreateByCombiningStrings(NULL
, newComponents
, CFSTR(" "));
1213 CFRelease(newComponents
);
1220 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set
, CFArrayRef interfaces
)
1225 CFArrayRef services
;
1226 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1227 Boolean updated
= FALSE
;
1229 // first, assume that we only want to add new services
1230 // for those interfaces that are not represented in the
1232 services
= SCNetworkSetCopyServices(set
);
1233 if ((services
!= NULL
) && setPrivate
->established
) {
1234 // but, if we are given an existing (or "established") set
1235 // than we only want to add new services for those interfaces
1236 // that are not represented in *any* set.
1237 CFRelease(services
);
1238 services
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1241 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
1242 for (i
= 0; i
< n
; i
++) {
1243 SCNetworkInterfaceRef interface
;
1244 CFMutableArrayRef interface_list
;
1246 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1247 if (_SCNetworkServiceExistsForInterface(services
, interface
)) {
1248 // if this is not a new interface
1252 interface_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1253 CFArrayAppendValue(interface_list
, interface
);
1255 while (ok
&& (CFArrayGetCount(interface_list
) > 0)) {
1256 CFArrayRef protocol_types
;
1258 interface
= CFArrayGetValueAtIndex(interface_list
, 0);
1260 protocol_types
= SCNetworkInterfaceGetSupportedProtocolTypes(interface
);
1261 if ((protocol_types
!= NULL
) && (CFArrayGetCount(protocol_types
) > 0)) {
1262 SCNetworkServiceRef service
;
1264 service
= SCNetworkServiceCreate(setPrivate
->prefs
, interface
);
1265 if (service
== NULL
) {
1266 SCLog(TRUE
, LOG_DEBUG
,
1267 CFSTR("could not create service for \"%@\": %s\n"),
1268 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1269 SCErrorString(SCError()));
1274 ok
= SCNetworkServiceEstablishDefaultConfiguration(service
);
1276 SCLog(TRUE
, LOG_DEBUG
,
1277 CFSTR("could not estabish default configuration for \"%@\": %s\n"),
1278 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1279 SCErrorString(SCError()));
1280 SCNetworkServiceRemove(service
);
1286 CFStringRef newName
;
1288 ok
= SCNetworkSetAddService(set
, service
);
1293 if (SCError() != kSCStatusKeyExists
) {
1294 SCLog(TRUE
, LOG_DEBUG
,
1295 CFSTR("could not add service for \"%@\": %s\n"),
1296 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1297 SCErrorString(SCError()));
1298 SCNetworkServiceRemove(service
);
1303 // we have two interfaces with the same service
1304 // name, acquire a new, hopefully unique, name
1306 newName
= next_service_name(service
);
1307 if (newName
== NULL
) {
1308 SCLog(TRUE
, LOG_DEBUG
,
1309 CFSTR("could not set unique name for \"%@\": %s\n"),
1310 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1311 SCErrorString(SCError()));
1312 SCNetworkServiceRemove(service
);
1317 ok
= SCNetworkServiceSetName(service
, newName
);
1323 if (SCError() != kSCStatusKeyExists
) {
1324 SCLog(TRUE
, LOG_DEBUG
,
1325 CFSTR("could not set unique name for \"%@\": %s\n"),
1326 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1327 SCErrorString(SCError()));
1328 SCNetworkServiceRemove(service
);
1337 add_supported_interfaces(interface_list
, interface
);
1342 CFArrayRemoveValueAtIndex(interface_list
, 0);
1344 CFRelease(interface_list
);
1346 if (services
!= NULL
) CFRelease(services
);
1348 if (ok
&& !updated
) {
1349 // if no changes were made
1350 _SCErrorSet(kSCStatusOK
);
1358 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set
)
1360 CFArrayRef interfaces
;
1363 if (!isA_SCNetworkSet(set
)) {
1364 _SCErrorSet(kSCStatusInvalidArgument
);
1368 interfaces
= SCNetworkInterfaceCopyAll();
1369 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
);
1370 if (interfaces
!= NULL
) CFRelease(interfaces
);
1377 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set
, SCNetworkInterfaceRef interface
)
1379 CFMutableArrayRef interfaces
;
1382 if (!isA_SCNetworkSet(set
)) {
1383 _SCErrorSet(kSCStatusInvalidArgument
);
1387 if (!isA_SCNetworkInterface(interface
)) {
1388 _SCErrorSet(kSCStatusInvalidArgument
);
1392 interfaces
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1393 CFArrayAppendValue(interfaces
, interface
);
1394 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
);
1395 CFRelease(interfaces
);