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 (!__SCNetworkSetExists(set
)) {
80 CFStringAppendFormat(result
, NULL
, CFSTR(", REMOVED"));
82 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
89 __SCNetworkSetDeallocate(CFTypeRef cf
)
91 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)cf
;
93 /* release resources */
95 CFRelease(setPrivate
->setID
);
96 CFRelease(setPrivate
->prefs
);
97 if (setPrivate
->name
!= NULL
)
98 CFRelease(setPrivate
->name
);
105 __SCNetworkSetEqual(CFTypeRef cf1
, CFTypeRef cf2
)
107 SCNetworkSetPrivateRef s1
= (SCNetworkSetPrivateRef
)cf1
;
108 SCNetworkSetPrivateRef s2
= (SCNetworkSetPrivateRef
)cf2
;
113 if (s1
->prefs
!= s2
->prefs
)
114 return FALSE
; // if not the same prefs
116 if (!CFEqual(s1
->setID
, s2
->setID
))
117 return FALSE
; // if not the same set identifier
124 __SCNetworkSetHash(CFTypeRef cf
)
126 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)cf
;
128 return CFHash(setPrivate
->setID
);
133 __SCNetworkSetInitialize(void)
135 __kSCNetworkSetTypeID
= _CFRuntimeRegisterClass(&__SCNetworkSetClass
);
140 static SCNetworkSetPrivateRef
141 __SCNetworkSetCreatePrivate(CFAllocatorRef allocator
,
142 SCPreferencesRef prefs
,
145 SCNetworkSetPrivateRef setPrivate
;
148 /* initialize runtime */
149 pthread_once(&initialized
, __SCNetworkSetInitialize
);
151 /* allocate target */
152 size
= sizeof(SCNetworkSetPrivate
) - sizeof(CFRuntimeBase
);
153 setPrivate
= (SCNetworkSetPrivateRef
)_CFRuntimeCreateInstance(allocator
,
154 __kSCNetworkSetTypeID
,
157 if (setPrivate
== NULL
) {
161 /* initialize non-zero/NULL members */
162 setPrivate
->setID
= CFStringCreateCopy(NULL
, setID
);
163 setPrivate
->prefs
= CFRetain(prefs
);
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_clear(CFMutableArrayRef order
, CFStringRef serviceID
)
189 CFIndex f
; // # of serviceID's found
195 n
= CFArrayGetCount(order
);
197 CFStringRef thisServiceID
= CFArrayGetValueAtIndex(order
, i
);
199 if (CFEqual(thisServiceID
, serviceID
)) {
200 // remove the serviceID
201 CFArrayRemoveValueAtIndex(order
, i
);
207 i
++; // move to the next serviceID
215 _serviceOrder_add(SCNetworkSetRef set
, SCNetworkServiceRef service
)
218 CFMutableArrayRef newOrder
;
220 CFStringRef serviceID
= SCNetworkServiceGetServiceID(service
);
221 CFIndex serviceOrder
= _serviceOrder(service
);
222 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
225 order
= SCNetworkSetGetServiceOrder(set
);
227 newOrder
= CFArrayCreateMutableCopy(NULL
, 0, order
);
229 newOrder
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
231 assert(newOrder
!= NULL
);
233 n
= _serviceOrder_clear(newOrder
, serviceID
);
235 SC_log(LOG_ERR
, "SCNetworkSetAddService() w/service already in ServiceOrder\n service = %@\n matched = %ld",
238 _SC_crash_once("SCNetworkSetAddService() w/service already in ServiceOrder", NULL
, NULL
);
242 n
= CFArrayGetCount(newOrder
);
243 for (CFIndex i
= 0; i
< n
; i
++) {
245 SCNetworkServiceRef slotService
;
246 CFStringRef slotServiceID
;
248 slotServiceID
= CFArrayGetValueAtIndex(newOrder
, i
);
249 if (!isA_CFString(slotServiceID
)) {
254 slotService
= SCNetworkServiceCopy(setPrivate
->prefs
, slotServiceID
);
255 if (slotService
== NULL
) {
256 // if serviceID not valid
260 slotOrder
= _serviceOrder(slotService
);
261 if (serviceOrder
>= slotOrder
) {
262 // add the service *after* this one
266 CFRelease(slotService
);
269 CFArrayInsertValueAtIndex(newOrder
, slot
, serviceID
);
270 (void) SCNetworkSetSetServiceOrder(set
, newOrder
);
278 _serviceOrder_remove(SCNetworkSetRef set
, SCNetworkServiceRef service
)
281 CFMutableArrayRef newOrder
;
283 CFStringRef serviceID
;
285 order
= SCNetworkSetGetServiceOrder(set
);
289 newOrder
= CFArrayCreateMutableCopy(NULL
, 0, order
);
291 serviceID
= SCNetworkServiceGetServiceID(service
);
293 n
= _serviceOrder_clear(newOrder
, serviceID
);
295 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/multiple instances of service in ServiceOrder\n service = %@\n count = %ld",
300 (void) SCNetworkSetSetServiceOrder(set
, newOrder
);
308 #pragma mark SCNetworkSet APIs
311 #define DEFAULT_SET_NAME CFSTR("Automatic")
316 copy_default_set_name(Boolean loc
)
319 static CFStringRef non_localized
= NULL
;
320 static CFStringRef localized
= NULL
;
323 static dispatch_once_t once
;
325 dispatch_once(&once
, ^{
328 bundle
= _SC_CFBundleGet();
329 if (bundle
!= NULL
) {
330 non_localized
= _SC_CFBundleCopyNonLocalizedString(bundle
,
331 CFSTR("DEFAULT_SET_NAME"),
336 name
= non_localized
;
338 static dispatch_once_t once
;
340 dispatch_once(&once
, ^{
343 bundle
= _SC_CFBundleGet();
344 if (bundle
!= NULL
) {
345 localized
= CFBundleCopyLocalizedString(bundle
,
346 CFSTR("DEFAULT_SET_NAME"),
355 // if bundle or localized names not available
356 name
= DEFAULT_SET_NAME
;
364 #define PREVENT_DUPLICATE_SERVICE_NAMES
365 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
367 copy_next_name(CFStringRef name
)
369 CFArrayRef components
;
371 CFMutableArrayRef newComponents
;
378 components
= CFStringCreateArrayBySeparatingStrings(NULL
, name
, CFSTR(" "));
379 if (components
!= NULL
) {
380 newComponents
= CFArrayCreateMutableCopy(NULL
, 0, components
);
381 CFRelease(components
);
383 newComponents
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
384 CFArrayAppendValue(newComponents
, name
);
387 n
= CFArrayGetCount(newComponents
);
391 str
= CFArrayGetValueAtIndex(newComponents
, n
- 1);
392 suffix
= CFStringGetIntValue(str
);
394 CFArrayRemoveValueAtIndex(newComponents
, n
- 1);
400 name
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), (int)suffix
);
401 CFArrayAppendValue(newComponents
, name
);
404 name
= CFStringCreateByCombiningStrings(NULL
, newComponents
, CFSTR(" "));
405 CFRelease(newComponents
);
412 ensure_unique_service_name(SCNetworkServiceRef service
)
414 SCNetworkInterfaceRef interface
;
418 interface
= SCNetworkServiceGetInterface(service
);
420 name
= SCNetworkServiceGetName(service
);
428 ok
= SCNetworkServiceSetName(service
, name
);
433 if (SCError() != kSCStatusKeyExists
) {
434 SC_log(LOG_INFO
, "could not update service name for \"%@\": %s",
435 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
436 SCErrorString(SCError()));
440 newName
= copy_next_name(name
);
441 if (newName
== NULL
) {
442 SC_log(LOG_INFO
, "could not create unique name for \"%@\": %s",
443 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
444 SCErrorString(SCError()));
448 // try again with the "new" name
461 #endif // PREVENT_DUPLICATE_SERVICE_NAMES
465 SCNetworkSetAddService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
467 SCNetworkInterfaceRef interface
;
468 CFArrayRef interface_config
= NULL
;
472 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
473 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
475 if (!isA_SCNetworkSet(set
)) {
476 _SCErrorSet(kSCStatusInvalidArgument
);
480 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
481 _SCErrorSet(kSCStatusInvalidArgument
);
485 if (!__SCNetworkSetExists(set
)) {
486 SC_log(LOG_ERR
, "SCNetworkSetAddService() w/removed set\n set = %@\n service = %@",
489 _SC_crash_once("SCNetworkSetAddService() w/removed set", NULL
, NULL
);
490 _SCErrorSet(kSCStatusInvalidArgument
);
493 if (!__SCNetworkServiceExists(service
)) {
494 SC_log(LOG_ERR
, "SCNetworkSetAddService() w/removed service\n set = %@\n service = %@",
497 _SC_crash_once("SCNetworkSetAddService() w/removed service", NULL
, NULL
);
498 _SCErrorSet(kSCStatusInvalidArgument
);
502 // make sure that we do not add an orphaned network service if its
503 // associated interface is a member of a bond or bridge.
504 interface
= SCNetworkServiceGetInterface(service
);
505 if ((interface
!= NULL
) &&
506 __SCNetworkInterfaceIsMember(servicePrivate
->prefs
, interface
)) {
507 _SCErrorSet(kSCStatusKeyExists
);
511 //#define PREVENT_DUPLICATE_SETS
512 #ifdef PREVENT_DUPLICATE_SETS
515 // ensure that each service is only a member of ONE set
516 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
521 n
= CFArrayGetCount(sets
);
522 for (i
= 0; i
< n
; i
++) {
527 set
= CFArrayGetValueAtIndex(sets
, i
);
528 services
= SCNetworkSetCopyServices(set
);
529 found
= CFArrayContainsValue(services
,
530 CFRangeMake(0, CFArrayGetCount(services
)),
536 _SCErrorSet(kSCStatusKeyExists
);
542 #endif /* PREVENT_DUPLICATE_SETS */
544 // get the [deep] interface configuration settings
545 interface
= SCNetworkServiceGetInterface(service
);
546 if (interface
!= NULL
) {
547 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(set
, interface
);
550 // create the link between "set" and the "service"
551 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
, // allocator
552 setPrivate
->setID
, // set
553 servicePrivate
->serviceID
, // service
555 link
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
556 servicePrivate
->serviceID
, // service
558 ok
= SCPreferencesPathSetLink(setPrivate
->prefs
, path
, link
);
559 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
561 // We use the interface cache here to not reach into the
562 // IORegistry for every service we go through
563 _SCNetworkInterfaceCacheOpen();
564 ok
= ensure_unique_service_name(service
);
565 _SCNetworkInterfaceCacheClose();
568 // if we could not ensure a unique name, remove the (just added)
569 // link between the "set" and the "service"
570 (void) SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
573 #endif // PREVENT_DUPLICATE_SERVICE_NAMES
580 // push the [deep] interface configuration into all sets which contain this service.
581 if (interface
!= NULL
) {
582 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, interface_config
);
585 // add service to ServiceOrder
586 _serviceOrder_add(set
, service
);
588 // mark set as no longer "new"
589 setPrivate
->established
= TRUE
;
594 SC_log(LOG_DEBUG
, "SCNetworkSetAddService(): %@, %@", set
, service
);
597 if (interface_config
!= NULL
) CFRelease(interface_config
);
603 SCNetworkSetCopy(SCPreferencesRef prefs
, CFStringRef setID
)
605 CFDictionaryRef entity
;
607 SCNetworkSetPrivateRef setPrivate
;
609 if (!isA_CFString(setID
)) {
610 _SCErrorSet(kSCStatusInvalidArgument
);
614 path
= SCPreferencesPathKeyCreateSet(NULL
, setID
);
615 entity
= SCPreferencesPathGetValue(prefs
, path
);
618 if (!isA_CFDictionary(entity
)) {
619 _SCErrorSet(kSCStatusNoKey
);
623 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
624 assert(setPrivate
!= NULL
);
626 // mark set as "old" (already established)
627 setPrivate
->established
= TRUE
;
629 return (SCNetworkSetRef
)setPrivate
;
634 SCNetworkSetContainsInterface(SCNetworkSetRef set
, SCNetworkInterfaceRef interface
)
636 Boolean found
= FALSE
;
639 services
= SCNetworkSetCopyServices(set
);
640 if (services
!= NULL
) {
641 found
= __SCNetworkServiceExistsForInterface(services
, interface
);
649 CFArrayRef
/* of SCNetworkSetRef's */
650 SCNetworkSetCopyAll(SCPreferencesRef prefs
)
652 CFMutableArrayRef array
;
655 CFDictionaryRef sets
;
657 path
= SCPreferencesPathKeyCreateSets(NULL
);
658 sets
= SCPreferencesPathGetValue(prefs
, path
);
661 if ((sets
!= NULL
) && !isA_CFDictionary(sets
)) {
665 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
667 n
= (sets
!= NULL
) ? CFDictionaryGetCount(sets
) : 0;
670 const void * keys_q
[N_QUICK
];
671 const void ** keys
= keys_q
;
672 const void * vals_q
[N_QUICK
];
673 const void ** vals
= vals_q
;
675 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
676 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
677 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
679 CFDictionaryGetKeysAndValues(sets
, keys
, vals
);
680 for (i
= 0; i
< n
; i
++) {
681 SCNetworkSetPrivateRef setPrivate
;
683 if (!isA_CFDictionary(vals
[i
])) {
684 SC_log(LOG_INFO
, "error w/set \"%@\"", keys
[i
]);
688 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, keys
[i
]);
689 assert(setPrivate
!= NULL
);
691 // mark set as "old" (already established)
692 setPrivate
->established
= TRUE
;
694 CFArrayAppendValue(array
, (SCNetworkSetRef
)setPrivate
);
695 CFRelease(setPrivate
);
697 if (keys
!= keys_q
) {
698 CFAllocatorDeallocate(NULL
, keys
);
699 CFAllocatorDeallocate(NULL
, vals
);
707 CFArrayRef
/* of SCNetworkInterfaceRef's */
708 SCNetworkSetCopyAvailableInterfaces(SCNetworkSetRef set
)
710 CFMutableArrayRef available
;
711 CFMutableSetRef excluded
= NULL
;
713 CFArrayRef interfaces
;
714 CFIndex n_interfaces
;
715 CFIndex n_exclusions
= 0;
716 SCPreferencesRef prefs
;
717 SCNetworkSetPrivateRef setPrivate
;
719 setPrivate
= (SCNetworkSetPrivateRef
)set
;
720 prefs
= setPrivate
->prefs
;
722 interfaces
= _SCNetworkInterfaceCopyAllWithPreferences(prefs
);
723 n_interfaces
= CFArrayGetCount(interfaces
);
724 if (n_interfaces
== 0) {
729 CFArrayRef bridges
= NULL
;
731 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
733 #if !TARGET_OS_IPHONE
734 CFArrayRef bonds
= NULL
;
736 bonds
= SCBondInterfaceCopyAll(prefs
);
738 __SCBondInterfaceListCollectMembers(bonds
, excluded
);
741 #endif /* !TARGET_OS_IPHONE */
743 bridges
= SCBridgeInterfaceCopyAll(prefs
);
744 if (bridges
!= NULL
) {
745 __SCBridgeInterfaceListCollectMembers(bridges
, excluded
);
749 n_exclusions
= CFSetGetCount(excluded
);
752 if (n_exclusions
== 0) {
753 if (excluded
!= NULL
) {
760 available
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
762 for (i
= 0; i
< n_interfaces
; i
++) {
763 SCNetworkInterfaceRef interface
;
765 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
766 if (CFSetContainsValue(excluded
, interface
)) {
771 CFArrayAppendValue(available
, interface
);
774 CFRelease(interfaces
);
782 SCNetworkSetCopyCurrent(SCPreferencesRef prefs
)
784 CFArrayRef components
;
785 CFStringRef currentID
;
786 SCNetworkSetPrivateRef setPrivate
= NULL
;
788 currentID
= SCPreferencesGetValue(prefs
, kSCPrefCurrentSet
);
789 if (!isA_CFString(currentID
)) {
793 components
= CFStringCreateArrayBySeparatingStrings(NULL
, currentID
, CFSTR("/"));
794 if (CFArrayGetCount(components
) == 3) {
798 setID
= CFArrayGetValueAtIndex(components
, 2);
799 path
= SCPreferencesPathKeyCreateSet(NULL
, setID
);
800 if (CFEqual(path
, currentID
)) {
801 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
802 assert(setPrivate
!= NULL
);
804 // mark set as "old" (already established)
805 setPrivate
->established
= TRUE
;
807 SC_log(LOG_NOTICE
, "SCNetworkSetCopyCurrent(): preferences are non-conformant");
811 CFRelease(components
);
813 return (SCNetworkSetRef
)setPrivate
;
817 CFArrayRef
/* of SCNetworkServiceRef's */
818 SCNetworkSetCopyServices(SCNetworkSetRef set
)
820 CFMutableArrayRef array
;
821 CFDictionaryRef dict
;
824 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
826 if (!isA_SCNetworkSet(set
)) {
827 _SCErrorSet(kSCStatusInvalidArgument
);
832 path
= SCPreferencesPathKeyCreateSetNetworkService(NULL
, setPrivate
->setID
, NULL
);
833 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
835 if ((dict
!= NULL
) && !isA_CFDictionary(dict
)) {
839 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
841 n
= (dict
!= NULL
) ? CFDictionaryGetCount(dict
) : 0;
844 const void * keys_q
[N_QUICK
];
845 const void ** keys
= keys_q
;
847 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
848 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
850 CFDictionaryGetKeysAndValues(dict
, keys
, NULL
);
851 for (i
= 0; i
< n
; i
++) {
852 CFArrayRef components
;
855 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
857 (CFStringRef
)keys
[i
],
859 link
= SCPreferencesPathGetLink(setPrivate
->prefs
, path
);
862 SC_log(LOG_INFO
, "service \"%@\" for set \"%@\" is not a link",
865 continue; // if the service is not a link
868 components
= CFStringCreateArrayBySeparatingStrings(NULL
, link
, CFSTR("/"));
869 if (CFArrayGetCount(components
) == 3) {
870 CFStringRef serviceID
;
872 serviceID
= CFArrayGetValueAtIndex(components
, 2);
873 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
874 serviceID
, // service
876 if (CFEqual(path
, link
)) {
877 CFDictionaryRef entity
;
878 CFStringRef interfacePath
;
879 Boolean skip
= FALSE
;
881 interfacePath
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
882 serviceID
, // service
883 kSCEntNetInterface
); // entity
884 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, interfacePath
);
885 CFRelease(interfacePath
);
887 if (__SCNetworkInterfaceEntityIsPPTP(entity
)) {
888 SC_log(LOG_INFO
, "PPTP services are no longer supported");
893 SCNetworkServicePrivateRef servicePrivate
;
895 servicePrivate
= __SCNetworkServiceCreatePrivate(NULL
,
899 CFArrayAppendValue(array
, (SCNetworkServiceRef
)servicePrivate
);
900 CFRelease(servicePrivate
);
905 CFRelease(components
);
907 if (keys
!= keys_q
) {
908 CFAllocatorDeallocate(NULL
, keys
);
917 SCNetworkSetCreate(SCPreferencesRef prefs
)
919 CFArrayRef components
;
920 CFDictionaryRef entity
;
925 SCNetworkSetPrivateRef setPrivate
;
927 prefix
= SCPreferencesPathKeyCreateSets(NULL
);
928 path
= __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs
, prefix
);
929 if (path
== NULL
) path
= SCPreferencesPathCreateUniqueChild(prefs
, prefix
);
935 components
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
936 setID
= CFArrayGetValueAtIndex(components
, 2);
937 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
938 assert(setPrivate
!= NULL
);
939 CFRelease(components
);
941 // mark set as "new" (not yet established)
942 setPrivate
->established
= FALSE
;
944 // establish the set in the preferences
945 entity
= CFDictionaryCreate(NULL
,
947 &kCFTypeDictionaryKeyCallBacks
,
948 &kCFTypeDictionaryValueCallBacks
);
949 ok
= SCPreferencesPathSetValue(prefs
, path
, entity
);
953 CFRelease(setPrivate
);
957 if (setPrivate
!= NULL
) {
958 SC_log(LOG_DEBUG
, "SCNetworkSetCreate(): %@", setPrivate
);
961 return (SCNetworkSetRef
)setPrivate
;
966 _SCNetworkSetCreateDefault(SCPreferencesRef prefs
)
971 CFStringRef setName
= NULL
;
974 set
= SCNetworkSetCopyCurrent(prefs
);
976 SC_log(LOG_NOTICE
, "creating default set w/already existing set");
978 _SCErrorSet(kSCStatusKeyExists
);
982 // create a new ("Automatic") set
983 set
= SCNetworkSetCreate(prefs
);
985 SC_log(LOG_NOTICE
, "could not create \"new\" set: %s",
986 SCErrorString(SCError()));
990 setName
= copy_default_set_name(TRUE
);
991 ok
= SCNetworkSetSetName(set
, setName
);
994 // if we could not save the new set's "name"
995 SC_log(LOG_NOTICE
, "could not save the new set's name: %s",
996 SCErrorString(SCError()));
1000 ok
= SCNetworkSetSetCurrent(set
);
1002 // if we could not make this the "current" set
1003 SC_log(LOG_NOTICE
, "could not establish new set as current: %s",
1004 SCErrorString(SCError()));
1008 model
= SCPreferencesGetValue(prefs
, MODEL
);
1009 if (model
== NULL
) {
1010 model
= _SC_hw_model(FALSE
);
1011 SCPreferencesSetValue(prefs
, MODEL
, model
);
1014 version
= SCPreferencesGetValue(prefs
, kSCPrefVersion
);
1015 if (version
== NULL
) {
1016 const int new_version
= NETWORK_CONFIGURATION_VERSION
;
1018 version
= CFNumberCreate(NULL
, kCFNumberIntType
, &new_version
);
1019 SCPreferencesSetValue(prefs
, kSCPrefVersion
, version
);
1025 if (!ok
&& (set
!= NULL
)) {
1026 SCNetworkSetRemove(set
);
1035 SCNetworkSetGetSetID(SCNetworkSetRef set
)
1037 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1039 if (!isA_SCNetworkSet(set
)) {
1040 _SCErrorSet(kSCStatusInvalidArgument
);
1044 return setPrivate
->setID
;
1049 SCNetworkSetGetName(SCNetworkSetRef set
)
1051 CFDictionaryRef entity
;
1053 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1055 if (!isA_SCNetworkSet(set
)) {
1056 _SCErrorSet(kSCStatusInvalidArgument
);
1060 if (setPrivate
->name
!= NULL
) {
1061 return setPrivate
->name
;
1064 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1065 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1068 if (isA_CFDictionary(entity
)) {
1071 name
= CFDictionaryGetValue(entity
, kSCPropUserDefinedName
);
1072 if (isA_CFString(name
)) {
1073 setPrivate
->name
= CFRetain(name
);
1077 if (setPrivate
->name
!= NULL
) {
1078 CFStringRef non_localized
;
1080 non_localized
= copy_default_set_name(FALSE
);
1081 if (CFEqual(setPrivate
->name
, non_localized
)) {
1082 CFStringRef localized
;
1084 // if "Automatic", return localized name
1085 localized
= copy_default_set_name(TRUE
);
1086 CFRelease(setPrivate
->name
);
1087 setPrivate
->name
= localized
;
1090 CFRelease(non_localized
);
1093 return setPrivate
->name
;
1097 CFArrayRef
/* of serviceID CFStringRef's */
1098 SCNetworkSetGetServiceOrder(SCNetworkSetRef set
)
1100 CFDictionaryRef dict
;
1102 CFArrayRef serviceOrder
;
1103 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1105 if (!isA_SCNetworkSet(set
)) {
1106 _SCErrorSet(kSCStatusInvalidArgument
);
1110 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1115 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1117 if (!isA_CFDictionary(dict
)) {
1121 serviceOrder
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
);
1122 serviceOrder
= isA_CFArray(serviceOrder
);
1124 return serviceOrder
;
1129 SCNetworkSetGetTypeID(void)
1131 pthread_once(&initialized
, __SCNetworkSetInitialize
); /* initialize runtime */
1132 return __kSCNetworkSetTypeID
;
1136 #if TARGET_OS_IPHONE
1138 isDefaultSet(SCNetworkSetRef set
)
1140 CFStringRef defaultName
;
1141 Boolean isDefault
= FALSE
;
1142 CFStringRef setName
;
1144 defaultName
= copy_default_set_name(TRUE
);
1145 setName
= SCNetworkSetGetName(set
);
1146 isDefault
= _SC_CFEqual(setName
, defaultName
);
1147 CFRelease(defaultName
);
1151 #endif // TARGET_OS_IPHONE
1155 SCNetworkSetRemove(SCNetworkSetRef set
)
1157 CFStringRef currentPath
;
1160 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1162 if (!isA_SCNetworkSet(set
)) {
1163 _SCErrorSet(kSCStatusInvalidArgument
);
1167 if (!__SCNetworkSetExists(set
)) {
1168 SC_log(LOG_ERR
, "SCNetworkSetRemove() w/removed set\n set = %@", set
);
1169 _SC_crash_once("SCNetworkSetRemove() w/removed set", NULL
, NULL
);
1170 _SCErrorSet(kSCStatusInvalidArgument
);
1173 #if TARGET_OS_IPHONE
1174 if (isDefaultSet(set
) && (geteuid() != 0)) {
1175 SC_log(LOG_ERR
, "SCNetworkSetRemove() failed, cannot remove set : %@", set
);
1176 _SC_crash("The \"Automatic\" network set cannot be removed", NULL
, NULL
);
1177 _SCErrorSet(kSCStatusInvalidArgument
);
1180 #endif // TARGET_OS_IPHONE
1182 currentPath
= SCPreferencesGetValue(setPrivate
->prefs
, kSCPrefCurrentSet
);
1183 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1184 if (!isA_CFString(currentPath
) || !CFEqual(currentPath
, path
)) {
1185 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
1187 SC_log(LOG_DEBUG
, "SCNetworkSetRemove() failed, currently active: %@", setPrivate
->setID
);
1188 _SCErrorSet(kSCStatusInvalidArgument
);
1193 SC_log(LOG_DEBUG
, "SCNetworkSetRemove(): %@", set
);
1201 SCNetworkSetRemoveService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
1203 SCNetworkInterfaceRef interface
;
1204 CFArrayRef interface_config
= NULL
;
1207 int sc_status
= kSCStatusOK
;
1208 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1209 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1211 if (!isA_SCNetworkSet(set
)) {
1212 _SCErrorSet(kSCStatusInvalidArgument
);
1216 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
1217 _SCErrorSet(kSCStatusInvalidArgument
);
1221 if (!__SCNetworkSetExists(set
)) {
1222 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/removed set\n set = %@\n service = %@",
1225 _SC_crash_once("SCNetworkSetRemoveService() w/removed set", NULL
, NULL
);
1226 _SCErrorSet(kSCStatusInvalidArgument
);
1229 if (!__SCNetworkServiceExists(service
)) {
1230 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/removed service\n set = %@\n service = %@",
1233 _SC_crash_once("SCNetworkSetRemoveService() w/removed service", NULL
, NULL
);
1234 _SCErrorSet(kSCStatusInvalidArgument
);
1238 // remove service from ServiceOrder
1239 _serviceOrder_remove(set
, service
);
1241 // get the [deep] interface configuration settings
1242 interface
= SCNetworkServiceGetInterface(service
);
1243 if (interface
!= NULL
) {
1244 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(set
, interface
);
1245 if (interface_config
!= NULL
) {
1246 // remove the interface configuration from all sets which contain this service.
1247 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, NULL
);
1251 // remove the link between "set" and the "service"
1252 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
1254 servicePrivate
->serviceID
,
1256 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
1258 sc_status
= SCError(); // preserve the error
1262 // push the [deep] interface configuration [back] into all sets which contain the service.
1263 if (interface_config
!= NULL
) {
1264 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, interface_config
);
1265 CFRelease(interface_config
);
1269 SC_log(LOG_DEBUG
, "SCNetworkSetRemoveService(): %@, %@", set
, service
);
1271 _SCErrorSet(sc_status
);
1279 SCNetworkSetSetCurrent(SCNetworkSetRef set
)
1283 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1285 if (!isA_SCNetworkSet(set
)) {
1286 _SCErrorSet(kSCStatusInvalidArgument
);
1290 if (!__SCNetworkSetExists(set
)) {
1291 SC_log(LOG_ERR
, "SCNetworkSetSetCurrent() w/removed set\n set = %@", set
);
1292 _SC_crash_once("SCNetworkSetSetCurrent() w/removed set", NULL
, NULL
);
1293 _SCErrorSet(kSCStatusInvalidArgument
);
1297 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1298 ok
= SCPreferencesSetValue(setPrivate
->prefs
, kSCPrefCurrentSet
, path
);
1302 SC_log(LOG_DEBUG
, "SCNetworkSetSetCurrent(): %@", set
);
1310 SCNetworkSetSetName(SCNetworkSetRef set
, CFStringRef name
)
1312 CFDictionaryRef entity
;
1313 #if TARGET_OS_IPHONE
1314 Boolean isDefaultName
= FALSE
;
1315 #endif // TARGET_OS_IPHONE
1316 CFStringRef localized
= NULL
;
1317 CFStringRef non_localized
= NULL
;
1320 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1322 if (!isA_SCNetworkSet(set
)) {
1323 _SCErrorSet(kSCStatusInvalidArgument
);
1327 if (!__SCNetworkSetExists(set
)) {
1328 SC_log(LOG_ERR
, "SCNetworkSetSetName() w/removed set\n set = %@\n name = %@",
1330 name
!= NULL
? name
: CFSTR("<NULL>"));
1331 _SC_crash_once("SCNetworkSetSetName() w/removed set", NULL
, NULL
);
1332 _SCErrorSet(kSCStatusInvalidArgument
);
1336 if ((name
!= NULL
) && !isA_CFString(name
)) {
1337 _SCErrorSet(kSCStatusInvalidArgument
);
1341 // if known, compare against localized name
1344 non_localized
= copy_default_set_name(FALSE
);
1345 if (CFEqual(name
, non_localized
)) {
1346 localized
= copy_default_set_name(TRUE
);
1348 #if TARGET_OS_IPHONE
1349 isDefaultName
= TRUE
;
1350 #endif // TARGET_OS_IPHONE
1352 #if TARGET_OS_IPHONE
1354 localized
= copy_default_set_name(TRUE
);
1355 isDefaultName
= CFEqual(name
, non_localized
);
1357 #endif // TARGET_OS_IPHONE
1360 #if TARGET_OS_IPHONE
1361 if (!isDefaultName
&& isDefaultSet(set
) && (geteuid() != 0)) {
1362 // if we are trying to change the name of the "Automatic" set
1363 SC_log(LOG_ERR
, "SCNetworkSetSetName() failed, cannot rename : %@", set
);
1364 _SC_crash("The \"Automatic\" network set cannot be renamed", NULL
, NULL
);
1365 _SCErrorSet(kSCStatusInvalidArgument
);
1368 #endif // TARGET_OS_IPHONE
1370 #define PREVENT_DUPLICATE_SET_NAMES
1371 #ifdef PREVENT_DUPLICATE_SET_NAMES
1373 #if TARGET_OS_IPHONE
1374 if (!isDefaultName
) {
1375 // On iOS, only block naming multiple sets with the name
1376 // "Automatic". Others names are OK.
1378 #endif // TARGET_OS_IPHONE
1383 // ensure that each set is uniquely named
1385 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1390 n
= CFArrayGetCount(sets
);
1391 for (i
= 0; i
< n
; i
++) {
1392 CFStringRef otherID
;
1393 CFStringRef otherName
;
1394 SCNetworkSetRef set
= CFArrayGetValueAtIndex(sets
, i
);
1396 otherID
= SCNetworkSetGetSetID(set
);
1397 if (CFEqual(setPrivate
->setID
, otherID
)) {
1398 continue; // skip current set
1401 otherName
= SCNetworkSetGetName(set
);
1402 if ((otherName
!= NULL
) && CFEqual(name
, otherName
)) {
1403 // if "name" not unique
1405 _SCErrorSet(kSCStatusKeyExists
);
1412 #endif /* PREVENT_DUPLICATE_SET_NAMES */
1414 // if known, store non-localized name
1416 if ((name
!= NULL
) && (non_localized
!= NULL
)) {
1417 if (localized
== NULL
) {
1418 localized
= copy_default_set_name(TRUE
);
1420 if (CFEqual(name
, localized
)) {
1421 name
= non_localized
;
1425 // update the "name"
1427 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1428 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1429 if (isA_CFDictionary(entity
) ||
1430 ((entity
== NULL
) && (name
!= NULL
))) {
1431 CFMutableDictionaryRef newEntity
;
1433 if (entity
!= NULL
) {
1434 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1436 newEntity
= CFDictionaryCreateMutable(NULL
,
1438 &kCFTypeDictionaryKeyCallBacks
,
1439 &kCFTypeDictionaryValueCallBacks
);
1442 CFDictionarySetValue(newEntity
, kSCPropUserDefinedName
, name
);
1444 CFDictionaryRemoveValue(newEntity
, kSCPropUserDefinedName
);
1446 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newEntity
);
1447 CFRelease(newEntity
);
1454 SC_log(LOG_DEBUG
, "SCNetworkSetSetName(): %@", set
);
1457 if (localized
!= NULL
) CFRelease(localized
);
1458 if (non_localized
!= NULL
) CFRelease(non_localized
);
1464 SCNetworkSetSetServiceOrder(SCNetworkSetRef set
, CFArrayRef newOrder
)
1466 CFMutableArrayRef cleanOrder
;
1467 CFDictionaryRef dict
;
1470 CFMutableDictionaryRef newDict
;
1473 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1475 if (!isA_SCNetworkSet(set
)) {
1476 _SCErrorSet(kSCStatusInvalidArgument
);
1480 if (!__SCNetworkSetExists(set
)) {
1481 SC_log(LOG_ERR
, "SCNetworkSetSetServiceOrder() w/removed set\n set = %@", set
);
1482 _SC_crash_once("SCNetworkSetSetServiceOrder() w/removed set", NULL
, NULL
);
1483 _SCErrorSet(kSCStatusInvalidArgument
);
1487 if (isA_CFArray(newOrder
)) {
1488 n
= CFArrayGetCount(newOrder
);
1489 for (i
= 0; i
< n
; i
++) {
1490 CFStringRef serviceID
;
1492 serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1493 if (!isA_CFString(serviceID
)) {
1494 _SCErrorSet(kSCStatusInvalidArgument
);
1499 _SCErrorSet(kSCStatusInvalidArgument
);
1503 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1508 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1510 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
1512 newDict
= CFDictionaryCreateMutable(NULL
,
1514 &kCFTypeDictionaryKeyCallBacks
,
1515 &kCFTypeDictionaryValueCallBacks
);
1518 cleanOrder
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1519 n
= CFArrayGetCount(newOrder
);
1520 for (i
= 0; i
< n
; i
++) {
1521 CFIndex nClean
= CFArrayGetCount(cleanOrder
);
1522 CFStringRef serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1524 if ((nClean
== 0) ||
1525 !CFArrayContainsValue(cleanOrder
, CFRangeMake(0, nClean
), serviceID
)) {
1526 // if first reference to this serviceID
1527 CFArrayAppendValue(cleanOrder
, serviceID
);
1529 // skip duplicate serviceID
1530 SC_log(LOG_ERR
, "SCNetworkSetSetServiceOrder() found duplicate serviceID: removed %@\n", serviceID
);
1533 CFDictionarySetValue(newDict
, kSCPropNetServiceOrder
, cleanOrder
);
1534 CFRelease(cleanOrder
);
1536 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newDict
);
1545 #pragma mark SCNetworkSet SPIs
1550 __SCNetworkSetExists(SCNetworkSetRef set
)
1552 CFDictionaryRef entity
;
1554 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1556 if (setPrivate
->prefs
== NULL
) {
1560 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1561 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1564 if (!isA_CFDictionary(entity
)) {
1574 add_supported_interfaces(CFMutableArrayRef interface_list
, SCNetworkInterfaceRef interface
)
1577 CFArrayRef interface_types
;
1580 interface_types
= SCNetworkInterfaceGetSupportedInterfaceTypes(interface
);
1581 n
= (interface_types
!= NULL
) ? CFArrayGetCount(interface_types
) : 0;
1582 for (i
= 0; i
< n
; i
++) {
1583 SCNetworkInterfaceRef parent
;
1584 CFStringRef interface_type
;
1586 interface_type
= CFArrayGetValueAtIndex(interface_types
, i
);
1587 parent
= SCNetworkInterfaceCreateWithInterface(interface
, interface_type
);
1588 if (parent
!= NULL
) {
1589 CFArrayAppendValue(interface_list
, parent
);
1598 static CFSetRef
/* of SCNetworkInterfaceRef's */
1599 copyExcludedInterfaces(SCPreferencesRef prefs
)
1601 CFMutableSetRef excluded
;
1602 CFArrayRef interfaces
;
1604 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1606 #if !TARGET_OS_IPHONE
1607 // exclude Bond [member] interfaces
1608 interfaces
= SCBondInterfaceCopyAll(prefs
);
1609 if (interfaces
!= NULL
) {
1610 __SCBondInterfaceListCollectMembers(interfaces
, excluded
);
1611 CFRelease(interfaces
);
1613 #endif // !TARGET_OS_IPHONE
1615 // exclude Bridge [member] interfaces
1616 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
1617 if (interfaces
!= NULL
) {
1618 __SCBridgeInterfaceListCollectMembers(interfaces
, excluded
);
1619 CFRelease(interfaces
);
1626 #if !TARGET_OS_IPHONE
1627 static SCBridgeInterfaceRef
1628 copyAutoBridgeInterface(SCPreferencesRef prefs
, CFStringRef bridgeName
)
1630 SCBridgeInterfaceRef bridge
= NULL
;
1631 CFArrayRef interfaces
;
1633 // exclude Bridge [member] interfaces
1634 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
1635 if (interfaces
!= NULL
) {
1639 n
= CFArrayGetCount(interfaces
);
1640 for (i
= 0; i
< n
; i
++) {
1641 SCBridgeInterfaceRef interface
;
1642 CFStringRef name
= NULL
;
1643 CFDictionaryRef options
;
1645 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1646 options
= SCBridgeInterfaceGetOptions(interface
);
1647 if ((options
!= NULL
) &&
1648 CFDictionaryGetValueIfPresent(options
,
1650 (const void **)&name
) &&
1651 _SC_CFEqual(name
, bridgeName
)) {
1658 CFRelease(interfaces
);
1661 if (bridge
== NULL
) {
1662 bridge
= SCBridgeInterfaceCreate(prefs
);
1663 if (bridge
!= NULL
) {
1664 CFMutableDictionaryRef newOptions
;
1667 newOptions
= CFDictionaryCreateMutable(NULL
, 0,
1668 &kCFTypeDictionaryKeyCallBacks
,
1669 &kCFTypeDictionaryValueCallBacks
);
1670 CFDictionarySetValue(newOptions
, CFSTR("__AUTO__"), bridgeName
);
1671 ok
= SCBridgeInterfaceSetOptions(bridge
, newOptions
);
1672 CFRelease(newOptions
);
1682 #endif // !TARGET_OS_IPHONE
1686 copyServices(SCNetworkSetRef set
)
1688 CFArrayRef services
;
1689 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1691 // first, assume that we only want to add new services
1692 // for those interfaces that are not represented in the
1694 services
= SCNetworkSetCopyServices(set
);
1695 if ((services
!= NULL
) && setPrivate
->established
) {
1696 // but, if we are given an existing (or "established") set
1697 // than we only want to add new services for those interfaces
1698 // that are not represented in *any* set.
1699 CFRelease(services
);
1700 services
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1707 #if !TARGET_OS_IPHONE
1708 static CF_RETURNS_RETAINED CFArrayRef
1709 updateServices(CFArrayRef services
, SCNetworkInterfaceRef interface
)
1711 CFStringRef bsdName
;
1714 CFMutableArrayRef newServices
;
1716 if (services
== NULL
) {
1720 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
1722 newServices
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1724 n
= CFArrayGetCount(services
);
1725 for (i
= 0; i
< n
; i
++) {
1726 SCNetworkInterfaceRef interface
;
1727 CFStringRef interfaceName
;
1728 SCNetworkServiceRef newService
;
1729 SCNetworkServiceRef service
;
1730 CFStringRef serviceID
;
1731 SCNetworkServicePrivateRef servicePrivate
;
1733 service
= CFArrayGetValueAtIndex(services
, i
);
1734 interface
= SCNetworkServiceGetInterface(service
);
1735 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
1736 if (!_SC_CFEqual(interfaceName
, bsdName
)) {
1737 // if not a match, retain
1738 CFArrayAppendValue(newServices
, service
);
1742 // if a match, update
1743 serviceID
= SCNetworkServiceGetServiceID(service
);
1744 servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1745 newService
= SCNetworkServiceCopy(servicePrivate
->prefs
, serviceID
);
1746 if (newService
!= NULL
) {
1747 CFArrayAppendValue(newServices
, newService
);
1748 CFRelease(newService
);
1754 #endif // !TARGET_OS_IPHONE
1757 static __inline__ Boolean
1758 skipInterface(SCNetworkInterfaceRef interface
)
1762 action
= _SCNetworkInterfaceGetConfigurationAction(interface
);
1763 if (isA_CFString(action
) &&
1764 CFEqual(action
, kSCNetworkInterfaceConfigurationActionValueNone
)) {
1773 _SCNetworkSetCompare(const void *val1
, const void *val2
, void *context
)
1775 #pragma unused(context)
1780 SCNetworkSetRef s1
= (SCNetworkSetRef
)val1
;
1781 SCNetworkSetRef s2
= (SCNetworkSetRef
)val2
;
1783 name1
= SCNetworkSetGetName(s1
);
1784 name2
= SCNetworkSetGetName(s2
);
1786 if (name1
!= NULL
) {
1787 if (name2
!= NULL
) {
1788 return CFStringCompare(name1
, name2
, 0);
1790 return kCFCompareLessThan
;
1794 if (name2
!= NULL
) {
1795 return kCFCompareGreaterThan
;
1798 id1
= SCNetworkSetGetSetID(s1
);
1799 id2
= SCNetworkSetGetSetID(s2
);
1800 return CFStringCompare(id1
, id2
, 0);
1805 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set
, CFArrayRef interfaces
, Boolean excludeHidden
)
1811 CFArrayRef services
;
1812 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1813 Boolean updated
= FALSE
;
1814 #if !TARGET_OS_IPHONE
1815 Boolean updatedIFs
= FALSE
;
1816 #endif // !TARGET_OS_IPHONE
1818 #if TARGET_OS_IPHONE
1819 CFArrayRef orphans
= NULL
;
1822 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1824 if (CFArrayGetCount(sets
) == 1) {
1825 services
= SCNetworkSetCopyServices(set
);
1826 if (services
!= NULL
) {
1827 n
= CFArrayGetCount(services
);
1828 CFRelease(services
);
1831 if ((n
== 0) && CFEqual(set
, CFArrayGetValueAtIndex(sets
, 0))) {
1832 // after a "Reset Network Settings" we need to find (and
1833 // add back) any VPN services that were orphaned.
1834 orphans
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1840 #endif // TARGET_OS_IPHONE
1842 // copy network services
1843 services
= copyServices(set
);
1845 // copy network interfaces to be excluded
1846 excluded
= copyExcludedInterfaces(setPrivate
->prefs
);
1848 #if !TARGET_OS_IPHONE
1849 // look for interfaces that should auto-magically be added
1850 // to an Ethernet bridge
1851 n
= ((services
!= NULL
) && (interfaces
!= NULL
)) ? CFArrayGetCount(interfaces
) : 0;
1852 for (i
= 0; i
< n
; i
++) {
1853 SCBridgeInterfaceRef bridge
= NULL
;
1854 SCNetworkInterfaceRef interface
;
1856 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1858 if (excludeHidden
&& skipInterface(interface
)) {
1859 // if not auto-configure
1863 if (CFSetContainsValue(excluded
, interface
)) {
1864 // if this interface is a member of a Bond or Bridge
1868 if (__SCNetworkServiceExistsForInterface(services
, interface
)) {
1869 // if this is not a new interface
1873 if (_SCNetworkInterfaceIsBuiltin(interface
) &&
1874 _SCNetworkInterfaceIsThunderbolt(interface
) &&
1875 !isA_SCBridgeInterface(interface
)) {
1876 // add built-in Thunderbolt interfaces to bridge
1877 bridge
= copyAutoBridgeInterface(setPrivate
->prefs
, CFSTR("thunderbolt-bridge"));
1880 if (bridge
!= NULL
) {
1881 CFIndex bridgeIndex
;
1883 CFMutableArrayRef newMembers
;
1884 CFMutableSetRef newExcluded
;
1885 CFMutableArrayRef newInterfaces
;
1886 CFArrayRef newServices
;
1888 // track the bridge interface (if it's in our list)
1889 bridgeIndex
= CFArrayGetFirstIndexOfValue(interfaces
,
1890 CFRangeMake(0, CFArrayGetCount(interfaces
)),
1893 // add new member interface
1894 members
= SCBridgeInterfaceGetMemberInterfaces(bridge
);
1895 if ((members
!= NULL
) && (CFArrayGetCount(members
) > 0)) {
1896 newMembers
= CFArrayCreateMutableCopy(NULL
, 0, members
);
1897 updated
= TRUE
; // if we're updating an existing bridge
1899 newMembers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1901 CFArrayAppendValue(newMembers
, interface
);
1902 ok
= SCBridgeInterfaceSetMemberInterfaces(bridge
, newMembers
);
1903 CFRelease(newMembers
);
1905 SC_log(LOG_INFO
, "could not update bridge with \"%@\": %s",
1906 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1907 SCErrorString(SCError()));
1912 // exclude the new member interface
1913 newExcluded
= CFSetCreateMutableCopy(NULL
, 0, excluded
);
1914 CFRelease(excluded
);
1915 CFSetAddValue(newExcluded
, interface
);
1916 excluded
= newExcluded
;
1918 // update the list of interfaces to include the [new or updated] bridge
1919 newInterfaces
= CFArrayCreateMutableCopy(NULL
, 0, interfaces
);
1920 if (bridgeIndex
!= kCFNotFound
) {
1921 CFArraySetValueAtIndex(newInterfaces
, bridgeIndex
, bridge
);
1923 CFArrayAppendValue(newInterfaces
, bridge
);
1926 CFRelease(interfaces
);
1928 interfaces
= newInterfaces
;
1931 // refresh [existing] services
1932 newServices
= updateServices(services
, bridge
);
1933 if (newServices
!= NULL
) {
1934 CFRelease(services
);
1935 services
= newServices
;
1941 #endif // !TARGET_OS_IPHONE
1943 n
= ((services
!= NULL
) && (interfaces
!= NULL
)) ? CFArrayGetCount(interfaces
) : 0;
1944 for (i
= 0; i
< n
; i
++) {
1945 SCNetworkInterfaceRef interface
;
1946 CFMutableArrayRef interface_list
;
1948 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1950 if (excludeHidden
&& skipInterface(interface
)) {
1951 // if not auto-configure
1955 if (CFSetContainsValue(excluded
, interface
)) {
1956 // if this interface is a member of a Bond or Bridge
1960 if (__SCNetworkServiceExistsForInterface(services
, interface
)) {
1961 // if this is not a new interface
1965 interface_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1966 CFArrayAppendValue(interface_list
, interface
);
1968 while (ok
&& (CFArrayGetCount(interface_list
) > 0)) {
1969 CFArrayRef protocol_types
;
1971 interface
= CFArrayGetValueAtIndex(interface_list
, 0);
1973 protocol_types
= SCNetworkInterfaceGetSupportedProtocolTypes(interface
);
1974 if ((protocol_types
!= NULL
) && (CFArrayGetCount(protocol_types
) > 0)) {
1975 SCNetworkServiceRef service
;
1977 service
= SCNetworkServiceCreate(setPrivate
->prefs
, interface
);
1978 if (service
== NULL
) {
1979 SC_log(LOG_ERR
, "could not create service for \"%@\": %s",
1980 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1981 SCErrorString(SCError()));
1986 ok
= SCNetworkServiceEstablishDefaultConfiguration(service
);
1988 SC_log(LOG_ERR
, "could not estabish default configuration for \"%@\": %s",
1989 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1990 SCErrorString(SCError()));
1991 SCNetworkServiceRemove(service
);
1996 ok
= SCNetworkSetAddService(set
, service
);
1998 SC_log(LOG_ERR
, "could not add service for \"%@\": %s",
1999 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
2000 SCErrorString(SCError()));
2001 SCNetworkServiceRemove(service
);
2009 add_supported_interfaces(interface_list
, interface
);
2014 CFArrayRemoveValueAtIndex(interface_list
, 0);
2016 CFRelease(interface_list
);
2018 #if !TARGET_OS_IPHONE
2019 if (updatedIFs
&& (interfaces
!= NULL
)) {
2020 CFRelease(interfaces
);
2022 #endif // !TARGET_OS_IPHONE
2023 if (services
!= NULL
) CFRelease(services
);
2024 CFRelease(excluded
);
2026 #if TARGET_OS_IPHONE
2027 if (orphans
!= NULL
) {
2028 if (ok
&& updated
) {
2030 CFIndex n
= CFArrayGetCount(orphans
);
2032 for (i
= 0; i
< n
; i
++) {
2033 SCNetworkServiceRef service
;
2035 service
= CFArrayGetValueAtIndex(orphans
, i
);
2036 if (_SCNetworkServiceIsVPN(service
)) {
2037 ok
= SCNetworkSetAddService(set
, service
);
2047 #endif // TARGET_OS_IPHONE
2053 model
= SCPreferencesGetValue(setPrivate
->prefs
, MODEL
);
2054 if (model
== NULL
) {
2055 model
= _SC_hw_model(FALSE
);
2056 SCPreferencesSetValue(setPrivate
->prefs
, MODEL
, model
);
2059 // if no changes were made
2060 _SCErrorSet(kSCStatusOK
);
2069 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set
)
2071 CFArrayRef interfaces
;
2072 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
2073 Boolean updated
= FALSE
;
2075 if (!isA_SCNetworkSet(set
)) {
2076 _SCErrorSet(kSCStatusInvalidArgument
);
2080 interfaces
= _SCNetworkInterfaceCopyAllWithPreferences(setPrivate
->prefs
);
2081 if (interfaces
!= NULL
) {
2082 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
, TRUE
);
2083 CFRelease(interfaces
);
2091 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set
, SCNetworkInterfaceRef interface
)
2093 CFArrayRef interfaces
;
2096 if (!isA_SCNetworkSet(set
)) {
2097 _SCErrorSet(kSCStatusInvalidArgument
);
2101 if (!isA_SCNetworkInterface(interface
)) {
2102 _SCErrorSet(kSCStatusInvalidArgument
);
2106 interfaces
= CFArrayCreate(NULL
, (const void **)&interface
, 1, &kCFTypeArrayCallBacks
);
2107 assert(interfaces
!= NULL
);
2108 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
, FALSE
);
2109 CFRelease(interfaces
);
2116 SCNetworkSetCopySelectedVPNService(SCNetworkSetRef set
)
2120 SCNetworkServiceRef selected
= NULL
;
2121 CFArrayRef services
;
2122 CFMutableArrayRef services_vpn
= NULL
;
2124 if (!isA_SCNetworkSet(set
)) {
2125 _SCErrorSet(kSCStatusInvalidArgument
);
2129 services
= SCNetworkSetCopyServices(set
);
2130 if (services
!= NULL
) {
2131 n
= CFArrayGetCount(services
);
2132 for (i
= 0; i
< n
; i
++) {
2133 SCNetworkServiceRef service
;
2135 service
= CFArrayGetValueAtIndex(services
, i
);
2136 if (!SCNetworkServiceGetEnabled(service
)) {
2141 if (!_SCNetworkServiceIsVPN(service
)) {
2142 // if not VPN service
2146 if (services_vpn
== NULL
) {
2147 services_vpn
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2149 CFArrayAppendValue(services_vpn
, service
);
2152 CFRelease(services
);
2155 if (services_vpn
== NULL
) {
2156 // if no VPN services
2160 n
= CFArrayGetCount(services_vpn
);
2163 CFMutableArrayRef sorted
;
2165 order
= SCNetworkSetGetServiceOrder(set
);
2166 sorted
= CFArrayCreateMutableCopy(NULL
, 0, services_vpn
);
2167 CFArraySortValues(sorted
,
2168 CFRangeMake(0, CFArrayGetCount(sorted
)),
2169 _SCNetworkServiceCompare
,
2171 CFRelease(services_vpn
);
2172 services_vpn
= sorted
;
2175 #if TARGET_OS_IPHONE
2177 CFStringRef serviceID_prefs
;
2179 #define VPN_PREFERENCES CFSTR("com.apple.mobilevpn")
2180 #define VPN_SERVICE_ID CFSTR("activeVPNID")
2182 CFPreferencesAppSynchronize(VPN_PREFERENCES
);
2183 serviceID_prefs
= CFPreferencesCopyAppValue(VPN_SERVICE_ID
, VPN_PREFERENCES
);
2184 if (serviceID_prefs
!= NULL
) {
2185 for (i
= 0; i
< n
; i
++) {
2186 SCNetworkServiceRef service
;
2187 CFStringRef serviceID
;
2189 service
= CFArrayGetValueAtIndex(services_vpn
, i
);
2190 serviceID
= SCNetworkServiceGetServiceID(service
);
2191 if (CFEqual(serviceID
, serviceID_prefs
)) {
2199 CFRelease(serviceID_prefs
);
2202 #endif // TARGET_OS_IPHONE
2204 if (selected
== NULL
) {
2205 selected
= CFArrayGetValueAtIndex(services_vpn
, 0);
2209 CFRelease(services_vpn
);
2215 SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
2218 CFArrayRef services
;
2220 if (!isA_SCNetworkSet(set
)) {
2221 _SCErrorSet(kSCStatusInvalidArgument
);
2225 if (!isA_SCNetworkService(service
) || !_SCNetworkServiceIsVPN(service
)) {
2226 _SCErrorSet(kSCStatusInvalidArgument
);
2230 services
= SCNetworkSetCopyServices(set
);
2231 if (services
!= NULL
) {
2233 CFIndex n
= CFArrayGetCount(services
);
2235 if (!CFArrayContainsValue(services
, CFRangeMake(0, n
), service
)) {
2236 // if selected service not a member of the current set
2237 _SCErrorSet(kSCStatusInvalidArgument
);
2242 for (i
= 0; ok
&& (i
< n
); i
++) {
2243 SCNetworkServiceRef vpn
;
2245 vpn
= CFArrayGetValueAtIndex(services
, i
);
2246 if (!_SCNetworkServiceIsVPN(vpn
)) {
2247 // if not VPN service
2251 ok
= SCNetworkServiceSetEnabled(vpn
, CFEqual(service
, vpn
));
2257 if (services
!= NULL
) CFRelease(services
);
2263 _SCNetworkSetSetSetID(SCNetworkSetRef set
, CFStringRef newSetID
)
2265 SCNetworkSetRef currentSet
= NULL
;
2266 SCNetworkSetPrivateRef currentSetPrivate
= NULL
;
2267 CFDictionaryRef entity
;
2268 CFStringRef newPath
;
2270 CFStringRef oldPath
= NULL
;
2271 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
2272 Boolean updateCurrentSet
= FALSE
;
2274 if (!isA_SCNetworkSet(set
)) {
2275 _SCErrorSet(kSCStatusInvalidArgument
);
2279 if (!isA_CFString(newSetID
)) {
2280 _SCErrorSet(kSCStatusInvalidArgument
);
2284 if (!__SCNetworkSetExists(set
)) {
2285 SC_log(LOG_ERR
, "_SCNetworkSetSetSetID() w/removed set\n set = %@\n setID = %@",
2288 _SC_crash_once("_SCNetworkSetSetSetID() w/removed set", NULL
, NULL
);
2289 _SCErrorSet(kSCStatusInvalidArgument
);
2293 // If newSetID is equal to current setID, our work is done
2294 if (CFEqual(newSetID
, setPrivate
->setID
)) {
2298 newPath
= SCPreferencesPathKeyCreateSet(NULL
, newSetID
);
2299 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, newPath
);
2300 if (isA_CFDictionary(entity
)) {
2301 // if the new set already exists
2302 _SCErrorSet(kSCStatusKeyExists
);
2306 oldPath
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
2307 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, oldPath
);
2308 if (!isA_CFDictionary(entity
)) {
2309 // if the set has already been removed
2310 _SCErrorSet(kSCStatusNoKey
);
2314 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, newPath
, entity
);
2319 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, oldPath
);
2324 // update current set (if needed)
2325 currentSet
= SCNetworkSetCopyCurrent(setPrivate
->prefs
);
2326 if (currentSet
!= NULL
) {
2327 currentSetPrivate
= (SCNetworkSetPrivateRef
)currentSet
;
2328 if (CFEqual(currentSetPrivate
->setID
, setPrivate
->setID
)) {
2329 updateCurrentSet
= TRUE
;
2331 CFRelease(currentSet
);
2334 SC_log(LOG_DEBUG
, "_SCNetworkSetSetID(): %@ --> %@", set
, newSetID
);
2336 // replace setID with new one
2338 CFRelease(setPrivate
->setID
);
2339 setPrivate
->setID
= newSetID
;
2341 if (updateCurrentSet
) {
2342 SCNetworkSetSetCurrent(set
);
2347 if (oldPath
!= NULL
) {
2350 if (newPath
!= NULL
) {