2 * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * May 13, 2004 Allan Nathanson <ajn@apple.com>
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>
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
);
48 static CFTypeID __kSCNetworkServiceTypeID
= _kCFRuntimeNotATypeID
;
51 static const CFRuntimeClass __SCNetworkServiceClass
= {
53 "SCNetworkService", // className
56 __SCNetworkServiceDeallocate
, // dealloc
57 __SCNetworkServiceEqual
, // equal
58 __SCNetworkServiceHash
, // hash
59 NULL
, // copyFormattingDesc
60 __SCNetworkServiceCopyDescription
// copyDebugDesc
64 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
68 __SCNetworkServiceCopyDescription(CFTypeRef cf
)
70 CFAllocatorRef allocator
= CFGetAllocator(cf
);
71 CFMutableStringRef result
;
72 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)cf
;
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
);
82 if (servicePrivate
->name
!= NULL
) {
83 CFStringAppendFormat(result
, NULL
, CFSTR(", name = %@"), servicePrivate
->name
);
85 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
92 __SCNetworkServiceDeallocate(CFTypeRef cf
)
94 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)cf
;
96 /* release resources */
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
);
109 __SCNetworkServiceEqual(CFTypeRef cf1
, CFTypeRef cf2
)
111 SCNetworkServicePrivateRef s1
= (SCNetworkServicePrivateRef
)cf1
;
112 SCNetworkServicePrivateRef s2
= (SCNetworkServicePrivateRef
)cf2
;
117 if (s1
->prefs
!= s2
->prefs
)
118 return FALSE
; // if not the same prefs
120 if (!CFEqual(s1
->serviceID
, s2
->serviceID
))
121 return FALSE
; // if not the same service identifier
128 __SCNetworkServiceHash(CFTypeRef cf
)
130 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)cf
;
132 return CFHash(servicePrivate
->serviceID
);
137 __SCNetworkServiceInitialize(void)
139 __kSCNetworkServiceTypeID
= _CFRuntimeRegisterClass(&__SCNetworkServiceClass
);
144 __private_extern__ SCNetworkServicePrivateRef
145 __SCNetworkServiceCreatePrivate(CFAllocatorRef allocator
,
146 SCPreferencesRef prefs
,
147 CFStringRef serviceID
,
148 SCNetworkInterfaceRef interface
)
150 SCNetworkServicePrivateRef servicePrivate
;
153 /* initialize runtime */
154 pthread_once(&initialized
, __SCNetworkServiceInitialize
);
156 /* allocate target */
157 size
= sizeof(SCNetworkServicePrivate
) - sizeof(CFRuntimeBase
);
158 servicePrivate
= (SCNetworkServicePrivateRef
)_CFRuntimeCreateInstance(allocator
,
159 __kSCNetworkServiceTypeID
,
162 if (servicePrivate
== NULL
) {
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
;
171 return servicePrivate
;
176 #pragma mark SCNetworkService APIs
182 static CFDictionaryRef
183 _protocolTemplate(SCNetworkServiceRef service
, CFStringRef protocolType
)
185 CFDictionaryRef newEntity
= NULL
;
186 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
188 if (servicePrivate
->interface
!= NULL
) {
189 SCNetworkInterfaceRef childInterface
;
190 CFStringRef childInterfaceType
= NULL
;
191 CFStringRef interfaceType
;
193 interfaceType
= SCNetworkInterfaceGetInterfaceType(servicePrivate
->interface
);
194 childInterface
= SCNetworkInterfaceGetInterface(servicePrivate
->interface
);
195 if (childInterface
!= NULL
) {
196 childInterfaceType
= SCNetworkInterfaceGetInterfaceType(childInterface
);
199 newEntity
= __copyProtocolTemplate(interfaceType
, childInterfaceType
, protocolType
);
202 if (newEntity
== NULL
) {
203 newEntity
= CFDictionaryCreate(NULL
,
207 &kCFTypeDictionaryKeyCallBacks
,
208 &kCFTypeDictionaryValueCallBacks
);
216 SCNetworkServiceAddProtocolType(SCNetworkServiceRef service
, CFStringRef protocolType
)
218 CFDictionaryRef entity
;
219 CFDictionaryRef newEntity
= NULL
;
222 SCNetworkProtocolRef protocol
;
223 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
225 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
226 _SCErrorSet(kSCStatusInvalidArgument
);
230 if (!__SCNetworkProtocolIsValidType(protocolType
)) {
231 _SCErrorSet(kSCStatusInvalidArgument
);
235 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
236 servicePrivate
->serviceID
, // service
237 protocolType
); // entity
239 entity
= SCPreferencesPathGetValue(servicePrivate
->prefs
, path
);
240 if (entity
!= NULL
) {
241 // if "protocol" already exists
242 _SCErrorSet(kSCStatusKeyExists
);
246 newEntity
= CFDictionaryCreate(NULL
,
250 &kCFTypeDictionaryKeyCallBacks
,
251 &kCFTypeDictionaryValueCallBacks
);
252 ok
= SCPreferencesPathSetValue(servicePrivate
->prefs
, path
, newEntity
);
253 CFRelease(newEntity
);
258 protocol
= SCNetworkServiceCopyProtocol(service
, protocolType
);
259 newEntity
= _protocolTemplate(service
, protocolType
);
260 ok
= SCNetworkProtocolSetConfiguration(protocol
, newEntity
);
261 CFRelease(newEntity
);
271 CFArrayRef
/* of SCNetworkServiceRef's */
272 SCNetworkServiceCopyAll(SCPreferencesRef prefs
)
274 CFMutableArrayRef array
;
277 CFDictionaryRef services
;
279 path
= SCPreferencesPathKeyCreateNetworkServices(NULL
);
280 services
= SCPreferencesPathGetValue(prefs
, path
);
283 if ((services
!= NULL
) && !isA_CFDictionary(services
)) {
287 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
289 n
= (services
!= NULL
) ? CFDictionaryGetCount(services
) : 0;
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
;
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);
301 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
302 for (i
= 0; i
< n
; i
++) {
303 CFDictionaryRef entity
;
304 SCNetworkServicePrivateRef servicePrivate
;
306 if (!isA_CFDictionary(vals
[i
])) {
309 CFSTR("SCNetworkServiceCopyAll(): error w/service \"%@\"\n"),
314 entity
= CFDictionaryGetValue(vals
[i
], kSCEntNetInterface
);
315 if (!isA_CFDictionary(entity
)) {
319 CFSTR("SCNetworkServiceCopyAll(): no \"%@\" entity for service \"%@\"\n"),
325 servicePrivate
= __SCNetworkServiceCreatePrivate(NULL
, prefs
, keys
[i
], NULL
);
326 CFArrayAppendValue(array
, (SCNetworkServiceRef
)servicePrivate
);
327 CFRelease(servicePrivate
);
329 if (keys
!= keys_q
) {
330 CFAllocatorDeallocate(NULL
, keys
);
331 CFAllocatorDeallocate(NULL
, vals
);
340 * build a list of all of a servives entity types that are associated
341 * with the services interface. The list will include :
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, ...)
348 _copyInterfaceEntityTypes(CFDictionaryRef protocols
)
350 CFDictionaryRef interface
;
351 CFMutableSetRef interface_entity_types
;
353 interface_entity_types
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
355 interface
= CFDictionaryGetValue(protocols
, kSCEntNetInterface
);
356 if (isA_CFDictionary(interface
)) {
357 CFStringRef entities
[] = { kSCPropNetInterfaceType
,
358 kSCPropNetInterfaceSubType
,
359 kSCPropNetInterfaceHardware
};
362 // include the "Interface" entity itself
363 CFSetAddValue(interface_entity_types
, kSCEntNetInterface
);
365 // include the entities associated with the interface
366 for (i
= 0; i
< sizeof(entities
)/sizeof(entities
[0]); i
++) {
369 entity
= CFDictionaryGetValue(interface
, entities
[i
]);
370 if (isA_CFString(entity
)) {
371 CFSetAddValue(interface_entity_types
, entity
);
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...
380 CFSetAddValue(interface_entity_types
, kSCEntNetPPP
);
383 return interface_entity_types
;
388 SCNetworkServiceCopy(SCPreferencesRef prefs
, CFStringRef serviceID
)
390 CFDictionaryRef entity
;
392 SCNetworkServicePrivateRef servicePrivate
;
394 if (!isA_CFString(serviceID
)) {
395 _SCErrorSet(kSCStatusInvalidArgument
);
399 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
400 serviceID
, // service
401 kSCEntNetInterface
); // entity
402 entity
= SCPreferencesPathGetValue(prefs
, path
);
405 if (!isA_CFDictionary(entity
)) {
406 // a "service" must have an "interface"
407 _SCErrorSet(kSCStatusNoKey
);
411 servicePrivate
= __SCNetworkServiceCreatePrivate(NULL
, prefs
, serviceID
, NULL
);
412 return (SCNetworkServiceRef
)servicePrivate
;
417 _SCNetworkServiceCopyActive(SCDynamicStoreRef store
, CFStringRef serviceID
)
419 SCNetworkServicePrivateRef servicePrivate
;
421 if (!isA_CFString(serviceID
)) {
422 _SCErrorSet(kSCStatusInvalidArgument
);
426 servicePrivate
= __SCNetworkServiceCreatePrivate(NULL
, NULL
, serviceID
, NULL
);
428 servicePrivate
->store
= CFRetain(store
);
430 return (SCNetworkServiceRef
)servicePrivate
;
435 SCNetworkServiceCopyProtocol(SCNetworkServiceRef service
, CFStringRef protocolType
)
437 CFSetRef non_protocol_entities
;
439 CFDictionaryRef protocols
;
440 SCNetworkProtocolPrivateRef protocolPrivate
= NULL
;
441 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
443 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
444 _SCErrorSet(kSCStatusInvalidArgument
);
448 if (!isA_CFString(protocolType
)) {
449 _SCErrorSet(kSCStatusInvalidArgument
);
453 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
454 servicePrivate
->serviceID
, // service
456 protocols
= SCPreferencesPathGetValue(servicePrivate
->prefs
, path
);
459 if (!isA_CFDictionary(protocols
)) {
461 _SCErrorSet(kSCStatusFailed
);
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
);
472 if (!CFDictionaryContainsKey(protocols
, protocolType
)) {
473 // if the "protocolType" entity does not exist
474 _SCErrorSet(kSCStatusNoKey
);
478 protocolPrivate
= __SCNetworkProtocolCreatePrivate(NULL
, protocolType
, service
);
482 CFRelease(non_protocol_entities
);
484 return (SCNetworkProtocolRef
)protocolPrivate
;
488 CFArrayRef
/* of SCNetworkProtocolRef's */
489 SCNetworkServiceCopyProtocols(SCNetworkServiceRef service
)
491 CFMutableArrayRef array
;
493 CFSetRef non_protocol_entities
;
495 CFDictionaryRef protocols
;
496 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
498 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
499 _SCErrorSet(kSCStatusInvalidArgument
);
503 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
504 servicePrivate
->serviceID
, // service
506 protocols
= SCPreferencesPathGetValue(servicePrivate
->prefs
, path
);
509 if (!isA_CFDictionary(protocols
)) {
511 _SCErrorSet(kSCStatusFailed
);
515 non_protocol_entities
= _copyInterfaceEntityTypes(protocols
);
517 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
519 n
= CFDictionaryGetCount(protocols
);
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
;
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);
531 CFDictionaryGetKeysAndValues(protocols
, keys
, vals
);
532 for (i
= 0; i
< n
; i
++) {
533 SCNetworkProtocolPrivateRef protocolPrivate
;
535 if (!isA_CFDictionary(vals
[i
])) {
536 // if it's not a dictionary then it can't be a protocol entity
540 if (CFSetContainsValue(non_protocol_entities
, keys
[i
])) {
541 // skip any non-protocol (interface) entities
545 protocolPrivate
= __SCNetworkProtocolCreatePrivate(NULL
, keys
[i
], service
);
546 CFArrayAppendValue(array
, (SCNetworkProtocolRef
)protocolPrivate
);
548 CFRelease(protocolPrivate
);
550 if (keys
!= keys_q
) {
551 CFAllocatorDeallocate(NULL
, keys
);
552 CFAllocatorDeallocate(NULL
, vals
);
556 CFRelease(non_protocol_entities
);
563 __SCNetworkServiceSetInterfaceEntity(SCNetworkServiceRef service
,
564 SCNetworkInterfaceRef interface
)
566 CFDictionaryRef entity
;
569 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
571 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
572 servicePrivate
->serviceID
, // service
573 kSCEntNetInterface
); // entity
574 entity
= __SCNetworkInterfaceCopyInterfaceEntity(interface
);
575 ok
= SCPreferencesPathSetValue(servicePrivate
->prefs
, path
, entity
);
584 mergeDict(const void *key
, const void *value
, void *context
)
586 CFMutableDictionaryRef newDict
= (CFMutableDictionaryRef
)context
;
588 CFDictionarySetValue(newDict
, key
, value
);
594 SCNetworkServiceCreate(SCPreferencesRef prefs
, SCNetworkInterfaceRef interface
)
596 CFArrayRef components
;
597 CFArrayRef interface_config
;
598 CFStringRef interface_name
;
599 SCNetworkInterfaceRef newInterface
;
602 CFStringRef serviceID
;
603 SCNetworkServicePrivateRef servicePrivate
;
604 CFArrayRef supported_protocols
;
606 if (!isA_SCNetworkInterface(interface
)) {
607 _SCErrorSet(kSCStatusInvalidArgument
);
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
;
618 interface_type
= SCNetworkInterfaceGetInterfaceType(interface
);
619 if (CFStringFind(interface_type
, CFSTR("."), 0).location
== kCFNotFound
) {
624 // establish the service
625 prefix
= SCPreferencesPathKeyCreateNetworkServices(NULL
);
626 path
= __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs
, prefix
);
627 if (path
== NULL
) path
= SCPreferencesPathCreateUniqueChild(prefs
, prefix
);
633 components
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
636 serviceID
= CFArrayGetValueAtIndex(components
, 2);
637 servicePrivate
= __SCNetworkServiceCreatePrivate(NULL
, prefs
, serviceID
, NULL
);
638 CFRelease(components
);
640 // duplicate the interface and associate the copy with the new service
641 newInterface
= (SCNetworkInterfaceRef
)__SCNetworkInterfaceCreateCopy(NULL
,
645 servicePrivate
->interface
= newInterface
;
647 // establish "default" configuration(s) for the interface
648 for (interface
= newInterface
;
650 interface
= SCNetworkInterfaceGetInterface(interface
)) {
651 SCNetworkInterfaceRef childInterface
;
652 CFStringRef childInterfaceType
= NULL
;
653 CFDictionaryRef config
;
654 CFStringRef interfaceType
;
656 interfaceType
= SCNetworkInterfaceGetInterfaceType(interface
);
657 childInterface
= SCNetworkInterfaceGetInterface(interface
);
658 if (childInterface
!= NULL
) {
659 childInterfaceType
= SCNetworkInterfaceGetInterfaceType(childInterface
);
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
;
671 overrides
= __SCNetworkInterfaceGetTemplateOverrides(interface
, kSCNetworkInterfaceTypeModem
);
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
;
679 newConfig
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
680 CFDictionaryRemoveValue(newConfig
, kSCPropNetModemConnectionPersonality
);
681 CFDictionaryRemoveValue(newConfig
, kSCPropNetModemConnectionScript
);
682 CFDictionaryRemoveValue(newConfig
, kSCPropNetModemDeviceVendor
);
683 CFDictionaryRemoveValue(newConfig
, kSCPropNetModemDeviceModel
);
688 if (overrides
!= NULL
) {
689 CFMutableDictionaryRef newConfig
;
691 newConfig
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
692 CFDictionaryApplyFunction(overrides
, mergeDict
, newConfig
);
696 } else if (CFEqual(interfaceType
, kSCNetworkInterfaceTypePPP
)) {
697 CFDictionaryRef overrides
;
699 overrides
= __SCNetworkInterfaceGetTemplateOverrides(interface
, kSCNetworkInterfaceTypePPP
);
700 if (overrides
!= NULL
) {
701 CFMutableDictionaryRef newConfig
;
703 newConfig
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
704 CFDictionaryApplyFunction(overrides
, mergeDict
, newConfig
);
710 if (!__SCNetworkInterfaceSetConfiguration(interface
, NULL
, config
, TRUE
)) {
711 SCLog(TRUE
, LOG_DEBUG
,
712 CFSTR("SCNetworkService __SCNetworkInterfaceSetConfiguration failed(), interface=%@, type=NULL"),
719 // add the interface [entity] to the service
720 (void) __SCNetworkServiceSetInterfaceEntity((SCNetworkServiceRef
)servicePrivate
,
721 servicePrivate
->interface
);
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
);
728 // set the service name to match that of the associated interface
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.
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.
739 interface_name
= SCNetworkServiceGetName((SCNetworkServiceRef
)servicePrivate
);
740 if (interface_name
!= NULL
) {
741 (void) SCNetworkServiceSetName((SCNetworkServiceRef
)servicePrivate
,
745 return (SCNetworkServiceRef
)servicePrivate
;
750 SCNetworkServiceEstablishDefaultConfiguration(SCNetworkServiceRef service
)
753 SCNetworkInterfaceRef interface
;
755 CFArrayRef protocolTypes
;
756 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
758 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
759 _SCErrorSet(kSCStatusInvalidArgument
);
763 interface
= SCNetworkServiceGetInterface(service
);
764 if (interface
== NULL
) {
768 protocolTypes
= SCNetworkInterfaceGetSupportedProtocolTypes(interface
);
769 n
= (protocolTypes
!= NULL
) ? CFArrayGetCount(protocolTypes
) : 0;
770 for (i
= 0; i
< n
; i
++) {
772 CFDictionaryRef newEntity
= NULL
;
774 SCNetworkProtocolRef protocol
= NULL
;
775 CFStringRef protocolType
;
777 protocolType
= CFArrayGetValueAtIndex(protocolTypes
, i
);
778 ok
= SCNetworkServiceAddProtocolType(service
, protocolType
);
779 if (!ok
&& (SCError() != kSCStatusKeyExists
)) {
780 // could not add protocol
784 protocol
= SCNetworkServiceCopyProtocol(service
, protocolType
);
785 if (protocol
== NULL
) {
786 // oops, somethings wrong (should never happen)
790 newEntity
= _protocolTemplate(service
, protocolType
);
791 ok
= SCNetworkProtocolSetConfiguration(protocol
, newEntity
);
793 // could not set default configuration
797 enabled
= !CFDictionaryContainsKey(newEntity
, kSCResvInactive
);
798 ok
= SCNetworkProtocolSetEnabled(protocol
, enabled
);
800 // could not enable/disable protocol
806 if (newEntity
!= NULL
) CFRelease(newEntity
);
807 if (protocol
!= NULL
) CFRelease(protocol
);
815 SCNetworkServiceGetEnabled(SCNetworkServiceRef service
)
819 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
821 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
822 _SCErrorSet(kSCStatusInvalidArgument
);
826 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
827 servicePrivate
->serviceID
, // service
829 enabled
= __getPrefsEnabled(servicePrivate
->prefs
, path
);
836 SCNetworkInterfaceRef
837 SCNetworkServiceGetInterface(SCNetworkServiceRef service
)
839 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
841 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
842 _SCErrorSet(kSCStatusInvalidArgument
);
846 if (servicePrivate
->interface
== NULL
) {
847 CFDictionaryRef entity
;
850 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
851 servicePrivate
->serviceID
, // service
852 kSCEntNetInterface
); // entity
853 entity
= SCPreferencesPathGetValue(servicePrivate
->prefs
, path
);
856 if (isA_CFDictionary(entity
)) {
857 servicePrivate
->interface
= _SCNetworkInterfaceCreateWithEntity(NULL
, entity
, service
);
861 return servicePrivate
->interface
;
866 SCNetworkServiceGetName(SCNetworkServiceRef service
)
868 CFDictionaryRef entity
;
869 SCNetworkInterfaceRef interface
;
870 CFStringRef name
= NULL
;
872 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
874 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
875 _SCErrorSet(kSCStatusInvalidArgument
);
879 if (servicePrivate
->name
!= NULL
) {
880 return servicePrivate
->name
;
883 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
884 servicePrivate
->serviceID
, // service
886 entity
= SCPreferencesPathGetValue(servicePrivate
->prefs
, path
);
889 if (isA_CFDictionary(entity
)) {
890 name
= CFDictionaryGetValue(entity
, kSCPropUserDefinedName
);
891 if (isA_CFString(name
)) {
892 servicePrivate
->name
= CFRetain(name
);
896 interface
= SCNetworkServiceGetInterface(service
);
897 while (interface
!= NULL
) {
898 SCNetworkInterfaceRef childInterface
;
900 childInterface
= SCNetworkInterfaceGetInterface(interface
);
901 if ((childInterface
== NULL
) || CFEqual(childInterface
, kSCNetworkInterfaceIPv4
)) {
905 interface
= childInterface
;
908 if (interface
!= NULL
) {
910 CFStringRef interface_name
= NULL
;
911 CFStringRef suffix
= NULL
;
914 // check if the [stored] service name matches the non-localized interface
915 // name. If so, return the localized name.
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.
921 // Note: the user/admin will no longer be able to set the service name
922 // to "Built-in Ethernet".
924 for (i
= 0; i
< 3; i
++) {
925 if (servicePrivate
->name
== NULL
) {
926 // if no [stored] service name to compare
932 // compare the non-localized interface name
933 interface_name
= __SCNetworkInterfaceGetNonLocalizedDisplayName(interface
);
934 if (interface_name
!= NULL
) {
935 CFRetain(interface_name
);
939 // compare the older "Built-in XXX" localized name
940 interface_name
= __SCNetworkInterfaceCopyXLocalizedDisplayName(interface
);
943 // compare the older "Built-in XXX" non-localized name
944 interface_name
= __SCNetworkInterfaceCopyXNonLocalizedDisplayName(interface
);
948 if (interface_name
!= NULL
) {
949 Boolean match
= FALSE
;
951 if (CFEqual(name
, interface_name
)) {
952 // if service name matches the OLD localized
955 } else if (CFStringHasPrefix(name
, interface_name
)) {
956 CFIndex prefixLen
= CFStringGetLength(interface_name
);
957 CFIndex suffixLen
= CFStringGetLength(name
);
959 suffix
= CFStringCreateWithSubstring(NULL
,
961 CFRangeMake(prefixLen
, suffixLen
- prefixLen
));
964 CFRelease(interface_name
);
967 CFRelease(servicePrivate
->name
);
968 servicePrivate
->name
= NULL
;
975 // if the service name has not been set, use the localized interface name
977 if (servicePrivate
->name
== NULL
) {
978 interface_name
= SCNetworkInterfaceGetLocalizedDisplayName(interface
);
979 if (interface_name
!= NULL
) {
980 if (suffix
!= NULL
) {
981 servicePrivate
->name
= CFStringCreateWithFormat(NULL
,
987 servicePrivate
->name
= CFRetain(interface_name
);
991 if (suffix
!= NULL
) CFRelease(suffix
);
994 return servicePrivate
->name
;
999 SCNetworkServiceGetServiceID(SCNetworkServiceRef service
)
1001 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1003 if (!isA_SCNetworkService(service
)) {
1004 _SCErrorSet(kSCStatusInvalidArgument
);
1008 return servicePrivate
->serviceID
;
1013 SCNetworkServiceGetTypeID(void)
1015 pthread_once(&initialized
, __SCNetworkServiceInitialize
); /* initialize runtime */
1016 return __kSCNetworkServiceTypeID
;
1021 SCNetworkServiceRemove(SCNetworkServiceRef service
)
1025 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1028 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
1029 _SCErrorSet(kSCStatusInvalidArgument
);
1033 // remove service from all sets
1035 sets
= SCNetworkSetCopyAll(servicePrivate
->prefs
);
1040 n
= CFArrayGetCount(sets
);
1041 for (i
= 0; i
< n
; i
++) {
1042 SCNetworkSetRef set
;
1044 set
= CFArrayGetValueAtIndex(sets
, i
);
1045 ok
= SCNetworkSetRemoveService(set
, service
);
1046 if (!ok
&& (SCError() != kSCStatusNoKey
)) {
1056 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
1057 servicePrivate
->serviceID
, // service
1059 ok
= SCPreferencesPathRemoveValue(servicePrivate
->prefs
, path
);
1067 SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service
, CFStringRef protocolType
)
1069 CFDictionaryRef entity
;
1072 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1074 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
1075 _SCErrorSet(kSCStatusInvalidArgument
);
1079 if (!__SCNetworkProtocolIsValidType(protocolType
)) {
1080 _SCErrorSet(kSCStatusInvalidArgument
);
1084 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
1085 servicePrivate
->serviceID
, // service
1086 protocolType
); // entity
1088 entity
= SCPreferencesPathGetValue(servicePrivate
->prefs
, path
);
1089 if (entity
== NULL
) {
1090 // if "protocol" does not exist
1091 _SCErrorSet(kSCStatusNoKey
);
1095 ok
= SCPreferencesPathRemoveValue(servicePrivate
->prefs
, path
);
1105 SCNetworkServiceSetEnabled(SCNetworkServiceRef service
, Boolean enabled
)
1109 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1111 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
1112 _SCErrorSet(kSCStatusInvalidArgument
);
1116 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
1117 servicePrivate
->serviceID
, // service
1119 ok
= __setPrefsEnabled(servicePrivate
->prefs
, path
, enabled
);
1127 SCNetworkServiceSetName(SCNetworkServiceRef service
, CFStringRef name
)
1129 CFDictionaryRef entity
;
1132 CFStringRef saveName
= NULL
;
1133 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1135 if (!isA_SCNetworkService(service
) || (servicePrivate
->prefs
== NULL
)) {
1136 _SCErrorSet(kSCStatusInvalidArgument
);
1141 if (!isA_CFString(name
)) {
1142 _SCErrorSet(kSCStatusInvalidArgument
);
1145 saveName
= CFRetain(name
);
1149 SCNetworkInterfaceRef interface
;
1151 interface
= SCNetworkServiceGetInterface(service
);
1152 while (interface
!= NULL
) {
1153 SCNetworkInterfaceRef childInterface
;
1155 childInterface
= SCNetworkInterfaceGetInterface(interface
);
1156 if (childInterface
== NULL
) {
1160 interface
= childInterface
;
1163 if (interface
!= NULL
) {
1164 CFStringRef interface_name
;
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
);
1176 } else if (CFStringHasPrefix(name
, interface_name
)) {
1177 CFIndex prefixLen
= CFStringGetLength(interface_name
);
1179 CFIndex suffixLen
= CFStringGetLength(name
);
1181 // if service name matches the localized interface name plus
1182 // a few extra characters) then store the non-localized name with
1184 suffix
= CFStringCreateWithSubstring(NULL
,
1186 CFRangeMake(prefixLen
, suffixLen
- prefixLen
));
1187 interface_name
= __SCNetworkInterfaceGetNonLocalizedDisplayName(interface
);
1188 if (interface_name
!= NULL
) {
1189 CFRelease(saveName
);
1190 saveName
= CFStringCreateWithFormat(NULL
,
1202 #define PREVENT_DUPLICATE_SERVICE_NAMES
1203 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
1207 // ensure that each service is uniquely named within its sets
1209 sets
= SCNetworkSetCopyAll(servicePrivate
->prefs
);
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
);
1223 services
= SCNetworkSetCopyServices(set
);
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
;
1231 otherService
= CFArrayGetValueAtIndex(services
, service_index
);
1233 otherID
= SCNetworkServiceGetServiceID(otherService
);
1234 if (CFEqual(servicePrivate
->serviceID
, otherID
)) {
1235 // if the service is a member of this set
1240 otherName
= SCNetworkServiceGetName(otherService
);
1241 if ((otherName
!= NULL
) && CFEqual(name
, otherName
)) {
1247 CFRelease(services
);
1249 if (isMember
&& isDup
) {
1251 * if this service is a member of the set and
1252 * the "name" is not unique.
1255 if (saveName
!= NULL
) CFRelease(saveName
);
1256 _SCErrorSet(kSCStatusKeyExists
);
1264 #endif /* PREVENT_DUPLICATE_SERVICE_NAMES */
1266 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
1267 servicePrivate
->serviceID
, // service
1269 entity
= SCPreferencesPathGetValue(servicePrivate
->prefs
, path
);
1270 if (isA_CFDictionary(entity
) ||
1271 ((entity
== NULL
) && (name
!= NULL
))) {
1272 CFMutableDictionaryRef newEntity
;
1274 if (entity
!= NULL
) {
1275 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1277 newEntity
= CFDictionaryCreateMutable(NULL
,
1279 &kCFTypeDictionaryKeyCallBacks
,
1280 &kCFTypeDictionaryValueCallBacks
);
1282 if (saveName
!= NULL
) {
1283 CFDictionarySetValue(newEntity
, kSCPropUserDefinedName
, saveName
);
1285 CFDictionaryRemoveValue(newEntity
, kSCPropUserDefinedName
);
1287 ok
= SCPreferencesPathSetValue(servicePrivate
->prefs
, path
, newEntity
);
1288 CFRelease(newEntity
);
1291 if (saveName
!= NULL
) CFRelease(saveName
);
1293 if (servicePrivate
->name
!= NULL
) CFRelease(servicePrivate
->name
);
1294 if (name
!= NULL
) CFRetain(name
);
1295 servicePrivate
->name
= name
;
1302 #pragma mark SCNetworkService SPIs
1306 str_to_rank(CFStringRef rankStr
, SCNetworkServicePrimaryRank
*rank
)
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
;
1318 } else if (rankStr
== NULL
) {
1319 *rank
= kSCNetworkServicePrimaryRankDefault
;
1328 SCNetworkServicePrimaryRank
1329 SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service
)
1331 CFDictionaryRef entity
;
1334 SCNetworkServicePrimaryRank rank
= kSCNetworkServicePrimaryRankDefault
;
1335 CFStringRef rankStr
= NULL
;
1336 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1338 if (!isA_SCNetworkService(service
)) {
1339 _SCErrorSet(kSCStatusInvalidArgument
);
1343 if (servicePrivate
->prefs
!= NULL
) {
1344 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
,
1345 servicePrivate
->serviceID
,
1347 entity
= SCPreferencesPathGetValue(servicePrivate
->prefs
, path
);
1349 if (isA_CFDictionary(entity
)) {
1350 rankStr
= CFDictionaryGetValue(entity
, kSCPropNetServicePrimaryRank
);
1351 ok
= str_to_rank(rankStr
, &rank
);
1353 } else if (servicePrivate
->store
!= NULL
) {
1354 path
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1355 kSCDynamicStoreDomainState
,
1356 servicePrivate
->serviceID
,
1358 entity
= SCDynamicStoreCopyValue(servicePrivate
->store
, path
);
1360 if (entity
!= NULL
) {
1361 if (isA_CFDictionary(entity
)) {
1362 rankStr
= CFDictionaryGetValue(entity
, kSCPropNetServicePrimaryRank
);
1363 ok
= str_to_rank(rankStr
, &rank
);
1368 _SCErrorSet(kSCStatusInvalidArgument
);
1373 rank
= kSCNetworkServicePrimaryRankDefault
;
1374 _SCErrorSet(kSCStatusInvalidArgument
);
1375 } else if (rank
== kSCNetworkServicePrimaryRankDefault
) {
1376 _SCErrorSet(kSCStatusOK
);
1384 rank_to_str(SCNetworkServicePrimaryRank rank
, CFStringRef
*rankStr
)
1387 case kSCNetworkServicePrimaryRankDefault
:
1390 case kSCNetworkServicePrimaryRankFirst
:
1391 *rankStr
= kSCValNetServicePrimaryRankFirst
;
1393 case kSCNetworkServicePrimaryRankLast
:
1394 *rankStr
= kSCValNetServicePrimaryRankLast
;
1396 case kSCNetworkServicePrimaryRankNever
:
1397 *rankStr
= kSCValNetServicePrimaryRankNever
;
1408 SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service
,
1409 SCNetworkServicePrimaryRank newRank
)
1412 CFDictionaryRef entity
;
1413 CFMutableDictionaryRef newEntity
;
1414 CFStringRef path
= NULL
;
1415 CFStringRef rankStr
= NULL
;
1416 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
1418 if (!isA_SCNetworkService(service
)) {
1419 _SCErrorSet(kSCStatusInvalidArgument
);
1423 ok
= rank_to_str(newRank
, &rankStr
);
1425 _SCErrorSet(kSCStatusInvalidArgument
);
1429 if (servicePrivate
->prefs
!= NULL
) {
1430 if ((newRank
== kSCNetworkServicePrimaryRankDefault
) || (newRank
== kSCNetworkServicePrimaryRankNever
)) {
1431 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
,
1432 servicePrivate
->serviceID
,
1434 entity
= SCPreferencesPathGetValue(servicePrivate
->prefs
, path
);
1435 if (entity
!= NULL
) {
1436 if (!isA_CFDictionary(entity
)) {
1438 _SCErrorSet(kSCStatusFailed
);
1441 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1443 newEntity
= CFDictionaryCreateMutable(NULL
,
1445 &kCFTypeDictionaryKeyCallBacks
,
1446 &kCFTypeDictionaryValueCallBacks
);
1448 if (rankStr
!= NULL
) {
1449 CFDictionarySetValue(newEntity
, kSCPropNetServicePrimaryRank
, rankStr
);
1451 CFDictionaryRemoveValue(newEntity
, kSCPropNetServicePrimaryRank
);
1453 if (CFDictionaryGetCount(newEntity
) > 0) {
1454 ok
= SCPreferencesPathSetValue(servicePrivate
->prefs
, path
, newEntity
);
1456 ok
= SCPreferencesPathRemoveValue(servicePrivate
->prefs
, path
);
1458 CFRelease(newEntity
);
1463 _SCErrorSet(kSCStatusInvalidArgument
);
1466 } else if (servicePrivate
->store
!= NULL
) {
1467 path
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1468 kSCDynamicStoreDomainState
,
1469 servicePrivate
->serviceID
,
1471 entity
= SCDynamicStoreCopyValue(servicePrivate
->store
, path
);
1472 if (entity
!= NULL
) {
1473 if (!isA_CFDictionary(entity
)) {
1476 _SCErrorSet(kSCStatusFailed
);
1479 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1482 newEntity
= CFDictionaryCreateMutable(NULL
,
1484 &kCFTypeDictionaryKeyCallBacks
,
1485 &kCFTypeDictionaryValueCallBacks
);
1487 if (rankStr
!= NULL
) {
1488 CFDictionarySetValue(newEntity
, kSCPropNetServicePrimaryRank
, rankStr
);
1490 CFDictionaryRemoveValue(newEntity
, kSCPropNetServicePrimaryRank
);
1492 if (CFDictionaryGetCount(newEntity
) > 0) {
1493 ok
= SCDynamicStoreSetValue(servicePrivate
->store
, path
, newEntity
);
1495 ok
= SCDynamicStoreRemoveValue(servicePrivate
->store
, path
);
1497 CFRelease(newEntity
);
1502 _SCErrorSet(kSCStatusInvalidArgument
);
1508 if (path
!= NULL
) CFRelease(path
);