1/*
2 * Copyright (c) 2004-2008 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
42static CFStringRef	__SCNetworkProtocolCopyDescription	(CFTypeRef cf);
43static void		__SCNetworkProtocolDeallocate		(CFTypeRef cf);
44static Boolean		__SCNetworkProtocolEqual		(CFTypeRef cf1, CFTypeRef cf2);
45static CFHashCode	__SCNetworkProtocolHash			(CFTypeRef cf);
46
47
48#if	!TARGET_OS_IPHONE
49const CFStringRef kSCNetworkProtocolTypeAppleTalk       = CFSTR("AppleTalk");
50#endif	// !TARGET_OS_IPHONE
51const CFStringRef kSCNetworkProtocolTypeDNS		= CFSTR("DNS");
52const CFStringRef kSCNetworkProtocolTypeIPv4		= CFSTR("IPv4");
53const CFStringRef kSCNetworkProtocolTypeIPv6		= CFSTR("IPv6");
54const CFStringRef kSCNetworkProtocolTypeProxies		= CFSTR("Proxies");
55#if	!TARGET_OS_IPHONE
56const CFStringRef kSCNetworkProtocolTypeSMB		= CFSTR("SMB");
57#endif	// !TARGET_OS_IPHONE
58
59
60static CFTypeID __kSCNetworkProtocolTypeID	= _kCFRuntimeNotATypeID;
61
62
63static const CFRuntimeClass __SCNetworkProtocolClass = {
64	0,					// version
65	"SCNetworkProtocol",			// className
66	NULL,					// init
67	NULL,					// copy
68	__SCNetworkProtocolDeallocate,		// dealloc
69	__SCNetworkProtocolEqual,		// equal
70	__SCNetworkProtocolHash,		// hash
71	NULL,					// copyFormattingDesc
72	__SCNetworkProtocolCopyDescription	// copyDebugDesc
73};
74
75
76static pthread_once_t		initialized	= PTHREAD_ONCE_INIT;
77
78
79static CFStringRef
80__SCNetworkProtocolCopyDescription(CFTypeRef cf)
81{
82	CFAllocatorRef			allocator	= CFGetAllocator(cf);
83	CFMutableStringRef		result;
84	SCNetworkProtocolPrivateRef	protocolPrivate	= (SCNetworkProtocolPrivateRef)cf;
85
86	result = CFStringCreateMutable(allocator, 0);
87	CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkProtocol %p [%p]> {"), cf, allocator);
88	CFStringAppendFormat(result, NULL, CFSTR("id = %@"), protocolPrivate->entityID);
89	CFStringAppendFormat(result, NULL, CFSTR(", service = %p"), protocolPrivate->service);
90	CFStringAppendFormat(result, NULL,
91			     CFSTR(", prefs = %p"),
92			     ((SCNetworkServicePrivateRef)protocolPrivate->service)->prefs);
93	CFStringAppendFormat(result, NULL, CFSTR("}"));
94
95	return result;
96}
97
98
99static void
100__SCNetworkProtocolDeallocate(CFTypeRef cf)
101{
102	SCNetworkProtocolPrivateRef	protocolPrivate	= (SCNetworkProtocolPrivateRef)cf;
103
104	/* release resources */
105	CFRelease(protocolPrivate->entityID);
106	CFRelease(protocolPrivate->service);
107
108	return;
109}
110
111
112static Boolean
113__SCNetworkProtocolEqual(CFTypeRef cf1, CFTypeRef cf2)
114{
115	SCNetworkProtocolPrivateRef	p1	= (SCNetworkProtocolPrivateRef)cf1;
116	SCNetworkProtocolPrivateRef	p2	= (SCNetworkProtocolPrivateRef)cf2;
117
118	if (p1 == p2)
119		return TRUE;
120
121	if (!CFEqual(p1->entityID, p2->entityID))
122		return FALSE;	// if not the same protocol type
123
124	if (p1->service == p2->service)
125		return TRUE;    // if both point to the same service
126
127	if ((p1->service != NULL) && (p2->service != NULL) && CFEqual(p1->service, p2->service))
128		return TRUE;    // if both effectively point to the same service
129
130	return FALSE;
131}
132
133
134static CFHashCode
135__SCNetworkProtocolHash(CFTypeRef cf)
136{
137	SCNetworkProtocolPrivateRef	protocolPrivate	= (SCNetworkProtocolPrivateRef)cf;
138
139	return CFHash(protocolPrivate->entityID);
140}
141
142
143static void
144__SCNetworkProtocolInitialize(void)
145{
146	__kSCNetworkProtocolTypeID = _CFRuntimeRegisterClass(&__SCNetworkProtocolClass);
147	return;
148}
149
150
151__private_extern__ SCNetworkProtocolPrivateRef
152__SCNetworkProtocolCreatePrivate(CFAllocatorRef		allocator,
153				 CFStringRef		entityID,
154				 SCNetworkServiceRef	service)
155{
156	SCNetworkProtocolPrivateRef		protocolPrivate;
157	uint32_t				size;
158
159	/* initialize runtime */
160	pthread_once(&initialized, __SCNetworkProtocolInitialize);
161
162	/* allocate target */
163	size           = sizeof(SCNetworkProtocolPrivate) - sizeof(CFRuntimeBase);
164	protocolPrivate = (SCNetworkProtocolPrivateRef)_CFRuntimeCreateInstance(allocator,
165									      __kSCNetworkProtocolTypeID,
166									      size,
167									      NULL);
168	if (protocolPrivate == NULL) {
169		return NULL;
170	}
171
172	protocolPrivate->entityID       = CFStringCreateCopy(NULL, entityID);
173	protocolPrivate->service	= CFRetain(service);
174
175	return protocolPrivate;
176}
177
178
179__private_extern__ Boolean
180__SCNetworkProtocolIsValidType(CFStringRef protocolType)
181{
182	int				i;
183	static const CFStringRef	*valid_types[]   = {
184#if	!TARGET_OS_IPHONE
185		&kSCNetworkProtocolTypeAppleTalk,
186#endif	// !TARGET_OS_IPHONE
187		&kSCNetworkProtocolTypeDNS,
188		&kSCNetworkProtocolTypeIPv4,
189		&kSCNetworkProtocolTypeIPv6,
190		&kSCNetworkProtocolTypeProxies,
191#if	!TARGET_OS_IPHONE
192		&kSCNetworkProtocolTypeSMB,
193#endif	// !TARGET_OS_IPHONE
194	};
195
196	for (i = 0; i < sizeof(valid_types)/sizeof(valid_types[0]); i++) {
197		if (CFEqual(protocolType, *valid_types[i])) {
198			// if known/valid protocol type
199			return TRUE;
200		}
201	}
202
203	if (CFStringFindWithOptions(protocolType,
204				    CFSTR("."),
205				    CFRangeMake(0, CFStringGetLength(protocolType)),
206				    0,
207				    NULL)) {
208		// if user-defined protocol type (e.g. com.apple.myProtocol)
209		return TRUE;
210	}
211
212	return FALSE;
213}
214
215
216static CFStringRef
217copyProtocolConfigurationPath(SCNetworkProtocolPrivateRef protocolPrivate)
218{
219	CFStringRef			path;
220	SCNetworkServicePrivateRef      servicePrivate;
221
222	servicePrivate = (SCNetworkServicePrivateRef)protocolPrivate->service;
223	path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,				// allocator
224							      servicePrivate->serviceID,	// service
225							      protocolPrivate->entityID);       // entity
226	return path;
227}
228
229
230#pragma mark -
231#pragma mark SCNetworkProtocol APIs
232
233
234CFTypeID
235SCNetworkProtocolGetTypeID()
236{
237	pthread_once(&initialized, __SCNetworkProtocolInitialize);	/* initialize runtime */
238	return __kSCNetworkProtocolTypeID;
239}
240
241
242CFDictionaryRef
243SCNetworkProtocolGetConfiguration(SCNetworkProtocolRef protocol)
244{
245	CFDictionaryRef			config;
246	CFStringRef			path;
247	SCNetworkProtocolPrivateRef	protocolPrivate	= (SCNetworkProtocolPrivateRef)protocol;
248	SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)protocolPrivate->service;
249
250	if (!isA_SCNetworkProtocol(protocol)) {
251		_SCErrorSet(kSCStatusInvalidArgument);
252		return NULL;
253	}
254
255	path = copyProtocolConfigurationPath(protocolPrivate);
256	config = __getPrefsConfiguration(servicePrivate->prefs, path);
257	CFRelease(path);
258
259	return config;
260}
261
262
263Boolean
264SCNetworkProtocolGetEnabled(SCNetworkProtocolRef protocol)
265{
266	Boolean				enabled;
267	CFStringRef			path;
268	SCNetworkProtocolPrivateRef	protocolPrivate	= (SCNetworkProtocolPrivateRef)protocol;
269	SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)protocolPrivate->service;
270
271	if (!isA_SCNetworkProtocol(protocol)) {
272		_SCErrorSet(kSCStatusInvalidArgument);
273		return FALSE;
274	}
275
276	path = copyProtocolConfigurationPath(protocolPrivate);
277	enabled = __getPrefsEnabled(servicePrivate->prefs, path);
278	CFRelease(path);
279
280	return enabled;
281}
282
283
284CFStringRef
285SCNetworkProtocolGetProtocolType(SCNetworkProtocolRef protocol)
286{
287	SCNetworkProtocolPrivateRef	protocolPrivate	= (SCNetworkProtocolPrivateRef)protocol;
288
289	if (!isA_SCNetworkProtocol(protocol)) {
290		_SCErrorSet(kSCStatusInvalidArgument);
291		return NULL;
292	}
293
294	return protocolPrivate->entityID;
295}
296
297
298Boolean
299SCNetworkProtocolSetConfiguration(SCNetworkProtocolRef protocol, CFDictionaryRef config)
300{
301	Boolean				ok;
302	CFStringRef			path;
303	SCNetworkProtocolPrivateRef	protocolPrivate	= (SCNetworkProtocolPrivateRef)protocol;
304	SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)protocolPrivate->service;
305
306	if (!isA_SCNetworkProtocol(protocol)) {
307		_SCErrorSet(kSCStatusInvalidArgument);
308		return FALSE;
309	}
310
311	path = copyProtocolConfigurationPath(protocolPrivate);
312	ok = __setPrefsConfiguration(servicePrivate->prefs, path, config, TRUE);
313	CFRelease(path);
314
315	return ok;
316}
317
318
319Boolean
320SCNetworkProtocolSetEnabled(SCNetworkProtocolRef protocol, Boolean enabled)
321{
322	Boolean				ok;
323	CFStringRef			path;
324	SCNetworkProtocolPrivateRef	protocolPrivate	= (SCNetworkProtocolPrivateRef)protocol;
325	SCNetworkServicePrivateRef      servicePrivate  = (SCNetworkServicePrivateRef)protocolPrivate->service;
326
327	if (!isA_SCNetworkProtocol(protocol)) {
328		_SCErrorSet(kSCStatusInvalidArgument);
329		return FALSE;
330	}
331
332	path = copyProtocolConfigurationPath(protocolPrivate);
333	ok = __setPrefsEnabled(servicePrivate->prefs, path, enabled);
334	CFRelease(path);
335
336	return ok;
337}
338