]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkSet.c
922f7e01cb6e887b1a80c7cb61cb582c3644d843
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkSet.c
1 /*
2 * Copyright (c) 2004-2007 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
164 return setPrivate;
165 }
166
167
168 #pragma mark -
169
170
171 static Boolean
172 _serviceIsPPP(SCNetworkServiceRef service)
173 {
174 SCNetworkInterfaceRef interface;
175 CFStringRef interfaceType;
176
177 interface = SCNetworkServiceGetInterface(service);
178 if (interface == NULL) {
179 return FALSE;
180 }
181
182 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
183 return CFEqual(interfaceType, kSCNetworkInterfaceTypePPP);
184 }
185
186
187 static Boolean
188 _serviceIsVPN(SCNetworkServiceRef service)
189 {
190 SCNetworkInterfaceRef interface;
191 CFStringRef interfaceType;
192
193 // if (!_serviceIsPPP(service)) {
194 // return FALSE;
195 // }
196
197 interface = SCNetworkServiceGetInterface(service);
198 // if (interface == NULL) {
199 // return FALSE;
200 // }
201
202 interface = SCNetworkInterfaceGetInterface(interface);
203 if (interface == NULL) {
204 return FALSE;
205 }
206
207 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
208 return (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP) ||
209 CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP));
210 }
211
212
213 static int
214 _serviceOrder(SCNetworkServiceRef service)
215 {
216 SCNetworkInterfaceRef interface;
217
218 interface = SCNetworkServiceGetInterface(service);
219 if (interface == NULL) {
220 return 100000; // sort last
221 }
222
223 return __SCNetworkInterfaceOrder(interface);
224 }
225
226
227 static void
228 _serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service)
229 {
230 CFIndex i;
231 CFIndex n;
232 CFMutableArrayRef newOrder;
233 CFArrayRef order;
234 CFStringRef serviceID;
235 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
236 CFIndex slot;
237
238 order = SCNetworkSetGetServiceOrder(set);
239 if (order != NULL) {
240 newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
241 } else {
242 newOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
243 }
244 n = CFArrayGetCount(newOrder);
245
246 serviceID = SCNetworkServiceGetServiceID(service);
247 if (CFArrayContainsValue(newOrder, CFRangeMake(0, n), serviceID)) {
248 // if serviceID already present
249 goto done;
250 }
251
252 if (_serviceIsPPP(service) && !_serviceIsVPN(service)) {
253 int serviceOrder;
254
255 /*
256 * we add [non-VPN] PPP interfaces to the head of the
257 * service order but ensure that "modem" devices are
258 * in front of "Bluetooth" & "IrDA" devices.
259 */
260 slot = 0;
261
262 serviceOrder = _serviceOrder(service);
263
264 for (i = 0; i < n; i++) {
265 int slotOrder;
266 CFStringRef slotServiceID;
267 SCNetworkServiceRef slotService;
268
269 slotServiceID = CFArrayGetValueAtIndex(newOrder, i);
270 if (!isA_CFString(slotServiceID)) {
271 // if bad prefs
272 continue;
273 }
274
275 slotService = SCNetworkServiceCopy(setPrivate->prefs, slotServiceID);
276 if (slotService == NULL) {
277 // if serviceID not valid
278 continue;
279 }
280
281 if (_serviceIsPPP(slotService)) {
282 // if PPP service
283 slotOrder = _serviceOrder(slotService);
284 if (serviceOrder >= slotOrder) {
285 // add the service *after* this one
286 slot = i + 1;
287 }
288 }
289
290 CFRelease(slotService);
291 }
292 } else {
293 /*
294 * non-PPP interfaces are added to the end of the list.
295 */
296 slot = n;
297 }
298
299 CFArrayInsertValueAtIndex(newOrder, slot, serviceID);
300 (void) SCNetworkSetSetServiceOrder(set, newOrder);
301
302 done :
303
304 CFRelease(newOrder);
305
306 return;
307 }
308
309
310 static void
311 _serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service)
312 {
313 CFMutableArrayRef newOrder;
314 CFArrayRef order;
315 CFStringRef serviceID;
316
317 order = SCNetworkSetGetServiceOrder(set);
318 if (order == NULL) {
319 return;
320 }
321
322 serviceID = SCNetworkServiceGetServiceID(service);
323
324 newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
325 while (TRUE) {
326 CFIndex i;
327
328 i = CFArrayGetFirstIndexOfValue(newOrder,
329 CFRangeMake(0, CFArrayGetCount(newOrder)),
330 serviceID);
331 if (i == kCFNotFound) {
332 break;
333 }
334
335 CFArrayRemoveValueAtIndex(newOrder, i);
336 }
337 (void) SCNetworkSetSetServiceOrder(set, newOrder);
338 CFRelease(newOrder);
339
340 return;
341 }
342
343
344 #pragma mark -
345 #pragma mark SCNetworkSet APIs
346
347
348 #define N_QUICK 16
349
350
351 Boolean
352 SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
353 {
354 SCNetworkInterfaceRef interface;
355 CFArrayRef interface_config = NULL;
356 CFStringRef link;
357 Boolean ok;
358 CFStringRef path;
359 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
360 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
361
362 if (!isA_SCNetworkSet(set)) {
363 _SCErrorSet(kSCStatusInvalidArgument);
364 return FALSE;
365 }
366
367 if (!isA_SCNetworkService(service)) {
368 _SCErrorSet(kSCStatusInvalidArgument);
369 return FALSE;
370 }
371
372 #define PREVENT_DUPLICATE_SERVICE_NAMES
373 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
374 CFStringRef name;
375
376 name = SCNetworkServiceGetName(service);
377 if (name != NULL) {
378 CFArrayRef services;
379
380 services = SCNetworkSetCopyServices(set);
381 if (services != NULL) {
382 CFIndex i;
383 CFIndex n;
384
385 n = CFArrayGetCount(services);
386 for (i = 0; i < n; i++) {
387 CFStringRef otherName;
388 SCNetworkServiceRef otherService;
389
390 otherService = CFArrayGetValueAtIndex(services, i);
391 otherName = SCNetworkServiceGetName(otherService);
392 if ((otherName != NULL) && CFEqual(name, otherName)) {
393 /*
394 * if a service with the same "name" is
395 * already a member of the set.
396 */
397 CFRelease(services);
398 _SCErrorSet(kSCStatusKeyExists);
399 return FALSE;
400 }
401 }
402 }
403
404 CFRelease(services);
405 }
406 #endif // PREVENT_DUPLICATE_SERVICE_NAMES
407
408 //#define PREVENT_DUPLICATE_SETS
409 #ifdef PREVENT_DUPLICATE_SETS
410 CFArrayRef sets;
411
412 // ensure that each service is only a member of ONE set
413 sets = SCNetworkSetCopyAll(setPrivate->prefs);
414 if (sets != NULL) {
415 CFIndex i;
416 CFIndex n;
417
418 n = CFArrayGetCount(sets);
419 for (i = 0; i < n; i++) {
420 Boolean found;
421 CFArrayRef services;
422 SCNetworkSetRef set;
423
424 set = CFArrayGetValueAtIndex(sets, i);
425 services = SCNetworkSetCopyServices(set);
426 found = CFArrayContainsValue(services,
427 CFRangeMake(0, CFArrayGetCount(services)),
428 service);
429 CFRelease(services);
430
431 if (found) {
432 CFRelease(sets);
433 _SCErrorSet(kSCStatusKeyExists);
434 return FALSE;
435 }
436 }
437 CFRelease(sets);
438 }
439 #endif /* PREVENT_DUPLICATE_SETS */
440
441 // get the [deep] interface configuration settings
442 interface = SCNetworkServiceGetInterface(service);
443 if (interface != NULL) {
444 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(interface);
445 }
446
447 // create the link between "set" and the "service"
448 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator
449 setPrivate->setID, // set
450 servicePrivate->serviceID, // service
451 NULL); // entity
452 link = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
453 servicePrivate->serviceID, // service
454 NULL); // entity
455 ok = SCPreferencesPathSetLink(setPrivate->prefs, path, link);
456 CFRelease(path);
457 CFRelease(link);
458 if (!ok) {
459 goto done;
460 }
461
462 // push the [deep] interface configuration into all sets which contain this service.
463 if (interface != NULL) {
464 __SCNetworkInterfaceSetDeepConfiguration(interface, interface_config);
465 }
466
467 // add service to ServiceOrder
468 _serviceOrder_add(set, service);
469
470 done :
471
472 if (interface_config != NULL) CFRelease(interface_config);
473 return ok;
474 }
475
476
477 SCNetworkSetRef
478 SCNetworkSetCopy(SCPreferencesRef prefs, CFStringRef setID)
479 {
480 CFDictionaryRef entity;
481 CFStringRef path;
482 SCNetworkSetPrivateRef setPrivate;
483
484 if (!isA_CFString(setID)) {
485 _SCErrorSet(kSCStatusInvalidArgument);
486 return NULL;
487 }
488
489 path = SCPreferencesPathKeyCreateSet(NULL, setID);
490 entity = SCPreferencesPathGetValue(prefs, path);
491 CFRelease(path);
492
493 if (!isA_CFDictionary(entity)) {
494 _SCErrorSet(kSCStatusNoKey);
495 return NULL;
496 }
497
498 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
499 return (SCNetworkSetRef)setPrivate;
500 }
501
502
503 static Boolean
504 _SCNetworkServiceExistsForInterface(CFArrayRef services, SCNetworkInterfaceRef interface)
505 {
506 CFIndex i;
507 CFIndex n;
508
509 n = isA_CFArray(services) ? CFArrayGetCount(services) : 0;
510 for (i = 0; i < n; i++) {
511 SCNetworkServiceRef service;
512 SCNetworkInterfaceRef service_interface;
513
514 service = CFArrayGetValueAtIndex(services, i);
515
516 service_interface = SCNetworkServiceGetInterface(service);
517 while (service_interface != NULL) {
518 if (CFEqual(interface, service_interface)) {
519 return TRUE;
520 }
521
522 service_interface = SCNetworkInterfaceGetInterface(service_interface);
523 }
524 }
525
526 return FALSE;
527 }
528
529
530 Boolean
531 SCNetworkSetContainsInterface(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
532 {
533 Boolean found = FALSE;
534 CFArrayRef services;
535
536 services = SCNetworkSetCopyServices(set);
537 if (services != NULL) {
538 found = _SCNetworkServiceExistsForInterface(services, interface);
539 CFRelease(services);
540 }
541
542 return found;
543 }
544
545
546 CFArrayRef /* of SCNetworkSetRef's */
547 SCNetworkSetCopyAll(SCPreferencesRef prefs)
548 {
549 CFMutableArrayRef array;
550 CFIndex n;
551 CFStringRef path;
552 CFDictionaryRef sets;
553
554 path = SCPreferencesPathKeyCreateSets(NULL);
555 sets = SCPreferencesPathGetValue(prefs, path);
556 CFRelease(path);
557
558 if ((sets != NULL) && !isA_CFDictionary(sets)) {
559 return NULL;
560 }
561
562 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
563
564 n = (sets != NULL) ? CFDictionaryGetCount(sets) : 0;
565 if (n > 0) {
566 CFIndex i;
567 const void * keys_q[N_QUICK];
568 const void ** keys = keys_q;
569 const void * vals_q[N_QUICK];
570 const void ** vals = vals_q;
571
572 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
573 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
574 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
575 }
576 CFDictionaryGetKeysAndValues(sets, keys, vals);
577 for (i = 0; i < n; i++) {
578 SCNetworkSetPrivateRef setPrivate;
579
580 if (!isA_CFDictionary(vals[i])) {
581 SCLog(TRUE,
582 LOG_INFO,
583 CFSTR("SCNetworkSetCopyAll(): error w/set \"%@\"\n"),
584 keys[i]);
585 continue;
586 }
587
588 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, keys[i]);
589 CFArrayAppendValue(array, (SCNetworkSetRef)setPrivate);
590 CFRelease(setPrivate);
591 }
592 if (keys != keys_q) {
593 CFAllocatorDeallocate(NULL, keys);
594 CFAllocatorDeallocate(NULL, vals);
595 }
596 }
597
598 return array;
599 }
600
601
602 SCNetworkSetRef
603 SCNetworkSetCopyCurrent(SCPreferencesRef prefs)
604 {
605 CFArrayRef components;
606 CFStringRef currentID;
607 SCNetworkSetPrivateRef setPrivate = NULL;
608
609 currentID = SCPreferencesGetValue(prefs, kSCPrefCurrentSet);
610 if (!isA_CFString(currentID)) {
611 return NULL;
612 }
613
614 components = CFStringCreateArrayBySeparatingStrings(NULL, currentID, CFSTR("/"));
615 if (CFArrayGetCount(components) == 3) {
616 CFStringRef setID;
617 CFStringRef path;
618
619 setID = CFArrayGetValueAtIndex(components, 2);
620 path = SCPreferencesPathKeyCreateSet(NULL, setID);
621 if (CFEqual(path, currentID)) {
622 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
623 } else {
624 SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkSetCopyCurrent(): preferences are non-conformant"));
625 }
626 CFRelease(path);
627 }
628 CFRelease(components);
629
630 return (SCNetworkSetRef)setPrivate;
631 }
632
633
634 CFArrayRef /* of SCNetworkServiceRef's */
635 SCNetworkSetCopyServices(SCNetworkSetRef set)
636 {
637 CFMutableArrayRef array;
638 CFDictionaryRef dict;
639 CFIndex n;
640 CFStringRef path;
641 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
642
643 if (!isA_SCNetworkSet(set)) {
644 _SCErrorSet(kSCStatusInvalidArgument);
645 return NULL;
646 }
647
648 path = SCPreferencesPathKeyCreateSetNetworkService(NULL, setPrivate->setID, NULL);
649 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
650 CFRelease(path);
651 if ((dict != NULL) && !isA_CFDictionary(dict)) {
652 return NULL;
653 }
654
655 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
656
657 n = (dict != NULL) ? CFDictionaryGetCount(dict) : 0;
658 if (n > 0) {
659 CFIndex i;
660 const void * keys_q[N_QUICK];
661 const void ** keys = keys_q;
662
663 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
664 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
665 }
666 CFDictionaryGetKeysAndValues(dict, keys, NULL);
667 for (i = 0; i < n; i++) {
668 CFArrayRef components;
669 CFStringRef link;
670
671 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
672 setPrivate->setID,
673 (CFStringRef)keys[i],
674 NULL);
675 link = SCPreferencesPathGetLink(setPrivate->prefs, path);
676 CFRelease(path);
677 if (link == NULL) {
678 SCLog(TRUE,
679 LOG_INFO,
680 CFSTR("SCNetworkSetCopyServices(): service \"%@\" for set \"%@\" is not a link\n"),
681 keys[i],
682 setPrivate->setID);
683 continue; // if the service is not a link
684 }
685
686 components = CFStringCreateArrayBySeparatingStrings(NULL, link, CFSTR("/"));
687 if (CFArrayGetCount(components) == 3) {
688 CFStringRef serviceID;
689
690 serviceID = CFArrayGetValueAtIndex(components, 2);
691 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
692 serviceID, // service
693 NULL); // entity
694 if (CFEqual(path, link)) {
695 SCNetworkServicePrivateRef servicePrivate;
696
697 servicePrivate = __SCNetworkServiceCreatePrivate(NULL,
698 setPrivate->prefs,
699 serviceID,
700 NULL);
701 CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
702 CFRelease(servicePrivate);
703 }
704 CFRelease(path);
705 }
706 CFRelease(components);
707 }
708 if (keys != keys_q) {
709 CFAllocatorDeallocate(NULL, keys);
710 }
711 }
712
713 return array;
714 }
715
716
717 SCNetworkSetRef
718 SCNetworkSetCreate(SCPreferencesRef prefs)
719 {
720 CFArrayRef components;
721 CFStringRef path;
722 CFStringRef prefix;
723 CFStringRef setID;
724 SCNetworkSetPrivateRef setPrivate;
725
726 prefix = SCPreferencesPathKeyCreateSets(NULL);
727 path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
728 if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
729 CFRelease(prefix);
730 if (path == NULL) {
731 return NULL;
732 }
733
734 components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
735 CFRelease(path);
736
737 setID = CFArrayGetValueAtIndex(components, 2);
738 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
739 CFRelease(components);
740
741 return (SCNetworkSetRef)setPrivate;
742 }
743
744
745 CFStringRef
746 SCNetworkSetGetSetID(SCNetworkSetRef set)
747 {
748 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
749
750 if (!isA_SCNetworkSet(set)) {
751 _SCErrorSet(kSCStatusInvalidArgument);
752 return NULL;
753 }
754
755 return setPrivate->setID;
756 }
757
758
759 CFStringRef
760 SCNetworkSetGetName(SCNetworkSetRef set)
761 {
762 CFBundleRef bundle;
763 CFDictionaryRef entity;
764 CFStringRef path;
765 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
766
767 if (!isA_SCNetworkSet(set)) {
768 _SCErrorSet(kSCStatusInvalidArgument);
769 return NULL;
770 }
771
772 if (setPrivate->name != NULL) {
773 return setPrivate->name;;
774 }
775
776 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
777 entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
778 CFRelease(path);
779
780 if (isA_CFDictionary(entity)) {
781 CFStringRef name;
782
783 name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
784 if (isA_CFString(name)) {
785 setPrivate->name = CFRetain(name);
786 }
787 }
788
789 bundle = _SC_CFBundleGet();
790 if (bundle != NULL) {
791 if (setPrivate->name != NULL) {
792 CFStringRef non_localized;
793
794 non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
795 CFSTR("DEFAULT_SET_NAME"),
796 CFSTR("Automatic"),
797 NULL);
798 if (non_localized != NULL) {
799 if (CFEqual(setPrivate->name, non_localized)) {
800 CFStringRef localized;
801
802 // if "Automatic", return localized name
803 localized = CFBundleCopyLocalizedString(bundle,
804 CFSTR("DEFAULT_SET_NAME"),
805 CFSTR("Automatic"),
806 NULL);
807 if (localized != NULL) {
808 CFRelease(setPrivate->name);
809 setPrivate->name = localized;
810 }
811 }
812
813 CFRelease(non_localized);
814 }
815 }
816 }
817
818 return setPrivate->name;
819 }
820
821
822 CFArrayRef /* of serviceID CFStringRef's */
823 SCNetworkSetGetServiceOrder(SCNetworkSetRef set)
824 {
825 CFDictionaryRef dict;
826 CFStringRef path;
827 CFArrayRef serviceOrder;
828 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
829
830 if (!isA_SCNetworkSet(set)) {
831 _SCErrorSet(kSCStatusInvalidArgument);
832 return NULL;
833 }
834
835 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
836 if (path == NULL) {
837 return NULL;
838 }
839
840 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
841 CFRelease(path);
842 if (!isA_CFDictionary(dict)) {
843 return NULL;
844 }
845
846 serviceOrder = CFDictionaryGetValue(dict, kSCPropNetServiceOrder);
847 serviceOrder = isA_CFArray(serviceOrder);
848
849 return serviceOrder;
850 }
851
852
853 CFTypeID
854 SCNetworkSetGetTypeID(void)
855 {
856 pthread_once(&initialized, __SCNetworkSetInitialize); /* initialize runtime */
857 return __kSCNetworkSetTypeID;
858 }
859
860
861 Boolean
862 SCNetworkSetRemove(SCNetworkSetRef set)
863 {
864 CFStringRef currentPath;
865 Boolean ok = FALSE;
866 CFStringRef path;
867 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
868
869 if (!isA_SCNetworkSet(set)) {
870 _SCErrorSet(kSCStatusInvalidArgument);
871 return FALSE;
872 }
873
874 currentPath = SCPreferencesGetValue(setPrivate->prefs, kSCPrefCurrentSet);
875 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
876 if (!isA_CFString(currentPath) || !CFEqual(currentPath, path)) {
877 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
878 }
879 CFRelease(path);
880
881 return ok;
882 }
883
884
885 Boolean
886 SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service)
887 {
888 SCNetworkInterfaceRef interface;
889 CFArrayRef interface_config = NULL;
890 Boolean ok;
891 CFStringRef path;
892 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
893 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
894
895 if (!isA_SCNetworkSet(set)) {
896 _SCErrorSet(kSCStatusInvalidArgument);
897 return FALSE;
898 }
899
900 if (!isA_SCNetworkService(service)) {
901 _SCErrorSet(kSCStatusInvalidArgument);
902 return FALSE;
903 }
904
905 // remove service from ServiceOrder
906 _serviceOrder_remove(set, service);
907
908 // get the [deep] interface configuration settings
909 interface = SCNetworkServiceGetInterface(service);
910 if (interface != NULL) {
911 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(interface);
912 if (interface_config != NULL) {
913 // remove the interface configuration from all sets which contain this service.
914 __SCNetworkInterfaceSetDeepConfiguration(interface, NULL);
915 }
916 }
917
918 // remove the link between "set" and the "service"
919 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
920 setPrivate->setID,
921 servicePrivate->serviceID,
922 NULL);
923 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
924 CFRelease(path);
925 if (!ok) {
926 goto done;
927 }
928
929 // push the [deep] interface configuration [back] into all sets which contain the service.
930 if (interface_config != NULL) {
931 __SCNetworkInterfaceSetDeepConfiguration(interface, interface_config);
932 }
933
934 done :
935
936 if (interface_config != NULL) CFRelease(interface_config);
937 return ok;
938 }
939
940
941 Boolean
942 SCNetworkSetSetCurrent(SCNetworkSetRef set)
943 {
944 Boolean ok;
945 CFStringRef path;
946 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
947
948 if (!isA_SCNetworkSet(set)) {
949 _SCErrorSet(kSCStatusInvalidArgument);
950 return FALSE;
951 }
952
953 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
954 ok = SCPreferencesSetValue(setPrivate->prefs, kSCPrefCurrentSet, path);
955 CFRelease(path);
956 return ok;
957 }
958
959
960 Boolean
961 SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
962 {
963 CFBundleRef bundle = NULL;
964 CFDictionaryRef entity;
965 CFStringRef localized = NULL;
966 CFStringRef non_localized = NULL;
967 Boolean ok = FALSE;
968 CFStringRef path;
969 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
970
971 if (!isA_SCNetworkSet(set)) {
972 _SCErrorSet(kSCStatusInvalidArgument);
973 return FALSE;
974 }
975
976 if ((name != NULL) && !isA_CFString(name)) {
977 _SCErrorSet(kSCStatusInvalidArgument);
978 return FALSE;
979 }
980
981 // if known, compare against localized name
982
983 if (name != NULL) {
984 bundle = _SC_CFBundleGet();
985 if (bundle != NULL) {
986 non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
987 CFSTR("DEFAULT_SET_NAME"),
988 CFSTR("Automatic"),
989 NULL);
990 if (non_localized != NULL) {
991 if (CFEqual(name, non_localized)) {
992 localized = CFBundleCopyLocalizedString(bundle,
993 CFSTR("DEFAULT_SET_NAME"),
994 CFSTR("Automatic"),
995 NULL);
996 if (localized != NULL) {
997 name = localized;
998 }
999 }
1000 }
1001 }
1002 }
1003
1004 #define PREVENT_DUPLICATE_SET_NAMES
1005 #ifdef PREVENT_DUPLICATE_SET_NAMES
1006 if (name != NULL) {
1007 CFArrayRef sets;
1008
1009 // ensure that each set is uniquely named
1010
1011 sets = SCNetworkSetCopyAll(setPrivate->prefs);
1012 if (sets != NULL) {
1013 CFIndex i;
1014 CFIndex n;
1015
1016 n = CFArrayGetCount(sets);
1017 for (i = 0; i < n; i++) {
1018 CFStringRef otherID;
1019 CFStringRef otherName;
1020 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, i);
1021
1022 otherID = SCNetworkSetGetSetID(set);
1023 if (CFEqual(setPrivate->setID, otherID)) {
1024 continue; // skip current set
1025 }
1026
1027 otherName = SCNetworkSetGetName(set);
1028 if ((otherName != NULL) && CFEqual(name, otherName)) {
1029 // if "name" not unique
1030 CFRelease(sets);
1031 _SCErrorSet(kSCStatusKeyExists);
1032 goto done;
1033 }
1034 }
1035 CFRelease(sets);
1036 }
1037 }
1038 #endif /* PREVENT_DUPLICATE_SET_NAMES */
1039
1040 // if known, store non-localized name
1041
1042 if ((name != NULL) && (bundle != NULL) && (non_localized != NULL)) {
1043 if (localized == NULL) {
1044 localized = CFBundleCopyLocalizedString(bundle,
1045 CFSTR("DEFAULT_SET_NAME"),
1046 CFSTR("Automatic"),
1047 NULL);
1048 }
1049
1050 if (localized != NULL) {
1051 if (CFEqual(name, localized)) {
1052 name = non_localized;
1053 }
1054 }
1055 }
1056
1057 // update the "name"
1058
1059 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
1060 entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
1061 if ((entity == NULL) && (name != NULL)) {
1062 entity = CFDictionaryCreate(NULL,
1063 NULL,
1064 NULL,
1065 0,
1066 &kCFTypeDictionaryKeyCallBacks,
1067 &kCFTypeDictionaryValueCallBacks);
1068 }
1069 if (isA_CFDictionary(entity)) {
1070 CFMutableDictionaryRef newEntity;
1071
1072 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1073 if (name != NULL) {
1074 CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name);
1075 } else {
1076 CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
1077 }
1078 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newEntity);
1079 CFRelease(newEntity);
1080 }
1081 CFRelease(path);
1082
1083 done :
1084
1085 if (localized != NULL) CFRelease(localized);
1086 if (non_localized != NULL) CFRelease(non_localized);
1087 return ok;
1088 }
1089
1090
1091 Boolean
1092 SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
1093 {
1094 CFDictionaryRef dict;
1095 CFMutableDictionaryRef newDict;
1096 Boolean ok;
1097 CFStringRef path;
1098 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1099
1100 if (!isA_SCNetworkSet(set)) {
1101 _SCErrorSet(kSCStatusInvalidArgument);
1102 return FALSE;
1103 }
1104
1105 if (isA_CFArray(newOrder)) {
1106 CFIndex i;
1107 CFIndex n = CFArrayGetCount(newOrder);
1108
1109 for (i = 0; i < n; i++) {
1110 CFStringRef serviceID;
1111
1112 serviceID = CFArrayGetValueAtIndex(newOrder, i);
1113 if (!isA_CFString(serviceID)) {
1114 _SCErrorSet(kSCStatusInvalidArgument);
1115 return FALSE;
1116 }
1117 }
1118 } else {
1119 _SCErrorSet(kSCStatusInvalidArgument);
1120 return FALSE;
1121 }
1122
1123 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
1124 if (path == NULL) {
1125 return FALSE;
1126 }
1127
1128 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
1129 if (dict != NULL) {
1130 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
1131 } else {
1132 newDict = CFDictionaryCreateMutable(NULL,
1133 0,
1134 &kCFTypeDictionaryKeyCallBacks,
1135 &kCFTypeDictionaryValueCallBacks);
1136 }
1137
1138 CFDictionarySetValue(newDict, kSCPropNetServiceOrder, newOrder);
1139 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newDict);
1140 CFRelease(newDict);
1141 CFRelease(path);
1142
1143 return ok;
1144 }
1145
1146
1147 #pragma mark -
1148 #pragma mark SCNetworkSet SPIs
1149
1150
1151 static void
1152 add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef interface)
1153 {
1154 CFIndex i;
1155 CFArrayRef interface_types;
1156 CFIndex n;
1157
1158 interface_types = SCNetworkInterfaceGetSupportedInterfaceTypes(interface);
1159 n = (interface_types != NULL) ? CFArrayGetCount(interface_types) : 0;
1160 for (i = 0; i < n; i++) {
1161 SCNetworkInterfaceRef parent;
1162 CFStringRef interface_type;
1163
1164 interface_type = CFArrayGetValueAtIndex(interface_types, i);
1165 parent = SCNetworkInterfaceCreateWithInterface(interface, interface_type);
1166 if (parent != NULL) {
1167 CFArrayAppendValue(interface_list, parent);
1168 CFRelease(parent);
1169 }
1170 }
1171
1172 return;
1173 }
1174
1175
1176 Boolean
1177 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set)
1178 {
1179 CFIndex i;
1180 CFArrayRef interfaces;
1181 CFIndex n;
1182 Boolean ok = TRUE;
1183 CFArrayRef services;
1184 Boolean setUpdated = FALSE;
1185 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1186
1187 if (!isA_SCNetworkSet(set)) {
1188 _SCErrorSet(kSCStatusInvalidArgument);
1189 return FALSE;
1190 }
1191
1192 // first, assume that we only want to add new services
1193 // for those interfaces that are not represented in the
1194 // current set.
1195 services = SCNetworkSetCopyServices(set);
1196 if ((services != NULL) && (CFArrayGetCount(services) > 0)) {
1197 // but, if we are starting off with a non-empty
1198 // set than we only want to add new services for
1199 // those interfaces that are not represented in
1200 // *any* set.
1201 CFRelease(services);
1202 services = SCNetworkServiceCopyAll(setPrivate->prefs);
1203 }
1204
1205 interfaces = SCNetworkInterfaceCopyAll();
1206 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
1207 for (i = 0; i < n; i++) {
1208 SCNetworkInterfaceRef interface;
1209 CFMutableArrayRef interface_list;
1210
1211 interface = CFArrayGetValueAtIndex(interfaces, i);
1212 if (_SCNetworkServiceExistsForInterface(services, interface)) {
1213 // if this is not a new interface
1214 continue;
1215 }
1216
1217 interface_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1218 CFArrayAppendValue(interface_list, interface);
1219
1220 while (ok && (CFArrayGetCount(interface_list) > 0)) {
1221 CFArrayRef protocol_types;
1222
1223 interface = CFArrayGetValueAtIndex(interface_list, 0);
1224
1225 protocol_types = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
1226 if ((protocol_types != NULL) && (CFArrayGetCount(protocol_types) > 0)) {
1227 SCNetworkServiceRef service;
1228
1229 service = SCNetworkServiceCreate(setPrivate->prefs, interface);
1230 if (service == NULL) {
1231 SCLog(TRUE, LOG_DEBUG,
1232 CFSTR("could not create service for \"%@\": %s\n"),
1233 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1234 SCErrorString(SCError()));
1235 ok = FALSE;
1236 goto nextInterface;
1237 }
1238
1239 ok = SCNetworkServiceEstablishDefaultConfiguration(service);
1240 if (!ok) {
1241 SCLog(TRUE, LOG_DEBUG,
1242 CFSTR("could not estabish default configuration for \"%@\": %s\n"),
1243 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1244 SCErrorString(SCError()));
1245 SCNetworkServiceRemove(service);
1246 CFRelease(service);
1247 goto nextInterface;
1248 }
1249
1250 ok = SCNetworkSetAddService(set, service);
1251 if (!ok) {
1252 SCLog(TRUE, LOG_DEBUG,
1253 CFSTR("could not add service for \"%@\": %s\n"),
1254 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1255 SCErrorString(SCError()));
1256 SCNetworkServiceRemove(service);
1257 CFRelease(service);
1258 goto nextInterface;
1259 }
1260
1261 CFRelease(service);
1262 setUpdated = TRUE;
1263 } else {
1264 add_supported_interfaces(interface_list, interface);
1265 }
1266
1267 nextInterface :
1268
1269 CFArrayRemoveValueAtIndex(interface_list, 0);
1270 }
1271 CFRelease(interface_list);
1272 }
1273 if (interfaces != NULL) CFRelease(interfaces);
1274 if (services != NULL) CFRelease(services);
1275
1276 if (ok && !setUpdated) {
1277 // if no changes were made
1278 _SCErrorSet(kSCStatusOK);
1279 }
1280
1281 return setUpdated;
1282 }