2 * Copyright (c) 2004-2019 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
;
972 set
= SCNetworkSetCopyCurrent(prefs
);
974 SC_log(LOG_NOTICE
, "creating default set w/already existing set");
976 _SCErrorSet(kSCStatusKeyExists
);
980 // create a new ("Automatic") set
981 set
= SCNetworkSetCreate(prefs
);
983 SC_log(LOG_NOTICE
, "could not create \"new\" set: %s",
984 SCErrorString(SCError()));
988 setName
= copy_default_set_name(TRUE
);
989 ok
= SCNetworkSetSetName(set
, setName
);
992 // if we could not save the new set's "name"
993 SC_log(LOG_NOTICE
, "could not save the new set's name: %s",
994 SCErrorString(SCError()));
998 ok
= SCNetworkSetSetCurrent(set
);
1000 // if we could not make this the "current" set
1001 SC_log(LOG_NOTICE
, "could not establish new set as current: %s",
1002 SCErrorString(SCError()));
1006 model
= SCPreferencesGetValue(prefs
, MODEL
);
1007 if (model
== NULL
) {
1008 model
= _SC_hw_model(FALSE
);
1009 SCPreferencesSetValue(prefs
, MODEL
, model
);
1014 if (!ok
&& (set
!= NULL
)) {
1015 SCNetworkSetRemove(set
);
1024 SCNetworkSetGetSetID(SCNetworkSetRef set
)
1026 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1028 if (!isA_SCNetworkSet(set
)) {
1029 _SCErrorSet(kSCStatusInvalidArgument
);
1033 return setPrivate
->setID
;
1038 SCNetworkSetGetName(SCNetworkSetRef set
)
1040 CFDictionaryRef entity
;
1042 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1044 if (!isA_SCNetworkSet(set
)) {
1045 _SCErrorSet(kSCStatusInvalidArgument
);
1049 if (setPrivate
->name
!= NULL
) {
1050 return setPrivate
->name
;
1053 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1054 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1057 if (isA_CFDictionary(entity
)) {
1060 name
= CFDictionaryGetValue(entity
, kSCPropUserDefinedName
);
1061 if (isA_CFString(name
)) {
1062 setPrivate
->name
= CFRetain(name
);
1066 if (setPrivate
->name
!= NULL
) {
1067 CFStringRef non_localized
;
1069 non_localized
= copy_default_set_name(FALSE
);
1070 if (CFEqual(setPrivate
->name
, non_localized
)) {
1071 CFStringRef localized
;
1073 // if "Automatic", return localized name
1074 localized
= copy_default_set_name(TRUE
);
1075 CFRelease(setPrivate
->name
);
1076 setPrivate
->name
= localized
;
1079 CFRelease(non_localized
);
1082 return setPrivate
->name
;
1086 CFArrayRef
/* of serviceID CFStringRef's */
1087 SCNetworkSetGetServiceOrder(SCNetworkSetRef set
)
1089 CFDictionaryRef dict
;
1091 CFArrayRef serviceOrder
;
1092 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1094 if (!isA_SCNetworkSet(set
)) {
1095 _SCErrorSet(kSCStatusInvalidArgument
);
1099 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1104 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1106 if (!isA_CFDictionary(dict
)) {
1110 serviceOrder
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
);
1111 serviceOrder
= isA_CFArray(serviceOrder
);
1113 return serviceOrder
;
1118 SCNetworkSetGetTypeID(void)
1120 pthread_once(&initialized
, __SCNetworkSetInitialize
); /* initialize runtime */
1121 return __kSCNetworkSetTypeID
;
1125 #if TARGET_OS_IPHONE
1127 isDefaultSet(SCNetworkSetRef set
)
1129 CFStringRef defaultName
;
1130 Boolean isDefault
= FALSE
;
1131 CFStringRef setName
;
1133 defaultName
= copy_default_set_name(TRUE
);
1134 setName
= SCNetworkSetGetName(set
);
1135 isDefault
= _SC_CFEqual(setName
, defaultName
);
1136 CFRelease(defaultName
);
1140 #endif // TARGET_OS_IPHONE
1144 SCNetworkSetRemove(SCNetworkSetRef set
)
1146 CFStringRef currentPath
;
1149 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1151 if (!isA_SCNetworkSet(set
)) {
1152 _SCErrorSet(kSCStatusInvalidArgument
);
1156 if (!__SCNetworkSetExists(set
)) {
1157 SC_log(LOG_ERR
, "SCNetworkSetRemove() w/removed set\n set = %@", set
);
1158 _SC_crash_once("SCNetworkSetRemove() w/removed set", NULL
, NULL
);
1159 _SCErrorSet(kSCStatusInvalidArgument
);
1162 #if TARGET_OS_IPHONE
1163 if (isDefaultSet(set
) && (geteuid() != 0)) {
1164 SC_log(LOG_ERR
, "SCNetworkSetRemove() failed, cannot remove set : %@", set
);
1165 _SC_crash("The \"Automatic\" network set cannot be removed", NULL
, NULL
);
1166 _SCErrorSet(kSCStatusInvalidArgument
);
1169 #endif // TARGET_OS_IPHONE
1171 currentPath
= SCPreferencesGetValue(setPrivate
->prefs
, kSCPrefCurrentSet
);
1172 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1173 if (!isA_CFString(currentPath
) || !CFEqual(currentPath
, path
)) {
1174 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
1176 SC_log(LOG_DEBUG
, "SCNetworkSetRemove() failed, currently active: %@", setPrivate
->setID
);
1177 _SCErrorSet(kSCStatusInvalidArgument
);
1182 SC_log(LOG_DEBUG
, "SCNetworkSetRemove(): %@", set
);
1190 SCNetworkSetRemoveService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
1192 SCNetworkInterfaceRef interface
;
1193 CFArrayRef interface_config
= NULL
;
1196 int sc_status
= kSCStatusOK
;
1197 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1198 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1200 if (!isA_SCNetworkSet(set
)) {
1201 _SCErrorSet(kSCStatusInvalidArgument
);
1205 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
1206 _SCErrorSet(kSCStatusInvalidArgument
);
1210 if (!__SCNetworkSetExists(set
)) {
1211 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/removed set\n set = %@\n service = %@",
1214 _SC_crash_once("SCNetworkSetRemoveService() w/removed set", NULL
, NULL
);
1215 _SCErrorSet(kSCStatusInvalidArgument
);
1218 if (!__SCNetworkServiceExists(service
)) {
1219 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() w/removed service\n set = %@\n service = %@",
1222 _SC_crash_once("SCNetworkSetRemoveService() w/removed service", NULL
, NULL
);
1223 _SCErrorSet(kSCStatusInvalidArgument
);
1227 // remove service from ServiceOrder
1228 _serviceOrder_remove(set
, service
);
1230 // get the [deep] interface configuration settings
1231 interface
= SCNetworkServiceGetInterface(service
);
1232 if (interface
!= NULL
) {
1233 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(set
, interface
);
1234 if (interface_config
!= NULL
) {
1235 // remove the interface configuration from all sets which contain this service.
1236 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, NULL
);
1240 // remove the link between "set" and the "service"
1241 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
1243 servicePrivate
->serviceID
,
1245 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
1247 sc_status
= SCError(); // preserve the error
1251 // push the [deep] interface configuration [back] into all sets which contain the service.
1252 if (interface_config
!= NULL
) {
1253 __SCNetworkInterfaceSetDeepConfiguration(set
, interface
, interface_config
);
1254 CFRelease(interface_config
);
1258 SC_log(LOG_DEBUG
, "SCNetworkSetRemoveService(): %@, %@", set
, service
);
1260 _SCErrorSet(sc_status
);
1268 SCNetworkSetSetCurrent(SCNetworkSetRef set
)
1272 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1274 if (!isA_SCNetworkSet(set
)) {
1275 _SCErrorSet(kSCStatusInvalidArgument
);
1279 if (!__SCNetworkSetExists(set
)) {
1280 SC_log(LOG_ERR
, "SCNetworkSetSetCurrent() w/removed set\n set = %@", set
);
1281 _SC_crash_once("SCNetworkSetSetCurrent() w/removed set", NULL
, NULL
);
1282 _SCErrorSet(kSCStatusInvalidArgument
);
1286 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1287 ok
= SCPreferencesSetValue(setPrivate
->prefs
, kSCPrefCurrentSet
, path
);
1291 SC_log(LOG_DEBUG
, "SCNetworkSetSetCurrent(): %@", set
);
1299 SCNetworkSetSetName(SCNetworkSetRef set
, CFStringRef name
)
1301 CFDictionaryRef entity
;
1302 #if TARGET_OS_IPHONE
1303 Boolean isDefaultName
= FALSE
;
1304 #endif // TARGET_OS_IPHONE
1305 CFStringRef localized
= NULL
;
1306 CFStringRef non_localized
= NULL
;
1309 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1311 if (!isA_SCNetworkSet(set
)) {
1312 _SCErrorSet(kSCStatusInvalidArgument
);
1316 if (!__SCNetworkSetExists(set
)) {
1317 SC_log(LOG_ERR
, "SCNetworkSetSetName() w/removed set\n set = %@\n name = %@",
1319 name
!= NULL
? name
: CFSTR("<NULL>"));
1320 _SC_crash_once("SCNetworkSetSetName() w/removed set", NULL
, NULL
);
1321 _SCErrorSet(kSCStatusInvalidArgument
);
1325 if ((name
!= NULL
) && !isA_CFString(name
)) {
1326 _SCErrorSet(kSCStatusInvalidArgument
);
1330 // if known, compare against localized name
1333 non_localized
= copy_default_set_name(FALSE
);
1334 if (CFEqual(name
, non_localized
)) {
1335 localized
= copy_default_set_name(TRUE
);
1337 #if TARGET_OS_IPHONE
1338 isDefaultName
= TRUE
;
1339 #endif // TARGET_OS_IPHONE
1341 #if TARGET_OS_IPHONE
1343 localized
= copy_default_set_name(TRUE
);
1344 isDefaultName
= CFEqual(name
, non_localized
);
1346 #endif // TARGET_OS_IPHONE
1349 #if TARGET_OS_IPHONE
1350 if (!isDefaultName
&& isDefaultSet(set
) && (geteuid() != 0)) {
1351 // if we are trying to change the name of the "Automatic" set
1352 SC_log(LOG_ERR
, "SCNetworkSetSetName() failed, cannot rename : %@", set
);
1353 _SC_crash("The \"Automatic\" network set cannot be renamed", NULL
, NULL
);
1354 _SCErrorSet(kSCStatusInvalidArgument
);
1357 #endif // TARGET_OS_IPHONE
1359 #define PREVENT_DUPLICATE_SET_NAMES
1360 #ifdef PREVENT_DUPLICATE_SET_NAMES
1362 #if TARGET_OS_IPHONE
1363 if (!isDefaultName
) {
1364 // On iOS, only block naming multiple sets with the name
1365 // "Automatic". Others names are OK.
1367 #endif // TARGET_OS_IPHONE
1372 // ensure that each set is uniquely named
1374 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1379 n
= CFArrayGetCount(sets
);
1380 for (i
= 0; i
< n
; i
++) {
1381 CFStringRef otherID
;
1382 CFStringRef otherName
;
1383 SCNetworkSetRef set
= CFArrayGetValueAtIndex(sets
, i
);
1385 otherID
= SCNetworkSetGetSetID(set
);
1386 if (CFEqual(setPrivate
->setID
, otherID
)) {
1387 continue; // skip current set
1390 otherName
= SCNetworkSetGetName(set
);
1391 if ((otherName
!= NULL
) && CFEqual(name
, otherName
)) {
1392 // if "name" not unique
1394 _SCErrorSet(kSCStatusKeyExists
);
1401 #endif /* PREVENT_DUPLICATE_SET_NAMES */
1403 // if known, store non-localized name
1405 if ((name
!= NULL
) && (non_localized
!= NULL
)) {
1406 if (localized
== NULL
) {
1407 localized
= copy_default_set_name(TRUE
);
1409 if (CFEqual(name
, localized
)) {
1410 name
= non_localized
;
1414 // update the "name"
1416 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1417 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1418 if (isA_CFDictionary(entity
) ||
1419 ((entity
== NULL
) && (name
!= NULL
))) {
1420 CFMutableDictionaryRef newEntity
;
1422 if (entity
!= NULL
) {
1423 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1425 newEntity
= CFDictionaryCreateMutable(NULL
,
1427 &kCFTypeDictionaryKeyCallBacks
,
1428 &kCFTypeDictionaryValueCallBacks
);
1431 CFDictionarySetValue(newEntity
, kSCPropUserDefinedName
, name
);
1433 CFDictionaryRemoveValue(newEntity
, kSCPropUserDefinedName
);
1435 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newEntity
);
1436 CFRelease(newEntity
);
1443 SC_log(LOG_DEBUG
, "SCNetworkSetSetName(): %@", set
);
1446 if (localized
!= NULL
) CFRelease(localized
);
1447 if (non_localized
!= NULL
) CFRelease(non_localized
);
1453 SCNetworkSetSetServiceOrder(SCNetworkSetRef set
, CFArrayRef newOrder
)
1455 CFMutableArrayRef cleanOrder
;
1456 CFDictionaryRef dict
;
1459 CFMutableDictionaryRef newDict
;
1462 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1464 if (!isA_SCNetworkSet(set
)) {
1465 _SCErrorSet(kSCStatusInvalidArgument
);
1469 if (!__SCNetworkSetExists(set
)) {
1470 SC_log(LOG_ERR
, "SCNetworkSetSetServiceOrder() w/removed set\n set = %@", set
);
1471 _SC_crash_once("SCNetworkSetSetServiceOrder() w/removed set", NULL
, NULL
);
1472 _SCErrorSet(kSCStatusInvalidArgument
);
1476 if (isA_CFArray(newOrder
)) {
1477 n
= CFArrayGetCount(newOrder
);
1478 for (i
= 0; i
< n
; i
++) {
1479 CFStringRef serviceID
;
1481 serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1482 if (!isA_CFString(serviceID
)) {
1483 _SCErrorSet(kSCStatusInvalidArgument
);
1488 _SCErrorSet(kSCStatusInvalidArgument
);
1492 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
1497 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1499 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
1501 newDict
= CFDictionaryCreateMutable(NULL
,
1503 &kCFTypeDictionaryKeyCallBacks
,
1504 &kCFTypeDictionaryValueCallBacks
);
1507 cleanOrder
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1508 n
= CFArrayGetCount(newOrder
);
1509 for (i
= 0; i
< n
; i
++) {
1510 CFIndex nClean
= CFArrayGetCount(cleanOrder
);
1511 CFStringRef serviceID
= CFArrayGetValueAtIndex(newOrder
, i
);
1513 if ((nClean
== 0) ||
1514 !CFArrayContainsValue(cleanOrder
, CFRangeMake(0, nClean
), serviceID
)) {
1515 // if first reference to this serviceID
1516 CFArrayAppendValue(cleanOrder
, serviceID
);
1518 // skip duplicate serviceID
1519 SC_log(LOG_ERR
, "SCNetworkSetSetServiceOrder() found duplicate serviceID: removed %@\n", serviceID
);
1522 CFDictionarySetValue(newDict
, kSCPropNetServiceOrder
, cleanOrder
);
1523 CFRelease(cleanOrder
);
1525 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newDict
);
1534 #pragma mark SCNetworkSet SPIs
1539 __SCNetworkSetExists(SCNetworkSetRef set
)
1541 CFDictionaryRef entity
;
1543 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1545 if (setPrivate
->prefs
== NULL
) {
1549 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
1550 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
1553 if (!isA_CFDictionary(entity
)) {
1563 add_supported_interfaces(CFMutableArrayRef interface_list
, SCNetworkInterfaceRef interface
)
1566 CFArrayRef interface_types
;
1569 interface_types
= SCNetworkInterfaceGetSupportedInterfaceTypes(interface
);
1570 n
= (interface_types
!= NULL
) ? CFArrayGetCount(interface_types
) : 0;
1571 for (i
= 0; i
< n
; i
++) {
1572 SCNetworkInterfaceRef parent
;
1573 CFStringRef interface_type
;
1575 interface_type
= CFArrayGetValueAtIndex(interface_types
, i
);
1576 parent
= SCNetworkInterfaceCreateWithInterface(interface
, interface_type
);
1577 if (parent
!= NULL
) {
1578 CFArrayAppendValue(interface_list
, parent
);
1587 static CFSetRef
/* of SCNetworkInterfaceRef's */
1588 copyExcludedInterfaces(SCPreferencesRef prefs
)
1590 CFMutableSetRef excluded
;
1591 CFArrayRef interfaces
;
1593 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1595 #if !TARGET_OS_IPHONE
1596 // exclude Bond [member] interfaces
1597 interfaces
= SCBondInterfaceCopyAll(prefs
);
1598 if (interfaces
!= NULL
) {
1599 __SCBondInterfaceListCollectMembers(interfaces
, excluded
);
1600 CFRelease(interfaces
);
1602 #endif // !TARGET_OS_IPHONE
1604 // exclude Bridge [member] interfaces
1605 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
1606 if (interfaces
!= NULL
) {
1607 __SCBridgeInterfaceListCollectMembers(interfaces
, excluded
);
1608 CFRelease(interfaces
);
1615 #if !TARGET_OS_IPHONE
1616 static SCBridgeInterfaceRef
1617 copyAutoBridgeInterface(SCPreferencesRef prefs
, CFStringRef bridgeName
)
1619 SCBridgeInterfaceRef bridge
= NULL
;
1620 CFArrayRef interfaces
;
1622 // exclude Bridge [member] interfaces
1623 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
1624 if (interfaces
!= NULL
) {
1628 n
= CFArrayGetCount(interfaces
);
1629 for (i
= 0; i
< n
; i
++) {
1630 SCBridgeInterfaceRef interface
;
1631 CFStringRef name
= NULL
;
1632 CFDictionaryRef options
;
1634 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1635 options
= SCBridgeInterfaceGetOptions(interface
);
1636 if ((options
!= NULL
) &&
1637 CFDictionaryGetValueIfPresent(options
,
1639 (const void **)&name
) &&
1640 _SC_CFEqual(name
, bridgeName
)) {
1647 CFRelease(interfaces
);
1650 if (bridge
== NULL
) {
1651 bridge
= SCBridgeInterfaceCreate(prefs
);
1652 if (bridge
!= NULL
) {
1653 CFMutableDictionaryRef newOptions
;
1656 newOptions
= CFDictionaryCreateMutable(NULL
, 0,
1657 &kCFTypeDictionaryKeyCallBacks
,
1658 &kCFTypeDictionaryValueCallBacks
);
1659 CFDictionarySetValue(newOptions
, CFSTR("__AUTO__"), bridgeName
);
1660 ok
= SCBridgeInterfaceSetOptions(bridge
, newOptions
);
1661 CFRelease(newOptions
);
1671 #endif // !TARGET_OS_IPHONE
1675 copyServices(SCNetworkSetRef set
)
1677 CFArrayRef services
;
1678 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1680 // first, assume that we only want to add new services
1681 // for those interfaces that are not represented in the
1683 services
= SCNetworkSetCopyServices(set
);
1684 if ((services
!= NULL
) && setPrivate
->established
) {
1685 // but, if we are given an existing (or "established") set
1686 // than we only want to add new services for those interfaces
1687 // that are not represented in *any* set.
1688 CFRelease(services
);
1689 services
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1696 #if !TARGET_OS_IPHONE
1697 static CF_RETURNS_RETAINED CFArrayRef
1698 updateServices(CFArrayRef services
, SCNetworkInterfaceRef interface
)
1700 CFStringRef bsdName
;
1703 CFMutableArrayRef newServices
;
1705 if (services
== NULL
) {
1709 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
1711 newServices
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1713 n
= CFArrayGetCount(services
);
1714 for (i
= 0; i
< n
; i
++) {
1715 SCNetworkInterfaceRef interface
;
1716 CFStringRef interfaceName
;
1717 SCNetworkServiceRef newService
;
1718 SCNetworkServiceRef service
;
1719 CFStringRef serviceID
;
1720 SCNetworkServicePrivateRef servicePrivate
;
1722 service
= CFArrayGetValueAtIndex(services
, i
);
1723 interface
= SCNetworkServiceGetInterface(service
);
1724 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
1725 if (!_SC_CFEqual(interfaceName
, bsdName
)) {
1726 // if not a match, retain
1727 CFArrayAppendValue(newServices
, service
);
1731 // if a match, update
1732 serviceID
= SCNetworkServiceGetServiceID(service
);
1733 servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1734 newService
= SCNetworkServiceCopy(servicePrivate
->prefs
, serviceID
);
1735 if (newService
!= NULL
) {
1736 CFArrayAppendValue(newServices
, newService
);
1737 CFRelease(newService
);
1743 #endif // !TARGET_OS_IPHONE
1746 static __inline__ Boolean
1747 skipInterface(SCNetworkInterfaceRef interface
)
1751 action
= _SCNetworkInterfaceGetConfigurationAction(interface
);
1752 if (isA_CFString(action
) &&
1753 CFEqual(action
, kSCNetworkInterfaceConfigurationActionValueNone
)) {
1762 _SCNetworkSetCompare(const void *val1
, const void *val2
, void *context
)
1764 #pragma unused(context)
1769 SCNetworkSetRef s1
= (SCNetworkSetRef
)val1
;
1770 SCNetworkSetRef s2
= (SCNetworkSetRef
)val2
;
1772 name1
= SCNetworkSetGetName(s1
);
1773 name2
= SCNetworkSetGetName(s2
);
1775 if (name1
!= NULL
) {
1776 if (name2
!= NULL
) {
1777 return CFStringCompare(name1
, name2
, 0);
1779 return kCFCompareLessThan
;
1783 if (name2
!= NULL
) {
1784 return kCFCompareGreaterThan
;
1787 id1
= SCNetworkSetGetSetID(s1
);
1788 id2
= SCNetworkSetGetSetID(s2
);
1789 return CFStringCompare(id1
, id2
, 0);
1794 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set
, CFArrayRef interfaces
, Boolean excludeHidden
)
1800 CFArrayRef services
;
1801 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
1802 Boolean updated
= FALSE
;
1803 #if !TARGET_OS_IPHONE
1804 Boolean updatedIFs
= FALSE
;
1805 #endif // !TARGET_OS_IPHONE
1807 #if TARGET_OS_IPHONE
1808 CFArrayRef orphans
= NULL
;
1811 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
1813 if (CFArrayGetCount(sets
) == 1) {
1814 services
= SCNetworkSetCopyServices(set
);
1815 if (services
!= NULL
) {
1816 n
= CFArrayGetCount(services
);
1817 CFRelease(services
);
1820 if ((n
== 0) && CFEqual(set
, CFArrayGetValueAtIndex(sets
, 0))) {
1821 // after a "Reset Network Settings" we need to find (and
1822 // add back) any VPN services that were orphaned.
1823 orphans
= SCNetworkServiceCopyAll(setPrivate
->prefs
);
1829 #endif // TARGET_OS_IPHONE
1831 // copy network services
1832 services
= copyServices(set
);
1834 // copy network interfaces to be excluded
1835 excluded
= copyExcludedInterfaces(setPrivate
->prefs
);
1837 #if !TARGET_OS_IPHONE
1838 // look for interfaces that should auto-magically be added
1839 // to an Ethernet bridge
1840 n
= ((services
!= NULL
) && (interfaces
!= NULL
)) ? CFArrayGetCount(interfaces
) : 0;
1841 for (i
= 0; i
< n
; i
++) {
1842 SCBridgeInterfaceRef bridge
= NULL
;
1843 SCNetworkInterfaceRef interface
;
1845 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1847 if (excludeHidden
&& skipInterface(interface
)) {
1848 // if not auto-configure
1852 if (CFSetContainsValue(excluded
, interface
)) {
1853 // if this interface is a member of a Bond or Bridge
1857 if (__SCNetworkServiceExistsForInterface(services
, interface
)) {
1858 // if this is not a new interface
1862 if (_SCNetworkInterfaceIsBuiltin(interface
) &&
1863 _SCNetworkInterfaceIsThunderbolt(interface
) &&
1864 !isA_SCBridgeInterface(interface
)) {
1865 // add built-in Thunderbolt interfaces to bridge
1866 bridge
= copyAutoBridgeInterface(setPrivate
->prefs
, CFSTR("thunderbolt-bridge"));
1869 if (bridge
!= NULL
) {
1870 CFIndex bridgeIndex
;
1872 CFMutableArrayRef newMembers
;
1873 CFMutableSetRef newExcluded
;
1874 CFMutableArrayRef newInterfaces
;
1875 CFArrayRef newServices
;
1877 // track the bridge interface (if it's in our list)
1878 bridgeIndex
= CFArrayGetFirstIndexOfValue(interfaces
,
1879 CFRangeMake(0, CFArrayGetCount(interfaces
)),
1882 // add new member interface
1883 members
= SCBridgeInterfaceGetMemberInterfaces(bridge
);
1884 if ((members
!= NULL
) && (CFArrayGetCount(members
) > 0)) {
1885 newMembers
= CFArrayCreateMutableCopy(NULL
, 0, members
);
1886 updated
= TRUE
; // if we're updating an existing bridge
1888 newMembers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1890 CFArrayAppendValue(newMembers
, interface
);
1891 ok
= SCBridgeInterfaceSetMemberInterfaces(bridge
, newMembers
);
1892 CFRelease(newMembers
);
1894 SC_log(LOG_INFO
, "could not update bridge with \"%@\": %s",
1895 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1896 SCErrorString(SCError()));
1901 // exclude the new member interface
1902 newExcluded
= CFSetCreateMutableCopy(NULL
, 0, excluded
);
1903 CFRelease(excluded
);
1904 CFSetAddValue(newExcluded
, interface
);
1905 excluded
= newExcluded
;
1907 // update the list of interfaces to include the [new or updated] bridge
1908 newInterfaces
= CFArrayCreateMutableCopy(NULL
, 0, interfaces
);
1909 if (bridgeIndex
!= kCFNotFound
) {
1910 CFArraySetValueAtIndex(newInterfaces
, bridgeIndex
, bridge
);
1912 CFArrayAppendValue(newInterfaces
, bridge
);
1915 CFRelease(interfaces
);
1917 interfaces
= newInterfaces
;
1920 // refresh [existing] services
1921 newServices
= updateServices(services
, bridge
);
1922 if (newServices
!= NULL
) {
1923 CFRelease(services
);
1924 services
= newServices
;
1930 #endif // !TARGET_OS_IPHONE
1932 n
= ((services
!= NULL
) && (interfaces
!= NULL
)) ? CFArrayGetCount(interfaces
) : 0;
1933 for (i
= 0; i
< n
; i
++) {
1934 SCNetworkInterfaceRef interface
;
1935 CFMutableArrayRef interface_list
;
1937 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1939 if (excludeHidden
&& skipInterface(interface
)) {
1940 // if not auto-configure
1944 if (CFSetContainsValue(excluded
, interface
)) {
1945 // if this interface is a member of a Bond or Bridge
1949 if (__SCNetworkServiceExistsForInterface(services
, interface
)) {
1950 // if this is not a new interface
1954 interface_list
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1955 CFArrayAppendValue(interface_list
, interface
);
1957 while (ok
&& (CFArrayGetCount(interface_list
) > 0)) {
1958 CFArrayRef protocol_types
;
1960 interface
= CFArrayGetValueAtIndex(interface_list
, 0);
1962 protocol_types
= SCNetworkInterfaceGetSupportedProtocolTypes(interface
);
1963 if ((protocol_types
!= NULL
) && (CFArrayGetCount(protocol_types
) > 0)) {
1964 SCNetworkServiceRef service
;
1966 service
= SCNetworkServiceCreate(setPrivate
->prefs
, interface
);
1967 if (service
== NULL
) {
1968 SC_log(LOG_ERR
, "could not create service for \"%@\": %s",
1969 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1970 SCErrorString(SCError()));
1975 ok
= SCNetworkServiceEstablishDefaultConfiguration(service
);
1977 SC_log(LOG_ERR
, "could not estabish default configuration for \"%@\": %s",
1978 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1979 SCErrorString(SCError()));
1980 SCNetworkServiceRemove(service
);
1985 ok
= SCNetworkSetAddService(set
, service
);
1987 SC_log(LOG_ERR
, "could not add service for \"%@\": %s",
1988 SCNetworkInterfaceGetLocalizedDisplayName(interface
),
1989 SCErrorString(SCError()));
1990 SCNetworkServiceRemove(service
);
1998 add_supported_interfaces(interface_list
, interface
);
2003 CFArrayRemoveValueAtIndex(interface_list
, 0);
2005 CFRelease(interface_list
);
2007 #if !TARGET_OS_IPHONE
2008 if (updatedIFs
&& (interfaces
!= NULL
)) {
2009 CFRelease(interfaces
);
2011 #endif // !TARGET_OS_IPHONE
2012 if (services
!= NULL
) CFRelease(services
);
2013 CFRelease(excluded
);
2015 #if TARGET_OS_IPHONE
2016 if (orphans
!= NULL
) {
2017 if (ok
&& updated
) {
2019 CFIndex n
= CFArrayGetCount(orphans
);
2021 for (i
= 0; i
< n
; i
++) {
2022 SCNetworkServiceRef service
;
2024 service
= CFArrayGetValueAtIndex(orphans
, i
);
2025 if (_SCNetworkServiceIsVPN(service
)) {
2026 ok
= SCNetworkSetAddService(set
, service
);
2036 #endif // TARGET_OS_IPHONE
2042 model
= SCPreferencesGetValue(setPrivate
->prefs
, MODEL
);
2043 if (model
== NULL
) {
2044 model
= _SC_hw_model(FALSE
);
2045 SCPreferencesSetValue(setPrivate
->prefs
, MODEL
, model
);
2048 // if no changes were made
2049 _SCErrorSet(kSCStatusOK
);
2058 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set
)
2060 CFArrayRef interfaces
;
2061 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
2062 Boolean updated
= FALSE
;
2064 if (!isA_SCNetworkSet(set
)) {
2065 _SCErrorSet(kSCStatusInvalidArgument
);
2069 interfaces
= _SCNetworkInterfaceCopyAllWithPreferences(setPrivate
->prefs
);
2070 if (interfaces
!= NULL
) {
2071 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
, TRUE
);
2072 CFRelease(interfaces
);
2080 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set
, SCNetworkInterfaceRef interface
)
2082 CFArrayRef interfaces
;
2085 if (!isA_SCNetworkSet(set
)) {
2086 _SCErrorSet(kSCStatusInvalidArgument
);
2090 if (!isA_SCNetworkInterface(interface
)) {
2091 _SCErrorSet(kSCStatusInvalidArgument
);
2095 interfaces
= CFArrayCreate(NULL
, (const void **)&interface
, 1, &kCFTypeArrayCallBacks
);
2096 assert(interfaces
!= NULL
);
2097 updated
= __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set
, interfaces
, FALSE
);
2098 CFRelease(interfaces
);
2105 SCNetworkSetCopySelectedVPNService(SCNetworkSetRef set
)
2109 SCNetworkServiceRef selected
= NULL
;
2110 CFArrayRef services
;
2111 CFMutableArrayRef services_vpn
= NULL
;
2113 if (!isA_SCNetworkSet(set
)) {
2114 _SCErrorSet(kSCStatusInvalidArgument
);
2118 services
= SCNetworkSetCopyServices(set
);
2119 if (services
!= NULL
) {
2120 n
= CFArrayGetCount(services
);
2121 for (i
= 0; i
< n
; i
++) {
2122 SCNetworkServiceRef service
;
2124 service
= CFArrayGetValueAtIndex(services
, i
);
2125 if (!SCNetworkServiceGetEnabled(service
)) {
2130 if (!_SCNetworkServiceIsVPN(service
)) {
2131 // if not VPN service
2135 if (services_vpn
== NULL
) {
2136 services_vpn
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2138 CFArrayAppendValue(services_vpn
, service
);
2141 CFRelease(services
);
2144 if (services_vpn
== NULL
) {
2145 // if no VPN services
2149 n
= CFArrayGetCount(services_vpn
);
2152 CFMutableArrayRef sorted
;
2154 order
= SCNetworkSetGetServiceOrder(set
);
2155 sorted
= CFArrayCreateMutableCopy(NULL
, 0, services_vpn
);
2156 CFArraySortValues(sorted
,
2157 CFRangeMake(0, CFArrayGetCount(sorted
)),
2158 _SCNetworkServiceCompare
,
2160 CFRelease(services_vpn
);
2161 services_vpn
= sorted
;
2164 #if TARGET_OS_IPHONE
2166 CFStringRef serviceID_prefs
;
2168 #define VPN_PREFERENCES CFSTR("com.apple.mobilevpn")
2169 #define VPN_SERVICE_ID CFSTR("activeVPNID")
2171 CFPreferencesAppSynchronize(VPN_PREFERENCES
);
2172 serviceID_prefs
= CFPreferencesCopyAppValue(VPN_SERVICE_ID
, VPN_PREFERENCES
);
2173 if (serviceID_prefs
!= NULL
) {
2174 for (i
= 0; i
< n
; i
++) {
2175 SCNetworkServiceRef service
;
2176 CFStringRef serviceID
;
2178 service
= CFArrayGetValueAtIndex(services_vpn
, i
);
2179 serviceID
= SCNetworkServiceGetServiceID(service
);
2180 if (CFEqual(serviceID
, serviceID_prefs
)) {
2188 CFRelease(serviceID_prefs
);
2191 #endif // TARGET_OS_IPHONE
2193 if (selected
== NULL
) {
2194 selected
= CFArrayGetValueAtIndex(services_vpn
, 0);
2198 CFRelease(services_vpn
);
2204 SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
2207 CFArrayRef services
;
2209 if (!isA_SCNetworkSet(set
)) {
2210 _SCErrorSet(kSCStatusInvalidArgument
);
2214 if (!isA_SCNetworkService(service
) || !_SCNetworkServiceIsVPN(service
)) {
2215 _SCErrorSet(kSCStatusInvalidArgument
);
2219 services
= SCNetworkSetCopyServices(set
);
2220 if (services
!= NULL
) {
2222 CFIndex n
= CFArrayGetCount(services
);
2224 if (!CFArrayContainsValue(services
, CFRangeMake(0, n
), service
)) {
2225 // if selected service not a member of the current set
2226 _SCErrorSet(kSCStatusInvalidArgument
);
2231 for (i
= 0; ok
&& (i
< n
); i
++) {
2232 SCNetworkServiceRef vpn
;
2234 vpn
= CFArrayGetValueAtIndex(services
, i
);
2235 if (!_SCNetworkServiceIsVPN(vpn
)) {
2236 // if not VPN service
2240 ok
= SCNetworkServiceSetEnabled(vpn
, CFEqual(service
, vpn
));
2246 if (services
!= NULL
) CFRelease(services
);
2252 _SCNetworkSetSetSetID(SCNetworkSetRef set
, CFStringRef newSetID
)
2254 SCNetworkSetRef currentSet
= NULL
;
2255 SCNetworkSetPrivateRef currentSetPrivate
= NULL
;
2256 CFDictionaryRef entity
;
2257 CFStringRef newPath
;
2259 CFStringRef oldPath
= NULL
;
2260 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
2261 Boolean updateCurrentSet
= FALSE
;
2263 if (!isA_SCNetworkSet(set
)) {
2264 _SCErrorSet(kSCStatusInvalidArgument
);
2268 if (!isA_CFString(newSetID
)) {
2269 _SCErrorSet(kSCStatusInvalidArgument
);
2273 if (!__SCNetworkSetExists(set
)) {
2274 SC_log(LOG_ERR
, "_SCNetworkSetSetSetID() w/removed set\n set = %@\n setID = %@",
2277 _SC_crash_once("_SCNetworkSetSetSetID() w/removed set", NULL
, NULL
);
2278 _SCErrorSet(kSCStatusInvalidArgument
);
2282 // If newSetID is equal to current setID, our work is done
2283 if (CFEqual(newSetID
, setPrivate
->setID
)) {
2287 newPath
= SCPreferencesPathKeyCreateSet(NULL
, newSetID
);
2288 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, newPath
);
2289 if (isA_CFDictionary(entity
)) {
2290 // if the new set already exists
2291 _SCErrorSet(kSCStatusKeyExists
);
2295 oldPath
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
2296 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, oldPath
);
2297 if (!isA_CFDictionary(entity
)) {
2298 // if the set has already been removed
2299 _SCErrorSet(kSCStatusNoKey
);
2303 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, newPath
, entity
);
2308 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, oldPath
);
2313 // update current set (if needed)
2314 currentSet
= SCNetworkSetCopyCurrent(setPrivate
->prefs
);
2315 if (currentSet
!= NULL
) {
2316 currentSetPrivate
= (SCNetworkSetPrivateRef
)currentSet
;
2317 if (CFEqual(currentSetPrivate
->setID
, setPrivate
->setID
)) {
2318 updateCurrentSet
= TRUE
;
2320 CFRelease(currentSet
);
2323 SC_log(LOG_DEBUG
, "_SCNetworkSetSetID(): %@ --> %@", set
, newSetID
);
2325 // replace setID with new one
2327 CFRelease(setPrivate
->setID
);
2328 setPrivate
->setID
= newSetID
;
2330 if (updateCurrentSet
) {
2331 SCNetworkSetSetCurrent(set
);
2336 if (oldPath
!= NULL
) {
2339 if (newPath
!= NULL
) {