]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkSet.c
41dd8d26b8365d4a3ed3cada65b8260c31ea9c9b
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkSet.c
1 /*
2 * Copyright (c) 2004-2007, 2009-2013 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 Boolean
295 SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
296 {
297 SCNetworkInterfaceRef interface;
298 CFArrayRef interface_config = NULL;
299 CFStringRef link;
300 Boolean ok;
301 CFStringRef path;
302 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
303 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
304
305 if (!isA_SCNetworkSet(set)) {
306 _SCErrorSet(kSCStatusInvalidArgument);
307 return FALSE;
308 }
309
310 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
311 _SCErrorSet(kSCStatusInvalidArgument);
312 return FALSE;
313 }
314
315 // make sure that we do not add an orphaned network service if its
316 // associated interface is a member of a bond or bridge.
317 interface = SCNetworkServiceGetInterface(service);
318 if ((interface != NULL) &&
319 __SCNetworkInterfaceIsMember(servicePrivate->prefs, interface)) {
320 _SCErrorSet(kSCStatusKeyExists);
321 return FALSE;
322 }
323
324 #define PREVENT_DUPLICATE_SERVICE_NAMES
325 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
326 CFStringRef name;
327
328 name = SCNetworkServiceGetName(service);
329 if (name != NULL) {
330 CFArrayRef services;
331
332 services = SCNetworkSetCopyServices(set);
333 if (services != NULL) {
334 CFIndex i;
335 CFIndex n;
336
337 n = CFArrayGetCount(services);
338 for (i = 0; i < n; i++) {
339 CFStringRef otherName;
340 SCNetworkServiceRef otherService;
341
342 otherService = CFArrayGetValueAtIndex(services, i);
343 otherName = SCNetworkServiceGetName(otherService);
344 if ((otherName != NULL) && CFEqual(name, otherName)) {
345 /*
346 * if a service with the same "name" is
347 * already a member of the set.
348 */
349 CFRelease(services);
350 _SCErrorSet(kSCStatusKeyExists);
351 return FALSE;
352 }
353 }
354
355 CFRelease(services);
356 }
357 }
358 #endif // PREVENT_DUPLICATE_SERVICE_NAMES
359
360 //#define PREVENT_DUPLICATE_SETS
361 #ifdef PREVENT_DUPLICATE_SETS
362 CFArrayRef sets;
363
364 // ensure that each service is only a member of ONE set
365 sets = SCNetworkSetCopyAll(setPrivate->prefs);
366 if (sets != NULL) {
367 CFIndex i;
368 CFIndex n;
369
370 n = CFArrayGetCount(sets);
371 for (i = 0; i < n; i++) {
372 Boolean found;
373 CFArrayRef services;
374 SCNetworkSetRef set;
375
376 set = CFArrayGetValueAtIndex(sets, i);
377 services = SCNetworkSetCopyServices(set);
378 found = CFArrayContainsValue(services,
379 CFRangeMake(0, CFArrayGetCount(services)),
380 service);
381 CFRelease(services);
382
383 if (found) {
384 CFRelease(sets);
385 _SCErrorSet(kSCStatusKeyExists);
386 return FALSE;
387 }
388 }
389 CFRelease(sets);
390 }
391 #endif /* PREVENT_DUPLICATE_SETS */
392
393 // get the [deep] interface configuration settings
394 interface = SCNetworkServiceGetInterface(service);
395 if (interface != NULL) {
396 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface);
397 }
398
399 // create the link between "set" and the "service"
400 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator
401 setPrivate->setID, // set
402 servicePrivate->serviceID, // service
403 NULL); // entity
404 link = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
405 servicePrivate->serviceID, // service
406 NULL); // entity
407 ok = SCPreferencesPathSetLink(setPrivate->prefs, path, link);
408 CFRelease(path);
409 CFRelease(link);
410 if (!ok) {
411 goto done;
412 }
413
414 // push the [deep] interface configuration into all sets which contain this service.
415 if (interface != NULL) {
416 __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config);
417 }
418
419 // add service to ServiceOrder
420 _serviceOrder_add(set, service);
421
422 // mark set as no longer "new"
423 setPrivate->established = TRUE;
424
425 done :
426
427 if (interface_config != NULL) CFRelease(interface_config);
428 return ok;
429 }
430
431
432 SCNetworkSetRef
433 SCNetworkSetCopy(SCPreferencesRef prefs, CFStringRef setID)
434 {
435 CFDictionaryRef entity;
436 CFStringRef path;
437 SCNetworkSetPrivateRef setPrivate;
438
439 if (!isA_CFString(setID)) {
440 _SCErrorSet(kSCStatusInvalidArgument);
441 return NULL;
442 }
443
444 path = SCPreferencesPathKeyCreateSet(NULL, setID);
445 entity = SCPreferencesPathGetValue(prefs, path);
446 CFRelease(path);
447
448 if (!isA_CFDictionary(entity)) {
449 _SCErrorSet(kSCStatusNoKey);
450 return NULL;
451 }
452
453 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
454 assert(setPrivate != NULL);
455
456 // mark set as "old" (already established)
457 setPrivate->established = TRUE;
458
459 return (SCNetworkSetRef)setPrivate;
460 }
461
462
463 Boolean
464 SCNetworkSetContainsInterface(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
465 {
466 Boolean found = FALSE;
467 CFArrayRef services;
468
469 services = SCNetworkSetCopyServices(set);
470 if (services != NULL) {
471 found = __SCNetworkServiceExistsForInterface(services, interface);
472 CFRelease(services);
473 }
474
475 return found;
476 }
477
478
479 CFArrayRef /* of SCNetworkSetRef's */
480 SCNetworkSetCopyAll(SCPreferencesRef prefs)
481 {
482 CFMutableArrayRef array;
483 CFIndex n;
484 CFStringRef path;
485 CFDictionaryRef sets;
486
487 path = SCPreferencesPathKeyCreateSets(NULL);
488 sets = SCPreferencesPathGetValue(prefs, path);
489 CFRelease(path);
490
491 if ((sets != NULL) && !isA_CFDictionary(sets)) {
492 return NULL;
493 }
494
495 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
496
497 n = (sets != NULL) ? CFDictionaryGetCount(sets) : 0;
498 if (n > 0) {
499 CFIndex i;
500 const void * keys_q[N_QUICK];
501 const void ** keys = keys_q;
502 const void * vals_q[N_QUICK];
503 const void ** vals = vals_q;
504
505 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
506 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
507 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
508 }
509 CFDictionaryGetKeysAndValues(sets, keys, vals);
510 for (i = 0; i < n; i++) {
511 SCNetworkSetPrivateRef setPrivate;
512
513 if (!isA_CFDictionary(vals[i])) {
514 SCLog(TRUE,
515 LOG_INFO,
516 CFSTR("SCNetworkSetCopyAll(): error w/set \"%@\"\n"),
517 keys[i]);
518 continue;
519 }
520
521 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, keys[i]);
522 assert(setPrivate != NULL);
523
524 // mark set as "old" (already established)
525 setPrivate->established = TRUE;
526
527 CFArrayAppendValue(array, (SCNetworkSetRef)setPrivate);
528 CFRelease(setPrivate);
529 }
530 if (keys != keys_q) {
531 CFAllocatorDeallocate(NULL, keys);
532 CFAllocatorDeallocate(NULL, vals);
533 }
534 }
535
536 return array;
537 }
538
539
540 CFArrayRef /* of SCNetworkInterfaceRef's */
541 SCNetworkSetCopyAvailableInterfaces(SCNetworkSetRef set)
542 {
543 CFMutableArrayRef available;
544 CFMutableSetRef excluded = NULL;
545 int i;
546 CFArrayRef interfaces;
547 int n_interfaces;
548 int n_exclusions = 0;
549 SCPreferencesRef prefs;
550 SCNetworkSetPrivateRef setPrivate;
551
552 setPrivate = (SCNetworkSetPrivateRef)set;
553 prefs = setPrivate->prefs;
554
555 interfaces = _SCNetworkInterfaceCopyAllWithPreferences(prefs);
556 n_interfaces = CFArrayGetCount(interfaces);
557 if (n_interfaces == 0) {
558 return interfaces;
559 }
560
561 if (prefs != NULL) {
562 CFArrayRef bridges = NULL;
563
564 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
565
566 #if !TARGET_OS_IPHONE
567 CFArrayRef bonds = NULL;
568
569 bonds = SCBondInterfaceCopyAll(prefs);
570 if (bonds != NULL) {
571 __SCBondInterfaceListCollectMembers(bonds, excluded);
572 CFRelease(bonds);
573 }
574 #endif /* !TARGET_OS_IPHONE */
575
576 bridges = SCBridgeInterfaceCopyAll(prefs);
577 if (bridges != NULL) {
578 __SCBridgeInterfaceListCollectMembers(bridges, excluded);
579 CFRelease(bridges);
580 }
581
582 n_exclusions = CFSetGetCount(excluded);
583 }
584
585 if (n_exclusions == 0) {
586 if (excluded != NULL) {
587 CFRelease(excluded);
588 }
589
590 return interfaces;
591 }
592
593 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
594
595 for (i = 0; i < n_interfaces; i++) {
596 SCNetworkInterfaceRef interface;
597
598 interface = CFArrayGetValueAtIndex(interfaces, i);
599 if (CFSetContainsValue(excluded, interface)) {
600 // if excluded
601 continue;
602 }
603
604 CFArrayAppendValue(available, interface);
605 }
606
607 CFRelease(interfaces);
608 CFRelease(excluded);
609
610 return available;
611 }
612
613
614 SCNetworkSetRef
615 SCNetworkSetCopyCurrent(SCPreferencesRef prefs)
616 {
617 CFArrayRef components;
618 CFStringRef currentID;
619 SCNetworkSetPrivateRef setPrivate = NULL;
620
621 currentID = SCPreferencesGetValue(prefs, kSCPrefCurrentSet);
622 if (!isA_CFString(currentID)) {
623 return NULL;
624 }
625
626 components = CFStringCreateArrayBySeparatingStrings(NULL, currentID, CFSTR("/"));
627 if (CFArrayGetCount(components) == 3) {
628 CFStringRef setID;
629 CFStringRef path;
630
631 setID = CFArrayGetValueAtIndex(components, 2);
632 path = SCPreferencesPathKeyCreateSet(NULL, setID);
633 if (CFEqual(path, currentID)) {
634 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
635 assert(setPrivate != NULL);
636
637 // mark set as "old" (already established)
638 setPrivate->established = TRUE;
639 } else {
640 SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkSetCopyCurrent(): preferences are non-conformant"));
641 }
642 CFRelease(path);
643 }
644 CFRelease(components);
645
646 return (SCNetworkSetRef)setPrivate;
647 }
648
649
650 CFArrayRef /* of SCNetworkServiceRef's */
651 SCNetworkSetCopyServices(SCNetworkSetRef set)
652 {
653 CFMutableArrayRef array;
654 CFDictionaryRef dict;
655 CFIndex n;
656 CFStringRef path;
657 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
658
659 if (!isA_SCNetworkSet(set)) {
660 _SCErrorSet(kSCStatusInvalidArgument);
661 return NULL;
662 }
663
664 path = SCPreferencesPathKeyCreateSetNetworkService(NULL, setPrivate->setID, NULL);
665 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
666 CFRelease(path);
667 if ((dict != NULL) && !isA_CFDictionary(dict)) {
668 return NULL;
669 }
670
671 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
672
673 n = (dict != NULL) ? CFDictionaryGetCount(dict) : 0;
674 if (n > 0) {
675 CFIndex i;
676 const void * keys_q[N_QUICK];
677 const void ** keys = keys_q;
678
679 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
680 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
681 }
682 CFDictionaryGetKeysAndValues(dict, keys, NULL);
683 for (i = 0; i < n; i++) {
684 CFArrayRef components;
685 CFStringRef link;
686
687 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
688 setPrivate->setID,
689 (CFStringRef)keys[i],
690 NULL);
691 link = SCPreferencesPathGetLink(setPrivate->prefs, path);
692 CFRelease(path);
693 if (link == NULL) {
694 SCLog(TRUE,
695 LOG_INFO,
696 CFSTR("SCNetworkSetCopyServices(): service \"%@\" for set \"%@\" is not a link\n"),
697 keys[i],
698 setPrivate->setID);
699 continue; // if the service is not a link
700 }
701
702 components = CFStringCreateArrayBySeparatingStrings(NULL, link, CFSTR("/"));
703 if (CFArrayGetCount(components) == 3) {
704 CFStringRef serviceID;
705
706 serviceID = CFArrayGetValueAtIndex(components, 2);
707 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
708 serviceID, // service
709 NULL); // entity
710 if (CFEqual(path, link)) {
711 SCNetworkServicePrivateRef servicePrivate;
712
713 servicePrivate = __SCNetworkServiceCreatePrivate(NULL,
714 setPrivate->prefs,
715 serviceID,
716 NULL);
717 CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
718 CFRelease(servicePrivate);
719 }
720 CFRelease(path);
721 }
722 CFRelease(components);
723 }
724 if (keys != keys_q) {
725 CFAllocatorDeallocate(NULL, keys);
726 }
727 }
728
729 return array;
730 }
731
732
733 SCNetworkSetRef
734 SCNetworkSetCreate(SCPreferencesRef prefs)
735 {
736 CFArrayRef components;
737 CFDictionaryRef entity;
738 Boolean ok;
739 CFStringRef path;
740 CFStringRef prefix;
741 CFStringRef setID;
742 SCNetworkSetPrivateRef setPrivate;
743
744 prefix = SCPreferencesPathKeyCreateSets(NULL);
745 path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
746 if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
747 CFRelease(prefix);
748 if (path == NULL) {
749 return NULL;
750 }
751
752 components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
753 setID = CFArrayGetValueAtIndex(components, 2);
754 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
755 assert(setPrivate != NULL);
756 CFRelease(components);
757
758 // mark set as "new" (not yet established)
759 setPrivate->established = FALSE;
760
761 // establish the set in the preferences
762 entity = CFDictionaryCreate(NULL,
763 NULL, NULL, 0,
764 &kCFTypeDictionaryKeyCallBacks,
765 &kCFTypeDictionaryValueCallBacks);
766 ok = SCPreferencesPathSetValue(prefs, path, entity);
767 CFRelease(path);
768 CFRelease(entity);
769 if (!ok) {
770 CFRelease(setPrivate);
771 setPrivate = NULL;
772 }
773
774 return (SCNetworkSetRef)setPrivate;
775 }
776
777
778 CFStringRef
779 SCNetworkSetGetSetID(SCNetworkSetRef set)
780 {
781 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
782
783 if (!isA_SCNetworkSet(set)) {
784 _SCErrorSet(kSCStatusInvalidArgument);
785 return NULL;
786 }
787
788 return setPrivate->setID;
789 }
790
791
792 CFStringRef
793 SCNetworkSetGetName(SCNetworkSetRef set)
794 {
795 CFBundleRef bundle;
796 CFDictionaryRef entity;
797 CFStringRef path;
798 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
799
800 if (!isA_SCNetworkSet(set)) {
801 _SCErrorSet(kSCStatusInvalidArgument);
802 return NULL;
803 }
804
805 if (setPrivate->name != NULL) {
806 return setPrivate->name;
807 }
808
809 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
810 entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
811 CFRelease(path);
812
813 if (isA_CFDictionary(entity)) {
814 CFStringRef name;
815
816 name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
817 if (isA_CFString(name)) {
818 setPrivate->name = CFRetain(name);
819 }
820 }
821
822 bundle = _SC_CFBundleGet();
823 if (bundle != NULL) {
824 if (setPrivate->name != NULL) {
825 CFStringRef non_localized;
826
827 non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
828 CFSTR("DEFAULT_SET_NAME"),
829 CFSTR("Automatic"),
830 NULL);
831 if (non_localized != NULL) {
832 if (CFEqual(setPrivate->name, non_localized)) {
833 CFStringRef localized;
834
835 // if "Automatic", return localized name
836 localized = CFBundleCopyLocalizedString(bundle,
837 CFSTR("DEFAULT_SET_NAME"),
838 CFSTR("Automatic"),
839 NULL);
840 if (localized != NULL) {
841 CFRelease(setPrivate->name);
842 setPrivate->name = localized;
843 }
844 }
845
846 CFRelease(non_localized);
847 }
848 }
849 }
850
851 return setPrivate->name;
852 }
853
854
855 CFArrayRef /* of serviceID CFStringRef's */
856 SCNetworkSetGetServiceOrder(SCNetworkSetRef set)
857 {
858 CFDictionaryRef dict;
859 CFStringRef path;
860 CFArrayRef serviceOrder;
861 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
862
863 if (!isA_SCNetworkSet(set)) {
864 _SCErrorSet(kSCStatusInvalidArgument);
865 return NULL;
866 }
867
868 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
869 if (path == NULL) {
870 return NULL;
871 }
872
873 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
874 CFRelease(path);
875 if (!isA_CFDictionary(dict)) {
876 return NULL;
877 }
878
879 serviceOrder = CFDictionaryGetValue(dict, kSCPropNetServiceOrder);
880 serviceOrder = isA_CFArray(serviceOrder);
881
882 return serviceOrder;
883 }
884
885
886 CFTypeID
887 SCNetworkSetGetTypeID(void)
888 {
889 pthread_once(&initialized, __SCNetworkSetInitialize); /* initialize runtime */
890 return __kSCNetworkSetTypeID;
891 }
892
893
894 Boolean
895 SCNetworkSetRemove(SCNetworkSetRef set)
896 {
897 CFStringRef currentPath;
898 Boolean ok = FALSE;
899 CFStringRef path;
900 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
901
902 if (!isA_SCNetworkSet(set)) {
903 _SCErrorSet(kSCStatusInvalidArgument);
904 return FALSE;
905 }
906
907 currentPath = SCPreferencesGetValue(setPrivate->prefs, kSCPrefCurrentSet);
908 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
909 if (!isA_CFString(currentPath) || !CFEqual(currentPath, path)) {
910 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
911 } else {
912 _SCErrorSet(kSCStatusInvalidArgument);
913 }
914 CFRelease(path);
915
916 return ok;
917 }
918
919
920 Boolean
921 SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service)
922 {
923 SCNetworkInterfaceRef interface;
924 CFArrayRef interface_config = NULL;
925 Boolean ok;
926 CFStringRef path;
927 int sc_status = kSCStatusOK;
928 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
929 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
930
931 if (!isA_SCNetworkSet(set)) {
932 _SCErrorSet(kSCStatusInvalidArgument);
933 return FALSE;
934 }
935
936 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
937 _SCErrorSet(kSCStatusInvalidArgument);
938 return FALSE;
939 }
940
941 // remove service from ServiceOrder
942 _serviceOrder_remove(set, service);
943
944 // get the [deep] interface configuration settings
945 interface = SCNetworkServiceGetInterface(service);
946 if (interface != NULL) {
947 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface);
948 if (interface_config != NULL) {
949 // remove the interface configuration from all sets which contain this service.
950 __SCNetworkInterfaceSetDeepConfiguration(set, interface, NULL);
951 }
952 }
953
954 // remove the link between "set" and the "service"
955 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
956 setPrivate->setID,
957 servicePrivate->serviceID,
958 NULL);
959 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
960 if (!ok) {
961 sc_status = SCError(); // preserve the error
962 }
963 CFRelease(path);
964
965 // push the [deep] interface configuration [back] into all sets which contain the service.
966 if (interface_config != NULL) {
967 __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config);
968 }
969
970 if (interface_config != NULL) CFRelease(interface_config);
971 if (!ok) {
972 _SCErrorSet(sc_status);
973 }
974 return ok;
975 }
976
977
978 Boolean
979 SCNetworkSetSetCurrent(SCNetworkSetRef set)
980 {
981 Boolean ok;
982 CFStringRef path;
983 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
984
985 if (!isA_SCNetworkSet(set)) {
986 _SCErrorSet(kSCStatusInvalidArgument);
987 return FALSE;
988 }
989
990 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
991 ok = SCPreferencesSetValue(setPrivate->prefs, kSCPrefCurrentSet, path);
992 CFRelease(path);
993 return ok;
994 }
995
996
997 Boolean
998 SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
999 {
1000 CFBundleRef bundle = NULL;
1001 CFDictionaryRef entity;
1002 CFStringRef localized = NULL;
1003 CFStringRef non_localized = NULL;
1004 Boolean ok = FALSE;
1005 CFStringRef path;
1006 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1007
1008 if (!isA_SCNetworkSet(set)) {
1009 _SCErrorSet(kSCStatusInvalidArgument);
1010 return FALSE;
1011 }
1012
1013 if ((name != NULL) && !isA_CFString(name)) {
1014 _SCErrorSet(kSCStatusInvalidArgument);
1015 return FALSE;
1016 }
1017
1018 // if known, compare against localized name
1019
1020 if (name != NULL) {
1021 bundle = _SC_CFBundleGet();
1022 if (bundle != NULL) {
1023 non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
1024 CFSTR("DEFAULT_SET_NAME"),
1025 CFSTR("Automatic"),
1026 NULL);
1027 if (non_localized != NULL) {
1028 if (CFEqual(name, non_localized)) {
1029 localized = CFBundleCopyLocalizedString(bundle,
1030 CFSTR("DEFAULT_SET_NAME"),
1031 CFSTR("Automatic"),
1032 NULL);
1033 if (localized != NULL) {
1034 name = localized;
1035 }
1036 }
1037 }
1038 }
1039 }
1040
1041 #define PREVENT_DUPLICATE_SET_NAMES
1042 #ifdef PREVENT_DUPLICATE_SET_NAMES
1043 if (name != NULL) {
1044 CFArrayRef sets;
1045
1046 // ensure that each set is uniquely named
1047
1048 sets = SCNetworkSetCopyAll(setPrivate->prefs);
1049 if (sets != NULL) {
1050 CFIndex i;
1051 CFIndex n;
1052
1053 n = CFArrayGetCount(sets);
1054 for (i = 0; i < n; i++) {
1055 CFStringRef otherID;
1056 CFStringRef otherName;
1057 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, i);
1058
1059 otherID = SCNetworkSetGetSetID(set);
1060 if (CFEqual(setPrivate->setID, otherID)) {
1061 continue; // skip current set
1062 }
1063
1064 otherName = SCNetworkSetGetName(set);
1065 if ((otherName != NULL) && CFEqual(name, otherName)) {
1066 // if "name" not unique
1067 CFRelease(sets);
1068 _SCErrorSet(kSCStatusKeyExists);
1069 goto done;
1070 }
1071 }
1072 CFRelease(sets);
1073 }
1074 }
1075 #endif /* PREVENT_DUPLICATE_SET_NAMES */
1076
1077 // if known, store non-localized name
1078
1079 if ((name != NULL) && (bundle != NULL) && (non_localized != NULL)) {
1080 if (localized == NULL) {
1081 localized = CFBundleCopyLocalizedString(bundle,
1082 CFSTR("DEFAULT_SET_NAME"),
1083 CFSTR("Automatic"),
1084 NULL);
1085 }
1086
1087 if (localized != NULL) {
1088 if (CFEqual(name, localized)) {
1089 name = non_localized;
1090 }
1091 }
1092 }
1093
1094 // update the "name"
1095
1096 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
1097 entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
1098 if (isA_CFDictionary(entity) ||
1099 ((entity == NULL) && (name != NULL))) {
1100 CFMutableDictionaryRef newEntity;
1101
1102 if (entity != NULL) {
1103 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1104 } else {
1105 newEntity = CFDictionaryCreateMutable(NULL,
1106 0,
1107 &kCFTypeDictionaryKeyCallBacks,
1108 &kCFTypeDictionaryValueCallBacks);
1109 }
1110 if (name != NULL) {
1111 CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name);
1112 } else {
1113 CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
1114 }
1115 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newEntity);
1116 CFRelease(newEntity);
1117 }
1118 CFRelease(path);
1119
1120 done :
1121
1122 if (localized != NULL) CFRelease(localized);
1123 if (non_localized != NULL) CFRelease(non_localized);
1124 return ok;
1125 }
1126
1127
1128 Boolean
1129 SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
1130 {
1131 CFDictionaryRef dict;
1132 CFMutableDictionaryRef newDict;
1133 Boolean ok;
1134 CFStringRef path;
1135 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1136
1137 if (!isA_SCNetworkSet(set)) {
1138 _SCErrorSet(kSCStatusInvalidArgument);
1139 return FALSE;
1140 }
1141
1142 if (isA_CFArray(newOrder)) {
1143 CFIndex i;
1144 CFIndex n = CFArrayGetCount(newOrder);
1145
1146 for (i = 0; i < n; i++) {
1147 CFStringRef serviceID;
1148
1149 serviceID = CFArrayGetValueAtIndex(newOrder, i);
1150 if (!isA_CFString(serviceID)) {
1151 _SCErrorSet(kSCStatusInvalidArgument);
1152 return FALSE;
1153 }
1154 }
1155 } else {
1156 _SCErrorSet(kSCStatusInvalidArgument);
1157 return FALSE;
1158 }
1159
1160 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
1161 if (path == NULL) {
1162 return FALSE;
1163 }
1164
1165 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
1166 if (dict != NULL) {
1167 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
1168 } else {
1169 newDict = CFDictionaryCreateMutable(NULL,
1170 0,
1171 &kCFTypeDictionaryKeyCallBacks,
1172 &kCFTypeDictionaryValueCallBacks);
1173 }
1174
1175 CFDictionarySetValue(newDict, kSCPropNetServiceOrder, newOrder);
1176 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newDict);
1177 CFRelease(newDict);
1178 CFRelease(path);
1179
1180 return ok;
1181 }
1182
1183
1184 #pragma mark -
1185 #pragma mark SCNetworkSet SPIs
1186
1187
1188 static void
1189 add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef interface)
1190 {
1191 CFIndex i;
1192 CFArrayRef interface_types;
1193 CFIndex n;
1194
1195 interface_types = SCNetworkInterfaceGetSupportedInterfaceTypes(interface);
1196 n = (interface_types != NULL) ? CFArrayGetCount(interface_types) : 0;
1197 for (i = 0; i < n; i++) {
1198 SCNetworkInterfaceRef parent;
1199 CFStringRef interface_type;
1200
1201 interface_type = CFArrayGetValueAtIndex(interface_types, i);
1202 parent = SCNetworkInterfaceCreateWithInterface(interface, interface_type);
1203 if (parent != NULL) {
1204 CFArrayAppendValue(interface_list, parent);
1205 CFRelease(parent);
1206 }
1207 }
1208
1209 return;
1210 }
1211
1212
1213 static CFSetRef /* of SCNetworkInterfaceRef's */
1214 copyExcludedInterfaces(SCPreferencesRef prefs)
1215 {
1216 CFMutableSetRef excluded;
1217 CFArrayRef interfaces;
1218
1219 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1220
1221 #if !TARGET_OS_IPHONE
1222 // exclude Bond [member] interfaces
1223 interfaces = SCBondInterfaceCopyAll(prefs);
1224 if (interfaces != NULL) {
1225 __SCBondInterfaceListCollectMembers(interfaces, excluded);
1226 CFRelease(interfaces);
1227 }
1228 #endif // !TARGET_OS_IPHONE
1229
1230 // exclude Bridge [member] interfaces
1231 interfaces = SCBridgeInterfaceCopyAll(prefs);
1232 if (interfaces != NULL) {
1233 __SCBridgeInterfaceListCollectMembers(interfaces, excluded);
1234 CFRelease(interfaces);
1235 }
1236
1237 return excluded;
1238 }
1239
1240
1241 #if !TARGET_OS_IPHONE
1242 static SCBridgeInterfaceRef
1243 copyAutoBridgeInterface(SCPreferencesRef prefs, CFStringRef bridgeName)
1244 {
1245 SCBridgeInterfaceRef bridge = NULL;
1246 CFArrayRef interfaces;
1247
1248 // exclude Bridge [member] interfaces
1249 interfaces = SCBridgeInterfaceCopyAll(prefs);
1250 if (interfaces != NULL) {
1251 CFIndex i;
1252 CFIndex n;
1253
1254 n = CFArrayGetCount(interfaces);
1255 for (i = 0; i < n; i++) {
1256 SCBridgeInterfaceRef interface;
1257 CFStringRef name = NULL;
1258 CFDictionaryRef options;
1259
1260 interface = CFArrayGetValueAtIndex(interfaces, i);
1261 options = SCBridgeInterfaceGetOptions(interface);
1262 if ((options != NULL) &&
1263 CFDictionaryGetValueIfPresent(options,
1264 CFSTR("__AUTO__"),
1265 (const void **)&name) &&
1266 _SC_CFEqual(name, bridgeName)) {
1267 bridge = interface;
1268 CFRetain(bridge);
1269 break;
1270 }
1271 }
1272
1273 CFRelease(interfaces);
1274 }
1275
1276 if (bridge == NULL) {
1277 bridge = SCBridgeInterfaceCreate(prefs);
1278 if (bridge != NULL) {
1279 CFMutableDictionaryRef newOptions;
1280 Boolean ok;
1281
1282 newOptions = CFDictionaryCreateMutable(NULL, 0,
1283 &kCFTypeDictionaryKeyCallBacks,
1284 &kCFTypeDictionaryValueCallBacks);
1285 CFDictionarySetValue(newOptions, CFSTR("__AUTO__"), bridgeName);
1286 ok = SCBridgeInterfaceSetOptions(bridge, newOptions);
1287 CFRelease(newOptions);
1288 if (!ok) {
1289 CFRelease(bridge);
1290 bridge = NULL;
1291 }
1292 }
1293 }
1294
1295 return bridge;
1296 }
1297 #endif // !TARGET_OS_IPHONE
1298
1299
1300 static CFArrayRef
1301 copyServices(SCNetworkSetRef set)
1302 {
1303 CFArrayRef services;
1304 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1305
1306 // first, assume that we only want to add new services
1307 // for those interfaces that are not represented in the
1308 // current set.
1309 services = SCNetworkSetCopyServices(set);
1310 if ((services != NULL) && setPrivate->established) {
1311 // but, if we are given an existing (or "established") set
1312 // than we only want to add new services for those interfaces
1313 // that are not represented in *any* set.
1314 CFRelease(services);
1315 services = SCNetworkServiceCopyAll(setPrivate->prefs);
1316 }
1317
1318 return services;
1319 }
1320
1321
1322 #if !TARGET_OS_IPHONE
1323 static CFArrayRef
1324 updateServices(CFArrayRef services, SCNetworkInterfaceRef interface)
1325 {
1326 CFStringRef bsdName;
1327 CFIndex i;
1328 CFIndex n;
1329 CFMutableArrayRef newServices;
1330
1331 if (services == NULL) {
1332 return NULL;
1333 }
1334
1335 bsdName = SCNetworkInterfaceGetBSDName(interface);
1336
1337 newServices = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1338
1339 n = CFArrayGetCount(services);
1340 for (i = 0; i < n; i++) {
1341 SCNetworkInterfaceRef interface;
1342 CFStringRef interfaceName;
1343 SCNetworkServiceRef newService;
1344 SCNetworkServiceRef service;
1345 CFStringRef serviceID;
1346 SCNetworkServicePrivateRef servicePrivate;
1347
1348 service = CFArrayGetValueAtIndex(services, i);
1349 interface = SCNetworkServiceGetInterface(service);
1350 interfaceName = SCNetworkInterfaceGetBSDName(interface);
1351 if (!_SC_CFEqual(interfaceName, bsdName)) {
1352 // if not a match, retain
1353 CFArrayAppendValue(newServices, service);
1354 continue;
1355 }
1356
1357 // if a match, update
1358 serviceID = SCNetworkServiceGetServiceID(service);
1359 servicePrivate = (SCNetworkServicePrivateRef)service;
1360 newService = SCNetworkServiceCopy(servicePrivate->prefs, serviceID);
1361 if (newService != NULL) {
1362 CFArrayAppendValue(newServices, newService);
1363 CFRelease(newService);
1364 }
1365 }
1366
1367 return newServices;
1368 }
1369 #endif // !TARGET_OS_IPHONE
1370
1371
1372 static Boolean
1373 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces)
1374 {
1375 CFSetRef excluded = NULL;
1376 CFIndex i;
1377 CFIndex n = 0;
1378 Boolean ok = TRUE;
1379 CFArrayRef services;
1380 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1381 Boolean updated = FALSE;
1382 Boolean updatedIFs = FALSE;
1383
1384 #if TARGET_OS_IPHONE
1385 CFArrayRef orphans = NULL;
1386 CFArrayRef sets;
1387
1388 sets = SCNetworkSetCopyAll(setPrivate->prefs);
1389 if (sets != NULL) {
1390 if (CFArrayGetCount(sets) == 1) {
1391 services = SCNetworkSetCopyServices(set);
1392 if (services != NULL) {
1393 n = CFArrayGetCount(services);
1394 CFRelease(services);
1395 }
1396
1397 if ((n == 0) && CFEqual(set, CFArrayGetValueAtIndex(sets, 0))) {
1398 // after a "Reset Network Settings" we need to find (and
1399 // add back) any VPN services that were orphaned.
1400 orphans = SCNetworkServiceCopyAll(setPrivate->prefs);
1401 }
1402 }
1403
1404 CFRelease(sets);
1405 }
1406 #endif // TARGET_OS_IPHONE
1407
1408 // copy network services
1409 services = copyServices(set);
1410
1411 // copy network interfaces to be excluded
1412 excluded = copyExcludedInterfaces(setPrivate->prefs);
1413
1414 #if !TARGET_OS_IPHONE
1415 // look for interfaces that should auto-magically be added
1416 // to an Ethernet bridge
1417 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
1418 for (i = 0; i < n; i++) {
1419 SCBridgeInterfaceRef bridge = NULL;
1420 SCNetworkInterfaceRef interface;
1421
1422 interface = CFArrayGetValueAtIndex(interfaces, i);
1423 if ((excluded != NULL)
1424 && CFSetContainsValue(excluded, interface)) {
1425 // if this interface is a member of a Bond or Bridge
1426 continue;
1427 }
1428
1429 if (__SCNetworkServiceExistsForInterface(services, interface)) {
1430 // if this is not a new interface
1431 continue;
1432 }
1433
1434 if (_SCNetworkInterfaceIsBuiltin(interface) &&
1435 _SCNetworkInterfaceIsThunderbolt(interface) &&
1436 !isA_SCBridgeInterface(interface)) {
1437 // add built-in Thunderbolt interfaces to bridge
1438 bridge = copyAutoBridgeInterface(setPrivate->prefs, CFSTR("thunderbolt-bridge"));
1439 }
1440
1441 if (bridge != NULL) {
1442 CFIndex bridgeIndex;
1443 CFArrayRef members;
1444 CFMutableArrayRef newMembers;
1445 CFMutableSetRef newExcluded;
1446 CFMutableArrayRef newInterfaces;
1447 CFArrayRef newServices;
1448
1449 // track the bridge interface (if it's in our list)
1450 bridgeIndex = CFArrayGetFirstIndexOfValue(interfaces,
1451 CFRangeMake(0, CFArrayGetCount(interfaces)),
1452 bridge);
1453
1454 // add new member interface
1455 members = SCBridgeInterfaceGetMemberInterfaces(bridge);
1456 if ((members != NULL) && (CFArrayGetCount(members) > 0)) {
1457 newMembers = CFArrayCreateMutableCopy(NULL, 0, members);
1458 updated = TRUE; // if we're updating an existing bridge
1459 } else {
1460 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1461 }
1462 CFArrayAppendValue(newMembers, interface);
1463 ok = SCBridgeInterfaceSetMemberInterfaces(bridge, newMembers);
1464 CFRelease(newMembers);
1465 if (!ok) {
1466 SCLog(TRUE, LOG_DEBUG,
1467 CFSTR("could not update bridge with \"%@\": %s\n"),
1468 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1469 SCErrorString(SCError()));
1470 CFRelease(bridge);
1471 continue;
1472 }
1473
1474 // exclude the new member interface
1475 newExcluded = CFSetCreateMutableCopy(NULL, 0, excluded);
1476 CFRelease(excluded);
1477 CFSetAddValue(newExcluded, interface);
1478 excluded = newExcluded;
1479
1480 // update the list of interfaces to include the [new or updated] bridge
1481 newInterfaces = CFArrayCreateMutableCopy(NULL, 0, interfaces);
1482 if (bridgeIndex != kCFNotFound) {
1483 CFArraySetValueAtIndex(newInterfaces, bridgeIndex, bridge);
1484 } else {
1485 CFArrayAppendValue(newInterfaces, bridge);
1486 }
1487 if (updatedIFs) {
1488 CFRelease(interfaces);
1489 }
1490 interfaces = newInterfaces;
1491 updatedIFs = TRUE;
1492
1493 // refresh [existing] services
1494 newServices = updateServices(services, bridge);
1495 if (newServices != NULL) {
1496 CFRelease(services);
1497 services = newServices;
1498 }
1499
1500 CFRelease(bridge);
1501 }
1502 }
1503 #endif // !TARGET_OS_IPHONE
1504
1505 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
1506 for (i = 0; i < n; i++) {
1507 SCNetworkInterfaceRef interface;
1508 CFMutableArrayRef interface_list;
1509
1510 interface = CFArrayGetValueAtIndex(interfaces, i);
1511 if ((excluded != NULL)
1512 && CFSetContainsValue(excluded, interface)) {
1513 // if this interface is a member of a Bond or Bridge
1514 continue;
1515 }
1516
1517 if (__SCNetworkServiceExistsForInterface(services, interface)) {
1518 // if this is not a new interface
1519 continue;
1520 }
1521
1522 interface_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1523 CFArrayAppendValue(interface_list, interface);
1524
1525 while (ok && (CFArrayGetCount(interface_list) > 0)) {
1526 CFArrayRef protocol_types;
1527
1528 interface = CFArrayGetValueAtIndex(interface_list, 0);
1529
1530 protocol_types = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
1531 if ((protocol_types != NULL) && (CFArrayGetCount(protocol_types) > 0)) {
1532 SCNetworkServiceRef service;
1533
1534 service = SCNetworkServiceCreate(setPrivate->prefs, interface);
1535 if (service == NULL) {
1536 SCLog(TRUE, LOG_DEBUG,
1537 CFSTR("could not create service for \"%@\": %s\n"),
1538 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1539 SCErrorString(SCError()));
1540 ok = FALSE;
1541 goto nextInterface;
1542 }
1543
1544 ok = SCNetworkServiceEstablishDefaultConfiguration(service);
1545 if (!ok) {
1546 SCLog(TRUE, LOG_DEBUG,
1547 CFSTR("could not estabish default configuration for \"%@\": %s\n"),
1548 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1549 SCErrorString(SCError()));
1550 SCNetworkServiceRemove(service);
1551 CFRelease(service);
1552 goto nextInterface;
1553 }
1554
1555 while (TRUE) {
1556 CFStringRef newName;
1557
1558 ok = SCNetworkSetAddService(set, service);
1559 if (ok) {
1560 break;
1561 }
1562
1563 if (SCError() != kSCStatusKeyExists) {
1564 SCLog(TRUE, LOG_DEBUG,
1565 CFSTR("could not add service for \"%@\": %s\n"),
1566 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1567 SCErrorString(SCError()));
1568 SCNetworkServiceRemove(service);
1569 CFRelease(service);
1570 goto nextInterface;
1571 }
1572
1573 // we have two interfaces with the same service
1574 // name, acquire a new, hopefully unique, name
1575
1576 newName = __SCNetworkServiceNextName(service);
1577 if (newName == NULL) {
1578 SCLog(TRUE, LOG_DEBUG,
1579 CFSTR("could not set unique name for \"%@\": %s\n"),
1580 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1581 SCErrorString(SCError()));
1582 SCNetworkServiceRemove(service);
1583 CFRelease(service);
1584 goto nextInterface;
1585 }
1586
1587 ok = SCNetworkServiceSetName(service, newName);
1588 CFRelease(newName);
1589 if (ok) {
1590 continue;
1591 }
1592
1593 if (SCError() != kSCStatusKeyExists) {
1594 SCLog(TRUE, LOG_DEBUG,
1595 CFSTR("could not set unique name for \"%@\": %s\n"),
1596 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1597 SCErrorString(SCError()));
1598 SCNetworkServiceRemove(service);
1599 CFRelease(service);
1600 goto nextInterface;
1601 }
1602 }
1603
1604 CFRelease(service);
1605 updated = TRUE;
1606 } else {
1607 add_supported_interfaces(interface_list, interface);
1608 }
1609
1610 nextInterface :
1611
1612 CFArrayRemoveValueAtIndex(interface_list, 0);
1613 }
1614 CFRelease(interface_list);
1615 }
1616 if (updatedIFs) CFRelease(interfaces);
1617 if (services != NULL) CFRelease(services);
1618 if (excluded != NULL) CFRelease(excluded);
1619
1620 #if TARGET_OS_IPHONE
1621 if (orphans != NULL) {
1622 if (ok && updated) {
1623 CFIndex i;
1624 CFIndex n = CFArrayGetCount(orphans);
1625
1626 for (i = 0; i < n; i++) {
1627 SCNetworkServiceRef service;
1628
1629 service = CFArrayGetValueAtIndex(orphans, i);
1630 if (_SCNetworkServiceIsVPN(service)) {
1631 ok = SCNetworkSetAddService(set, service);
1632 if (!ok) {
1633 break;
1634 }
1635 }
1636 }
1637 }
1638
1639 CFRelease(orphans);
1640 }
1641 #endif // TARGET_OS_IPHONE
1642
1643 if (ok && !updated) {
1644 // if no changes were made
1645 _SCErrorSet(kSCStatusOK);
1646 }
1647
1648 return updated;
1649 }
1650
1651
1652 Boolean
1653 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set)
1654 {
1655 CFArrayRef interfaces;
1656 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1657 Boolean updated = FALSE;
1658
1659 if (!isA_SCNetworkSet(set)) {
1660 _SCErrorSet(kSCStatusInvalidArgument);
1661 return FALSE;
1662 }
1663
1664 interfaces = _SCNetworkInterfaceCopyAllWithPreferences(setPrivate->prefs);
1665 if (interfaces != NULL) {
1666 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
1667 CFRelease(interfaces);
1668 }
1669
1670 return updated;
1671 }
1672
1673
1674 Boolean
1675 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
1676 {
1677 CFArrayRef interfaces;
1678 Boolean updated;
1679
1680 if (!isA_SCNetworkSet(set)) {
1681 _SCErrorSet(kSCStatusInvalidArgument);
1682 return FALSE;
1683 }
1684
1685 if (!isA_SCNetworkInterface(interface)) {
1686 _SCErrorSet(kSCStatusInvalidArgument);
1687 return FALSE;
1688 }
1689
1690 interfaces = CFArrayCreate(NULL, (const void **)&interface, 1, &kCFTypeArrayCallBacks);
1691 assert(interfaces != NULL);
1692 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
1693 CFRelease(interfaces);
1694
1695 return updated;
1696 }
1697
1698
1699 SCNetworkServiceRef
1700 SCNetworkSetCopySelectedVPNService(SCNetworkSetRef set)
1701 {
1702 CFIndex i;
1703 CFIndex n;
1704 SCNetworkServiceRef selected = NULL;
1705 CFArrayRef services;
1706 CFMutableArrayRef services_vpn = NULL;
1707
1708 if (!isA_SCNetworkSet(set)) {
1709 _SCErrorSet(kSCStatusInvalidArgument);
1710 return NULL;
1711 }
1712
1713 services = SCNetworkSetCopyServices(set);
1714 if (services != NULL) {
1715 n = CFArrayGetCount(services);
1716 for (i = 0; i < n; i++) {
1717 SCNetworkServiceRef service;
1718
1719 service = CFArrayGetValueAtIndex(services, i);
1720 if (!SCNetworkServiceGetEnabled(service)) {
1721 // if not enabled
1722 continue;
1723 }
1724
1725 if (!_SCNetworkServiceIsVPN(service)) {
1726 // if not VPN service
1727 continue;
1728 }
1729
1730 if (services_vpn == NULL) {
1731 services_vpn = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1732 }
1733 CFArrayAppendValue(services_vpn, service);
1734 }
1735
1736 CFRelease(services);
1737 }
1738
1739 if (services_vpn == NULL) {
1740 // if no VPN services
1741 return NULL;
1742 }
1743
1744 n = CFArrayGetCount(services_vpn);
1745 if (n > 1) {
1746 CFArrayRef order;
1747 CFMutableArrayRef sorted;
1748
1749 order = SCNetworkSetGetServiceOrder(set);
1750 sorted = CFArrayCreateMutableCopy(NULL, 0, services_vpn);
1751 CFArraySortValues(sorted,
1752 CFRangeMake(0, CFArrayGetCount(sorted)),
1753 _SCNetworkServiceCompare,
1754 (void *)order);
1755 CFRelease(services_vpn);
1756 services_vpn = sorted;
1757 }
1758
1759 #if TARGET_OS_IPHONE
1760 if (n > 1) {
1761 CFStringRef serviceID_prefs;
1762
1763 #define VPN_PREFERENCES CFSTR("com.apple.mobilevpn")
1764 #define VPN_SERVICE_ID CFSTR("activeVPNID")
1765
1766 CFPreferencesAppSynchronize(VPN_PREFERENCES);
1767 serviceID_prefs = CFPreferencesCopyAppValue(VPN_SERVICE_ID, VPN_PREFERENCES);
1768 if (serviceID_prefs != NULL) {
1769 for (i = 0; i < n; i++) {
1770 SCNetworkServiceRef service;
1771 CFStringRef serviceID;
1772
1773 service = CFArrayGetValueAtIndex(services_vpn, i);
1774 serviceID = SCNetworkServiceGetServiceID(service);
1775 if (CFEqual(serviceID, serviceID_prefs)) {
1776 selected = service;
1777 CFRetain(selected);
1778 break;
1779 }
1780
1781 }
1782
1783 CFRelease(serviceID_prefs);
1784 }
1785 }
1786 #endif // TARGET_OS_IPHONE
1787
1788 if (selected == NULL) {
1789 selected = CFArrayGetValueAtIndex(services_vpn, 0);
1790 CFRetain(selected);
1791 }
1792
1793 CFRelease(services_vpn);
1794 return selected;
1795 }
1796
1797
1798 Boolean
1799 SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set, SCNetworkServiceRef service)
1800 {
1801 Boolean ok = TRUE;
1802 CFArrayRef services;
1803
1804 if (!isA_SCNetworkSet(set)) {
1805 _SCErrorSet(kSCStatusInvalidArgument);
1806 return FALSE;
1807 }
1808
1809 if (!isA_SCNetworkService(service) || !_SCNetworkServiceIsVPN(service)) {
1810 _SCErrorSet(kSCStatusInvalidArgument);
1811 return FALSE;
1812 }
1813
1814 services = SCNetworkSetCopyServices(set);
1815 if (services != NULL) {
1816 CFIndex i;
1817 CFIndex n = CFArrayGetCount(services);
1818
1819 if (!CFArrayContainsValue(services, CFRangeMake(0, n), service)) {
1820 // if selected service not a member of the current set
1821 _SCErrorSet(kSCStatusInvalidArgument);
1822 ok = FALSE;
1823 goto done;
1824 }
1825
1826 for (i = 0; ok && (i < n); i++) {
1827 SCNetworkServiceRef vpn;
1828
1829 vpn = CFArrayGetValueAtIndex(services, i);
1830 if (!_SCNetworkServiceIsVPN(vpn)) {
1831 // if not VPN service
1832 continue;
1833 }
1834
1835 ok = SCNetworkServiceSetEnabled(vpn, CFEqual(service, vpn));
1836 }
1837 }
1838
1839 done :
1840
1841 if (services != NULL) CFRelease(services);
1842 return ok;
1843 }