]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkService.c
configd-293.4.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkService.c
1 /*
2 * Copyright (c) 2004-2009 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 __SCNetworkServiceCopyDescription (CFTypeRef cf);
43 static void __SCNetworkServiceDeallocate (CFTypeRef cf);
44 static Boolean __SCNetworkServiceEqual (CFTypeRef cf1, CFTypeRef cf2);
45 static CFHashCode __SCNetworkServiceHash (CFTypeRef cf);
46
47
48 static CFTypeID __kSCNetworkServiceTypeID = _kCFRuntimeNotATypeID;
49
50
51 static const CFRuntimeClass __SCNetworkServiceClass = {
52 0, // version
53 "SCNetworkService", // className
54 NULL, // init
55 NULL, // copy
56 __SCNetworkServiceDeallocate, // dealloc
57 __SCNetworkServiceEqual, // equal
58 __SCNetworkServiceHash, // hash
59 NULL, // copyFormattingDesc
60 __SCNetworkServiceCopyDescription // copyDebugDesc
61 };
62
63
64 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
65
66
67 static CFStringRef
68 __SCNetworkServiceCopyDescription(CFTypeRef cf)
69 {
70 CFAllocatorRef allocator = CFGetAllocator(cf);
71 CFMutableStringRef result;
72 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
73
74 result = CFStringCreateMutable(allocator, 0);
75 CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkService %p [%p]> {"), cf, allocator);
76 CFStringAppendFormat(result, NULL, CFSTR("id = %@"), servicePrivate->serviceID);
77 if (servicePrivate->prefs != NULL) {
78 CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), servicePrivate->prefs);
79 } else if (servicePrivate->store != NULL) {
80 CFStringAppendFormat(result, NULL, CFSTR(", store = %p"), servicePrivate->store);
81 }
82 if (servicePrivate->name != NULL) {
83 CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), servicePrivate->name);
84 }
85 CFStringAppendFormat(result, NULL, CFSTR("}"));
86
87 return result;
88 }
89
90
91 static void
92 __SCNetworkServiceDeallocate(CFTypeRef cf)
93 {
94 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
95
96 /* release resources */
97
98 CFRelease(servicePrivate->serviceID);
99 if (servicePrivate->interface != NULL) CFRelease(servicePrivate->interface);
100 if (servicePrivate->prefs != NULL) CFRelease(servicePrivate->prefs);
101 if (servicePrivate->store != NULL) CFRelease(servicePrivate->store);
102 if (servicePrivate->name != NULL) CFRelease(servicePrivate->name);
103
104 return;
105 }
106
107
108 static Boolean
109 __SCNetworkServiceEqual(CFTypeRef cf1, CFTypeRef cf2)
110 {
111 SCNetworkServicePrivateRef s1 = (SCNetworkServicePrivateRef)cf1;
112 SCNetworkServicePrivateRef s2 = (SCNetworkServicePrivateRef)cf2;
113
114 if (s1 == s2)
115 return TRUE;
116
117 if (s1->prefs != s2->prefs)
118 return FALSE; // if not the same prefs
119
120 if (!CFEqual(s1->serviceID, s2->serviceID))
121 return FALSE; // if not the same service identifier
122
123 return TRUE;
124 }
125
126
127 static CFHashCode
128 __SCNetworkServiceHash(CFTypeRef cf)
129 {
130 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
131
132 return CFHash(servicePrivate->serviceID);
133 }
134
135
136 static void
137 __SCNetworkServiceInitialize(void)
138 {
139 __kSCNetworkServiceTypeID = _CFRuntimeRegisterClass(&__SCNetworkServiceClass);
140 return;
141 }
142
143
144 __private_extern__ SCNetworkServicePrivateRef
145 __SCNetworkServiceCreatePrivate(CFAllocatorRef allocator,
146 SCPreferencesRef prefs,
147 CFStringRef serviceID,
148 SCNetworkInterfaceRef interface)
149 {
150 SCNetworkServicePrivateRef servicePrivate;
151 uint32_t size;
152
153 /* initialize runtime */
154 pthread_once(&initialized, __SCNetworkServiceInitialize);
155
156 /* allocate target */
157 size = sizeof(SCNetworkServicePrivate) - sizeof(CFRuntimeBase);
158 servicePrivate = (SCNetworkServicePrivateRef)_CFRuntimeCreateInstance(allocator,
159 __kSCNetworkServiceTypeID,
160 size,
161 NULL);
162 if (servicePrivate == NULL) {
163 return NULL;
164 }
165
166 servicePrivate->prefs = (prefs != NULL) ? CFRetain(prefs): NULL;
167 servicePrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
168 servicePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL;
169 servicePrivate->name = NULL;
170
171 return servicePrivate;
172 }
173
174
175 #pragma mark -
176 #pragma mark SCNetworkService APIs
177
178
179 #define N_QUICK 64
180
181
182 static CFDictionaryRef
183 _protocolTemplate(SCNetworkServiceRef service, CFStringRef protocolType)
184 {
185 CFDictionaryRef newEntity = NULL;
186 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
187
188 if (servicePrivate->interface != NULL) {
189 SCNetworkInterfaceRef childInterface;
190 CFStringRef childInterfaceType = NULL;
191 CFStringRef interfaceType;
192
193 interfaceType = SCNetworkInterfaceGetInterfaceType(servicePrivate->interface);
194 childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface);
195 if (childInterface != NULL) {
196 childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
197 }
198
199 newEntity = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType);
200 }
201
202 if (newEntity == NULL) {
203 newEntity = CFDictionaryCreate(NULL,
204 NULL,
205 NULL,
206 0,
207 &kCFTypeDictionaryKeyCallBacks,
208 &kCFTypeDictionaryValueCallBacks);
209 }
210
211 return newEntity;
212 }
213
214
215 Boolean
216 SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
217 {
218 CFDictionaryRef entity;
219 CFDictionaryRef newEntity = NULL;
220 Boolean ok = FALSE;
221 CFStringRef path;
222 SCNetworkProtocolRef protocol;
223 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
224
225 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
226 _SCErrorSet(kSCStatusInvalidArgument);
227 return FALSE;
228 }
229
230 if (!__SCNetworkProtocolIsValidType(protocolType)) {
231 _SCErrorSet(kSCStatusInvalidArgument);
232 return FALSE;
233 }
234
235 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
236 servicePrivate->serviceID, // service
237 protocolType); // entity
238
239 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
240 if (entity != NULL) {
241 // if "protocol" already exists
242 _SCErrorSet(kSCStatusKeyExists);
243 goto done;
244 }
245
246 newEntity = CFDictionaryCreate(NULL,
247 NULL,
248 NULL,
249 0,
250 &kCFTypeDictionaryKeyCallBacks,
251 &kCFTypeDictionaryValueCallBacks);
252 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
253 CFRelease(newEntity);
254 if (!ok) {
255 goto done;
256 }
257
258 protocol = SCNetworkServiceCopyProtocol(service, protocolType);
259 newEntity = _protocolTemplate(service, protocolType);
260 ok = SCNetworkProtocolSetConfiguration(protocol, newEntity);
261 CFRelease(newEntity);
262 CFRelease(protocol);
263
264 done :
265
266 CFRelease(path);
267 return ok;
268 }
269
270
271 CFArrayRef /* of SCNetworkServiceRef's */
272 SCNetworkServiceCopyAll(SCPreferencesRef prefs)
273 {
274 CFMutableArrayRef array;
275 CFIndex n;
276 CFStringRef path;
277 CFDictionaryRef services;
278
279 path = SCPreferencesPathKeyCreateNetworkServices(NULL);
280 services = SCPreferencesPathGetValue(prefs, path);
281 CFRelease(path);
282
283 if ((services != NULL) && !isA_CFDictionary(services)) {
284 return NULL;
285 }
286
287 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
288
289 n = (services != NULL) ? CFDictionaryGetCount(services) : 0;
290 if (n > 0) {
291 CFIndex i;
292 const void * keys_q[N_QUICK];
293 const void ** keys = keys_q;
294 const void * vals_q[N_QUICK];
295 const void ** vals = vals_q;
296
297 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
298 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
299 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
300 }
301 CFDictionaryGetKeysAndValues(services, keys, vals);
302 for (i = 0; i < n; i++) {
303 CFDictionaryRef entity;
304 SCNetworkServicePrivateRef servicePrivate;
305
306 if (!isA_CFDictionary(vals[i])) {
307 SCLog(TRUE,
308 LOG_INFO,
309 CFSTR("SCNetworkServiceCopyAll(): error w/service \"%@\"\n"),
310 keys[i]);
311 continue;
312 }
313
314 entity = CFDictionaryGetValue(vals[i], kSCEntNetInterface);
315 if (!isA_CFDictionary(entity)) {
316 // if no "interface"
317 SCLog(TRUE,
318 LOG_INFO,
319 CFSTR("SCNetworkServiceCopyAll(): no \"%@\" entity for service \"%@\"\n"),
320 kSCEntNetInterface,
321 keys[i]);
322 continue;
323 }
324
325 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, keys[i], NULL);
326 CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
327 CFRelease(servicePrivate);
328 }
329 if (keys != keys_q) {
330 CFAllocatorDeallocate(NULL, keys);
331 CFAllocatorDeallocate(NULL, vals);
332 }
333 }
334
335 return array;
336 }
337
338
339 /*
340 * build a list of all of a servives entity types that are associated
341 * with the services interface. The list will include :
342 *
343 * - entity types associated with the interface type (Ethernet, FireWire, PPP, ...)
344 * - entity types associated with the interface sub-type (PPPSerial, PPPoE, L2TP, PPTP, ...)
345 * - entity types associated with the hardware device (Ethernet, AirPort, FireWire, Modem, ...)
346 */
347 static CFSetRef
348 _copyInterfaceEntityTypes(CFDictionaryRef protocols)
349 {
350 CFDictionaryRef interface;
351 CFMutableSetRef interface_entity_types;
352
353 interface_entity_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
354
355 interface = CFDictionaryGetValue(protocols, kSCEntNetInterface);
356 if (isA_CFDictionary(interface)) {
357 CFStringRef entities[] = { kSCPropNetInterfaceType,
358 kSCPropNetInterfaceSubType,
359 kSCPropNetInterfaceHardware };
360 int i;
361
362 // include the "Interface" entity itself
363 CFSetAddValue(interface_entity_types, kSCEntNetInterface);
364
365 // include the entities associated with the interface
366 for (i = 0; i < sizeof(entities)/sizeof(entities[0]); i++) {
367 CFStringRef entity;
368
369 entity = CFDictionaryGetValue(interface, entities[i]);
370 if (isA_CFString(entity)) {
371 CFSetAddValue(interface_entity_types, entity);
372 }
373 }
374
375 /*
376 * and, because we've found some misguided network preference code
377 * developers leaving [PPP] entity dictionaries around even though
378 * they are unused and/or unneeded...
379 */
380 CFSetAddValue(interface_entity_types, kSCEntNetPPP);
381 }
382
383 return interface_entity_types;
384 }
385
386
387 SCNetworkServiceRef
388 SCNetworkServiceCopy(SCPreferencesRef prefs, CFStringRef serviceID)
389 {
390 CFDictionaryRef entity;
391 CFStringRef path;
392 SCNetworkServicePrivateRef servicePrivate;
393
394 if (!isA_CFString(serviceID)) {
395 _SCErrorSet(kSCStatusInvalidArgument);
396 return NULL;
397 }
398
399 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
400 serviceID, // service
401 kSCEntNetInterface); // entity
402 entity = SCPreferencesPathGetValue(prefs, path);
403 CFRelease(path);
404
405 if (!isA_CFDictionary(entity)) {
406 // a "service" must have an "interface"
407 _SCErrorSet(kSCStatusNoKey);
408 return NULL;
409 }
410
411 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
412 return (SCNetworkServiceRef)servicePrivate;
413 }
414
415
416 SCNetworkServiceRef
417 _SCNetworkServiceCopyActive(SCDynamicStoreRef store, CFStringRef serviceID)
418 {
419 SCNetworkServicePrivateRef servicePrivate;
420
421 if (!isA_CFString(serviceID)) {
422 _SCErrorSet(kSCStatusInvalidArgument);
423 return NULL;
424 }
425
426 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, NULL, serviceID, NULL);
427 if (store != NULL) {
428 servicePrivate->store = CFRetain(store);
429 }
430 return (SCNetworkServiceRef)servicePrivate;
431 }
432
433
434 SCNetworkProtocolRef
435 SCNetworkServiceCopyProtocol(SCNetworkServiceRef service, CFStringRef protocolType)
436 {
437 CFSetRef non_protocol_entities;
438 CFStringRef path;
439 CFDictionaryRef protocols;
440 SCNetworkProtocolPrivateRef protocolPrivate = NULL;
441 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
442
443 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
444 _SCErrorSet(kSCStatusInvalidArgument);
445 return NULL;
446 }
447
448 if (!isA_CFString(protocolType)) {
449 _SCErrorSet(kSCStatusInvalidArgument);
450 return NULL;
451 }
452
453 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
454 servicePrivate->serviceID, // service
455 NULL); // entity
456 protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
457 CFRelease(path);
458
459 if (!isA_CFDictionary(protocols)) {
460 // if corrupt prefs
461 _SCErrorSet(kSCStatusFailed);
462 return NULL;
463 }
464
465 non_protocol_entities = _copyInterfaceEntityTypes(protocols);
466 if (CFSetContainsValue(non_protocol_entities, protocolType)) {
467 // if the "protocolType" matches an interface entity type
468 _SCErrorSet(kSCStatusInvalidArgument);
469 goto done;
470 }
471
472 if (!CFDictionaryContainsKey(protocols, protocolType)) {
473 // if the "protocolType" entity does not exist
474 _SCErrorSet(kSCStatusNoKey);
475 goto done;
476 }
477
478 protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, protocolType, service);
479
480 done :
481
482 CFRelease(non_protocol_entities);
483
484 return (SCNetworkProtocolRef)protocolPrivate;
485 }
486
487
488 CFArrayRef /* of SCNetworkProtocolRef's */
489 SCNetworkServiceCopyProtocols(SCNetworkServiceRef service)
490 {
491 CFMutableArrayRef array;
492 CFIndex n;
493 CFSetRef non_protocol_entities;
494 CFStringRef path;
495 CFDictionaryRef protocols;
496 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
497
498 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
499 _SCErrorSet(kSCStatusInvalidArgument);
500 return NULL;
501 }
502
503 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
504 servicePrivate->serviceID, // service
505 NULL); // entity
506 protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
507 CFRelease(path);
508
509 if (!isA_CFDictionary(protocols)) {
510 // if corrupt prefs
511 _SCErrorSet(kSCStatusFailed);
512 return NULL;
513 }
514
515 non_protocol_entities = _copyInterfaceEntityTypes(protocols);
516
517 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
518
519 n = CFDictionaryGetCount(protocols);
520 if (n > 0) {
521 CFIndex i;
522 const void * keys_q[N_QUICK];
523 const void ** keys = keys_q;
524 const void * vals_q[N_QUICK];
525 const void ** vals = vals_q;
526
527 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
528 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
529 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
530 }
531 CFDictionaryGetKeysAndValues(protocols, keys, vals);
532 for (i = 0; i < n; i++) {
533 SCNetworkProtocolPrivateRef protocolPrivate;
534
535 if (!isA_CFDictionary(vals[i])) {
536 // if it's not a dictionary then it can't be a protocol entity
537 continue;
538 }
539
540 if (CFSetContainsValue(non_protocol_entities, keys[i])) {
541 // skip any non-protocol (interface) entities
542 continue;
543 }
544
545 protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, keys[i], service);
546 CFArrayAppendValue(array, (SCNetworkProtocolRef)protocolPrivate);
547
548 CFRelease(protocolPrivate);
549 }
550 if (keys != keys_q) {
551 CFAllocatorDeallocate(NULL, keys);
552 CFAllocatorDeallocate(NULL, vals);
553 }
554 }
555
556 CFRelease(non_protocol_entities);
557
558 return array;
559 }
560
561
562 static Boolean
563 __SCNetworkServiceSetInterfaceEntity(SCNetworkServiceRef service,
564 SCNetworkInterfaceRef interface)
565 {
566 CFDictionaryRef entity;
567 Boolean ok;
568 CFStringRef path;
569 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
570
571 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
572 servicePrivate->serviceID, // service
573 kSCEntNetInterface); // entity
574 entity = __SCNetworkInterfaceCopyInterfaceEntity(interface);
575 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, entity);
576 CFRelease(entity);
577 CFRelease(path);
578
579 return ok;
580 }
581
582
583 static void
584 mergeDict(const void *key, const void *value, void *context)
585 {
586 CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context;
587
588 CFDictionarySetValue(newDict, key, value);
589 return;
590 }
591
592
593 SCNetworkServiceRef
594 SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface)
595 {
596 CFArrayRef components;
597 CFArrayRef interface_config;
598 CFStringRef interface_name;
599 SCNetworkInterfaceRef newInterface;
600 CFStringRef path;
601 CFStringRef prefix;
602 CFStringRef serviceID;
603 SCNetworkServicePrivateRef servicePrivate;
604 CFArrayRef supported_protocols;
605
606 if (!isA_SCNetworkInterface(interface)) {
607 _SCErrorSet(kSCStatusInvalidArgument);
608 return NULL;
609 }
610
611 // only allow network interfaces which support one or more protocols
612 // to be added to a service. The one exception is that we allow
613 // third-party interface types to be configured.
614 supported_protocols = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
615 if (supported_protocols == NULL) {
616 CFStringRef interface_type;
617
618 interface_type = SCNetworkInterfaceGetInterfaceType(interface);
619 if (CFStringFind(interface_type, CFSTR("."), 0).location == kCFNotFound) {
620 return NULL;
621 }
622 }
623
624 // establish the service
625 prefix = SCPreferencesPathKeyCreateNetworkServices(NULL);
626 path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
627 if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
628 CFRelease(prefix);
629 if (path == NULL) {
630 return NULL;
631 }
632
633 components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
634 CFRelease(path);
635
636 serviceID = CFArrayGetValueAtIndex(components, 2);
637 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
638 CFRelease(components);
639
640 // duplicate the interface and associate the copy with the new service
641 newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL,
642 interface,
643 prefs,
644 serviceID);
645 servicePrivate->interface = newInterface;
646
647 // establish "default" configuration(s) for the interface
648 for (interface = newInterface;
649 interface != NULL;
650 interface = SCNetworkInterfaceGetInterface(interface)) {
651 SCNetworkInterfaceRef childInterface;
652 CFStringRef childInterfaceType = NULL;
653 CFDictionaryRef config;
654 CFStringRef interfaceType;
655
656 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
657 childInterface = SCNetworkInterfaceGetInterface(interface);
658 if (childInterface != NULL) {
659 childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
660 }
661
662 config = __copyInterfaceTemplate(interfaceType, childInterfaceType);
663 if (config != NULL) {
664 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBluetooth) ||
665 CFEqual(interfaceType, kSCNetworkInterfaceTypeIrDA ) ||
666 CFEqual(interfaceType, kSCNetworkInterfaceTypeModem ) ||
667 CFEqual(interfaceType, kSCNetworkInterfaceTypeSerial ) ||
668 CFEqual(interfaceType, kSCNetworkInterfaceTypeWWAN )) {
669 CFDictionaryRef overrides;
670
671 overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypeModem);
672
673 // a ConnectionScript (and related keys) from the interface
674 // should trump the settings from the configuration template.
675 if ((overrides != NULL) &&
676 CFDictionaryContainsKey(overrides, kSCPropNetModemConnectionScript)) {
677 CFMutableDictionaryRef newConfig;
678
679 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
680 CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionPersonality);
681 CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionScript);
682 CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceVendor);
683 CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceModel);
684 CFRelease(config);
685 config = newConfig;
686 }
687
688 if (overrides != NULL) {
689 CFMutableDictionaryRef newConfig;
690
691 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
692 CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
693 CFRelease(config);
694 config = newConfig;
695 }
696 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
697 CFDictionaryRef overrides;
698
699 overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypePPP);
700 if (overrides != NULL) {
701 CFMutableDictionaryRef newConfig;
702
703 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
704 CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
705 CFRelease(config);
706 config = newConfig;
707 }
708 }
709
710 if (!__SCNetworkInterfaceSetConfiguration(interface, NULL, config, TRUE)) {
711 SCLog(TRUE, LOG_DEBUG,
712 CFSTR("SCNetworkService __SCNetworkInterfaceSetConfiguration failed(), interface=%@, type=NULL"),
713 interface);
714 }
715 CFRelease(config);
716 }
717 }
718
719 // add the interface [entity] to the service
720 (void) __SCNetworkServiceSetInterfaceEntity((SCNetworkServiceRef)servicePrivate,
721 servicePrivate->interface);
722
723 // push the [deep] interface configuration into the service.
724 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(NULL, servicePrivate->interface);
725 __SCNetworkInterfaceSetDeepConfiguration(NULL, servicePrivate->interface, interface_config);
726 if (interface_config != NULL) CFRelease(interface_config);
727
728 // set the service name to match that of the associated interface
729 //
730 // Note: It might seem a bit odd to call SCNetworkServiceGetName
731 // followed by an immediate call to SCNetworkServiceSetName. The
732 // trick here is that if no name has previously been set, the
733 // "get" function will return the name of the associated interface.
734 //
735 // ... and we "set" a name to ensure that applications that do
736 // not use the APIs will still find a UserDefinedName property
737 // in the SCDynamicStore.
738 //
739 interface_name = SCNetworkServiceGetName((SCNetworkServiceRef)servicePrivate);
740 if (interface_name != NULL) {
741 (void) SCNetworkServiceSetName((SCNetworkServiceRef)servicePrivate,
742 interface_name);
743 }
744
745 return (SCNetworkServiceRef)servicePrivate;
746 }
747
748
749 Boolean
750 SCNetworkServiceEstablishDefaultConfiguration(SCNetworkServiceRef service)
751 {
752 CFIndex i;
753 SCNetworkInterfaceRef interface;
754 CFIndex n;
755 CFArrayRef protocolTypes;
756 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
757
758 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
759 _SCErrorSet(kSCStatusInvalidArgument);
760 return FALSE;
761 }
762
763 interface = SCNetworkServiceGetInterface(service);
764 if (interface == NULL) {
765 return FALSE;
766 }
767
768 protocolTypes = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
769 n = (protocolTypes != NULL) ? CFArrayGetCount(protocolTypes) : 0;
770 for (i = 0; i < n; i++) {
771 Boolean enabled;
772 CFDictionaryRef newEntity = NULL;
773 Boolean ok;
774 SCNetworkProtocolRef protocol = NULL;
775 CFStringRef protocolType;
776
777 protocolType = CFArrayGetValueAtIndex(protocolTypes, i);
778 ok = SCNetworkServiceAddProtocolType(service, protocolType);
779 if (!ok && (SCError() != kSCStatusKeyExists)) {
780 // could not add protocol
781 goto nextProtocol;
782 }
783
784 protocol = SCNetworkServiceCopyProtocol(service, protocolType);
785 if (protocol == NULL) {
786 // oops, somethings wrong (should never happen)
787 goto nextProtocol;
788 }
789
790 newEntity = _protocolTemplate(service, protocolType);
791 ok = SCNetworkProtocolSetConfiguration(protocol, newEntity);
792 if (!ok) {
793 // could not set default configuration
794 goto nextProtocol;
795 }
796
797 enabled = !CFDictionaryContainsKey(newEntity, kSCResvInactive);
798 ok = SCNetworkProtocolSetEnabled(protocol, enabled);
799 if (!ok) {
800 // could not enable/disable protocol
801 goto nextProtocol;
802 }
803
804 nextProtocol :
805
806 if (newEntity != NULL) CFRelease(newEntity);
807 if (protocol != NULL) CFRelease(protocol);
808 }
809
810 return TRUE;
811 }
812
813
814 Boolean
815 SCNetworkServiceGetEnabled(SCNetworkServiceRef service)
816 {
817 Boolean enabled;
818 CFStringRef path;
819 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
820
821 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
822 _SCErrorSet(kSCStatusInvalidArgument);
823 return FALSE;
824 }
825
826 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
827 servicePrivate->serviceID, // service
828 NULL); // entity
829 enabled = __getPrefsEnabled(servicePrivate->prefs, path);
830 CFRelease(path);
831
832 return enabled;
833 }
834
835
836 SCNetworkInterfaceRef
837 SCNetworkServiceGetInterface(SCNetworkServiceRef service)
838 {
839 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
840
841 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
842 _SCErrorSet(kSCStatusInvalidArgument);
843 return NULL;
844 }
845
846 if (servicePrivate->interface == NULL) {
847 CFDictionaryRef entity;
848 CFStringRef path;
849
850 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
851 servicePrivate->serviceID, // service
852 kSCEntNetInterface); // entity
853 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
854 CFRelease(path);
855
856 if (isA_CFDictionary(entity)) {
857 servicePrivate->interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, service);
858 }
859 }
860
861 return servicePrivate->interface;
862 }
863
864
865 CFStringRef
866 SCNetworkServiceGetName(SCNetworkServiceRef service)
867 {
868 CFDictionaryRef entity;
869 SCNetworkInterfaceRef interface;
870 CFStringRef name = NULL;
871 CFStringRef path;
872 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
873
874 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
875 _SCErrorSet(kSCStatusInvalidArgument);
876 return NULL;
877 }
878
879 if (servicePrivate->name != NULL) {
880 return servicePrivate->name;
881 }
882
883 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
884 servicePrivate->serviceID, // service
885 NULL); // entity
886 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
887 CFRelease(path);
888
889 if (isA_CFDictionary(entity)) {
890 name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
891 if (isA_CFString(name)) {
892 servicePrivate->name = CFRetain(name);
893 }
894 }
895
896 interface = SCNetworkServiceGetInterface(service);
897 while (interface != NULL) {
898 SCNetworkInterfaceRef childInterface;
899
900 childInterface = SCNetworkInterfaceGetInterface(interface);
901 if ((childInterface == NULL) || CFEqual(childInterface, kSCNetworkInterfaceIPv4)) {
902 break;
903 }
904
905 interface = childInterface;
906 }
907
908 if (interface != NULL) {
909 int i;
910 CFStringRef interface_name = NULL;
911 CFStringRef suffix = NULL;
912
913 //
914 // check if the [stored] service name matches the non-localized interface
915 // name. If so, return the localized name.
916 //
917 // Also, the older "Built-in XXX" interface names are too long for the
918 // current UI. If we find that the [stored] service name matches the older
919 // name, return the newer (and shorter) localized name.
920 //
921 // Note: the user/admin will no longer be able to set the service name
922 // to "Built-in Ethernet".
923 //
924 for (i = 0; i < 3; i++) {
925 if (servicePrivate->name == NULL) {
926 // if no [stored] service name to compare
927 break;
928 }
929
930 switch (i) {
931 case 0 :
932 // compare the non-localized interface name
933 interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
934 if (interface_name != NULL) {
935 CFRetain(interface_name);
936 }
937 break;
938 case 1 :
939 // compare the older "Built-in XXX" localized name
940 interface_name = __SCNetworkInterfaceCopyXLocalizedDisplayName(interface);
941 break;
942 case 2 :
943 // compare the older "Built-in XXX" non-localized name
944 interface_name = __SCNetworkInterfaceCopyXNonLocalizedDisplayName(interface);
945 break;
946 }
947
948 if (interface_name != NULL) {
949 Boolean match = FALSE;
950
951 if (CFEqual(name, interface_name)) {
952 // if service name matches the OLD localized
953 // interface name
954 match = TRUE;
955 } else if (CFStringHasPrefix(name, interface_name)) {
956 CFIndex prefixLen = CFStringGetLength(interface_name);
957 CFIndex suffixLen = CFStringGetLength(name);
958
959 suffix = CFStringCreateWithSubstring(NULL,
960 name,
961 CFRangeMake(prefixLen, suffixLen - prefixLen));
962 match = TRUE;
963 }
964 CFRelease(interface_name);
965
966 if (match) {
967 CFRelease(servicePrivate->name);
968 servicePrivate->name = NULL;
969 break;
970 }
971 }
972 }
973
974 //
975 // if the service name has not been set, use the localized interface name
976 //
977 if (servicePrivate->name == NULL) {
978 interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
979 if (interface_name != NULL) {
980 if (suffix != NULL) {
981 servicePrivate->name = CFStringCreateWithFormat(NULL,
982 NULL,
983 CFSTR("%@%@"),
984 interface_name,
985 suffix);
986 } else {
987 servicePrivate->name = CFRetain(interface_name);
988 }
989 }
990 }
991 if (suffix != NULL) CFRelease(suffix);
992 }
993
994 return servicePrivate->name;
995 }
996
997
998 CFStringRef
999 SCNetworkServiceGetServiceID(SCNetworkServiceRef service)
1000 {
1001 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1002
1003 if (!isA_SCNetworkService(service)) {
1004 _SCErrorSet(kSCStatusInvalidArgument);
1005 return NULL;
1006 }
1007
1008 return servicePrivate->serviceID;
1009 }
1010
1011
1012 CFTypeID
1013 SCNetworkServiceGetTypeID(void)
1014 {
1015 pthread_once(&initialized, __SCNetworkServiceInitialize); /* initialize runtime */
1016 return __kSCNetworkServiceTypeID;
1017 }
1018
1019
1020 Boolean
1021 SCNetworkServiceRemove(SCNetworkServiceRef service)
1022 {
1023 Boolean ok = FALSE;
1024 CFStringRef path;
1025 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1026 CFArrayRef sets;
1027
1028 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1029 _SCErrorSet(kSCStatusInvalidArgument);
1030 return FALSE;
1031 }
1032
1033 // remove service from all sets
1034
1035 sets = SCNetworkSetCopyAll(servicePrivate->prefs);
1036 if (sets != NULL) {
1037 CFIndex i;
1038 CFIndex n;
1039
1040 n = CFArrayGetCount(sets);
1041 for (i = 0; i < n; i++) {
1042 SCNetworkSetRef set;
1043
1044 set = CFArrayGetValueAtIndex(sets, i);
1045 ok = SCNetworkSetRemoveService(set, service);
1046 if (!ok && (SCError() != kSCStatusNoKey)) {
1047 CFRelease(sets);
1048 return ok;
1049 }
1050 }
1051 CFRelease(sets);
1052 }
1053
1054 // remove service
1055
1056 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1057 servicePrivate->serviceID, // service
1058 NULL); // entity
1059 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
1060 CFRelease(path);
1061
1062 return ok;
1063 }
1064
1065
1066 Boolean
1067 SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
1068 {
1069 CFDictionaryRef entity;
1070 Boolean ok = FALSE;
1071 CFStringRef path;
1072 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1073
1074 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1075 _SCErrorSet(kSCStatusInvalidArgument);
1076 return FALSE;
1077 }
1078
1079 if (!__SCNetworkProtocolIsValidType(protocolType)) {
1080 _SCErrorSet(kSCStatusInvalidArgument);
1081 return FALSE;
1082 }
1083
1084 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1085 servicePrivate->serviceID, // service
1086 protocolType); // entity
1087
1088 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1089 if (entity == NULL) {
1090 // if "protocol" does not exist
1091 _SCErrorSet(kSCStatusNoKey);
1092 goto done;
1093 }
1094
1095 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
1096
1097 done :
1098
1099 CFRelease(path);
1100 return ok;
1101 }
1102
1103
1104 Boolean
1105 SCNetworkServiceSetEnabled(SCNetworkServiceRef service, Boolean enabled)
1106 {
1107 Boolean ok;
1108 CFStringRef path;
1109 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1110
1111 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1112 _SCErrorSet(kSCStatusInvalidArgument);
1113 return FALSE;
1114 }
1115
1116 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1117 servicePrivate->serviceID, // service
1118 NULL); // entity
1119 ok = __setPrefsEnabled(servicePrivate->prefs, path, enabled);
1120 CFRelease(path);
1121
1122 return ok;
1123 }
1124
1125
1126 Boolean
1127 SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name)
1128 {
1129 CFDictionaryRef entity;
1130 Boolean ok = FALSE;
1131 CFStringRef path;
1132 CFStringRef saveName = NULL;
1133 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1134
1135 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1136 _SCErrorSet(kSCStatusInvalidArgument);
1137 return FALSE;
1138 }
1139
1140 if (name != NULL) {
1141 if (!isA_CFString(name)) {
1142 _SCErrorSet(kSCStatusInvalidArgument);
1143 return FALSE;
1144 }
1145 saveName = CFRetain(name);
1146 }
1147
1148 if (name != NULL) {
1149 SCNetworkInterfaceRef interface;
1150
1151 interface = SCNetworkServiceGetInterface(service);
1152 while (interface != NULL) {
1153 SCNetworkInterfaceRef childInterface;
1154
1155 childInterface = SCNetworkInterfaceGetInterface(interface);
1156 if (childInterface == NULL) {
1157 break;
1158 }
1159
1160 interface = childInterface;
1161 }
1162
1163 if (interface != NULL) {
1164 CFStringRef interface_name;
1165
1166 interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
1167 if (interface_name != NULL) {
1168 if (CFEqual(name, interface_name)) {
1169 // if service name matches the localized interface name
1170 // then store the non-localized name.
1171 interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
1172 if (interface_name != NULL) {
1173 CFRelease(saveName);
1174 saveName = CFRetain(interface_name);
1175 }
1176 } else if (CFStringHasPrefix(name, interface_name)) {
1177 CFIndex prefixLen = CFStringGetLength(interface_name);
1178 CFStringRef suffix;
1179 CFIndex suffixLen = CFStringGetLength(name);
1180
1181 // if service name matches the localized interface name plus
1182 // a few extra characters) then store the non-localized name with
1183 // the same suffix.
1184 suffix = CFStringCreateWithSubstring(NULL,
1185 name,
1186 CFRangeMake(prefixLen, suffixLen - prefixLen));
1187 interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
1188 if (interface_name != NULL) {
1189 CFRelease(saveName);
1190 saveName = CFStringCreateWithFormat(NULL,
1191 NULL,
1192 CFSTR("%@%@"),
1193 interface_name,
1194 suffix);
1195 }
1196 CFRelease(suffix);
1197 }
1198 }
1199 }
1200 }
1201
1202 #define PREVENT_DUPLICATE_SERVICE_NAMES
1203 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
1204 if (name != NULL) {
1205 CFArrayRef sets;
1206
1207 // ensure that each service is uniquely named within its sets
1208
1209 sets = SCNetworkSetCopyAll(servicePrivate->prefs);
1210 if (sets != NULL) {
1211 CFIndex set_index;
1212 CFIndex set_count;
1213
1214 set_count = CFArrayGetCount(sets);
1215 for (set_index = 0; set_index < set_count; set_index++) {
1216 CFIndex service_index;
1217 Boolean isDup = FALSE;
1218 Boolean isMember = FALSE;
1219 CFIndex service_count;
1220 CFArrayRef services;
1221 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, set_index);
1222
1223 services = SCNetworkSetCopyServices(set);
1224
1225 service_count = CFArrayGetCount(services);
1226 for (service_index = 0; service_index < service_count; service_index++) {
1227 CFStringRef otherID;
1228 CFStringRef otherName;
1229 SCNetworkServiceRef otherService;
1230
1231 otherService = CFArrayGetValueAtIndex(services, service_index);
1232
1233 otherID = SCNetworkServiceGetServiceID(otherService);
1234 if (CFEqual(servicePrivate->serviceID, otherID)) {
1235 // if the service is a member of this set
1236 isMember = TRUE;
1237 continue;
1238 }
1239
1240 otherName = SCNetworkServiceGetName(otherService);
1241 if ((otherName != NULL) && CFEqual(name, otherName)) {
1242 isDup = TRUE;
1243 continue;
1244 }
1245 }
1246
1247 CFRelease(services);
1248
1249 if (isMember && isDup) {
1250 /*
1251 * if this service is a member of the set and
1252 * the "name" is not unique.
1253 */
1254 CFRelease(sets);
1255 if (saveName != NULL) CFRelease(saveName);
1256 _SCErrorSet(kSCStatusKeyExists);
1257 return FALSE;
1258 }
1259 }
1260
1261 CFRelease(sets);
1262 }
1263 }
1264 #endif /* PREVENT_DUPLICATE_SERVICE_NAMES */
1265
1266 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1267 servicePrivate->serviceID, // service
1268 NULL); // entity
1269 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1270 if (isA_CFDictionary(entity) ||
1271 ((entity == NULL) && (name != NULL))) {
1272 CFMutableDictionaryRef newEntity;
1273
1274 if (entity != NULL) {
1275 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1276 } else {
1277 newEntity = CFDictionaryCreateMutable(NULL,
1278 0,
1279 &kCFTypeDictionaryKeyCallBacks,
1280 &kCFTypeDictionaryValueCallBacks);
1281 }
1282 if (saveName != NULL) {
1283 CFDictionarySetValue(newEntity, kSCPropUserDefinedName, saveName);
1284 } else {
1285 CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
1286 }
1287 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
1288 CFRelease(newEntity);
1289 }
1290 CFRelease(path);
1291 if (saveName != NULL) CFRelease(saveName);
1292
1293 if (servicePrivate->name != NULL) CFRelease(servicePrivate->name);
1294 if (name != NULL) CFRetain(name);
1295 servicePrivate->name = name;
1296
1297 return ok;
1298 }
1299
1300
1301 #pragma mark -
1302 #pragma mark SCNetworkService SPIs
1303
1304
1305 static Boolean
1306 str_to_rank(CFStringRef rankStr, SCNetworkServicePrimaryRank *rank)
1307 {
1308 if (isA_CFString(rankStr)) {
1309 if (CFEqual(rankStr, kSCValNetServicePrimaryRankFirst)) {
1310 *rank = kSCNetworkServicePrimaryRankFirst;
1311 } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankLast)) {
1312 *rank = kSCNetworkServicePrimaryRankLast;
1313 } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankNever)) {
1314 *rank = kSCNetworkServicePrimaryRankNever;
1315 } else {
1316 return FALSE;
1317 }
1318 } else if (rankStr == NULL) {
1319 *rank = kSCNetworkServicePrimaryRankDefault;
1320 } else {
1321 return FALSE;
1322 }
1323
1324 return TRUE;
1325 }
1326
1327
1328 SCNetworkServicePrimaryRank
1329 SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service)
1330 {
1331 CFDictionaryRef entity;
1332 Boolean ok = TRUE;
1333 CFStringRef path;
1334 SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault;
1335 CFStringRef rankStr = NULL;
1336 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1337
1338 if (!isA_SCNetworkService(service)) {
1339 _SCErrorSet(kSCStatusInvalidArgument);
1340 return rank;
1341 }
1342
1343 if (servicePrivate->prefs != NULL) {
1344 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
1345 servicePrivate->serviceID,
1346 NULL);
1347 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1348 CFRelease(path);
1349 if (isA_CFDictionary(entity)) {
1350 rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
1351 ok = str_to_rank(rankStr, &rank);
1352 }
1353 } else if (servicePrivate->store != NULL) {
1354 path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1355 kSCDynamicStoreDomainState,
1356 servicePrivate->serviceID,
1357 NULL);
1358 entity = SCDynamicStoreCopyValue(servicePrivate->store, path);
1359 CFRelease(path);
1360 if (entity != NULL) {
1361 if (isA_CFDictionary(entity)) {
1362 rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
1363 ok = str_to_rank(rankStr, &rank);
1364 }
1365 CFRelease(entity);
1366 }
1367 } else {
1368 _SCErrorSet(kSCStatusInvalidArgument);
1369 return rank;
1370 }
1371
1372 if (!ok) {
1373 rank = kSCNetworkServicePrimaryRankDefault;
1374 _SCErrorSet(kSCStatusInvalidArgument);
1375 } else if (rank == kSCNetworkServicePrimaryRankDefault) {
1376 _SCErrorSet(kSCStatusOK);
1377 }
1378
1379 return rank;
1380 }
1381
1382
1383 static Boolean
1384 rank_to_str(SCNetworkServicePrimaryRank rank, CFStringRef *rankStr)
1385 {
1386 switch (rank) {
1387 case kSCNetworkServicePrimaryRankDefault :
1388 *rankStr = NULL;
1389 break;
1390 case kSCNetworkServicePrimaryRankFirst :
1391 *rankStr = kSCValNetServicePrimaryRankFirst;
1392 break;
1393 case kSCNetworkServicePrimaryRankLast :
1394 *rankStr = kSCValNetServicePrimaryRankLast;
1395 break;
1396 case kSCNetworkServicePrimaryRankNever :
1397 *rankStr = kSCValNetServicePrimaryRankNever;
1398 break;
1399 default :
1400 return FALSE;
1401 }
1402
1403 return TRUE;
1404 }
1405
1406
1407 Boolean
1408 SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service,
1409 SCNetworkServicePrimaryRank newRank)
1410 {
1411 Boolean ok;
1412 CFDictionaryRef entity;
1413 CFMutableDictionaryRef newEntity;
1414 CFStringRef path = NULL;
1415 CFStringRef rankStr = NULL;
1416 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1417
1418 if (!isA_SCNetworkService(service)) {
1419 _SCErrorSet(kSCStatusInvalidArgument);
1420 return FALSE;
1421 }
1422
1423 ok = rank_to_str(newRank, &rankStr);
1424 if (!ok) {
1425 _SCErrorSet(kSCStatusInvalidArgument);
1426 return FALSE;
1427 }
1428
1429 if (servicePrivate->prefs != NULL) {
1430 if ((newRank == kSCNetworkServicePrimaryRankDefault) || (newRank == kSCNetworkServicePrimaryRankNever)) {
1431 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
1432 servicePrivate->serviceID,
1433 NULL);
1434 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1435 if (entity != NULL) {
1436 if (!isA_CFDictionary(entity)) {
1437 // if corrupt prefs
1438 _SCErrorSet(kSCStatusFailed);
1439 goto done;
1440 }
1441 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1442 } else {
1443 newEntity = CFDictionaryCreateMutable(NULL,
1444 0,
1445 &kCFTypeDictionaryKeyCallBacks,
1446 &kCFTypeDictionaryValueCallBacks);
1447 }
1448 if (rankStr != NULL) {
1449 CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr);
1450 } else {
1451 CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank);
1452 }
1453 if (CFDictionaryGetCount(newEntity) > 0) {
1454 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
1455 } else {
1456 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
1457 }
1458 CFRelease(newEntity);
1459 if (!ok) {
1460 goto done;
1461 }
1462 } else {
1463 _SCErrorSet(kSCStatusInvalidArgument);
1464 return FALSE;
1465 }
1466 } else if (servicePrivate->store != NULL) {
1467 path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1468 kSCDynamicStoreDomainState,
1469 servicePrivate->serviceID,
1470 NULL);
1471 entity = SCDynamicStoreCopyValue(servicePrivate->store, path);
1472 if (entity != NULL) {
1473 if (!isA_CFDictionary(entity)) {
1474 // if corrupt prefs
1475 CFRelease(entity);
1476 _SCErrorSet(kSCStatusFailed);
1477 goto done;
1478 }
1479 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1480 CFRelease(entity);
1481 } else {
1482 newEntity = CFDictionaryCreateMutable(NULL,
1483 0,
1484 &kCFTypeDictionaryKeyCallBacks,
1485 &kCFTypeDictionaryValueCallBacks);
1486 }
1487 if (rankStr != NULL) {
1488 CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr);
1489 } else {
1490 CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank);
1491 }
1492 if (CFDictionaryGetCount(newEntity) > 0) {
1493 ok = SCDynamicStoreSetValue(servicePrivate->store, path, newEntity);
1494 } else {
1495 ok = SCDynamicStoreRemoveValue(servicePrivate->store, path);
1496 }
1497 CFRelease(newEntity);
1498 if (!ok) {
1499 goto done;
1500 }
1501 } else {
1502 _SCErrorSet(kSCStatusInvalidArgument);
1503 return FALSE;
1504 }
1505
1506 done :
1507
1508 if (path != NULL) CFRelease(path);
1509 return ok;
1510 }