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
);
831 path
= SCPreferencesPathKeyCreateSetNetworkService(NULL
, setPrivate
->setID
, NULL
);
832 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
834 if ((dict
!= NULL
) && !isA_CFDictionary(dict
)) {
838 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
840 n
= (dict
!= NULL
) ? CFDictionaryGetCount(dict
) : 0;
843 const void * keys_q
[N_QUICK
];
844 const void ** keys
= keys_q
;
846 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
847 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
849 CFDictionaryGetKeysAndValues(dict
, keys
, NULL
);
850 for (i
= 0; i
< n
; i
++) {
851 CFArrayRef components
;
854 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
856 (CFStringRef
)keys
[i
],
858 link
= SCPreferencesPathGetLink(setPrivate
->prefs
, path
);
861 SC_log(LOG_INFO
, "service \"%@\" for set \"%@\" is not a link",
864 continue; // if the service is not a link
867 components
= CFStringCreateArrayBySeparatingStrings(NULL
, link
, CFSTR("/"));
868 if (CFArrayGetCount(components
) == 3) {
869 CFStringRef serviceID
;
871 serviceID
= CFArrayGetValueAtIndex(components
, 2);
872 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
873 serviceID
, // service
875 if (CFEqual(path
, link
)) {
876 CFDictionaryRef entity
;
877 CFStringRef interfacePath
;
878 Boolean skip
= FALSE
;
880 interfacePath
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
881 serviceID
, // service
882 kSCEntNetInterface
); // entity
883 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, interfacePath
);
884 CFRelease(interfacePath
);
886 if (__SCNetworkInterfaceEntityIsPPTP(entity
)) {
887 SC_log(LOG_INFO
, "PPTP services are no longer supported");
892 SCNetworkServicePrivateRef servicePrivate
;
894 servicePrivate
= __SCNetworkServiceCreatePrivate(NULL
,
898 CFArrayAppendValue(array
, (SCNetworkServiceRef
)servicePrivate
);
899 CFRelease(servicePrivate
);
904 CFRelease(components
);
906 if (keys
!= keys_q
) {
907 CFAllocatorDeallocate(NULL
, keys
);
916 SCNetworkSetCreate(SCPreferencesRef prefs
)
918 CFArrayRef components
;
919 CFDictionaryRef entity
;
924 SCNetworkSetPrivateRef setPrivate
;
926 prefix
= SCPreferencesPathKeyCreateSets(NULL
);
927 path
= __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs
, prefix
);
928 if (path
== NULL
) path
= SCPreferencesPathCreateUniqueChild(prefs
, prefix
);
934 components
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
935 setID
= CFArrayGetValueAtIndex(components
, 2);
936 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
937 assert(setPrivate
!= NULL
);
938 CFRelease(components
);
940 // mark set as "new" (not yet established)
941 setPrivate
->established
= FALSE
;
943 // establish the set in the preferences
944 entity
= CFDictionaryCreate(NULL
,
946 &kCFTypeDictionaryKeyCallBacks
,
947 &kCFTypeDictionaryValueCallBacks
);
948 ok
= SCPreferencesPathSetValue(prefs
, path
, entity
);
952 CFRelease(setPrivate
);
956 if (setPrivate
!= NULL
) {
957 SC_log(LOG_DEBUG
, "SCNetworkSetCreate(): %@", setPrivate
);
960 return (SCNetworkSetRef
)setPrivate
;
965 _SCNetworkSetCreateDefault(SCPreferencesRef prefs
)
970 CFStringRef setName
= NULL
;
973 set
= SCNetworkSetCopyCurrent(prefs
);
975 SC_log(LOG_NOTICE
, "creating default set w/already existing set");
977 _SCErrorSet(kSCStatusKeyExists
);
981 // create a new ("Automatic") set
982 set
= SCNetworkSetCreate(prefs
);
984 SC_log(LOG_NOTICE
, "could not create \"new\" set: %s",
985 SCErrorString(SCError()));
989 setName
= copy_default_set_name(TRUE
);
990 ok
= SCNetworkSetSetName(set
, setName
);
993 // if we could not save the new set's "name"
994 SC_log(LOG_NOTICE
, "could not save the new set's name: %s",
995 SCErrorString(SCError()));
999 ok
= SCNetworkSetSetCurrent(set
);
1001 // if we could not make this the "current" set
1002 SC_log(LOG_NOTICE
, "could not establish new set as current: %s",
1003 SCErrorString(SCError()));
1007 model
= SCPreferencesGetValue(prefs
, MODEL
);
1008 if (model
== NULL
) {
1009 model
= _SC_hw_model(FALSE
);
1010 SCPreferencesSetValue(prefs
, MODEL
, model
);
1013 version
= SCPreferencesGetValue(prefs
, kSCPrefVersion
);
1014 if (version
== NULL
) {
1015 const int new_version
= NETWORK_CONFIGURATION_VERSION
;
1017 version
= CFNumberCreate(NULL
, kCFNumberIntType
, &new_version
);
1018 SCPreferencesSetValue(prefs
, kSCPrefVersion
, version
);
1024 if (!ok
&& (set
!= NULL
)) {
1025 SCNetworkSetRemove(set
);
1034 SCNetworkSetGetSetID(SCNetworkSetRef set
)
1036 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1038 if (!isA_SCNetworkSet(set
)) {
1039 _SCErrorSet(kSCStatusInvalidArgument
);
1043 return setPrivate
->setID
;
1048 SCNetworkSetGetName(SCNetworkSetRef set
)
1050 CFDictionaryRef entity
;
1052 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1054 if (!isA_SCNetworkSet(set
)) {
1055 _SCErrorSet(kSCStatusInvalidArgument
);
1059 if (setPrivate
->name
!= NULL
) {
1060 return setPrivate
->name
;
1063 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1064 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1067 if (isA_CFDictionary(entity
)) {
1070 name
= CFDictionaryGetValue(entity
, kSCPropUserDefinedName
);
1071 if (isA_CFString(name
)) {
1072 setPrivate
->name
= CFRetain(name
);
1076 if (setPrivate
->name
!= NULL
) {
1077 CFStringRef non_localized
;
1079 non_localized
= copy_default_set_name(FALSE
);
1080 if (CFEqual(setPrivate
->name
, non_localized
)) {
1081 CFStringRef localized
;
1083 // if "Automatic", return localized name
1084 localized
= copy_default_set_name(TRUE
);
1085 CFRelease(setPrivate
->name
);
1086 setPrivate
->name
= localized
;
1089 CFRelease(non_localized
);
1092 return setPrivate
->name
;
1096 CFArrayRef
/* of serviceID CFStringRef's */
1097 SCNetworkSetGetServiceOrder(SCNetworkSetRef set
)
1099 CFDictionaryRef dict
;
1101 CFArrayRef serviceOrder
;
1102 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1104 if (!isA_SCNetworkSet(set
)) {
1105 _SCErrorSet(kSCStatusInvalidArgument
);
1109 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1114 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1116 if (!isA_CFDictionary(dict
)) {
1120 serviceOrder
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
);
1121 serviceOrder
= isA_CFArray(serviceOrder
);
1123 return serviceOrder
;
1128 SCNetworkSetGetTypeID(void)
1130 pthread_once(&initialized
, __SCNetworkSetInitialize
); /* initialize runtime */
1131 return __kSCNetworkSetTypeID
;
1135 #if TARGET_OS_IPHONE
1137 isDefaultSet(SCNetworkSetRef set
)
1139 CFStringRef defaultName
;
1140 Boolean isDefault
= FALSE
;
1141 CFStringRef setName
;
1143 defaultName
= copy_default_set_name(TRUE
);
1144 setName
= SCNetworkSetGetName(set
);
1145 isDefault
= _SC_CFEqual(setName
, defaultName
);
1146 CFRelease(defaultName
);
1150 #endif // TARGET_OS_IPHONE
1154 SCNetworkSetRemove(SCNetworkSetRef set
)
1156 CFStringRef currentPath
;
1159 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1161 if (!isA_SCNetworkSet(set
)) {
1162 _SCErrorSet(kSCStatusInvalidArgument
);
1166 if (!__SCNetworkSetExists(set
)) {
1167 SC_log(LOG_ERR
, "SCNetworkSetRemove() w/removed set\n set = %@", set
);
1168 _SC_crash_once("SCNetworkSetRemove() w/removed set", NULL
, NULL
);
1169 _SCErrorSet(kSCStatusInvalidArgument
);
1172 #if TARGET_OS_IPHONE
1173 if (isDefaultSet(set
) && (geteuid() != 0)) {
1174 SC_log(LOG_ERR
, "SCNetworkSetRemove() failed, cannot remove set : %@", set
);
1175 _SC_crash("The \"Automatic\" network set cannot be removed", NULL
, NULL
);
1176 _SCErrorSet(kSCStatusInvalidArgument
);
1179 #endif // TARGET_OS_IPHONE
1181 currentPath
= SCPreferencesGetValue(setPrivate
->prefs
, kSCPrefCurrentSet
);
1182 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1183 if (!isA_CFString(currentPath
) || !CFEqual(currentPath
, path
)) {
1184 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
1186 SC_log(LOG_DEBUG
, "SCNetworkSetRemove() failed, currently active: %@", setPrivate
->setID
);
1187 _SCErrorSet(kSCStatusInvalidArgument
);
1192 SC_log(LOG_DEBUG
, "SCNetworkSetRemove(): %@", set
);
1200 SCNetworkSetRemoveService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
1202 SCNetworkInterfaceRef interface
;
1203 CFArrayRef interface_config
= NULL
;
1206 int sc_status
= kSCStatusOK
;
1207 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1208 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1210 if (!isA_SCNetworkSet(set
)) {
1211 _SCErrorSet(kSCStatusInvalidArgument
);
1215 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
1216 _SCErrorSet(kSCStatusInvalidArgument
);
1220 if (!__SCNetworkSetExists(set
)) {
1221 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/removed set\n set = %@\n service = %@",
1224 _SC_crash_once("SCNetworkSetRemoveService() w/removed set", NULL
, NULL
);
1225 _SCErrorSet(kSCStatusInvalidArgument
);
1228 if (!__SCNetworkServiceExists(service
)) {
1229 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/removed service\n set = %@\n service = %@",
1232 _SC_crash_once("SCNetworkSetRemoveService() w/removed service", NULL
, NULL
);
1233 _SCErrorSet(kSCStatusInvalidArgument
);
1237 // remove service from ServiceOrder
1238 _serviceOrder_remove(set
, service
);
1240 // get the [deep] interface configuration settings
1241 interface
= SCNetworkServiceGetInterface(service
);
1242 if (interface
!= NULL
) {
1243 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(set
, interface
);
1244 if (interface_config
!= NULL
) {
1245 // remove the interface configuration from all sets which contain this service.
1246 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, NULL
);
1250 // remove the link between "set" and the "service"
1251 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
1253 servicePrivate
->serviceID
,
1255 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
1257 sc_status
= SCError(); // preserve the error
1261 // push the [deep] interface configuration [back] into all sets which contain the service.
1262 if (interface_config
!= NULL
) {
1263 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, interface_config
);
1264 CFRelease(interface_config
);
1268 SC_log(LOG_DEBUG
, "SCNetworkSetRemoveService(): %@, %@", set
, service
);
1270 _SCErrorSet(sc_status
);
1278 SCNetworkSetSetCurrent(SCNetworkSetRef set
)
1282 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1284 if (!isA_SCNetworkSet(set
)) {
1285 _SCErrorSet(kSCStatusInvalidArgument
);
1289 if (!__SCNetworkSetExists(set
)) {
1290 SC_log(LOG_ERR
, "SCNetworkSetSetCurrent() w/removed set\n set = %@", set
);
1291 _SC_crash_once("SCNetworkSetSetCurrent() w/removed set", NULL
, NULL
);
1292 _SCErrorSet(kSCStatusInvalidArgument
);
1296 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1297 ok
= SCPreferencesSetValue(setPrivate
->prefs
, kSCPrefCurrentSet
, path
);
1301 SC_log(LOG_DEBUG
, "SCNetworkSetSetCurrent(): %@", set
);
1309 SCNetworkSetSetName(SCNetworkSetRef set
, CFStringRef name
)
1311 CFDictionaryRef entity
;
1312 #if TARGET_OS_IPHONE
1313 Boolean isDefaultName
= FALSE
;
1314 #endif // TARGET_OS_IPHONE
1315 CFStringRef localized
= NULL
;
1316 CFStringRef non_localized
= NULL
;
1319 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1321 if (!isA_SCNetworkSet(set
)) {
1322 _SCErrorSet(kSCStatusInvalidArgument
);
1326 if (!__SCNetworkSetExists(set
)) {
1327 SC_log(LOG_ERR
, "SCNetworkSetSetName() w/removed set\n set = %@\n name = %@",
1329 name
!= NULL
? name
: CFSTR("<NULL>"));
1330 _SC_crash_once("SCNetworkSetSetName() w/removed set", NULL
, NULL
);
1331 _SCErrorSet(kSCStatusInvalidArgument
);
1335 if ((name
!= NULL
) && !isA_CFString(name
)) {
1336 _SCErrorSet(kSCStatusInvalidArgument
);
1340 // if known, compare against localized name
1343 non_localized
= copy_default_set_name(FALSE
);
1344 if (CFEqual(name
, non_localized
)) {
1345 localized
= copy_default_set_name(TRUE
);
1347 #if TARGET_OS_IPHONE
1348 isDefaultName
= TRUE
;
1349 #endif // TARGET_OS_IPHONE
1351 #if TARGET_OS_IPHONE
1353 localized
= copy_default_set_name(TRUE
);
1354 isDefaultName
= CFEqual(name
, non_localized
);
1356 #endif // TARGET_OS_IPHONE
1359 #if TARGET_OS_IPHONE
1360 if (!isDefaultName
&& isDefaultSet(set
) && (geteuid() != 0)) {
1361 // if we are trying to change the name of the "Automatic" set
1362 SC_log(LOG_ERR
, "SCNetworkSetSetName() failed, cannot rename : %@", set
);
1363 _SC_crash("The \"Automatic\" network set cannot be renamed", NULL
, NULL
);
1364 _SCErrorSet(kSCStatusInvalidArgument
);
1367 #endif // TARGET_OS_IPHONE
1369 #define PREVENT_DUPLICATE_SET_NAMES
1370 #ifdef PREVENT_DUPLICATE_SET_NAMES
1372 #if TARGET_OS_IPHONE
1373 if (!isDefaultName
) {
1374 // On iOS, only block naming multiple sets with the name
1375 // "Automatic". Others names are OK.
1377 #endif // TARGET_OS_IPHONE
1382 // ensure that each set is uniquely named
1384 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1389 n
= CFArrayGetCount(sets
);
1390 for (i
= 0; i
< n
; i
++) {
1391 CFStringRef otherID
;
1392 CFStringRef otherName
;
1393 SCNetworkSetRef set
= CFArrayGetValueAtIndex(sets
, i
);
1395 otherID
= SCNetworkSetGetSetID(set
);
1396 if (CFEqual(setPrivate
->setID
, otherID
)) {
1397 continue; // skip current set
1400 otherName
= SCNetworkSetGetName(set
);
1401 if ((otherName
!= NULL
) && CFEqual(name
, otherName
)) {
1402 // if "name" not unique
1404 _SCErrorSet(kSCStatusKeyExists
);
1411 #endif /* PREVENT_DUPLICATE_SET_NAMES */
1413 // if known, store non-localized name
1415 if ((name
!= NULL
) && (non_localized
!= NULL
)) {
1416 if (localized
== NULL
) {
1417 localized
= copy_default_set_name(TRUE
);
1419 if (CFEqual(name
, localized
)) {
1420 name
= non_localized
;
1424 // update the "name"
1426 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1427 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1428 if (isA_CFDictionary(entity
) ||
1429 ((entity
== NULL
) && (name
!= NULL
))) {
1430 CFMutableDictionaryRef newEntity
;
1432 if (entity
!= NULL
) {
1433 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1435 newEntity
= CFDictionaryCreateMutable(NULL
,
1437 &kCFTypeDictionaryKeyCallBacks
,
1438 &kCFTypeDictionaryValueCallBacks
);
1441 CFDictionarySetValue(newEntity
, kSCPropUserDefinedName
, name
);
1443 CFDictionaryRemoveValue(newEntity
, kSCPropUserDefinedName
);
1445 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newEntity
);
1446 CFRelease(newEntity
);
1453 SC_log(LOG_DEBUG
, "SCNetworkSetSetName(): %@", set
);
1456 if (localized
!= NULL
) CFRelease(localized
);
1457 if (non_localized
!= NULL
) CFRelease(non_localized
);
1463 SCNetworkSetSetServiceOrder(SCNetworkSetRef set
, CFArrayRef newOrder
)
1465 CFMutableArrayRef cleanOrder
;
1466 CFDictionaryRef dict
;
1469 CFMutableDictionaryRef newDict
;
1472 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1474 if (!isA_SCNetworkSet(set
)) {
1475 _SCErrorSet(kSCStatusInvalidArgument
);
1479 if (!__SCNetworkSetExists(set
)) {
1480 SC_log(LOG_ERR
, "SCNetworkSetSetServiceOrder() w/removed set\n set = %@", set
);
1481 _SC_crash_once("SCNetworkSetSetServiceOrder() w/removed set", NULL
, NULL
);
1482 _SCErrorSet(kSCStatusInvalidArgument
);
1486 if (isA_CFArray(newOrder
)) {
1487 n
= CFArrayGetCount(newOrder
);
1488 for (i
= 0; i
< n
; i
++) {
1489 CFStringRef serviceID
;
1491 serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1492 if (!isA_CFString(serviceID
)) {
1493 _SCErrorSet(kSCStatusInvalidArgument
);
1498 _SCErrorSet(kSCStatusInvalidArgument
);
1502 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1507 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1509 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
1511 newDict
= CFDictionaryCreateMutable(NULL
,
1513 &kCFTypeDictionaryKeyCallBacks
,
1514 &kCFTypeDictionaryValueCallBacks
);
1517 cleanOrder
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1518 n
= CFArrayGetCount(newOrder
);
1519 for (i
= 0; i
< n
; i
++) {
1520 CFIndex nClean
= CFArrayGetCount(cleanOrder
);
1521 CFStringRef serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1523 if ((nClean
== 0) ||
1524 !CFArrayContainsValue(cleanOrder
, CFRangeMake(0, nClean
), serviceID
)) {
1525 // if first reference to this serviceID
1526 CFArrayAppendValue(cleanOrder
, serviceID
);
1528 // skip duplicate serviceID
1529 SC_log(LOG_ERR
, "SCNetworkSetSetServiceOrder() found duplicate serviceID: removed %@\n", serviceID
);
1532 CFDictionarySetValue(newDict
, kSCPropNetServiceOrder
, cleanOrder
);
1533 CFRelease(cleanOrder
);
1535 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newDict
);
1544 #pragma mark SCNetworkSet SPIs
1549 __SCNetworkSetExists(SCNetworkSetRef set
)
1551 CFDictionaryRef entity
;
1553 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1555 if (setPrivate
->prefs
== NULL
) {
1559 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1560 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1563 if (!isA_CFDictionary(entity
)) {
1573 add_supported_interfaces(CFMutableArrayRef interface_list
, SCNetworkInterfaceRef interface
)
1576 CFArrayRef interface_types
;
1579 interface_types
= SCNetworkInterfaceGetSupportedInterfaceTypes(interface
);
1580 n
= (interface_types
!= NULL
) ? CFArrayGetCount(interface_types
) : 0;
1581 for (i
= 0; i
< n
; i
++) {
1582 SCNetworkInterfaceRef parent
;
1583 CFStringRef interface_type
;
1585 interface_type
= CFArrayGetValueAtIndex(interface_types
, i
);
1586 parent
= SCNetworkInterfaceCreateWithInterface(interface
, interface_type
);
1587 if (parent
!= NULL
) {
1588 CFArrayAppendValue(interface_list
, parent
);
1597 static CFSetRef
/* of SCNetworkInterfaceRef's */
1598 copyExcludedInterfaces(SCPreferencesRef prefs
)
1600 CFMutableSetRef excluded
;
1601 CFArrayRef interfaces
;
1603 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1605 #if !TARGET_OS_IPHONE
1606 // exclude Bond [member] interfaces
1607 interfaces
= SCBondInterfaceCopyAll(prefs
);
1608 if (interfaces
!= NULL
) {
1609 __SCBondInterfaceListCollectMembers(interfaces
, excluded
);
1610 CFRelease(interfaces
);
1612 #endif // !TARGET_OS_IPHONE
1614 // exclude Bridge [member] interfaces
1615 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
1616 if (interfaces
!= NULL
) {
1617 __SCBridgeInterfaceListCollectMembers(interfaces
, excluded
);
1618 CFRelease(interfaces
);
1625 #if !TARGET_OS_IPHONE
1626 static SCBridgeInterfaceRef
1627 copyAutoBridgeInterface(SCPreferencesRef prefs
, CFStringRef bridgeName
)
1629 SCBridgeInterfaceRef bridge
= NULL
;
1630 CFArrayRef interfaces
;
1632 // exclude Bridge [member] interfaces
1633 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
1634 if (interfaces
!= NULL
) {
1638 n
= CFArrayGetCount(interfaces
);
1639 for (i
= 0; i
< n
; i
++) {
1640 SCBridgeInterfaceRef interface
;
1641 CFStringRef name
= NULL
;
1642 CFDictionaryRef options
;
1644 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1645 options
= SCBridgeInterfaceGetOptions(interface
);
1646 if ((options
!= NULL
) &&
1647 CFDictionaryGetValueIfPresent(options
,
1649 (const void **)&name
) &&
1650 _SC_CFEqual(name
, bridgeName
)) {
1657 CFRelease(interfaces
);
1660 if (bridge
== NULL
) {
1661 bridge
= SCBridgeInterfaceCreate(prefs
);
1662 if (bridge
!= NULL
) {
1663 CFMutableDictionaryRef newOptions
;
1666 newOptions
= CFDictionaryCreateMutable(NULL
, 0,
1667 &kCFTypeDictionaryKeyCallBacks
,
1668 &kCFTypeDictionaryValueCallBacks
);
1669 CFDictionarySetValue(newOptions
, CFSTR("__AUTO__"), bridgeName
);
1670 ok
= SCBridgeInterfaceSetOptions(bridge
, newOptions
);
1671 CFRelease(newOptions
);
1681 #endif // !TARGET_OS_IPHONE
1685 copyServices(SCNetworkSetRef set
)
1687 CFArrayRef services
;
1688 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1690 // first, assume that we only want to add new services
1691 // for those interfaces that are not represented in the
1693 services
= SCNetworkSetCopyServices(set
);
1694 if ((services
!= NULL
) && setPrivate
->established
) {
1695 // but, if we are given an existing (or "established") set
1696 // than we only want to add new services for those interfaces
1697 // that are not represented in *any* set.
1698 CFRelease(services
);
1699 services
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1706 #if !TARGET_OS_IPHONE
1707 static CF_RETURNS_RETAINED CFArrayRef
1708 updateServices(CFArrayRef services
, SCNetworkInterfaceRef interface
)
1710 CFStringRef bsdName
;
1713 CFMutableArrayRef newServices
;
1715 if (services
== NULL
) {
1719 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
1721 newServices
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1723 n
= CFArrayGetCount(services
);
1724 for (i
= 0; i
< n
; i
++) {
1725 SCNetworkInterfaceRef interface
;
1726 CFStringRef interfaceName
;
1727 SCNetworkServiceRef newService
;
1728 SCNetworkServiceRef service
;
1729 CFStringRef serviceID
;
1730 SCNetworkServicePrivateRef servicePrivate
;
1732 service
= CFArrayGetValueAtIndex(services
, i
);
1733 interface
= SCNetworkServiceGetInterface(service
);
1734 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
1735 if (!_SC_CFEqual(interfaceName
, bsdName
)) {
1736 // if not a match, retain
1737 CFArrayAppendValue(newServices
, service
);
1741 // if a match, update
1742 serviceID
= SCNetworkServiceGetServiceID(service
);
1743 servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1744 newService
= SCNetworkServiceCopy(servicePrivate
->prefs
, serviceID
);
1745 if (newService
!= NULL
) {
1746 CFArrayAppendValue(newServices
, newService
);
1747 CFRelease(newService
);
1753 #endif // !TARGET_OS_IPHONE
1756 static __inline__ Boolean
1757 skipInterface(SCNetworkInterfaceRef interface
)
1761 action
= _SCNetworkInterfaceGetConfigurationAction(interface
);
1762 if (isA_CFString(action
) &&
1763 CFEqual(action
, kSCNetworkInterfaceConfigurationActionValueNone
)) {
1772 _SCNetworkSetCompare(const void *val1
, const void *val2
, void *context
)
1774 #pragma unused(context)
1779 SCNetworkSetRef s1
= (SCNetworkSetRef
)val1
;
1780 SCNetworkSetRef s2
= (SCNetworkSetRef
)val2
;
1782 name1
= SCNetworkSetGetName(s1
);
1783 name2
= SCNetworkSetGetName(s2
);
1785 if (name1
!= NULL
) {
1786 if (name2
!= NULL
) {
1787 return CFStringCompare(name1
, name2
, 0);
1789 return kCFCompareLessThan
;
1793 if (name2
!= NULL
) {
1794 return kCFCompareGreaterThan
;
1797 id1
= SCNetworkSetGetSetID(s1
);
1798 id2
= SCNetworkSetGetSetID(s2
);
1799 return CFStringCompare(id1
, id2
, 0);
1804 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set
, CFArrayRef interfaces
, Boolean excludeHidden
)
1810 CFArrayRef services
;
1811 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1812 Boolean updated
= FALSE
;
1813 #if !TARGET_OS_IPHONE
1814 Boolean updatedIFs
= FALSE
;
1815 #endif // !TARGET_OS_IPHONE
1817 #if TARGET_OS_IPHONE
1818 CFArrayRef orphans
= NULL
;
1821 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1823 if (CFArrayGetCount(sets
) == 1) {
1824 services
= SCNetworkSetCopyServices(set
);
1825 if (services
!= NULL
) {
1826 n
= CFArrayGetCount(services
);
1827 CFRelease(services
);
1830 if ((n
== 0) && CFEqual(set
, CFArrayGetValueAtIndex(sets
, 0))) {
1831 // after a "Reset Network Settings" we need to find (and
1832 // add back) any VPN services that were orphaned.
1833 orphans
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1839 #endif // TARGET_OS_IPHONE
1841 // copy network services
1842 services
= copyServices(set
);
1844 // copy network interfaces to be excluded
1845 excluded
= copyExcludedInterfaces(setPrivate
->prefs
);
1847 #if !TARGET_OS_IPHONE
1848 // look for interfaces that should auto-magically be added
1849 // to an Ethernet bridge
1850 n
= ((services
!= NULL
) && (interfaces
!= NULL
)) ? CFArrayGetCount(interfaces
) : 0;
1851 for (i
= 0; i
< n
; i
++) {
1852 SCBridgeInterfaceRef bridge
= NULL
;
1853 SCNetworkInterfaceRef interface
;
1855 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1857 if (excludeHidden
&& skipInterface(interface
)) {
1858 // if not auto-configure
1862 if (CFSetContainsValue(excluded
, interface
)) {
1863 // if this interface is a member of a Bond or Bridge
1867 if (__SCNetworkServiceExistsForInterface(services
, interface
)) {
1868 // if this is not a new interface
1872 if (_SCNetworkInterfaceIsBuiltin(interface
) &&
1873 _SCNetworkInterfaceIsThunderbolt(interface
) &&
1874 !isA_SCBridgeInterface(interface
)) {
1875 // add built-in Thunderbolt interfaces to bridge
1876 bridge
= copyAutoBridgeInterface(setPrivate
->prefs
, CFSTR("thunderbolt-bridge"));
1879 if (bridge
!= NULL
) {
1880 CFIndex bridgeIndex
;
1882 CFMutableArrayRef newMembers
;
1883 CFMutableSetRef newExcluded
;
1884 CFMutableArrayRef newInterfaces
;
1885 CFArrayRef newServices
;
1887 // track the bridge interface (if it's in our list)
1888 bridgeIndex
= CFArrayGetFirstIndexOfValue(interfaces
,
1889 CFRangeMake(0, CFArrayGetCount(interfaces
)),
1892 // add new member interface
1893 members
= SCBridgeInterfaceGetMemberInterfaces(bridge
);
1894 if ((members
!= NULL
) && (CFArrayGetCount(members
) > 0)) {
1895 newMembers
= CFArrayCreateMutableCopy(NULL
, 0, members
);
1896 updated
= TRUE
; // if we're updating an existing bridge
1898 newMembers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1900 CFArrayAppendValue(newMembers
, interface
);
1901 ok
= SCBridgeInterfaceSetMemberInterfaces(bridge
, newMembers
);
1902 CFRelease(newMembers
);
1904 SC_log(LOG_INFO
, "could not update bridge with \"%@\": %s",
1905 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1906 SCErrorString(SCError()));
1911 // exclude the new member interface
1912 newExcluded
= CFSetCreateMutableCopy(NULL
, 0, excluded
);
1913 CFRelease(excluded
);
1914 CFSetAddValue(newExcluded
, interface
);
1915 excluded
= newExcluded
;
1917 // update the list of interfaces to include the [new or updated] bridge
1918 newInterfaces
= CFArrayCreateMutableCopy(NULL
, 0, interfaces
);
1919 if (bridgeIndex
!= kCFNotFound
) {
1920 CFArraySetValueAtIndex(newInterfaces
, bridgeIndex
, bridge
);
1922 CFArrayAppendValue(newInterfaces
, bridge
);
1925 CFRelease(interfaces
);
1927 interfaces
= newInterfaces
;
1930 // refresh [existing] services
1931 newServices
= updateServices(services
, bridge
);
1932 if (newServices
!= NULL
) {
1933 CFRelease(services
);
1934 services
= newServices
;
1940 #endif // !TARGET_OS_IPHONE
1942 n
= ((services
!= NULL
) && (interfaces
!= NULL
)) ? CFArrayGetCount(interfaces
) : 0;
1943 for (i
= 0; i
< n
; i
++) {
1944 SCNetworkInterfaceRef interface
;
1945 CFMutableArrayRef interface_list
;
1947 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1949 if (excludeHidden
&& skipInterface(interface
)) {
1950 // if not auto-configure
1954 if (CFSetContainsValue(excluded
, interface
)) {
1955 // if this interface is a member of a Bond or Bridge
1959 if (__SCNetworkServiceExistsForInterface(services
, interface
)) {
1960 // if this is not a new interface
1964 interface_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1965 CFArrayAppendValue(interface_list
, interface
);
1967 while (ok
&& (CFArrayGetCount(interface_list
) > 0)) {
1968 CFArrayRef protocol_types
;
1970 interface
= CFArrayGetValueAtIndex(interface_list
, 0);
1972 protocol_types
= SCNetworkInterfaceGetSupportedProtocolTypes(interface
);
1973 if ((protocol_types
!= NULL
) && (CFArrayGetCount(protocol_types
) > 0)) {
1974 SCNetworkServiceRef service
;
1976 service
= SCNetworkServiceCreate(setPrivate
->prefs
, interface
);
1977 if (service
== NULL
) {
1978 SC_log(LOG_ERR
, "could not create service for \"%@\": %s",
1979 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1980 SCErrorString(SCError()));
1985 ok
= SCNetworkServiceEstablishDefaultConfiguration(service
);
1987 SC_log(LOG_ERR
, "could not estabish default configuration for \"%@\": %s",
1988 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1989 SCErrorString(SCError()));
1990 SCNetworkServiceRemove(service
);
1995 ok
= SCNetworkSetAddService(set
, service
);
1997 SC_log(LOG_ERR
, "could not add service for \"%@\": %s",
1998 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1999 SCErrorString(SCError()));
2000 SCNetworkServiceRemove(service
);
2008 add_supported_interfaces(interface_list
, interface
);
2013 CFArrayRemoveValueAtIndex(interface_list
, 0);
2015 CFRelease(interface_list
);
2017 #if !TARGET_OS_IPHONE
2018 if (updatedIFs
&& (interfaces
!= NULL
)) {
2019 CFRelease(interfaces
);
2021 #endif // !TARGET_OS_IPHONE
2022 if (services
!= NULL
) CFRelease(services
);
2023 CFRelease(excluded
);
2025 #if TARGET_OS_IPHONE
2026 if (orphans
!= NULL
) {
2027 if (ok
&& updated
) {
2029 CFIndex n
= CFArrayGetCount(orphans
);
2031 for (i
= 0; i
< n
; i
++) {
2032 SCNetworkServiceRef service
;
2034 service
= CFArrayGetValueAtIndex(orphans
, i
);
2035 if (_SCNetworkServiceIsVPN(service
)) {
2036 ok
= SCNetworkSetAddService(set
, service
);
2046 #endif // TARGET_OS_IPHONE
2052 model
= SCPreferencesGetValue(setPrivate
->prefs
, MODEL
);
2053 if (model
== NULL
) {
2054 model
= _SC_hw_model(FALSE
);
2055 SCPreferencesSetValue(setPrivate
->prefs
, MODEL
, model
);
2058 // if no changes were made
2059 _SCErrorSet(kSCStatusOK
);
2068 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set
)
2070 CFArrayRef interfaces
;
2071 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
2072 Boolean updated
= FALSE
;
2074 if (!isA_SCNetworkSet(set
)) {
2075 _SCErrorSet(kSCStatusInvalidArgument
);
2079 interfaces
= _SCNetworkInterfaceCopyAllWithPreferences(setPrivate
->prefs
);
2080 if (interfaces
!= NULL
) {
2081 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
, TRUE
);
2082 CFRelease(interfaces
);
2090 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set
, SCNetworkInterfaceRef interface
)
2092 CFArrayRef interfaces
;
2095 if (!isA_SCNetworkSet(set
)) {
2096 _SCErrorSet(kSCStatusInvalidArgument
);
2100 if (!isA_SCNetworkInterface(interface
)) {
2101 _SCErrorSet(kSCStatusInvalidArgument
);
2105 interfaces
= CFArrayCreate(NULL
, (const void **)&interface
, 1, &kCFTypeArrayCallBacks
);
2106 assert(interfaces
!= NULL
);
2107 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
, FALSE
);
2108 CFRelease(interfaces
);
2115 SCNetworkSetCopySelectedVPNService(SCNetworkSetRef set
)
2119 SCNetworkServiceRef selected
= NULL
;
2120 CFArrayRef services
;
2121 CFMutableArrayRef services_vpn
= NULL
;
2123 if (!isA_SCNetworkSet(set
)) {
2124 _SCErrorSet(kSCStatusInvalidArgument
);
2128 services
= SCNetworkSetCopyServices(set
);
2129 if (services
!= NULL
) {
2130 n
= CFArrayGetCount(services
);
2131 for (i
= 0; i
< n
; i
++) {
2132 SCNetworkServiceRef service
;
2134 service
= CFArrayGetValueAtIndex(services
, i
);
2135 if (!SCNetworkServiceGetEnabled(service
)) {
2140 if (!_SCNetworkServiceIsVPN(service
)) {
2141 // if not VPN service
2145 if (services_vpn
== NULL
) {
2146 services_vpn
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2148 CFArrayAppendValue(services_vpn
, service
);
2151 CFRelease(services
);
2154 if (services_vpn
== NULL
) {
2155 // if no VPN services
2159 n
= CFArrayGetCount(services_vpn
);
2162 CFMutableArrayRef sorted
;
2164 order
= SCNetworkSetGetServiceOrder(set
);
2165 sorted
= CFArrayCreateMutableCopy(NULL
, 0, services_vpn
);
2166 CFArraySortValues(sorted
,
2167 CFRangeMake(0, CFArrayGetCount(sorted
)),
2168 _SCNetworkServiceCompare
,
2170 CFRelease(services_vpn
);
2171 services_vpn
= sorted
;
2174 #if TARGET_OS_IPHONE
2176 CFStringRef serviceID_prefs
;
2178 #define VPN_PREFERENCES CFSTR("com.apple.mobilevpn")
2179 #define VPN_SERVICE_ID CFSTR("activeVPNID")
2181 CFPreferencesAppSynchronize(VPN_PREFERENCES
);
2182 serviceID_prefs
= CFPreferencesCopyAppValue(VPN_SERVICE_ID
, VPN_PREFERENCES
);
2183 if (serviceID_prefs
!= NULL
) {
2184 for (i
= 0; i
< n
; i
++) {
2185 SCNetworkServiceRef service
;
2186 CFStringRef serviceID
;
2188 service
= CFArrayGetValueAtIndex(services_vpn
, i
);
2189 serviceID
= SCNetworkServiceGetServiceID(service
);
2190 if (CFEqual(serviceID
, serviceID_prefs
)) {
2198 CFRelease(serviceID_prefs
);
2201 #endif // TARGET_OS_IPHONE
2203 if (selected
== NULL
) {
2204 selected
= CFArrayGetValueAtIndex(services_vpn
, 0);
2208 CFRelease(services_vpn
);
2214 SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
2217 CFArrayRef services
;
2219 if (!isA_SCNetworkSet(set
)) {
2220 _SCErrorSet(kSCStatusInvalidArgument
);
2224 if (!isA_SCNetworkService(service
) || !_SCNetworkServiceIsVPN(service
)) {
2225 _SCErrorSet(kSCStatusInvalidArgument
);
2229 services
= SCNetworkSetCopyServices(set
);
2230 if (services
!= NULL
) {
2232 CFIndex n
= CFArrayGetCount(services
);
2234 if (!CFArrayContainsValue(services
, CFRangeMake(0, n
), service
)) {
2235 // if selected service not a member of the current set
2236 _SCErrorSet(kSCStatusInvalidArgument
);
2241 for (i
= 0; ok
&& (i
< n
); i
++) {
2242 SCNetworkServiceRef vpn
;
2244 vpn
= CFArrayGetValueAtIndex(services
, i
);
2245 if (!_SCNetworkServiceIsVPN(vpn
)) {
2246 // if not VPN service
2250 ok
= SCNetworkServiceSetEnabled(vpn
, CFEqual(service
, vpn
));
2256 if (services
!= NULL
) CFRelease(services
);
2262 _SCNetworkSetSetSetID(SCNetworkSetRef set
, CFStringRef newSetID
)
2264 SCNetworkSetRef currentSet
= NULL
;
2265 SCNetworkSetPrivateRef currentSetPrivate
= NULL
;
2266 CFDictionaryRef entity
;
2267 CFStringRef newPath
;
2269 CFStringRef oldPath
= NULL
;
2270 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
2271 Boolean updateCurrentSet
= FALSE
;
2273 if (!isA_SCNetworkSet(set
)) {
2274 _SCErrorSet(kSCStatusInvalidArgument
);
2278 if (!isA_CFString(newSetID
)) {
2279 _SCErrorSet(kSCStatusInvalidArgument
);
2283 if (!__SCNetworkSetExists(set
)) {
2284 SC_log(LOG_ERR
, "_SCNetworkSetSetSetID() w/removed set\n set = %@\n setID = %@",
2287 _SC_crash_once("_SCNetworkSetSetSetID() w/removed set", NULL
, NULL
);
2288 _SCErrorSet(kSCStatusInvalidArgument
);
2292 // If newSetID is equal to current setID, our work is done
2293 if (CFEqual(newSetID
, setPrivate
->setID
)) {
2297 newPath
= SCPreferencesPathKeyCreateSet(NULL
, newSetID
);
2298 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, newPath
);
2299 if (isA_CFDictionary(entity
)) {
2300 // if the new set already exists
2301 _SCErrorSet(kSCStatusKeyExists
);
2305 oldPath
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
2306 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, oldPath
);
2307 if (!isA_CFDictionary(entity
)) {
2308 // if the set has already been removed
2309 _SCErrorSet(kSCStatusNoKey
);
2313 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, newPath
, entity
);
2318 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, oldPath
);
2323 // update current set (if needed)
2324 currentSet
= SCNetworkSetCopyCurrent(setPrivate
->prefs
);
2325 if (currentSet
!= NULL
) {
2326 currentSetPrivate
= (SCNetworkSetPrivateRef
)currentSet
;
2327 if (CFEqual(currentSetPrivate
->setID
, setPrivate
->setID
)) {
2328 updateCurrentSet
= TRUE
;
2330 CFRelease(currentSet
);
2333 SC_log(LOG_DEBUG
, "_SCNetworkSetSetID(): %@ --> %@", set
, newSetID
);
2335 // replace setID with new one
2337 CFRelease(setPrivate
->setID
);
2338 setPrivate
->setID
= newSetID
;
2340 if (updateCurrentSet
) {
2341 SCNetworkSetSetCurrent(set
);
2346 if (oldPath
!= NULL
) {
2349 if (newPath
!= NULL
) {