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