]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkService.c
configd-204.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkService.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 __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 CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), servicePrivate->prefs);
78 CFStringAppendFormat(result, NULL, CFSTR("}"));
79
80 return result;
81 }
82
83
84 static void
85 __SCNetworkServiceDeallocate(CFTypeRef cf)
86 {
87 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
88
89 /* release resources */
90
91 CFRelease(servicePrivate->serviceID);
92 if (servicePrivate->interface != NULL) CFRelease(servicePrivate->interface);
93 CFRelease(servicePrivate->prefs);
94
95 return;
96 }
97
98
99 static Boolean
100 __SCNetworkServiceEqual(CFTypeRef cf1, CFTypeRef cf2)
101 {
102 SCNetworkServicePrivateRef s1 = (SCNetworkServicePrivateRef)cf1;
103 SCNetworkServicePrivateRef s2 = (SCNetworkServicePrivateRef)cf2;
104
105 if (s1 == s2)
106 return TRUE;
107
108 if (s1->prefs != s2->prefs)
109 return FALSE; // if not the same prefs
110
111 if (!CFEqual(s1->serviceID, s2->serviceID))
112 return FALSE; // if not the same service identifier
113
114 return TRUE;
115 }
116
117
118 static CFHashCode
119 __SCNetworkServiceHash(CFTypeRef cf)
120 {
121 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
122
123 return CFHash(servicePrivate->serviceID);
124 }
125
126
127 static void
128 __SCNetworkServiceInitialize(void)
129 {
130 __kSCNetworkServiceTypeID = _CFRuntimeRegisterClass(&__SCNetworkServiceClass);
131 return;
132 }
133
134
135 __private_extern__ SCNetworkServicePrivateRef
136 __SCNetworkServiceCreatePrivate(CFAllocatorRef allocator,
137 SCPreferencesRef prefs,
138 CFStringRef serviceID,
139 SCNetworkInterfaceRef interface)
140 {
141 SCNetworkServicePrivateRef servicePrivate;
142 uint32_t size;
143
144 /* initialize runtime */
145 pthread_once(&initialized, __SCNetworkServiceInitialize);
146
147 /* allocate target */
148 size = sizeof(SCNetworkServicePrivate) - sizeof(CFRuntimeBase);
149 servicePrivate = (SCNetworkServicePrivateRef)_CFRuntimeCreateInstance(allocator,
150 __kSCNetworkServiceTypeID,
151 size,
152 NULL);
153 if (servicePrivate == NULL) {
154 return NULL;
155 }
156
157 servicePrivate->prefs = CFRetain(prefs);
158 servicePrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
159 servicePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL;
160
161 return servicePrivate;
162 }
163
164
165 #pragma mark -
166 #pragma mark SCNetworkService APIs
167
168
169 #define N_QUICK 64
170
171
172 static CFDictionaryRef
173 _protocolTemplate(SCNetworkServiceRef service, CFStringRef protocolType)
174 {
175 CFDictionaryRef newEntity = NULL;
176 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
177
178 if (servicePrivate->interface != NULL) {
179 SCNetworkInterfaceRef childInterface;
180 CFStringRef childInterfaceType = NULL;
181 CFStringRef interfaceType;
182
183 interfaceType = SCNetworkInterfaceGetInterfaceType(servicePrivate->interface);
184 childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface);
185 if (childInterface != NULL) {
186 childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
187 }
188
189 newEntity = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType);
190 }
191
192 if (newEntity == NULL) {
193 newEntity = CFDictionaryCreate(NULL,
194 NULL,
195 NULL,
196 0,
197 &kCFTypeDictionaryKeyCallBacks,
198 &kCFTypeDictionaryValueCallBacks);
199 }
200
201 return newEntity;
202 }
203
204
205 Boolean
206 SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
207 {
208 CFDictionaryRef entity;
209 CFDictionaryRef newEntity = NULL;
210 Boolean ok = FALSE;
211 CFStringRef path;
212 SCNetworkProtocolRef protocol;
213 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
214
215 if (!isA_SCNetworkService(service)) {
216 _SCErrorSet(kSCStatusInvalidArgument);
217 return FALSE;
218 }
219
220 if (!__SCNetworkProtocolIsValidType(protocolType)) {
221 _SCErrorSet(kSCStatusInvalidArgument);
222 return FALSE;
223 }
224
225 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
226 servicePrivate->serviceID, // service
227 protocolType); // entity
228
229 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
230 if (entity != NULL) {
231 // if "protocol" already exists
232 _SCErrorSet(kSCStatusKeyExists);
233 goto done;
234 }
235
236 newEntity = CFDictionaryCreate(NULL,
237 NULL,
238 NULL,
239 0,
240 &kCFTypeDictionaryKeyCallBacks,
241 &kCFTypeDictionaryValueCallBacks);
242 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
243 CFRelease(newEntity);
244 if (!ok) {
245 goto done;
246 }
247
248 protocol = SCNetworkServiceCopyProtocol(service, protocolType);
249 newEntity = _protocolTemplate(service, protocolType);
250 ok = SCNetworkProtocolSetConfiguration(protocol, newEntity);
251 CFRelease(newEntity);
252 CFRelease(protocol);
253
254 done :
255
256 CFRelease(path);
257 return ok;
258 }
259
260
261 CFArrayRef /* of SCNetworkServiceRef's */
262 SCNetworkServiceCopyAll(SCPreferencesRef prefs)
263 {
264 CFMutableArrayRef array;
265 CFIndex n;
266 CFStringRef path;
267 CFDictionaryRef services;
268
269 path = SCPreferencesPathKeyCreateNetworkServices(NULL);
270 services = SCPreferencesPathGetValue(prefs, path);
271 CFRelease(path);
272
273 if ((services != NULL) && !isA_CFDictionary(services)) {
274 return NULL;
275 }
276
277 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
278
279 n = (services != NULL) ? CFDictionaryGetCount(services) : 0;
280 if (n > 0) {
281 CFIndex i;
282 const void * keys_q[N_QUICK];
283 const void ** keys = keys_q;
284 const void * vals_q[N_QUICK];
285 const void ** vals = vals_q;
286
287 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
288 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
289 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
290 }
291 CFDictionaryGetKeysAndValues(services, keys, vals);
292 for (i = 0; i < n; i++) {
293 CFDictionaryRef entity;
294 SCNetworkServicePrivateRef servicePrivate;
295
296 if (!isA_CFDictionary(vals[i])) {
297 SCLog(TRUE,
298 LOG_INFO,
299 CFSTR("SCNetworkServiceCopyAll(): error w/service \"%@\"\n"),
300 keys[i]);
301 continue;
302 }
303
304 entity = CFDictionaryGetValue(vals[i], kSCEntNetInterface);
305 if (!isA_CFDictionary(entity)) {
306 // if no "interface"
307 SCLog(TRUE,
308 LOG_INFO,
309 CFSTR("SCNetworkServiceCopyAll(): no \"%@\" entity for service \"%@\"\n"),
310 kSCEntNetInterface,
311 keys[i]);
312 continue;
313 }
314
315 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, keys[i], NULL);
316 CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
317 CFRelease(servicePrivate);
318 }
319 if (keys != keys_q) {
320 CFAllocatorDeallocate(NULL, keys);
321 CFAllocatorDeallocate(NULL, vals);
322 }
323 }
324
325 return array;
326 }
327
328
329 /*
330 * build a list of all of a servives entity types that are associated
331 * with the services interface. The list will include :
332 *
333 * - entity types associated with the interface type (Ethernet, FireWire, PPP, ...)
334 * - entity types associated with the interface sub-type (PPPSerial, PPPoE, L2TP, PPTP, ...)
335 * - entity types associated with the hardware device (Ethernet, AirPort, FireWire, Modem, ...)
336 */
337 static CFSetRef
338 _copyInterfaceEntityTypes(CFDictionaryRef protocols)
339 {
340 CFDictionaryRef interface;
341 CFMutableSetRef interface_entity_types;
342
343 interface_entity_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
344
345 interface = CFDictionaryGetValue(protocols, kSCEntNetInterface);
346 if (isA_CFDictionary(interface)) {
347 CFStringRef entities[] = { kSCPropNetInterfaceType,
348 kSCPropNetInterfaceSubType,
349 kSCPropNetInterfaceHardware };
350 int i;
351
352 // include the "Interface" entity itself
353 CFSetAddValue(interface_entity_types, kSCEntNetInterface);
354
355 // include the entities associated with the interface
356 for (i = 0; i < sizeof(entities)/sizeof(entities[0]); i++) {
357 CFStringRef entity;
358
359 entity = CFDictionaryGetValue(interface, entities[i]);
360 if (isA_CFString(entity)) {
361 CFSetAddValue(interface_entity_types, entity);
362 }
363 }
364
365 /*
366 * and, because we've found some misguided network preference code
367 * developers leaving [PPP] entity dictionaries around even though
368 * they are unused and/or unneeded...
369 */
370 CFSetAddValue(interface_entity_types, kSCEntNetPPP);
371 }
372
373 return interface_entity_types;
374 }
375
376
377 SCNetworkServiceRef
378 SCNetworkServiceCopy(SCPreferencesRef prefs, CFStringRef serviceID)
379 {
380 CFDictionaryRef entity;
381 CFStringRef path;
382 SCNetworkServicePrivateRef servicePrivate;
383
384 if (!isA_CFString(serviceID)) {
385 _SCErrorSet(kSCStatusInvalidArgument);
386 return NULL;
387 }
388
389 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
390 serviceID, // service
391 kSCEntNetInterface); // entity
392 entity = SCPreferencesPathGetValue(prefs, path);
393 CFRelease(path);
394
395 if (!isA_CFDictionary(entity)) {
396 // a "service" must have an "interface"
397 _SCErrorSet(kSCStatusNoKey);
398 return NULL;
399 }
400
401 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
402 return (SCNetworkServiceRef)servicePrivate;
403 }
404
405
406 SCNetworkProtocolRef
407 SCNetworkServiceCopyProtocol(SCNetworkServiceRef service, CFStringRef protocolType)
408 {
409 CFSetRef non_protocol_entities;
410 CFStringRef path;
411 CFDictionaryRef protocols;
412 SCNetworkProtocolPrivateRef protocolPrivate = NULL;
413 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
414
415 if (!isA_SCNetworkService(service)) {
416 _SCErrorSet(kSCStatusInvalidArgument);
417 return NULL;
418 }
419
420 if (!isA_CFString(protocolType)) {
421 _SCErrorSet(kSCStatusInvalidArgument);
422 return NULL;
423 }
424
425 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
426 servicePrivate->serviceID, // service
427 NULL); // entity
428 protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
429 CFRelease(path);
430
431 if ((protocols != NULL) && !isA_CFDictionary(protocols)) {
432 // if corrupt prefs
433 _SCErrorSet(kSCStatusFailed);
434 return NULL;
435 }
436
437 non_protocol_entities = _copyInterfaceEntityTypes(protocols);
438 if (CFSetContainsValue(non_protocol_entities, protocolType)) {
439 // if the "protocolType" matches an interface entity type
440 _SCErrorSet(kSCStatusInvalidArgument);
441 goto done;
442 }
443
444 if (!CFDictionaryContainsKey(protocols, protocolType)) {
445 // if the "protocolType" entity does not exist
446 _SCErrorSet(kSCStatusNoKey);
447 goto done;
448 }
449
450 protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, protocolType, service);
451
452 done :
453
454 CFRelease(non_protocol_entities);
455
456 return (SCNetworkProtocolRef)protocolPrivate;
457 }
458
459
460 CFArrayRef /* of SCNetworkProtocolRef's */
461 SCNetworkServiceCopyProtocols(SCNetworkServiceRef service)
462 {
463 CFMutableArrayRef array;
464 CFIndex n;
465 CFSetRef non_protocol_entities;
466 CFStringRef path;
467 CFDictionaryRef protocols;
468 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
469
470 if (!isA_SCNetworkService(service)) {
471 _SCErrorSet(kSCStatusInvalidArgument);
472 return NULL;
473 }
474
475 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
476 servicePrivate->serviceID, // service
477 NULL); // entity
478 protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
479 CFRelease(path);
480
481 if (!isA_CFDictionary(protocols)) {
482 return NULL;
483 }
484
485 non_protocol_entities = _copyInterfaceEntityTypes(protocols);
486
487 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
488
489 n = CFDictionaryGetCount(protocols);
490 if (n > 0) {
491 CFIndex i;
492 const void * keys_q[N_QUICK];
493 const void ** keys = keys_q;
494 const void * vals_q[N_QUICK];
495 const void ** vals = vals_q;
496
497 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
498 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
499 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
500 }
501 CFDictionaryGetKeysAndValues(protocols, keys, vals);
502 for (i = 0; i < n; i++) {
503 SCNetworkProtocolPrivateRef protocolPrivate;
504
505 if (!isA_CFDictionary(vals[i])) {
506 // if it's not a dictionary then it can't be a protocol entity
507 continue;
508 }
509
510 if (CFSetContainsValue(non_protocol_entities, keys[i])) {
511 // skip any non-protocol (interface) entities
512 continue;
513 }
514
515 protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, keys[i], service);
516 CFArrayAppendValue(array, (SCNetworkProtocolRef)protocolPrivate);
517
518 CFRelease(protocolPrivate);
519 }
520 if (keys != keys_q) {
521 CFAllocatorDeallocate(NULL, keys);
522 CFAllocatorDeallocate(NULL, vals);
523 }
524 }
525
526 CFRelease(non_protocol_entities);
527
528 return array;
529 }
530
531
532 static Boolean
533 __SCNetworkServiceSetInterfaceEntity(SCNetworkServiceRef service,
534 SCNetworkInterfaceRef interface)
535 {
536 CFDictionaryRef entity;
537 Boolean ok;
538 CFStringRef path;
539 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
540
541 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
542 servicePrivate->serviceID, // service
543 kSCEntNetInterface); // entity
544 entity = __SCNetworkInterfaceCopyInterfaceEntity(interface);
545 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, entity);
546 CFRelease(entity);
547 CFRelease(path);
548
549 return ok;
550 }
551
552
553 static void
554 mergeDict(const void *key, const void *value, void *context)
555 {
556 CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context;
557
558 CFDictionarySetValue(newDict, key, value);
559 return;
560 }
561
562
563 SCNetworkServiceRef
564 SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface)
565 {
566 CFArrayRef components;
567 CFArrayRef interface_config;
568 CFStringRef interface_name;
569 SCNetworkInterfaceRef newInterface;
570 CFStringRef path;
571 CFStringRef prefix;
572 CFStringRef serviceID;
573 SCNetworkServicePrivateRef servicePrivate;
574 CFArrayRef supported_protocols;
575
576 if (!isA_SCNetworkInterface(interface)) {
577 _SCErrorSet(kSCStatusInvalidArgument);
578 return NULL;
579 }
580
581 // only allow network interfaces which support one or more protocols
582 // to be added to a service. The one exception is that we allow
583 // third-party interface types to be configured.
584 supported_protocols = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
585 if (supported_protocols == NULL) {
586 CFStringRef interface_type;
587
588 interface_type = SCNetworkInterfaceGetInterfaceType(interface);
589 if (CFStringFind(interface_type, CFSTR("."), 0).location == kCFNotFound) {
590 return NULL;
591 }
592 }
593
594 // establish the service
595 prefix = SCPreferencesPathKeyCreateNetworkServices(NULL);
596 path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
597 if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
598 CFRelease(prefix);
599 if (path == NULL) {
600 return NULL;
601 }
602
603 components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
604 CFRelease(path);
605
606 serviceID = CFArrayGetValueAtIndex(components, 2);
607 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
608 CFRelease(components);
609
610 // duplicate the interface and associate the copy with the new service
611 newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL,
612 interface,
613 prefs,
614 serviceID);
615 servicePrivate->interface = newInterface;
616
617 // establish "default" configuration(s) for the interface
618 for (interface = newInterface;
619 interface != NULL;
620 interface = SCNetworkInterfaceGetInterface(interface)) {
621 SCNetworkInterfaceRef childInterface;
622 CFStringRef childInterfaceType = NULL;
623 CFDictionaryRef config;
624 CFStringRef interfaceType;
625
626 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
627 childInterface = SCNetworkInterfaceGetInterface(interface);
628 if (childInterface != NULL) {
629 childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
630 }
631
632 config = __copyInterfaceTemplate(interfaceType, childInterfaceType);
633 if (config != NULL) {
634 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBluetooth) ||
635 CFEqual(interfaceType, kSCNetworkInterfaceTypeIrDA ) ||
636 CFEqual(interfaceType, kSCNetworkInterfaceTypeModem ) ||
637 CFEqual(interfaceType, kSCNetworkInterfaceTypeSerial ) ||
638 CFEqual(interfaceType, kSCNetworkInterfaceTypeWWAN )) {
639 CFDictionaryRef overrides;
640 CFStringRef script;
641
642 overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypeModem);
643
644 // a ConnectionScript (and related keys) from the interface
645 // should trump the settings from the configuration template.
646 if ((overrides != NULL) &&
647 CFDictionaryContainsKey(overrides, kSCPropNetModemConnectionScript)) {
648 CFMutableDictionaryRef newConfig;
649
650 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
651 CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionPersonality);
652 CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionScript);
653 CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceVendor);
654 CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceModel);
655 CFRelease(config);
656 config = newConfig;
657 }
658
659 // update template for v.92 modems
660 if ((overrides == NULL) &&
661 CFDictionaryGetValueIfPresent(config,
662 kSCPropNetModemConnectionScript,
663 (const void **)&script) &&
664 CFEqual(script, CFSTR("v.34 Personality")) &&
665 _SCNetworkInterfaceIsModemV92(interface)) {
666 CFMutableDictionaryRef newConfig;
667
668 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
669 CFDictionarySetValue(newConfig,
670 kSCPropNetModemConnectionPersonality,
671 CFSTR("v.92 Personality"));
672 CFDictionarySetValue(newConfig,
673 kSCPropNetModemDeviceModel,
674 CFSTR("Apple Modem (v.92)"));
675 CFRelease(config);
676 config = newConfig;
677 }
678
679 if (overrides != NULL) {
680 CFMutableDictionaryRef newConfig;
681
682 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
683 CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
684 CFRelease(config);
685 config = newConfig;
686 }
687 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
688 CFDictionaryRef overrides;
689
690 overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypePPP);
691 if (overrides != NULL) {
692 CFMutableDictionaryRef newConfig;
693
694 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
695 CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
696 CFRelease(config);
697 config = newConfig;
698 }
699 }
700
701 if (!__SCNetworkInterfaceSetConfiguration(interface, NULL, config, TRUE)) {
702 SCLog(TRUE, LOG_DEBUG,
703 CFSTR("SCNetworkService __SCNetworkInterfaceSetConfiguration failed(), interface=%@, type=NULL"),
704 interface);
705 }
706 CFRelease(config);
707 }
708 }
709
710 // add the interface [entity] to the service
711 (void) __SCNetworkServiceSetInterfaceEntity((SCNetworkServiceRef)servicePrivate,
712 servicePrivate->interface);
713
714 // push the [deep] interface configuration into the service.
715 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(servicePrivate->interface);
716 __SCNetworkInterfaceSetDeepConfiguration(servicePrivate->interface, interface_config);
717 if (interface_config != NULL) CFRelease(interface_config);
718
719 // set the service name to match that of the associated interface
720 //
721 // Note: It might seem a bit odd to call SCNetworkServiceGetName
722 // followed by an immediate call to SCNetworkServiceSetName. The
723 // trick here is that if no name has previously been set, the
724 // "get" function will return the name of the associated interface.
725 //
726 // ... and we "set" a name to ensure that applications that do
727 // not use the APIs will still find a UserDefinedName property
728 // in the SCDynamicStore.
729 //
730 interface_name = SCNetworkServiceGetName((SCNetworkServiceRef)servicePrivate);
731 if (interface_name != NULL) {
732 (void) SCNetworkServiceSetName((SCNetworkServiceRef)servicePrivate,
733 interface_name);
734 }
735
736 return (SCNetworkServiceRef)servicePrivate;
737 }
738
739
740 Boolean
741 SCNetworkServiceEstablishDefaultConfiguration(SCNetworkServiceRef service)
742 {
743 CFIndex i;
744 SCNetworkInterfaceRef interface;
745 CFIndex n;
746 CFArrayRef protocolTypes;
747
748 interface = SCNetworkServiceGetInterface(service);
749 if (interface == NULL) {
750 return FALSE;
751 }
752
753 protocolTypes = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
754 n = (protocolTypes != NULL) ? CFArrayGetCount(protocolTypes) : 0;
755 for (i = 0; i < n; i++) {
756 Boolean enabled;
757 CFDictionaryRef newEntity = NULL;
758 Boolean ok;
759 SCNetworkProtocolRef protocol = NULL;
760 CFStringRef protocolType;
761
762 protocolType = CFArrayGetValueAtIndex(protocolTypes, i);
763 ok = SCNetworkServiceAddProtocolType(service, protocolType);
764 if (!ok && (SCError() != kSCStatusKeyExists)) {
765 // could not add protocol
766 goto nextProtocol;
767 }
768
769 protocol = SCNetworkServiceCopyProtocol(service, protocolType);
770 if (protocol == NULL) {
771 // oops, somethings wrong (should never happen)
772 goto nextProtocol;
773 }
774
775 newEntity = _protocolTemplate(service, protocolType);
776 ok = SCNetworkProtocolSetConfiguration(protocol, newEntity);
777 if (!ok) {
778 // could not set default configuration
779 goto nextProtocol;
780 }
781
782 enabled = !CFDictionaryContainsKey(newEntity, kSCResvInactive);
783 ok = SCNetworkProtocolSetEnabled(protocol, enabled);
784 if (!ok) {
785 // could not enable/disable protocol
786 goto nextProtocol;
787 }
788
789 nextProtocol :
790
791 if (newEntity != NULL) CFRelease(newEntity);
792 if (protocol != NULL) CFRelease(protocol);
793 }
794
795 return TRUE;
796 }
797
798
799 Boolean
800 SCNetworkServiceGetEnabled(SCNetworkServiceRef service)
801 {
802 Boolean enabled;
803 CFStringRef path;
804 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
805
806 if (!isA_SCNetworkService(service)) {
807 _SCErrorSet(kSCStatusInvalidArgument);
808 return FALSE;
809 }
810
811 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
812 servicePrivate->serviceID, // service
813 NULL); // entity
814 enabled = __getPrefsEnabled(servicePrivate->prefs, path);
815 CFRelease(path);
816
817 return enabled;
818 }
819
820
821 SCNetworkInterfaceRef
822 SCNetworkServiceGetInterface(SCNetworkServiceRef service)
823 {
824 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
825
826 if (!isA_SCNetworkService(service)) {
827 _SCErrorSet(kSCStatusInvalidArgument);
828 return NULL;
829 }
830
831 if (servicePrivate->interface == NULL) {
832 CFDictionaryRef entity;
833 CFStringRef path;
834
835 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
836 servicePrivate->serviceID, // service
837 kSCEntNetInterface); // entity
838 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
839 CFRelease(path);
840
841 if (isA_CFDictionary(entity)) {
842 servicePrivate->interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, service);
843 }
844 }
845
846 return servicePrivate->interface;
847 }
848
849
850 CFStringRef
851 SCNetworkServiceGetName(SCNetworkServiceRef service)
852 {
853 CFDictionaryRef entity;
854 SCNetworkInterfaceRef interface;
855 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
856 CFStringRef name = NULL;
857 CFStringRef path;
858
859 if (!isA_SCNetworkService(service)) {
860 _SCErrorSet(kSCStatusInvalidArgument);
861 return NULL;
862 }
863
864 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
865 servicePrivate->serviceID, // service
866 NULL); // entity
867 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
868 CFRelease(path);
869
870 if (isA_CFDictionary(entity)) {
871 name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
872 name = isA_CFString(name);
873 }
874
875 interface = SCNetworkServiceGetInterface(service);
876 while (interface != NULL) {
877 SCNetworkInterfaceRef childInterface;
878
879 childInterface = SCNetworkInterfaceGetInterface(interface);
880 if (childInterface == NULL) {
881 break;
882 }
883
884 interface = childInterface;
885 }
886
887 if (interface != NULL) {
888 if (name != NULL) {
889 CFStringRef interface_name;
890
891 interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
892 if ((interface_name != NULL) && CFEqual(name, interface_name)) {
893 // if service name matches the [non-]localized
894 // interface name
895 name = NULL;
896 }
897 }
898
899 if (name == NULL) {
900 name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
901 }
902 }
903
904 return name;
905 }
906
907
908 CFStringRef
909 SCNetworkServiceGetServiceID(SCNetworkServiceRef service)
910 {
911 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
912
913 if (!isA_SCNetworkService(service)) {
914 _SCErrorSet(kSCStatusInvalidArgument);
915 return NULL;
916 }
917
918 return servicePrivate->serviceID;
919 }
920
921
922 CFTypeID
923 SCNetworkServiceGetTypeID(void)
924 {
925 pthread_once(&initialized, __SCNetworkServiceInitialize); /* initialize runtime */
926 return __kSCNetworkServiceTypeID;
927 }
928
929
930 Boolean
931 SCNetworkServiceRemove(SCNetworkServiceRef service)
932 {
933 Boolean ok = FALSE;
934 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
935 CFArrayRef sets;
936 CFStringRef path;
937
938 if (!isA_SCNetworkService(service)) {
939 _SCErrorSet(kSCStatusInvalidArgument);
940 return FALSE;
941 }
942
943 // remove service from all sets
944
945 sets = SCNetworkSetCopyAll(servicePrivate->prefs);
946 if (sets != NULL) {
947 CFIndex i;
948 CFIndex n;
949
950 n = CFArrayGetCount(sets);
951 for (i = 0; i < n; i++) {
952 SCNetworkSetRef set;
953
954 set = CFArrayGetValueAtIndex(sets, i);
955 ok = SCNetworkSetRemoveService(set, service);
956 if (!ok && (SCError() != kSCStatusNoKey)) {
957 CFRelease(sets);
958 return ok;
959 }
960 }
961 CFRelease(sets);
962 }
963
964 // remove service
965
966 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
967 servicePrivate->serviceID, // service
968 NULL); // entity
969 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
970 CFRelease(path);
971
972 return ok;
973 }
974
975
976 Boolean
977 SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
978 {
979 CFDictionaryRef entity;
980 Boolean ok = FALSE;
981 CFStringRef path;
982 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
983
984 if (!isA_SCNetworkService(service)) {
985 _SCErrorSet(kSCStatusInvalidArgument);
986 return FALSE;
987 }
988
989 if (!__SCNetworkProtocolIsValidType(protocolType)) {
990 _SCErrorSet(kSCStatusInvalidArgument);
991 return FALSE;
992 }
993
994 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
995 servicePrivate->serviceID, // service
996 protocolType); // entity
997
998 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
999 if (entity == NULL) {
1000 // if "protocol" does not exist
1001 _SCErrorSet(kSCStatusNoKey);
1002 goto done;
1003 }
1004
1005 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
1006
1007 done :
1008
1009 CFRelease(path);
1010 return ok;
1011 }
1012
1013
1014 Boolean
1015 SCNetworkServiceSetEnabled(SCNetworkServiceRef service, Boolean enabled)
1016 {
1017 Boolean ok;
1018 CFStringRef path;
1019 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1020
1021 if (!isA_SCNetworkService(service)) {
1022 _SCErrorSet(kSCStatusInvalidArgument);
1023 return FALSE;
1024 }
1025
1026 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1027 servicePrivate->serviceID, // service
1028 NULL); // entity
1029 ok = __setPrefsEnabled(servicePrivate->prefs, path, enabled);
1030 CFRelease(path);
1031
1032 return ok;
1033 }
1034
1035
1036 Boolean
1037 SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name)
1038 {
1039 CFDictionaryRef entity;
1040 Boolean ok = FALSE;
1041 CFStringRef path;
1042 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1043
1044 if (!isA_SCNetworkService(service)) {
1045 _SCErrorSet(kSCStatusInvalidArgument);
1046 return FALSE;
1047 }
1048
1049 if ((name != NULL) && !isA_CFString(name)) {
1050 _SCErrorSet(kSCStatusInvalidArgument);
1051 return FALSE;
1052 }
1053
1054 if (name != NULL) {
1055 SCNetworkInterfaceRef interface;
1056
1057 interface = SCNetworkServiceGetInterface(service);
1058 while (interface != NULL) {
1059 SCNetworkInterfaceRef childInterface;
1060
1061 childInterface = SCNetworkInterfaceGetInterface(interface);
1062 if (childInterface == NULL) {
1063 break;
1064 }
1065
1066 interface = childInterface;
1067 }
1068
1069 if (interface != NULL) {
1070 CFStringRef interface_name;
1071
1072 interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
1073 if ((interface_name != NULL) && CFEqual(name, interface_name)) {
1074 // if service name matches the localized interface name
1075 // then store the non-localized name.
1076 interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
1077 if (interface_name != NULL) {
1078 name = interface_name;
1079 }
1080 }
1081 }
1082 }
1083
1084 #define PREVENT_DUPLICATE_SERVICE_NAMES
1085 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
1086 if (name != NULL) {
1087 CFArrayRef sets;
1088
1089 // ensure that each service is uniquely named within its sets
1090
1091 sets = SCNetworkSetCopyAll(servicePrivate->prefs);
1092 if (sets != NULL) {
1093 CFIndex set_index;
1094 CFIndex set_count;
1095
1096 set_count = CFArrayGetCount(sets);
1097 for (set_index = 0; set_index < set_count; set_index++) {
1098 CFIndex service_index;
1099 Boolean isDup = FALSE;
1100 Boolean isMember = FALSE;
1101 CFIndex service_count;
1102 CFArrayRef services;
1103 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, set_index);
1104
1105 services = SCNetworkSetCopyServices(set);
1106
1107 service_count = CFArrayGetCount(services);
1108 for (service_index = 0; service_index < service_count; service_index++) {
1109 CFStringRef otherID;
1110 CFStringRef otherName;
1111 SCNetworkServiceRef otherService;
1112
1113 otherService = CFArrayGetValueAtIndex(services, service_index);
1114
1115 otherID = SCNetworkServiceGetServiceID(otherService);
1116 if (CFEqual(servicePrivate->serviceID, otherID)) {
1117 // if the service is a member of this set
1118 isMember = TRUE;
1119 continue;
1120 }
1121
1122 otherName = SCNetworkServiceGetName(otherService);
1123 if ((otherName != NULL) && CFEqual(name, otherName)) {
1124 isDup = TRUE;
1125 continue;
1126 }
1127 }
1128
1129 CFRelease(services);
1130
1131 if (isMember && isDup) {
1132 /*
1133 * if this service is a member of the set and
1134 * the "name" is not unique.
1135 */
1136 CFRelease(sets);
1137 _SCErrorSet(kSCStatusKeyExists);
1138 return FALSE;
1139 }
1140 }
1141
1142 CFRelease(sets);
1143 }
1144 }
1145 #endif /* PREVENT_DUPLICATE_SERVICE_NAMES */
1146
1147 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1148 servicePrivate->serviceID, // service
1149 NULL); // entity
1150 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1151 if ((entity == NULL) && (name != NULL)) {
1152 entity = CFDictionaryCreate(NULL,
1153 NULL,
1154 NULL,
1155 0,
1156 &kCFTypeDictionaryKeyCallBacks,
1157 &kCFTypeDictionaryValueCallBacks);
1158 }
1159 if (isA_CFDictionary(entity)) {
1160 CFMutableDictionaryRef newEntity;
1161
1162 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1163 if (name != NULL) {
1164 CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name);
1165 } else {
1166 CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
1167 }
1168 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
1169 CFRelease(newEntity);
1170 }
1171 CFRelease(path);
1172
1173 return ok;
1174 }