]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkSet.c
configd-210.tar.gz
[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 static CFStringRef
1177 next_service_name(SCNetworkServiceRef service)
1178 {
1179 CFArrayRef components;
1180 CFIndex n;
1181 CFStringRef name;
1182 CFMutableArrayRef newComponents;
1183 SInt32 suffix = 2;
1184
1185 name = SCNetworkServiceGetName(service);
1186 if (name == NULL) {
1187 return NULL;
1188 }
1189
1190 components = CFStringCreateArrayBySeparatingStrings(NULL, name, CFSTR(" "));
1191 if (components != NULL) {
1192 newComponents = CFArrayCreateMutableCopy(NULL, 0, components);
1193 CFRelease(components);
1194 } else {
1195 newComponents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1196 CFArrayAppendValue(newComponents, name);
1197 }
1198
1199 n = CFArrayGetCount(newComponents);
1200 if (n > 1) {
1201 CFStringRef str;
1202
1203 str = CFArrayGetValueAtIndex(newComponents, n - 1);
1204 suffix = CFStringGetIntValue(str);
1205 if (suffix++ > 0) {
1206 CFArrayRemoveValueAtIndex(newComponents, n - 1);
1207 } else {
1208 suffix = 2;
1209 }
1210 }
1211
1212 name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), suffix);
1213 CFArrayAppendValue(newComponents, name);
1214 CFRelease(name);
1215
1216 name = CFStringCreateByCombiningStrings(NULL, newComponents, CFSTR(" "));
1217 CFRelease(newComponents);
1218
1219 return name;
1220 }
1221
1222
1223 static Boolean
1224 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces)
1225 {
1226 CFIndex i;
1227 CFIndex n;
1228 Boolean ok = TRUE;
1229 CFArrayRef services;
1230 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1231 Boolean updated = FALSE;
1232
1233 // first, assume that we only want to add new services
1234 // for those interfaces that are not represented in the
1235 // current set.
1236 services = SCNetworkSetCopyServices(set);
1237 if ((services != NULL) && (CFArrayGetCount(services) > 0)) {
1238 // but, if we are starting off with a non-empty
1239 // set than we only want to add new services for
1240 // those interfaces that are not represented in
1241 // *any* set.
1242 CFRelease(services);
1243 services = SCNetworkServiceCopyAll(setPrivate->prefs);
1244 }
1245
1246 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
1247 for (i = 0; i < n; i++) {
1248 SCNetworkInterfaceRef interface;
1249 CFMutableArrayRef interface_list;
1250
1251 interface = CFArrayGetValueAtIndex(interfaces, i);
1252 if (_SCNetworkServiceExistsForInterface(services, interface)) {
1253 // if this is not a new interface
1254 continue;
1255 }
1256
1257 interface_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1258 CFArrayAppendValue(interface_list, interface);
1259
1260 while (ok && (CFArrayGetCount(interface_list) > 0)) {
1261 CFArrayRef protocol_types;
1262
1263 interface = CFArrayGetValueAtIndex(interface_list, 0);
1264
1265 protocol_types = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
1266 if ((protocol_types != NULL) && (CFArrayGetCount(protocol_types) > 0)) {
1267 SCNetworkServiceRef service;
1268
1269 service = SCNetworkServiceCreate(setPrivate->prefs, interface);
1270 if (service == NULL) {
1271 SCLog(TRUE, LOG_DEBUG,
1272 CFSTR("could not create service for \"%@\": %s\n"),
1273 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1274 SCErrorString(SCError()));
1275 ok = FALSE;
1276 goto nextInterface;
1277 }
1278
1279 ok = SCNetworkServiceEstablishDefaultConfiguration(service);
1280 if (!ok) {
1281 SCLog(TRUE, LOG_DEBUG,
1282 CFSTR("could not estabish default configuration for \"%@\": %s\n"),
1283 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1284 SCErrorString(SCError()));
1285 SCNetworkServiceRemove(service);
1286 CFRelease(service);
1287 goto nextInterface;
1288 }
1289
1290 while (TRUE) {
1291 CFStringRef newName;
1292
1293 ok = SCNetworkSetAddService(set, service);
1294 if (ok) {
1295 break;
1296 }
1297
1298 if (SCError() != kSCStatusKeyExists) {
1299 SCLog(TRUE, LOG_DEBUG,
1300 CFSTR("could not add service for \"%@\": %s\n"),
1301 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1302 SCErrorString(SCError()));
1303 SCNetworkServiceRemove(service);
1304 CFRelease(service);
1305 goto nextInterface;
1306 }
1307
1308 // we have two interfaces with the same service
1309 // name, acquire a new, hopefully unique, name
1310
1311 newName = next_service_name(service);
1312 if (newName == NULL) {
1313 SCLog(TRUE, LOG_DEBUG,
1314 CFSTR("could not set unique name for \"%@\": %s\n"),
1315 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1316 SCErrorString(SCError()));
1317 SCNetworkServiceRemove(service);
1318 CFRelease(service);
1319 goto nextInterface;
1320 }
1321
1322 ok = SCNetworkServiceSetName(service, newName);
1323 CFRelease(newName);
1324 if (ok) {
1325 continue;
1326 }
1327
1328 if (SCError() != kSCStatusKeyExists) {
1329 SCLog(TRUE, LOG_DEBUG,
1330 CFSTR("could not set unique name for \"%@\": %s\n"),
1331 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1332 SCErrorString(SCError()));
1333 SCNetworkServiceRemove(service);
1334 CFRelease(service);
1335 goto nextInterface;
1336 }
1337 }
1338
1339 CFRelease(service);
1340 updated = TRUE;
1341 } else {
1342 add_supported_interfaces(interface_list, interface);
1343 }
1344
1345 nextInterface :
1346
1347 CFArrayRemoveValueAtIndex(interface_list, 0);
1348 }
1349 CFRelease(interface_list);
1350 }
1351 if (services != NULL) CFRelease(services);
1352
1353 if (ok && !updated) {
1354 // if no changes were made
1355 _SCErrorSet(kSCStatusOK);
1356 }
1357
1358 return updated;
1359 }
1360
1361
1362 Boolean
1363 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set)
1364 {
1365 CFArrayRef interfaces;
1366 Boolean updated;
1367
1368 if (!isA_SCNetworkSet(set)) {
1369 _SCErrorSet(kSCStatusInvalidArgument);
1370 return FALSE;
1371 }
1372
1373 interfaces = SCNetworkInterfaceCopyAll();
1374 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
1375 if (interfaces != NULL) CFRelease(interfaces);
1376
1377 return updated;
1378 }
1379
1380
1381 Boolean
1382 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
1383 {
1384 CFMutableArrayRef interfaces;
1385 Boolean updated;
1386
1387 if (!isA_SCNetworkSet(set)) {
1388 _SCErrorSet(kSCStatusInvalidArgument);
1389 return FALSE;
1390 }
1391
1392 if (!isA_SCNetworkInterface(interface)) {
1393 _SCErrorSet(kSCStatusInvalidArgument);
1394 return FALSE;
1395 }
1396
1397 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1398 CFArrayAppendValue(interfaces, interface);
1399 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
1400 CFRelease(interfaces);
1401
1402 return updated;
1403 }