1/*
2 * Copyright (c) 2004-2014 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 *	which includes code originally authored by
30 *	  Robert Ulrich		<rulrich@apple.com>
31 *	  Elizabeth Douglas	<elizabeth@apple.com>
32 *	  Quinn			<eskimo1@apple.com>
33 */
34
35
36#include <Availability.h>
37#include <TargetConditionals.h>
38#include <CoreFoundation/CoreFoundation.h>
39#include <CoreFoundation/CFRuntime.h>
40#include <SystemConfiguration/SystemConfiguration.h>
41#include "SCNetworkConfigurationInternal.h"
42#include <SystemConfiguration/SCValidation.h>
43#include <SystemConfiguration/SCPrivate.h>
44#include "SCPreferencesInternal.h"
45#include "SCHelper_client.h"
46
47#if	!TARGET_OS_IPHONE
48#include <EAP8021X/EAPClientProperties.h>
49#else	// !TARGET_OS_IPHONE
50#ifndef	kEAPClientPropUserName
51#define kEAPClientPropUserName CFSTR("UserName")
52#endif
53#ifndef	kEAPClientPropUserPasswordKeychainItemID
54#define kEAPClientPropUserPasswordKeychainItemID CFSTR("UserPasswordKeychainItemID")
55#endif
56#endif	// !TARGET_OS_IPHONE
57
58#include <IOKit/IOKitLib.h>
59#include <IOKit/IOCFBundle.h>
60#include <IOKit/IOBSD.h>
61#include <IOKit/network/IONetworkController.h>
62#include <IOKit/network/IONetworkInterface.h>
63#include <IOKit/network/IOEthernetInterface.h>	// for kIOEthernetInterfaceClass
64#include <IOKit/serial/IOSerialKeys.h>
65#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
66#if	!TARGET_IPHONE_SIMULATOR
67#include <IOKit/usb/USB.h>
68#endif	// !TARGET_IPHONE_SIMULATOR
69
70#include "dy_framework.h"
71
72#ifndef	kIODeviceSupportsHoldKey
73#define	kIODeviceSupportsHoldKey	"V92Modem"
74#endif
75
76#ifndef	kPCIThunderboltString
77#define kPCIThunderboltString		"PCI-Thunderbolt"
78#endif
79
80#ifndef	kIOUserEthernetInterfaceRoleKey
81#define	kIOUserEthernetInterfaceRoleKey	"InterfaceRole"
82#endif
83
84#include <string.h>
85#include <mach/mach.h>
86#include <net/if.h>
87#include <net/if_types.h>
88#include <net/route.h>
89#include <sys/ioctl.h>
90#include <sys/param.h>
91#include <sys/types.h>
92#include <sys/socket.h>
93#include <sys/stat.h>
94#include <sys/sysctl.h>
95#include <pthread.h>
96#include <NSSystemDirectories.h>
97
98
99static CFStringRef	copy_interface_string				(CFBundleRef bundle, CFStringRef key, Boolean localized);
100static CFStringRef	__SCNetworkInterfaceCopyFormattingDescription	(CFTypeRef cf, CFDictionaryRef formatOptions);
101static void		__SCNetworkInterfaceDeallocate			(CFTypeRef cf);
102static Boolean		__SCNetworkInterfaceEqual			(CFTypeRef cf1, CFTypeRef cf2);
103static CFHashCode	__SCNetworkInterfaceHash			(CFTypeRef cf);
104
105
106enum {
107	kSortInternalModem,
108	kSortUSBModem,
109	kSortModem,
110	kSortBluetooth,
111	kSortIrDA,
112	kSortSerialPort,
113	kSortWWAN,
114	kSortEthernetPPP,
115	kSortAirportPPP,
116	kSortEthernet,
117	kSortFireWire,
118	kSortAirPort,
119	kSortOtherWireless,
120	kSortTethered,
121	kSortWWANEthernet,
122	kSortBluetoothPAN_GN,
123	kSortBluetoothPAN_NAP,
124	kSortBluetoothPAN_U,
125	kSortThunderbolt,
126	kSortBond,
127	kSortBridge,
128	kSortVLAN,
129	kSortUnknown
130};
131
132
133const CFStringRef kSCNetworkInterfaceType6to4		= CFSTR("6to4");
134const CFStringRef kSCNetworkInterfaceTypeBluetooth	= CFSTR("Bluetooth");
135const CFStringRef kSCNetworkInterfaceTypeBond		= CFSTR("Bond");
136const CFStringRef kSCNetworkInterfaceTypeBridge		= CFSTR("Bridge");
137const CFStringRef kSCNetworkInterfaceTypeEthernet	= CFSTR("Ethernet");
138const CFStringRef kSCNetworkInterfaceTypeFireWire	= CFSTR("FireWire");
139const CFStringRef kSCNetworkInterfaceTypeIEEE80211	= CFSTR("IEEE80211");	// IEEE 802.11, AirPort
140const CFStringRef kSCNetworkInterfaceTypeIPSec		= CFSTR("IPSec");
141const CFStringRef kSCNetworkInterfaceTypeIrDA		= CFSTR("IrDA");
142const CFStringRef kSCNetworkInterfaceTypeL2TP		= CFSTR("L2TP");
143const CFStringRef kSCNetworkInterfaceTypeLoopback	= CFSTR("Loopback");
144const CFStringRef kSCNetworkInterfaceTypeModem		= CFSTR("Modem");
145const CFStringRef kSCNetworkInterfaceTypePPP		= CFSTR("PPP");
146const CFStringRef kSCNetworkInterfaceTypePPTP		= CFSTR("PPTP");
147const CFStringRef kSCNetworkInterfaceTypeSerial		= CFSTR("Serial");
148const CFStringRef kSCNetworkInterfaceTypeVLAN		= CFSTR("VLAN");
149const CFStringRef kSCNetworkInterfaceTypeVPN		= CFSTR("VPN");
150const CFStringRef kSCNetworkInterfaceTypeWWAN		= CFSTR("WWAN");
151
152const CFStringRef kSCNetworkInterfaceTypeIPv4		= CFSTR("IPv4");
153
154static SCNetworkInterfacePrivate __kSCNetworkInterfaceIPv4	= {
155	INIT_CFRUNTIME_BASE(),			// cfBase
156	NULL,					// interface type
157	FALSE,					// active
158	NULL,					// name
159	NULL,					// localized name
160	NULL,					// localization key
161	NULL,					// localization arg1
162	NULL,					// localization arg2
163	NULL,					// [layered] interface
164	NULL,					// prefs
165	NULL,					// store
166	NULL,					// serviceID
167	NULL,					// unsaved
168	NULL,					// entity_device
169	NULL,					// entity_device_unique
170	NULL,					// entity_type
171	NULL,					// entity_subtype
172	NULL,					// supported_interface_types
173	NULL,					// supported_protocol_types
174	NULL,					// address
175	NULL,					// addressString
176	FALSE,					// builtin
177	NULL,					// configurationAction
178	FALSE,					// hidden
179	NULL,					// location
180	NULL,					// path
181	0,					// entryID
182	NULL,					// overrides
183	FALSE,					// modemIsV92
184	NULL,					// name prefix
185	NULL,					// type
186	NULL,					// unit
187	{ NULL, 0, 0 },				// usb { name, vid, pid }
188	kSortUnknown,				// sort_order
189	FALSE,					// supportsBond
190	{ NULL, NULL, NULL },			// bond { interfaces, mode, options }
191	FALSE,					// supportsBridge
192	{ NULL, NULL },				// bridge { interfaces, options }
193	FALSE,					// supportsVLAN
194	{ NULL, NULL, NULL },			// vlan { interface, tag, options }
195#if	!TARGET_IPHONE_SIMULATOR
196	NULL,					// IPMonitorControl
197#endif	// !TARGET_IPHONE_SIMULATOR
198};
199
200const SCNetworkInterfaceRef kSCNetworkInterfaceIPv4	= (SCNetworkInterfaceRef)&__kSCNetworkInterfaceIPv4;
201
202static SCNetworkInterfacePrivate __kSCNetworkInterfaceLoopback	= {
203	INIT_CFRUNTIME_BASE(),			// cfBase
204	NULL,					// interface type
205	FALSE,					// active
206	NULL,					// name
207	NULL,					// localized name
208	NULL,					// localization key
209	NULL,					// localization arg1
210	NULL,					// localization arg2
211	NULL,					// [layered] interface
212	NULL,					// prefs
213	NULL,					// store
214	NULL,					// serviceID
215	NULL,					// unsaved
216	NULL,					// entity_device
217	NULL,					// entity_device_unique
218	NULL,					// entity_type
219	NULL,					// entity_subtype
220	NULL,					// supported_interface_types
221	NULL,					// supported_protocol_types
222	NULL,					// address
223	NULL,					// addressString
224	FALSE,					// builtin
225	NULL,					// configurationAction
226	FALSE,					// hidden
227	NULL,					// location
228	NULL,					// path
229	0,					// entryID
230	NULL,					// overrides
231	FALSE,					// modemIsV92
232	NULL,					// name prefix
233	NULL,					// type
234	NULL,					// unit
235	{ NULL, 0, 0 },				// usb { name, vid, pid }
236	kSortUnknown,				// sort_order
237	FALSE,					// supportsBond
238	{ NULL, NULL, NULL },			// bond { interfaces, mode, options }
239	FALSE,					// supportsBridge
240	{ NULL, NULL },				// bridge { interfaces, options }
241	FALSE,					// supportsVLAN
242	{ NULL, NULL, NULL },			// vlan { interface, tag, options }
243#if	!TARGET_IPHONE_SIMULATOR
244	NULL,					// IPMonitorControl
245#endif	// !TARGET_IPHONE_SIMULATOR
246};
247
248const SCNetworkInterfaceRef kSCNetworkInterfaceLoopback	= (SCNetworkInterfaceRef)&__kSCNetworkInterfaceLoopback;
249
250static CFMutableSetRef	vendor_interface_types	= NULL;
251
252#pragma mark -
253#pragma mark SCNetworkInterface configuration details
254
255#define doNone		0
256
257#define do6to4		1<<0
258#define doL2TP		1<<1
259#define doPPP		1<<2
260#define doPPTP		1<<3
261#define doIPSec		1<<4
262#define doOverIP	do6to4|doL2TP|doPPTP|doIPSec
263
264#define doDNS		1<<1
265#define doIPv4		1<<2
266#define doIPv6		1<<3
267#define doProxies       1<<4
268#if	!TARGET_OS_IPHONE
269#define doSMB		1<<5
270#else	// !TARGET_OS_IPHONE
271#define doSMB		0
272#endif	// !TARGET_OS_IPHONE
273
274static const struct {
275	const CFStringRef       *interface_type;
276	const CFStringRef	*entity_hardware;
277	Boolean			per_interface_config;
278	uint32_t		supported_interfaces;
279	const CFStringRef       *ppp_subtype;
280	uint32_t		supported_protocols;
281} configurations[] = {
282	// interface type			  entity_hardware      if config? interface types PPP sub-type				interface protocols
283	// =====================================  ==================== ========== =============== ======================================= =========================================
284	{ &kSCNetworkInterfaceType6to4		, &kSCEntNet6to4      , FALSE,	doNone,		NULL,					doIPv6					},
285	{ &kSCNetworkInterfaceTypeBluetooth     , &kSCEntNetModem     , FALSE,	doPPP,		&kSCValNetInterfaceSubTypePPPSerial,    doNone					},
286	{ &kSCNetworkInterfaceTypeBond		, &kSCEntNetEthernet  , TRUE ,	doNone,		NULL,					doDNS|doIPv4|doIPv6|doProxies|doSMB	},
287	{ &kSCNetworkInterfaceTypeBridge	, &kSCEntNetEthernet  , TRUE ,	doNone,		NULL,					doDNS|doIPv4|doIPv6|doProxies|doSMB	},
288	{ &kSCNetworkInterfaceTypeEthernet      , &kSCEntNetEthernet  , TRUE ,	doPPP,		&kSCValNetInterfaceSubTypePPPoE,	doDNS|doIPv4|doIPv6|doProxies|doSMB	},
289	{ &kSCNetworkInterfaceTypeFireWire      , &kSCEntNetFireWire  , TRUE ,	doNone,		NULL,					doDNS|doIPv4|doIPv6|doProxies|doSMB	},
290	{ &kSCNetworkInterfaceTypeIEEE80211     , &kSCEntNetAirPort   , TRUE ,	doPPP,		&kSCValNetInterfaceSubTypePPPoE,	doDNS|doIPv4|doIPv6|doProxies|doSMB	},
291	{ &kSCNetworkInterfaceTypeIPSec		, &kSCEntNetIPSec     , FALSE,	doNone,		NULL,					doDNS|doIPv4|doIPv6|doProxies|doSMB	},
292	{ &kSCNetworkInterfaceTypeIrDA		, &kSCEntNetModem     , FALSE,	doPPP,		&kSCValNetInterfaceSubTypePPPSerial,    doNone					},
293	{ &kSCNetworkInterfaceTypeL2TP		, NULL                , FALSE,	doPPP,		&kSCValNetInterfaceSubTypeL2TP,		doNone					},
294	{ &kSCNetworkInterfaceTypeModem		, &kSCEntNetModem     , FALSE,	doPPP,		&kSCValNetInterfaceSubTypePPPSerial,    doNone					},
295	{ &kSCNetworkInterfaceTypePPP		, &kSCEntNetPPP       , FALSE,	doNone,		NULL,					doDNS|doIPv4|doIPv6|doProxies|doSMB	},
296	{ &kSCNetworkInterfaceTypePPTP		, NULL                , FALSE,	doPPP,		&kSCValNetInterfaceSubTypePPTP,		doNone					},
297	{ &kSCNetworkInterfaceTypeSerial	, &kSCEntNetModem     , FALSE,	doPPP,		&kSCValNetInterfaceSubTypePPPSerial,    doNone					},
298	{ &kSCNetworkInterfaceTypeVLAN		, &kSCEntNetEthernet  , TRUE ,	doNone,		NULL,					doDNS|doIPv4|doIPv6|doProxies|doSMB	},
299	{ &kSCNetworkInterfaceTypeVPN		, &kSCEntNetVPN       , FALSE,	doNone,		NULL,					doDNS|doIPv4|doIPv6|doProxies|doSMB	},
300	{ &kSCNetworkInterfaceTypeWWAN          , &kSCEntNetModem     , FALSE,	doPPP,		&kSCValNetInterfaceSubTypePPPSerial,    doNone					},
301	// =====================================  =================== ========== =============== ======================================= =========================================
302	{ &kSCNetworkInterfaceTypeLoopback	, NULL                , TRUE ,	doNone,		NULL,					doIPv4|doIPv6				},
303	// =====================================  =================== ========== =============== ======================================= =========================================
304	{ &kSCNetworkInterfaceTypeIPv4		, NULL                , FALSE,	doOverIP,	NULL,					doNone					}
305};
306
307
308#define kSCNetworkInterfaceActive			"Active"
309#define kSCNetworkInterfaceInfo				"SCNetworkInterfaceInfo"
310#define kSCNetworkInterfaceType				"SCNetworkInterfaceType"
311#define kSCNetworkInterfaceBSDName			kIOBSDNameKey
312#define kSCNetworkInterfaceIOBuiltin			kIOBuiltin
313#define kSCNetworkInterfaceIOInterfaceNamePrefix	kIOInterfaceNamePrefix
314#define kSCNetworkInterfaceIOInterfaceType		kIOInterfaceType
315#define kSCNetworkInterfaceIOInterfaceUnit		kIOInterfaceUnit
316#define kSCNetworkInterfaceIOMACAddress			kIOMACAddress
317#define kSCNetworkInterfaceIOPathMatch			kIOPathMatchKey
318
319
320#define	NETWORKINTERFACE_LOCALIZATIONS	CFSTR("NetworkInterface")
321static CFBundleRef bundle			= NULL;
322
323
324static CFTypeID __kSCNetworkInterfaceTypeID	= _kCFRuntimeNotATypeID;
325
326
327static const CFRuntimeClass __SCNetworkInterfaceClass = {
328	0,						// version
329	"SCNetworkInterface",				// className
330	NULL,						// init
331	NULL,						// copy
332	__SCNetworkInterfaceDeallocate,			// dealloc
333	__SCNetworkInterfaceEqual,			// equal
334	__SCNetworkInterfaceHash,			// hash
335	__SCNetworkInterfaceCopyFormattingDescription,	// copyFormattingDesc
336	NULL						// copyDebugDesc
337};
338
339
340static pthread_once_t		initialized	= PTHREAD_ONCE_INIT;
341static pthread_once_t		iokit_quiet	= PTHREAD_ONCE_INIT;
342
343
344static mach_port_t		masterPort	= MACH_PORT_NULL;
345
346
347static CFStringRef
348__SCNetworkInterfaceCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions)
349{
350	CFAllocatorRef			allocator		= CFGetAllocator(cf);
351	CFMutableStringRef		result;
352	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)cf;
353
354	result = CFStringCreateMutable(allocator, 0);
355	CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkInterface %p [%p]> {"), cf, allocator);
356	CFStringAppendFormat(result, NULL, CFSTR("type = %@"), interfacePrivate->interface_type);
357	CFStringAppendFormat(result, NULL, CFSTR(", entity_device = %@"), interfacePrivate->entity_device);
358	if (interfacePrivate->entity_device_unique != NULL) {
359		CFStringAppendFormat(result, NULL, CFSTR("+%@"), interfacePrivate->entity_device_unique);
360	}
361	CFStringAppendFormat(result, NULL, CFSTR(", entity_type = %@"), interfacePrivate->entity_type);
362	if (interfacePrivate->entity_subtype != NULL) {
363		CFStringAppendFormat(result, NULL, CFSTR(" / %@"), interfacePrivate->entity_subtype);
364	}
365	if (interfacePrivate->name != NULL) {
366		CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), interfacePrivate->name);
367	}
368	if (interfacePrivate->localized_name != NULL) {
369		CFStringAppendFormat(result, NULL, CFSTR(", name(l) = %@"), interfacePrivate->localized_name);
370	} else {
371		if (interfacePrivate->localized_key != NULL) {
372			CFStringAppendFormat(result, NULL, CFSTR(", name(k) = \"%@\""), interfacePrivate->localized_key);
373			if (interfacePrivate->localized_arg1 != NULL) {
374				CFStringAppendFormat(result, NULL, CFSTR("+\"%@\""), interfacePrivate->localized_arg1);
375			}
376			if (interfacePrivate->localized_arg2 != NULL) {
377				CFStringAppendFormat(result, NULL, CFSTR("+\"%@\""), interfacePrivate->localized_arg2);
378			}
379		}
380	}
381	if (interfacePrivate->address != NULL) {
382		const uint8_t		*data;
383		CFIndex			dataLen;
384		CFIndex			i;
385
386		CFStringAppendFormat(result, NULL, CFSTR(", address = 0x"));
387
388		data    = CFDataGetBytePtr(interfacePrivate->address);
389		dataLen = CFDataGetLength(interfacePrivate->address);
390		for (i = 0; i < dataLen; i++) {
391			CFStringAppendFormat(result, NULL, CFSTR("%02x"), data[i]);
392		}
393	}
394	CFStringAppendFormat(result, NULL, CFSTR(", builtin = %s"), interfacePrivate->builtin ? "TRUE" : "FALSE");
395	if (interfacePrivate->hidden) {
396		CFStringAppendFormat(result, NULL, CFSTR(", hidden = TRUE"));
397	}
398	if (interfacePrivate->modemIsV92) {
399		CFStringAppendFormat(result, NULL, CFSTR(", v.92"));
400	}
401	if (interfacePrivate->location != NULL) {
402		CFStringAppendFormat(result, NULL, CFSTR(", location = %@"), interfacePrivate->location);
403	}
404	if (interfacePrivate->path != NULL) {
405		CFStringAppendFormat(result, NULL, CFSTR(", path = %@"), interfacePrivate->path);
406	}
407	if (interfacePrivate->entryID != 0) {
408		CFStringAppendFormat(result, NULL, CFSTR(", entryID = 0x%llx"), interfacePrivate->entryID);
409	}
410	if (interfacePrivate->type != NULL) {
411		CFStringAppendFormat(result, NULL, CFSTR(", type = %@"), interfacePrivate->type);
412	}
413	if (interfacePrivate->unit != NULL) {
414		CFStringAppendFormat(result, NULL, CFSTR(", unit = %@"), interfacePrivate->unit);
415	}
416	if ((interfacePrivate->usb.vid != NULL) || (interfacePrivate->usb.pid != NULL)) {
417		int	pid	= 0;
418		int	vid	= 0;
419
420		if (!isA_CFNumber(interfacePrivate->usb.pid) ||
421		    !CFNumberGetValue(interfacePrivate->usb.pid, kCFNumberIntType, &pid)) {
422			pid = 0;
423		}
424		if (!isA_CFNumber(interfacePrivate->usb.vid) ||
425		    !CFNumberGetValue(interfacePrivate->usb.vid, kCFNumberIntType, &vid)) {
426			vid = 0;
427		}
428
429		if (interfacePrivate->usb.name != NULL) {
430			CFStringAppendFormat(result, NULL, CFSTR(", USB name = %@"),
431					     interfacePrivate->usb.name);
432		}
433
434		CFStringAppendFormat(result, NULL, CFSTR(", USB vid/pid = 0x%0x/0x%0x"),
435				     vid,
436				     pid);
437	}
438	if (interfacePrivate->configurationAction != NULL) {
439		CFStringAppendFormat(result, NULL, CFSTR(", action = %@"), interfacePrivate->configurationAction);
440	}
441	if (interfacePrivate->overrides != NULL) {
442		CFStringAppendFormat(result, formatOptions, CFSTR(", overrides = %p"), interfacePrivate->overrides);
443	}
444	CFStringAppendFormat(result, NULL, CFSTR(", order = %d"), interfacePrivate->sort_order);
445	if (interfacePrivate->prefs != NULL) {
446		CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), interfacePrivate->prefs);
447	}
448	if (interfacePrivate->serviceID != NULL) {
449		CFStringAppendFormat(result, NULL, CFSTR(", service = %@"), interfacePrivate->serviceID);
450	}
451	if (interfacePrivate->interface != NULL) {
452		CFStringAppendFormat(result, NULL, CFSTR(", interface = %@"), interfacePrivate->interface);
453	}
454	if (interfacePrivate->unsaved != NULL) {
455		CFStringAppendFormat(result, formatOptions, CFSTR(", unsaved = %@"), interfacePrivate->unsaved);
456	}
457
458	if (interfacePrivate->bond.interfaces != NULL) {
459		CFIndex	i;
460		CFIndex	n;
461
462		n = CFArrayGetCount(interfacePrivate->bond.interfaces);
463		for (i = 0; i < n; i++) {
464			SCNetworkInterfaceRef	member;
465
466			member = CFArrayGetValueAtIndex(interfacePrivate->bond.interfaces, i);
467			CFStringAppendFormat(result, NULL,
468					     CFSTR("%s%@"),
469					     (i == 0) ? ", interfaces = " : ",",
470					     SCNetworkInterfaceGetBSDName(member));
471		}
472	}
473	if (interfacePrivate->bond.mode != NULL) {
474		CFStringAppendFormat(result, NULL, CFSTR(", mode = %@"), interfacePrivate->bond.mode);
475	}
476	if (interfacePrivate->bond.options != NULL) {
477		CFStringRef	str;
478
479		str = _SCCopyDescription(interfacePrivate->bond.options, formatOptions);
480		CFStringAppendFormat(result, formatOptions, CFSTR(", options = %@"), str);
481		CFRelease(str);
482	}
483
484	if (interfacePrivate->bridge.interfaces != NULL) {
485		CFIndex	i;
486		CFIndex	n;
487
488		n = CFArrayGetCount(interfacePrivate->bridge.interfaces);
489		for (i = 0; i < n; i++) {
490			SCNetworkInterfaceRef	member;
491
492			member = CFArrayGetValueAtIndex(interfacePrivate->bridge.interfaces, i);
493			CFStringAppendFormat(result, NULL,
494					     CFSTR("%s%@"),
495					     (i == 0) ? ", interfaces = " : ",",
496					     SCNetworkInterfaceGetBSDName(member));
497		}
498	}
499	if (interfacePrivate->bridge.options != NULL) {
500		CFStringRef	str;
501
502		str = _SCCopyDescription(interfacePrivate->bridge.options, formatOptions);
503		CFStringAppendFormat(result, formatOptions, CFSTR(", options = %@"), str);
504		CFRelease(str);
505	}
506
507	if (interfacePrivate->vlan.interface != NULL) {
508		CFStringAppendFormat(result, NULL,
509				     CFSTR(", interface = %@"),
510				     SCNetworkInterfaceGetBSDName(interfacePrivate->vlan.interface));
511	}
512	if (interfacePrivate->vlan.tag != NULL) {
513		CFStringAppendFormat(result, NULL, CFSTR(", tag = %@"), interfacePrivate->vlan.tag);
514	}
515	if (interfacePrivate->vlan.options != NULL) {
516		CFStringRef	str;
517
518		str = _SCCopyDescription(interfacePrivate->vlan.options, formatOptions);
519		CFStringAppendFormat(result, formatOptions, CFSTR(", options = %@"), str);
520		CFRelease(str);
521	}
522
523	CFStringAppendFormat(result, NULL, CFSTR("}"));
524
525	return result;
526}
527
528
529static void
530__SCNetworkInterfaceDeallocate(CFTypeRef cf)
531{
532	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)cf;
533
534	/* release resources */
535
536	if (interfacePrivate->name != NULL)
537		CFRelease(interfacePrivate->name);
538
539	if (interfacePrivate->localized_name != NULL)
540		CFRelease(interfacePrivate->localized_name);
541
542	if (interfacePrivate->localized_arg1 != NULL)
543		CFRelease(interfacePrivate->localized_arg1);
544
545	if (interfacePrivate->localized_arg2 != NULL)
546		CFRelease(interfacePrivate->localized_arg2);
547
548	if (interfacePrivate->interface != NULL)
549		CFRelease(interfacePrivate->interface);
550
551	if (interfacePrivate->prefs != NULL)
552		CFRelease(interfacePrivate->prefs);
553
554	if (interfacePrivate->store != NULL)
555		CFRelease(interfacePrivate->store);
556
557	if (interfacePrivate->serviceID != NULL)
558		CFRelease(interfacePrivate->serviceID);
559
560	if (interfacePrivate->unsaved != NULL)
561		CFRelease(interfacePrivate->unsaved);
562
563	if (interfacePrivate->entity_device != NULL)
564		CFRelease(interfacePrivate->entity_device);
565
566	if (interfacePrivate->entity_device_unique != NULL)
567		CFRelease(interfacePrivate->entity_device_unique);
568
569	if (interfacePrivate->supported_interface_types != NULL)
570		CFRelease(interfacePrivate->supported_interface_types);
571
572	if (interfacePrivate->supported_protocol_types != NULL)
573		CFRelease(interfacePrivate->supported_protocol_types);
574
575	if (interfacePrivate->address != NULL)
576		CFRelease(interfacePrivate->address);
577
578	if (interfacePrivate->addressString != NULL)
579		CFRelease(interfacePrivate->addressString);
580
581	if (interfacePrivate->configurationAction != NULL)
582		CFRelease(interfacePrivate->configurationAction);
583
584	if (interfacePrivate->location != NULL)
585		CFRelease(interfacePrivate->location);
586
587	if (interfacePrivate->path != NULL)
588		CFRelease(interfacePrivate->path);
589
590	if (interfacePrivate->overrides != NULL)
591		CFRelease(interfacePrivate->overrides);
592
593	if (interfacePrivate->prefix != NULL)
594		CFRelease(interfacePrivate->prefix);
595
596	if (interfacePrivate->type != NULL)
597		CFRelease(interfacePrivate->type);
598
599	if (interfacePrivate->unit != NULL)
600		CFRelease(interfacePrivate->unit);
601
602	if (interfacePrivate->usb.name != NULL)
603		CFRelease(interfacePrivate->usb.name);
604
605	if (interfacePrivate->usb.pid != NULL)
606		CFRelease(interfacePrivate->usb.pid);
607
608	if (interfacePrivate->usb.vid != NULL)
609		CFRelease(interfacePrivate->usb.vid);
610
611	if (interfacePrivate->bond.interfaces != NULL)
612		CFRelease(interfacePrivate->bond.interfaces);
613
614	if (interfacePrivate->bond.mode != NULL)
615		CFRelease(interfacePrivate->bond.mode);
616
617	if (interfacePrivate->bond.options != NULL)
618		CFRelease(interfacePrivate->bond.options);
619
620	if (interfacePrivate->bridge.interfaces != NULL)
621		CFRelease(interfacePrivate->bridge.interfaces);
622
623	if (interfacePrivate->bridge.options != NULL)
624		CFRelease(interfacePrivate->bridge.options);
625
626	if (interfacePrivate->vlan.interface != NULL)
627		CFRelease(interfacePrivate->vlan.interface);
628
629	if (interfacePrivate->vlan.tag != NULL)
630		CFRelease(interfacePrivate->vlan.tag);
631
632	if (interfacePrivate->vlan.options != NULL)
633		CFRelease(interfacePrivate->vlan.options);
634#if	!TARGET_IPHONE_SIMULATOR
635	if (interfacePrivate->IPMonitorControl != NULL)
636		CFRelease(interfacePrivate->IPMonitorControl);
637#endif	// !TARGET_IPHONE_SIMULATOR
638	return;
639}
640
641
642static Boolean
643__SCNetworkInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2)
644{
645	SCNetworkInterfacePrivateRef	if1	= (SCNetworkInterfacePrivateRef)cf1;
646	SCNetworkInterfacePrivateRef	if2	= (SCNetworkInterfacePrivateRef)cf2;
647
648	if (if1 == if2)
649		return TRUE;
650
651	if (!CFEqual(if1->interface_type, if2->interface_type)) {
652		return FALSE;	// if not the same interface type
653	}
654
655	if (!_SC_CFEqual(if1->entity_device, if2->entity_device)) {
656		return FALSE; // if not the same device
657	}
658
659	if ((if1->entity_device_unique != NULL) && (if2->entity_device_unique != NULL)) {
660		if (!_SC_CFEqual(if1->entity_device_unique, if2->entity_device_unique)) {
661			return FALSE; // if not the same device unique identifier
662		}
663	} else if ((if1->entity_device_unique != NULL) || (if2->entity_device_unique != NULL)) {
664		CFStringRef	name1;
665		CFStringRef	name2;
666
667		name1 = __SCNetworkInterfaceGetNonLocalizedDisplayName((SCNetworkInterfaceRef)if1);
668		name2 = __SCNetworkInterfaceGetNonLocalizedDisplayName((SCNetworkInterfaceRef)if2);
669		if ((name1 != NULL) && (name2 != NULL) && !_SC_CFEqual(name1, name2)) {
670			return FALSE; // if same device but not the same display name
671		}
672	}
673
674	if (CFEqual(if1->interface_type, kSCNetworkInterfaceTypeBond)) {
675		if (!_SC_CFEqual(if1->bond.interfaces, if2->bond.interfaces)) {
676			return FALSE; // if not the same interfaces
677		}
678		if (!_SC_CFEqual(if1->bond.mode, if2->bond.mode)) {
679			return FALSE; // if not the same mode
680		}
681	}
682
683	if (CFEqual(if1->interface_type, kSCNetworkInterfaceTypeBridge)) {
684		if (!_SC_CFEqual(if1->bridge.interfaces, if2->bridge.interfaces)) {
685			return FALSE; // if not the same interfaces
686		}
687	}
688
689	if (CFEqual(if1->interface_type, kSCNetworkInterfaceTypeVLAN)) {
690		if (!_SC_CFEqual(if1->vlan.interface, if2->vlan.interface)) {
691			return FALSE;	// if not the same physical interface
692		}
693		if (!_SC_CFEqual(if1->vlan.tag, if2->vlan.tag)) {
694			return FALSE;	// if not the same tag
695		}
696	}
697
698	if (!_SC_CFEqual(if1->interface, if2->interface)) {
699		return FALSE;	// if not the same layering
700	}
701
702	return TRUE;
703}
704
705
706static CFHashCode
707__SCNetworkInterfaceHash(CFTypeRef cf)
708{
709	CFHashCode			hash			= 0;
710	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)cf;
711
712	if (interfacePrivate->entity_device != NULL) {
713		if (interfacePrivate->entity_device_unique == NULL) {
714			hash = CFHash(interfacePrivate->entity_device);
715		} else {
716			CFStringRef	str;
717
718			str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@+%@"),
719						       interfacePrivate->entity_device,
720						       interfacePrivate->entity_device_unique);
721			hash = CFHash(str);
722			CFRelease(str);
723		}
724	}
725
726	return hash;
727}
728
729
730static void
731__SCNetworkInterfaceInitialize(void)
732{
733	kern_return_t   kr;
734
735	// register w/CF
736	__kSCNetworkInterfaceTypeID = _CFRuntimeRegisterClass(&__SCNetworkInterfaceClass);
737
738	// initialize __kSCNetworkInterfaceIPv4
739	_CFRuntimeInitStaticInstance(&__kSCNetworkInterfaceIPv4, __kSCNetworkInterfaceTypeID);
740	__kSCNetworkInterfaceIPv4.interface_type = kSCNetworkInterfaceTypeIPv4;
741	__kSCNetworkInterfaceIPv4.localized_key  = CFSTR("ipv4");
742
743	// initialize __kSCNetworkInterfaceLoopback
744	_CFRuntimeInitStaticInstance(&__kSCNetworkInterfaceLoopback, __kSCNetworkInterfaceTypeID);
745	__kSCNetworkInterfaceLoopback.interface_type = kSCNetworkInterfaceTypeLoopback;
746	__kSCNetworkInterfaceLoopback.localized_key  = CFSTR("loopback");
747	__kSCNetworkInterfaceLoopback.entity_device  = CFRetain(CFSTR("lo0"));
748	__kSCNetworkInterfaceLoopback.entity_type    = kSCValNetInterfaceTypeLoopback;
749
750	// get CFBundleRef for SystemConfiguration.framework
751	bundle = _SC_CFBundleGet();
752
753	// get mach port used to communication with IOKit
754	kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
755	if (kr != kIOReturnSuccess) {
756		SCLog(TRUE, LOG_DEBUG,
757		      CFSTR("__SCNetworkInterfaceInitialize(), could not get IOMasterPort, kr = 0x%x"),
758		      kr);
759	}
760
761	return;
762}
763
764
765__private_extern__
766SCNetworkInterfacePrivateRef
767__SCNetworkInterfaceCreatePrivate(CFAllocatorRef	allocator,
768				  SCNetworkInterfaceRef	interface,
769				  SCPreferencesRef	prefs,
770				  CFStringRef		serviceID)
771{
772	SCNetworkInterfacePrivateRef		interfacePrivate;
773	uint32_t				size;
774
775	/* initialize runtime */
776	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
777
778	/* allocate target */
779	size             = sizeof(SCNetworkInterfacePrivate) - sizeof(CFRuntimeBase);
780	interfacePrivate = (SCNetworkInterfacePrivateRef)_CFRuntimeCreateInstance(allocator,
781										  __kSCNetworkInterfaceTypeID,
782										  size,
783										  NULL);
784	if (interfacePrivate == NULL) {
785		return NULL;
786	}
787
788	interfacePrivate->interface_type		= NULL;
789	interfacePrivate->active			= FALSE;
790	interfacePrivate->name				= NULL;
791	interfacePrivate->localized_name		= NULL;
792	interfacePrivate->localized_key			= NULL;
793	interfacePrivate->localized_arg1		= NULL;
794	interfacePrivate->localized_arg2		= NULL;
795	interfacePrivate->interface			= (interface != NULL) ? CFRetain(interface) : NULL;
796	interfacePrivate->prefs				= (prefs     != NULL) ? CFRetain(prefs)     : NULL;
797	interfacePrivate->store				= NULL;
798	interfacePrivate->serviceID			= (serviceID != NULL) ? CFRetain(serviceID) : NULL;
799	interfacePrivate->unsaved			= NULL;
800	interfacePrivate->entity_device			= NULL;
801	interfacePrivate->entity_device_unique		= NULL;
802	interfacePrivate->entity_type			= NULL;
803	interfacePrivate->entity_subtype		= NULL;
804	interfacePrivate->supported_interface_types     = NULL;
805	interfacePrivate->supported_protocol_types      = NULL;
806	interfacePrivate->address			= NULL;
807	interfacePrivate->addressString			= NULL;
808	interfacePrivate->builtin			= FALSE;
809	interfacePrivate->configurationAction		= NULL;
810	interfacePrivate->hidden			= FALSE;
811	interfacePrivate->location			= NULL;
812	interfacePrivate->path				= NULL;
813	interfacePrivate->entryID			= 0;
814	interfacePrivate->overrides			= NULL;
815	interfacePrivate->modemIsV92			= FALSE;
816	interfacePrivate->prefix			= NULL;
817	interfacePrivate->type				= NULL;
818	interfacePrivate->unit				= NULL;
819	interfacePrivate->usb.name			= NULL;
820	interfacePrivate->usb.vid			= NULL;
821	interfacePrivate->usb.pid			= NULL;
822	interfacePrivate->sort_order			= kSortUnknown;
823
824	interfacePrivate->supportsBond			= FALSE;
825	interfacePrivate->bond.interfaces		= NULL;
826	interfacePrivate->bond.mode			= NULL;
827	interfacePrivate->bond.options			= NULL;
828
829	interfacePrivate->supportsBridge		= FALSE;
830	interfacePrivate->bridge.interfaces		= NULL;
831	interfacePrivate->bridge.options		= NULL;
832
833	interfacePrivate->supportsVLAN			= FALSE;
834	interfacePrivate->vlan.interface		= NULL;
835	interfacePrivate->vlan.tag			= NULL;
836	interfacePrivate->vlan.options			= NULL;
837
838	return interfacePrivate;
839}
840
841
842__private_extern__
843Boolean
844__SCNetworkInterfaceSupportsVLAN(CFStringRef bsd_if)
845{
846	char *			buf	= NULL;
847	size_t			buf_len	= 0;
848	struct if_msghdr *	ifm;
849	char *			if_name	= NULL;
850	unsigned int		if_index;
851	int			mib[6];
852	Boolean			vlanOK	= FALSE;
853
854	// get the interface index
855	if_name = _SC_cfstring_to_cstring(bsd_if, NULL, 0, kCFStringEncodingASCII);
856	if (if_name == NULL) {
857		return FALSE;	// if conversion error
858	}
859	if_index = if_nametoindex(if_name);
860	if (if_index == 0) {
861		goto done;	// if unknown interface
862	}
863
864	// get information for the specified interface
865	mib[0] = CTL_NET;
866	mib[1] = PF_ROUTE;
867	mib[2] = 0;
868	mib[3] = AF_LINK;
869	mib[4] = NET_RT_IFLIST;
870	mib[5] = if_index;	/* ask for exactly one interface */
871
872	if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) == -1) {
873		SCLog(TRUE, LOG_ERR, CFSTR("sysctl() size failed: %s"), strerror(errno));
874		goto done;
875	}
876	buf = CFAllocatorAllocate(NULL, buf_len, 0);
877	if (sysctl(mib, 6, buf, &buf_len, NULL, 0) == -1) {
878		SCLog(TRUE, LOG_ERR, CFSTR("sysctl() failed: %s"), strerror(errno));
879		goto done;
880	}
881
882	// check the link type and hwassist flags
883	// ALIGN: buf is aligned
884	ifm = (struct if_msghdr *)(void *)buf;
885	switch (ifm->ifm_type) {
886		case RTM_IFINFO : {
887#if	defined(IF_HWASSIST_VLAN_TAGGING) && defined(IF_HWASSIST_VLAN_MTU)
888			struct if_data	*if_data = &ifm->ifm_data;
889
890			if (if_data->ifi_hwassist & (IF_HWASSIST_VLAN_TAGGING | IF_HWASSIST_VLAN_MTU)) {
891				vlanOK = TRUE;
892			}
893#endif
894			break;
895		}
896	}
897
898    done :
899
900	if (if_name != NULL)	CFAllocatorDeallocate(NULL, if_name);
901	if (buf != NULL)	CFAllocatorDeallocate(NULL, buf);
902
903	return vlanOK;
904}
905
906
907__private_extern__
908SCNetworkInterfacePrivateRef
909_SCBondInterfaceCreatePrivate(CFAllocatorRef	allocator,
910			      CFStringRef	bond_if)
911{
912	SCNetworkInterfacePrivateRef	interfacePrivate;
913
914	interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL);
915	if (interfacePrivate == NULL) {
916		return NULL;
917	}
918
919	interfacePrivate->interface_type	= kSCNetworkInterfaceTypeBond;
920	interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
921	interfacePrivate->entity_device		= CFStringCreateCopy(allocator, bond_if);
922	interfacePrivate->builtin		= TRUE;
923	interfacePrivate->supportsVLAN		= __SCNetworkInterfaceSupportsVLAN(bond_if);
924	interfacePrivate->sort_order		= kSortBond;
925
926	interfacePrivate->localized_key		= CFSTR("bond");
927	interfacePrivate->localized_arg1	= CFRetain(interfacePrivate->entity_device);
928
929	interfacePrivate->bond.interfaces	= CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
930//	interfacePrivate->bond.mode		= NULL;
931//	interfacePrivate->bond.options		= NULL;
932
933	return interfacePrivate;
934}
935
936
937__private_extern__
938SCNetworkInterfacePrivateRef
939_SCBridgeInterfaceCreatePrivate(CFAllocatorRef	allocator,
940				CFStringRef	bridge_if)
941{
942	SCNetworkInterfacePrivateRef	interfacePrivate;
943
944	interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL);
945	if (interfacePrivate == NULL) {
946		return NULL;
947	}
948
949	interfacePrivate->interface_type	= kSCNetworkInterfaceTypeBridge;
950	interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
951	interfacePrivate->entity_device		= CFStringCreateCopy(allocator, bridge_if);
952	interfacePrivate->builtin		= TRUE;
953	interfacePrivate->supportsVLAN		= __SCNetworkInterfaceSupportsVLAN(bridge_if);
954	interfacePrivate->sort_order		= kSortBridge;
955
956	interfacePrivate->localized_key		= CFSTR("bridge");
957	interfacePrivate->localized_arg1	= CFRetain(interfacePrivate->entity_device);
958
959	interfacePrivate->bridge.interfaces	= CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
960//	interfacePrivate->bridge.options	= NULL;
961
962	return interfacePrivate;
963}
964
965
966__private_extern__
967SCNetworkInterfacePrivateRef
968_SCVLANInterfaceCreatePrivate(CFAllocatorRef		allocator,
969			      CFStringRef		vlan_if)
970{
971	SCNetworkInterfacePrivateRef	interfacePrivate;
972
973	interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL);
974	if (interfacePrivate == NULL) {
975		return NULL;
976	}
977
978	interfacePrivate->interface_type        = kSCNetworkInterfaceTypeVLAN;
979	interfacePrivate->entity_type           = kSCValNetInterfaceTypeEthernet;
980	interfacePrivate->entity_device         = CFStringCreateCopy(allocator, vlan_if);
981	interfacePrivate->builtin               = TRUE;
982	interfacePrivate->sort_order            = kSortVLAN;
983
984	interfacePrivate->localized_key		= CFSTR("vlan");
985	interfacePrivate->localized_arg1	= CFRetain(interfacePrivate->entity_device);
986
987//	interfacePrivate->vlan.interface	= NULL;
988//	interfacePrivate->vlan.tag		= NULL;
989//	interfacePrivate->vlan.options		= NULL;
990
991	return interfacePrivate;
992}
993
994
995#pragma mark -
996#pragma mark Interface ordering
997
998
999static CF_RETURNS_RETAINED CFArrayRef
1000split_path(CFStringRef path)
1001{
1002	CFArrayRef		components;
1003	CFMutableStringRef	nPath;
1004
1005	// turn '@'s into '/'s
1006	nPath = CFStringCreateMutableCopy(NULL, 0, path);
1007	(void) CFStringFindAndReplace(nPath,
1008				      CFSTR("@"),
1009				      CFSTR("/"),
1010				      CFRangeMake(0, CFStringGetLength(nPath)),
1011				      0);
1012
1013	// split path into components to be compared
1014	components = CFStringCreateArrayBySeparatingStrings(NULL, nPath, CFSTR("/"));
1015	CFRelease(nPath);
1016
1017	return components;
1018}
1019
1020
1021CFComparisonResult
1022_SCNetworkInterfaceCompare(const void *val1, const void *val2, void *context)
1023{
1024	SCNetworkInterfacePrivateRef	dev1		= (SCNetworkInterfacePrivateRef)val1;
1025	SCNetworkInterfacePrivateRef	dev2		= (SCNetworkInterfacePrivateRef)val2;
1026	CFComparisonResult		res		= kCFCompareEqualTo;
1027
1028	/* sort by interface type */
1029	if (dev1->sort_order != dev2->sort_order) {
1030		if (dev1->sort_order < dev2->sort_order) {
1031			res = kCFCompareLessThan;
1032		} else {
1033			res = kCFCompareGreaterThan;
1034		}
1035		return (res);
1036	}
1037
1038	/* built-in interfaces sort first */
1039	if (dev1->builtin != dev2->builtin) {
1040		if (dev1->builtin) {
1041			res = kCFCompareLessThan;
1042		} else {
1043			res = kCFCompareGreaterThan;
1044		}
1045		return (res);
1046	}
1047
1048	/* ... and then, sort built-in interfaces by "location" */
1049	if (dev1->builtin) {
1050		if (dev1->location != dev2->location) {
1051			if (isA_CFString(dev1->location)) {
1052				if (isA_CFString(dev2->location)) {
1053					res = CFStringCompare(dev1->location, dev2->location, 0);
1054				} else {
1055					res = kCFCompareLessThan;
1056				}
1057			} else {
1058				res = kCFCompareGreaterThan;
1059			}
1060
1061			if (res != kCFCompareEqualTo) {
1062				return (res);
1063			}
1064		}
1065	}
1066
1067	/* ... and, then sort by IOPathMatch */
1068	if ((dev1->path != NULL) && (dev2->path != NULL)) {
1069		CFArrayRef	elements1;
1070		CFArrayRef	elements2;
1071		CFIndex		i;
1072		CFIndex		n;
1073		CFIndex		n1;
1074		CFIndex		n2;
1075
1076		elements1 = split_path(dev1->path);
1077		n1 = CFArrayGetCount(elements1);
1078
1079		elements2 = split_path(dev2->path);
1080		n2 = CFArrayGetCount(elements2);
1081
1082		n = (n1 <= n2) ? n1 : n2;
1083		for (i = 0; i < n; i++) {
1084			CFStringRef	e1;
1085			CFStringRef	e2;
1086			char		*end;
1087			quad_t		q1;
1088			quad_t		q2;
1089			char		*str;
1090			Boolean		isNum;
1091
1092			e1 = CFArrayGetValueAtIndex(elements1, i);
1093			e2 = CFArrayGetValueAtIndex(elements2, i);
1094
1095			str = _SC_cfstring_to_cstring(e1, NULL, 0, kCFStringEncodingUTF8);
1096			errno = 0;
1097			q1 = strtoq(str, &end, 16);
1098			isNum = ((*str != '\0') && (*end == '\0') && (errno == 0));
1099			CFAllocatorDeallocate(NULL, str);
1100
1101			if (isNum) {
1102				// if e1 is a valid numeric string
1103				str = _SC_cfstring_to_cstring(e2, NULL, 0, kCFStringEncodingUTF8);
1104				errno = 0;
1105				q2 = strtoq(str, &end, 16);
1106				isNum = ((*str != '\0') && (*end == '\0') && (errno == 0));
1107				CFAllocatorDeallocate(NULL, str);
1108
1109				if (isNum) {
1110					// if e2 is also a valid numeric string
1111
1112					if (q1 == q2) {
1113						res = kCFCompareEqualTo;
1114						continue;
1115					} else if (q1 < q2) {
1116						res = kCFCompareLessThan;
1117					} else {
1118						res = kCFCompareGreaterThan;
1119					}
1120					break;
1121				}
1122			}
1123
1124			res = CFStringCompare(e1, e2, 0);
1125			if (res != kCFCompareEqualTo) {
1126				break;
1127			}
1128		}
1129
1130		if (res == kCFCompareEqualTo) {
1131			if (n1 < n2) {
1132				res = kCFCompareLessThan;
1133			} else if (n1 < n2) {
1134				res = kCFCompareGreaterThan;
1135			}
1136		}
1137
1138		CFRelease(elements1);
1139		CFRelease(elements2);
1140
1141		if (res != kCFCompareEqualTo) {
1142			return (res);
1143		}
1144	}
1145
1146	/* ... and, then sort by BSD interface name */
1147	if ((dev1->entity_device != NULL) && (dev2->entity_device != NULL)) {
1148		res = CFStringCompare(dev1->entity_device, dev2->entity_device, 0);
1149		if (res != kCFCompareEqualTo) {
1150			return (res);
1151		}
1152	}
1153
1154	/* ... and lastly, sort by BSD interface unique identifier */
1155	if ((dev1->entity_device_unique != NULL) && (dev2->entity_device_unique != NULL)) {
1156		res = CFStringCompare(dev1->entity_device_unique, dev2->entity_device_unique, 0);
1157//		if (res != kCFCompareEqualTo) {
1158//			return (res);
1159//		}
1160	}
1161
1162	return res;
1163}
1164
1165
1166static void
1167sort_interfaces(CFMutableArrayRef all_interfaces)
1168{
1169	CFIndex		n;
1170
1171	n = CFArrayGetCount(all_interfaces);
1172	if (n < 2) {
1173		return;
1174	}
1175
1176	CFArraySortValues(all_interfaces, CFRangeMake(0, n), _SCNetworkInterfaceCompare, NULL);
1177	return;
1178}
1179
1180
1181__private_extern__
1182int
1183__SCNetworkInterfaceOrder(SCNetworkInterfaceRef interface)
1184{
1185	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
1186
1187	return interfacePrivate->sort_order;
1188}
1189
1190
1191#pragma mark -
1192#pragma mark Interface details
1193
1194
1195static CFStringRef
1196IOCopyCFStringValue(CFTypeRef ioVal)
1197{
1198	if (isA_CFString(ioVal)) {
1199		return CFStringCreateCopy(NULL, ioVal);
1200	}
1201
1202	if (isA_CFData(ioVal)) {
1203		return CFStringCreateWithCString(NULL,
1204						 (const char *)CFDataGetBytePtr(ioVal),
1205						 kCFStringEncodingUTF8);
1206	}
1207
1208	return NULL;
1209}
1210
1211
1212static CFStringRef
1213IODictionaryCopyBSDName(CFDictionaryRef io_dict)
1214{
1215	CFStringRef	if_bsdName;
1216	CFStringRef	if_prefix;
1217	CFNumberRef	if_unit;
1218
1219	if_bsdName = CFDictionaryGetValue(io_dict, CFSTR(kIOBSDNameKey));
1220	if (if_bsdName != NULL) {
1221		return IOCopyCFStringValue(if_bsdName);
1222	}
1223
1224	// no BSD name, get interface prefix and unit
1225	if_prefix = CFDictionaryGetValue(io_dict, CFSTR(kIOInterfaceNamePrefix));
1226	if_unit   = CFDictionaryGetValue(io_dict, CFSTR(kIOInterfaceUnit));
1227	if (isA_CFString(if_prefix) && isA_CFNumber(if_unit)) {
1228		// if both prefix and unit available, construct BSD name
1229		if_bsdName = CFStringCreateWithFormat(NULL,
1230						      NULL,
1231						      CFSTR("%@%@"),
1232						      if_prefix,
1233						      if_unit);
1234	}
1235
1236	return if_bsdName;
1237};
1238
1239
1240static CFStringRef
1241IODictionaryCopyCFStringValue(CFDictionaryRef io_dict, CFStringRef io_key)
1242{
1243	CFTypeRef	ioVal;
1244
1245	ioVal = CFDictionaryGetValue(io_dict, io_key);
1246	return IOCopyCFStringValue(ioVal);
1247}
1248
1249
1250static Boolean
1251IOStringValueHasPrefix(CFTypeRef ioVal, CFStringRef prefix)
1252{
1253	Boolean		match		= FALSE;
1254	CFIndex		prefixLen	= CFStringGetLength(prefix);
1255	CFStringRef	str		= NULL;
1256
1257	if (!isA_CFString(ioVal)) {
1258		if (isA_CFData(ioVal)) {
1259			str = CFStringCreateWithCStringNoCopy(NULL,
1260							      (const char *)CFDataGetBytePtr(ioVal),
1261							      kCFStringEncodingUTF8,
1262							      kCFAllocatorNull);
1263			ioVal = str;
1264		} else {
1265			return FALSE;
1266		}
1267	}
1268
1269	if ((ioVal != NULL) &&
1270	    (CFStringGetLength(ioVal) >= prefixLen) &&
1271	    (CFStringCompareWithOptions(ioVal,
1272					prefix,
1273					CFRangeMake(0, prefixLen),
1274					kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
1275		match = TRUE;
1276	}
1277
1278	if (str != NULL) CFRelease(str);
1279	return match;
1280}
1281
1282
1283static const struct {
1284	const CFStringRef	name;
1285	const CFStringRef	slot;
1286} slot_mappings[] = {
1287	// Beige G3
1288	{ CFSTR("A1") , CFSTR("1") },
1289	{ CFSTR("B1") , CFSTR("2") },
1290	{ CFSTR("C1") , CFSTR("3") },
1291
1292	// Blue&White G3, Yikes G4
1293	{ CFSTR("J12"), CFSTR("1") },
1294	{ CFSTR("J11"), CFSTR("2") },
1295	{ CFSTR("J10"), CFSTR("3") },
1296	{ CFSTR("J9"),  CFSTR("4") },
1297
1298	// AGP G4
1299	{ CFSTR("A")  , CFSTR("1") },
1300	{ CFSTR("B")  , CFSTR("2") },
1301	{ CFSTR("C")  , CFSTR("3") },
1302	{ CFSTR("D") ,  CFSTR("4") },
1303
1304	// Digital Audio G4 (and later models)
1305	{ CFSTR("1")  , CFSTR("1") },
1306	{ CFSTR("2")  , CFSTR("2") },
1307	{ CFSTR("3")  , CFSTR("3") },
1308	{ CFSTR("4") ,  CFSTR("4") },
1309	{ CFSTR("5") ,  CFSTR("5") }
1310};
1311
1312
1313static const CFStringRef	slot_prefixes[]	= {
1314	CFSTR("thunderbolt slot "),
1315	CFSTR("pci slot "),
1316	CFSTR("slot-"),
1317};
1318
1319
1320static CF_RETURNS_RETAINED CFStringRef
1321pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name)
1322{
1323	kern_return_t		kr;
1324	io_registry_entry_t	parent;
1325	CFMutableStringRef	slot;
1326	CFTypeRef		slot_name;
1327
1328	slot = NULL;
1329	if (pci_slot_name != NULL) *pci_slot_name = NULL;
1330
1331	slot_name = IORegistryEntryCreateCFProperty(interface, CFSTR("AAPL,slot-name"), NULL, 0);
1332	if (slot_name != NULL) {
1333		CFIndex	i;
1334
1335		slot = CFStringCreateMutable(NULL, 0);
1336		if (isA_CFString(slot_name)) {
1337			if (pci_slot_name != NULL) *pci_slot_name = CFStringCreateCopy(NULL, slot_name);
1338			CFStringAppend(slot, slot_name);
1339		} else if (isA_CFData(slot_name)) {
1340			if (pci_slot_name != NULL) *pci_slot_name = CFDataCreateCopy(NULL, slot_name);
1341			CFStringAppendCString(slot,
1342					      (const char *)CFDataGetBytePtr(slot_name),
1343					      kCFStringEncodingUTF8);
1344		}
1345
1346		for (i = 0; i < sizeof(slot_prefixes)/sizeof(slot_prefixes[0]); i++) {
1347			CFIndex		len;
1348
1349			len = CFStringGetLength(slot_prefixes[i]);
1350			if (CFStringGetLength(slot) > len) {
1351				(void) CFStringFindAndReplace(slot,
1352							      slot_prefixes[i],
1353							      CFSTR(""),
1354							      CFRangeMake(0, len),
1355							      kCFCompareCaseInsensitive|kCFCompareAnchored);
1356			}
1357		}
1358
1359		for (i = 0; i < sizeof(slot_mappings)/sizeof(slot_mappings[0]); i++) {
1360			if (CFStringCompare(slot,
1361					    slot_mappings[i].name,
1362					    kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
1363				CFRelease(slot);
1364				slot = (CFMutableStringRef)CFRetain(slot_mappings[i].slot);
1365				break;
1366			}
1367		}
1368
1369		CFRelease(slot_name);
1370	}
1371
1372	kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &parent);
1373	switch (kr) {
1374		case kIOReturnSuccess : {
1375			CFTypeRef	parent_pci_slot_name	= NULL;
1376			CFStringRef	parent_slot;
1377
1378			parent_slot = pci_slot(parent, &parent_pci_slot_name);
1379			if (parent_slot != NULL) {
1380				if (slot != NULL) CFRelease(slot);
1381				slot = (CFMutableStringRef)parent_slot;
1382
1383				if (pci_slot_name != NULL) {
1384					if (*pci_slot_name != NULL) CFRelease(*pci_slot_name);
1385					*pci_slot_name = parent_pci_slot_name;
1386				} else {
1387					CFRelease(parent_pci_slot_name);
1388				}
1389			}
1390
1391			IOObjectRelease(parent);
1392			break;
1393		}
1394		case kIOReturnNoDevice :
1395			// if we have hit the root node
1396			break;
1397		default :
1398			SCLog(TRUE, LOG_DEBUG, CFSTR("pci_slot IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
1399			break;
1400	}
1401
1402	return slot;
1403}
1404
1405
1406static CFComparisonResult
1407compare_bsdNames(const void *val1, const void *val2, void *context)
1408{
1409	CFStringRef	bsd1	= (CFStringRef)val1;
1410	CFStringRef	bsd2	= (CFStringRef)val2;
1411
1412	return CFStringCompare(bsd1, bsd2, 0);
1413}
1414
1415
1416static CF_RETURNS_RETAINED CFStringRef
1417pci_port(CFTypeRef slot_name, int ift, CFStringRef bsdName)
1418{
1419	CFIndex			n;
1420	CFStringRef		port_name	= NULL;
1421	CFMutableArrayRef	port_names;
1422
1423	kern_return_t		kr;
1424	CFStringRef		match_keys[2];
1425	CFTypeRef		match_vals[2];
1426	CFDictionaryRef		match_dict;
1427	CFDictionaryRef		matching;
1428	io_registry_entry_t	slot;
1429	io_iterator_t		slot_iterator	= MACH_PORT_NULL;
1430
1431	match_keys[0] = CFSTR("AAPL,slot-name");
1432	match_vals[0] = slot_name;
1433
1434	match_dict = CFDictionaryCreate(NULL,
1435					(const void **)match_keys,
1436					(const void **)match_vals,
1437					1,
1438					&kCFTypeDictionaryKeyCallBacks,
1439					&kCFTypeDictionaryValueCallBacks);
1440
1441	match_keys[0] = CFSTR(kIOProviderClassKey);
1442	match_vals[0] = CFSTR("IOPCIDevice");
1443
1444	match_keys[1] = CFSTR(kIOPropertyMatchKey);
1445	match_vals[1] = match_dict;
1446
1447	// note: the "matching" dictionary will be consumed by the following
1448	matching = CFDictionaryCreate(NULL,
1449				      (const void **)match_keys,
1450				      (const void **)match_vals,
1451				      sizeof(match_keys)/sizeof(match_keys[0]),
1452				      &kCFTypeDictionaryKeyCallBacks,
1453				      &kCFTypeDictionaryValueCallBacks);
1454	CFRelease(match_dict);
1455
1456	kr = IOServiceGetMatchingServices(masterPort, matching, &slot_iterator);
1457	if (kr != kIOReturnSuccess) {
1458		SCLog(TRUE, LOG_DEBUG, CFSTR("pci_port IOServiceGetMatchingServices() failed, kr = 0x%x"), kr);
1459		return MACH_PORT_NULL;
1460	}
1461
1462	port_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1463
1464	while ((slot = IOIteratorNext(slot_iterator)) != MACH_PORT_NULL) {
1465		io_registry_entry_t	child;
1466		io_iterator_t		child_iterator	= MACH_PORT_NULL;
1467
1468		kr = IORegistryEntryCreateIterator(slot,
1469						   kIOServicePlane,
1470						   kIORegistryIterateRecursively,
1471						   &child_iterator);
1472		if (kr != kIOReturnSuccess) {
1473			SCLog(TRUE, LOG_DEBUG, CFSTR("pci_port IORegistryEntryCreateIterator() failed, kr = 0x%x"), kr);
1474			CFRelease(port_names);
1475			return MACH_PORT_NULL;
1476		}
1477
1478		while ((child = IOIteratorNext(child_iterator)) != MACH_PORT_NULL) {
1479			if (IOObjectConformsTo(child, kIONetworkInterfaceClass)) {
1480				CFMutableDictionaryRef	interface_dict	= NULL;
1481
1482				(void) IORegistryEntryCreateCFProperties(child, &interface_dict, NULL, kNilOptions);
1483				if (interface_dict != NULL) {
1484					CFNumberRef	child_if_type;
1485					int		child_ift	= ift;
1486
1487					child_if_type = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceType));
1488					if (child_if_type != NULL) {
1489						if (!isA_CFNumber(child_if_type) ||
1490						    !CFNumberGetValue(child_if_type, kCFNumberIntType, &child_ift)) {
1491							// assume that it's a match
1492							child_ift = ift;
1493						}
1494					}
1495
1496					if (ift == child_ift) {
1497						CFStringRef	if_bsdName;
1498
1499						if_bsdName = IODictionaryCopyBSDName(interface_dict);
1500						if (if_bsdName != NULL) {
1501							CFArrayAppendValue(port_names, if_bsdName);
1502							CFRelease(if_bsdName);
1503						}
1504					}
1505
1506					CFRelease(interface_dict);
1507				}
1508			}
1509			IOObjectRelease(child);
1510		}
1511		IOObjectRelease(child_iterator);
1512		IOObjectRelease(slot);
1513	}
1514	IOObjectRelease(slot_iterator);
1515
1516	n = CFArrayGetCount(port_names);
1517	if (n > 1) {
1518		CFArraySortValues(port_names, CFRangeMake(0, n), compare_bsdNames, NULL);
1519		n = CFArrayGetFirstIndexOfValue(port_names, CFRangeMake(0, n), bsdName);
1520		if (n != kCFNotFound) {
1521			port_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%ld"), n + 1);
1522		}
1523	}
1524
1525	CFRelease(port_names);
1526	return port_name;
1527}
1528
1529
1530static Boolean
1531pci_slot_info(io_registry_entry_t interface, int ift, CFStringRef *slot_name, CFStringRef *port_name)
1532{
1533	CFStringRef		bsd_name	= NULL;
1534	CFMutableDictionaryRef	interface_dict	= NULL;
1535	Boolean			ok		= FALSE;
1536	CFTypeRef		pci_slot_name;
1537
1538	*slot_name = NULL;
1539	*port_name = NULL;
1540
1541	(void) IORegistryEntryCreateCFProperties(interface, &interface_dict, NULL, kNilOptions);
1542	if (interface_dict != NULL) {
1543		bsd_name = IODictionaryCopyBSDName(interface_dict);
1544		CFRelease(interface_dict);
1545	}
1546
1547	if (bsd_name == NULL) {
1548		return FALSE;
1549	}
1550
1551	*slot_name = pci_slot(interface, &pci_slot_name);
1552	if (*slot_name != NULL) {
1553		if (pci_slot_name != NULL) {
1554			*port_name = pci_port(pci_slot_name, ift, bsd_name);
1555			CFRelease(pci_slot_name);
1556		}
1557		ok = TRUE;
1558	}
1559
1560	CFRelease(bsd_name);
1561	return ok;
1562}
1563
1564
1565static Boolean
1566isBuiltin(io_registry_entry_t interface)
1567{
1568	CFStringRef	slot;
1569
1570	slot = pci_slot(interface, NULL);
1571	if (slot != NULL) {
1572		// interfaces which have a "slot" are not built-in
1573		CFRelease(slot);
1574		return FALSE;
1575	}
1576
1577	return TRUE;
1578}
1579
1580
1581static Boolean
1582isBluetoothBuiltin(Boolean *haveController)
1583{
1584	Boolean		builtin		= FALSE;
1585	io_object_t	hciController;
1586	io_iterator_t	iter		= MACH_PORT_NULL;
1587	kern_return_t	kr;
1588
1589	kr = IOServiceGetMatchingServices(masterPort,
1590					  IOServiceMatching("IOBluetoothHCIController"),
1591					  &iter);
1592	if ((kr != kIOReturnSuccess) || (iter == MACH_PORT_NULL)) {
1593		if (kr != kIOReturnSuccess) {
1594			SCLog(TRUE, LOG_DEBUG, CFSTR("isBluetoothBuiltin IOServiceGetMatchingServices() failed, kr = 0x%x"), kr);
1595		}
1596		*haveController = FALSE;
1597		return FALSE;
1598	}
1599	*haveController = TRUE;
1600
1601	hciController = IOIteratorNext(iter);
1602	IOObjectRelease(iter);
1603	if(hciController != MACH_PORT_NULL) {
1604#if	!TARGET_IPHONE_SIMULATOR
1605		CFNumberRef	idVendor;
1606
1607		idVendor = IORegistryEntryCreateCFProperty(hciController, CFSTR(kUSBVendorID), NULL, 0);
1608		if (idVendor != NULL) {
1609			int	idVendorVal;
1610
1611			if (isA_CFNumber(idVendor) &&
1612			    CFNumberGetValue(idVendor, kCFNumberIntType, &idVendorVal) &&
1613			    (idVendorVal == kIOUSBVendorIDAppleComputer)) {
1614				builtin = TRUE;
1615			}
1616
1617			CFRelease(idVendor);
1618		}
1619#endif	// !TARGET_IPHONE_SIMULATOR
1620
1621		IOObjectRelease(hciController);
1622	}
1623
1624	return builtin;
1625}
1626
1627
1628static Boolean
1629isThunderbolt(io_registry_entry_t interface)
1630{
1631	CFTypeRef	val;
1632
1633	val = IORegistryEntrySearchCFProperty(interface,
1634					      kIOServicePlane,
1635					      CFSTR(kPCIThunderboltString),
1636					      NULL,
1637					      kIORegistryIterateRecursively | kIORegistryIterateParents);
1638	if (val != NULL) {
1639		CFRelease(val);
1640		return TRUE;
1641	}
1642
1643	return FALSE;
1644}
1645
1646
1647static void
1648processUSBInterface(SCNetworkInterfacePrivateRef	interfacePrivate,
1649		    io_registry_entry_t			interface,
1650		    CFDictionaryRef			interface_dict,
1651		    io_registry_entry_t			controller,
1652		    CFDictionaryRef			controller_dict,
1653		    io_registry_entry_t			bus,
1654		    CFDictionaryRef			bus_dict)
1655{
1656#if	!TARGET_IPHONE_SIMULATOR
1657	// capture USB info
1658	interfacePrivate->usb.name = IORegistryEntrySearchCFProperty(interface,
1659								     kIOServicePlane,
1660								     CFSTR(kUSBProductString),
1661								     NULL,
1662								     kIORegistryIterateRecursively | kIORegistryIterateParents);
1663	interfacePrivate->usb.vid  = IORegistryEntrySearchCFProperty(interface,
1664								     kIOServicePlane,
1665								     CFSTR(kUSBVendorID),
1666								     NULL,
1667								     kIORegistryIterateRecursively | kIORegistryIterateParents);
1668	interfacePrivate->usb.pid  = IORegistryEntrySearchCFProperty(interface,
1669								     kIOServicePlane,
1670								     CFSTR(kUSBProductID),
1671								     NULL,
1672								     kIORegistryIterateRecursively | kIORegistryIterateParents);
1673#endif	// !TARGET_IPHONE_SIMULATOR
1674
1675	return;
1676}
1677
1678
1679static Boolean
1680update_interface_name(SCNetworkInterfacePrivateRef	interfacePrivate,
1681		      io_registry_entry_t		interface,
1682		      Boolean				useUSBInfo)
1683{
1684	Boolean		updated	= FALSE;
1685	CFTypeRef	val;
1686
1687	// check if a "Product Name" has been provided
1688	val = IORegistryEntrySearchCFProperty(interface,
1689					      kIOServicePlane,
1690					      CFSTR(kIOPropertyProductNameKey),
1691					      NULL,
1692					      kIORegistryIterateRecursively | kIORegistryIterateParents);
1693	if ((val == NULL) && useUSBInfo && (interfacePrivate->usb.name != NULL)) {
1694		// else, use "USB Product Name" if available
1695		val = CFRetain(interfacePrivate->usb.name);
1696	}
1697	if (val != NULL) {
1698		CFStringRef	productName;
1699
1700		productName = IOCopyCFStringValue(val);
1701		CFRelease(val);
1702
1703		if (productName != NULL) {
1704			if (CFStringGetLength(productName) > 0) {
1705				// if we have a [somewhat reasonable?] product name
1706				if (interfacePrivate->name != NULL) {
1707					CFRelease(interfacePrivate->name);
1708				}
1709				interfacePrivate->name = CFRetain(productName);
1710				if (interfacePrivate->localized_name != NULL) {
1711					CFRelease(interfacePrivate->localized_name);
1712					interfacePrivate->localized_name = NULL;
1713				}
1714				if (bundle != NULL) {
1715					interfacePrivate->localized_name = copy_interface_string(bundle, productName, TRUE);
1716				}
1717
1718				updated = TRUE;
1719			}
1720
1721			CFRelease(productName);
1722		}
1723	}
1724
1725	return updated;
1726}
1727
1728
1729#pragma mark -
1730#pragma mark Interface enumeration
1731
1732
1733typedef Boolean (*processInterface)(SCNetworkInterfacePrivateRef	interfacePrivate,
1734				    io_registry_entry_t			interface,
1735				    CFDictionaryRef			interface_dict,
1736				    io_registry_entry_t			controller,
1737				    CFDictionaryRef			controller_dict,
1738				    io_registry_entry_t			bus,
1739				    CFDictionaryRef			bus_dict);
1740
1741
1742static void
1743merge_override(SCNetworkInterfacePrivateRef	interfacePrivate,
1744	       io_registry_entry_t		interface,
1745	       CFStringRef			override)
1746{
1747	CFStringRef	key;
1748	CFTypeRef	val;
1749
1750	key = CFStringCreateWithFormat(NULL, NULL, CFSTR("Device%@Overrides"), override);
1751	val = IORegistryEntrySearchCFProperty(interface,
1752					      kIOServicePlane,
1753					      key,
1754					      NULL,
1755					      kIORegistryIterateRecursively | kIORegistryIterateParents);
1756	CFRelease(key);
1757	if (val != NULL) {
1758		if (isA_CFDictionary(val)) {
1759			if (interfacePrivate->overrides == NULL) {
1760				interfacePrivate->overrides = CFDictionaryCreateMutable(NULL,
1761											0,
1762											&kCFTypeDictionaryKeyCallBacks,
1763											&kCFTypeDictionaryValueCallBacks);
1764			}
1765			CFDictionarySetValue(interfacePrivate->overrides, override, val);
1766		}
1767		CFRelease(val);
1768	}
1769
1770	return;
1771}
1772
1773
1774#define	BT_PAN_NAME	"Bluetooth PAN"
1775#define	BT_PAN_MAC	BT_PAN_NAME " (MAC)"
1776
1777static Boolean
1778processNetworkInterface(SCNetworkInterfacePrivateRef	interfacePrivate,
1779			io_registry_entry_t		interface,
1780			CFDictionaryRef			interface_dict,
1781			io_registry_entry_t		controller,
1782			CFDictionaryRef			controller_dict,
1783			io_registry_entry_t		bus,
1784			CFDictionaryRef			bus_dict)
1785{
1786	CFDataRef	data;
1787	int		ift	= -1;
1788	int		iVal;
1789	CFNumberRef	num;
1790	CFStringRef	str;
1791	CFBooleanRef	val;
1792
1793	// interface type
1794	num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceType));
1795	if (isA_CFNumber(num) &&
1796	    CFNumberGetValue(num, kCFNumberIntType, &ift)) {
1797		interfacePrivate->type = CFRetain(num);
1798	} else {
1799		SCLog(TRUE, LOG_DEBUG, CFSTR("processNetworkInterface() failed, no interface type"));
1800		return FALSE;
1801	}
1802
1803	switch (ift) {
1804		case IFT_ETHER :
1805			// Type, Hardware
1806
1807			if (IOObjectConformsTo(controller, "IO80211Controller") ||
1808			    IOObjectConformsTo(controller, "AirPortPCI"       ) ||
1809			    IOObjectConformsTo(controller, "AirPortDriver"    )) {
1810				interfacePrivate->interface_type	= kSCNetworkInterfaceTypeIEEE80211;
1811				interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
1812				interfacePrivate->sort_order		= kSortAirPort;
1813			} else if (IOObjectConformsTo(controller, "AppleThunderboltIPPort")) {
1814				interfacePrivate->interface_type	= kSCNetworkInterfaceTypeEthernet;
1815				interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
1816				interfacePrivate->sort_order		= kSortThunderbolt;
1817			} else if (IOObjectConformsTo(controller, "IOBluetoothBNEPDriver")) {
1818				interfacePrivate->interface_type	= kSCNetworkInterfaceTypeEthernet;
1819				interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
1820				interfacePrivate->sort_order		= kSortBluetoothPAN_GN;
1821			} else if (IOObjectConformsTo(controller, "AppleUSBEthernetHost")) {
1822				interfacePrivate->interface_type	= kSCNetworkInterfaceTypeEthernet;
1823				interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
1824				interfacePrivate->sort_order		= kSortTethered;
1825			} else if (IOObjectConformsTo(controller, "AppleUSBCDCECMData")) {
1826				interfacePrivate->interface_type	= kSCNetworkInterfaceTypeEthernet;
1827				interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
1828				interfacePrivate->sort_order		= kSortWWANEthernet;
1829			}
1830
1831			if (interfacePrivate->interface_type == NULL) {
1832				val = IORegistryEntrySearchCFProperty(interface,
1833								      kIOServicePlane,
1834								      CFSTR(kIOUserEthernetInterfaceRoleKey),
1835								      NULL,
1836								      kIORegistryIterateRecursively | kIORegistryIterateParents);
1837				if (val != NULL) {
1838					if (isA_CFString(val)) {
1839						if (CFEqual(val, CFSTR(BT_PAN_NAME))) {
1840							interfacePrivate->interface_type	= kSCNetworkInterfaceTypeEthernet;
1841							interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
1842							interfacePrivate->sort_order		= kSortBluetoothPAN_GN;
1843						} else if (CFEqual(val, CFSTR("Bluetooth PAN-NAP"))) {
1844							interfacePrivate->interface_type	= kSCNetworkInterfaceTypeEthernet;
1845							interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
1846							interfacePrivate->sort_order		= kSortBluetoothPAN_NAP;
1847						} else if (CFEqual(val, CFSTR("Bluetooth P2P"))) {
1848							interfacePrivate->interface_type	= kSCNetworkInterfaceTypeEthernet;
1849							interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
1850							interfacePrivate->sort_order		= kSortBluetoothPAN_U;
1851						}
1852					}
1853
1854					CFRelease(val);
1855				}
1856			}
1857
1858			if (interfacePrivate->interface_type == NULL) {
1859				str = IODictionaryCopyCFStringValue(bus_dict, CFSTR("name"));
1860				if (str != NULL) {
1861					if (CFEqual(str, CFSTR("radio"))) {
1862						interfacePrivate->interface_type	= kSCNetworkInterfaceTypeEthernet;	// ??
1863						interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
1864						interfacePrivate->sort_order		= kSortOtherWireless;
1865					}
1866
1867					CFRelease(str);
1868				}
1869			}
1870
1871			if (interfacePrivate->interface_type == NULL) {
1872				interfacePrivate->interface_type	= kSCNetworkInterfaceTypeEthernet;
1873				interfacePrivate->entity_type		= kSCValNetInterfaceTypeEthernet;
1874				interfacePrivate->sort_order		= kSortEthernet;
1875
1876				// BOND support only enabled for ethernet devices
1877				interfacePrivate->supportsBond = TRUE;
1878			}
1879
1880			// enable Bridge support
1881			interfacePrivate->supportsBridge = TRUE;
1882
1883			// built-in
1884			val = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOBuiltin)));
1885			if (val == NULL) {
1886				val = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOPrimaryInterface)));
1887			}
1888			if (val != NULL) {
1889				interfacePrivate->builtin = CFBooleanGetValue(val);
1890			} else {
1891				interfacePrivate->builtin = isBuiltin(interface);
1892			}
1893
1894			if (!interfacePrivate->builtin &&
1895			    CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) {
1896				// always treat AirPort interfaces as built-in
1897				interfacePrivate->builtin = TRUE;
1898			}
1899
1900			// location
1901			interfacePrivate->location = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOLocation));
1902			if ((interfacePrivate->location != NULL) &&
1903			    (CFStringGetLength(interfacePrivate->location) == 0)) {
1904				CFRelease(interfacePrivate->location);
1905				interfacePrivate->location = NULL;
1906			}
1907
1908			// VLAN support
1909			num = CFDictionaryGetValue(controller_dict, CFSTR(kIOFeatures));
1910			if (isA_CFNumber(num) &&
1911			    CFNumberGetValue(num, kCFNumberIntType, & iVal)) {
1912				if (iVal & (kIONetworkFeatureHardwareVlan | kIONetworkFeatureSoftwareVlan)) {
1913					interfacePrivate->supportsVLAN = TRUE;
1914				}
1915			}
1916
1917			// localized name
1918			if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) {
1919				interfacePrivate->localized_key = CFSTR("airport");
1920			} else if (interfacePrivate->sort_order == kSortThunderbolt) {
1921				if ((interfacePrivate->location == NULL) ||
1922				    (CFStringGetLength(interfacePrivate->location) == 0)) {
1923					interfacePrivate->localized_key = CFSTR("thunderbolt");
1924				} else {
1925					interfacePrivate->localized_key  = CFSTR("multithunderbolt");
1926					interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->location);
1927				}
1928			} else if (interfacePrivate->sort_order == kSortBluetoothPAN_GN) {
1929				interfacePrivate->localized_key  = CFSTR("bluetooth-pan-gn");
1930			} else if (interfacePrivate->sort_order == kSortBluetoothPAN_NAP) {
1931				interfacePrivate->localized_key  = CFSTR("bluetooth-pan-nap");
1932			} else if (interfacePrivate->sort_order == kSortBluetoothPAN_U) {
1933				interfacePrivate->localized_key  = CFSTR("bluetooth-pan-u");
1934			} else if (interfacePrivate->sort_order == kSortOtherWireless) {
1935				interfacePrivate->localized_key  = CFSTR("wireless");
1936				interfacePrivate->localized_arg1 = CFRetain(CFSTR(""));		// ??
1937			} else if (interfacePrivate->builtin) {
1938				if ((interfacePrivate->location == NULL) ||
1939				    (CFStringGetLength(interfacePrivate->location) == 0)) {
1940					interfacePrivate->localized_key = CFSTR("ether");
1941				} else {
1942					interfacePrivate->localized_key  = CFSTR("multiether");
1943					interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->location);
1944				}
1945			} else {
1946				CFStringRef	provider;
1947
1948				// check provider class
1949				provider = IORegistryEntrySearchCFProperty(interface,
1950									   kIOServicePlane,
1951									   CFSTR(kIOProviderClassKey),
1952									   NULL,
1953									   kIORegistryIterateRecursively | kIORegistryIterateParents);
1954				if (provider != NULL) {
1955					if (CFEqual(provider, CFSTR("IOPCIDevice"))) {
1956						CFStringRef		port_name;
1957						CFStringRef		slot_name;
1958
1959						// set interface "name"
1960						if (!update_interface_name(interfacePrivate, interface, FALSE) &&
1961						    pci_slot_info(interface, ift, &slot_name, &port_name)) {
1962							if (isThunderbolt(interface)) {
1963								if (port_name == NULL) {
1964									interfacePrivate->localized_key  = CFSTR("thunderbolt-ether");
1965									interfacePrivate->localized_arg1 = slot_name;
1966								} else {
1967									interfacePrivate->localized_key  = CFSTR("thunderbolt-multiether");
1968									interfacePrivate->localized_arg1 = slot_name;
1969									interfacePrivate->localized_arg2 = port_name;
1970								}
1971
1972							} else {
1973								if (port_name == NULL) {
1974									interfacePrivate->localized_key  = CFSTR("pci-ether");
1975									interfacePrivate->localized_arg1 = slot_name;
1976								} else {
1977									interfacePrivate->localized_key  = CFSTR("pci-multiether");
1978									interfacePrivate->localized_arg1 = slot_name;
1979									interfacePrivate->localized_arg2 = port_name;
1980								}
1981							}
1982						}
1983					} else {
1984						io_registry_entry_t	node	= interface;
1985
1986						while (provider != NULL) {
1987							if (CFEqual(provider, CFSTR("IOUSBDevice")) ||
1988							    CFEqual(provider, CFSTR("IOUSBInterface"))) {
1989								// get USB info (if available)
1990								processUSBInterface(interfacePrivate,
1991										    interface,
1992										    interface_dict,
1993										    controller,
1994										    controller_dict,
1995										    bus,
1996										    bus_dict);
1997
1998								// set interface "name"
1999								if (!update_interface_name(interfacePrivate, interface, TRUE)) {
2000									interfacePrivate->localized_key  = CFSTR("usb-ether");
2001									interfacePrivate->localized_arg1 = IODictionaryCopyBSDName(interface_dict);
2002								}
2003								break;
2004							}
2005
2006							if (node == interface) {
2007								node = controller;
2008							} else if (node == controller ) {
2009								node = bus;
2010							} else {
2011								break;
2012							}
2013
2014							CFRelease(provider);
2015							provider = IORegistryEntrySearchCFProperty(node,
2016												   kIOServicePlane,
2017												   CFSTR(kIOProviderClassKey),
2018												   NULL,
2019												   kIORegistryIterateRecursively | kIORegistryIterateParents);
2020						}
2021
2022						if (interfacePrivate->localized_key == NULL) {
2023							update_interface_name(interfacePrivate, interface, FALSE);
2024						}
2025					}
2026
2027					if (provider != NULL) CFRelease(provider);
2028				}
2029
2030				if (interfacePrivate->localized_key == NULL) {
2031					// if no provider, not a PCI device, or no slot information
2032					interfacePrivate->localized_key  = CFSTR("generic-ether");
2033					interfacePrivate->localized_arg1 = IODictionaryCopyBSDName(interface_dict);
2034				}
2035			}
2036
2037			break;
2038		case IFT_IEEE1394 :
2039			// Type
2040			interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire;
2041
2042			// Entity
2043			interfacePrivate->entity_type = kSCValNetInterfaceTypeFireWire;
2044
2045			// built-in
2046			interfacePrivate->builtin = isBuiltin(interface);
2047
2048			// sort order
2049			interfacePrivate->sort_order = kSortFireWire;
2050
2051			// localized name
2052			if (interfacePrivate->builtin) {
2053				interfacePrivate->localized_key = CFSTR("firewire");
2054			} else {
2055				CFStringRef	port_name;
2056				CFStringRef	slot_name;
2057
2058				// set interface "name"
2059				if (!update_interface_name(interfacePrivate, interface, FALSE) &&
2060				    pci_slot_info(interface, ift, &slot_name, &port_name)) {
2061					if (isThunderbolt(interface)) {
2062						if (port_name == NULL) {
2063							interfacePrivate->localized_key  = CFSTR("thunderbolt-firewire");
2064							interfacePrivate->localized_arg1 = slot_name;
2065						} else {
2066							interfacePrivate->localized_key  = CFSTR("thunderbolt-multifirewire");
2067							interfacePrivate->localized_arg1 = slot_name;
2068							interfacePrivate->localized_arg2 = port_name;
2069						}
2070					} else {
2071						if (port_name == NULL) {
2072							interfacePrivate->localized_key  = CFSTR("pci-firewire");
2073							interfacePrivate->localized_arg1 = slot_name;
2074						} else {
2075							interfacePrivate->localized_key  = CFSTR("pci-multifirewire");
2076							interfacePrivate->localized_arg1 = slot_name;
2077							interfacePrivate->localized_arg2 = port_name;
2078						}
2079					}
2080				}
2081			}
2082
2083			break;
2084		default :
2085			SCLog(TRUE, LOG_DEBUG, CFSTR("processNetworkInterface() failed, unknown interface type = %d"), ift);
2086			return FALSE;
2087	}
2088
2089	// Device
2090	interfacePrivate->entity_device = IODictionaryCopyBSDName(interface_dict);
2091
2092	// Hardware (MAC) address
2093	data = CFDictionaryGetValue(controller_dict, CFSTR(kIOMACAddress));
2094	if (isA_CFData(data)) {
2095		interfacePrivate->address = CFRetain(data);
2096	}
2097
2098	// interface prefix
2099	str = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceNamePrefix));
2100	if (isA_CFString(str)) {
2101		interfacePrivate->prefix = CFRetain(str);
2102	}
2103
2104	// interface unit
2105	num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceUnit));
2106	if (isA_CFNumber(num) &&
2107	    CFNumberGetValue(num, kCFNumberIntType, & iVal)) {
2108		interfacePrivate->unit = CFRetain(num);
2109	}
2110
2111	// configuration [PPP] template override (now deprecated, use NetworkConfigurationOverrides)
2112	merge_override(interfacePrivate, interface, kSCNetworkInterfaceTypePPP);
2113
2114	return TRUE;
2115}
2116
2117
2118static void
2119set_connection_script(SCNetworkInterfacePrivateRef interfacePrivate, CFStringRef script)
2120{
2121	CFDictionaryRef		dict;
2122	CFMutableDictionaryRef	newDict;
2123
2124	if (interfacePrivate->overrides == NULL) {
2125		interfacePrivate->overrides = CFDictionaryCreateMutable(NULL,
2126									0,
2127									&kCFTypeDictionaryKeyCallBacks,
2128									&kCFTypeDictionaryValueCallBacks);
2129	}
2130
2131	dict = CFDictionaryGetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem);
2132	if (dict != NULL) {
2133		newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
2134	} else {
2135		newDict = CFDictionaryCreateMutable(NULL,
2136						    0,
2137						    &kCFTypeDictionaryKeyCallBacks,
2138						    &kCFTypeDictionaryValueCallBacks);
2139	}
2140	if (script != NULL) {
2141		CFDictionarySetValue(newDict, kSCPropNetModemConnectionScript, script);
2142	} else {
2143		CFDictionaryRemoveValue(newDict, kSCPropNetModemConnectionScript);
2144	}
2145	if (CFDictionaryGetCount(newDict) > 0) {
2146		CFDictionarySetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem, newDict);
2147	} else {
2148		CFDictionaryRemoveValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem);
2149	}
2150	CFRelease(newDict);
2151
2152	if (CFDictionaryGetCount(interfacePrivate->overrides) == 0) {
2153		CFRelease(interfacePrivate->overrides);
2154		interfacePrivate->overrides = NULL;
2155	}
2156	return;
2157}
2158
2159
2160static Boolean
2161is_valid_connection_script(CFStringRef script)
2162{
2163	char				ccl[MAXPATHLEN];
2164	char				path[MAXPATHLEN];
2165	NSSearchPathEnumerationState	state;
2166
2167	(void) _SC_cfstring_to_cstring(script,
2168				       ccl,
2169				       sizeof(ccl),
2170				       kCFStringEncodingUTF8);
2171
2172	state = NSStartSearchPathEnumeration(NSLibraryDirectory,
2173					     NSLocalDomainMask|NSSystemDomainMask);
2174	while ((state = NSGetNextSearchPathEnumeration(state, path))) {
2175		size_t		n;
2176		struct stat	statBuf;
2177
2178		if (ccl[0] == '/') {
2179			path[0] = '\0';		// if modemCCL is a full path
2180		} else {
2181			strlcat(path, "/Modem Scripts/", sizeof(path));
2182		}
2183		strlcat(path, ccl, sizeof(path));
2184
2185		if (stat(path, &statBuf) != 0) {
2186			if (errno == ENOENT) {
2187				goto bundle;
2188			}
2189
2190			SCLog(TRUE, LOG_DEBUG,
2191			      CFSTR("processSerialInterface stat() failed: %s"),
2192			      strerror(errno));
2193			continue;
2194		}
2195		if (S_ISREG(statBuf.st_mode)) {
2196			// if we have a valid CCL script
2197			return TRUE;
2198		}
2199
2200#define	BUNDLE_EXT	".ccl"
2201#define	BUNDLE_EXT_LEN	sizeof(BUNDLE_EXT) - 1
2202
2203	    bundle :
2204
2205		n = strlen(path);
2206		if ((n <= BUNDLE_EXT_LEN) ||
2207		    (strstr(&path[n - BUNDLE_EXT_LEN], BUNDLE_EXT) == NULL)) {
2208			strlcat(path, BUNDLE_EXT, sizeof(path));
2209			if (stat(path, &statBuf) != 0) {
2210				if (errno == ENOENT) {
2211					continue;
2212				}
2213
2214				SCLog(TRUE, LOG_DEBUG,
2215				      CFSTR("processSerialInterface stat() failed: %s"),
2216				      strerror(errno));
2217				continue;
2218			}
2219		}
2220		if (S_ISDIR(statBuf.st_mode)) {
2221			// if we have a valid CCL bundle
2222			return TRUE;
2223		}
2224	}
2225
2226	return FALSE;
2227}
2228
2229
2230static Boolean
2231processSerialInterface(SCNetworkInterfacePrivateRef	interfacePrivate,
2232		       io_registry_entry_t		interface,
2233		       CFDictionaryRef			interface_dict,
2234		       io_registry_entry_t		controller,
2235		       CFDictionaryRef			controller_dict,
2236		       io_registry_entry_t		bus,
2237		       CFDictionaryRef			bus_dict)
2238{
2239	CFStringRef		base		= NULL;
2240	CFStringRef		ift;
2241	Boolean			isModem		= FALSE;
2242	Boolean			isWWAN		= FALSE;
2243	CFStringRef		modemCCL	= NULL;
2244	Boolean			ok		= FALSE;
2245	CFTypeRef		val;
2246
2247	// check if initializing
2248	val = IORegistryEntrySearchCFProperty(interface,
2249					      kIOServicePlane,
2250					      kSCNetworkInterfaceInitializingKey,
2251					      NULL,
2252					      kIORegistryIterateRecursively | kIORegistryIterateParents);
2253	if (val != NULL) {
2254		Boolean	initializing;
2255
2256		initializing = isA_CFBoolean(val) && CFBooleanGetValue(val);
2257		CFRelease(val);
2258		if (initializing) {
2259			return FALSE;	// if this interface is still initializing
2260		}
2261	}
2262
2263	// check if WWAN
2264	val = IORegistryEntrySearchCFProperty(interface,
2265					      kIOServicePlane,
2266					      CFSTR("WWAN"),
2267					      NULL,
2268					      kIORegistryIterateRecursively | kIORegistryIterateParents);
2269	if (val != NULL) {
2270		isWWAN = isA_CFBoolean(val) && CFBooleanGetValue(val);
2271		CFRelease(val);
2272	}
2273
2274	// Entity (Device)
2275	interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOTTYDeviceKey));
2276	if (interfacePrivate->entity_device == NULL) {
2277		return FALSE;
2278	}
2279
2280	base = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOTTYBaseNameKey));
2281	if (base == NULL) {
2282		base = CFRetain(interfacePrivate->entity_device);
2283	}
2284
2285	/*
2286	 * From MoreSCF:
2287	 *
2288	 * Exclude ports named "irda" because otherwise the IrDA ports on the
2289	 * original iMac (rev's A through D) show up as serial ports.  Given
2290	 * that only the rev A actually had an IrDA port, and Mac OS X doesn't
2291	 * even support it, these ports definitely shouldn't be listed.
2292	 */
2293	if (CFStringCompare(base,
2294			    CFSTR("irda"),
2295			    kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
2296		goto done;
2297	}
2298
2299	if (IOStringValueHasPrefix(base, CFSTR("bluetooth"))) {
2300		Boolean	haveController	= FALSE;
2301
2302		// Bluetooth
2303		interfacePrivate->interface_type	= kSCNetworkInterfaceTypeBluetooth;
2304		interfacePrivate->sort_order		= kSortBluetooth;
2305		interfacePrivate->builtin		= isBluetoothBuiltin(&haveController);
2306		if (!haveController) {
2307			// if device with no controller present
2308			goto done;
2309		}
2310	} else if (IOStringValueHasPrefix(base, CFSTR("irda-ircomm"))) {
2311		// IrDA
2312		interfacePrivate->interface_type	= kSCNetworkInterfaceTypeIrDA;
2313		interfacePrivate->sort_order		= kSortIrDA;
2314	} else if (isWWAN) {
2315		// WWAN
2316		interfacePrivate->interface_type	= kSCNetworkInterfaceTypeWWAN;
2317		interfacePrivate->sort_order		= kSortWWAN;
2318	} else {
2319		// Modem
2320		interfacePrivate->interface_type	= kSCNetworkInterfaceTypeModem;
2321		interfacePrivate->sort_order		= kSortModem;
2322
2323		// V.92 support
2324		val = IORegistryEntrySearchCFProperty(interface,
2325						      kIOServicePlane,
2326						      CFSTR(kIODeviceSupportsHoldKey),
2327						      NULL,
2328						      kIORegistryIterateRecursively | kIORegistryIterateParents);
2329		if (val != NULL) {
2330			uint32_t	v92;
2331
2332			if (isA_CFNumber(val) &&
2333			    CFNumberGetValue(val, kCFNumberSInt32Type, &v92)) {
2334				interfacePrivate->modemIsV92 = (v92 == 1);
2335			}
2336			CFRelease(val);
2337		}
2338	}
2339
2340	// Entity (Type)
2341	interfacePrivate->entity_type = kSCEntNetModem;
2342
2343	// Entity (Hardware)
2344	ift = CFDictionaryGetValue(interface_dict, CFSTR(kIOSerialBSDTypeKey));
2345	if (!isA_CFString(ift)) {
2346		goto done;
2347	}
2348
2349	if (CFEqual(ift, CFSTR(kIOSerialBSDModemType))) {
2350		// if modem
2351		isModem = TRUE;
2352
2353		if (CFEqual(base, CFSTR("modem"))) {
2354			interfacePrivate->builtin = TRUE;
2355			interfacePrivate->sort_order = kSortInternalModem;
2356		} else if (CFEqual(base, CFSTR("usbmodem"))) {
2357			interfacePrivate->sort_order = kSortUSBModem;
2358		}
2359	} else if (CFEqual(ift, CFSTR(kIOSerialBSDRS232Type))) {
2360		// if serial port
2361		interfacePrivate->sort_order = kSortSerialPort;
2362	} else {
2363		goto done;
2364	}
2365
2366	// configuration [PPP] template override   (now deprecated, use NetworkConfigurationOverrides)
2367	merge_override(interfacePrivate, interface, kSCNetworkInterfaceTypePPP);
2368
2369	// configuration [Modem] template override (now deprecated, use NetworkConfigurationOverrides)
2370	merge_override(interfacePrivate, interface, kSCNetworkInterfaceTypeModem);
2371
2372	// look for modem CCL, unique identifier
2373	if (interfacePrivate->overrides != NULL) {
2374		val = CFDictionaryGetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem);
2375		if (val != NULL) {
2376			CFStringRef	uniqueID;
2377
2378			modemCCL = CFDictionaryGetValue(val, kSCPropNetModemConnectionScript);
2379			modemCCL = isA_CFString(modemCCL);
2380
2381			uniqueID = CFDictionaryGetValue(val, CFSTR("UniqueIdentifier"));
2382			uniqueID = isA_CFString(uniqueID);
2383			if (uniqueID != NULL) {
2384				// retain the device's base name and the unique id
2385				CFRelease(interfacePrivate->entity_device);
2386				interfacePrivate->entity_device = CFRetain(base);
2387				interfacePrivate->entity_device_unique = CFStringCreateCopy(NULL, uniqueID);
2388			}
2389		}
2390	}
2391
2392	// if not part of the NetworkConfigurationOverrides/DeviceModemOverrides, look
2393	// a bit harder for the modem CCL
2394	if (modemCCL == NULL) {
2395		val = IORegistryEntrySearchCFProperty(interface,
2396						      kIOServicePlane,
2397						      CFSTR("ModemCCL"),
2398						      NULL,
2399						      kIORegistryIterateRecursively | kIORegistryIterateParents);
2400		if (val != NULL) {
2401			modemCCL = IOCopyCFStringValue(val);
2402			if (modemCCL != NULL) {
2403				set_connection_script(interfacePrivate, modemCCL);
2404				CFRelease(modemCCL);
2405			}
2406
2407			CFRelease(val);
2408		}
2409	}
2410
2411	// localized name
2412	if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIrDA)) {
2413		interfacePrivate->localized_key = CFSTR("irda");
2414	} else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBluetooth)) {
2415		interfacePrivate->localized_key = CFSTR("bluetooth");
2416	} else {
2417		CFStringRef		localized	= NULL;
2418		CFStringRef		name		= NULL;
2419		CFMutableStringRef	port;
2420
2421		port = CFStringCreateMutableCopy(NULL, 0, base);
2422		CFStringLowercase(port, NULL);
2423
2424		if (!isModem) {
2425			CFStringAppend(port, CFSTR("-port"));
2426		}
2427
2428		// set non-localized name
2429		if (bundle != NULL) {
2430			name = copy_interface_string(bundle, port, FALSE);
2431		}
2432		if (name != NULL) {
2433			if (!CFEqual(port, name)) {
2434				// if [English] localization available
2435				interfacePrivate->name = name;
2436			} else {
2437				// if no [English] localization available, use TTY base name
2438				CFRelease(name);
2439				interfacePrivate->name = CFStringCreateCopy(NULL, base);
2440			}
2441		} else {
2442			interfacePrivate->name = CFStringCreateCopy(NULL, base);
2443		}
2444
2445		// set localized name
2446		if (bundle != NULL) {
2447			localized = copy_interface_string(bundle, port, TRUE);
2448		}
2449		if (localized != NULL) {
2450			if (!CFEqual(port, localized)) {
2451				// if localization available
2452				interfacePrivate->localized_name = localized;
2453			} else {
2454				// if no localization available, use TTY base name
2455				CFRelease(localized);
2456				interfacePrivate->localized_name = CFStringCreateCopy(NULL, base);
2457			}
2458		} else {
2459			interfacePrivate->localized_name = CFStringCreateCopy(NULL, base);
2460		}
2461
2462		if (!isModem || !CFEqual(base, CFSTR("modem"))) {
2463			// get USB info (if available)
2464			processUSBInterface(interfacePrivate,
2465					    interface,
2466					    interface_dict,
2467					    controller,
2468					    controller_dict,
2469					    bus,
2470					    bus_dict);
2471
2472			// set interface "name"
2473			if (update_interface_name(interfacePrivate, interface, TRUE)) {
2474				// if "ModemCCL" not provided, also check if the product/interface
2475				// name matches a CCL script
2476				if ((modemCCL == NULL) &&
2477				    is_valid_connection_script(interfacePrivate->name)) {
2478					set_connection_script(interfacePrivate, interfacePrivate->name);
2479				}
2480			}
2481		}
2482
2483		CFRelease(port);
2484	}
2485
2486	ok = TRUE;
2487
2488    done :
2489
2490	if (!ok && (interfacePrivate->entity_device != NULL)) {
2491		CFRelease(interfacePrivate->entity_device);
2492		interfacePrivate->entity_device = NULL;
2493	}
2494	if (base != NULL) CFRelease(base);
2495
2496	return ok;
2497}
2498
2499
2500static CFStringRef
2501__SC_IORegistryEntryCopyPath(io_registry_entry_t entry, const io_name_t plane)
2502{
2503	/*
2504	 * Create a path for a registry entry.
2505	 */
2506	io_string_t	path;
2507	IOReturn	status;
2508	CFStringRef	str	= NULL;
2509
2510	status = IORegistryEntryGetPath(entry, plane, path);
2511	if (status == kIOReturnSuccess) {
2512		str = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8);
2513	} else if (status == kIOReturnBadArgument) {
2514		io_registry_entry_t	parent;
2515
2516		status = IORegistryEntryGetParentEntry(entry, plane, &parent);
2517		if (status == kIOReturnSuccess) {
2518			CFStringRef	str_parent;
2519
2520			str_parent = __SC_IORegistryEntryCopyPath(parent, plane);
2521			if (str_parent != NULL) {
2522				io_name_t	name;
2523
2524				status = IORegistryEntryGetNameInPlane(entry, plane, name);
2525				if (status == kIOReturnSuccess) {
2526					io_name_t	location;
2527
2528					status = IORegistryEntryGetLocationInPlane(entry, plane, location);
2529					if (status == kIOReturnSuccess) {
2530						str = CFStringCreateWithFormat(NULL,
2531									       NULL,
2532									       CFSTR("%@/%s@%s"),
2533									       str_parent,
2534									       name,
2535									       location);
2536					} else {
2537						str = CFStringCreateWithFormat(NULL,
2538									       NULL,
2539									       CFSTR("%@/%s"),
2540									       str_parent,
2541									       name);
2542					}
2543				}
2544
2545				CFRelease(str_parent);
2546			}
2547
2548			IOObjectRelease(parent);
2549		}
2550	}
2551
2552	return str;
2553}
2554
2555
2556static SCNetworkInterfaceRef
2557createInterface(io_registry_entry_t interface, processInterface func,
2558		CFStringRef hidden_key)
2559{
2560	io_registry_entry_t		bus			= MACH_PORT_NULL;
2561	CFMutableDictionaryRef		bus_dict		= NULL;
2562	io_registry_entry_t		controller		= MACH_PORT_NULL;
2563	CFMutableDictionaryRef		controller_dict		= NULL;
2564	uint64_t			entryID			= 0;
2565	SCNetworkInterfacePrivateRef	interfacePrivate	= NULL;
2566	CFMutableDictionaryRef		interface_dict		= NULL;
2567	kern_return_t			kr;
2568	CFTypeRef			val;
2569
2570	if (hidden_key != NULL) {
2571		// check if hidden
2572		val = IORegistryEntrySearchCFProperty(interface,
2573						      kIOServicePlane,
2574						      hidden_key,
2575						      NULL,
2576						      kIORegistryIterateRecursively | kIORegistryIterateParents);
2577		if (val != NULL) {
2578			CFRelease(val);
2579			goto done;	// if this interface should not be exposed
2580		}
2581	}
2582
2583	// get the dictionary associated with the [interface] node
2584	kr = IORegistryEntryCreateCFProperties(interface, &interface_dict, NULL, kNilOptions);
2585	if (kr != kIOReturnSuccess) {
2586		SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
2587		goto done;
2588	}
2589
2590	// get the controller node
2591	kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &controller);
2592	if (kr != kIOReturnSuccess) {
2593		SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
2594		goto done;
2595	}
2596
2597	// get the dictionary associated with the [controller] node
2598	kr = IORegistryEntryCreateCFProperties(controller, &controller_dict, NULL, kNilOptions);
2599	if (kr != kIOReturnSuccess) {
2600		SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
2601		goto done;
2602	}
2603
2604	// get the bus node
2605	kr = IORegistryEntryGetParentEntry(controller, kIOServicePlane, &bus);
2606	if (kr != kIOReturnSuccess) {
2607		SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
2608		goto done;
2609	}
2610
2611	// get the dictionary associated with the [bus] node
2612	kr = IORegistryEntryCreateCFProperties(bus, &bus_dict, NULL, kNilOptions);
2613	if (kr != kIOReturnSuccess) {
2614		SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
2615		goto done;
2616	}
2617
2618	// get the registry entry ID
2619	kr = IORegistryEntryGetRegistryEntryID(interface, &entryID);
2620	if (kr != kIOReturnSuccess) {
2621		SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetRegistryEntryID() failed, kr = 0x%x"), kr);
2622		goto done;
2623	}
2624
2625	interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
2626	assert(interfacePrivate != NULL);
2627	interfacePrivate->path = __SC_IORegistryEntryCopyPath(interface, kIOServicePlane);
2628	interfacePrivate->entryID = entryID;
2629
2630	// configuration [PPP, Modem, DNS, IPv4, IPv6, Proxies, SMB] template overrides
2631	val = IORegistryEntrySearchCFProperty(interface,
2632					      kIOServicePlane,
2633					      kSCNetworkInterfaceNetworkConfigurationOverridesKey,
2634					      NULL,
2635					      kIORegistryIterateRecursively | kIORegistryIterateParents);
2636	if (val != NULL) {
2637		if (isA_CFDictionary(val)) {
2638			interfacePrivate->overrides = CFDictionaryCreateMutableCopy(NULL, 0, val);
2639		}
2640		CFRelease(val);
2641	}
2642
2643	if ((*func)(interfacePrivate, interface, interface_dict, controller, controller_dict, bus, bus_dict)) {
2644		// get user-notification / auto-configuration preference
2645		val = IORegistryEntrySearchCFProperty(interface,
2646						      kIOServicePlane,
2647						      kSCNetworkInterfaceConfigurationActionKey,
2648						      NULL,
2649						      kIORegistryIterateRecursively | kIORegistryIterateParents);
2650		if (val != NULL) {
2651			if (isA_CFString(val)) {
2652				interfacePrivate->configurationAction = CFRetain(val);
2653			}
2654			CFRelease(val);
2655		}
2656
2657		// get HiddenConfiguration preference
2658		val = IORegistryEntrySearchCFProperty(interface,
2659						      kIOServicePlane,
2660						      kSCNetworkInterfaceHiddenConfigurationKey,
2661						      NULL,
2662						      kIORegistryIterateRecursively | kIORegistryIterateParents);
2663		if (val != NULL) {
2664			interfacePrivate->hidden = TRUE;
2665			CFRelease(val);
2666		}
2667	} else {
2668		CFRelease(interfacePrivate);
2669		interfacePrivate = NULL;
2670	}
2671
2672    done :
2673
2674	if (interface_dict != NULL)		CFRelease(interface_dict);
2675
2676	if (controller != MACH_PORT_NULL)	IOObjectRelease(controller);
2677	if (controller_dict != NULL)		CFRelease(controller_dict);
2678
2679	if (bus != MACH_PORT_NULL)		IOObjectRelease(bus);
2680	if (bus_dict != NULL)			CFRelease(bus_dict);
2681
2682	return (SCNetworkInterfaceRef)interfacePrivate;
2683}
2684
2685
2686static CF_RETURNS_RETAINED CFArrayRef
2687findMatchingInterfaces(CFDictionaryRef matching, processInterface func,
2688		       CFStringRef hidden_key)
2689{
2690	CFMutableArrayRef	interfaces;
2691	io_registry_entry_t	interface;
2692	kern_return_t		kr;
2693	io_iterator_t		iterator	= MACH_PORT_NULL;
2694
2695	/*
2696	 * A reference to the "matching" dictionary will be consumed by the
2697	 * the call to IOServiceGetMatchingServices so we bump up the retain
2698	 * count.
2699	 */
2700	CFRetain(matching);
2701
2702	kr = IOServiceGetMatchingServices(masterPort, matching, &iterator);
2703	if (kr != kIOReturnSuccess) {
2704		SCLog(TRUE, LOG_DEBUG, CFSTR("findMatchingInterfaces IOServiceGetMatchingServices() failed, kr = 0x%x"), kr);
2705		return NULL;
2706	}
2707
2708	interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2709
2710	while ((interface = IOIteratorNext(iterator)) != MACH_PORT_NULL) {
2711		SCNetworkInterfaceRef		match;
2712
2713		match = createInterface(interface, func, hidden_key);
2714		if (match != NULL) {
2715			CFArrayAppendValue(interfaces, match);
2716			CFRelease(match);
2717		}
2718
2719		IOObjectRelease(interface);
2720	}
2721
2722	IOObjectRelease(iterator);
2723
2724	return interfaces;
2725}
2726
2727
2728#pragma mark -
2729#pragma mark helper functions
2730
2731
2732static CFIndex
2733findConfiguration(CFStringRef interface_type)
2734{
2735	CFIndex i;
2736
2737	for (i = 0; i < sizeof(configurations)/sizeof(configurations[0]); i++) {
2738		if (CFEqual(interface_type, *configurations[i].interface_type)) {
2739			return i;
2740		}
2741	}
2742
2743	return kCFNotFound;
2744}
2745
2746
2747__private_extern__
2748CFStringRef
2749__SCNetworkInterfaceGetDefaultConfigurationType(SCNetworkInterfaceRef interface)
2750{
2751	CFIndex				interfaceIndex;
2752	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
2753
2754	if (interfacePrivate->serviceID == NULL) {
2755		// if not associated with a service (yet)
2756		_SCErrorSet(kSCStatusInvalidArgument);
2757		return NULL;
2758	}
2759
2760	interfaceIndex = findConfiguration(interfacePrivate->interface_type);
2761	if (interfaceIndex == kCFNotFound) {
2762		// unknown interface type, use per-service configuration preferences
2763		return interfacePrivate->interface_type;	// entity
2764	}
2765
2766	if (configurations[interfaceIndex].entity_hardware != NULL) {
2767		// if configuration information can be associated with this interface type
2768		return *configurations[interfaceIndex].entity_hardware;
2769	}
2770
2771	_SCErrorSet(kSCStatusInvalidArgument);
2772	return NULL;
2773}
2774
2775
2776__private_extern__
2777Boolean
2778__SCNetworkInterfaceIsValidExtendedConfigurationType(SCNetworkInterfaceRef	interface,
2779						     CFStringRef		extendedType,
2780						     Boolean			requirePerInterface)
2781{
2782	CFStringRef			defaultType;
2783	CFIndex				extendedIndex;
2784	CFIndex				interfaceIndex;
2785	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
2786	Boolean				isL2TP			= FALSE;
2787	Boolean				ok			= FALSE;
2788
2789	defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
2790	if (defaultType == NULL) {
2791		goto done;
2792	}
2793
2794	if (CFEqual(extendedType, defaultType)) {
2795		// extended and default configuration types cannot conflict
2796		goto done;
2797	}
2798
2799	interfaceIndex = findConfiguration(interfacePrivate->interface_type);
2800	if (interfaceIndex == kCFNotFound) {
2801		// configuration information for unknown interface type's
2802		// are stored along with the service and we don't allow
2803		// per-service extended configurations
2804		goto done;
2805	}
2806
2807	if (CFEqual(extendedType, kSCEntNetIPSec)) {
2808		CFStringRef	interfaceType;
2809
2810		interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
2811		if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
2812			SCNetworkInterfaceRef	child;
2813
2814			child = SCNetworkInterfaceGetInterface(interface);
2815			if (child != NULL) {
2816				interfaceType = SCNetworkInterfaceGetInterfaceType(child);
2817				if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
2818					isL2TP = TRUE;
2819				}
2820			}
2821		}
2822	}
2823
2824	if (requirePerInterface &&
2825	    !configurations[interfaceIndex].per_interface_config &&
2826	    !isL2TP) {
2827		// we don't allow per-service extended configurations (except
2828		// that we do allow IPSec as an extended type for PPP->L2TP)
2829		goto done;
2830	}
2831
2832	extendedIndex = findConfiguration(extendedType);
2833	if ((extendedIndex != kCFNotFound) && !isL2TP) {
2834		// extended type cannot match a known interface type (except
2835		// that we do allow IPSec as an extended type for PPP->L2TP)
2836		goto done;
2837	}
2838
2839	/*
2840	 * ???
2841	 * Do we match specific/known extended configuration types (e.g. EAPOL)
2842	 * and ensure that any non-standard extended configuration types be of
2843	 * the form com.myCompany.myType?
2844	 * ???
2845	 */
2846
2847	ok = TRUE;
2848
2849    done :
2850
2851	if (!ok) {
2852		_SCErrorSet(kSCStatusInvalidArgument);
2853	}
2854	return ok;
2855}
2856
2857
2858typedef struct {
2859	CFStringRef		defaultType;
2860	CFMutableArrayRef	types;
2861} extendedConfiguration, *extendedConfigurationRef;
2862
2863
2864static void
2865__addExtendedConfigurationType(const void *key, const void *value, void *context)
2866{
2867	CFStringRef			extendedType	= (CFStringRef)key;
2868	extendedConfigurationRef	myContextRef	= (extendedConfigurationRef)context;
2869
2870	if (CFEqual(extendedType, myContextRef->defaultType)) {
2871		// do not include the default configuration type
2872		return;
2873	}
2874
2875	if (CFArrayContainsValue(myContextRef->types,
2876				 CFRangeMake(0, CFArrayGetCount(myContextRef->types)),
2877				 extendedType)) {
2878		// if extendedType already has already been added
2879		return;
2880	}
2881
2882	CFArrayAppendValue(myContextRef->types, extendedType);
2883
2884	return;
2885}
2886
2887
2888static CF_RETURNS_RETAINED CFArrayRef
2889extendedConfigurationTypes(SCNetworkInterfaceRef interface)
2890{
2891	CFIndex				i;
2892	CFIndex				interfaceIndex;
2893	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
2894	extendedConfiguration		myContext;
2895	SCNetworkServiceRef		service;
2896	CFArrayRef			sets;
2897	CFIndex				n;
2898
2899	myContext.defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
2900	if (myContext.defaultType == NULL) {
2901		myContext.types = NULL;
2902		goto done;
2903	}
2904
2905	myContext.types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2906
2907	if (interfacePrivate->serviceID == NULL) {
2908		// if not associated with a service (yet)
2909		goto done;
2910	}
2911
2912	interfaceIndex = findConfiguration(interfacePrivate->interface_type);
2913	if (interfaceIndex == kCFNotFound) {
2914		// we don't allow per-service extended configurations
2915		goto done;
2916	}
2917
2918	if (!configurations[interfaceIndex].per_interface_config) {
2919		// known interface type but we still don't allow
2920		// per-service extended configurations
2921		goto done;
2922	}
2923
2924	service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
2925								       interfacePrivate->prefs,
2926								       interfacePrivate->serviceID,
2927								       interface);
2928
2929	sets = SCNetworkSetCopyAll(interfacePrivate->prefs);
2930	n = (sets != NULL) ? CFArrayGetCount(sets) : 0;
2931
2932	for (i = 0; i < n; i++) {
2933		CFDictionaryRef		configs;
2934		Boolean			found;
2935		CFStringRef		path;
2936		CFArrayRef		services;
2937		SCNetworkSetRef		set;
2938
2939		set = CFArrayGetValueAtIndex(sets, i);
2940		services = SCNetworkSetCopyServices(set);
2941		found = CFArrayContainsValue(services,
2942					     CFRangeMake(0, CFArrayGetCount(services)),
2943					     service);
2944		CFRelease(services);
2945
2946		if (!found) {
2947			continue;
2948		}
2949
2950		// add stored extended configuration types
2951		path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL,				// allocator
2952									   SCNetworkSetGetSetID(set),		// set
2953									   interfacePrivate->entity_device,	// service
2954									   NULL);				// entity
2955		configs = __getPrefsConfiguration(interfacePrivate->prefs, path);
2956		CFRelease(path);
2957		if (isA_CFDictionary(configs)) {
2958			CFDictionaryApplyFunction(configs,
2959						  __addExtendedConfigurationType,
2960						  &myContext);
2961		}
2962
2963		// add not-yet-stored extended configuration types
2964		if (interfacePrivate->unsaved != NULL) {
2965			CFDictionaryApplyFunction(interfacePrivate->unsaved,
2966						  __addExtendedConfigurationType,
2967						  &myContext);
2968		}
2969
2970		break;
2971	}
2972
2973	CFRelease(service);
2974	if (sets != NULL) CFRelease(sets);
2975
2976    done :
2977
2978	return myContext.types;
2979}
2980
2981
2982static CFArrayRef
2983copyConfigurationPaths(SCNetworkInterfacePrivateRef	interfacePrivate,
2984		       CFStringRef			extendedType)
2985{
2986	CFMutableArrayRef		array;
2987	CFIndex				i;
2988	CFIndex				interfaceIndex;
2989	CFIndex				n;
2990	CFStringRef			path;
2991	SCNetworkServiceRef		service;
2992	CFArrayRef			sets;
2993
2994	array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2995
2996	interfaceIndex = findConfiguration(interfacePrivate->interface_type);
2997	if (interfaceIndex == kCFNotFound) {
2998		// unknown interface type, use per-service configuration preferences
2999		path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,				// allocator
3000								      interfacePrivate->serviceID,	// service
3001								      extendedType);			// entity
3002		CFArrayAppendValue(array, path);
3003		CFRelease(path);
3004		return array;
3005	}
3006
3007	if (!configurations[interfaceIndex].per_interface_config) {
3008		// known interface type, per-service configuration preferences
3009		path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,				// allocator
3010								      interfacePrivate->serviceID,	// service
3011								      extendedType);			// entity
3012		CFArrayAppendValue(array, path);
3013		CFRelease(path);
3014		return array;
3015	}
3016
3017	// known interface type, per-interface configuration preferences
3018	//
3019	// 1. look for all sets which contain the associated service
3020	// 2. add a per-set path for the interface configuration for
3021	//    each set.
3022
3023	service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
3024								       interfacePrivate->prefs,
3025								       interfacePrivate->serviceID,
3026								       (SCNetworkInterfaceRef)interfacePrivate);
3027
3028	sets = SCNetworkSetCopyAll(interfacePrivate->prefs);
3029	n = (sets != NULL) ? CFArrayGetCount(sets) : 0;
3030
3031	for (i = 0; i < n; i++) {
3032		CFArrayRef      services;
3033		SCNetworkSetRef set;
3034
3035		set = CFArrayGetValueAtIndex(sets, i);
3036		services = SCNetworkSetCopyServices(set);
3037		if (CFArrayContainsValue(services,
3038					 CFRangeMake(0, CFArrayGetCount(services)),
3039					 service)) {
3040			path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL,				// allocator
3041										   SCNetworkSetGetSetID(set),		// set
3042										   interfacePrivate->entity_device,	// service
3043										   extendedType);			// entity
3044			CFArrayAppendValue(array, path);
3045			CFRelease(path);
3046		}
3047		CFRelease(services);
3048	}
3049
3050	if (CFArrayGetCount(array) == 0) {
3051		CFRelease(array);
3052		array = NULL;
3053	}
3054
3055	CFRelease(service);
3056	if (sets != NULL) CFRelease(sets);
3057	return array;
3058}
3059
3060
3061#pragma mark -
3062#pragma mark SCNetworkInterface <--> preferences entity
3063
3064
3065__private_extern__
3066CFDictionaryRef
3067__SCNetworkInterfaceCopyInterfaceEntity(SCNetworkInterfaceRef interface)
3068{
3069	CFMutableDictionaryRef		entity;
3070	CFIndex				interfaceIndex;
3071	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
3072
3073	entity = CFDictionaryCreateMutable(NULL,
3074					   0,
3075					   &kCFTypeDictionaryKeyCallBacks,
3076					   &kCFTypeDictionaryValueCallBacks);
3077	if (interfacePrivate->entity_type != NULL) {
3078		CFDictionarySetValue(entity,
3079				     kSCPropNetInterfaceType,
3080				     interfacePrivate->entity_type);
3081	}
3082	if (interfacePrivate->entity_subtype != NULL) {
3083		CFDictionarySetValue(entity,
3084				     kSCPropNetInterfaceSubType,
3085				     interfacePrivate->entity_subtype);
3086	}
3087	if (interfacePrivate->entity_device != NULL) {
3088		CFDictionarySetValue(entity,
3089				     kSCPropNetInterfaceDeviceName,
3090				     interfacePrivate->entity_device);
3091	}
3092	if (interfacePrivate->entity_device_unique != NULL) {
3093		CFDictionarySetValue(entity,
3094				     CFSTR("DeviceUniqueIdentifier"),
3095				     interfacePrivate->entity_device_unique);
3096	}
3097	if (interfacePrivate->hidden) {
3098		CFDictionarySetValue(entity,
3099				     kSCNetworkInterfaceHiddenConfigurationKey,
3100				     kCFBooleanTrue);
3101	}
3102
3103	// match the "hardware" with the lowest layer
3104	while (TRUE) {
3105		SCNetworkInterfaceRef	nextInterface;
3106
3107		nextInterface = SCNetworkInterfaceGetInterface(interface);
3108		if (nextInterface == NULL) {
3109			break;
3110		}
3111
3112		interface = nextInterface;
3113	}
3114	interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3115
3116	if (CFEqual(interface, kSCNetworkInterfaceIPv4)) {
3117		return entity;
3118	}
3119
3120	interfaceIndex = findConfiguration(interfacePrivate->interface_type);
3121	if (interfaceIndex != kCFNotFound) {
3122		if (configurations[interfaceIndex].entity_hardware != NULL) {
3123			CFDictionarySetValue(entity,
3124					     kSCPropNetInterfaceHardware,
3125					     *configurations[interfaceIndex].entity_hardware);
3126		}
3127	} else {
3128		CFDictionarySetValue(entity,
3129				     kSCPropNetInterfaceHardware,
3130				     interfacePrivate->interface_type);
3131	}
3132
3133	// add the localized display name (which will only be used when/if the
3134	// interface is removed from the system)
3135	CFDictionarySetValue(entity,
3136			     kSCPropUserDefinedName,
3137			     SCNetworkInterfaceGetLocalizedDisplayName(interface));
3138
3139	// note that this is a V.92 capable modem
3140	if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeModem) &&
3141	    interfacePrivate->modemIsV92) {
3142		int		one     = 1;
3143		CFNumberRef     num;
3144
3145		num = CFNumberCreate(NULL, kCFNumberIntType, &one);
3146		CFDictionarySetValue(entity,
3147				     kSCPropNetInterfaceSupportsModemOnHold,
3148				     num);
3149		CFRelease(num);
3150	}
3151
3152	return entity;
3153}
3154
3155
3156static SCNetworkInterfaceRef
3157findInterface(CFArrayRef interfaces, CFStringRef match_if)
3158{
3159	CFIndex	i;
3160	CFIndex	n;
3161
3162	n = CFArrayGetCount(interfaces);
3163	for (i = 0; i < n; i++) {
3164		SCNetworkInterfaceRef	interface	= CFArrayGetValueAtIndex(interfaces, i);
3165		CFStringRef		interfaceName;
3166
3167		interfaceName = SCNetworkInterfaceGetBSDName(interface);
3168		if ((interfaceName != NULL) && CFEqual(interfaceName, match_if)) {
3169			CFRetain(interface);
3170			return interface;
3171		}
3172	}
3173
3174	return NULL;
3175}
3176
3177#if	!TARGET_OS_IPHONE
3178static SCNetworkInterfaceRef
3179findBondInterface(SCPreferencesRef prefs, CFStringRef ifDevice)
3180{
3181	CFArrayRef		bonds;
3182	SCNetworkInterfaceRef	interface	= NULL;
3183
3184	if (prefs == NULL) {
3185		return (NULL);
3186	}
3187
3188	// check if the interface is an Ethernet Bond
3189	bonds = SCBondInterfaceCopyAll(prefs);
3190	if (bonds != NULL) {
3191		interface = findInterface(bonds, ifDevice);
3192		CFRelease(bonds);
3193	}
3194	return interface;
3195}
3196#endif	// !TARGET_OS_IPHONE
3197
3198static SCNetworkInterfaceRef
3199findBridgeInterface(SCPreferencesRef prefs, CFStringRef ifDevice)
3200{
3201	CFArrayRef		bridges;
3202	SCNetworkInterfaceRef	interface	= NULL;
3203
3204	if (prefs == NULL) {
3205		return (NULL);
3206	}
3207
3208	// check if the interface is an bridge
3209	bridges = SCBridgeInterfaceCopyAll(prefs);
3210	if (bridges != NULL) {
3211		interface = findInterface(bridges, ifDevice);
3212		CFRelease(bridges);
3213	}
3214	return interface;
3215}
3216
3217static SCNetworkInterfaceRef
3218findVLANInterface(SCPreferencesRef prefs, CFStringRef ifDevice)
3219{
3220	SCNetworkInterfaceRef	interface	= NULL;
3221	CFArrayRef		vlans;
3222
3223	if (prefs == NULL) {
3224		return (NULL);
3225	}
3226
3227	// check if the interface is a VLAN
3228	vlans = SCVLANInterfaceCopyAll(prefs);
3229	if (vlans != NULL) {
3230		interface = findInterface(vlans, ifDevice);
3231		CFRelease(vlans);
3232	}
3233	return interface;
3234}
3235
3236
3237#define	N_QUICK	32
3238
3239
3240static CFMutableDictionaryRef
3241copy_ppp_entity(CFStringRef bsdName)
3242{
3243	CFMutableDictionaryRef	entity		= NULL;
3244	CFStringRef		pattern;
3245	CFMutableArrayRef	patterns;
3246	CFDictionaryRef		dict;
3247
3248	patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3249	pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetPPP);
3250	CFArrayAppendValue(patterns, pattern);
3251	CFRelease(pattern);
3252	pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
3253	CFArrayAppendValue(patterns, pattern);
3254	CFRelease(pattern);
3255	dict = SCDynamicStoreCopyMultiple(NULL, NULL, patterns);
3256	CFRelease(patterns);
3257	if (dict != NULL) {
3258		CFIndex		i;
3259		const void *	keys_q[N_QUICK];
3260		const void **	keys	= keys_q;
3261		CFIndex		n;
3262		const void *	vals_q[N_QUICK];
3263		const void **	vals	= vals_q;
3264
3265		n = CFDictionaryGetCount(dict);
3266		if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
3267			keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
3268			vals = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
3269		}
3270		CFDictionaryGetKeysAndValues(dict, keys, vals);
3271		for (i = 0; i < n; i++) {
3272			CFArrayRef	components;
3273			CFStringRef	interfaceKey;
3274			CFDictionaryRef	interfaceVal;
3275			CFStringRef	ifName;
3276			CFStringRef	pppKey		= (CFStringRef)keys[i];
3277			CFDictionaryRef	pppVal		= (CFDictionaryRef)vals[i];
3278			CFStringRef	serviceID;
3279
3280			if (!CFStringHasSuffix(pppKey, kSCEntNetPPP) ||
3281			    !CFDictionaryGetValueIfPresent(pppVal, kSCPropInterfaceName, (const void **)&ifName) ||
3282			    !CFEqual(bsdName, ifName)) {
3283				// if not matching PPP interface
3284				continue;
3285			}
3286
3287			components = CFStringCreateArrayBySeparatingStrings(NULL, pppKey, CFSTR("/"));
3288			serviceID = CFArrayGetValueAtIndex(components, 3);
3289			interfaceKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, kSCEntNetInterface);
3290			interfaceVal = CFDictionaryGetValue(dict, interfaceKey);
3291			CFRelease(interfaceKey);
3292			CFRelease(components);
3293			if (interfaceVal != NULL) {
3294				entity = CFDictionaryCreateMutableCopy(NULL, 0, interfaceVal);
3295				break;
3296			}
3297		}
3298		if (keys != keys_q) {
3299			CFAllocatorDeallocate(NULL, keys);
3300			CFAllocatorDeallocate(NULL, vals);
3301		}
3302
3303		CFRelease(dict);
3304	}
3305
3306	return entity;
3307}
3308
3309
3310SCNetworkInterfaceRef
3311_SCNetworkInterfaceCreateWithBSDName(CFAllocatorRef		allocator,
3312				     CFStringRef		bsdName,
3313				     UInt32			flags)
3314{
3315	CFMutableDictionaryRef	entity	= NULL;
3316	struct ifreq		ifr;
3317	SCNetworkInterfaceRef	interface;
3318
3319	bzero(&ifr, sizeof(ifr));
3320	if (_SC_cfstring_to_cstring(bsdName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) != NULL) {
3321		int	s;
3322
3323		s = socket(AF_INET, SOCK_DGRAM, 0);
3324		if (s != -1) {
3325			if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
3326				ifr.ifr_flags = 0;
3327			}
3328			close(s);
3329		}
3330
3331		if ((ifr.ifr_flags & IFF_POINTOPOINT) != 0) {
3332			// if PPP
3333			entity = copy_ppp_entity(bsdName);
3334		}
3335	}
3336
3337	if (entity == NULL) {
3338		entity = CFDictionaryCreateMutable(NULL,
3339						   0,
3340						   &kCFTypeDictionaryKeyCallBacks,
3341						   &kCFTypeDictionaryValueCallBacks);
3342		CFDictionarySetValue(entity, kSCPropNetInterfaceDeviceName, bsdName);
3343	}
3344
3345#if	!TARGET_OS_IPHONE
3346	if ((flags & kIncludeBondInterfaces) == 0) {
3347		CFDictionarySetValue(entity, CFSTR("_NO_BOND_INTERFACES_"), kCFBooleanTrue);
3348	}
3349#endif	// !TARGET_OS_IPHONE
3350
3351	if ((flags & kIncludeBridgeInterfaces) == 0) {
3352		CFDictionarySetValue(entity, CFSTR("_NO_BRIDGE_INTERFACES_"), kCFBooleanTrue);
3353	}
3354
3355	if ((flags & kIncludeVLANInterfaces) == 0) {
3356		CFDictionarySetValue(entity, CFSTR("_NO_VLAN_INTERFACES_"), kCFBooleanTrue);
3357	}
3358
3359	interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, NULL);
3360	CFRelease(entity);
3361
3362	return interface;
3363}
3364
3365
3366static CFStringRef
3367_SCNetworkInterfaceCopyPrefixFromBSDName(CFStringRef bsdName)
3368{
3369	CFMutableStringRef interfacePrefix = NULL;
3370	UniChar lastChar;
3371	CFIndex length = 0;
3372
3373	if (isA_CFString(bsdName) == NULL) {
3374		SCLog(TRUE, LOG_DEBUG, CFSTR("_SCNetworkInterfaceCopyPrefixFromBSDName: bsdName is NULL or not of the correct type"));
3375		goto done;
3376	}
3377
3378	interfacePrefix = CFStringCreateMutableCopy(NULL, 0, bsdName);
3379	length = CFStringGetLength(interfacePrefix);
3380
3381	while (length > 0) {
3382		lastChar = CFStringGetCharacterAtIndex(interfacePrefix, length - 1);
3383		if (lastChar >= '0' && lastChar <= '9') {
3384			CFStringDelete(interfacePrefix,
3385				       CFRangeMake(length-1, 1));
3386		}
3387		else {
3388			break;
3389		}
3390		length = CFStringGetLength(interfacePrefix);
3391	}
3392done:
3393	return interfacePrefix;
3394}
3395
3396
3397static void
3398__SCNetworkInterfaceSetIOInterfacePrefix(SCNetworkInterfaceRef interface,
3399					 CFStringRef prefix);
3400
3401
3402static Boolean
3403__SCNetworkInterfaceUpdateBSDName(SCNetworkInterfaceRef interface, CFStringRef currentBSDName, CFStringRef newBSDName)
3404{
3405	Boolean success = FALSE;
3406	SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3407
3408	if (isA_SCNetworkInterface(interface) == NULL) {
3409		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceUpdateBSDName: interface is NULL or not of the correct type"));
3410		goto done;
3411	}
3412
3413	if (CFEqual(currentBSDName, newBSDName)) {
3414		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceUpdateBSDName: bsdName (%@) is equal to interfacePrivate->entity_device (%@)"), currentBSDName, newBSDName);
3415		goto done;
3416	}
3417
3418	if (interfacePrivate->entity_device != NULL) {
3419		CFRelease(interfacePrivate->entity_device);
3420	}
3421	interfacePrivate->entity_device = CFRetain(newBSDName);
3422	success = TRUE;
3423done:
3424	return success;
3425}
3426
3427
3428static Boolean
3429__SCNetworkInterfaceUpdateIOPath(SCNetworkInterfaceRef interface)
3430{
3431	Boolean success = FALSE;
3432	SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3433	CFStringRef oldPath = NULL;
3434	CFStringRef newPath = NULL;
3435
3436	// Using the BSD Name update the path
3437	oldPath = interfacePrivate->path;
3438	if (isA_CFString(oldPath) == NULL) {
3439		goto done;
3440	}
3441	newPath = CFStringCreateWithFormat(NULL, NULL, CFSTR("Migrated_From: %@"), oldPath);
3442	if (interfacePrivate->path != NULL) {
3443		CFRelease(interfacePrivate->path);
3444	}
3445	interfacePrivate->path = CFRetain(newPath);
3446	success = TRUE;
3447
3448done:
3449	if (newPath != NULL) {
3450		CFRelease(newPath);
3451	}
3452	return success;
3453}
3454
3455
3456static void
3457__SCNetworkInterfaceSetIOInterfacePrefix (SCNetworkInterfaceRef interface,
3458					  CFStringRef prefix)
3459{
3460	SCNetworkInterfacePrivateRef interfacePrivate;
3461
3462	if (isA_CFString(prefix) == NULL) {
3463		return;
3464	}
3465
3466	interfacePrivate = (SCNetworkInterfacePrivateRef) interface;
3467
3468	CFRetain(prefix);
3469
3470	if (interfacePrivate->prefix != NULL) {
3471		CFRelease(interfacePrivate->prefix);
3472	}
3473
3474	interfacePrivate->prefix = prefix;
3475	return;
3476}
3477
3478
3479__private_extern__
3480void
3481__SCNetworkInterfaceSetIOInterfaceUnit (SCNetworkInterfaceRef interface,
3482				       CFNumberRef unit)
3483{
3484	SCNetworkInterfacePrivateRef interfacePrivate;
3485	CFStringRef newBSDName = NULL;
3486	CFStringRef oldBSDName = NULL;
3487
3488	if (isA_CFNumber(unit) == NULL) {
3489		return;
3490	}
3491	interfacePrivate = (SCNetworkInterfacePrivateRef) interface;
3492
3493	oldBSDName = SCNetworkInterfaceGetBSDName(interface);
3494
3495	if (interfacePrivate->prefix == NULL) {
3496		if (isA_CFString(interfacePrivate->entity_device) != NULL) {
3497			CFStringRef interfaceNamePrefix = _SCNetworkInterfaceCopyPrefixFromBSDName(interfacePrivate->entity_device);
3498			if (interfaceNamePrefix == NULL) {
3499				SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceSetIOInterfaceUnit: interfaceNamePrefix is NULL"));
3500			}
3501			else {
3502				__SCNetworkInterfaceSetIOInterfacePrefix(interface, interfaceNamePrefix);
3503				CFRelease(interfaceNamePrefix);
3504			}
3505		}
3506	}
3507
3508	if (interfacePrivate->prefix != NULL) {
3509		newBSDName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), interfacePrivate->prefix, unit);
3510	}
3511
3512	// Update the BSD Name
3513	if ((newBSDName == NULL) ||
3514	    (__SCNetworkInterfaceUpdateBSDName(interface, oldBSDName, newBSDName) == FALSE)) {
3515		SCLog(_sc_debug, LOG_DEBUG, CFSTR("__SCNetworkInterfaceSetIOInterfaceUnit: Update BSD Name Failed"));
3516	}
3517
3518	// Update the path
3519	if (__SCNetworkInterfaceUpdateIOPath(interface) == FALSE) {
3520		SCLog(_sc_debug, LOG_DEBUG, CFSTR("__SCNetworkInterfaceSetIOInterfaceUnit: Update IO Path Failed"));
3521	}
3522
3523	CFRetain(unit);
3524	if (interfacePrivate->unit != NULL) {
3525		CFRelease(interfacePrivate->unit);
3526	}
3527	interfacePrivate->unit = unit;
3528
3529
3530	if (newBSDName != NULL) {
3531		CFRelease(newBSDName);
3532	}
3533	return;
3534}
3535
3536
3537__private_extern__
3538CFDictionaryRef
3539__SCNetworkInterfaceCopyStorageEntity(SCNetworkInterfaceRef interface)
3540{
3541	CFMutableDictionaryRef interface_entity = NULL;
3542	SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3543	CFBooleanRef active = NULL;
3544	CFStringRef bsdName = NULL;
3545	CFBooleanRef builtin = NULL;
3546	CFStringRef interfaceNamePrefix = NULL;
3547	CFNumberRef interfaceType = NULL;
3548	CFNumberRef interfaceUnit = NULL;
3549	CFDataRef macAddress = NULL;
3550	CFStringRef pathMatch = NULL;
3551	CFDictionaryRef info = NULL;
3552	CFStringRef type = NULL;
3553
3554	if (interfacePrivate->active == TRUE) {
3555		active = kCFBooleanTrue;
3556	}
3557
3558	bsdName = SCNetworkInterfaceGetBSDName(interface);
3559	if (isA_CFString(bsdName) == NULL) {
3560		goto done;
3561	}
3562
3563	builtin = interfacePrivate->builtin ? kCFBooleanTrue : kCFBooleanFalse;
3564	interfaceNamePrefix = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface);
3565	if (isA_CFString(interfaceNamePrefix) == NULL) {
3566		goto done;
3567	}
3568
3569	interfaceType = _SCNetworkInterfaceGetIOInterfaceType(interface);
3570	if (isA_CFNumber(interfaceType) == NULL) {
3571		goto done;
3572	}
3573
3574	interfaceUnit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
3575	if (isA_CFNumber(interfaceUnit) == NULL) {
3576		goto done;
3577	}
3578
3579	macAddress = _SCNetworkInterfaceGetHardwareAddress(interface);
3580	if (isA_CFData(macAddress) == NULL) {
3581		goto done;
3582	}
3583
3584	pathMatch = _SCNetworkInterfaceGetIOPath(interface);
3585	if (isA_CFString(pathMatch) == NULL) {
3586		goto done;
3587	}
3588
3589	info = _SCNetworkInterfaceCopyInterfaceInfo(interface);
3590	if (isA_CFDictionary(info) == NULL) {
3591		goto done;
3592	}
3593
3594	type = SCNetworkInterfaceGetInterfaceType(interface);
3595	if (isA_CFString(type) == NULL) {
3596		goto done;
3597	}
3598
3599	interface_entity = CFDictionaryCreateMutable(NULL, 0,
3600						     &kCFTypeDictionaryKeyCallBacks,
3601						     &kCFTypeDictionaryValueCallBacks);
3602
3603	if (isA_CFBoolean(active) != NULL) {
3604		CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceActive), active);
3605	}
3606
3607	CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceBSDName), bsdName);
3608	CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOBuiltin), builtin);
3609	CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceNamePrefix), interfaceNamePrefix);
3610	CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceType), interfaceType);
3611	CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceUnit), interfaceUnit);
3612	CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOMACAddress), macAddress);
3613	CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceIOPathMatch), pathMatch);
3614	CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceInfo), info);
3615	CFDictionaryAddValue(interface_entity, CFSTR(kSCNetworkInterfaceType), type);
3616done:
3617	if (info != NULL) {
3618		CFRelease(info);
3619	}
3620	return interface_entity;
3621}
3622
3623
3624static void
3625__SCNetworkInterfaceSetService(SCNetworkInterfaceRef	interface,
3626			       SCNetworkServiceRef	service)
3627{
3628	SCNetworkInterfacePrivateRef	interfacePrivate;
3629	SCNetworkServicePrivateRef	servicePrivate;
3630
3631	interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3632	if (interfacePrivate->prefs != NULL) {
3633		CFRelease(interfacePrivate->prefs);
3634		interfacePrivate->prefs = NULL;
3635	}
3636	if (interfacePrivate->serviceID != NULL) {
3637		CFRelease(interfacePrivate->serviceID);
3638		interfacePrivate->serviceID = NULL;
3639	}
3640
3641	servicePrivate = (SCNetworkServicePrivateRef)service;
3642	if (servicePrivate->prefs != NULL) {
3643		interfacePrivate->prefs = CFRetain(servicePrivate->prefs);
3644	}
3645	if (servicePrivate->serviceID != NULL) {
3646		interfacePrivate->serviceID = CFRetain(servicePrivate->serviceID);
3647	}
3648
3649	return;
3650}
3651
3652
3653__private_extern__
3654Boolean
3655__SCNetworkInterfaceMatchesName(CFStringRef name, CFStringRef key)
3656{
3657	Boolean		match;
3658	CFStringRef	str;
3659
3660	if (bundle == NULL) {
3661		// if no bundle
3662		return FALSE;
3663	}
3664
3665	if (!isA_CFString(name)) {
3666		// if no interface "name"
3667		return FALSE;
3668	}
3669
3670	// check non-localized name for a match
3671	str = copy_interface_string(bundle, key, FALSE);
3672	if (str != NULL) {
3673		match = CFEqual(name, str);
3674		CFRelease(str);
3675		if (match) {
3676			return TRUE;
3677		}
3678	}
3679
3680	// check localized name for a match
3681	str = copy_interface_string(bundle, key, TRUE);
3682	if (str != NULL) {
3683		match = CFEqual(name, str);
3684		CFRelease(str);
3685		if (match) {
3686			return TRUE;
3687		}
3688	}
3689
3690	return FALSE;
3691}
3692
3693
3694#define kInterfaceTypeEthernetValue 6
3695#define kInterfaceTypeFirewireValue 144
3696
3697
3698static SCNetworkInterfaceRef
3699__SCNetworkInterfaceCreateWithStorageEntity (CFAllocatorRef allocator,
3700					     CFDictionaryRef interface_entity,
3701					     SCPreferencesRef prefs)
3702{
3703	SCNetworkInterfacePrivateRef interfacePrivate = NULL;
3704	CFBooleanRef    active = NULL;
3705	CFStringRef     bsdName = NULL;
3706	CFBooleanRef    ioBuiltin = NULL;
3707	CFStringRef     ioInterfaceNamePrefix = NULL;
3708	CFNumberRef     ioInterfaceType = NULL;
3709	int		ioInterfaceTypeNum;
3710	CFNumberRef     ioInterfaceUnit = NULL;
3711	CFDataRef       ioMACAddress = NULL;
3712	CFStringRef     ioPathMatch = NULL;
3713	CFDictionaryRef SCNetworkInterfaceInfo = NULL;
3714	CFStringRef	userDefinedName = NULL;
3715	CFStringRef	usbProductName = NULL;
3716	CFNumberRef	idProduct = NULL;
3717	CFNumberRef	idVendor = NULL;
3718	CFStringRef     type = NULL;
3719
3720	/* initialize runtime */
3721	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
3722
3723	if (isA_CFDictionary(interface_entity) == NULL) {
3724		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateWithStorageEntity: interface_entity is NULL or not of the correct type"));
3725		goto done;
3726	}
3727	active = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceActive));
3728	if (isA_CFBoolean(active) == NULL) {
3729		active = kCFBooleanFalse;
3730	}
3731	bsdName = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceBSDName));
3732	if (isA_CFString(bsdName) == NULL) {
3733		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateWithStorageEntity: bsdName is NULL or not of the correct type"));
3734		goto done;
3735	}
3736	ioBuiltin = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOBuiltin));
3737	if (isA_CFBoolean(ioBuiltin) == NULL) {
3738		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateWithStorageEntity: ioBuiltin is NULL or not of the correct type"));
3739		goto done;
3740	}
3741	ioInterfaceNamePrefix = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceNamePrefix));
3742	if (isA_CFString(ioInterfaceNamePrefix) == NULL) {
3743		ioInterfaceNamePrefix = _SCNetworkInterfaceCopyPrefixFromBSDName(bsdName);
3744		if (ioInterfaceNamePrefix == NULL) {
3745			SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateWithStorageEntity: ioInterfaceNamePrefix is NULL or not of the correct type"));
3746			goto done;
3747		}
3748	}
3749	else {
3750		CFRetain(ioInterfaceNamePrefix);
3751	}
3752	ioInterfaceType = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceType));
3753	if (isA_CFNumber(ioInterfaceType) == NULL) {
3754		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateWithStorageEntity: ioInterfaceType is NULL or not of the correct type"));
3755		goto done;
3756	}
3757	if (CFNumberGetValue(ioInterfaceType, kCFNumberIntType, &ioInterfaceTypeNum) == FALSE) {
3758		SCLog(TRUE, LOG_ERR, CFSTR("__SCNetworkInterfaceCreateWithStorageEntity: Count not extract value from ioInterfaceType"));
3759	}
3760
3761	ioInterfaceUnit = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOInterfaceUnit));
3762	if (isA_CFNumber(ioInterfaceUnit) == NULL) {
3763		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateWithStorageEntity: ioInterfaceUnit is NULL or not of the correct type"));
3764
3765		goto done;
3766	}
3767	ioMACAddress = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOMACAddress));
3768	if (isA_CFData(ioMACAddress) == NULL) {
3769		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateWithStorageEntity: ioMACAddress is NULL or not of the correct type"));
3770		goto done;
3771	}
3772	ioPathMatch = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceIOPathMatch));
3773	if (isA_CFString(ioPathMatch) == NULL) {
3774		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateWithStorageEntity: ioPathMatch is NULL or not of the correct type"));
3775		goto done;
3776	}
3777	else {
3778		// Check if Path contains the BSD Name in the end
3779	}
3780	SCNetworkInterfaceInfo = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceInfo));
3781	if (isA_CFDictionary(SCNetworkInterfaceInfo) == NULL) {
3782		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateWithStorageEntity: SCNetworkInterfaceInfo is NULL or not of the correct type"));
3783		goto done;
3784	}
3785	userDefinedName = CFDictionaryGetValue(SCNetworkInterfaceInfo, kSCPropUserDefinedName);
3786#if	!TARGET_IPHONE_SIMULATOR
3787	usbProductName = CFDictionaryGetValue(SCNetworkInterfaceInfo, CFSTR(kUSBProductString));
3788	idProduct = CFDictionaryGetValue(SCNetworkInterfaceInfo, CFSTR(kUSBProductID));
3789	idVendor = CFDictionaryGetValue(SCNetworkInterfaceInfo, CFSTR(kUSBVendorID));
3790#endif	// !TARGET_IPHONE_SIMULATOR
3791
3792	type = CFDictionaryGetValue(interface_entity, CFSTR(kSCNetworkInterfaceType));
3793	if (isA_CFString(type) == NULL) {
3794		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateWithStorageEntity: type is NULL or not of the correct type"));
3795		goto done;
3796	}
3797
3798	interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
3799	interfacePrivate->active = CFBooleanGetValue(active);
3800	interfacePrivate->entity_device = CFRetain(bsdName);
3801	interfacePrivate->builtin = CFBooleanGetValue(ioBuiltin);
3802	interfacePrivate->prefix = CFRetain(ioInterfaceNamePrefix);
3803	interfacePrivate->type = CFRetain(ioInterfaceType);
3804	interfacePrivate->unit = CFRetain(ioInterfaceUnit);
3805	interfacePrivate->address = CFRetain(ioMACAddress);
3806	interfacePrivate->path = CFRetain(ioPathMatch);
3807	interfacePrivate->name = ((userDefinedName != NULL) ? CFRetain(userDefinedName) : NULL);
3808	interfacePrivate->localized_name = ((userDefinedName != NULL) ? CFRetain(userDefinedName) : NULL);
3809	interfacePrivate->usb.name = ((usbProductName != NULL) ? CFRetain(usbProductName) : NULL);
3810	interfacePrivate->usb.pid = ((idProduct != NULL) ? CFRetain(idProduct) : NULL);
3811	interfacePrivate->usb.vid = ((idVendor != NULL) ? CFRetain(idVendor) : NULL);
3812
3813	// Handling interface types to be seen in NetworkInterfaces.plist
3814	CFIndex interfaceIndex;
3815
3816	interfaceIndex = findConfiguration(type);
3817	if (interfaceIndex != kCFNotFound) {
3818		interfacePrivate->interface_type = *configurations[interfaceIndex].interface_type;
3819	}
3820	else {
3821		interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
3822	}
3823
3824	// Extracting entity type from value of interface type
3825	if (ioInterfaceTypeNum == kInterfaceTypeEthernetValue) {
3826		interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet; // kSCNetworkInterfaceTypeEthernet;
3827	}
3828	else if (ioInterfaceTypeNum == kInterfaceTypeFirewireValue) {
3829		interfacePrivate->entity_type = kSCValNetInterfaceTypeFireWire;
3830	}
3831done:
3832	if (ioInterfaceNamePrefix != NULL) {
3833		CFRelease(ioInterfaceNamePrefix);
3834	}
3835
3836	return (SCNetworkInterfaceRef)interfacePrivate;
3837}
3838
3839
3840SCNetworkInterfaceRef
3841_SCNetworkInterfaceCreateWithEntity(CFAllocatorRef		allocator,
3842				    CFDictionaryRef		interface_entity,
3843				    SCNetworkServiceRef		service)
3844{
3845	SCNetworkInterfacePrivateRef	interfacePrivate	= NULL;
3846	CFStringRef			ifDevice;
3847	CFStringRef			ifName			= NULL;
3848	CFStringRef			ifSubType;
3849	CFStringRef			ifType;
3850	CFStringRef			ifUnique;
3851	CFArrayRef			matching_interfaces	= NULL;
3852	SCPreferencesRef		servicePref		= NULL;
3853	Boolean				useSystemInterfaces	= TRUE;
3854
3855	/* initialize runtime (and kSCNetworkInterfaceIPv4) */
3856	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
3857
3858	if (service != NULL) {
3859		servicePref = ((SCNetworkServicePrivateRef)service)->prefs;
3860		useSystemInterfaces = ((__SCPreferencesUsingDefaultPrefs(servicePref)) &&
3861                                       (__SCPreferencesGetLimitSCNetworkConfiguration(servicePref) == FALSE));
3862	}
3863
3864	ifType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceType);
3865	if (ifType == NULL) {
3866		/*
3867		 * The interface "Type" was not specified.  We'll make an
3868		 * assumption that this is an "Ethernet" interface.  If a
3869		 * real interface exists with the provided interface name
3870		 * then the actual type will be set accordingly. If not, we'll
3871		 * end up crafting an "Ethernet" SCNetworkInterface that
3872		 * will keep the rest of the configuration APIs happy.
3873		 */
3874		ifType = kSCValNetInterfaceTypeEthernet;
3875	}
3876
3877	if (!isA_CFString(ifType)) {
3878		return NULL;
3879	}
3880
3881	ifSubType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceSubType);
3882	if (CFEqual(ifType, kSCValNetInterfaceTypePPP) ||
3883	    CFEqual(ifType, kSCValNetInterfaceTypeVPN)) {
3884		if (!isA_CFString(ifSubType)) {
3885			return NULL;
3886		}
3887	}
3888
3889	ifDevice = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceDeviceName);
3890	ifUnique = CFDictionaryGetValue(interface_entity, CFSTR("DeviceUniqueIdentifier"));
3891
3892	if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet) ||
3893	    CFEqual(ifType, kSCValNetInterfaceTypeFireWire) ||
3894	    (CFEqual(ifType, kSCValNetInterfaceTypePPP) && CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE))) {
3895		char			bsdName[IFNAMSIZ];
3896		CFMutableDictionaryRef	matching;
3897
3898		if (!isA_CFString(ifDevice)) {
3899			return NULL;
3900		}
3901
3902		if (CFEqual(ifDevice, CFSTR("lo0"))) {	// for _SCNetworkInterfaceCreateWithBSDName
3903			interfacePrivate = __SCNetworkInterfaceCreateCopy(NULL, kSCNetworkInterfaceLoopback, NULL, NULL);
3904			goto done;
3905		}
3906		if (useSystemInterfaces) {
3907			if (_SC_cfstring_to_cstring(ifDevice, bsdName, sizeof(bsdName), kCFStringEncodingASCII) == NULL) {
3908				goto done;
3909			}
3910
3911			matching = IOBSDNameMatching(masterPort, 0, bsdName);
3912			if (matching == NULL) {
3913				goto done;
3914			}
3915			matching_interfaces = findMatchingInterfaces(matching, processNetworkInterface, kSCNetworkInterfaceHiddenInterfaceKey);
3916			CFRelease(matching);
3917		}
3918	} else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
3919		if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) {
3920			CFDictionaryRef	matching;
3921			CFStringRef	match_keys[2];
3922			CFStringRef	match_vals[2];
3923
3924			if (!isA_CFString(ifDevice)) {
3925				return NULL;
3926			}
3927
3928			if (useSystemInterfaces) {
3929				match_keys[0] = CFSTR(kIOProviderClassKey);
3930				match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
3931
3932				match_keys[1] = CFSTR(kIOTTYBaseNameKey);
3933				match_vals[1] = ifDevice;
3934
3935				matching = CFDictionaryCreate(NULL,
3936							      (const void **)match_keys,
3937							      (const void **)match_vals,
3938							      sizeof(match_keys)/sizeof(match_keys[0]),
3939							      &kCFTypeDictionaryKeyCallBacks,
3940							      &kCFTypeDictionaryValueCallBacks);
3941				matching_interfaces = findMatchingInterfaces(matching, processSerialInterface, kSCNetworkInterfaceHiddenPortKey);
3942				CFRelease(matching);
3943			}
3944			if (ifUnique == NULL) {
3945				CFIndex	n;
3946				Boolean	useDeviceName	= TRUE;
3947
3948				n = (matching_interfaces != NULL) ? CFArrayGetCount(matching_interfaces) : 0;
3949				if (n > 0) {
3950					CFIndex	i;
3951
3952					for (i = 0; i < n; i++) {
3953						SCNetworkInterfacePrivateRef	scanPrivate;
3954
3955						scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i);
3956						if (scanPrivate->entity_device_unique != NULL) {
3957							useDeviceName = FALSE;
3958							break;
3959						}
3960					}
3961				}
3962
3963				if (useDeviceName && useSystemInterfaces) {
3964					if (matching_interfaces != NULL) {
3965						CFRelease(matching_interfaces);
3966					}
3967
3968					match_keys[1] = CFSTR(kIOTTYDeviceKey);
3969					matching = CFDictionaryCreate(NULL,
3970								      (const void **)match_keys,
3971								      (const void **)match_vals,
3972								      sizeof(match_keys)/sizeof(match_keys[0]),
3973								      &kCFTypeDictionaryKeyCallBacks,
3974								      &kCFTypeDictionaryValueCallBacks);
3975					matching_interfaces = findMatchingInterfaces(matching, processSerialInterface, kSCNetworkInterfaceHiddenPortKey);
3976					CFRelease(matching);
3977				}
3978			}
3979		} else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypeL2TP)) {
3980			interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
3981													       kSCNetworkInterfaceTypeL2TP);
3982		} else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPTP)) {
3983			interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
3984													       kSCNetworkInterfaceTypePPTP);
3985		} else {
3986			// XXX do we allow non-Apple variants of PPP??? XXX
3987			interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
3988													       ifSubType);
3989		}
3990	} else if (CFEqual(ifType, kSCValNetInterfaceType6to4)) {
3991		if (!isA_CFString(ifDevice)) {
3992			return NULL;
3993		}
3994
3995		interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
3996												       kSCNetworkInterfaceType6to4);
3997	} else if (CFEqual(ifType, kSCValNetInterfaceTypeIPSec)) {
3998		interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
3999												       kSCNetworkInterfaceTypeIPSec);
4000	} else if (CFEqual(ifType, kSCValNetInterfaceTypeLoopback)) {
4001		interfacePrivate = __SCNetworkInterfaceCreateCopy(NULL, kSCNetworkInterfaceLoopback, NULL, NULL);
4002	} else if (CFEqual(ifType, kSCValNetInterfaceTypeVPN)) {
4003		if (CFStringFind(ifSubType, CFSTR("."), 0).location != kCFNotFound) {
4004			interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
4005													       ifSubType);
4006		}
4007	} else if ((CFStringFind(ifType, CFSTR("."), 0).location != kCFNotFound) && (ifDevice == NULL)) {
4008		interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
4009												       ifType);
4010	}
4011
4012	if (matching_interfaces != NULL) {
4013		CFIndex 		n;
4014		SCPreferencesRef	prefs;
4015		Boolean			temp_preferences	= FALSE;
4016
4017		n = CFArrayGetCount(matching_interfaces);
4018		switch (n) {
4019			case 1 :
4020				interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0);
4021				if (_SC_CFEqual(ifUnique, interfacePrivate->entity_device_unique)) {
4022					// if the unique ID's  match
4023					CFRetain(interfacePrivate);
4024					break;
4025				}
4026
4027				interfacePrivate = NULL;
4028				// fall through
4029			case 0 :
4030				if (!CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) {
4031					break;
4032				}
4033
4034				if (CFDictionaryGetValueIfPresent(interface_entity,
4035								  kSCPropUserDefinedName,
4036								  (const void **)&ifName) &&
4037				    CFEqual(ifName, CFSTR(BT_PAN_NAME))) {
4038					break;
4039				}
4040
4041				prefs = (service != NULL) ? ((SCNetworkServicePrivateRef)service)->prefs : NULL;
4042				if (prefs == NULL) {
4043					prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterface"), NULL);
4044					if (prefs != NULL) {
4045						temp_preferences = TRUE;
4046					}
4047				}
4048				if (prefs == NULL) {
4049					break;
4050				}
4051#if	!TARGET_OS_IPHONE
4052				if (!CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BOND_INTERFACES_"))) {
4053					interfacePrivate = (SCNetworkInterfacePrivateRef)findBondInterface(prefs, ifDevice);
4054				}
4055#endif	// !TARGET_OS_IPHONE
4056				if ((interfacePrivate == NULL)
4057				    && !CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BRIDGE_INTERFACES_"))) {
4058					interfacePrivate = (SCNetworkInterfacePrivateRef)findBridgeInterface(prefs, ifDevice);
4059				}
4060
4061				if ((interfacePrivate == NULL)
4062				    && !CFDictionaryContainsKey(interface_entity, CFSTR("_NO_VLAN_INTERFACES_"))) {
4063					interfacePrivate = (SCNetworkInterfacePrivateRef)findVLANInterface(prefs, ifDevice);
4064				}
4065				if (temp_preferences) CFRelease(prefs);
4066				break;
4067			default :
4068				if (ifUnique != NULL) {
4069					CFIndex	i;
4070
4071					// we are looking for an interface with a unique ID
4072					// so let's try to focus our choices
4073					for (i = 0; i < n; i++) {
4074						SCNetworkInterfacePrivateRef	scanPrivate;
4075
4076						scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i);
4077						if (_SC_CFEqual(ifUnique, scanPrivate->entity_device_unique)) {
4078							if (interfacePrivate != NULL) {
4079								// if we've matched more than one interface
4080								interfacePrivate = NULL;
4081								break;
4082							}
4083							interfacePrivate = scanPrivate;
4084						}
4085					}
4086				} else if (CFDictionaryGetValueIfPresent(interface_entity,
4087									 kSCPropUserDefinedName,
4088									 (const void **)&ifName)) {
4089					CFIndex	i;
4090
4091					// we don't have a unique ID but do have an interface
4092					// name.  If the matching interfaces do have IDs than
4093					// we can try to focus our choices using the name
4094					for (i = 0; i < n; i++) {
4095						SCNetworkInterfacePrivateRef	scanPrivate;
4096
4097						scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i);
4098						if (scanPrivate->entity_device_unique != NULL) {
4099							SCNetworkInterfaceRef	scan	= (SCNetworkInterfaceRef)scanPrivate;
4100							CFStringRef		scanName;
4101
4102							scanName = __SCNetworkInterfaceGetNonLocalizedDisplayName(scan);
4103							if ((scanName != NULL) && !_SC_CFEqual(ifName, scanName)) {
4104								continue; // if not the same display name
4105							}
4106						}
4107
4108						if (interfacePrivate != NULL) {
4109							// if we've matched more than one interface
4110							interfacePrivate = NULL;
4111							break;
4112						}
4113						interfacePrivate = scanPrivate;
4114					}
4115				}
4116				if (interfacePrivate == NULL) {
4117					SCLog(TRUE, LOG_ERR, CFSTR("_SCNetworkInterfaceCreateWithEntity() failed, more than one interface matches %@"), ifDevice);
4118					interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0);
4119				}
4120				CFRetain(interfacePrivate);
4121				break;
4122		}
4123		CFRelease(matching_interfaces);
4124	}
4125
4126    done :
4127
4128	if ((interfacePrivate == NULL) || (useSystemInterfaces == FALSE))  {
4129		/*
4130		 * if device not present on this system
4131		 */
4132		if (useSystemInterfaces == FALSE) {
4133			if (interfacePrivate != NULL) {
4134				CFRelease(interfacePrivate);
4135			}
4136		}
4137
4138		interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
4139		interfacePrivate->entity_type          = (ifType != NULL) ? ifType : NULL;
4140		interfacePrivate->entity_subtype       = (ifSubType != NULL) ? ifSubType : NULL;
4141		interfacePrivate->entity_device        = (ifDevice != NULL) ? CFStringCreateCopy(NULL, ifDevice) : NULL;
4142		interfacePrivate->entity_device_unique = (ifUnique != NULL) ? CFStringCreateCopy(NULL, ifUnique) : NULL;
4143
4144		// Using UserDefinedName to check the validity of preferences file
4145		// when useSystemInterfaces is FALSE
4146		if (useSystemInterfaces == FALSE) {
4147			CFStringRef userDefinedName = CFDictionaryGetValue(interface_entity, kSCPropUserDefinedName);
4148			if (isA_CFString(userDefinedName) != NULL) {
4149				CFRetain(userDefinedName);
4150				if (interfacePrivate->name != NULL) {
4151					CFRelease(interfacePrivate->name);
4152				}
4153				interfacePrivate->name = userDefinedName;
4154
4155				CFRetain(userDefinedName);
4156				if (interfacePrivate->localized_name != NULL) {
4157					CFRelease(interfacePrivate->localized_name);
4158				}
4159				interfacePrivate->localized_name = userDefinedName;
4160			}
4161		}
4162
4163		if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) {
4164			CFStringRef	entity_hardware;
4165			SCNetworkInterfaceRef virtualInterface;
4166
4167			if ((useSystemInterfaces == FALSE) &&
4168			    (((virtualInterface = findBridgeInterface(servicePref, ifDevice)) != NULL) ||
4169#if	!TARGET_OS_IPHONE
4170			    ((virtualInterface = findBondInterface(servicePref,  ifDevice)) != NULL) ||
4171#endif
4172			    ((virtualInterface = findVLANInterface(servicePref, ifDevice)) != NULL))) {
4173				CFRelease(interfacePrivate);
4174				interfacePrivate = (SCNetworkInterfacePrivateRef)virtualInterface;
4175			} else {
4176				entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware);
4177				if (isA_CFString((entity_hardware)) &&
4178				    CFEqual(entity_hardware, kSCEntNetAirPort)) {
4179					interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
4180					interfacePrivate->localized_key  = CFSTR("airport");
4181					interfacePrivate->sort_order     = kSortAirPort;
4182				} else {
4183					CFStringRef	name;
4184
4185					interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
4186
4187					name = CFDictionaryGetValue(interface_entity, kSCPropUserDefinedName);
4188					if (__SCNetworkInterfaceMatchesName(name, CFSTR("iPhone"))) {
4189						interfacePrivate->localized_key = CFSTR("iPhone");
4190						interfacePrivate->sort_order    = kSortTethered;
4191					} else if (__SCNetworkInterfaceMatchesName(name, CFSTR("iPad"))) {
4192						interfacePrivate->localized_key = CFSTR("iPad");
4193						interfacePrivate->sort_order    = kSortTethered;
4194					} else if (__SCNetworkInterfaceMatchesName(name, CFSTR("thunderbolt"))) {
4195						interfacePrivate->localized_key = CFSTR("thunderbolt");
4196						interfacePrivate->sort_order    = kSortThunderbolt;
4197					} else if (__SCNetworkInterfaceMatchesName(name, CFSTR("bluetooth-pan-gn"))) {
4198						interfacePrivate->localized_key = CFSTR("bluetooth-pan-gn");
4199						interfacePrivate->sort_order    = kSortBluetoothPAN_GN;
4200					} else if (__SCNetworkInterfaceMatchesName(name, CFSTR("bluetooth-pan-nap"))) {
4201						interfacePrivate->localized_key = CFSTR("bluetooth-pan-nap");
4202						interfacePrivate->sort_order    = kSortBluetoothPAN_NAP;
4203					} else if (__SCNetworkInterfaceMatchesName(name, CFSTR("bluetooth-pan-u"))) {
4204						interfacePrivate->localized_key = CFSTR("bluetooth-pan-u");
4205						interfacePrivate->sort_order    = kSortBluetoothPAN_U;
4206					} else {
4207						interfacePrivate->sort_order = kSortEthernet;
4208					}
4209				}
4210			}
4211		} else if (CFEqual(ifType, kSCValNetInterfaceTypeFireWire)) {
4212			interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire;
4213			interfacePrivate->sort_order     = kSortFireWire;
4214		} else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
4215			if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE)) {
4216				CFStringRef	entity_hardware;
4217
4218				entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware);
4219				if (isA_CFString((entity_hardware)) &&
4220				    CFEqual(entity_hardware, kSCEntNetAirPort)) {
4221					interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
4222					interfacePrivate->sort_order     = kSortAirPort;
4223				} else {
4224					interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
4225					interfacePrivate->sort_order     = kSortEthernet;
4226				}
4227			} else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) {
4228				if (CFStringHasPrefix(ifDevice, CFSTR("Bluetooth"))) {
4229					interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth;
4230					interfacePrivate->sort_order     = kSortBluetooth;
4231				} else if (CFStringHasPrefix(ifDevice, CFSTR("irda"))) {
4232					interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA;
4233					interfacePrivate->sort_order     = kSortIrDA;
4234				} else if (CFStringHasPrefix(ifDevice, CFSTR("wwan"))) {
4235					interfacePrivate->interface_type = kSCNetworkInterfaceTypeWWAN;
4236					interfacePrivate->sort_order     = kSortWWAN;
4237				} else {
4238					interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem;
4239					interfacePrivate->sort_order     = kSortModem;
4240				}
4241			} else {
4242				SCNetworkInterfaceRef	child;
4243				// PPTP, L2TP, ...
4244				CFRelease(interfacePrivate);
4245				child = SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, ifSubType);
4246				interfacePrivate = (SCNetworkInterfacePrivateRef)child;
4247				if (interfacePrivate == NULL) {
4248					return NULL;
4249				}
4250			}
4251		} else if (CFEqual(ifType, kSCValNetInterfaceTypeVPN)) {
4252			SCNetworkInterfaceRef	child;
4253			CFRelease(interfacePrivate);
4254			child = SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, ifSubType);
4255			interfacePrivate = (SCNetworkInterfacePrivateRef)child;
4256			if (interfacePrivate == NULL) {
4257				return NULL;
4258			}
4259                } else if (CFEqual(ifType, kSCValNetInterfaceTypeIPSec)) {
4260                        CFRelease(interfacePrivate);
4261                        interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
4262                                                                                                               kSCNetworkInterfaceTypeIPSec);
4263                } else if (CFEqual(ifType, kSCValNetInterfaceType6to4)) {
4264                        CFRelease(interfacePrivate);
4265                        if (!isA_CFString(ifDevice)) {
4266                                return NULL;
4267                        }
4268                        interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
4269                                                                                                               kSCNetworkInterfaceType6to4);
4270                } else if (CFEqual(ifType, kSCValNetInterfaceTypeLoopback)) {
4271                        CFRelease(interfacePrivate);
4272                        interfacePrivate = __SCNetworkInterfaceCreateCopy(NULL, kSCNetworkInterfaceLoopback, NULL, NULL);
4273                } else if (CFStringFind(ifType, CFSTR("."), 0).location != kCFNotFound) {
4274			// if vendor interface
4275			if (vendor_interface_types == NULL) {
4276				vendor_interface_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
4277			}
4278			CFSetAddValue(vendor_interface_types, ifType);
4279
4280			interfacePrivate->interface_type = CFSetGetValue(vendor_interface_types, ifType);
4281		} else {
4282			// if unknown interface
4283			CFRelease(interfacePrivate);
4284			interfacePrivate = NULL;
4285			return NULL;
4286		}
4287
4288		if (CFDictionaryContainsKey(interface_entity, kSCNetworkInterfaceHiddenConfigurationKey)) {
4289			interfacePrivate->hidden = TRUE;
4290		}
4291	}
4292
4293	if (service != NULL) {
4294		__SCNetworkInterfaceSetService((SCNetworkInterfaceRef)interfacePrivate,
4295					       service);
4296
4297#if	!TARGET_OS_IPHONE
4298		// set prefs & serviceID to Bond member interfaces
4299		if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBond)) {
4300			CFIndex		i;
4301			CFArrayRef	members;
4302			CFIndex		n;
4303
4304			members = SCBondInterfaceGetMemberInterfaces((SCNetworkInterfaceRef)interfacePrivate);
4305			n = (members != NULL) ? CFArrayGetCount(members) : 0;
4306			for (i = 0; i < n; i++) {
4307				SCNetworkInterfaceRef	member;
4308
4309				member = CFArrayGetValueAtIndex(members, i);
4310				__SCNetworkInterfaceSetService(member, service);
4311			}
4312		}
4313#endif	// !TARGET_OS_IPHONE
4314
4315		// set prefs & serviceID to Bridge member interfaces
4316		if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBridge)) {
4317			CFIndex		i;
4318			CFArrayRef	members;
4319			CFIndex		n;
4320
4321			members = SCBridgeInterfaceGetMemberInterfaces((SCNetworkInterfaceRef)interfacePrivate);
4322			n = (members != NULL) ? CFArrayGetCount(members) : 0;
4323			for (i = 0; i < n; i++) {
4324				SCNetworkInterfaceRef	member;
4325
4326				member = CFArrayGetValueAtIndex(members, i);
4327				__SCNetworkInterfaceSetService(member, service);
4328			}
4329		}
4330		// set prefs & serviceID to VLAN pyhsical interface
4331		if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeVLAN)) {
4332			SCNetworkInterfaceRef	vlan_physical;
4333
4334			vlan_physical = SCVLANInterfaceGetPhysicalInterface((SCNetworkInterfaceRef)interfacePrivate);
4335			if (vlan_physical != NULL) {
4336				__SCNetworkInterfaceSetService(vlan_physical, service);
4337			}
4338		}
4339	}
4340
4341	if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
4342		SCNetworkInterfaceRef   parent;
4343
4344		// create parent
4345		parent = SCNetworkInterfaceCreateWithInterface((SCNetworkInterfaceRef)interfacePrivate,
4346							       kSCNetworkInterfaceTypePPP);
4347		CFRelease(interfacePrivate);
4348		interfacePrivate = (SCNetworkInterfacePrivateRef)parent;
4349	} else if (CFEqual(ifType, kSCValNetInterfaceTypeVPN)) {
4350		SCNetworkInterfaceRef   parent;
4351
4352		// create parent
4353		parent = SCNetworkInterfaceCreateWithInterface((SCNetworkInterfaceRef)interfacePrivate,
4354							       kSCNetworkInterfaceTypeVPN);
4355		CFRelease(interfacePrivate);
4356		interfacePrivate = (SCNetworkInterfacePrivateRef)parent;
4357	}
4358
4359	return (SCNetworkInterfaceRef)interfacePrivate;
4360}
4361
4362
4363#pragma mark -
4364#pragma mark SCNetworkInterface APIs
4365
4366
4367__private_extern__
4368CFArrayRef
4369__SCNetworkInterfaceCopyAll_IONetworkInterface(void)
4370{
4371	CFDictionaryRef		matching;
4372	CFArrayRef		new_interfaces;
4373
4374	// get Ethernet, Firewire, Thunderbolt, and AirPort interfaces
4375
4376	matching = IOServiceMatching(kIONetworkInterfaceClass);
4377	new_interfaces = findMatchingInterfaces(matching, processNetworkInterface, kSCNetworkInterfaceHiddenInterfaceKey);
4378	CFRelease(matching);
4379
4380	return new_interfaces;
4381}
4382
4383
4384static
4385CFArrayRef
4386__SCNetworkInterfaceCopyAll_Modem()
4387{
4388	CFDictionaryRef		matching;
4389	CFStringRef		match_keys[2];
4390	CFStringRef		match_vals[2];
4391	CFArrayRef		new_interfaces;
4392
4393	match_keys[0] = CFSTR(kIOProviderClassKey);
4394	match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
4395
4396	match_keys[1] = CFSTR(kIOSerialBSDTypeKey);
4397	match_vals[1] = CFSTR(kIOSerialBSDModemType);
4398
4399	matching = CFDictionaryCreate(NULL,
4400				      (const void **)match_keys,
4401				      (const void **)match_vals,
4402				      sizeof(match_keys)/sizeof(match_keys[0]),
4403				      &kCFTypeDictionaryKeyCallBacks,
4404				      &kCFTypeDictionaryValueCallBacks);
4405	new_interfaces = findMatchingInterfaces(matching, processSerialInterface, kSCNetworkInterfaceHiddenPortKey);
4406	CFRelease(matching);
4407
4408	return new_interfaces;
4409}
4410
4411
4412static
4413CFArrayRef
4414__SCNetworkInterfaceCopyAll_RS232()
4415{
4416	CFDictionaryRef		matching;
4417	CFStringRef		match_keys[2];
4418	CFStringRef		match_vals[2];
4419	CFArrayRef		new_interfaces;
4420
4421	match_keys[0] = CFSTR(kIOProviderClassKey);
4422	match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
4423
4424	match_keys[1] = CFSTR(kIOSerialBSDTypeKey);
4425	match_vals[1] = CFSTR(kIOSerialBSDRS232Type);
4426
4427	matching = CFDictionaryCreate(NULL,
4428				      (const void **)match_keys,
4429				      (const void **)match_vals,
4430				      sizeof(match_keys)/sizeof(match_keys[0]),
4431				      &kCFTypeDictionaryKeyCallBacks,
4432				      &kCFTypeDictionaryValueCallBacks);
4433	new_interfaces = findMatchingInterfaces(matching, processSerialInterface, kSCNetworkInterfaceHiddenPortKey);
4434	CFRelease(matching);
4435
4436	return new_interfaces;
4437}
4438
4439
4440#if	!TARGET_OS_IPHONE
4441static void
4442addBTPANInterface(SCPreferencesRef prefs, CFMutableArrayRef all_interfaces)
4443{
4444	CFIndex			i;
4445	SCNetworkInterfaceRef	interface;
4446	CFIndex			n;
4447
4448	n = CFArrayGetCount(all_interfaces);
4449	for (i = 0; i < n; i++) {
4450		SCNetworkInterfaceRef	interface;
4451
4452		interface = CFArrayGetValueAtIndex(all_interfaces, i);
4453		if (_SCNetworkInterfaceIsBluetoothPAN(interface)) {
4454			// if we already have a BT-PAN interface
4455			return;
4456		}
4457	}
4458
4459	interface = _SCNetworkInterfaceCopyBTPANInterface();
4460	if (interface != NULL) {
4461		// include BT-PAN interface
4462		CFArrayAppendValue(all_interfaces, interface);
4463		CFRelease(interface);
4464	}
4465
4466	return;
4467}
4468#endif	// !TARGET_OS_IPHONE
4469
4470
4471static void
4472add_interfaces(CFMutableArrayRef all_interfaces, CFArrayRef new_interfaces)
4473{
4474	CFIndex	i;
4475	CFIndex	n;
4476
4477	n = CFArrayGetCount(new_interfaces);
4478	for (i = 0; i < n; i++) {
4479		CFStringRef		bsdName;
4480		SCNetworkInterfaceRef	interface;
4481
4482		interface = CFArrayGetValueAtIndex(new_interfaces, i);
4483		bsdName = SCNetworkInterfaceGetBSDName(interface);
4484		if (bsdName != NULL) {
4485			CFArrayAppendValue(all_interfaces, interface);
4486		}
4487	}
4488
4489	return;
4490}
4491
4492
4493static void
4494__waitForInterfaces()
4495{
4496	CFStringRef		key;
4497	CFArrayRef		keys;
4498	Boolean			ok;
4499	SCDynamicStoreRef	store;
4500
4501	store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkInterfaceCopyAll"), NULL, NULL);
4502	if (store == NULL) {
4503		return;
4504	}
4505
4506	key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" "InterfaceNamer"), kSCDynamicStoreDomainPlugin);
4507	keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
4508	ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
4509	CFRelease(keys);
4510	if (!ok) {
4511		SCLog(TRUE, LOG_ERR,
4512		      CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"), SCErrorString(SCError()));
4513		goto done;
4514	}
4515
4516	while (TRUE) {
4517		CFArrayRef	changedKeys;
4518		CFDictionaryRef	dict;
4519		Boolean		quiet	= FALSE;
4520
4521		// check if quiet
4522		dict = SCDynamicStoreCopyValue(store, key);
4523		if (dict != NULL) {
4524			if (isA_CFDictionary(dict) &&
4525			    (CFDictionaryContainsKey(dict, CFSTR("*QUIET*")) ||
4526			     CFDictionaryContainsKey(dict, CFSTR("*TIMEOUT*")))) {
4527				quiet = TRUE;
4528			}
4529			CFRelease(dict);
4530		}
4531		if (quiet) {
4532			break;
4533		}
4534
4535		ok = SCDynamicStoreNotifyWait(store);
4536		if (!ok) {
4537			SCLog(TRUE, LOG_ERR,
4538			      CFSTR("SCDynamicStoreNotifyWait() failed: %s"), SCErrorString(SCError()));
4539			goto done;
4540		}
4541
4542		changedKeys = SCDynamicStoreCopyNotifiedKeys(store);
4543		if (changedKeys != NULL) {
4544			CFRelease(changedKeys);
4545		}
4546	}
4547
4548    done :
4549
4550	CFRelease(key);
4551	CFRelease(store);
4552	return;
4553}
4554
4555
4556CFArrayRef /* of SCNetworkInterfaceRef's */
4557_SCNetworkInterfaceCopyAllWithPreferences(SCPreferencesRef prefs)
4558{
4559	CFMutableArrayRef	all_interfaces;
4560	CFArrayRef		new_interfaces;
4561	Boolean			temp_preferences	= FALSE;
4562
4563	/* initialize runtime */
4564	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
4565
4566	/* wait for IOKit to quiesce */
4567	pthread_once(&iokit_quiet, __waitForInterfaces);
4568
4569	all_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
4570
4571	// get Ethernet, Firewire, Thunderbolt, and AirPort interfaces
4572	new_interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface();
4573	if (new_interfaces != NULL) {
4574		add_interfaces(all_interfaces, new_interfaces);
4575		CFRelease(new_interfaces);
4576	}
4577
4578	// get Modem interfaces
4579	new_interfaces = __SCNetworkInterfaceCopyAll_Modem();
4580	if (new_interfaces != NULL) {
4581		add_interfaces(all_interfaces, new_interfaces);
4582		CFRelease(new_interfaces);
4583	}
4584
4585	// get serial (RS232) interfaces
4586	new_interfaces = __SCNetworkInterfaceCopyAll_RS232();
4587	if (new_interfaces != NULL) {
4588		add_interfaces(all_interfaces, new_interfaces);
4589		CFRelease(new_interfaces);
4590	}
4591
4592	// get virtual network interfaces (Bond, Bridge, VLAN)
4593	if (prefs == NULL) {
4594		prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterfaceCopyAll"), NULL);
4595		if (prefs != NULL) {
4596			temp_preferences = TRUE;
4597		}
4598	}
4599	if (prefs != NULL) {
4600#if	!TARGET_OS_IPHONE
4601		new_interfaces = SCBondInterfaceCopyAll(prefs);
4602		if (new_interfaces != NULL) {
4603			add_interfaces(all_interfaces, new_interfaces);
4604			CFRelease(new_interfaces);
4605		}
4606#endif	// !TARGET_OS_IPHONE
4607
4608		new_interfaces = SCBridgeInterfaceCopyAll(prefs);
4609		if (new_interfaces != NULL) {
4610			add_interfaces(all_interfaces, new_interfaces);
4611			CFRelease(new_interfaces);
4612		}
4613
4614		new_interfaces = SCVLANInterfaceCopyAll(prefs);
4615		if (new_interfaces != NULL) {
4616			add_interfaces(all_interfaces, new_interfaces);
4617			CFRelease(new_interfaces);
4618		}
4619
4620#if	!TARGET_OS_IPHONE
4621		// add BT-PAN interface
4622		addBTPANInterface(prefs, all_interfaces);
4623#endif	// !TARGET_OS_IPHONE
4624
4625		if (temp_preferences) CFRelease(prefs);
4626	}
4627
4628	// all interfaces have been identified, order and return
4629	sort_interfaces(all_interfaces);
4630
4631	return all_interfaces;
4632}
4633
4634
4635CFArrayRef /* of SCNetworkInterfaceRef's */
4636SCNetworkInterfaceCopyAll()
4637{
4638	CFArrayRef	all_interfaces;
4639
4640	all_interfaces = _SCNetworkInterfaceCopyAllWithPreferences(NULL);
4641	return all_interfaces;
4642}
4643
4644
4645CFArrayRef /* of kSCNetworkInterfaceTypeXXX CFStringRef's */
4646SCNetworkInterfaceGetSupportedInterfaceTypes(SCNetworkInterfaceRef interface)
4647{
4648	CFIndex				i;
4649	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
4650
4651	if (!isA_SCNetworkInterface(interface)) {
4652		_SCErrorSet(kSCStatusInvalidArgument);
4653		return NULL;
4654	}
4655
4656	if (interfacePrivate->supported_interface_types != NULL) {
4657		goto done;
4658	}
4659
4660	i = findConfiguration(interfacePrivate->interface_type);
4661	if (i != kCFNotFound) {
4662		if (configurations[i].supported_interfaces != doNone) {
4663			interfacePrivate->supported_interface_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
4664			if (configurations[i].supported_interfaces & do6to4) {
4665				CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceType6to4);
4666			}
4667			if (configurations[i].supported_interfaces & doL2TP) {
4668				CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeL2TP);
4669			}
4670			if (configurations[i].supported_interfaces & doPPP) {
4671				CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPP);
4672			}
4673			if (configurations[i].supported_interfaces & doPPTP) {
4674				CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPTP);
4675			}
4676			if (configurations[i].supported_interfaces & doIPSec) {
4677				CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeIPSec);
4678			}
4679		}
4680	} else {
4681		SCNetworkInterfaceRef	child;
4682
4683		child = SCNetworkInterfaceGetInterface(interface);
4684		if ((child != NULL) && CFEqual(child, kSCNetworkInterfaceIPv4)) {
4685			interfacePrivate->supported_interface_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
4686			CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeVPN);
4687		}
4688	}
4689
4690    done :
4691
4692	return interfacePrivate->supported_interface_types;
4693}
4694
4695
4696CFArrayRef /* of kSCNetworkProtocolTypeXXX CFStringRef's */
4697SCNetworkInterfaceGetSupportedProtocolTypes(SCNetworkInterfaceRef interface)
4698{
4699	CFIndex				i;
4700	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
4701
4702	if (!isA_SCNetworkInterface(interface)) {
4703		_SCErrorSet(kSCStatusInvalidArgument);
4704		return NULL;
4705	}
4706
4707	if (interfacePrivate->supported_protocol_types != NULL) {
4708		goto done;
4709	}
4710
4711	i = findConfiguration(interfacePrivate->interface_type);
4712	if (i != kCFNotFound) {
4713		if (configurations[i].supported_protocols != doNone) {
4714			interfacePrivate->supported_protocol_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
4715			if (configurations[i].supported_protocols & doDNS) {
4716				CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeDNS);
4717			}
4718			if (configurations[i].supported_protocols & doIPv4) {
4719				CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv4);
4720			}
4721			if (configurations[i].supported_protocols & doIPv6) {
4722				CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv6);
4723			}
4724			if (configurations[i].supported_protocols & doProxies) {
4725				CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeProxies);
4726			}
4727#if	!TARGET_OS_IPHONE
4728			if (configurations[i].supported_protocols & doSMB) {
4729				CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeSMB);
4730			}
4731#endif	// !TARGET_OS_IPHONE
4732		}
4733	}
4734
4735    done :
4736
4737	return interfacePrivate->supported_protocol_types;
4738}
4739
4740
4741SCNetworkInterfaceRef
4742SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef interfaceType)
4743{
4744	SCNetworkInterfacePrivateRef	childPrivate	= (SCNetworkInterfacePrivateRef)child;
4745	CFIndex				childIndex;
4746	SCNetworkInterfacePrivateRef	parentPrivate;
4747
4748	if (!isA_SCNetworkInterface(child)) {
4749		_SCErrorSet(kSCStatusInvalidArgument);
4750		return NULL;
4751	}
4752
4753	if (!isA_CFString(interfaceType)) {
4754		_SCErrorSet(kSCStatusInvalidArgument);
4755		return NULL;
4756	}
4757
4758	if (CFEqual(child, kSCNetworkInterfaceLoopback)) {
4759		// can't layer on top of loopback
4760		_SCErrorSet(kSCStatusInvalidArgument);
4761		return NULL;
4762	}
4763
4764	childIndex = findConfiguration(childPrivate->interface_type);
4765
4766	parentPrivate = __SCNetworkInterfaceCreatePrivate(NULL,
4767							  child,
4768							  childPrivate->prefs,
4769							  childPrivate->serviceID);
4770	if (parentPrivate == NULL) {
4771		_SCErrorSet(kSCStatusFailed);
4772		return NULL;
4773	}
4774
4775	if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
4776		parentPrivate->interface_type = kSCNetworkInterfaceTypePPP;
4777		parentPrivate->entity_type    = kSCValNetInterfaceTypePPP;
4778
4779		// entity subtype
4780		if (childIndex != kCFNotFound) {
4781			if (configurations[childIndex].ppp_subtype != NULL) {
4782				parentPrivate->entity_subtype = *configurations[childIndex].ppp_subtype;
4783			} else {
4784				// sorry, the child interface does not support PPP
4785				goto fail;
4786			}
4787		} else {
4788			// if the child's interface type not known, use the child entities "Type"
4789			parentPrivate->entity_subtype = childPrivate->entity_type;
4790		}
4791
4792		if (childPrivate->entity_device != NULL) {
4793			parentPrivate->entity_device = CFStringCreateCopy(NULL, childPrivate->entity_device);
4794		}
4795
4796		if (childPrivate->entity_device_unique != NULL) {
4797			parentPrivate->entity_device_unique = CFStringCreateCopy(NULL, childPrivate->entity_device_unique);
4798		}
4799	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
4800		if ((childIndex == kCFNotFound) ||
4801		    ((configurations[childIndex].supported_interfaces & doL2TP) != doL2TP)) {
4802			// if the child interface does not support L2TP
4803			goto fail;
4804		}
4805		parentPrivate->interface_type = kSCNetworkInterfaceTypeL2TP;
4806		parentPrivate->localized_key  = CFSTR("l2tp");
4807		parentPrivate->entity_type    = kSCEntNetL2TP;			// interface config goes into "L2TP"
4808	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) {
4809		if ((childIndex == kCFNotFound) ||
4810		    ((configurations[childIndex].supported_interfaces & doPPTP) != doPPTP)) {
4811			// if the child interface does not support PPTP
4812			goto fail;
4813		}
4814		parentPrivate->interface_type = kSCNetworkInterfaceTypePPTP;
4815		parentPrivate->localized_key  = CFSTR("pptp");
4816		parentPrivate->entity_type    = kSCEntNetPPTP;			// interface config goes into "PPTP"
4817	} else if (CFEqual(interfaceType, kSCNetworkInterfaceType6to4)) {
4818		if ((childIndex == kCFNotFound) ||
4819		    ((configurations[childIndex].supported_interfaces & do6to4) != do6to4)) {
4820			// if the child interface does not support 6to4
4821			goto fail;
4822		}
4823
4824		parentPrivate->interface_type = kSCNetworkInterfaceType6to4;
4825		parentPrivate->localized_key  = CFSTR("6to4");
4826		parentPrivate->entity_type    = kSCValNetInterfaceType6to4;
4827		parentPrivate->entity_device  = CFRetain(CFSTR("stf0"));
4828	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
4829		if ((childIndex == kCFNotFound) ||
4830		    ((configurations[childIndex].supported_interfaces & doIPSec) != doIPSec)) {
4831			// if the child interface does not support IPSec
4832			goto fail;
4833		}
4834		parentPrivate->interface_type = kSCNetworkInterfaceTypeIPSec;
4835		parentPrivate->localized_key  = CFSTR("ipsec");
4836		parentPrivate->entity_type    = kSCValNetInterfaceTypeIPSec;
4837	} else 	if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
4838		if (childIndex != kCFNotFound) {
4839			// if not a "vendor" child interface
4840			goto fail;
4841		}
4842
4843		parentPrivate->interface_type = kSCNetworkInterfaceTypeVPN;
4844		parentPrivate->localized_key  = CFSTR("vpn");
4845		parentPrivate->localized_arg1 = CFRetain(childPrivate->entity_type);
4846		parentPrivate->entity_type    = kSCValNetInterfaceTypeVPN;
4847		parentPrivate->entity_subtype = childPrivate->entity_type;
4848		if (childPrivate->entity_device != NULL) {
4849			parentPrivate->entity_device = CFStringCreateCopy(NULL, childPrivate->entity_device);
4850		}
4851		if (parentPrivate->entity_subtype != NULL) {
4852			CFArrayRef	components;
4853			CFIndex		n;
4854			CFStringRef	vpnType;
4855
4856			//
4857			// the "default" interface name is derived from the VPN type
4858			//
4859			// e.g.
4860			//	com.apple.Apple-VPN.vpnplugin --> "Apple VPN"
4861			//	          ^^^^^^^^^
4862			//
4863			vpnType = parentPrivate->entity_subtype;
4864			components = CFStringCreateArrayBySeparatingStrings(NULL, vpnType, CFSTR("."));
4865			n = CFArrayGetCount(components);
4866			if ((n >= 4) &&
4867			    CFEqual(CFArrayGetValueAtIndex(components, n - 1), CFSTR("vpnplugin"))) {
4868				CFMutableStringRef	str;
4869
4870				str = CFStringCreateMutableCopy(NULL,
4871								0,
4872								CFArrayGetValueAtIndex(components, n - 2));
4873				(void) CFStringFindAndReplace(str,
4874							      CFSTR("-"),
4875							      CFSTR(" "),
4876							      CFRangeMake(0, CFStringGetLength(str)),
4877							      0);
4878				parentPrivate->localized_name = str;
4879			}
4880			CFRelease(components);
4881		}
4882	} else if (CFStringFind(interfaceType, CFSTR("."), 0).location != kCFNotFound) {
4883		// if custom interface type
4884		if (vendor_interface_types == NULL) {
4885			vendor_interface_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
4886		}
4887		CFSetAddValue(vendor_interface_types, interfaceType);
4888
4889		parentPrivate->interface_type = CFSetGetValue(vendor_interface_types, interfaceType);
4890		parentPrivate->entity_type    = parentPrivate->interface_type;	// interface config goes into a
4891										// a dictionary with the same
4892										// name as the interfaceType
4893	} else {
4894		// unknown interface type
4895		goto fail;
4896	}
4897
4898	parentPrivate->hidden = childPrivate->hidden;
4899
4900	if (childPrivate->overrides != NULL) {
4901		parentPrivate->overrides = CFDictionaryCreateMutableCopy(NULL, 0, childPrivate->overrides);
4902	}
4903
4904	// The following change handles the case where a user has both an Ethernet and
4905	// PPPoE network service. Because a PPPoE service is typically associated with
4906	// an ISP we want it to be sorted higher in the service order.
4907	if ((parentPrivate->entity_subtype != NULL) &&
4908	    (CFEqual(parentPrivate->entity_subtype, kSCValNetInterfaceSubTypePPPoE))) {
4909		if ((childPrivate->interface_type != NULL) &&
4910		    (CFEqual(childPrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211))) {
4911			parentPrivate->sort_order = kSortAirportPPP;
4912		} else {
4913			parentPrivate->sort_order = kSortEthernetPPP;
4914		}
4915	} else {
4916		// set sort order of the parent to match the child interface
4917		parentPrivate->sort_order = childPrivate->sort_order;
4918	}
4919
4920	return (SCNetworkInterfaceRef)parentPrivate;
4921
4922    fail :
4923
4924	CFRelease(parentPrivate);
4925	_SCErrorSet(kSCStatusInvalidArgument);
4926	return NULL;
4927}
4928
4929
4930__private_extern__
4931CFDictionaryRef
4932__SCNetworkInterfaceGetDefaultConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
4933{
4934	CFDictionaryRef			config			= NULL;
4935	CFStringRef			defaultType;
4936	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
4937
4938	/* initialize runtime (and kSCNetworkInterfaceIPv4) */
4939	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
4940
4941	defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
4942	if (defaultType != NULL) {
4943		if (set != NULL) {
4944			CFStringRef	path;
4945
4946			path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL,				// allocator
4947										   SCNetworkSetGetSetID(set),		// set
4948										   interfacePrivate->entity_device,	// interface
4949										   defaultType);			// entity
4950			if (path != NULL) {
4951				config = __getPrefsConfiguration(interfacePrivate->prefs, path);
4952				CFRelease(path);
4953
4954				if (config == NULL) {
4955					// if the "set" does not have a saved configuration, use
4956					// the [template] "interface" configuration
4957					if (interfacePrivate->unsaved != NULL) {
4958						config = CFDictionaryGetValue(interfacePrivate->unsaved, defaultType);
4959						if (config == (CFDictionaryRef)kCFNull) {
4960							config = NULL;
4961						}
4962					}
4963				}
4964				if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
4965					config = NULL;
4966				}
4967			}
4968		}
4969	}
4970
4971	return config;
4972}
4973
4974
4975static CFDictionaryRef
4976__SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef	interface,
4977				     CFStringRef		extendedType)
4978{
4979	CFDictionaryRef			config			= NULL;
4980	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
4981	CFArrayRef			paths;
4982
4983	/* initialize runtime (and kSCNetworkInterfaceIPv4) */
4984	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
4985
4986	paths = copyConfigurationPaths(interfacePrivate, extendedType);
4987	if (paths != NULL) {
4988		CFStringRef			path;
4989
4990		path = CFArrayGetValueAtIndex(paths, 0);
4991		config = __getPrefsConfiguration(interfacePrivate->prefs, path);
4992
4993		CFRelease(paths);
4994	} else {
4995		if (interfacePrivate->unsaved != NULL) {
4996			config = CFDictionaryGetValue(interfacePrivate->unsaved, extendedType);
4997			if (config == (CFDictionaryRef)kCFNull) {
4998				config = NULL;
4999			}
5000		}
5001	}
5002
5003	if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
5004		config = NULL;
5005	}
5006
5007	return config;
5008}
5009
5010
5011CFDictionaryRef
5012SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface)
5013{
5014	CFDictionaryRef	config;
5015	CFStringRef	defaultType;
5016
5017	if (!isA_SCNetworkInterface(interface)) {
5018		_SCErrorSet(kSCStatusInvalidArgument);
5019		return NULL;
5020	}
5021
5022	defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
5023	if (defaultType == NULL) {
5024		return NULL;
5025	}
5026
5027	config = __SCNetworkInterfaceGetConfiguration(interface, defaultType);
5028	if (config == NULL) {
5029		if (CFEqual(defaultType, kSCEntNetAirPort)) {
5030			SCNetworkInterfacePrivateRef	interfacePrivate;
5031			CFStringRef			path;
5032
5033			// if AirPort interface, check for a per-service config
5034			interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5035			path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,				// allocator
5036									      interfacePrivate->serviceID,	// service
5037									      kSCEntNetAirPort);		// entity
5038			config = __getPrefsConfiguration(interfacePrivate->prefs, path);
5039			CFRelease(path);
5040		}
5041	}
5042	if (config == NULL) {
5043		_SCErrorSet(kSCStatusOK);
5044	}
5045
5046	return config;
5047}
5048
5049
5050CFDictionaryRef
5051SCNetworkInterfaceGetExtendedConfiguration(SCNetworkInterfaceRef	interface,
5052					   CFStringRef			extendedType)
5053{
5054	CFDictionaryRef	config;
5055
5056	if (!isA_SCNetworkInterface(interface)) {
5057		_SCErrorSet(kSCStatusInvalidArgument);
5058		return NULL;
5059	}
5060
5061	if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, TRUE)) {
5062		_SCErrorSet(kSCStatusInvalidArgument);
5063		return NULL;
5064	}
5065
5066	config = __SCNetworkInterfaceGetConfiguration(interface, extendedType);
5067	if (config == NULL) {
5068		_SCErrorSet(kSCStatusOK);
5069	}
5070
5071	return config;
5072}
5073
5074
5075__private_extern__
5076CFStringRef
5077__SCNetworkInterfaceGetEntityType(SCNetworkInterfaceRef interface)
5078{
5079	SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5080
5081	return interfacePrivate->entity_type;
5082}
5083
5084
5085__private_extern__
5086CFStringRef
5087__SCNetworkInterfaceGetEntitySubType(SCNetworkInterfaceRef interface)
5088{
5089	SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef) interface;
5090
5091	return interfacePrivate->entity_subtype;
5092}
5093
5094
5095CFStringRef
5096SCNetworkInterfaceGetBSDName(SCNetworkInterfaceRef interface)
5097{
5098	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5099
5100	if (!isA_SCNetworkInterface(interface)) {
5101		_SCErrorSet(kSCStatusInvalidArgument);
5102		return NULL;
5103	}
5104
5105	if ((interfacePrivate->interface != NULL) &&
5106	    (interfacePrivate->interface != kSCNetworkInterfaceIPv4)) {
5107		_SCErrorSet(kSCStatusOK);
5108		return NULL;
5109	}
5110
5111	return interfacePrivate->entity_device;
5112}
5113
5114
5115CFStringRef
5116SCNetworkInterfaceGetHardwareAddressString(SCNetworkInterfaceRef interface)
5117{
5118	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5119
5120	if (!isA_SCNetworkInterface(interface)) {
5121		_SCErrorSet(kSCStatusInvalidArgument);
5122		return NULL;
5123	}
5124
5125	if ((interfacePrivate->address != NULL) &&
5126	    (interfacePrivate->addressString == NULL)) {
5127		uint8_t		*bp;
5128		char		*cp;
5129		CFIndex		n;
5130		char		mac[sizeof("xx:xx:xx:xx:xx:xx:xx:xx")];
5131		char		*mac_p	= mac;
5132
5133		bp = (uint8_t *)CFDataGetBytePtr(interfacePrivate->address);
5134		n  = CFDataGetLength(interfacePrivate->address) * 3;
5135
5136		if (n > sizeof(mac)) {
5137			mac_p = CFAllocatorAllocate(NULL, 0, n);
5138		}
5139
5140		for (cp = mac_p; n > 0; n -= 3) {
5141			cp += snprintf(cp, n, "%2.2x:", *bp++);
5142		}
5143
5144		interfacePrivate->addressString = CFStringCreateWithCString(NULL, mac_p, kCFStringEncodingUTF8);
5145		if (mac_p != mac)	CFAllocatorDeallocate(NULL, mac_p);
5146	}
5147
5148	return interfacePrivate->addressString;
5149}
5150
5151
5152SCNetworkInterfaceRef
5153SCNetworkInterfaceGetInterface(SCNetworkInterfaceRef interface)
5154{
5155	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5156
5157	if (!isA_SCNetworkInterface(interface)) {
5158		_SCErrorSet(kSCStatusInvalidArgument);
5159		return NULL;
5160	}
5161
5162	return interfacePrivate->interface;
5163}
5164
5165
5166CFStringRef
5167SCNetworkInterfaceGetInterfaceType(SCNetworkInterfaceRef interface)
5168{
5169	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5170
5171	if (!isA_SCNetworkInterface(interface)) {
5172		_SCErrorSet(kSCStatusInvalidArgument);
5173		return NULL;
5174	}
5175
5176	return interfacePrivate->interface_type;
5177}
5178
5179
5180static CFStringRef
5181copy_interface_string(CFBundleRef bundle, CFStringRef key, Boolean localized)
5182{
5183	CFStringRef	str	= NULL;
5184
5185	if (localized) {
5186		str = CFBundleCopyLocalizedString(bundle,
5187						  key,
5188						  key,
5189						  NETWORKINTERFACE_LOCALIZATIONS);
5190	} else {
5191		str = _SC_CFBundleCopyNonLocalizedString(bundle,
5192							 key,
5193							 key,
5194							 NETWORKINTERFACE_LOCALIZATIONS);
5195	}
5196
5197	return str;
5198}
5199
5200
5201static CFStringRef
5202copy_display_name(SCNetworkInterfaceRef interface, Boolean localized, Boolean oldLocalization)
5203{
5204	CFMutableStringRef	local;
5205	CFStringRef		name;
5206
5207	local = CFStringCreateMutable(NULL, 0);
5208
5209	while (interface != NULL) {
5210		Boolean				added			= FALSE;
5211		SCNetworkInterfaceRef		child			= NULL;
5212		SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5213
5214		if ((interfacePrivate->interface != NULL) &&
5215		    (interfacePrivate->interface != kSCNetworkInterfaceIPv4) &&
5216		    !CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeVPN)) {
5217			child = interfacePrivate->interface;
5218		}
5219
5220		if ((bundle != NULL) && (interfacePrivate->localized_key != NULL)) {
5221			CFStringRef	fmt;
5222			CFStringRef	key	= interfacePrivate->localized_key;
5223
5224			if (oldLocalization) {
5225				key = CFStringCreateWithFormat(NULL, NULL, CFSTR("X-%@"),
5226							       interfacePrivate->localized_key);
5227			}
5228			fmt = copy_interface_string(bundle, key, localized);
5229			if (fmt != NULL) {
5230				CFStringAppendFormat(local,
5231						     NULL,
5232						     fmt,
5233						     interfacePrivate->localized_arg1,
5234						     interfacePrivate->localized_arg2);
5235				CFRelease(fmt);
5236				added = TRUE;
5237			}
5238			if (oldLocalization) {
5239				CFRelease(key);
5240			}
5241		}
5242
5243		if (!added &&
5244		    (interfacePrivate->prefs != NULL) &&
5245		    (interfacePrivate->serviceID != NULL) &&
5246		    (child == NULL)) {
5247			CFDictionaryRef	entity;
5248			CFStringRef	path;
5249
5250			// check for (and use) the name of the interface when it
5251			// was last available
5252			path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
5253									      interfacePrivate->serviceID,
5254									      kSCEntNetInterface);
5255			entity = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
5256			CFRelease(path);
5257			if (isA_CFDictionary(entity)) {
5258				CFStringRef	name;
5259
5260				name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
5261				if (isA_CFString(name)) {
5262					CFStringAppend(local, name);
5263					added = TRUE;
5264				}
5265			}
5266		}
5267
5268		if (!added) {
5269			// create (non-)localized name based on the interface type
5270			CFStringAppend(local, interfacePrivate->interface_type);
5271
5272			// ... and, if this is a leaf node, the interface device
5273			if ((interfacePrivate->entity_device != NULL) && (child == NULL)) {
5274				CFStringAppendFormat(local, NULL, CFSTR(" (%@)"), interfacePrivate->entity_device);
5275			}
5276		}
5277
5278		if (child != NULL) {
5279			// if this interface is layered over another
5280			CFStringAppend(local, CFSTR(" --> "));
5281		}
5282
5283		interface = child;
5284	}
5285
5286	name = CFStringCreateCopy(NULL, local);
5287	CFRelease(local);
5288
5289	return name;
5290}
5291
5292
5293#if	!TARGET_OS_IPHONE
5294__private_extern__
5295CFStringRef
5296__SCNetworkInterfaceCopyXLocalizedDisplayName(SCNetworkInterfaceRef interface)
5297{
5298	CFStringRef			name;
5299
5300	if (!isA_SCNetworkInterface(interface)) {
5301		_SCErrorSet(kSCStatusInvalidArgument);
5302		return NULL;
5303	}
5304
5305	name = copy_display_name(interface, TRUE, TRUE);
5306	return name;
5307}
5308
5309
5310__private_extern__
5311CFStringRef
5312__SCNetworkInterfaceCopyXNonLocalizedDisplayName(SCNetworkInterfaceRef interface)
5313{
5314	CFStringRef			localized_name;
5315
5316	if (!isA_SCNetworkInterface(interface)) {
5317		_SCErrorSet(kSCStatusInvalidArgument);
5318		return NULL;
5319	}
5320
5321	localized_name = copy_display_name(interface, FALSE, TRUE);
5322	return localized_name;
5323}
5324#endif	// !TARGET_OS_IPHONE
5325
5326__private_extern__
5327void
5328__SCNetworkInterfaceSetUserDefinedName(SCNetworkInterfaceRef interface, CFStringRef name)
5329{
5330        SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5331
5332        if (!isA_SCNetworkInterface(interface)) {
5333                return;
5334	}
5335        if (name != NULL) {
5336                CFRetain(name);
5337	}
5338        if (interfacePrivate->name != NULL) {
5339                CFRelease(interfacePrivate->name);
5340	}
5341        interfacePrivate->name = name;
5342
5343	if (name != NULL) {
5344		CFRetain(name);
5345	}
5346	if (interfacePrivate->localized_name != NULL) {
5347		CFRelease(interfacePrivate->localized_name);
5348	}
5349	interfacePrivate->localized_name = name;
5350}
5351
5352__private_extern__
5353CFStringRef
5354__SCNetworkInterfaceGetUserDefinedName(SCNetworkInterfaceRef interface)
5355{
5356	SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5357
5358	if (!isA_SCNetworkInterface(interface)) {
5359		return NULL;
5360	}
5361
5362	return interfacePrivate->name;
5363}
5364
5365
5366__private_extern__
5367CFStringRef
5368__SCNetworkInterfaceGetNonLocalizedDisplayName(SCNetworkInterfaceRef interface)
5369{
5370	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5371
5372	if (!isA_SCNetworkInterface(interface)) {
5373		_SCErrorSet(kSCStatusInvalidArgument);
5374		return NULL;
5375	}
5376
5377	if (interfacePrivate->name == NULL) {
5378		interfacePrivate->name = copy_display_name(interface, FALSE, FALSE);
5379	}
5380
5381	return interfacePrivate->name;
5382}
5383
5384
5385CFStringRef
5386SCNetworkInterfaceGetLocalizedDisplayName(SCNetworkInterfaceRef interface)
5387{
5388	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5389
5390	if (!isA_SCNetworkInterface(interface)) {
5391		_SCErrorSet(kSCStatusInvalidArgument);
5392		return NULL;
5393	}
5394
5395	if (interfacePrivate->localized_name == NULL) {
5396		interfacePrivate->localized_name = copy_display_name(interface, TRUE, FALSE);
5397	}
5398
5399	return interfacePrivate->localized_name;
5400}
5401
5402
5403__private_extern__
5404CFDictionaryRef
5405__SCNetworkInterfaceGetTemplateOverrides(SCNetworkInterfaceRef interface, CFStringRef overrideType)
5406{
5407	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5408	CFDictionaryRef			overrides		= NULL;
5409
5410	if (interfacePrivate->overrides != NULL) {
5411		overrides = CFDictionaryGetValue(interfacePrivate->overrides, overrideType);
5412	}
5413
5414	return overrides;
5415}
5416
5417
5418CFTypeID
5419SCNetworkInterfaceGetTypeID(void)
5420{
5421	pthread_once(&initialized, __SCNetworkInterfaceInitialize);	/* initialize runtime */
5422	return __kSCNetworkInterfaceTypeID;
5423}
5424
5425
5426__private_extern__
5427Boolean
5428__SCNetworkInterfaceSetDefaultConfiguration(SCNetworkSetRef		set,
5429					    SCNetworkInterfaceRef	interface,
5430					    CFStringRef			defaultType,
5431					    CFDictionaryRef		config,
5432					    Boolean			okToHold)
5433{
5434	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5435	Boolean				ok			= FALSE;
5436
5437	/* initialize runtime (and kSCNetworkInterfaceIPv4) */
5438	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
5439
5440	if (defaultType == NULL) {
5441		defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
5442		if (defaultType == NULL) {
5443			return FALSE;
5444		}
5445	}
5446
5447	if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
5448		config = NULL;
5449	}
5450
5451	if (set != NULL) {
5452		CFStringRef	path;
5453
5454		path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL,				// allocator
5455									   SCNetworkSetGetSetID(set),		// set
5456									   interfacePrivate->entity_device,	// interface
5457									   defaultType);			// entity
5458		if (path != NULL) {
5459			ok = __setPrefsConfiguration(interfacePrivate->prefs, path, config, FALSE);
5460			CFRelease(path);
5461			if (ok) {
5462				// if configuration has been saved
5463				if (interfacePrivate->unsaved != NULL) {
5464					CFDictionaryRemoveValue(interfacePrivate->unsaved, defaultType);
5465					if (CFDictionaryGetCount(interfacePrivate->unsaved) == 0) {
5466						CFRelease(interfacePrivate->unsaved);
5467						interfacePrivate->unsaved = NULL;
5468					}
5469				}
5470			}
5471		} else {
5472			if (okToHold) {
5473				if (config == NULL) {
5474					// remember that we are clearing the configuration
5475					config = (CFDictionaryRef)kCFNull;
5476				}
5477
5478				if (interfacePrivate->unsaved == NULL) {
5479					interfacePrivate->unsaved = CFDictionaryCreateMutable(NULL,
5480											      0,
5481											      &kCFTypeDictionaryKeyCallBacks,
5482											      &kCFTypeDictionaryValueCallBacks);
5483				}
5484				CFDictionarySetValue(interfacePrivate->unsaved, defaultType, config);
5485				ok = TRUE;
5486			} else {
5487				_SCErrorSet(kSCStatusNoKey);
5488			}
5489		}
5490	}
5491
5492	return ok;
5493}
5494
5495
5496__private_extern__
5497Boolean
5498__SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef	interface,
5499				     CFStringRef		extendedType,
5500				     CFDictionaryRef		config,
5501				     Boolean			okToHold)
5502{
5503	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5504	Boolean				ok			= FALSE;
5505	CFArrayRef			paths;
5506
5507	/* initialize runtime (and kSCNetworkInterfaceIPv4) */
5508	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
5509
5510	if (extendedType == NULL) {
5511		extendedType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
5512		if (extendedType == NULL) {
5513			return FALSE;
5514		}
5515	}
5516
5517	if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
5518		config = NULL;
5519	}
5520
5521	paths = copyConfigurationPaths(interfacePrivate, extendedType);
5522	if (paths != NULL) {
5523		CFIndex				i;
5524		CFIndex				n;
5525
5526		n = CFArrayGetCount(paths);
5527		for (i = 0; i < n; i++) {
5528			CFStringRef     path;
5529
5530			path = CFArrayGetValueAtIndex(paths, i);
5531			ok = __setPrefsConfiguration(interfacePrivate->prefs, path, config, FALSE);
5532			if (!ok) {
5533				break;
5534			}
5535		}
5536
5537		if (ok) {
5538			// if configuration has been saved
5539			if (interfacePrivate->unsaved != NULL) {
5540				CFDictionaryRemoveValue(interfacePrivate->unsaved, extendedType);
5541				if (CFDictionaryGetCount(interfacePrivate->unsaved) == 0) {
5542					CFRelease(interfacePrivate->unsaved);
5543					interfacePrivate->unsaved = NULL;
5544				}
5545			}
5546		}
5547
5548		CFRelease(paths);
5549	} else {
5550		if (okToHold) {
5551			if (config == NULL) {
5552				// remember that we are clearing the configuration
5553				config = (CFDictionaryRef)kCFNull;
5554			}
5555
5556			if (interfacePrivate->unsaved == NULL) {
5557				interfacePrivate->unsaved = CFDictionaryCreateMutable(NULL,
5558										      0,
5559										      &kCFTypeDictionaryKeyCallBacks,
5560										      &kCFTypeDictionaryValueCallBacks);
5561			}
5562			CFDictionarySetValue(interfacePrivate->unsaved, extendedType, config);
5563			ok = TRUE;
5564		} else {
5565			_SCErrorSet(kSCStatusNoKey);
5566		}
5567	}
5568
5569	return ok;
5570}
5571
5572
5573Boolean
5574SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config)
5575{
5576	CFStringRef	defaultType;
5577
5578	if (!isA_SCNetworkInterface(interface)) {
5579		_SCErrorSet(kSCStatusInvalidArgument);
5580		return FALSE;
5581	}
5582
5583	defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
5584	if (defaultType == NULL) {
5585		return FALSE;
5586	}
5587
5588	return __SCNetworkInterfaceSetConfiguration(interface, defaultType, config, FALSE);
5589}
5590
5591
5592Boolean
5593SCNetworkInterfaceSetExtendedConfiguration(SCNetworkInterfaceRef	interface,
5594					   CFStringRef			extendedType,
5595					   CFDictionaryRef		config)
5596{
5597	if (!isA_SCNetworkInterface(interface)) {
5598		_SCErrorSet(kSCStatusInvalidArgument);
5599		return FALSE;
5600	}
5601
5602	if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, TRUE)) {
5603		return FALSE;
5604	}
5605
5606	return __SCNetworkInterfaceSetConfiguration(interface, extendedType, config, FALSE);
5607}
5608
5609
5610#pragma mark -
5611#pragma mark SCNetworkInterface [Refresh Configuration] API
5612
5613
5614#ifndef kSCEntNetRefreshConfiguration
5615#define kSCEntNetRefreshConfiguration	CFSTR("RefreshConfiguration")
5616#endif	// kSCEntNetRefreshConfiguration
5617
5618Boolean
5619_SCNetworkInterfaceForceConfigurationRefresh(CFStringRef ifName)
5620{
5621	CFStringRef		key;
5622	Boolean			ok     = FALSE;
5623
5624	if (!isA_CFString(ifName)) {
5625		_SCErrorSet(kSCStatusInvalidArgument);
5626		return FALSE;
5627	}
5628
5629	key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
5630							    kSCDynamicStoreDomainState,
5631							    ifName,
5632							    kSCEntNetRefreshConfiguration);
5633	ok = SCDynamicStoreNotifyValue(NULL, key);
5634	CFRelease(key);
5635	return ok;
5636}
5637
5638
5639static Boolean
5640__SCNetworkInterfaceForceConfigurationRefresh_helper(SCPreferencesRef prefs, CFStringRef ifName)
5641{
5642	CFDataRef		data		= NULL;
5643	Boolean			ok;
5644	SCPreferencesPrivateRef	prefsPrivate	= (SCPreferencesPrivateRef)prefs;
5645	uint32_t		status		= kSCStatusOK;
5646	CFDataRef		reply		= NULL;
5647
5648	if (prefsPrivate->helper_port == MACH_PORT_NULL) {
5649		ok = __SCPreferencesCreate_helper(prefs);
5650		if (!ok) {
5651			return FALSE;
5652		}
5653	}
5654
5655	// serialize the interface name
5656	ok = _SCSerializeString(ifName, &data, NULL, NULL);
5657	if (!ok) {
5658		goto fail;
5659	}
5660
5661	// have the helper "refresh" the configuration
5662	status = kSCStatusOK;
5663	reply  = NULL;
5664	ok = _SCHelperExec(prefsPrivate->helper_port,
5665			   SCHELPER_MSG_INTERFACE_REFRESH,
5666			   data,
5667			   &status,
5668			   NULL);
5669	if (data != NULL) CFRelease(data);
5670	if (!ok) {
5671		goto fail;
5672	}
5673
5674	if (status != kSCStatusOK) {
5675		goto error;
5676	}
5677
5678	return TRUE;
5679
5680    fail :
5681
5682	// close helper
5683	if (prefsPrivate->helper_port != MACH_PORT_NULL) {
5684		_SCHelperClose(&prefsPrivate->helper_port);
5685	}
5686
5687	status = kSCStatusAccessError;
5688
5689    error :
5690
5691	// return error
5692	_SCErrorSet(status);
5693	return FALSE;
5694}
5695
5696
5697Boolean
5698SCNetworkInterfaceForceConfigurationRefresh(SCNetworkInterfaceRef interface)
5699{
5700	CFStringRef			ifName;
5701	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5702
5703	if (!isA_SCNetworkInterface(interface)) {
5704		_SCErrorSet(kSCStatusInvalidArgument);
5705		return FALSE;
5706	}
5707
5708	ifName = SCNetworkInterfaceGetBSDName(interface);
5709	if (ifName == NULL) {
5710		_SCErrorSet(kSCStatusInvalidArgument);
5711		return FALSE;
5712	}
5713
5714	if (interfacePrivate->prefs != NULL) {
5715		SCPreferencesRef		prefs		= interfacePrivate->prefs;
5716		SCPreferencesPrivateRef		prefsPrivate	= (SCPreferencesPrivateRef)prefs;
5717
5718		if (prefsPrivate->authorizationData != NULL) {
5719			return __SCNetworkInterfaceForceConfigurationRefresh_helper(prefs, ifName);
5720		}
5721	}
5722
5723	return _SCNetworkInterfaceForceConfigurationRefresh(ifName);
5724}
5725
5726
5727Boolean
5728SCNetworkInterfaceRefreshConfiguration(CFStringRef ifName)
5729{
5730	return _SCNetworkInterfaceForceConfigurationRefresh(ifName);
5731}
5732
5733
5734#pragma mark -
5735#pragma mark SCNetworkInterface Password APIs
5736
5737
5738static CFStringRef
5739getPasswordID(CFDictionaryRef config, CFStringRef serviceID)
5740{
5741	CFStringRef	unique_id	= NULL;
5742
5743	if (config != NULL) {
5744		CFStringRef	encryption;
5745
5746		encryption = CFDictionaryGetValue(config, kSCPropNetPPPAuthPasswordEncryption);
5747		if (isA_CFString(encryption) &&
5748		    CFEqual(encryption, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
5749			unique_id = CFDictionaryGetValue(config, kSCPropNetPPPAuthPassword);
5750		}
5751	}
5752	if (unique_id == NULL) {
5753		unique_id = serviceID;
5754	}
5755
5756	return unique_id;
5757}
5758
5759
5760static CFStringRef
5761copySharedSecretID(CFDictionaryRef config, CFStringRef serviceID)
5762{
5763	CFMutableStringRef	shared_id	= NULL;
5764
5765	if (config != NULL) {
5766		CFStringRef	encryption;
5767
5768		encryption = CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecretEncryption);
5769		if (isA_CFString(encryption) &&
5770		    CFEqual(encryption, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
5771			shared_id = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecret);
5772			if (shared_id != NULL) {
5773				CFRetain(shared_id);
5774			}
5775		}
5776	}
5777
5778	if (shared_id == NULL) {
5779		CFStringRef	unique_id;
5780
5781		unique_id = getPasswordID(config, serviceID);
5782		shared_id = CFStringCreateMutableCopy(NULL, 0, unique_id);
5783		CFStringAppend(shared_id, CFSTR(".SS"));
5784	}
5785
5786	return shared_id;
5787}
5788
5789
5790static CFStringRef
5791copyXAuthID(CFDictionaryRef config, CFStringRef serviceID)
5792{
5793	CFMutableStringRef	xauth_id	= NULL;
5794
5795	if (config != NULL) {
5796		CFStringRef	encryption;
5797
5798		encryption = CFDictionaryGetValue(config, kSCPropNetIPSecXAuthPasswordEncryption);
5799		if (isA_CFString(encryption) &&
5800		    CFEqual(encryption, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) {
5801			xauth_id = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecXAuthPassword);
5802			if (xauth_id != NULL) {
5803				CFRetain(xauth_id);
5804			}
5805		}
5806	}
5807
5808	if (xauth_id == NULL) {
5809		CFStringRef	unique_id;
5810
5811		unique_id = getPasswordID(config, serviceID);
5812		xauth_id = CFStringCreateMutableCopy(NULL, 0, unique_id);
5813		CFStringAppend(xauth_id, CFSTR(".XAUTH"));
5814	}
5815
5816	return xauth_id;
5817}
5818
5819
5820static Boolean
5821checkInterfacePassword(SCNetworkInterfaceRef		interface,
5822		       SCNetworkInterfacePasswordType	passwordType,
5823		       SCPreferencesRef			*prefs,
5824		       CFStringRef			*serviceID)
5825{
5826	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
5827
5828	if (!isA_SCNetworkInterface(interface)) {
5829		goto error;
5830	}
5831
5832	*serviceID = interfacePrivate->serviceID;
5833	if (*serviceID == NULL) {
5834		goto error;
5835	}
5836
5837	*prefs = interfacePrivate->prefs;
5838	if (*prefs == NULL) {
5839		goto error;
5840	}
5841
5842	switch (passwordType) {
5843		case kSCNetworkInterfacePasswordTypePPP : {
5844			CFStringRef	interfaceType;
5845
5846			interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
5847			if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
5848				// if PPP
5849				break;
5850			}
5851
5852			goto error;
5853		}
5854
5855		case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
5856			CFStringRef	interfaceType;
5857
5858			interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
5859			if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
5860				interface = SCNetworkInterfaceGetInterface(interface);
5861				if (interface != NULL) {
5862					interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
5863					if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
5864						// if PPP->L2TP interface
5865						break;
5866					}
5867				}
5868			} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
5869				// if IPSec interface
5870				break;
5871			}
5872
5873			goto error;
5874		}
5875
5876		case kSCNetworkInterfacePasswordTypeEAPOL : {
5877			break;
5878		}
5879
5880		case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
5881			CFStringRef	interfaceType;
5882
5883			interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
5884			if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
5885				// if IPSec interface
5886				break;
5887			}
5888
5889			goto error;
5890		}
5891
5892		case kSCNetworkInterfacePasswordTypeVPN : {
5893			CFStringRef	interfaceType;
5894
5895			interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
5896			if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
5897				// if VPN interface
5898				break;
5899			}
5900
5901			goto error;
5902		}
5903
5904		default :
5905			break;
5906	}
5907
5908	return TRUE;
5909
5910    error :
5911
5912	_SCErrorSet(kSCStatusInvalidArgument);
5913	return FALSE;
5914}
5915
5916
5917Boolean
5918SCNetworkInterfaceCheckPassword(SCNetworkInterfaceRef		interface,
5919				SCNetworkInterfacePasswordType	passwordType)
5920{
5921	Boolean			exists		= FALSE;
5922	SCPreferencesRef        prefs		= NULL;
5923	CFStringRef		serviceID	= NULL;
5924
5925	if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
5926		return FALSE;
5927	}
5928
5929	switch (passwordType) {
5930		case kSCNetworkInterfacePasswordTypePPP : {
5931			CFDictionaryRef	config;
5932			CFStringRef	unique_id;
5933
5934			// get configuration
5935			config = SCNetworkInterfaceGetConfiguration(interface);
5936
5937			// get serviceID
5938			unique_id = getPasswordID(config, serviceID);
5939
5940			// check
5941			exists = __extract_password(prefs,
5942						    config,
5943						    kSCPropNetPPPAuthPassword,
5944						    kSCPropNetPPPAuthPasswordEncryption,
5945						    kSCValNetPPPAuthPasswordEncryptionKeychain,
5946						    unique_id,
5947						    NULL);
5948			break;
5949		}
5950
5951		case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
5952			CFDictionaryRef	config;
5953			Boolean		extended;
5954			CFStringRef	shared_id;
5955
5956			// get configuration
5957			extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
5958			if (extended) {
5959				config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
5960			} else {
5961				config = SCNetworkInterfaceGetConfiguration(interface);
5962			}
5963
5964			// get sharedSecret ID
5965			shared_id = copySharedSecretID(config, serviceID);
5966
5967			// check
5968			exists = __extract_password(prefs,
5969						    config,
5970						    kSCPropNetIPSecSharedSecret,
5971						    kSCPropNetIPSecSharedSecretEncryption,
5972						    kSCValNetIPSecSharedSecretEncryptionKeychain,
5973						    shared_id,
5974						    NULL);
5975			CFRelease(shared_id);
5976			break;
5977		}
5978
5979		case kSCNetworkInterfacePasswordTypeEAPOL : {
5980			CFDictionaryRef	config;
5981			CFStringRef	unique_id	= NULL;
5982
5983			// get configuration
5984			config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
5985
5986			// get 802.1X identifier
5987			if (config != NULL) {
5988				unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
5989			}
5990			if (!isA_CFString(unique_id)) {
5991				return FALSE;
5992			}
5993
5994			// check password
5995			exists = _SCPreferencesSystemKeychainPasswordItemExists(prefs, unique_id);
5996			break;
5997		}
5998
5999		case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
6000			CFDictionaryRef	config;
6001			CFStringRef	xauth_id;
6002
6003			// get configuration
6004			config = SCNetworkInterfaceGetConfiguration(interface);
6005
6006			// get XAuth ID
6007			xauth_id = copyXAuthID(config, serviceID);
6008
6009			// check
6010			exists = __extract_password(prefs,
6011						    config,
6012						    kSCPropNetIPSecXAuthPassword,
6013						    kSCPropNetIPSecXAuthPasswordEncryption,
6014						    kSCValNetIPSecXAuthPasswordEncryptionKeychain,
6015						    xauth_id,
6016						    NULL);
6017			CFRelease(xauth_id);
6018			break;
6019		}
6020
6021		case kSCNetworkInterfacePasswordTypeVPN : {
6022			CFDictionaryRef	config;
6023			CFStringRef	vpn_id;
6024
6025			// get configuration
6026			config = SCNetworkInterfaceGetConfiguration(interface);
6027
6028			// get serviceID
6029			vpn_id = getPasswordID(config, serviceID);
6030
6031			// check
6032			exists = __extract_password(prefs,
6033						    config,
6034						    kSCPropNetVPNAuthPassword,
6035						    kSCPropNetVPNAuthPasswordEncryption,
6036						    kSCValNetVPNAuthPasswordEncryptionKeychain,
6037						    vpn_id,
6038						    NULL);
6039			break;
6040		}
6041
6042		default :
6043			_SCErrorSet(kSCStatusInvalidArgument);
6044			return FALSE;
6045	}
6046
6047	return exists;
6048}
6049
6050
6051CFDataRef
6052SCNetworkInterfaceCopyPassword(SCNetworkInterfaceRef		interface,
6053			       SCNetworkInterfacePasswordType	passwordType)
6054{
6055	CFDataRef		password	= NULL;
6056	SCPreferencesRef        prefs		= NULL;
6057	CFStringRef		serviceID	= NULL;
6058
6059	if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
6060		return NULL;
6061	}
6062
6063	switch (passwordType) {
6064		case kSCNetworkInterfacePasswordTypePPP : {
6065			CFDictionaryRef	config;
6066			CFStringRef	unique_id;
6067
6068			// get configuration
6069			config = SCNetworkInterfaceGetConfiguration(interface);
6070
6071			// get serviceID
6072			unique_id = getPasswordID(config, serviceID);
6073
6074			// extract
6075			(void) __extract_password(prefs,
6076						  config,
6077						  kSCPropNetPPPAuthPassword,
6078						  kSCPropNetPPPAuthPasswordEncryption,
6079						  kSCValNetPPPAuthPasswordEncryptionKeychain,
6080						  unique_id,
6081						  &password);
6082			break;
6083		}
6084
6085		case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
6086			CFDictionaryRef	config;
6087			Boolean		extended;
6088			CFStringRef	shared_id;
6089
6090			// get configuration
6091			extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
6092			if (extended) {
6093				config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
6094			} else {
6095				config = SCNetworkInterfaceGetConfiguration(interface);
6096			}
6097
6098			// get sharedSecret ID
6099			shared_id = copySharedSecretID(config, serviceID);
6100
6101			// extract
6102			(void) __extract_password(prefs,
6103						  config,
6104						  kSCPropNetIPSecSharedSecret,
6105						  kSCPropNetIPSecSharedSecretEncryption,
6106						  kSCValNetIPSecSharedSecretEncryptionKeychain,
6107						  shared_id,
6108						  &password);
6109
6110			CFRelease(shared_id);
6111			break;
6112		}
6113
6114		case kSCNetworkInterfacePasswordTypeEAPOL : {
6115			CFDictionaryRef	config;
6116			CFStringRef	unique_id	= NULL;
6117
6118			// get configuration
6119			config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
6120
6121			// get 802.1X identifier
6122			if (config != NULL) {
6123				unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
6124			}
6125			if (!isA_CFString(unique_id)) {
6126				_SCErrorSet(kSCStatusFailed);
6127				return NULL;
6128			}
6129
6130			// copy password
6131			password = _SCPreferencesSystemKeychainPasswordItemCopy(prefs, unique_id);
6132			break;
6133		}
6134
6135		case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
6136			CFDictionaryRef	config;
6137			CFStringRef	xauth_id;
6138
6139			// get configuration
6140			config = SCNetworkInterfaceGetConfiguration(interface);
6141
6142			// get XAuth ID
6143			xauth_id = copyXAuthID(config, serviceID);
6144
6145			// extract
6146			(void) __extract_password(prefs,
6147						  config,
6148						  kSCPropNetIPSecXAuthPassword,
6149						  kSCPropNetIPSecXAuthPasswordEncryption,
6150						  kSCValNetIPSecXAuthPasswordEncryptionKeychain,
6151						  xauth_id,
6152						  &password);
6153			CFRelease(xauth_id);
6154			break;
6155		}
6156
6157		case kSCNetworkInterfacePasswordTypeVPN : {
6158			CFDictionaryRef	config;
6159			CFStringRef	vpn_id;
6160
6161			// get configuration
6162			config = SCNetworkInterfaceGetConfiguration(interface);
6163
6164			// get serviceID
6165			vpn_id = getPasswordID(config, serviceID);
6166
6167			// extract
6168			(void) __extract_password(prefs,
6169						  config,
6170						  kSCPropNetVPNAuthPassword,
6171						  kSCPropNetVPNAuthPasswordEncryption,
6172						  kSCValNetVPNAuthPasswordEncryptionKeychain,
6173						  vpn_id,
6174						  &password);
6175			break;
6176		}
6177
6178		default :
6179			_SCErrorSet(kSCStatusInvalidArgument);
6180			return NULL;
6181	}
6182
6183	return password;
6184}
6185
6186
6187Boolean
6188SCNetworkInterfaceRemovePassword(SCNetworkInterfaceRef		interface,
6189				 SCNetworkInterfacePasswordType	passwordType)
6190{
6191	Boolean			ok		= FALSE;
6192	SCPreferencesRef        prefs		= NULL;
6193	CFStringRef		serviceID	= NULL;
6194
6195	if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
6196		return FALSE;
6197	}
6198
6199	switch (passwordType) {
6200		case kSCNetworkInterfacePasswordTypePPP : {
6201			CFDictionaryRef	config;
6202			CFDictionaryRef	newConfig	= NULL;
6203			CFStringRef	unique_id;
6204
6205			// get configuration
6206			config = SCNetworkInterfaceGetConfiguration(interface);
6207
6208			// get serviceID
6209			unique_id = getPasswordID(config, serviceID);
6210
6211			// remove password
6212			ok = __remove_password(prefs,
6213					       config,
6214					       kSCPropNetPPPAuthPassword,
6215					       kSCPropNetPPPAuthPasswordEncryption,
6216					       kSCValNetPPPAuthPasswordEncryptionKeychain,
6217					       unique_id,
6218					       &newConfig);
6219			if (ok) {
6220				ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
6221				if (newConfig != NULL) CFRelease(newConfig);
6222			}
6223
6224			break;
6225		}
6226
6227		case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
6228			CFDictionaryRef	config;
6229			Boolean		extended;
6230			CFDictionaryRef	newConfig	= NULL;
6231			CFStringRef	shared_id;
6232
6233			// get configuration
6234			extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
6235			if (extended) {
6236				config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
6237			} else {
6238				config = SCNetworkInterfaceGetConfiguration(interface);
6239			}
6240
6241			// get sharedSecret ID
6242			shared_id = copySharedSecretID(config, serviceID);
6243
6244			// remove password
6245			ok = __remove_password(prefs,
6246					       config,
6247					       kSCPropNetIPSecSharedSecret,
6248					       kSCPropNetIPSecSharedSecretEncryption,
6249					       kSCValNetIPSecSharedSecretEncryptionKeychain,
6250					       shared_id,
6251					       &newConfig);
6252			if (ok) {
6253				if (extended) {
6254					ok = SCNetworkInterfaceSetExtendedConfiguration(interface,
6255											kSCEntNetIPSec,
6256											newConfig);
6257				} else {
6258					ok = SCNetworkInterfaceSetConfiguration(interface,
6259										newConfig);
6260				}
6261				if (newConfig != NULL) CFRelease(newConfig);
6262			}
6263
6264			CFRelease(shared_id);
6265			break;
6266		}
6267
6268		case kSCNetworkInterfacePasswordTypeEAPOL : {
6269			CFDictionaryRef	config;
6270			CFStringRef	unique_id	= NULL;
6271
6272			// get configuration
6273			config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
6274
6275			// get 802.1X identifier
6276			if (config != NULL) {
6277				unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
6278			}
6279			if (!isA_CFString(unique_id)) {
6280				_SCErrorSet(kSCStatusFailed);
6281				return FALSE;
6282			}
6283
6284			// remove password
6285			ok = _SCPreferencesSystemKeychainPasswordItemRemove(prefs, unique_id);
6286			break;
6287		}
6288
6289		case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
6290			CFDictionaryRef	config;
6291			CFDictionaryRef	newConfig	= NULL;
6292			CFStringRef	xauth_id;
6293
6294			// get configuration
6295			config = SCNetworkInterfaceGetConfiguration(interface);
6296
6297			// get XAuth ID
6298			xauth_id = copyXAuthID(config, serviceID);
6299
6300			// remove password
6301			ok = __remove_password(prefs,
6302					       config,
6303					       kSCPropNetIPSecXAuthPassword,
6304					       kSCPropNetIPSecXAuthPasswordEncryption,
6305					       kSCValNetIPSecXAuthPasswordEncryptionKeychain,
6306					       xauth_id,
6307					       &newConfig);
6308			if (ok) {
6309				ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
6310				if (newConfig != NULL) CFRelease(newConfig);
6311			}
6312
6313			CFRelease(xauth_id);
6314			break;
6315		}
6316
6317		case kSCNetworkInterfacePasswordTypeVPN : {
6318			CFDictionaryRef	config;
6319			CFDictionaryRef	newConfig	= NULL;
6320			CFStringRef	vpn_id;
6321
6322			// get configuration
6323			config = SCNetworkInterfaceGetConfiguration(interface);
6324
6325			// get serviceID
6326			vpn_id = getPasswordID(config, serviceID);
6327
6328			// remove password
6329			ok = __remove_password(prefs,
6330					       config,
6331					       kSCPropNetVPNAuthPassword,
6332					       kSCPropNetVPNAuthPasswordEncryption,
6333					       kSCValNetVPNAuthPasswordEncryptionKeychain,
6334					       vpn_id,
6335					       &newConfig);
6336			if (ok) {
6337				ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
6338				if (newConfig != NULL) CFRelease(newConfig);
6339			}
6340			break;
6341		}
6342
6343		default :
6344			_SCErrorSet(kSCStatusInvalidArgument);
6345			return FALSE;
6346	}
6347
6348	return ok;
6349}
6350
6351
6352Boolean
6353SCNetworkInterfaceSetPassword(SCNetworkInterfaceRef		interface,
6354			      SCNetworkInterfacePasswordType	passwordType,
6355			      CFDataRef				password,
6356			      CFDictionaryRef			options)
6357{
6358	CFStringRef		account		= NULL;
6359	CFDictionaryRef		config;
6360	CFStringRef		description	= NULL;
6361	CFStringRef		label		= NULL;
6362	Boolean			ok		= FALSE;
6363	SCPreferencesRef        prefs		= NULL;
6364	CFStringRef		serviceID	= NULL;
6365
6366	if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
6367		return FALSE;
6368	}
6369
6370	switch (passwordType) {
6371		case kSCNetworkInterfacePasswordTypePPP : {
6372			SCNetworkServiceRef	service	= NULL;
6373			CFStringRef		unique_id;
6374
6375			// get configuration
6376			config = SCNetworkInterfaceGetConfiguration(interface);
6377
6378			// get serviceID
6379			unique_id = getPasswordID(config, serviceID);
6380
6381			// get "Account", "Name", "Kind"
6382			if (config != NULL) {
6383				// auth name --> keychain "Account"
6384				account = CFDictionaryGetValue(config, kSCPropNetPPPAuthName);
6385
6386				// PPP [user defined] "name" --> keychain "Name"
6387				label = CFDictionaryGetValue(config, kSCPropUserDefinedName);
6388			}
6389
6390			if (label == NULL) {
6391				// service name --> keychain "Name"
6392				service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
6393											       prefs,
6394											       serviceID,
6395											       interface);
6396
6397				label = SCNetworkServiceGetName(service);
6398				if (label == NULL) {
6399					// interface name --> keychain "Name"
6400					label = SCNetworkInterfaceGetLocalizedDisplayName(interface);
6401				}
6402			}
6403
6404			if (bundle != NULL) {
6405				// "PPP Password" --> keychain "Kind"
6406				description = CFBundleCopyLocalizedString(bundle,
6407									  CFSTR("KEYCHAIN_KIND_PPP_PASSWORD"),
6408									  CFSTR("PPP Password"),
6409									  NULL);
6410			}
6411
6412			// store password
6413			ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
6414									 unique_id,
6415									 (label != NULL)       ? label       : CFSTR("Network Connection"),
6416									 (description != NULL) ? description : CFSTR("PPP Password"),
6417									 account,
6418									 password,
6419									 options);
6420			if (ok) {
6421				CFMutableDictionaryRef	newConfig;
6422
6423				if (config != NULL) {
6424					newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
6425				} else {
6426					newConfig = CFDictionaryCreateMutable(NULL,
6427									      0,
6428									      &kCFTypeDictionaryKeyCallBacks,
6429									      &kCFTypeDictionaryValueCallBacks);
6430				}
6431				CFDictionarySetValue(newConfig,
6432						     kSCPropNetPPPAuthPassword,
6433						     unique_id);
6434				CFDictionarySetValue(newConfig,
6435						     kSCPropNetPPPAuthPasswordEncryption,
6436						     kSCValNetPPPAuthPasswordEncryptionKeychain);
6437				ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
6438				CFRelease(newConfig);
6439			}
6440
6441			if (description != NULL) CFRelease(description);
6442			if (service     != NULL) CFRelease(service);
6443			break;
6444		}
6445
6446		case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
6447			CFDictionaryRef		baseConfig	= NULL;
6448			Boolean			extended;
6449			SCNetworkServiceRef	service		= NULL;
6450			CFStringRef		shared_id;
6451
6452			// get configuration
6453			extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
6454			config = SCNetworkInterfaceGetConfiguration(interface);
6455			if (extended) {
6456				baseConfig = config;
6457				config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
6458			}
6459
6460			// get sharedSecret ID
6461			shared_id = copySharedSecretID(config, serviceID);
6462
6463			// get "Account", "Name", "Kind"
6464			if (config != NULL) {
6465				CFStringRef	localIdentifier;
6466				CFStringRef	localIdentifierType;
6467
6468				if (CFDictionaryGetValueIfPresent(config,
6469								  kSCPropNetIPSecLocalIdentifierType,
6470								  (const void **)&localIdentifierType)
6471				    && CFEqual(localIdentifierType, kSCValNetIPSecLocalIdentifierTypeKeyID)
6472				    && CFDictionaryGetValueIfPresent(config,
6473								     kSCPropNetIPSecLocalIdentifier,
6474								     (const void **)&localIdentifier)
6475				    && isA_CFString(localIdentifier)) {
6476					// local identifier --> keychain "Account"
6477					account = localIdentifier;
6478				}
6479
6480				// PPP [user defined] "name" --> keychain "Name"
6481				if (!extended) {
6482					label = CFDictionaryGetValue(config, kSCPropUserDefinedName);
6483				} else {
6484					if (baseConfig != NULL) {
6485						label = CFDictionaryGetValue(baseConfig, kSCPropUserDefinedName);
6486					}
6487				}
6488			}
6489
6490			if (label == NULL) {
6491				// service name --> keychain "Name"
6492				service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
6493											       prefs,
6494											       serviceID,
6495											       interface);
6496
6497				label = SCNetworkServiceGetName(service);
6498				if (label == NULL) {
6499					// interface name --> keychain "Name"
6500					label = SCNetworkInterfaceGetLocalizedDisplayName(interface);
6501				}
6502			}
6503
6504			if (bundle != NULL) {
6505				// "IPSec Shared Secret" --> keychain "Kind"
6506				description = CFBundleCopyLocalizedString(bundle,
6507									  CFSTR("KEYCHAIN_KIND_IPSEC_SHARED_SECRET"),
6508									  CFSTR("IPSec Shared Secret"),
6509									  NULL);
6510			}
6511
6512			// set password
6513			ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
6514									 shared_id,
6515									 (label != NULL)       ? label       : CFSTR("Network Connection"),
6516									 (description != NULL) ? description : CFSTR("IPSec Shared Secret"),
6517									 account,
6518									 password,
6519									 options);
6520			if (ok) {
6521				CFMutableDictionaryRef	newConfig	= NULL;
6522
6523				if (config != NULL) {
6524					newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
6525				} else {
6526					newConfig = CFDictionaryCreateMutable(NULL,
6527									      0,
6528									      &kCFTypeDictionaryKeyCallBacks,
6529									      &kCFTypeDictionaryValueCallBacks);
6530				}
6531				CFDictionarySetValue(newConfig,
6532						     kSCPropNetIPSecSharedSecret,
6533						     shared_id);
6534				CFDictionarySetValue(newConfig,
6535						     kSCPropNetIPSecSharedSecretEncryption,
6536						     kSCValNetIPSecSharedSecretEncryptionKeychain);
6537				if (extended) {
6538					ok = SCNetworkInterfaceSetExtendedConfiguration(interface,
6539											kSCEntNetIPSec,
6540											newConfig);
6541				} else {
6542					ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
6543				}
6544				CFRelease(newConfig);
6545			}
6546
6547			if (description != NULL) CFRelease(description);
6548			if (service     != NULL) CFRelease(service);
6549			CFRelease(shared_id);
6550			break;
6551		}
6552
6553		case kSCNetworkInterfacePasswordTypeEAPOL : {
6554			CFStringRef	account		= NULL;
6555			CFStringRef	unique_id	= NULL;
6556
6557			// get configuration
6558			config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
6559
6560			// get 802.1X identifier
6561			if (config != NULL) {
6562				unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
6563				unique_id = isA_CFString(unique_id);
6564			}
6565			if (unique_id != NULL) {
6566				CFRetain(unique_id);
6567			} else {
6568				CFUUIDRef	uuid;
6569
6570				uuid      = CFUUIDCreate(NULL);
6571				unique_id = CFUUIDCreateString(NULL, uuid);
6572				CFRelease(uuid);
6573			}
6574
6575			// 802.1x UserName --> keychain "Account"
6576			if (config != NULL) {
6577				account = CFDictionaryGetValue(config, kEAPClientPropUserName);
6578			}
6579
6580			// get "Name", "Kind"
6581			if (bundle != NULL) {
6582				CFStringRef	interface_name;
6583
6584				// "Network Connection (%@)" --> keychain "Name"
6585				interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
6586				if (interface_name != NULL) {
6587					CFStringRef	label_fmt;
6588
6589					label_fmt = CFBundleCopyLocalizedString(bundle,
6590										CFSTR("KEYCHAIN_DESCRIPTION_EAPOL_INTERFACE"),
6591										CFSTR("Network Connection (%@)"),
6592										NULL);
6593					label = CFStringCreateWithFormat(NULL, NULL, label_fmt, interface_name);
6594					CFRelease(label_fmt);
6595				} else {
6596					label = CFBundleCopyLocalizedString(bundle,
6597									    CFSTR("KEYCHAIN_DESCRIPTION_EAPOL"),
6598									    CFSTR("Network Connection"),
6599									    NULL);
6600				}
6601
6602				// "802.1X Password" --> keychain "Kind"
6603				description = CFBundleCopyLocalizedString(bundle,
6604									  CFSTR("KEYCHAIN_KIND_EAPOL"),
6605									  CFSTR("802.1X Password"),
6606									  NULL);
6607			}
6608
6609			// set password
6610			ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
6611									 unique_id,
6612									 (label != NULL)       ? label       : CFSTR("Network Connection"),
6613									 (description != NULL) ? description : CFSTR("802.1X Password"),
6614									 account,
6615									 password,
6616									 options);
6617			if (ok) {
6618				CFMutableDictionaryRef	newConfig	= NULL;
6619
6620				if (config != NULL) {
6621					newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
6622				} else {
6623					newConfig = CFDictionaryCreateMutable(NULL,
6624									      0,
6625									      &kCFTypeDictionaryKeyCallBacks,
6626									      &kCFTypeDictionaryValueCallBacks);
6627				}
6628				CFDictionarySetValue(newConfig,
6629						     kEAPClientPropUserPasswordKeychainItemID,
6630						     unique_id);
6631				ok = SCNetworkInterfaceSetExtendedConfiguration(interface,
6632										kSCEntNetEAPOL,
6633										newConfig);
6634				CFRelease(newConfig);
6635			}
6636
6637			CFRelease(unique_id);
6638			if (label       != NULL) CFRelease(label);
6639			if (description != NULL) CFRelease(description);
6640			break;
6641		}
6642
6643		case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
6644			SCNetworkServiceRef	service	= NULL;
6645			CFStringRef		xauth_id;
6646
6647			// get configuration
6648			config = SCNetworkInterfaceGetConfiguration(interface);
6649
6650			// get XAuth ID
6651			xauth_id = copyXAuthID(config, serviceID);
6652
6653			// get "Account", "Name", "Kind"
6654			if (config != NULL) {
6655				// auth name --> keychain "Account"
6656				account = CFDictionaryGetValue(config, kSCPropNetIPSecXAuthName);
6657
6658				// IPSec [user defined] "name" --> keychain "Name"
6659				label = CFDictionaryGetValue(config, kSCPropUserDefinedName);
6660			}
6661
6662			if (label == NULL) {
6663				// service name --> keychain "Name"
6664				service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
6665											       prefs,
6666											       serviceID,
6667											       interface);
6668
6669				label = SCNetworkServiceGetName(service);
6670				if (label == NULL) {
6671					// interface name --> keychain "Name"
6672					label = SCNetworkInterfaceGetLocalizedDisplayName(interface);
6673				}
6674			}
6675
6676			if (bundle != NULL) {
6677				// "IPSec XAuth Password" --> keychain "Kind"
6678				description = CFBundleCopyLocalizedString(bundle,
6679									  CFSTR("KEYCHAIN_KIND_IPSEC_XAUTH_PASSWORD"),
6680									  CFSTR("IPSec XAuth Password"),
6681									  NULL);
6682			}
6683
6684			// store password
6685			ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
6686									 xauth_id,
6687									 (label != NULL)       ? label       : CFSTR("Network Connection"),
6688									 (description != NULL) ? description : CFSTR("IPSec XAuth Password"),
6689									 account,
6690									 password,
6691									 options);
6692			if (ok) {
6693				CFMutableDictionaryRef	newConfig;
6694
6695				if (config != NULL) {
6696					newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
6697				} else {
6698					newConfig = CFDictionaryCreateMutable(NULL,
6699									      0,
6700									      &kCFTypeDictionaryKeyCallBacks,
6701									      &kCFTypeDictionaryValueCallBacks);
6702				}
6703				CFDictionarySetValue(newConfig,
6704						     kSCPropNetIPSecXAuthPassword,
6705						     xauth_id);
6706				CFDictionarySetValue(newConfig,
6707						     kSCPropNetIPSecXAuthPasswordEncryption,
6708						     kSCValNetIPSecXAuthPasswordEncryptionKeychain);
6709				ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
6710				CFRelease(newConfig);
6711			}
6712
6713			CFRelease(xauth_id);
6714			if (description != NULL) CFRelease(description);
6715			if (service     != NULL) CFRelease(service);
6716			break;
6717		}
6718
6719		case kSCNetworkInterfacePasswordTypeVPN : {
6720			SCNetworkServiceRef	service	= NULL;
6721			CFStringRef		vpn_id;
6722
6723			// get configuration
6724			config = SCNetworkInterfaceGetConfiguration(interface);
6725
6726			// get serviceID
6727			vpn_id = getPasswordID(config, serviceID);
6728
6729			// get "Account", "Name", "Kind"
6730			if (config != NULL) {
6731				// auth name --> keychain "Account"
6732				account = CFDictionaryGetValue(config, kSCPropNetVPNAuthName);
6733
6734				// VPN [user defined] "name" --> keychain "Name"
6735				label = CFDictionaryGetValue(config, kSCPropUserDefinedName);
6736			}
6737
6738			if (label == NULL) {
6739				// service name --> keychain "Name"
6740				service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
6741											       prefs,
6742											       serviceID,
6743											       interface);
6744
6745				label = SCNetworkServiceGetName(service);
6746				if (label == NULL) {
6747					// interface name --> keychain "Name"
6748					label = SCNetworkInterfaceGetLocalizedDisplayName(interface);
6749				}
6750			}
6751
6752			if (bundle != NULL) {
6753				// "VPN Password" --> keychain "Kind"
6754				description = CFBundleCopyLocalizedString(bundle,
6755									  CFSTR("KEYCHAIN_KIND_VPN_PASSWORD"),
6756									  CFSTR("VPN Password"),
6757									  NULL);
6758			}
6759
6760			// store password
6761			ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
6762									 vpn_id,
6763									 (label != NULL)       ? label       : CFSTR("Network Connection"),
6764									 (description != NULL) ? description : CFSTR("VPN Password"),
6765									 account,
6766									 password,
6767									 options);
6768			if (ok) {
6769				CFMutableDictionaryRef	newConfig;
6770
6771				if (config != NULL) {
6772					newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
6773				} else {
6774					newConfig = CFDictionaryCreateMutable(NULL,
6775									      0,
6776									      &kCFTypeDictionaryKeyCallBacks,
6777									      &kCFTypeDictionaryValueCallBacks);
6778				}
6779				CFDictionarySetValue(newConfig,
6780						     kSCPropNetVPNAuthPassword,
6781						     vpn_id);
6782				CFDictionarySetValue(newConfig,
6783						     kSCPropNetVPNAuthPasswordEncryption,
6784						     kSCValNetVPNAuthPasswordEncryptionKeychain);
6785				ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
6786				CFRelease(newConfig);
6787			}
6788
6789			if (description != NULL) CFRelease(description);
6790			if (service     != NULL) CFRelease(service);
6791			break;
6792		}
6793
6794		default :
6795			_SCErrorSet(kSCStatusInvalidArgument);
6796			break;
6797	}
6798
6799	return ok;
6800}
6801
6802
6803#pragma mark -
6804#pragma mark SCNetworkInterface [InterfaceNamer] SPIs
6805
6806
6807CFDictionaryRef
6808_SCNetworkInterfaceCopyInterfaceInfo(SCNetworkInterfaceRef interface)
6809{
6810	CFMutableDictionaryRef		info;
6811	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
6812	CFStringRef			name;
6813
6814	if (interface == NULL) {
6815		return NULL;
6816	}
6817
6818	info = CFDictionaryCreateMutable(NULL,
6819					 0,
6820					 &kCFTypeDictionaryKeyCallBacks,
6821					 &kCFTypeDictionaryValueCallBacks);
6822
6823	// add non-localized interface name
6824	name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
6825	if (name != NULL) {
6826		CFDictionaryAddValue(info, kSCPropUserDefinedName, name);
6827	}
6828
6829	// add USB info
6830	if ((interfacePrivate->usb.vid != NULL) || (interfacePrivate->usb.pid != NULL)) {
6831#if	!TARGET_IPHONE_SIMULATOR
6832		if (interfacePrivate->usb.name != NULL) {
6833			CFDictionaryAddValue(info, CFSTR(kUSBProductString), interfacePrivate->usb.name);
6834		}
6835		if (interfacePrivate->usb.vid != NULL) {
6836			CFDictionaryAddValue(info, CFSTR(kUSBVendorID), interfacePrivate->usb.vid);
6837		}
6838		if (interfacePrivate->usb.pid != NULL) {
6839			CFDictionaryAddValue(info, CFSTR(kUSBProductID), interfacePrivate->usb.pid);
6840		}
6841#endif	// !TARGET_IPHONE_SIMULATOR
6842	}
6843
6844	if (CFDictionaryGetCount(info) == 0) {
6845		// do not return an empty dictionary
6846		CFRelease(info);
6847		info = NULL;
6848	}
6849
6850	return info;
6851}
6852
6853
6854SCNetworkInterfaceRef
6855_SCNetworkInterfaceCreateWithIONetworkInterfaceObject(io_object_t if_obj)
6856{
6857	SCNetworkInterfaceRef	interface	= NULL;
6858
6859	/* initialize runtime */
6860	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
6861
6862	if (IOObjectConformsTo(if_obj, kIONetworkInterfaceClass)) {
6863		interface = createInterface(if_obj, processNetworkInterface, NULL);
6864	} else if (IOObjectConformsTo(if_obj, kIOSerialBSDServiceValue)) {
6865		interface = createInterface(if_obj, processSerialInterface, kSCNetworkInterfaceHiddenPortKey);
6866	}
6867
6868	return interface;
6869}
6870
6871
6872CFStringRef
6873_SCNetworkInterfaceGetConfigurationAction(SCNetworkInterfaceRef interface)
6874{
6875	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
6876
6877	return interfacePrivate->configurationAction;
6878}
6879
6880
6881CFDataRef
6882_SCNetworkInterfaceGetHardwareAddress(SCNetworkInterfaceRef interface)
6883{
6884	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
6885
6886	return interfacePrivate->address;
6887}
6888
6889
6890CFStringRef
6891_SCNetworkInterfaceGetIOInterfaceNamePrefix(SCNetworkInterfaceRef interface)
6892{
6893	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
6894
6895	return interfacePrivate->prefix;
6896}
6897
6898
6899CFNumberRef
6900_SCNetworkInterfaceGetIOInterfaceType(SCNetworkInterfaceRef interface)
6901{
6902	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
6903
6904	return interfacePrivate->type;
6905}
6906
6907
6908CFNumberRef
6909_SCNetworkInterfaceGetIOInterfaceUnit(SCNetworkInterfaceRef interface)
6910{
6911	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
6912
6913	return interfacePrivate->unit;
6914}
6915
6916
6917CFStringRef
6918_SCNetworkInterfaceGetIOPath(SCNetworkInterfaceRef interface)
6919{
6920	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
6921
6922	return interfacePrivate->path;
6923}
6924
6925
6926uint64_t
6927_SCNetworkInterfaceGetIORegistryEntryID(SCNetworkInterfaceRef interface)
6928{
6929	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
6930
6931	return interfacePrivate->entryID;
6932}
6933
6934
6935__private_extern__
6936Boolean
6937__SCNetworkInterfaceIsActive (SCNetworkInterfaceRef interface)
6938{
6939	SCNetworkInterfacePrivateRef	interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
6940
6941	return interfacePrivate->active;
6942}
6943
6944
6945Boolean
6946_SCNetworkInterfaceIsBuiltin(SCNetworkInterfaceRef interface)
6947{
6948	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
6949
6950	return interfacePrivate->builtin;
6951}
6952
6953
6954#pragma mark -
6955#pragma mark SCNetworkInterface SPIs
6956
6957
6958#if	!TARGET_OS_EMBEDDED
6959
6960SCNetworkInterfaceRef
6961_SCNetworkInterfaceCopyBTPANInterface(void)
6962{
6963	CFDictionaryRef		dict;
6964	SCNetworkInterfaceRef	interface	= NULL;
6965	CFStringRef		key;
6966
6967	key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" "InterfaceNamer"), kSCDynamicStoreDomainPlugin);
6968	dict = SCDynamicStoreCopyValue(NULL, key);
6969	CFRelease(key);
6970	if (dict != NULL) {
6971		CFDataRef			addr;
6972		CFStringRef			if_name;
6973		SCNetworkInterfacePrivateRef	interfacePrivate;
6974
6975		if (isA_CFDictionary(dict) &&
6976		    CFDictionaryGetValueIfPresent(dict,
6977						  CFSTR("_" BT_PAN_NAME "_"),
6978						  (const void **)&if_name) &&
6979		    isA_CFString(if_name)) {
6980			CFMutableDictionaryRef	entity;
6981
6982			entity = CFDictionaryCreateMutable(NULL,
6983							   0,
6984							   &kCFTypeDictionaryKeyCallBacks,
6985							   &kCFTypeDictionaryValueCallBacks);
6986			CFDictionarySetValue(entity,
6987					     kSCPropNetInterfaceType,
6988					     kSCValNetInterfaceTypeEthernet);
6989			CFDictionarySetValue(entity,
6990					     kSCPropNetInterfaceDeviceName,
6991					     if_name);
6992			CFDictionarySetValue(entity,
6993					     kSCPropUserDefinedName,
6994					     CFSTR(BT_PAN_NAME));
6995			interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, NULL);
6996			CFRelease(entity);
6997		}
6998
6999		interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
7000
7001		if ((interfacePrivate != NULL) &&
7002		    (interfacePrivate->address == NULL) &&
7003		    CFDictionaryGetValueIfPresent(dict,
7004						  CFSTR("_" BT_PAN_MAC "_"),
7005						  (const void **)&addr) &&
7006		    isA_CFData(addr)) {
7007			interfacePrivate->address = CFRetain(addr);
7008		}
7009
7010		CFRelease(dict);
7011	}
7012
7013	return interface;
7014}
7015#endif	// !TARGET_OS_EMBEDDED
7016
7017
7018CFStringRef
7019_SCNetworkInterfaceCopySlashDevPath(SCNetworkInterfaceRef interface)
7020{
7021	io_registry_entry_t		device;
7022	io_iterator_t			device_iterator		= MACH_PORT_NULL;
7023	CFStringRef			device_path		= NULL;
7024	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
7025	kern_return_t			kr;
7026	CFStringRef			match_keys[2];
7027	CFTypeRef			match_vals[2];
7028	CFDictionaryRef			match_dict;
7029	CFDictionaryRef			matching;
7030
7031	if (interfacePrivate->entity_device == NULL) {
7032		return NULL;
7033	}
7034
7035	if (interfacePrivate->entity_device_unique == NULL) {
7036		goto done;
7037	}
7038
7039	match_keys[0] = CFSTR(kIOTTYBaseNameKey);
7040	match_vals[0] = interfacePrivate->entity_device;
7041	match_dict = CFDictionaryCreate(NULL,
7042					(const void **)match_keys,
7043					(const void **)match_vals,
7044					1,
7045					&kCFTypeDictionaryKeyCallBacks,
7046					&kCFTypeDictionaryValueCallBacks);
7047
7048	match_keys[0] = CFSTR(kIOProviderClassKey);
7049	match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
7050	match_keys[1] = CFSTR(kIOPropertyMatchKey);
7051	match_vals[1] = match_dict;
7052	matching = CFDictionaryCreate(NULL,
7053				      (const void **)match_keys,
7054				      (const void **)match_vals,
7055				      sizeof(match_keys)/sizeof(match_keys[0]),
7056				      &kCFTypeDictionaryKeyCallBacks,
7057				      &kCFTypeDictionaryValueCallBacks);
7058	CFRelease(match_dict);
7059
7060	// note: this "matching" dictionary will be consumed by the call to IOServiceGetMatchingServices
7061	kr = IOServiceGetMatchingServices(masterPort, matching, &device_iterator);
7062	if (kr != kIOReturnSuccess) {
7063		SCLog(TRUE, LOG_DEBUG, CFSTR("IOServiceGetMatchingServices() failed, kr = 0x%x"), kr);
7064		goto done;
7065	}
7066
7067	while ((device_path == NULL) &&
7068	       ((device = IOIteratorNext(device_iterator)) != MACH_PORT_NULL)) {
7069		CFDictionaryRef	overrides;
7070
7071		overrides = IORegistryEntrySearchCFProperty(device,
7072							    kIOServicePlane,
7073							    kSCNetworkInterfaceNetworkConfigurationOverridesKey,
7074							    NULL,
7075							    kIORegistryIterateRecursively | kIORegistryIterateParents);
7076		if (overrides != NULL) {
7077			CFDictionaryRef	modemOverrides;
7078
7079			modemOverrides = CFDictionaryGetValue(overrides, kSCEntNetModem);
7080			if (modemOverrides != NULL) {
7081				CFRetain(modemOverrides);
7082			}
7083			CFRelease(overrides);
7084			overrides = modemOverrides;
7085		}
7086		if (overrides == NULL) {
7087			overrides = IORegistryEntrySearchCFProperty(device,
7088								    kIOServicePlane,
7089								    CFSTR("DeviceModemOverrides"),
7090								    NULL,
7091								    kIORegistryIterateRecursively | kIORegistryIterateParents);
7092		}
7093		if (overrides != NULL) {
7094			if (isA_CFDictionary(overrides)) {
7095				CFStringRef	matchIdentifier;
7096
7097				matchIdentifier = CFDictionaryGetValue(overrides, CFSTR("UniqueIdentifier"));
7098				if (isA_CFString(matchIdentifier) &&
7099				    CFEqual(interfacePrivate->entity_device_unique, matchIdentifier)) {
7100					device_path = IORegistryEntryCreateCFProperty(device,
7101										      CFSTR(kIOTTYDeviceKey),
7102										      NULL,
7103										      0);
7104				}
7105			}
7106			CFRelease(overrides);
7107		}
7108		IOObjectRelease(device);
7109	}
7110
7111	IOObjectRelease(device_iterator);
7112
7113    done :
7114
7115	if (device_path == NULL) {
7116		// if we haven't found an exact match to our UniqueIdentifier
7117		// so we simply return the base name.
7118		device_path = SCNetworkInterfaceGetBSDName(interface);
7119		if (device_path != NULL) {
7120			CFRetain(device_path);
7121		}
7122	}
7123
7124	return device_path;
7125}
7126
7127
7128Boolean
7129_SCNetworkInterfaceIsBluetoothPAN(SCNetworkInterfaceRef interface)
7130{
7131	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
7132
7133	return (interfacePrivate->sort_order == kSortBluetoothPAN_GN);
7134}
7135
7136
7137Boolean
7138_SCNetworkInterfaceIsBluetoothPAN_NAP(SCNetworkInterfaceRef interface)
7139{
7140	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
7141
7142	return (interfacePrivate->sort_order == kSortBluetoothPAN_NAP);
7143}
7144
7145
7146Boolean
7147_SCNetworkInterfaceIsBluetoothP2P(SCNetworkInterfaceRef interface)
7148{
7149	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
7150
7151	return (interfacePrivate->sort_order == kSortBluetoothPAN_U);
7152}
7153
7154
7155Boolean
7156_SCNetworkInterfaceIsHiddenConfiguration(SCNetworkInterfaceRef interface)
7157{
7158	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
7159
7160	return interfacePrivate->hidden;
7161}
7162
7163
7164Boolean
7165_SCNetworkInterfaceIsModemV92(SCNetworkInterfaceRef interface)
7166{
7167	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
7168
7169	return interfacePrivate->modemIsV92;
7170}
7171
7172
7173Boolean
7174_SCNetworkInterfaceIsTethered(SCNetworkInterfaceRef interface)
7175{
7176	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
7177
7178	return (interfacePrivate->sort_order == kSortTethered);
7179}
7180
7181
7182Boolean
7183_SCNetworkInterfaceIsThunderbolt(SCNetworkInterfaceRef interface)
7184{
7185	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
7186	CFStringRef			interfaceType;
7187
7188	if (!isA_SCNetworkInterface(interface)) {
7189		return FALSE;
7190	}
7191
7192	interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
7193	if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) {
7194		CFIndex		i;
7195		CFArrayRef	members;
7196		CFIndex		n;
7197
7198		members = SCBridgeInterfaceGetMemberInterfaces(interface);
7199		n = (members != NULL) ? CFArrayGetCount(members) : 0;
7200		if (n == 0) {
7201			// if an empty bridge
7202			return FALSE;
7203		}
7204
7205		for (i = 0; i < n; i++) {
7206			SCNetworkInterfaceRef		member;
7207			SCNetworkInterfacePrivateRef	memberPrivate;
7208
7209			member = CFArrayGetValueAtIndex(members, i);
7210			memberPrivate = (SCNetworkInterfacePrivateRef)member;
7211			if (memberPrivate->sort_order != kSortThunderbolt) {
7212				return FALSE;
7213			}
7214		}
7215
7216		// if Ethernet Bridge interface with only Thunderbolt [IP] members
7217		return TRUE;
7218	}
7219
7220	return (interfacePrivate->sort_order == kSortThunderbolt);
7221}
7222
7223
7224#pragma mark -
7225#pragma mark SCNetworkInterface [internal] SPIs
7226
7227
7228__private_extern__
7229SCNetworkInterfacePrivateRef
7230__SCNetworkInterfaceCreateCopy(CFAllocatorRef		allocator,
7231			       SCNetworkInterfaceRef	interface,
7232			       SCPreferencesRef		prefs,
7233			       CFStringRef		serviceID)
7234{
7235	SCNetworkInterfacePrivateRef		oldPrivate	= (SCNetworkInterfacePrivateRef)interface;
7236	SCNetworkInterfacePrivateRef		newPrivate;
7237
7238	/* initialize runtime (and kSCNetworkInterfaceIPv4) */
7239	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
7240
7241	if (interface == kSCNetworkInterfaceIPv4) {
7242		return (SCNetworkInterfacePrivateRef)CFRetain(interface);
7243	}
7244
7245	newPrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, prefs, serviceID);
7246	newPrivate->interface_type		= oldPrivate->interface_type;
7247	if (oldPrivate->interface != NULL) {
7248		newPrivate->interface		= (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL,			// allocator
7249													oldPrivate->interface,	// interface
7250													prefs,			// [new] prefs
7251													serviceID);		// [new] serviceID
7252	}
7253	if (oldPrivate->name != NULL) {
7254		newPrivate->name		= CFRetain(oldPrivate->name);
7255	}
7256	if (oldPrivate->prefix != NULL) {
7257		newPrivate->prefix		= CFRetain(oldPrivate->prefix);
7258	}
7259	if (oldPrivate->localized_name != NULL) {
7260		newPrivate->localized_name	= CFRetain(oldPrivate->localized_name);
7261	}
7262	newPrivate->localized_key		= oldPrivate->localized_key;
7263	if (oldPrivate->localized_arg1 != NULL) {
7264		newPrivate->localized_arg1	= CFRetain(oldPrivate->localized_arg1);
7265	}
7266	if (oldPrivate->localized_arg2 != NULL) {
7267		newPrivate->localized_arg2	= CFRetain(oldPrivate->localized_arg2);
7268	}
7269	if (oldPrivate->unsaved != NULL) {
7270		newPrivate->unsaved		= CFDictionaryCreateMutableCopy(NULL, 0, oldPrivate->unsaved);
7271	}
7272	if (oldPrivate->entity_device != NULL) {
7273		newPrivate->entity_device	= CFRetain(oldPrivate->entity_device);
7274	}
7275	if (oldPrivate->entity_device_unique != NULL) {
7276		newPrivate->entity_device_unique = CFRetain(oldPrivate->entity_device_unique);
7277	}
7278	newPrivate->entity_type			= oldPrivate->entity_type;
7279	newPrivate->entity_subtype		= oldPrivate->entity_subtype;
7280	if (oldPrivate->supported_interface_types != NULL) {
7281		newPrivate->supported_interface_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_interface_types);
7282	}
7283	if (oldPrivate->supported_protocol_types != NULL) {
7284		newPrivate->supported_protocol_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_protocol_types);
7285	}
7286	if (oldPrivate->address != NULL) {
7287		newPrivate->address		= CFRetain(oldPrivate->address);
7288	}
7289	newPrivate->builtin			= oldPrivate->builtin;
7290	if (oldPrivate->configurationAction != NULL) {
7291		newPrivate->configurationAction	= CFRetain(oldPrivate->configurationAction);
7292	}
7293	newPrivate->hidden			= oldPrivate->hidden;
7294	if (oldPrivate->location != NULL) {
7295		newPrivate->location		= CFRetain(oldPrivate->location);
7296	}
7297	if (oldPrivate->path != NULL) {
7298		newPrivate->path		= CFRetain(oldPrivate->path);
7299	}
7300	newPrivate->entryID			= oldPrivate->entryID;
7301	if (oldPrivate->overrides != NULL) {
7302		newPrivate->overrides		= CFDictionaryCreateMutableCopy(NULL, 0, oldPrivate->overrides);
7303	}
7304	newPrivate->modemIsV92			= oldPrivate->modemIsV92;
7305	if (oldPrivate->type != NULL) {
7306		newPrivate->type		= CFRetain(oldPrivate->type);
7307	}
7308	if (oldPrivate->unit != NULL) {
7309		newPrivate->unit		= CFRetain(oldPrivate->unit);
7310	}
7311	if (oldPrivate->usb.name != NULL) {
7312		newPrivate->usb.name		= CFRetain(oldPrivate->usb.name);
7313	}
7314	if (oldPrivate->usb.vid != NULL) {
7315		newPrivate->usb.vid		= CFRetain(oldPrivate->usb.vid);
7316	}
7317	if (oldPrivate->usb.pid != NULL) {
7318		newPrivate->usb.pid		= CFRetain(oldPrivate->usb.pid);
7319	}
7320	newPrivate->sort_order			= oldPrivate->sort_order;
7321
7322	newPrivate->supportsBond		= oldPrivate->supportsBond;
7323	if (oldPrivate->bond.interfaces != NULL) {
7324		newPrivate->bond.interfaces	= CFRetain(oldPrivate->bond.interfaces);
7325	}
7326	if (oldPrivate->bond.mode != NULL) {
7327		newPrivate->bond.mode		= CFRetain(oldPrivate->bond.mode);
7328	}
7329	if (oldPrivate->bond.options != NULL) {
7330		newPrivate->bond.options	= CFRetain(oldPrivate->bond.options);
7331	}
7332
7333	newPrivate->supportsBridge		= oldPrivate->supportsBridge;
7334	if (oldPrivate->bridge.interfaces != NULL) {
7335		newPrivate->bridge.interfaces	= CFRetain(oldPrivate->bridge.interfaces);
7336	}
7337	if (oldPrivate->bridge.options != NULL) {
7338		newPrivate->bridge.options	= CFRetain(oldPrivate->bridge.options);
7339	}
7340
7341	newPrivate->supportsVLAN		= oldPrivate->supportsVLAN;
7342	if (oldPrivate->vlan.interface != NULL) {
7343		newPrivate->vlan.interface	= CFRetain(oldPrivate->vlan.interface);
7344	}
7345	if (oldPrivate->vlan.tag != NULL) {
7346		newPrivate->vlan.tag		= CFRetain(oldPrivate->vlan.tag);
7347	}
7348	if (oldPrivate->vlan.options != NULL) {
7349		newPrivate->vlan.options	= CFRetain(oldPrivate->vlan.options);
7350	}
7351
7352	return newPrivate;
7353}
7354
7355
7356__private_extern__
7357CFArrayRef
7358__SCNetworkInterfaceCopyDeepConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
7359{
7360	CFMutableArrayRef       configs;
7361
7362	configs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7363
7364	while (interface != NULL) {
7365		CFStringRef		defaultType;
7366		CFMutableDictionaryRef	interfaceConfiguration;
7367
7368		interfaceConfiguration = CFDictionaryCreateMutable(NULL,
7369								   0,
7370								   &kCFTypeDictionaryKeyCallBacks,
7371								   &kCFTypeDictionaryValueCallBacks);
7372
7373		defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
7374		if (defaultType != NULL) {
7375			CFDictionaryRef	config;
7376			CFArrayRef	extendedTypes;
7377
7378			if (set == NULL) {
7379				config = __SCNetworkInterfaceGetConfiguration(interface, defaultType);
7380			} else {
7381				config = __SCNetworkInterfaceGetDefaultConfiguration(set, interface);
7382			}
7383			if (config == NULL) {
7384				config = (CFDictionaryRef)kCFNull;
7385			}
7386			CFDictionarySetValue(interfaceConfiguration, defaultType, config);
7387
7388			extendedTypes = extendedConfigurationTypes(interface);
7389			if (extendedTypes != NULL) {
7390				CFIndex	i;
7391				CFIndex	n;
7392
7393				n = CFArrayGetCount(extendedTypes);
7394				for (i = 0; i < n; i++) {
7395					CFStringRef	extendedType;
7396
7397					extendedType = CFArrayGetValueAtIndex(extendedTypes, i);
7398					config = __SCNetworkInterfaceGetConfiguration(interface, extendedType);
7399					if (config == NULL) {
7400						config = (CFDictionaryRef)kCFNull;
7401					}
7402					CFDictionarySetValue(interfaceConfiguration, extendedType, config);
7403				}
7404
7405				CFRelease(extendedTypes);
7406			}
7407		}
7408
7409		CFArrayAppendValue(configs, interfaceConfiguration);
7410		CFRelease(interfaceConfiguration);
7411
7412		interface = SCNetworkInterfaceGetInterface(interface);
7413	}
7414
7415	return configs;
7416}
7417
7418
7419__private_extern__ Boolean
7420__SCNetworkInterfaceIsMember(SCPreferencesRef prefs, SCNetworkInterfaceRef interface)
7421{
7422	CFArrayRef	interfaces;
7423	Boolean		match		= FALSE;
7424	CFMutableSetRef	members;
7425
7426	members = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
7427
7428#if	!TARGET_OS_IPHONE
7429	// add Bond [member] interfaces
7430	interfaces = SCBondInterfaceCopyAll(prefs);
7431	if (interfaces != NULL) {
7432		__SCBondInterfaceListCollectMembers(interfaces, members);
7433		CFRelease(interfaces);
7434	}
7435#endif	// !TARGET_OS_IPHONE
7436
7437	// add Bridge [member] interfaces
7438	interfaces = SCBridgeInterfaceCopyAll(prefs);
7439	if (interfaces != NULL) {
7440		__SCBridgeInterfaceListCollectMembers(interfaces, members);
7441		CFRelease(interfaces);
7442	}
7443
7444	if (CFSetGetCount(members) == 0) {
7445		goto done;
7446	}
7447
7448	while (interface != NULL) {
7449		match = CFSetContainsValue(members, interface);
7450		if (match) {
7451			// if the interface is a member of an
7452			// Ethernet Bond or Bridge
7453			break;
7454		}
7455
7456		interface = SCNetworkInterfaceGetInterface(interface);
7457	}
7458
7459    done :
7460
7461	CFRelease(members);
7462	return match;
7463}
7464
7465
7466__private_extern__
7467void
7468__SCNetworkInterfaceSetDeepConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface, CFArrayRef configs)
7469{
7470	CFIndex	i;
7471
7472	for (i = 0; interface != NULL; i++) {
7473		CFStringRef	defaultType;
7474		CFDictionaryRef interfaceConfiguration;
7475
7476		interfaceConfiguration = (configs != NULL) ? CFArrayGetValueAtIndex(configs, i) : NULL;
7477
7478		defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
7479		if (defaultType != NULL) {
7480			CFDictionaryRef	config;
7481			CFArrayRef	extendedTypes;
7482
7483			config = (interfaceConfiguration != NULL) ? CFDictionaryGetValue(interfaceConfiguration, defaultType)
7484								  : NULL;
7485			if (config == (CFDictionaryRef)kCFNull) {
7486				config = NULL;
7487			}
7488			if (set == NULL) {
7489				// if service is not associated with the set
7490				if (!__SCNetworkInterfaceSetConfiguration(interface, defaultType, config, TRUE)) {
7491					SCLog(TRUE, LOG_DEBUG,
7492						  CFSTR("__SCNetworkInterfaceSetDeepConfiguration __SCNetworkInterfaceSetConfiguration() failed, interface=%@, type=%@"),
7493						  interface,
7494						  defaultType);
7495				}
7496			} else {
7497				// apply default configuration to this set
7498				if (!__SCNetworkInterfaceSetDefaultConfiguration(set, interface, defaultType, config, TRUE)) {
7499					SCLog(TRUE, LOG_DEBUG,
7500						  CFSTR("__SCNetworkInterfaceSetDeepConfiguration __SCNetworkInterfaceSetDefaultConfiguration() failed, interface=%@, type=%@"),
7501						  interface,
7502						  defaultType);
7503				}
7504			}
7505
7506			extendedTypes = extendedConfigurationTypes(interface);
7507			if (extendedTypes != NULL) {
7508				CFIndex	j;
7509				CFIndex	n;
7510
7511				n = CFArrayGetCount(extendedTypes);
7512				for (j = 0; j < n; j++) {
7513					CFStringRef	extendedType;
7514
7515					extendedType = CFArrayGetValueAtIndex(extendedTypes, j);
7516					config = (interfaceConfiguration != NULL) ? CFDictionaryGetValue(interfaceConfiguration, extendedType)
7517					: NULL;
7518					if (config == (CFDictionaryRef)kCFNull) {
7519						config = NULL;
7520					}
7521					if (!__SCNetworkInterfaceSetConfiguration(interface, extendedType, config, TRUE)) {
7522						SCLog(TRUE, LOG_DEBUG,
7523						      CFSTR("__SCNetworkInterfaceSetDeepConfiguration __SCNetworkInterfaceSetConfiguration() failed, interface=%@, type=%@"),
7524						      interface,
7525						      defaultType);
7526					}
7527				}
7528
7529				CFRelease(extendedTypes);
7530			}
7531		}
7532
7533		interface = SCNetworkInterfaceGetInterface(interface);
7534	}
7535
7536	return;
7537}
7538
7539
7540SCNetworkInterfaceRef
7541_SCNetworkInterfaceCopyActive(SCDynamicStoreRef store, CFStringRef bsdName)
7542{
7543	SCNetworkInterfaceRef		interface;
7544
7545	interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeAllVirtualInterfaces);
7546	if (interface == NULL) {
7547		return NULL;
7548	}
7549
7550	if (store != NULL) {
7551		SCNetworkInterfacePrivateRef	interfacePrivate =
7552			(SCNetworkInterfacePrivateRef)interface;
7553
7554		CFRetain(store);
7555		interfacePrivate->store = store;
7556	}
7557
7558	return interface;
7559}
7560
7561
7562#if	!TARGET_IPHONE_SIMULATOR
7563SCNetworkServicePrimaryRank
7564SCNetworkInterfaceGetPrimaryRank(SCNetworkInterfaceRef interface)
7565{
7566	IPMonitorControlRef 		control;
7567	SCNetworkInterfacePrivateRef 	interfacePrivate =
7568					(SCNetworkInterfacePrivateRef)interface;
7569	SCNetworkServicePrimaryRank	rank = kSCNetworkServicePrimaryRankDefault;
7570
7571	control = interfacePrivate->IPMonitorControl;
7572	if (control != NULL) {
7573		CFStringRef	ifName;
7574
7575		ifName = SCNetworkInterfaceGetBSDName(interface);
7576		if (ifName != NULL) {
7577			rank = IPMonitorControlGetInterfacePrimaryRank(control,
7578								       ifName);
7579		}
7580		else {
7581			_SCErrorSet(kSCStatusInvalidArgument);
7582		}
7583	}
7584	return rank;
7585}
7586
7587Boolean
7588SCNetworkInterfaceSetPrimaryRank(SCNetworkInterfaceRef interface,
7589				 SCNetworkServicePrimaryRank newRank)
7590{
7591	IPMonitorControlRef		control;
7592	SCNetworkInterfacePrivateRef 	interfacePrivate =
7593					(SCNetworkInterfacePrivateRef)interface;
7594	CFStringRef			ifName;
7595
7596	ifName = SCNetworkInterfaceGetBSDName(interface);
7597	if (ifName == NULL) {
7598		_SCErrorSet(kSCStatusInvalidArgument);
7599		return (FALSE);
7600	}
7601	control = interfacePrivate->IPMonitorControl;
7602	if (control == NULL) {
7603		control = IPMonitorControlCreate();
7604		if (control == NULL) {
7605			_SCErrorSet(kSCStatusFailed);
7606			return (FALSE);
7607		}
7608		interfacePrivate->IPMonitorControl = control;
7609	}
7610	return IPMonitorControlSetInterfacePrimaryRank(control,
7611						       ifName,
7612						       newRank);
7613}
7614#else 	// !TARGET_IPHONE_SIMULATOR
7615
7616SCNetworkServicePrimaryRank
7617SCNetworkInterfaceGetPrimaryRank(SCNetworkInterfaceRef interface)
7618{
7619	return (kSCNetworkServicePrimaryRankDefault);
7620}
7621
7622Boolean
7623SCNetworkInterfaceSetPrimaryRank(SCNetworkInterfaceRef interface,
7624				 SCNetworkServicePrimaryRank newRank)
7625{
7626	_SCErrorSet(kSCStatusInvalidArgument);
7627	return (FALSE);
7628}
7629
7630#endif	// !TARGET_IPHONE_SIMULATOR
7631
7632
7633__private_extern__
7634CFArrayRef  // SCNetworkInterfaceRef
7635__SCNetworkInterfaceCopyStoredWithPreferences (SCPreferencesRef ni_prefs)
7636{
7637	CFMutableArrayRef interfaceList = NULL;
7638	CFArrayRef		if_list;
7639	SCNetworkInterfaceRef interfaceNamer = NULL;
7640	CFStringRef defaultNetworkInterfacePath = NULL;
7641
7642	/* initialize runtime */
7643	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
7644
7645	if (ni_prefs == NULL) {
7646		defaultNetworkInterfacePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), PREFS_DEFAULT_DIR, NETWORK_INTERFACES_PREFS);
7647		ni_prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterface"), defaultNetworkInterfacePath);
7648	}
7649
7650	if_list = SCPreferencesGetValue(ni_prefs, INTERFACES);
7651
7652	if (isA_CFArray(if_list) != NULL) {
7653		CFIndex	i;
7654		CFIndex	n	= CFArrayGetCount(if_list);
7655
7656		interfaceList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7657		for (i = 0; i < n; i++) {
7658			CFDictionaryRef	dict;
7659
7660			dict = CFArrayGetValueAtIndex(if_list, i);
7661			if (isA_CFDictionary(dict) != NULL) {
7662				interfaceNamer = __SCNetworkInterfaceCreateWithStorageEntity(NULL, dict, ni_prefs);
7663
7664				if (interfaceNamer != NULL) {
7665					CFArrayAppendValue(interfaceList, interfaceNamer);
7666					CFRelease(interfaceNamer);
7667				}
7668			}
7669		}
7670	}
7671
7672	if (defaultNetworkInterfacePath != NULL) {
7673		CFRelease(defaultNetworkInterfacePath);
7674		// prefs were created in the function, and hence need to be released
7675		CFRelease(ni_prefs);
7676	}
7677	return interfaceList;
7678}
7679
7680
7681__private_extern__
7682Boolean
7683__SCNetworkInterfaceSaveStoredWithPreferences(SCPreferencesRef prefs, CFArrayRef interfacesToSave)
7684{
7685	CFStringRef defaultNetworkInterfacePath = NULL;
7686	Boolean success = FALSE;
7687
7688	if (prefs == NULL) {    // TODO: Get the default preferences on the system
7689		defaultNetworkInterfacePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), PREFS_DEFAULT_DIR, NETWORK_INTERFACES_PREFS);
7690		prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterface"), defaultNetworkInterfacePath);
7691	}
7692
7693	if (isA_CFArray(interfacesToSave) == NULL) {
7694		SCLog(TRUE, LOG_DEBUG, CFSTR("interfacesToSave is NULL or not of correct type"));
7695		goto done;
7696	}
7697	SCPreferencesSetValue(prefs, INTERFACES, interfacesToSave);
7698	success = TRUE;
7699done:
7700	if (defaultNetworkInterfacePath != NULL) {
7701		CFRelease(defaultNetworkInterfacePath);
7702		// prefs were created in the function, and hence need to be released
7703		CFRelease(prefs);
7704	}
7705
7706	return success;
7707}
7708
7709__private_extern__
7710SCNetworkInterfaceRef
7711__SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(CFAllocatorRef allocator, SCPreferencesRef ni_prefs, CFStringRef bsdName)
7712{
7713	CFArrayRef if_list;
7714	SCNetworkInterfaceRef interface = NULL;
7715	CFStringRef defaultNetworkInterfacePath;
7716
7717	/* initialize runtime */
7718	pthread_once(&initialized, __SCNetworkInterfaceInitialize);
7719
7720	if (ni_prefs == NULL) {
7721		defaultNetworkInterfacePath = CFStringCreateWithFormat(allocator, NULL, CFSTR("%@/%@"), PREFS_DEFAULT_DIR, NETWORK_INTERFACES_PREFS);
7722		ni_prefs = SCPreferencesCreate(allocator, CFSTR("SCNetworkInterface"), defaultNetworkInterfacePath);
7723		CFRelease(defaultNetworkInterfacePath);
7724	}
7725	else {
7726		CFRetain(ni_prefs);
7727	}
7728
7729	if_list = SCPreferencesGetValue(ni_prefs, INTERFACES);
7730
7731	if (isA_CFArray(if_list) != NULL) {
7732		CFIndex idx;
7733		CFIndex count = CFArrayGetCount(if_list);
7734
7735		for (idx = 0; idx < count; idx++) {
7736			CFDictionaryRef dict;
7737			CFStringRef tmp_bsdName;
7738
7739			dict = CFArrayGetValueAtIndex(if_list, idx);
7740			if (isA_CFDictionary(dict) == NULL) {
7741				continue;
7742			}
7743
7744			tmp_bsdName = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceBSDName));
7745			if (tmp_bsdName == NULL) {
7746				continue;
7747			}
7748			if (CFEqual(bsdName, tmp_bsdName) == TRUE) {
7749				interface = __SCNetworkInterfaceCreateWithStorageEntity(allocator, dict, ni_prefs);
7750				break;
7751			}
7752		}
7753	}
7754
7755	CFRelease(ni_prefs);
7756	return interface;
7757}
7758
7759__private_extern__
7760CFDictionaryRef
7761__SCNetworkInterfaceCreateMappingUsingBSDName(CFArrayRef interfaces)
7762{
7763	CFMutableDictionaryRef mappingBSDToInterface = NULL;
7764	CFStringRef bsdName = NULL;
7765	SCNetworkInterfaceRef interface = NULL;
7766	CFIndex count;
7767
7768	count = CFArrayGetCount(interfaces);
7769
7770	if (count == 0) {
7771		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateMappingUsingBSDName: Interface count is 0"));
7772		return NULL;
7773	}
7774	mappingBSDToInterface = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
7775
7776	for (CFIndex idx = 0; idx < count; idx++) {
7777		interface = (SCNetworkInterfaceRef) CFArrayGetValueAtIndex(interfaces, idx);
7778
7779		bsdName = SCNetworkInterfaceGetBSDName(interface);
7780		if (isA_CFString(bsdName) == NULL) {
7781			SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateMappingUsingBSDName: BSDName is NULL or not of the correct type"));
7782			continue;
7783		}
7784		CFDictionaryAddValue(mappingBSDToInterface, bsdName, interface);
7785	}
7786	if (CFDictionaryGetCount(mappingBSDToInterface) == 0) {
7787		CFRelease(mappingBSDToInterface);
7788		mappingBSDToInterface = NULL;
7789		SCLog(TRUE, LOG_DEBUG, CFSTR("__SCNetworkInterfaceCreateMappingUsingBSDName: Setting mappingBSDToInterface to NULL since it doesn't contain any data"));
7790	}
7791
7792	return mappingBSDToInterface;
7793}
7794