2 * Copyright (c) 2004-2020 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
872 components
= CFStringCreateArrayBySeparatingStrings(NULL
, link
, CFSTR("/"));
873 if (CFArrayGetCount(components
) == 3) {
874 CFStringRef serviceID
;
876 serviceID
= CFArrayGetValueAtIndex(components
, 2);
877 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
878 serviceID
, // service
880 if (CFEqual(path
, link
)) {
881 CFDictionaryRef entity
;
882 CFStringRef interfacePath
;
883 Boolean skip
= FALSE
;
885 interfacePath
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
886 serviceID
, // service
887 kSCEntNetInterface
); // entity
888 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, interfacePath
);
889 CFRelease(interfacePath
);
891 if (__SCNetworkInterfaceEntityIsPPTP(entity
)) {
892 SC_log(LOG_INFO
, "PPTP services are no longer supported");
897 SCNetworkServicePrivateRef servicePrivate
;
899 servicePrivate
= __SCNetworkServiceCreatePrivate(NULL
,
903 CFArrayAppendValue(array
, (SCNetworkServiceRef
)servicePrivate
);
904 CFRelease(servicePrivate
);
909 CFRelease(components
);
911 if (keys
!= keys_q
) {
912 CFAllocatorDeallocate(NULL
, keys
);
921 SCNetworkSetCreate(SCPreferencesRef prefs
)
923 CFArrayRef components
;
924 CFDictionaryRef entity
;
929 SCNetworkSetPrivateRef setPrivate
;
931 prefix
= SCPreferencesPathKeyCreateSets(NULL
);
932 path
= __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs
, prefix
);
933 if (path
== NULL
) path
= SCPreferencesPathCreateUniqueChild(prefs
, prefix
);
939 components
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
940 setID
= CFArrayGetValueAtIndex(components
, 2);
941 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
942 assert(setPrivate
!= NULL
);
943 CFRelease(components
);
945 // mark set as "new" (not yet established)
946 setPrivate
->established
= FALSE
;
948 // establish the set in the preferences
949 entity
= CFDictionaryCreate(NULL
,
951 &kCFTypeDictionaryKeyCallBacks
,
952 &kCFTypeDictionaryValueCallBacks
);
953 ok
= SCPreferencesPathSetValue(prefs
, path
, entity
);
957 CFRelease(setPrivate
);
961 if (setPrivate
!= NULL
) {
962 SC_log(LOG_DEBUG
, "SCNetworkSetCreate(): %@", setPrivate
);
965 return (SCNetworkSetRef
)setPrivate
;
970 _SCNetworkSetCreateDefault(SCPreferencesRef prefs
)
975 CFStringRef setName
= NULL
;
978 set
= SCNetworkSetCopyCurrent(prefs
);
980 SC_log(LOG_NOTICE
, "creating default set w/already existing set");
982 _SCErrorSet(kSCStatusKeyExists
);
986 // create a new ("Automatic") set
987 set
= SCNetworkSetCreate(prefs
);
989 SC_log(LOG_NOTICE
, "could not create \"new\" set: %s",
990 SCErrorString(SCError()));
994 setName
= copy_default_set_name(TRUE
);
995 ok
= SCNetworkSetSetName(set
, setName
);
998 // if we could not save the new set's "name"
999 SC_log(LOG_NOTICE
, "could not save the new set's name: %s",
1000 SCErrorString(SCError()));
1004 ok
= SCNetworkSetSetCurrent(set
);
1006 // if we could not make this the "current" set
1007 SC_log(LOG_NOTICE
, "could not establish new set as current: %s",
1008 SCErrorString(SCError()));
1012 model
= SCPreferencesGetValue(prefs
, MODEL
);
1013 if (model
== NULL
) {
1014 model
= _SC_hw_model(FALSE
);
1015 SCPreferencesSetValue(prefs
, MODEL
, model
);
1018 version
= SCPreferencesGetValue(prefs
, kSCPrefVersion
);
1019 if (version
== NULL
) {
1020 const int new_version
= NETWORK_CONFIGURATION_VERSION
;
1022 version
= CFNumberCreate(NULL
, kCFNumberIntType
, &new_version
);
1023 SCPreferencesSetValue(prefs
, kSCPrefVersion
, version
);
1029 if (!ok
&& (set
!= NULL
)) {
1030 SCNetworkSetRemove(set
);
1039 SCNetworkSetGetSetID(SCNetworkSetRef set
)
1041 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1043 if (!isA_SCNetworkSet(set
)) {
1044 _SCErrorSet(kSCStatusInvalidArgument
);
1048 return setPrivate
->setID
;
1053 SCNetworkSetGetName(SCNetworkSetRef set
)
1055 CFDictionaryRef entity
;
1057 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1059 if (!isA_SCNetworkSet(set
)) {
1060 _SCErrorSet(kSCStatusInvalidArgument
);
1064 if (setPrivate
->name
!= NULL
) {
1065 return setPrivate
->name
;
1068 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1069 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1072 if (isA_CFDictionary(entity
)) {
1075 name
= CFDictionaryGetValue(entity
, kSCPropUserDefinedName
);
1076 if (isA_CFString(name
)) {
1077 setPrivate
->name
= CFRetain(name
);
1081 if (setPrivate
->name
!= NULL
) {
1082 CFStringRef non_localized
;
1084 non_localized
= copy_default_set_name(FALSE
);
1085 if (CFEqual(setPrivate
->name
, non_localized
)) {
1086 CFStringRef localized
;
1088 // if "Automatic", return localized name
1089 localized
= copy_default_set_name(TRUE
);
1090 CFRelease(setPrivate
->name
);
1091 setPrivate
->name
= localized
;
1094 CFRelease(non_localized
);
1097 return setPrivate
->name
;
1101 CFArrayRef
/* of serviceID CFStringRef's */
1102 SCNetworkSetGetServiceOrder(SCNetworkSetRef set
)
1104 CFDictionaryRef dict
;
1106 CFArrayRef serviceOrder
;
1107 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1109 if (!isA_SCNetworkSet(set
)) {
1110 _SCErrorSet(kSCStatusInvalidArgument
);
1114 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1119 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1121 if (!isA_CFDictionary(dict
)) {
1125 serviceOrder
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
);
1126 serviceOrder
= isA_CFArray(serviceOrder
);
1128 return serviceOrder
;
1133 SCNetworkSetGetTypeID(void)
1135 pthread_once(&initialized
, __SCNetworkSetInitialize
); /* initialize runtime */
1136 return __kSCNetworkSetTypeID
;
1140 #if TARGET_OS_IPHONE
1142 isDefaultSet(SCNetworkSetRef set
)
1144 CFStringRef defaultName
;
1145 Boolean isDefault
= FALSE
;
1146 CFStringRef setName
;
1148 defaultName
= copy_default_set_name(TRUE
);
1149 setName
= SCNetworkSetGetName(set
);
1150 isDefault
= _SC_CFEqual(setName
, defaultName
);
1151 CFRelease(defaultName
);
1155 #endif // TARGET_OS_IPHONE
1159 SCNetworkSetRemove(SCNetworkSetRef set
)
1161 CFStringRef currentPath
;
1164 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1166 if (!isA_SCNetworkSet(set
)) {
1167 _SCErrorSet(kSCStatusInvalidArgument
);
1171 if (!__SCNetworkSetExists(set
)) {
1172 SC_log(LOG_ERR
, "SCNetworkSetRemove() w/removed set\n set = %@", set
);
1173 _SC_crash_once("SCNetworkSetRemove() w/removed set", NULL
, NULL
);
1174 _SCErrorSet(kSCStatusInvalidArgument
);
1178 #if TARGET_OS_IPHONE
1179 if (isDefaultSet(set
) && (geteuid() != 0)) {
1180 SC_log(LOG_ERR
, "SCNetworkSetRemove() failed, cannot remove set : %@", set
);
1181 _SC_crash("The \"Automatic\" network set cannot be removed", NULL
, NULL
);
1182 _SCErrorSet(kSCStatusInvalidArgument
);
1185 #endif // TARGET_OS_IPHONE
1187 currentPath
= SCPreferencesGetValue(setPrivate
->prefs
, kSCPrefCurrentSet
);
1188 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1189 if (!isA_CFString(currentPath
) || !CFEqual(currentPath
, path
)) {
1190 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
1192 SC_log(LOG_DEBUG
, "SCNetworkSetRemove() failed, currently active: %@", setPrivate
->setID
);
1193 _SCErrorSet(kSCStatusInvalidArgument
);
1198 SC_log(LOG_DEBUG
, "SCNetworkSetRemove(): %@", set
);
1206 SCNetworkSetRemoveService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
1208 SCNetworkInterfaceRef interface
;
1209 CFArrayRef interface_config
= NULL
;
1212 int sc_status
= kSCStatusOK
;
1213 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1214 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1216 if (!isA_SCNetworkSet(set
)) {
1217 _SCErrorSet(kSCStatusInvalidArgument
);
1221 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
1222 _SCErrorSet(kSCStatusInvalidArgument
);
1226 if (!__SCNetworkSetExists(set
)) {
1227 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/removed set\n set = %@\n service = %@",
1230 _SC_crash_once("SCNetworkSetRemoveService() w/removed set", NULL
, NULL
);
1231 _SCErrorSet(kSCStatusInvalidArgument
);
1235 if (!__SCNetworkServiceExists(service
)) {
1236 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/removed service\n set = %@\n service = %@",
1239 _SC_crash_once("SCNetworkSetRemoveService() w/removed service", NULL
, NULL
);
1240 _SCErrorSet(kSCStatusInvalidArgument
);
1244 // remove service from ServiceOrder
1245 _serviceOrder_remove(set
, service
);
1247 // get the [deep] interface configuration settings
1248 interface
= SCNetworkServiceGetInterface(service
);
1249 if (interface
!= NULL
) {
1250 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(set
, interface
);
1251 if (interface_config
!= NULL
) {
1252 // remove the interface configuration from all sets which contain this service.
1253 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, NULL
);
1257 // remove the link between "set" and the "service"
1258 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
1260 servicePrivate
->serviceID
,
1262 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
1264 sc_status
= SCError(); // preserve the error
1268 // push the [deep] interface configuration [back] into all sets which contain the service.
1269 if (interface_config
!= NULL
) {
1270 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, interface_config
);
1271 CFRelease(interface_config
);
1275 SC_log(LOG_DEBUG
, "SCNetworkSetRemoveService(): %@, %@", set
, service
);
1277 _SCErrorSet(sc_status
);
1285 SCNetworkSetSetCurrent(SCNetworkSetRef set
)
1289 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1291 if (!isA_SCNetworkSet(set
)) {
1292 _SCErrorSet(kSCStatusInvalidArgument
);
1296 if (!__SCNetworkSetExists(set
)) {
1297 SC_log(LOG_ERR
, "SCNetworkSetSetCurrent() w/removed set\n set = %@", set
);
1298 _SC_crash_once("SCNetworkSetSetCurrent() w/removed set", NULL
, NULL
);
1299 _SCErrorSet(kSCStatusInvalidArgument
);
1303 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1304 ok
= SCPreferencesSetValue(setPrivate
->prefs
, kSCPrefCurrentSet
, path
);
1308 SC_log(LOG_DEBUG
, "SCNetworkSetSetCurrent(): %@", set
);
1316 SCNetworkSetSetName(SCNetworkSetRef set
, CFStringRef name
)
1318 CFDictionaryRef entity
;
1319 #if TARGET_OS_IPHONE
1320 Boolean isDefaultName
= FALSE
;
1321 #endif // TARGET_OS_IPHONE
1322 CFStringRef localized
= NULL
;
1323 CFStringRef non_localized
= NULL
;
1326 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1328 if (!isA_SCNetworkSet(set
)) {
1329 _SCErrorSet(kSCStatusInvalidArgument
);
1333 if (!__SCNetworkSetExists(set
)) {
1334 SC_log(LOG_ERR
, "SCNetworkSetSetName() w/removed set\n set = %@\n name = %@",
1336 name
!= NULL
? name
: CFSTR("<NULL>"));
1337 _SC_crash_once("SCNetworkSetSetName() w/removed set", NULL
, NULL
);
1338 _SCErrorSet(kSCStatusInvalidArgument
);
1342 if ((name
!= NULL
) && !isA_CFString(name
)) {
1343 _SCErrorSet(kSCStatusInvalidArgument
);
1347 // if known, compare against localized name
1350 non_localized
= copy_default_set_name(FALSE
);
1351 if (CFEqual(name
, non_localized
)) {
1352 localized
= copy_default_set_name(TRUE
);
1354 #if TARGET_OS_IPHONE
1355 isDefaultName
= TRUE
;
1356 #endif // TARGET_OS_IPHONE
1358 #if TARGET_OS_IPHONE
1360 localized
= copy_default_set_name(TRUE
);
1361 isDefaultName
= CFEqual(name
, non_localized
);
1363 #endif // TARGET_OS_IPHONE
1366 #if TARGET_OS_IPHONE
1367 if (!isDefaultName
&& isDefaultSet(set
) && (geteuid() != 0)) {
1368 // if we are trying to change the name of the "Automatic" set
1369 SC_log(LOG_ERR
, "SCNetworkSetSetName() failed, cannot rename : %@", set
);
1370 _SC_crash("The \"Automatic\" network set cannot be renamed", NULL
, NULL
);
1371 _SCErrorSet(kSCStatusInvalidArgument
);
1374 #endif // TARGET_OS_IPHONE
1376 #define PREVENT_DUPLICATE_SET_NAMES
1377 #ifdef PREVENT_DUPLICATE_SET_NAMES
1379 #if TARGET_OS_IPHONE
1380 if (!isDefaultName
) {
1381 // On iOS, only block naming multiple sets with the name
1382 // "Automatic". Others names are OK.
1384 #endif // TARGET_OS_IPHONE
1389 // ensure that each set is uniquely named
1391 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1396 n
= CFArrayGetCount(sets
);
1397 for (i
= 0; i
< n
; i
++) {
1398 CFStringRef otherID
;
1399 CFStringRef otherName
;
1400 SCNetworkSetRef set
= CFArrayGetValueAtIndex(sets
, i
);
1402 otherID
= SCNetworkSetGetSetID(set
);
1403 if (CFEqual(setPrivate
->setID
, otherID
)) {
1404 continue; // skip current set
1407 otherName
= SCNetworkSetGetName(set
);
1408 if ((otherName
!= NULL
) && CFEqual(name
, otherName
)) {
1409 // if "name" not unique
1411 _SCErrorSet(kSCStatusKeyExists
);
1418 #endif /* PREVENT_DUPLICATE_SET_NAMES */
1420 // if known, store non-localized name
1422 if ((name
!= NULL
) && (non_localized
!= NULL
)) {
1423 if (localized
== NULL
) {
1424 localized
= copy_default_set_name(TRUE
);
1426 if (CFEqual(name
, localized
)) {
1427 name
= non_localized
;
1431 // update the "name"
1433 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1434 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1435 if (isA_CFDictionary(entity
) ||
1436 ((entity
== NULL
) && (name
!= NULL
))) {
1437 CFMutableDictionaryRef newEntity
;
1439 if (entity
!= NULL
) {
1440 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1442 newEntity
= CFDictionaryCreateMutable(NULL
,
1444 &kCFTypeDictionaryKeyCallBacks
,
1445 &kCFTypeDictionaryValueCallBacks
);
1448 CFDictionarySetValue(newEntity
, kSCPropUserDefinedName
, name
);
1450 CFDictionaryRemoveValue(newEntity
, kSCPropUserDefinedName
);
1452 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newEntity
);
1453 CFRelease(newEntity
);
1460 SC_log(LOG_DEBUG
, "SCNetworkSetSetName(): %@", set
);
1463 if (localized
!= NULL
) CFRelease(localized
);
1464 if (non_localized
!= NULL
) CFRelease(non_localized
);
1470 SCNetworkSetSetServiceOrder(SCNetworkSetRef set
, CFArrayRef newOrder
)
1472 CFMutableArrayRef cleanOrder
;
1473 CFDictionaryRef dict
;
1476 CFMutableDictionaryRef newDict
;
1479 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1481 if (!isA_SCNetworkSet(set
)) {
1482 _SCErrorSet(kSCStatusInvalidArgument
);
1486 if (!__SCNetworkSetExists(set
)) {
1487 SC_log(LOG_ERR
, "SCNetworkSetSetServiceOrder() w/removed set\n set = %@", set
);
1488 _SC_crash_once("SCNetworkSetSetServiceOrder() w/removed set", NULL
, NULL
);
1489 _SCErrorSet(kSCStatusInvalidArgument
);
1493 if (isA_CFArray(newOrder
)) {
1494 n
= CFArrayGetCount(newOrder
);
1495 for (i
= 0; i
< n
; i
++) {
1496 CFStringRef serviceID
;
1498 serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1499 if (!isA_CFString(serviceID
)) {
1500 _SCErrorSet(kSCStatusInvalidArgument
);
1505 _SCErrorSet(kSCStatusInvalidArgument
);
1509 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1514 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1516 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
1518 newDict
= CFDictionaryCreateMutable(NULL
,
1520 &kCFTypeDictionaryKeyCallBacks
,
1521 &kCFTypeDictionaryValueCallBacks
);
1524 cleanOrder
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1525 n
= CFArrayGetCount(newOrder
);
1526 for (i
= 0; i
< n
; i
++) {
1527 CFIndex nClean
= CFArrayGetCount(cleanOrder
);
1528 CFStringRef serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1530 if ((nClean
== 0) ||
1531 !CFArrayContainsValue(cleanOrder
, CFRangeMake(0, nClean
), serviceID
)) {
1532 // if first reference to this serviceID
1533 CFArrayAppendValue(cleanOrder
, serviceID
);
1535 // skip duplicate serviceID
1536 SC_log(LOG_ERR
, "SCNetworkSetSetServiceOrder() found duplicate serviceID: removed %@\n", serviceID
);
1539 CFDictionarySetValue(newDict
, kSCPropNetServiceOrder
, cleanOrder
);
1540 CFRelease(cleanOrder
);
1542 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newDict
);
1551 #pragma mark SCNetworkSet SPIs
1556 __SCNetworkSetExists(SCNetworkSetRef set
)
1558 CFDictionaryRef entity
;
1560 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1562 if (setPrivate
->prefs
== NULL
) {
1566 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1567 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1570 if (!isA_CFDictionary(entity
)) {
1580 add_supported_interfaces(CFMutableArrayRef interface_list
, SCNetworkInterfaceRef interface
)
1583 CFArrayRef interface_types
;
1586 interface_types
= SCNetworkInterfaceGetSupportedInterfaceTypes(interface
);
1587 n
= (interface_types
!= NULL
) ? CFArrayGetCount(interface_types
) : 0;
1588 for (i
= 0; i
< n
; i
++) {
1589 SCNetworkInterfaceRef parent
;
1590 CFStringRef interface_type
;
1592 interface_type
= CFArrayGetValueAtIndex(interface_types
, i
);
1593 parent
= SCNetworkInterfaceCreateWithInterface(interface
, interface_type
);
1594 if (parent
!= NULL
) {
1595 CFArrayAppendValue(interface_list
, parent
);
1604 static CFSetRef
/* of SCNetworkInterfaceRef's */
1605 copyExcludedInterfaces(SCPreferencesRef prefs
)
1607 CFMutableSetRef excluded
;
1608 CFArrayRef interfaces
;
1610 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1612 #if !TARGET_OS_IPHONE
1613 // exclude Bond [member] interfaces
1614 interfaces
= SCBondInterfaceCopyAll(prefs
);
1615 if (interfaces
!= NULL
) {
1616 __SCBondInterfaceListCollectMembers(interfaces
, excluded
);
1617 CFRelease(interfaces
);
1619 #endif // !TARGET_OS_IPHONE
1621 // exclude Bridge [member] interfaces
1622 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
1623 if (interfaces
!= NULL
) {
1624 __SCBridgeInterfaceListCollectMembers(interfaces
, excluded
);
1625 CFRelease(interfaces
);
1632 #if !TARGET_OS_IPHONE
1633 static SCBridgeInterfaceRef
1634 copyAutoBridgeInterface(SCPreferencesRef prefs
, CFStringRef bridgeName
)
1636 SCBridgeInterfaceRef bridge
= NULL
;
1637 CFArrayRef interfaces
;
1639 // exclude Bridge [member] interfaces
1640 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
1641 if (interfaces
!= NULL
) {
1645 n
= CFArrayGetCount(interfaces
);
1646 for (i
= 0; i
< n
; i
++) {
1647 SCBridgeInterfaceRef interface
;
1648 CFStringRef name
= NULL
;
1649 CFDictionaryRef options
;
1651 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1652 options
= SCBridgeInterfaceGetOptions(interface
);
1653 if ((options
!= NULL
) &&
1654 CFDictionaryGetValueIfPresent(options
,
1656 (const void **)&name
) &&
1657 _SC_CFEqual(name
, bridgeName
)) {
1664 CFRelease(interfaces
);
1667 if (bridge
== NULL
) {
1668 bridge
= SCBridgeInterfaceCreate(prefs
);
1669 if (bridge
!= NULL
) {
1670 CFMutableDictionaryRef newOptions
;
1673 newOptions
= CFDictionaryCreateMutable(NULL
, 0,
1674 &kCFTypeDictionaryKeyCallBacks
,
1675 &kCFTypeDictionaryValueCallBacks
);
1676 CFDictionarySetValue(newOptions
, CFSTR("__AUTO__"), bridgeName
);
1677 ok
= SCBridgeInterfaceSetOptions(bridge
, newOptions
);
1678 CFRelease(newOptions
);
1688 #endif // !TARGET_OS_IPHONE
1692 copyServices(SCNetworkSetRef set
)
1694 CFArrayRef services
;
1695 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1697 // first, assume that we only want to add new services
1698 // for those interfaces that are not represented in the
1700 services
= SCNetworkSetCopyServices(set
);
1701 if ((services
!= NULL
) && setPrivate
->established
) {
1702 // but, if we are given an existing (or "established") set
1703 // than we only want to add new services for those interfaces
1704 // that are not represented in *any* set.
1705 CFRelease(services
);
1706 services
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1713 #if !TARGET_OS_IPHONE
1714 static CF_RETURNS_RETAINED CFArrayRef
1715 updateServices(CFArrayRef services
, SCNetworkInterfaceRef interface
)
1717 CFStringRef bsdName
;
1720 CFMutableArrayRef newServices
;
1722 if (services
== NULL
) {
1726 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
1728 newServices
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1730 n
= CFArrayGetCount(services
);
1731 for (i
= 0; i
< n
; i
++) {
1732 SCNetworkInterfaceRef interface
;
1733 CFStringRef interfaceName
;
1734 SCNetworkServiceRef newService
;
1735 SCNetworkServiceRef service
;
1736 CFStringRef serviceID
;
1737 SCNetworkServicePrivateRef servicePrivate
;
1739 service
= CFArrayGetValueAtIndex(services
, i
);
1740 interface
= SCNetworkServiceGetInterface(service
);
1741 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
1742 if (!_SC_CFEqual(interfaceName
, bsdName
)) {
1743 // if not a match, retain
1744 CFArrayAppendValue(newServices
, service
);
1748 // if a match, update
1749 serviceID
= SCNetworkServiceGetServiceID(service
);
1750 servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1751 newService
= SCNetworkServiceCopy(servicePrivate
->prefs
, serviceID
);
1752 if (newService
!= NULL
) {
1753 CFArrayAppendValue(newServices
, newService
);
1754 CFRelease(newService
);
1760 #endif // !TARGET_OS_IPHONE
1763 static __inline__ Boolean
1764 skipInterface(SCNetworkInterfaceRef interface
)
1768 action
= _SCNetworkInterfaceGetConfigurationAction(interface
);
1769 if (isA_CFString(action
) &&
1770 CFEqual(action
, kSCNetworkInterfaceConfigurationActionValueNone
)) {
1779 _SCNetworkSetCompare(const void *val1
, const void *val2
, void *context
)
1781 #pragma unused(context)
1786 SCNetworkSetRef s1
= (SCNetworkSetRef
)val1
;
1787 SCNetworkSetRef s2
= (SCNetworkSetRef
)val2
;
1789 name1
= SCNetworkSetGetName(s1
);
1790 name2
= SCNetworkSetGetName(s2
);
1792 if (name1
!= NULL
) {
1793 if (name2
!= NULL
) {
1794 return CFStringCompare(name1
, name2
, 0);
1796 return kCFCompareLessThan
;
1800 if (name2
!= NULL
) {
1801 return kCFCompareGreaterThan
;
1804 id1
= SCNetworkSetGetSetID(s1
);
1805 id2
= SCNetworkSetGetSetID(s2
);
1806 return CFStringCompare(id1
, id2
, 0);
1811 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set
, CFArrayRef interfaces
, Boolean excludeHidden
)
1817 CFArrayRef services
;
1818 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1819 Boolean updated
= FALSE
;
1820 #if !TARGET_OS_IPHONE
1821 Boolean updatedIFs
= FALSE
;
1822 #endif // !TARGET_OS_IPHONE
1824 #if TARGET_OS_IPHONE
1825 CFArrayRef orphans
= NULL
;
1828 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1830 if (CFArrayGetCount(sets
) == 1) {
1831 services
= SCNetworkSetCopyServices(set
);
1832 if (services
!= NULL
) {
1833 n
= CFArrayGetCount(services
);
1834 CFRelease(services
);
1837 if ((n
== 0) && CFEqual(set
, CFArrayGetValueAtIndex(sets
, 0))) {
1838 // after a "Reset Network Settings" we need to find (and
1839 // add back) any VPN services that were orphaned.
1840 orphans
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1846 #endif // TARGET_OS_IPHONE
1848 // copy network services
1849 services
= copyServices(set
);
1851 // copy network interfaces to be excluded
1852 excluded
= copyExcludedInterfaces(setPrivate
->prefs
);
1854 #if !TARGET_OS_IPHONE
1855 // look for interfaces that should auto-magically be added
1856 // to an Ethernet bridge
1857 n
= ((services
!= NULL
) && (interfaces
!= NULL
)) ? CFArrayGetCount(interfaces
) : 0;
1858 for (i
= 0; i
< n
; i
++) {
1859 SCBridgeInterfaceRef bridge
= NULL
;
1860 SCNetworkInterfaceRef interface
;
1862 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1864 if (excludeHidden
&& skipInterface(interface
)) {
1865 // if not auto-configure
1869 if (CFSetContainsValue(excluded
, interface
)) {
1870 // if this interface is a member of a Bond or Bridge
1874 if (__SCNetworkServiceExistsForInterface(services
, interface
)) {
1875 // if this is not a new interface
1879 if (_SCNetworkInterfaceIsBuiltin(interface
) &&
1880 _SCNetworkInterfaceIsThunderbolt(interface
) &&
1881 !isA_SCBridgeInterface(interface
)) {
1882 // add built-in Thunderbolt interfaces to bridge
1883 bridge
= copyAutoBridgeInterface(setPrivate
->prefs
, CFSTR("thunderbolt-bridge"));
1886 if (bridge
!= NULL
) {
1887 CFIndex bridgeIndex
;
1889 CFMutableArrayRef newMembers
;
1890 CFMutableSetRef newExcluded
;
1891 CFMutableArrayRef newInterfaces
;
1892 CFArrayRef newServices
;
1894 // track the bridge interface (if it's in our list)
1895 bridgeIndex
= CFArrayGetFirstIndexOfValue(interfaces
,
1896 CFRangeMake(0, CFArrayGetCount(interfaces
)),
1899 // add new member interface
1900 members
= SCBridgeInterfaceGetMemberInterfaces(bridge
);
1901 if ((members
!= NULL
) && (CFArrayGetCount(members
) > 0)) {
1902 newMembers
= CFArrayCreateMutableCopy(NULL
, 0, members
);
1903 updated
= TRUE
; // if we're updating an existing bridge
1905 newMembers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1907 CFArrayAppendValue(newMembers
, interface
);
1908 ok
= SCBridgeInterfaceSetMemberInterfaces(bridge
, newMembers
);
1909 CFRelease(newMembers
);
1911 SC_log(LOG_INFO
, "could not update bridge with \"%@\": %s",
1912 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1913 SCErrorString(SCError()));
1918 // exclude the new member interface
1919 newExcluded
= CFSetCreateMutableCopy(NULL
, 0, excluded
);
1920 CFRelease(excluded
);
1921 CFSetAddValue(newExcluded
, interface
);
1922 excluded
= newExcluded
;
1924 // update the list of interfaces to include the [new or updated] bridge
1925 newInterfaces
= CFArrayCreateMutableCopy(NULL
, 0, interfaces
);
1926 if (bridgeIndex
!= kCFNotFound
) {
1927 CFArraySetValueAtIndex(newInterfaces
, bridgeIndex
, bridge
);
1929 CFArrayAppendValue(newInterfaces
, bridge
);
1932 CFRelease(interfaces
);
1934 interfaces
= newInterfaces
;
1937 // refresh [existing] services
1938 newServices
= updateServices(services
, bridge
);
1939 if (newServices
!= NULL
) {
1940 CFRelease(services
);
1941 services
= newServices
;
1947 #endif // !TARGET_OS_IPHONE
1949 n
= ((services
!= NULL
) && (interfaces
!= NULL
)) ? CFArrayGetCount(interfaces
) : 0;
1950 for (i
= 0; i
< n
; i
++) {
1951 SCNetworkInterfaceRef interface
;
1952 CFMutableArrayRef interface_list
;
1954 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1956 if (excludeHidden
&& skipInterface(interface
)) {
1957 // if not auto-configure
1961 if (CFSetContainsValue(excluded
, interface
)) {
1962 // if this interface is a member of a Bond or Bridge
1966 if (__SCNetworkServiceExistsForInterface(services
, interface
)) {
1967 // if this is not a new interface
1971 interface_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1972 CFArrayAppendValue(interface_list
, interface
);
1974 while (ok
&& (CFArrayGetCount(interface_list
) > 0)) {
1975 CFArrayRef protocol_types
;
1977 interface
= CFArrayGetValueAtIndex(interface_list
, 0);
1979 protocol_types
= SCNetworkInterfaceGetSupportedProtocolTypes(interface
);
1980 if ((protocol_types
!= NULL
) && (CFArrayGetCount(protocol_types
) > 0)) {
1981 SCNetworkServiceRef service
;
1983 service
= SCNetworkServiceCreate(setPrivate
->prefs
, interface
);
1984 if (service
== NULL
) {
1985 SC_log(LOG_ERR
, "could not create service for \"%@\": %s",
1986 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1987 SCErrorString(SCError()));
1992 ok
= SCNetworkServiceEstablishDefaultConfiguration(service
);
1994 SC_log(LOG_ERR
, "could not estabish default configuration for \"%@\": %s",
1995 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1996 SCErrorString(SCError()));
1997 SCNetworkServiceRemove(service
);
2002 ok
= SCNetworkSetAddService(set
, service
);
2004 SC_log(LOG_ERR
, "could not add service for \"%@\": %s",
2005 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
2006 SCErrorString(SCError()));
2007 SCNetworkServiceRemove(service
);
2015 add_supported_interfaces(interface_list
, interface
);
2020 CFArrayRemoveValueAtIndex(interface_list
, 0);
2022 CFRelease(interface_list
);
2024 #if !TARGET_OS_IPHONE
2025 if (updatedIFs
&& (interfaces
!= NULL
)) {
2026 CFRelease(interfaces
);
2028 #endif // !TARGET_OS_IPHONE
2029 if (services
!= NULL
) CFRelease(services
);
2030 CFRelease(excluded
);
2032 #if TARGET_OS_IPHONE
2033 if (orphans
!= NULL
) {
2034 if (ok
&& updated
) {
2036 CFIndex n
= CFArrayGetCount(orphans
);
2038 for (i
= 0; i
< n
; i
++) {
2039 SCNetworkServiceRef service
;
2041 service
= CFArrayGetValueAtIndex(orphans
, i
);
2042 if (_SCNetworkServiceIsVPN(service
)) {
2043 ok
= SCNetworkSetAddService(set
, service
);
2053 #endif // TARGET_OS_IPHONE
2059 model
= SCPreferencesGetValue(setPrivate
->prefs
, MODEL
);
2060 if (model
== NULL
) {
2061 model
= _SC_hw_model(FALSE
);
2062 SCPreferencesSetValue(setPrivate
->prefs
, MODEL
, model
);
2065 // if no changes were made
2066 _SCErrorSet(kSCStatusOK
);
2075 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set
)
2077 CFArrayRef interfaces
;
2078 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
2079 Boolean updated
= FALSE
;
2081 if (!isA_SCNetworkSet(set
)) {
2082 _SCErrorSet(kSCStatusInvalidArgument
);
2086 interfaces
= _SCNetworkInterfaceCopyAllWithPreferences(setPrivate
->prefs
);
2087 if (interfaces
!= NULL
) {
2088 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
, TRUE
);
2089 CFRelease(interfaces
);
2097 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set
, SCNetworkInterfaceRef interface
)
2099 CFArrayRef interfaces
;
2102 if (!isA_SCNetworkSet(set
)) {
2103 _SCErrorSet(kSCStatusInvalidArgument
);
2107 if (!isA_SCNetworkInterface(interface
)) {
2108 _SCErrorSet(kSCStatusInvalidArgument
);
2112 interfaces
= CFArrayCreate(NULL
, (const void **)&interface
, 1, &kCFTypeArrayCallBacks
);
2113 assert(interfaces
!= NULL
);
2114 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
, FALSE
);
2115 CFRelease(interfaces
);
2122 SCNetworkSetCopySelectedVPNService(SCNetworkSetRef set
)
2126 SCNetworkServiceRef selected
= NULL
;
2127 CFArrayRef services
;
2128 CFMutableArrayRef services_vpn
= NULL
;
2130 if (!isA_SCNetworkSet(set
)) {
2131 _SCErrorSet(kSCStatusInvalidArgument
);
2135 services
= SCNetworkSetCopyServices(set
);
2136 if (services
!= NULL
) {
2137 n
= CFArrayGetCount(services
);
2138 for (i
= 0; i
< n
; i
++) {
2139 SCNetworkServiceRef service
;
2141 service
= CFArrayGetValueAtIndex(services
, i
);
2142 if (!SCNetworkServiceGetEnabled(service
)) {
2147 if (!_SCNetworkServiceIsVPN(service
)) {
2148 // if not VPN service
2152 if (services_vpn
== NULL
) {
2153 services_vpn
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2155 CFArrayAppendValue(services_vpn
, service
);
2158 CFRelease(services
);
2161 if (services_vpn
== NULL
) {
2162 // if no VPN services
2166 n
= CFArrayGetCount(services_vpn
);
2169 CFMutableArrayRef sorted
;
2171 order
= SCNetworkSetGetServiceOrder(set
);
2172 sorted
= CFArrayCreateMutableCopy(NULL
, 0, services_vpn
);
2173 CFArraySortValues(sorted
,
2174 CFRangeMake(0, CFArrayGetCount(sorted
)),
2175 _SCNetworkServiceCompare
,
2177 CFRelease(services_vpn
);
2178 services_vpn
= sorted
;
2181 #if TARGET_OS_IPHONE
2183 CFStringRef serviceID_prefs
;
2185 #define VPN_PREFERENCES CFSTR("com.apple.mobilevpn")
2186 #define VPN_SERVICE_ID CFSTR("activeVPNID")
2188 CFPreferencesAppSynchronize(VPN_PREFERENCES
);
2189 serviceID_prefs
= CFPreferencesCopyAppValue(VPN_SERVICE_ID
, VPN_PREFERENCES
);
2190 if (serviceID_prefs
!= NULL
) {
2191 for (i
= 0; i
< n
; i
++) {
2192 SCNetworkServiceRef service
;
2193 CFStringRef serviceID
;
2195 service
= CFArrayGetValueAtIndex(services_vpn
, i
);
2196 serviceID
= SCNetworkServiceGetServiceID(service
);
2197 if (CFEqual(serviceID
, serviceID_prefs
)) {
2205 CFRelease(serviceID_prefs
);
2208 #endif // TARGET_OS_IPHONE
2210 if (selected
== NULL
) {
2211 selected
= CFArrayGetValueAtIndex(services_vpn
, 0);
2215 CFRelease(services_vpn
);
2221 SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
2224 CFArrayRef services
;
2226 if (!isA_SCNetworkSet(set
)) {
2227 _SCErrorSet(kSCStatusInvalidArgument
);
2231 if (!isA_SCNetworkService(service
) || !_SCNetworkServiceIsVPN(service
)) {
2232 _SCErrorSet(kSCStatusInvalidArgument
);
2236 services
= SCNetworkSetCopyServices(set
);
2237 if (services
!= NULL
) {
2239 CFIndex n
= CFArrayGetCount(services
);
2241 if (!CFArrayContainsValue(services
, CFRangeMake(0, n
), service
)) {
2242 // if selected service not a member of the current set
2243 _SCErrorSet(kSCStatusInvalidArgument
);
2248 for (i
= 0; ok
&& (i
< n
); i
++) {
2249 SCNetworkServiceRef vpn
;
2251 vpn
= CFArrayGetValueAtIndex(services
, i
);
2252 if (!_SCNetworkServiceIsVPN(vpn
)) {
2253 // if not VPN service
2257 ok
= SCNetworkServiceSetEnabled(vpn
, CFEqual(service
, vpn
));
2263 if (services
!= NULL
) CFRelease(services
);
2269 _SCNetworkSetSetSetID(SCNetworkSetRef set
, CFStringRef newSetID
)
2271 SCNetworkSetRef currentSet
= NULL
;
2272 SCNetworkSetPrivateRef currentSetPrivate
= NULL
;
2273 CFDictionaryRef entity
;
2274 CFStringRef newPath
;
2276 CFStringRef oldPath
= NULL
;
2277 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
2278 Boolean updateCurrentSet
= FALSE
;
2280 if (!isA_SCNetworkSet(set
)) {
2281 _SCErrorSet(kSCStatusInvalidArgument
);
2285 if (!isA_CFString(newSetID
)) {
2286 _SCErrorSet(kSCStatusInvalidArgument
);
2290 if (!__SCNetworkSetExists(set
)) {
2291 SC_log(LOG_ERR
, "_SCNetworkSetSetSetID() w/removed set\n set = %@\n setID = %@",
2294 _SC_crash_once("_SCNetworkSetSetSetID() w/removed set", NULL
, NULL
);
2295 _SCErrorSet(kSCStatusInvalidArgument
);
2299 // If newSetID is equal to current setID, our work is done
2300 if (CFEqual(newSetID
, setPrivate
->setID
)) {
2304 newPath
= SCPreferencesPathKeyCreateSet(NULL
, newSetID
);
2305 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, newPath
);
2306 if (isA_CFDictionary(entity
)) {
2307 // if the new set already exists
2308 _SCErrorSet(kSCStatusKeyExists
);
2312 oldPath
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
2313 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, oldPath
);
2314 if (!isA_CFDictionary(entity
)) {
2315 // if the set has already been removed
2316 _SCErrorSet(kSCStatusNoKey
);
2320 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, newPath
, entity
);
2325 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, oldPath
);
2330 // update current set (if needed)
2331 currentSet
= SCNetworkSetCopyCurrent(setPrivate
->prefs
);
2332 if (currentSet
!= NULL
) {
2333 currentSetPrivate
= (SCNetworkSetPrivateRef
)currentSet
;
2334 if (CFEqual(currentSetPrivate
->setID
, setPrivate
->setID
)) {
2335 updateCurrentSet
= TRUE
;
2337 CFRelease(currentSet
);
2340 SC_log(LOG_DEBUG
, "_SCNetworkSetSetID(): %@ --> %@", set
, newSetID
);
2342 // replace setID with new one
2344 CFRelease(setPrivate
->setID
);
2345 setPrivate
->setID
= newSetID
;
2347 if (updateCurrentSet
) {
2348 SCNetworkSetSetCurrent(set
);
2353 if (oldPath
!= NULL
) {
2356 if (newPath
!= NULL
) {