]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkSet.c
configd-699.30.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkSet.c
1 /*
2 * Copyright (c) 2004-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * May 13, 2004 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFRuntime.h>
34 #include <SystemConfiguration/SystemConfiguration.h>
35 #include "SCNetworkConfigurationInternal.h"
36 #include <SystemConfiguration/SCValidation.h>
37 #include <SystemConfiguration/SCPrivate.h>
38
39 #include <pthread.h>
40
41
42 static CFStringRef __SCNetworkSetCopyDescription (CFTypeRef cf);
43 static void __SCNetworkSetDeallocate (CFTypeRef cf);
44 static Boolean __SCNetworkSetEqual (CFTypeRef cf1, CFTypeRef cf2);
45 static CFHashCode __SCNetworkSetHash (CFTypeRef cf);
46
47
48 static CFTypeID __kSCNetworkSetTypeID = _kCFRuntimeNotATypeID;
49
50
51 static const CFRuntimeClass __SCNetworkSetClass = {
52 0, // version
53 "SCNetworkSet", // className
54 NULL, // init
55 NULL, // copy
56 __SCNetworkSetDeallocate, // dealloc
57 __SCNetworkSetEqual, // equal
58 __SCNetworkSetHash, // hash
59 NULL, // copyFormattingDesc
60 __SCNetworkSetCopyDescription // copyDebugDesc
61 };
62
63
64 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
65
66
67 static CFStringRef
68 __SCNetworkSetCopyDescription(CFTypeRef cf)
69 {
70 CFAllocatorRef allocator = CFGetAllocator(cf);
71 CFMutableStringRef result;
72 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
73
74 result = CFStringCreateMutable(allocator, 0);
75 CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkSet %p [%p]> {"), cf, allocator);
76 CFStringAppendFormat(result, NULL, CFSTR("id = %@"), setPrivate->setID);
77 CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), setPrivate->prefs);
78 if (setPrivate->name != NULL) {
79 CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), setPrivate->name);
80 }
81 CFStringAppendFormat(result, NULL, CFSTR("}"));
82
83 return result;
84 }
85
86
87 static void
88 __SCNetworkSetDeallocate(CFTypeRef cf)
89 {
90 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
91
92 /* release resources */
93
94 CFRelease(setPrivate->setID);
95 CFRelease(setPrivate->prefs);
96 if (setPrivate->name != NULL)
97 CFRelease(setPrivate->name);
98
99 return;
100 }
101
102
103 static Boolean
104 __SCNetworkSetEqual(CFTypeRef cf1, CFTypeRef cf2)
105 {
106 SCNetworkSetPrivateRef s1 = (SCNetworkSetPrivateRef)cf1;
107 SCNetworkSetPrivateRef s2 = (SCNetworkSetPrivateRef)cf2;
108
109 if (s1 == s2)
110 return TRUE;
111
112 if (s1->prefs != s2->prefs)
113 return FALSE; // if not the same prefs
114
115 if (!CFEqual(s1->setID, s2->setID))
116 return FALSE; // if not the same set identifier
117
118 return TRUE;
119 }
120
121
122 static CFHashCode
123 __SCNetworkSetHash(CFTypeRef cf)
124 {
125 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
126
127 return CFHash(setPrivate->setID);
128 }
129
130
131 static void
132 __SCNetworkSetInitialize(void)
133 {
134 __kSCNetworkSetTypeID = _CFRuntimeRegisterClass(&__SCNetworkSetClass);
135 return;
136 }
137
138
139 static SCNetworkSetPrivateRef
140 __SCNetworkSetCreatePrivate(CFAllocatorRef allocator,
141 SCPreferencesRef prefs,
142 CFStringRef setID)
143 {
144 SCNetworkSetPrivateRef setPrivate;
145 uint32_t size;
146
147 /* initialize runtime */
148 pthread_once(&initialized, __SCNetworkSetInitialize);
149
150 /* allocate target */
151 size = sizeof(SCNetworkSetPrivate) - sizeof(CFRuntimeBase);
152 setPrivate = (SCNetworkSetPrivateRef)_CFRuntimeCreateInstance(allocator,
153 __kSCNetworkSetTypeID,
154 size,
155 NULL);
156 if (setPrivate == NULL) {
157 return NULL;
158 }
159
160 setPrivate->setID = CFStringCreateCopy(NULL, setID);
161 setPrivate->prefs = CFRetain(prefs);
162 setPrivate->name = NULL;
163 setPrivate->established = FALSE; // "new" (not yet established) set
164
165 return setPrivate;
166 }
167
168
169 #pragma mark -
170
171
172 static int
173 _serviceOrder(SCNetworkServiceRef service)
174 {
175 SCNetworkInterfaceRef interface;
176
177 interface = SCNetworkServiceGetInterface(service);
178 if ((interface == NULL) || _SCNetworkServiceIsVPN(service)) {
179 return 100000; // if unknown or VPN interface, sort last
180 }
181
182 return __SCNetworkInterfaceOrder(interface);
183 }
184
185
186 static void
187 _serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service)
188 {
189 CFIndex i;
190 CFIndex n;
191 CFMutableArrayRef newOrder;
192 CFArrayRef order;
193 CFStringRef serviceID;
194 CFIndex serviceOrder;
195 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
196 CFIndex slot;
197
198 order = SCNetworkSetGetServiceOrder(set);
199 if (order != NULL) {
200 newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
201 } else {
202 newOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
203 }
204 assert(newOrder != NULL);
205 n = CFArrayGetCount(newOrder);
206
207 serviceID = SCNetworkServiceGetServiceID(service);
208 if (CFArrayContainsValue(newOrder, CFRangeMake(0, n), serviceID)) {
209 // if serviceID already present
210 goto done;
211 }
212
213 serviceOrder = _serviceOrder(service);
214
215 slot = 0;
216 for (i = 0; i < n; i++) {
217 int slotOrder;
218 SCNetworkServiceRef slotService;
219 CFStringRef slotServiceID;
220
221 slotServiceID = CFArrayGetValueAtIndex(newOrder, i);
222 if (!isA_CFString(slotServiceID)) {
223 // if bad prefs
224 continue;
225 }
226
227 slotService = SCNetworkServiceCopy(setPrivate->prefs, slotServiceID);
228 if (slotService == NULL) {
229 // if serviceID not valid
230 continue;
231 }
232
233 slotOrder = _serviceOrder(slotService);
234 if (serviceOrder >= slotOrder) {
235 // add the service *after* this one
236 slot = i + 1;
237 }
238
239 CFRelease(slotService);
240 }
241
242 CFArrayInsertValueAtIndex(newOrder, slot, serviceID);
243 (void) SCNetworkSetSetServiceOrder(set, newOrder);
244
245 done :
246
247 CFRelease(newOrder);
248
249 return;
250 }
251
252
253 static void
254 _serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service)
255 {
256 CFMutableArrayRef newOrder;
257 CFArrayRef order;
258 CFStringRef serviceID;
259
260 order = SCNetworkSetGetServiceOrder(set);
261 if (order == NULL) {
262 return;
263 }
264
265 serviceID = SCNetworkServiceGetServiceID(service);
266
267 newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
268 while (TRUE) {
269 CFIndex i;
270
271 i = CFArrayGetFirstIndexOfValue(newOrder,
272 CFRangeMake(0, CFArrayGetCount(newOrder)),
273 serviceID);
274 if (i == kCFNotFound) {
275 break;
276 }
277
278 CFArrayRemoveValueAtIndex(newOrder, i);
279 }
280 (void) SCNetworkSetSetServiceOrder(set, newOrder);
281 CFRelease(newOrder);
282
283 return;
284 }
285
286
287 #pragma mark -
288 #pragma mark SCNetworkSet APIs
289
290
291 #define N_QUICK 16
292
293
294 #define PREVENT_DUPLICATE_SERVICE_NAMES
295 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
296 static CFStringRef
297 copy_next_name(CFStringRef name)
298 {
299 CFArrayRef components;
300 CFIndex n;
301 CFMutableArrayRef newComponents;
302 SInt32 suffix = 2;
303
304 if (name == NULL) {
305 return NULL;
306 }
307
308 components = CFStringCreateArrayBySeparatingStrings(NULL, name, CFSTR(" "));
309 if (components != NULL) {
310 newComponents = CFArrayCreateMutableCopy(NULL, 0, components);
311 CFRelease(components);
312 } else {
313 newComponents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
314 CFArrayAppendValue(newComponents, name);
315 }
316
317 n = CFArrayGetCount(newComponents);
318 if (n > 1) {
319 CFStringRef str;
320
321 str = CFArrayGetValueAtIndex(newComponents, n - 1);
322 suffix = CFStringGetIntValue(str);
323 if (suffix++ > 0) {
324 CFArrayRemoveValueAtIndex(newComponents, n - 1);
325 } else {
326 suffix = 2;
327 }
328 }
329
330 name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), (int)suffix);
331 CFArrayAppendValue(newComponents, name);
332 CFRelease(name);
333
334 name = CFStringCreateByCombiningStrings(NULL, newComponents, CFSTR(" "));
335 CFRelease(newComponents);
336
337 return name;
338 }
339
340
341 static Boolean
342 ensure_unique_service_name(SCNetworkServiceRef service)
343 {
344 SCNetworkInterfaceRef interface;
345 CFStringRef name;
346 Boolean ok = TRUE;
347
348 interface = SCNetworkServiceGetInterface(service);
349
350 name = SCNetworkServiceGetName(service);
351 if (name != NULL) {
352 CFRetain(name);
353 }
354
355 while (TRUE) {
356 CFStringRef newName;
357
358 ok = SCNetworkServiceSetName(service, name);
359 if (ok) {
360 break;
361 }
362
363 if (SCError() != kSCStatusKeyExists) {
364 SCLog(TRUE, LOG_DEBUG,
365 CFSTR("could not update service name for \"%@\": %s"),
366 SCNetworkInterfaceGetLocalizedDisplayName(interface),
367 SCErrorString(SCError()));
368 break;
369 }
370
371 newName = copy_next_name(name);
372 if (newName == NULL) {
373 SCLog(TRUE, LOG_DEBUG,
374 CFSTR("could not create unique name for \"%@\": %s"),
375 SCNetworkInterfaceGetLocalizedDisplayName(interface),
376 SCErrorString(SCError()));
377 break;
378 }
379
380 // try again with the "new" name
381 if (name != NULL) {
382 CFRelease(name);
383 }
384 name = newName;
385 }
386
387 if (name != NULL) {
388 CFRelease(name);
389 }
390
391 return ok;
392 }
393 #endif // PREVENT_DUPLICATE_SERVICE_NAMES
394
395
396 Boolean
397 SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
398 {
399 SCNetworkInterfaceRef interface;
400 CFArrayRef interface_config = NULL;
401 CFStringRef link;
402 Boolean ok;
403 CFStringRef path;
404 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
405 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
406
407 if (!isA_SCNetworkSet(set)) {
408 _SCErrorSet(kSCStatusInvalidArgument);
409 return FALSE;
410 }
411
412 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
413 _SCErrorSet(kSCStatusInvalidArgument);
414 return FALSE;
415 }
416
417 // make sure that we do not add an orphaned network service if its
418 // associated interface is a member of a bond or bridge.
419 interface = SCNetworkServiceGetInterface(service);
420 if ((interface != NULL) &&
421 __SCNetworkInterfaceIsMember(servicePrivate->prefs, interface)) {
422 _SCErrorSet(kSCStatusKeyExists);
423 return FALSE;
424 }
425
426 //#define PREVENT_DUPLICATE_SETS
427 #ifdef PREVENT_DUPLICATE_SETS
428 CFArrayRef sets;
429
430 // ensure that each service is only a member of ONE set
431 sets = SCNetworkSetCopyAll(setPrivate->prefs);
432 if (sets != NULL) {
433 CFIndex i;
434 CFIndex n;
435
436 n = CFArrayGetCount(sets);
437 for (i = 0; i < n; i++) {
438 Boolean found;
439 CFArrayRef services;
440 SCNetworkSetRef set;
441
442 set = CFArrayGetValueAtIndex(sets, i);
443 services = SCNetworkSetCopyServices(set);
444 found = CFArrayContainsValue(services,
445 CFRangeMake(0, CFArrayGetCount(services)),
446 service);
447 CFRelease(services);
448
449 if (found) {
450 CFRelease(sets);
451 _SCErrorSet(kSCStatusKeyExists);
452 return FALSE;
453 }
454 }
455 CFRelease(sets);
456 }
457 #endif /* PREVENT_DUPLICATE_SETS */
458
459 // get the [deep] interface configuration settings
460 interface = SCNetworkServiceGetInterface(service);
461 if (interface != NULL) {
462 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface);
463 }
464
465 // create the link between "set" and the "service"
466 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator
467 setPrivate->setID, // set
468 servicePrivate->serviceID, // service
469 NULL); // entity
470 link = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
471 servicePrivate->serviceID, // service
472 NULL); // entity
473 ok = SCPreferencesPathSetLink(setPrivate->prefs, path, link);
474 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
475 if (ok) {
476 ok = ensure_unique_service_name(service);
477 if (!ok) {
478 // if we could not ensure a unique name, remove the (just added)
479 // link between the "set" and the "service"
480 (void) SCPreferencesPathRemoveValue(setPrivate->prefs, path);
481 }
482 }
483 #endif // PREVENT_DUPLICATE_SERVICE_NAMES
484 CFRelease(path);
485 CFRelease(link);
486 if (!ok) {
487 goto done;
488 }
489
490 // push the [deep] interface configuration into all sets which contain this service.
491 if (interface != NULL) {
492 __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config);
493 }
494
495 // add service to ServiceOrder
496 _serviceOrder_add(set, service);
497
498 // mark set as no longer "new"
499 setPrivate->established = TRUE;
500
501 done :
502
503 if (interface_config != NULL) CFRelease(interface_config);
504 return ok;
505 }
506
507
508 SCNetworkSetRef
509 SCNetworkSetCopy(SCPreferencesRef prefs, CFStringRef setID)
510 {
511 CFDictionaryRef entity;
512 CFStringRef path;
513 SCNetworkSetPrivateRef setPrivate;
514
515 if (!isA_CFString(setID)) {
516 _SCErrorSet(kSCStatusInvalidArgument);
517 return NULL;
518 }
519
520 path = SCPreferencesPathKeyCreateSet(NULL, setID);
521 entity = SCPreferencesPathGetValue(prefs, path);
522 CFRelease(path);
523
524 if (!isA_CFDictionary(entity)) {
525 _SCErrorSet(kSCStatusNoKey);
526 return NULL;
527 }
528
529 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
530 assert(setPrivate != NULL);
531
532 // mark set as "old" (already established)
533 setPrivate->established = TRUE;
534
535 return (SCNetworkSetRef)setPrivate;
536 }
537
538
539 Boolean
540 SCNetworkSetContainsInterface(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
541 {
542 Boolean found = FALSE;
543 CFArrayRef services;
544
545 services = SCNetworkSetCopyServices(set);
546 if (services != NULL) {
547 found = __SCNetworkServiceExistsForInterface(services, interface);
548 CFRelease(services);
549 }
550
551 return found;
552 }
553
554
555 CFArrayRef /* of SCNetworkSetRef's */
556 SCNetworkSetCopyAll(SCPreferencesRef prefs)
557 {
558 CFMutableArrayRef array;
559 CFIndex n;
560 CFStringRef path;
561 CFDictionaryRef sets;
562
563 path = SCPreferencesPathKeyCreateSets(NULL);
564 sets = SCPreferencesPathGetValue(prefs, path);
565 CFRelease(path);
566
567 if ((sets != NULL) && !isA_CFDictionary(sets)) {
568 return NULL;
569 }
570
571 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
572
573 n = (sets != NULL) ? CFDictionaryGetCount(sets) : 0;
574 if (n > 0) {
575 CFIndex i;
576 const void * keys_q[N_QUICK];
577 const void ** keys = keys_q;
578 const void * vals_q[N_QUICK];
579 const void ** vals = vals_q;
580
581 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
582 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
583 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
584 }
585 CFDictionaryGetKeysAndValues(sets, keys, vals);
586 for (i = 0; i < n; i++) {
587 SCNetworkSetPrivateRef setPrivate;
588
589 if (!isA_CFDictionary(vals[i])) {
590 SCLog(TRUE,
591 LOG_INFO,
592 CFSTR("SCNetworkSetCopyAll(): error w/set \"%@\"\n"),
593 keys[i]);
594 continue;
595 }
596
597 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, keys[i]);
598 assert(setPrivate != NULL);
599
600 // mark set as "old" (already established)
601 setPrivate->established = TRUE;
602
603 CFArrayAppendValue(array, (SCNetworkSetRef)setPrivate);
604 CFRelease(setPrivate);
605 }
606 if (keys != keys_q) {
607 CFAllocatorDeallocate(NULL, keys);
608 CFAllocatorDeallocate(NULL, vals);
609 }
610 }
611
612 return array;
613 }
614
615
616 CFArrayRef /* of SCNetworkInterfaceRef's */
617 SCNetworkSetCopyAvailableInterfaces(SCNetworkSetRef set)
618 {
619 CFMutableArrayRef available;
620 CFMutableSetRef excluded = NULL;
621 int i;
622 CFArrayRef interfaces;
623 CFIndex n_interfaces;
624 CFIndex n_exclusions = 0;
625 SCPreferencesRef prefs;
626 SCNetworkSetPrivateRef setPrivate;
627
628 setPrivate = (SCNetworkSetPrivateRef)set;
629 prefs = setPrivate->prefs;
630
631 interfaces = _SCNetworkInterfaceCopyAllWithPreferences(prefs);
632 n_interfaces = CFArrayGetCount(interfaces);
633 if (n_interfaces == 0) {
634 return interfaces;
635 }
636
637 if (prefs != NULL) {
638 CFArrayRef bridges = NULL;
639
640 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
641
642 #if !TARGET_OS_IPHONE
643 CFArrayRef bonds = NULL;
644
645 bonds = SCBondInterfaceCopyAll(prefs);
646 if (bonds != NULL) {
647 __SCBondInterfaceListCollectMembers(bonds, excluded);
648 CFRelease(bonds);
649 }
650 #endif /* !TARGET_OS_IPHONE */
651
652 bridges = SCBridgeInterfaceCopyAll(prefs);
653 if (bridges != NULL) {
654 __SCBridgeInterfaceListCollectMembers(bridges, excluded);
655 CFRelease(bridges);
656 }
657
658 n_exclusions = CFSetGetCount(excluded);
659 }
660
661 if (n_exclusions == 0) {
662 if (excluded != NULL) {
663 CFRelease(excluded);
664 }
665
666 return interfaces;
667 }
668
669 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
670
671 for (i = 0; i < n_interfaces; i++) {
672 SCNetworkInterfaceRef interface;
673
674 interface = CFArrayGetValueAtIndex(interfaces, i);
675 if (CFSetContainsValue(excluded, interface)) {
676 // if excluded
677 continue;
678 }
679
680 CFArrayAppendValue(available, interface);
681 }
682
683 CFRelease(interfaces);
684 CFRelease(excluded);
685
686 return available;
687 }
688
689
690 SCNetworkSetRef
691 SCNetworkSetCopyCurrent(SCPreferencesRef prefs)
692 {
693 CFArrayRef components;
694 CFStringRef currentID;
695 SCNetworkSetPrivateRef setPrivate = NULL;
696
697 currentID = SCPreferencesGetValue(prefs, kSCPrefCurrentSet);
698 if (!isA_CFString(currentID)) {
699 return NULL;
700 }
701
702 components = CFStringCreateArrayBySeparatingStrings(NULL, currentID, CFSTR("/"));
703 if (CFArrayGetCount(components) == 3) {
704 CFStringRef setID;
705 CFStringRef path;
706
707 setID = CFArrayGetValueAtIndex(components, 2);
708 path = SCPreferencesPathKeyCreateSet(NULL, setID);
709 if (CFEqual(path, currentID)) {
710 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
711 assert(setPrivate != NULL);
712
713 // mark set as "old" (already established)
714 setPrivate->established = TRUE;
715 } else {
716 SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkSetCopyCurrent(): preferences are non-conformant"));
717 }
718 CFRelease(path);
719 }
720 CFRelease(components);
721
722 return (SCNetworkSetRef)setPrivate;
723 }
724
725
726 CFArrayRef /* of SCNetworkServiceRef's */
727 SCNetworkSetCopyServices(SCNetworkSetRef set)
728 {
729 CFMutableArrayRef array;
730 CFDictionaryRef dict;
731 CFIndex n;
732 CFStringRef path;
733 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
734
735 if (!isA_SCNetworkSet(set)) {
736 _SCErrorSet(kSCStatusInvalidArgument);
737 return NULL;
738 }
739
740 path = SCPreferencesPathKeyCreateSetNetworkService(NULL, setPrivate->setID, NULL);
741 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
742 CFRelease(path);
743 if ((dict != NULL) && !isA_CFDictionary(dict)) {
744 return NULL;
745 }
746
747 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
748
749 n = (dict != NULL) ? CFDictionaryGetCount(dict) : 0;
750 if (n > 0) {
751 CFIndex i;
752 const void * keys_q[N_QUICK];
753 const void ** keys = keys_q;
754
755 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
756 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
757 }
758 CFDictionaryGetKeysAndValues(dict, keys, NULL);
759 for (i = 0; i < n; i++) {
760 CFArrayRef components;
761 CFStringRef link;
762
763 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
764 setPrivate->setID,
765 (CFStringRef)keys[i],
766 NULL);
767 link = SCPreferencesPathGetLink(setPrivate->prefs, path);
768 CFRelease(path);
769 if (link == NULL) {
770 SCLog(TRUE,
771 LOG_INFO,
772 CFSTR("SCNetworkSetCopyServices(): service \"%@\" for set \"%@\" is not a link\n"),
773 keys[i],
774 setPrivate->setID);
775 continue; // if the service is not a link
776 }
777
778 components = CFStringCreateArrayBySeparatingStrings(NULL, link, CFSTR("/"));
779 if (CFArrayGetCount(components) == 3) {
780 CFStringRef serviceID;
781
782 serviceID = CFArrayGetValueAtIndex(components, 2);
783 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
784 serviceID, // service
785 NULL); // entity
786 if (CFEqual(path, link)) {
787 SCNetworkServicePrivateRef servicePrivate;
788
789 servicePrivate = __SCNetworkServiceCreatePrivate(NULL,
790 setPrivate->prefs,
791 serviceID,
792 NULL);
793 CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
794 CFRelease(servicePrivate);
795 }
796 CFRelease(path);
797 }
798 CFRelease(components);
799 }
800 if (keys != keys_q) {
801 CFAllocatorDeallocate(NULL, keys);
802 }
803 }
804
805 return array;
806 }
807
808
809 SCNetworkSetRef
810 SCNetworkSetCreate(SCPreferencesRef prefs)
811 {
812 CFArrayRef components;
813 CFDictionaryRef entity;
814 Boolean ok;
815 CFStringRef path;
816 CFStringRef prefix;
817 CFStringRef setID;
818 SCNetworkSetPrivateRef setPrivate;
819
820 prefix = SCPreferencesPathKeyCreateSets(NULL);
821 path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
822 if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
823 CFRelease(prefix);
824 if (path == NULL) {
825 return NULL;
826 }
827
828 components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
829 setID = CFArrayGetValueAtIndex(components, 2);
830 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
831 assert(setPrivate != NULL);
832 CFRelease(components);
833
834 // mark set as "new" (not yet established)
835 setPrivate->established = FALSE;
836
837 // establish the set in the preferences
838 entity = CFDictionaryCreate(NULL,
839 NULL, NULL, 0,
840 &kCFTypeDictionaryKeyCallBacks,
841 &kCFTypeDictionaryValueCallBacks);
842 ok = SCPreferencesPathSetValue(prefs, path, entity);
843 CFRelease(path);
844 CFRelease(entity);
845 if (!ok) {
846 CFRelease(setPrivate);
847 setPrivate = NULL;
848 }
849
850 return (SCNetworkSetRef)setPrivate;
851 }
852
853
854 CFStringRef
855 SCNetworkSetGetSetID(SCNetworkSetRef set)
856 {
857 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
858
859 if (!isA_SCNetworkSet(set)) {
860 _SCErrorSet(kSCStatusInvalidArgument);
861 return NULL;
862 }
863
864 return setPrivate->setID;
865 }
866
867
868 CFStringRef
869 SCNetworkSetGetName(SCNetworkSetRef set)
870 {
871 CFBundleRef bundle;
872 CFDictionaryRef entity;
873 CFStringRef path;
874 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
875
876 if (!isA_SCNetworkSet(set)) {
877 _SCErrorSet(kSCStatusInvalidArgument);
878 return NULL;
879 }
880
881 if (setPrivate->name != NULL) {
882 return setPrivate->name;
883 }
884
885 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
886 entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
887 CFRelease(path);
888
889 if (isA_CFDictionary(entity)) {
890 CFStringRef name;
891
892 name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
893 if (isA_CFString(name)) {
894 setPrivate->name = CFRetain(name);
895 }
896 }
897
898 bundle = _SC_CFBundleGet();
899 if (bundle != NULL) {
900 if (setPrivate->name != NULL) {
901 CFStringRef non_localized;
902
903 non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
904 CFSTR("DEFAULT_SET_NAME"),
905 CFSTR("Automatic"),
906 NULL);
907 if (non_localized != NULL) {
908 if (CFEqual(setPrivate->name, non_localized)) {
909 CFStringRef localized;
910
911 // if "Automatic", return localized name
912 localized = CFBundleCopyLocalizedString(bundle,
913 CFSTR("DEFAULT_SET_NAME"),
914 CFSTR("Automatic"),
915 NULL);
916 if (localized != NULL) {
917 CFRelease(setPrivate->name);
918 setPrivate->name = localized;
919 }
920 }
921
922 CFRelease(non_localized);
923 }
924 }
925 }
926
927 return setPrivate->name;
928 }
929
930
931 CFArrayRef /* of serviceID CFStringRef's */
932 SCNetworkSetGetServiceOrder(SCNetworkSetRef set)
933 {
934 CFDictionaryRef dict;
935 CFStringRef path;
936 CFArrayRef serviceOrder;
937 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
938
939 if (!isA_SCNetworkSet(set)) {
940 _SCErrorSet(kSCStatusInvalidArgument);
941 return NULL;
942 }
943
944 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
945 if (path == NULL) {
946 return NULL;
947 }
948
949 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
950 CFRelease(path);
951 if (!isA_CFDictionary(dict)) {
952 return NULL;
953 }
954
955 serviceOrder = CFDictionaryGetValue(dict, kSCPropNetServiceOrder);
956 serviceOrder = isA_CFArray(serviceOrder);
957
958 return serviceOrder;
959 }
960
961
962 CFTypeID
963 SCNetworkSetGetTypeID(void)
964 {
965 pthread_once(&initialized, __SCNetworkSetInitialize); /* initialize runtime */
966 return __kSCNetworkSetTypeID;
967 }
968
969
970 Boolean
971 SCNetworkSetRemove(SCNetworkSetRef set)
972 {
973 CFStringRef currentPath;
974 Boolean ok = FALSE;
975 CFStringRef path;
976 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
977
978 if (!isA_SCNetworkSet(set)) {
979 _SCErrorSet(kSCStatusInvalidArgument);
980 return FALSE;
981 }
982
983 currentPath = SCPreferencesGetValue(setPrivate->prefs, kSCPrefCurrentSet);
984 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
985 if (!isA_CFString(currentPath) || !CFEqual(currentPath, path)) {
986 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
987 } else {
988 _SCErrorSet(kSCStatusInvalidArgument);
989 }
990 CFRelease(path);
991
992 return ok;
993 }
994
995
996 Boolean
997 SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service)
998 {
999 SCNetworkInterfaceRef interface;
1000 CFArrayRef interface_config = NULL;
1001 Boolean ok;
1002 CFStringRef path;
1003 int sc_status = kSCStatusOK;
1004 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1005 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1006
1007 if (!isA_SCNetworkSet(set)) {
1008 _SCErrorSet(kSCStatusInvalidArgument);
1009 return FALSE;
1010 }
1011
1012 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1013 _SCErrorSet(kSCStatusInvalidArgument);
1014 return FALSE;
1015 }
1016
1017 // remove service from ServiceOrder
1018 _serviceOrder_remove(set, service);
1019
1020 // get the [deep] interface configuration settings
1021 interface = SCNetworkServiceGetInterface(service);
1022 if (interface != NULL) {
1023 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface);
1024 if (interface_config != NULL) {
1025 // remove the interface configuration from all sets which contain this service.
1026 __SCNetworkInterfaceSetDeepConfiguration(set, interface, NULL);
1027 }
1028 }
1029
1030 // remove the link between "set" and the "service"
1031 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
1032 setPrivate->setID,
1033 servicePrivate->serviceID,
1034 NULL);
1035 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
1036 if (!ok) {
1037 sc_status = SCError(); // preserve the error
1038 }
1039 CFRelease(path);
1040
1041 // push the [deep] interface configuration [back] into all sets which contain the service.
1042 if (interface_config != NULL) {
1043 __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config);
1044 }
1045
1046 if (interface_config != NULL) CFRelease(interface_config);
1047 if (!ok) {
1048 _SCErrorSet(sc_status);
1049 }
1050 return ok;
1051 }
1052
1053
1054 Boolean
1055 SCNetworkSetSetCurrent(SCNetworkSetRef set)
1056 {
1057 Boolean ok;
1058 CFStringRef path;
1059 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1060
1061 if (!isA_SCNetworkSet(set)) {
1062 _SCErrorSet(kSCStatusInvalidArgument);
1063 return FALSE;
1064 }
1065
1066 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
1067 ok = SCPreferencesSetValue(setPrivate->prefs, kSCPrefCurrentSet, path);
1068 CFRelease(path);
1069 return ok;
1070 }
1071
1072
1073 Boolean
1074 SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
1075 {
1076 CFBundleRef bundle = NULL;
1077 CFDictionaryRef entity;
1078 CFStringRef localized = NULL;
1079 CFStringRef non_localized = NULL;
1080 Boolean ok = FALSE;
1081 CFStringRef path;
1082 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1083
1084 if (!isA_SCNetworkSet(set)) {
1085 _SCErrorSet(kSCStatusInvalidArgument);
1086 return FALSE;
1087 }
1088
1089 if ((name != NULL) && !isA_CFString(name)) {
1090 _SCErrorSet(kSCStatusInvalidArgument);
1091 return FALSE;
1092 }
1093
1094 // if known, compare against localized name
1095
1096 if (name != NULL) {
1097 bundle = _SC_CFBundleGet();
1098 if (bundle != NULL) {
1099 non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
1100 CFSTR("DEFAULT_SET_NAME"),
1101 CFSTR("Automatic"),
1102 NULL);
1103 if (non_localized != NULL) {
1104 if (CFEqual(name, non_localized)) {
1105 localized = CFBundleCopyLocalizedString(bundle,
1106 CFSTR("DEFAULT_SET_NAME"),
1107 CFSTR("Automatic"),
1108 NULL);
1109 if (localized != NULL) {
1110 name = localized;
1111 }
1112 }
1113 }
1114 }
1115 }
1116
1117 #define PREVENT_DUPLICATE_SET_NAMES
1118 #ifdef PREVENT_DUPLICATE_SET_NAMES
1119 if (name != NULL) {
1120 CFArrayRef sets;
1121
1122 // ensure that each set is uniquely named
1123
1124 sets = SCNetworkSetCopyAll(setPrivate->prefs);
1125 if (sets != NULL) {
1126 CFIndex i;
1127 CFIndex n;
1128
1129 n = CFArrayGetCount(sets);
1130 for (i = 0; i < n; i++) {
1131 CFStringRef otherID;
1132 CFStringRef otherName;
1133 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, i);
1134
1135 otherID = SCNetworkSetGetSetID(set);
1136 if (CFEqual(setPrivate->setID, otherID)) {
1137 continue; // skip current set
1138 }
1139
1140 otherName = SCNetworkSetGetName(set);
1141 if ((otherName != NULL) && CFEqual(name, otherName)) {
1142 // if "name" not unique
1143 CFRelease(sets);
1144 _SCErrorSet(kSCStatusKeyExists);
1145 goto done;
1146 }
1147 }
1148 CFRelease(sets);
1149 }
1150 }
1151 #endif /* PREVENT_DUPLICATE_SET_NAMES */
1152
1153 // if known, store non-localized name
1154
1155 if ((name != NULL) && (bundle != NULL) && (non_localized != NULL)) {
1156 if (localized == NULL) {
1157 localized = CFBundleCopyLocalizedString(bundle,
1158 CFSTR("DEFAULT_SET_NAME"),
1159 CFSTR("Automatic"),
1160 NULL);
1161 }
1162
1163 if (localized != NULL) {
1164 if (CFEqual(name, localized)) {
1165 name = non_localized;
1166 }
1167 }
1168 }
1169
1170 // update the "name"
1171
1172 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
1173 entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
1174 if (isA_CFDictionary(entity) ||
1175 ((entity == NULL) && (name != NULL))) {
1176 CFMutableDictionaryRef newEntity;
1177
1178 if (entity != NULL) {
1179 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1180 } else {
1181 newEntity = CFDictionaryCreateMutable(NULL,
1182 0,
1183 &kCFTypeDictionaryKeyCallBacks,
1184 &kCFTypeDictionaryValueCallBacks);
1185 }
1186 if (name != NULL) {
1187 CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name);
1188 } else {
1189 CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
1190 }
1191 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newEntity);
1192 CFRelease(newEntity);
1193 }
1194 CFRelease(path);
1195
1196 done :
1197
1198 if (localized != NULL) CFRelease(localized);
1199 if (non_localized != NULL) CFRelease(non_localized);
1200 return ok;
1201 }
1202
1203
1204 Boolean
1205 SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
1206 {
1207 CFDictionaryRef dict;
1208 CFMutableDictionaryRef newDict;
1209 Boolean ok;
1210 CFStringRef path;
1211 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1212
1213 if (!isA_SCNetworkSet(set)) {
1214 _SCErrorSet(kSCStatusInvalidArgument);
1215 return FALSE;
1216 }
1217
1218 if (isA_CFArray(newOrder)) {
1219 CFIndex i;
1220 CFIndex n = CFArrayGetCount(newOrder);
1221
1222 for (i = 0; i < n; i++) {
1223 CFStringRef serviceID;
1224
1225 serviceID = CFArrayGetValueAtIndex(newOrder, i);
1226 if (!isA_CFString(serviceID)) {
1227 _SCErrorSet(kSCStatusInvalidArgument);
1228 return FALSE;
1229 }
1230 }
1231 } else {
1232 _SCErrorSet(kSCStatusInvalidArgument);
1233 return FALSE;
1234 }
1235
1236 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
1237 if (path == NULL) {
1238 return FALSE;
1239 }
1240
1241 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
1242 if (dict != NULL) {
1243 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
1244 } else {
1245 newDict = CFDictionaryCreateMutable(NULL,
1246 0,
1247 &kCFTypeDictionaryKeyCallBacks,
1248 &kCFTypeDictionaryValueCallBacks);
1249 }
1250
1251 CFDictionarySetValue(newDict, kSCPropNetServiceOrder, newOrder);
1252 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newDict);
1253 CFRelease(newDict);
1254 CFRelease(path);
1255
1256 return ok;
1257 }
1258
1259
1260 #pragma mark -
1261 #pragma mark SCNetworkSet SPIs
1262
1263
1264 static void
1265 add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef interface)
1266 {
1267 CFIndex i;
1268 CFArrayRef interface_types;
1269 CFIndex n;
1270
1271 interface_types = SCNetworkInterfaceGetSupportedInterfaceTypes(interface);
1272 n = (interface_types != NULL) ? CFArrayGetCount(interface_types) : 0;
1273 for (i = 0; i < n; i++) {
1274 SCNetworkInterfaceRef parent;
1275 CFStringRef interface_type;
1276
1277 interface_type = CFArrayGetValueAtIndex(interface_types, i);
1278 parent = SCNetworkInterfaceCreateWithInterface(interface, interface_type);
1279 if (parent != NULL) {
1280 CFArrayAppendValue(interface_list, parent);
1281 CFRelease(parent);
1282 }
1283 }
1284
1285 return;
1286 }
1287
1288
1289 static CFSetRef /* of SCNetworkInterfaceRef's */
1290 copyExcludedInterfaces(SCPreferencesRef prefs)
1291 {
1292 CFMutableSetRef excluded;
1293 CFArrayRef interfaces;
1294
1295 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1296
1297 #if !TARGET_OS_IPHONE
1298 // exclude Bond [member] interfaces
1299 interfaces = SCBondInterfaceCopyAll(prefs);
1300 if (interfaces != NULL) {
1301 __SCBondInterfaceListCollectMembers(interfaces, excluded);
1302 CFRelease(interfaces);
1303 }
1304 #endif // !TARGET_OS_IPHONE
1305
1306 // exclude Bridge [member] interfaces
1307 interfaces = SCBridgeInterfaceCopyAll(prefs);
1308 if (interfaces != NULL) {
1309 __SCBridgeInterfaceListCollectMembers(interfaces, excluded);
1310 CFRelease(interfaces);
1311 }
1312
1313 return excluded;
1314 }
1315
1316
1317 #if !TARGET_OS_IPHONE
1318 static SCBridgeInterfaceRef
1319 copyAutoBridgeInterface(SCPreferencesRef prefs, CFStringRef bridgeName)
1320 {
1321 SCBridgeInterfaceRef bridge = NULL;
1322 CFArrayRef interfaces;
1323
1324 // exclude Bridge [member] interfaces
1325 interfaces = SCBridgeInterfaceCopyAll(prefs);
1326 if (interfaces != NULL) {
1327 CFIndex i;
1328 CFIndex n;
1329
1330 n = CFArrayGetCount(interfaces);
1331 for (i = 0; i < n; i++) {
1332 SCBridgeInterfaceRef interface;
1333 CFStringRef name = NULL;
1334 CFDictionaryRef options;
1335
1336 interface = CFArrayGetValueAtIndex(interfaces, i);
1337 options = SCBridgeInterfaceGetOptions(interface);
1338 if ((options != NULL) &&
1339 CFDictionaryGetValueIfPresent(options,
1340 CFSTR("__AUTO__"),
1341 (const void **)&name) &&
1342 _SC_CFEqual(name, bridgeName)) {
1343 bridge = interface;
1344 CFRetain(bridge);
1345 break;
1346 }
1347 }
1348
1349 CFRelease(interfaces);
1350 }
1351
1352 if (bridge == NULL) {
1353 bridge = SCBridgeInterfaceCreate(prefs);
1354 if (bridge != NULL) {
1355 CFMutableDictionaryRef newOptions;
1356 Boolean ok;
1357
1358 newOptions = CFDictionaryCreateMutable(NULL, 0,
1359 &kCFTypeDictionaryKeyCallBacks,
1360 &kCFTypeDictionaryValueCallBacks);
1361 CFDictionarySetValue(newOptions, CFSTR("__AUTO__"), bridgeName);
1362 ok = SCBridgeInterfaceSetOptions(bridge, newOptions);
1363 CFRelease(newOptions);
1364 if (!ok) {
1365 CFRelease(bridge);
1366 bridge = NULL;
1367 }
1368 }
1369 }
1370
1371 return bridge;
1372 }
1373 #endif // !TARGET_OS_IPHONE
1374
1375
1376 static CFArrayRef
1377 copyServices(SCNetworkSetRef set)
1378 {
1379 CFArrayRef services;
1380 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1381
1382 // first, assume that we only want to add new services
1383 // for those interfaces that are not represented in the
1384 // current set.
1385 services = SCNetworkSetCopyServices(set);
1386 if ((services != NULL) && setPrivate->established) {
1387 // but, if we are given an existing (or "established") set
1388 // than we only want to add new services for those interfaces
1389 // that are not represented in *any* set.
1390 CFRelease(services);
1391 services = SCNetworkServiceCopyAll(setPrivate->prefs);
1392 }
1393
1394 return services;
1395 }
1396
1397
1398 #if !TARGET_OS_IPHONE
1399 static CFArrayRef
1400 updateServices(CFArrayRef services, SCNetworkInterfaceRef interface)
1401 {
1402 CFStringRef bsdName;
1403 CFIndex i;
1404 CFIndex n;
1405 CFMutableArrayRef newServices;
1406
1407 if (services == NULL) {
1408 return NULL;
1409 }
1410
1411 bsdName = SCNetworkInterfaceGetBSDName(interface);
1412
1413 newServices = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1414
1415 n = CFArrayGetCount(services);
1416 for (i = 0; i < n; i++) {
1417 SCNetworkInterfaceRef interface;
1418 CFStringRef interfaceName;
1419 SCNetworkServiceRef newService;
1420 SCNetworkServiceRef service;
1421 CFStringRef serviceID;
1422 SCNetworkServicePrivateRef servicePrivate;
1423
1424 service = CFArrayGetValueAtIndex(services, i);
1425 interface = SCNetworkServiceGetInterface(service);
1426 interfaceName = SCNetworkInterfaceGetBSDName(interface);
1427 if (!_SC_CFEqual(interfaceName, bsdName)) {
1428 // if not a match, retain
1429 CFArrayAppendValue(newServices, service);
1430 continue;
1431 }
1432
1433 // if a match, update
1434 serviceID = SCNetworkServiceGetServiceID(service);
1435 servicePrivate = (SCNetworkServicePrivateRef)service;
1436 newService = SCNetworkServiceCopy(servicePrivate->prefs, serviceID);
1437 if (newService != NULL) {
1438 CFArrayAppendValue(newServices, newService);
1439 CFRelease(newService);
1440 }
1441 }
1442
1443 return newServices;
1444 }
1445 #endif // !TARGET_OS_IPHONE
1446
1447
1448 static __inline__ Boolean
1449 skipInterface(SCNetworkInterfaceRef interface)
1450 {
1451 CFStringRef action;
1452
1453 action = _SCNetworkInterfaceGetConfigurationAction(interface);
1454 if (isA_CFString(action) &&
1455 CFEqual(action, kSCNetworkInterfaceConfigurationActionValueNone)) {
1456 return TRUE;
1457 }
1458
1459 return FALSE;
1460 }
1461
1462
1463 static Boolean
1464 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces, Boolean excludeHidden)
1465 {
1466 CFSetRef excluded = NULL;
1467 CFIndex i;
1468 CFIndex n = 0;
1469 Boolean ok = TRUE;
1470 CFArrayRef services;
1471 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1472 Boolean updated = FALSE;
1473 Boolean updatedIFs = FALSE;
1474
1475 #if TARGET_OS_IPHONE
1476 CFArrayRef orphans = NULL;
1477 CFArrayRef sets;
1478
1479 sets = SCNetworkSetCopyAll(setPrivate->prefs);
1480 if (sets != NULL) {
1481 if (CFArrayGetCount(sets) == 1) {
1482 services = SCNetworkSetCopyServices(set);
1483 if (services != NULL) {
1484 n = CFArrayGetCount(services);
1485 CFRelease(services);
1486 }
1487
1488 if ((n == 0) && CFEqual(set, CFArrayGetValueAtIndex(sets, 0))) {
1489 // after a "Reset Network Settings" we need to find (and
1490 // add back) any VPN services that were orphaned.
1491 orphans = SCNetworkServiceCopyAll(setPrivate->prefs);
1492 }
1493 }
1494
1495 CFRelease(sets);
1496 }
1497 #endif // TARGET_OS_IPHONE
1498
1499 // copy network services
1500 services = copyServices(set);
1501
1502 // copy network interfaces to be excluded
1503 excluded = copyExcludedInterfaces(setPrivate->prefs);
1504
1505 #if !TARGET_OS_IPHONE
1506 // look for interfaces that should auto-magically be added
1507 // to an Ethernet bridge
1508 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
1509 for (i = 0; i < n; i++) {
1510 SCBridgeInterfaceRef bridge = NULL;
1511 SCNetworkInterfaceRef interface;
1512
1513 interface = CFArrayGetValueAtIndex(interfaces, i);
1514
1515 if (excludeHidden && skipInterface(interface)) {
1516 // if not auto-configure
1517 continue;
1518 }
1519
1520 if ((excluded != NULL)
1521 && CFSetContainsValue(excluded, interface)) {
1522 // if this interface is a member of a Bond or Bridge
1523 continue;
1524 }
1525
1526 if (__SCNetworkServiceExistsForInterface(services, interface)) {
1527 // if this is not a new interface
1528 continue;
1529 }
1530
1531 if (_SCNetworkInterfaceIsBuiltin(interface) &&
1532 _SCNetworkInterfaceIsThunderbolt(interface) &&
1533 !isA_SCBridgeInterface(interface)) {
1534 // add built-in Thunderbolt interfaces to bridge
1535 bridge = copyAutoBridgeInterface(setPrivate->prefs, CFSTR("thunderbolt-bridge"));
1536 }
1537
1538 if (bridge != NULL) {
1539 CFIndex bridgeIndex;
1540 CFArrayRef members;
1541 CFMutableArrayRef newMembers;
1542 CFMutableSetRef newExcluded;
1543 CFMutableArrayRef newInterfaces;
1544 CFArrayRef newServices;
1545
1546 // track the bridge interface (if it's in our list)
1547 bridgeIndex = CFArrayGetFirstIndexOfValue(interfaces,
1548 CFRangeMake(0, CFArrayGetCount(interfaces)),
1549 bridge);
1550
1551 // add new member interface
1552 members = SCBridgeInterfaceGetMemberInterfaces(bridge);
1553 if ((members != NULL) && (CFArrayGetCount(members) > 0)) {
1554 newMembers = CFArrayCreateMutableCopy(NULL, 0, members);
1555 updated = TRUE; // if we're updating an existing bridge
1556 } else {
1557 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1558 }
1559 CFArrayAppendValue(newMembers, interface);
1560 ok = SCBridgeInterfaceSetMemberInterfaces(bridge, newMembers);
1561 CFRelease(newMembers);
1562 if (!ok) {
1563 SCLog(TRUE, LOG_DEBUG,
1564 CFSTR("could not update bridge with \"%@\": %s\n"),
1565 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1566 SCErrorString(SCError()));
1567 CFRelease(bridge);
1568 continue;
1569 }
1570
1571 // exclude the new member interface
1572 newExcluded = CFSetCreateMutableCopy(NULL, 0, excluded);
1573 CFRelease(excluded);
1574 CFSetAddValue(newExcluded, interface);
1575 excluded = newExcluded;
1576
1577 // update the list of interfaces to include the [new or updated] bridge
1578 newInterfaces = CFArrayCreateMutableCopy(NULL, 0, interfaces);
1579 if (bridgeIndex != kCFNotFound) {
1580 CFArraySetValueAtIndex(newInterfaces, bridgeIndex, bridge);
1581 } else {
1582 CFArrayAppendValue(newInterfaces, bridge);
1583 }
1584 if (updatedIFs) {
1585 CFRelease(interfaces);
1586 }
1587 interfaces = newInterfaces;
1588 updatedIFs = TRUE;
1589
1590 // refresh [existing] services
1591 newServices = updateServices(services, bridge);
1592 if (newServices != NULL) {
1593 CFRelease(services);
1594 services = newServices;
1595 }
1596
1597 CFRelease(bridge);
1598 }
1599 }
1600 #endif // !TARGET_OS_IPHONE
1601
1602 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
1603 for (i = 0; i < n; i++) {
1604 SCNetworkInterfaceRef interface;
1605 CFMutableArrayRef interface_list;
1606
1607 interface = CFArrayGetValueAtIndex(interfaces, i);
1608
1609 if (excludeHidden && skipInterface(interface)) {
1610 // if not auto-configure
1611 continue;
1612 }
1613
1614 if ((excluded != NULL)
1615 && CFSetContainsValue(excluded, interface)) {
1616 // if this interface is a member of a Bond or Bridge
1617 continue;
1618 }
1619
1620 if (__SCNetworkServiceExistsForInterface(services, interface)) {
1621 // if this is not a new interface
1622 continue;
1623 }
1624
1625 interface_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1626 CFArrayAppendValue(interface_list, interface);
1627
1628 while (ok && (CFArrayGetCount(interface_list) > 0)) {
1629 CFArrayRef protocol_types;
1630
1631 interface = CFArrayGetValueAtIndex(interface_list, 0);
1632
1633 protocol_types = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
1634 if ((protocol_types != NULL) && (CFArrayGetCount(protocol_types) > 0)) {
1635 SCNetworkServiceRef service;
1636
1637 service = SCNetworkServiceCreate(setPrivate->prefs, interface);
1638 if (service == NULL) {
1639 SCLog(TRUE, LOG_DEBUG,
1640 CFSTR("could not create service for \"%@\": %s\n"),
1641 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1642 SCErrorString(SCError()));
1643 ok = FALSE;
1644 goto nextInterface;
1645 }
1646
1647 ok = SCNetworkServiceEstablishDefaultConfiguration(service);
1648 if (!ok) {
1649 SCLog(TRUE, LOG_DEBUG,
1650 CFSTR("could not estabish default configuration for \"%@\": %s\n"),
1651 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1652 SCErrorString(SCError()));
1653 SCNetworkServiceRemove(service);
1654 CFRelease(service);
1655 goto nextInterface;
1656 }
1657
1658 ok = SCNetworkSetAddService(set, service);
1659 if (!ok) {
1660 SCLog(TRUE, LOG_DEBUG,
1661 CFSTR("could not add service for \"%@\": %s\n"),
1662 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1663 SCErrorString(SCError()));
1664 SCNetworkServiceRemove(service);
1665 CFRelease(service);
1666 goto nextInterface;
1667 }
1668
1669 CFRelease(service);
1670 updated = TRUE;
1671 } else {
1672 add_supported_interfaces(interface_list, interface);
1673 }
1674
1675 nextInterface :
1676
1677 CFArrayRemoveValueAtIndex(interface_list, 0);
1678 }
1679 CFRelease(interface_list);
1680 }
1681 if (updatedIFs) CFRelease(interfaces);
1682 if (services != NULL) CFRelease(services);
1683 if (excluded != NULL) CFRelease(excluded);
1684
1685 #if TARGET_OS_IPHONE
1686 if (orphans != NULL) {
1687 if (ok && updated) {
1688 CFIndex i;
1689 CFIndex n = CFArrayGetCount(orphans);
1690
1691 for (i = 0; i < n; i++) {
1692 SCNetworkServiceRef service;
1693
1694 service = CFArrayGetValueAtIndex(orphans, i);
1695 if (_SCNetworkServiceIsVPN(service)) {
1696 ok = SCNetworkSetAddService(set, service);
1697 if (!ok) {
1698 break;
1699 }
1700 }
1701 }
1702 }
1703
1704 CFRelease(orphans);
1705 }
1706 #endif // TARGET_OS_IPHONE
1707
1708 if (ok && !updated) {
1709 // if no changes were made
1710 _SCErrorSet(kSCStatusOK);
1711 }
1712
1713 return updated;
1714 }
1715
1716
1717 Boolean
1718 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set)
1719 {
1720 CFArrayRef interfaces;
1721 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1722 Boolean updated = FALSE;
1723
1724 if (!isA_SCNetworkSet(set)) {
1725 _SCErrorSet(kSCStatusInvalidArgument);
1726 return FALSE;
1727 }
1728
1729 interfaces = _SCNetworkInterfaceCopyAllWithPreferences(setPrivate->prefs);
1730 if (interfaces != NULL) {
1731 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, TRUE);
1732 CFRelease(interfaces);
1733 }
1734
1735 return updated;
1736 }
1737
1738
1739 Boolean
1740 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
1741 {
1742 CFArrayRef interfaces;
1743 Boolean updated;
1744
1745 if (!isA_SCNetworkSet(set)) {
1746 _SCErrorSet(kSCStatusInvalidArgument);
1747 return FALSE;
1748 }
1749
1750 if (!isA_SCNetworkInterface(interface)) {
1751 _SCErrorSet(kSCStatusInvalidArgument);
1752 return FALSE;
1753 }
1754
1755 interfaces = CFArrayCreate(NULL, (const void **)&interface, 1, &kCFTypeArrayCallBacks);
1756 assert(interfaces != NULL);
1757 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, FALSE);
1758 CFRelease(interfaces);
1759
1760 return updated;
1761 }
1762
1763
1764 SCNetworkServiceRef
1765 SCNetworkSetCopySelectedVPNService(SCNetworkSetRef set)
1766 {
1767 CFIndex i;
1768 CFIndex n;
1769 SCNetworkServiceRef selected = NULL;
1770 CFArrayRef services;
1771 CFMutableArrayRef services_vpn = NULL;
1772
1773 if (!isA_SCNetworkSet(set)) {
1774 _SCErrorSet(kSCStatusInvalidArgument);
1775 return NULL;
1776 }
1777
1778 services = SCNetworkSetCopyServices(set);
1779 if (services != NULL) {
1780 n = CFArrayGetCount(services);
1781 for (i = 0; i < n; i++) {
1782 SCNetworkServiceRef service;
1783
1784 service = CFArrayGetValueAtIndex(services, i);
1785 if (!SCNetworkServiceGetEnabled(service)) {
1786 // if not enabled
1787 continue;
1788 }
1789
1790 if (!_SCNetworkServiceIsVPN(service)) {
1791 // if not VPN service
1792 continue;
1793 }
1794
1795 if (services_vpn == NULL) {
1796 services_vpn = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1797 }
1798 CFArrayAppendValue(services_vpn, service);
1799 }
1800
1801 CFRelease(services);
1802 }
1803
1804 if (services_vpn == NULL) {
1805 // if no VPN services
1806 return NULL;
1807 }
1808
1809 n = CFArrayGetCount(services_vpn);
1810 if (n > 1) {
1811 CFArrayRef order;
1812 CFMutableArrayRef sorted;
1813
1814 order = SCNetworkSetGetServiceOrder(set);
1815 sorted = CFArrayCreateMutableCopy(NULL, 0, services_vpn);
1816 CFArraySortValues(sorted,
1817 CFRangeMake(0, CFArrayGetCount(sorted)),
1818 _SCNetworkServiceCompare,
1819 (void *)order);
1820 CFRelease(services_vpn);
1821 services_vpn = sorted;
1822 }
1823
1824 #if TARGET_OS_IPHONE
1825 if (n > 1) {
1826 CFStringRef serviceID_prefs;
1827
1828 #define VPN_PREFERENCES CFSTR("com.apple.mobilevpn")
1829 #define VPN_SERVICE_ID CFSTR("activeVPNID")
1830
1831 CFPreferencesAppSynchronize(VPN_PREFERENCES);
1832 serviceID_prefs = CFPreferencesCopyAppValue(VPN_SERVICE_ID, VPN_PREFERENCES);
1833 if (serviceID_prefs != NULL) {
1834 for (i = 0; i < n; i++) {
1835 SCNetworkServiceRef service;
1836 CFStringRef serviceID;
1837
1838 service = CFArrayGetValueAtIndex(services_vpn, i);
1839 serviceID = SCNetworkServiceGetServiceID(service);
1840 if (CFEqual(serviceID, serviceID_prefs)) {
1841 selected = service;
1842 CFRetain(selected);
1843 break;
1844 }
1845
1846 }
1847
1848 CFRelease(serviceID_prefs);
1849 }
1850 }
1851 #endif // TARGET_OS_IPHONE
1852
1853 if (selected == NULL) {
1854 selected = CFArrayGetValueAtIndex(services_vpn, 0);
1855 CFRetain(selected);
1856 }
1857
1858 CFRelease(services_vpn);
1859 return selected;
1860 }
1861
1862
1863 Boolean
1864 SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set, SCNetworkServiceRef service)
1865 {
1866 Boolean ok = TRUE;
1867 CFArrayRef services;
1868
1869 if (!isA_SCNetworkSet(set)) {
1870 _SCErrorSet(kSCStatusInvalidArgument);
1871 return FALSE;
1872 }
1873
1874 if (!isA_SCNetworkService(service) || !_SCNetworkServiceIsVPN(service)) {
1875 _SCErrorSet(kSCStatusInvalidArgument);
1876 return FALSE;
1877 }
1878
1879 services = SCNetworkSetCopyServices(set);
1880 if (services != NULL) {
1881 CFIndex i;
1882 CFIndex n = CFArrayGetCount(services);
1883
1884 if (!CFArrayContainsValue(services, CFRangeMake(0, n), service)) {
1885 // if selected service not a member of the current set
1886 _SCErrorSet(kSCStatusInvalidArgument);
1887 ok = FALSE;
1888 goto done;
1889 }
1890
1891 for (i = 0; ok && (i < n); i++) {
1892 SCNetworkServiceRef vpn;
1893
1894 vpn = CFArrayGetValueAtIndex(services, i);
1895 if (!_SCNetworkServiceIsVPN(vpn)) {
1896 // if not VPN service
1897 continue;
1898 }
1899
1900 ok = SCNetworkServiceSetEnabled(vpn, CFEqual(service, vpn));
1901 }
1902 }
1903
1904 done :
1905
1906 if (services != NULL) CFRelease(services);
1907 return ok;
1908 }
1909
1910
1911 Boolean
1912 _SCNetworkSetSetSetID(SCNetworkSetRef set, CFStringRef newSetID)
1913 {
1914 SCNetworkSetRef currentSet = NULL;
1915 SCNetworkSetPrivateRef currentSetPrivate = NULL;
1916 CFDictionaryRef entity;
1917 CFStringRef newPath;
1918 Boolean ok = FALSE;
1919 CFStringRef oldPath = NULL;
1920 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1921 Boolean updateCurrentSet = FALSE;
1922
1923 if (!isA_SCNetworkSet(set)) {
1924 _SCErrorSet(kSCStatusInvalidArgument);
1925 return FALSE;
1926 }
1927
1928 if (!isA_CFString(newSetID)) {
1929 _SCErrorSet(kSCStatusInvalidArgument);
1930 return FALSE;
1931 }
1932
1933 // If newSetID is equal to current setID, our work is done
1934 if (CFEqual(newSetID, setPrivate->setID)) {
1935 return TRUE;
1936 }
1937
1938 newPath = SCPreferencesPathKeyCreateSet(NULL, newSetID);
1939 entity = SCPreferencesPathGetValue(setPrivate->prefs, newPath);
1940 if (isA_CFDictionary(entity)) {
1941 // if the new set already exists
1942 _SCErrorSet(kSCStatusKeyExists);
1943 goto done;
1944 }
1945
1946 oldPath = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
1947 entity = SCPreferencesPathGetValue(setPrivate->prefs, oldPath);
1948 if (!isA_CFDictionary(entity)) {
1949 // if the set has already been removed
1950 _SCErrorSet(kSCStatusNoKey);
1951 goto done;
1952 }
1953
1954 ok = SCPreferencesPathSetValue(setPrivate->prefs, newPath, entity);
1955 if (!ok) {
1956 goto done;
1957 }
1958
1959 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, oldPath);
1960 if (!ok) {
1961 goto done;
1962 }
1963
1964 // update current set (if needed)
1965 currentSet = SCNetworkSetCopyCurrent(setPrivate->prefs);
1966 if (currentSet != NULL) {
1967 currentSetPrivate = (SCNetworkSetPrivateRef)currentSet;
1968 if (CFEqual(currentSetPrivate->setID, setPrivate->setID)) {
1969 updateCurrentSet = TRUE;
1970 }
1971 CFRelease(currentSet);
1972 }
1973
1974 CFRetain(newSetID);
1975 CFRelease(setPrivate->setID);
1976
1977 setPrivate->setID = newSetID;
1978
1979 if (updateCurrentSet) {
1980 SCNetworkSetSetCurrent(set);
1981 }
1982
1983 done:
1984
1985 if (oldPath != NULL) {
1986 CFRelease(oldPath);
1987 }
1988 if (newPath != NULL) {
1989 CFRelease(newPath);
1990 }
1991
1992 return ok;
1993 }