]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkInterface.c
ce21227e8f52b1c76353b62991b30a634914d05e
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkInterface.c
1 /*
2 * Copyright (c) 2004-2009 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 #include <IOKit/usb/USB.h>
67
68 #include "dy_framework.h"
69
70 #ifndef kIODeviceSupportsHoldKey
71 #define kIODeviceSupportsHoldKey "V92Modem"
72 #endif
73
74 #ifndef kUSBProductString
75 #define kUSBProductString "USB Product Name"
76 #endif
77
78 #include <string.h>
79 #include <mach/mach.h>
80 #include <net/if.h>
81 #include <net/if_types.h>
82 #include <net/route.h>
83 #include <sys/param.h>
84 #include <sys/types.h>
85 #include <sys/socket.h>
86 #include <sys/stat.h>
87 #include <sys/sysctl.h>
88 #include <pthread.h>
89 #include <NSSystemDirectories.h>
90
91
92 static CFStringRef copy_interface_string (CFBundleRef bundle, CFStringRef key, Boolean localized);
93 static CFStringRef __SCNetworkInterfaceCopyDescription (CFTypeRef cf);
94 static void __SCNetworkInterfaceDeallocate (CFTypeRef cf);
95 static Boolean __SCNetworkInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2);
96 static CFHashCode __SCNetworkInterfaceHash (CFTypeRef cf);
97
98
99 enum {
100 kSortInternalModem,
101 kSortUSBModem,
102 kSortModem,
103 kSortBluetooth,
104 kSortIrDA,
105 kSortSerialPort,
106 kSortWWAN,
107 kSortEthernetPPP,
108 kSortAirportPPP,
109 kSortEthernet,
110 kSortFireWire,
111 kSortAirPort,
112 kSortOtherWireless,
113 kSortTethered,
114 kSortWWANEthernet,
115 kSortBluetoothPAN,
116 #if !TARGET_OS_IPHONE
117 kSortBond,
118 kSortVLAN,
119 #endif // !TARGET_OS_IPHONE
120 kSortUnknown
121 };
122
123
124 const CFStringRef kSCNetworkInterfaceType6to4 = CFSTR("6to4");
125 const CFStringRef kSCNetworkInterfaceTypeBluetooth = CFSTR("Bluetooth");
126 #if !TARGET_OS_IPHONE
127 const CFStringRef kSCNetworkInterfaceTypeBond = CFSTR("Bond");
128 #endif // !TARGET_OS_IPHONE
129 const CFStringRef kSCNetworkInterfaceTypeEthernet = CFSTR("Ethernet");
130 const CFStringRef kSCNetworkInterfaceTypeFireWire = CFSTR("FireWire");
131 const CFStringRef kSCNetworkInterfaceTypeIEEE80211 = CFSTR("IEEE80211"); // IEEE 802.11, AirPort
132 const CFStringRef kSCNetworkInterfaceTypeIPSec = CFSTR("IPSec");
133 const CFStringRef kSCNetworkInterfaceTypeIrDA = CFSTR("IrDA");
134 const CFStringRef kSCNetworkInterfaceTypeL2TP = CFSTR("L2TP");
135 const CFStringRef kSCNetworkInterfaceTypeModem = CFSTR("Modem");
136 const CFStringRef kSCNetworkInterfaceTypePPP = CFSTR("PPP");
137 const CFStringRef kSCNetworkInterfaceTypePPTP = CFSTR("PPTP");
138 const CFStringRef kSCNetworkInterfaceTypeSerial = CFSTR("Serial");
139 #if !TARGET_OS_IPHONE
140 const CFStringRef kSCNetworkInterfaceTypeVLAN = CFSTR("VLAN");
141 #endif // !TARGET_OS_IPHONE
142 const CFStringRef kSCNetworkInterfaceTypeWWAN = CFSTR("WWAN");
143
144 const CFStringRef kSCNetworkInterfaceTypeIPv4 = CFSTR("IPv4");
145
146 static SCNetworkInterfacePrivate __kSCNetworkInterfaceIPv4 = {
147 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), // cfBase
148 NULL, // interface type
149 NULL, // name
150 NULL, // localized name
151 NULL, // localization key
152 NULL, // localization arg1
153 NULL, // localization arg2
154 NULL, // [layered] interface
155 NULL, // prefs
156 NULL, // serviceID
157 NULL, // unsaved
158 NULL, // entity_device
159 NULL, // entity_device_unique
160 NULL, // entity_type
161 NULL, // entity_subtype
162 NULL, // supported_interface_types
163 NULL, // supported_protocol_types
164 NULL, // address
165 NULL, // addressString
166 FALSE, // builtin
167 NULL, // configurationAction
168 NULL, // location
169 NULL, // path
170 NULL, // overrides
171 FALSE, // modemIsV92
172 NULL, // type
173 NULL, // unit
174 { NULL, 0, 0 }, // usb { name, vid, pid }
175 kSortUnknown, // sort_order
176 #if !TARGET_OS_IPHONE
177 FALSE, // supportsBond
178 { NULL, NULL}, // bond { interfaces, options }
179 FALSE, // supportsVLAN
180 { NULL, NULL, NULL } // vlan { interface, tag, options }
181 #endif // !TARGET_OS_IPHONE
182 };
183
184 const SCNetworkInterfaceRef kSCNetworkInterfaceIPv4 = (SCNetworkInterfaceRef)&__kSCNetworkInterfaceIPv4;
185
186 #pragma mark -
187 #pragma mark SCNetworkInterface configuration details
188
189 #define doNone 0
190
191 #define do6to4 1<<0
192 #define doL2TP 1<<1
193 #define doPPP 1<<2
194 #define doPPTP 1<<3
195 #define doIPSec 1<<4
196 #define doOverIP do6to4|doL2TP|doPPTP|doIPSec
197
198 #if !TARGET_OS_IPHONE
199 #define doAppleTalk 1<<0
200 #else // !TARGET_OS_IPHONE
201 #define doAppleTalk 0
202 #endif // !TARGET_OS_IPHONE
203 #define doDNS 1<<1
204 #define doIPv4 1<<2
205 #define doIPv6 1<<3
206 #define doProxies 1<<4
207 #if !TARGET_OS_IPHONE
208 #define doSMB 1<<5
209 #else // !TARGET_OS_IPHONE
210 #define doSMB 0
211 #endif // !TARGET_OS_IPHONE
212
213 static const struct {
214 const CFStringRef *interface_type;
215 const CFStringRef *entity_hardware;
216 Boolean per_interface_config;
217 uint32_t supported_interfaces;
218 const CFStringRef *ppp_subtype;
219 uint32_t supported_protocols;
220 } configurations[] = {
221 // interface type entity_hardware if config? interface types PPP sub-type interface protocols
222 // ===================================== ================= ========== =============== ======================================= =========================================
223 { &kSCNetworkInterfaceType6to4 , &kSCEntNet6to4 , FALSE, doNone, NULL, doIPv6 },
224 { &kSCNetworkInterfaceTypeBluetooth , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
225 #if !TARGET_OS_IPHONE
226 { &kSCNetworkInterfaceTypeBond , &kSCEntNetEthernet, TRUE , doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB },
227 #endif // !TARGET_OS_IPHONE
228 { &kSCNetworkInterfaceTypeEthernet , &kSCEntNetEthernet, TRUE , doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB },
229 { &kSCNetworkInterfaceTypeFireWire , &kSCEntNetFireWire, TRUE , doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB },
230 { &kSCNetworkInterfaceTypeIEEE80211 , &kSCEntNetAirPort , TRUE , doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB },
231 { &kSCNetworkInterfaceTypeIPSec , &kSCEntNetIPSec , FALSE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB },
232 { &kSCNetworkInterfaceTypeIrDA , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
233 { &kSCNetworkInterfaceTypeL2TP , NULL , FALSE, doPPP, &kSCValNetInterfaceSubTypeL2TP, doNone },
234 { &kSCNetworkInterfaceTypeModem , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
235 { &kSCNetworkInterfaceTypePPP , &kSCEntNetPPP , FALSE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies|doSMB },
236 { &kSCNetworkInterfaceTypePPTP , NULL , FALSE, doPPP, &kSCValNetInterfaceSubTypePPTP, doNone },
237 { &kSCNetworkInterfaceTypeSerial , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
238 #if !TARGET_OS_IPHONE
239 { &kSCNetworkInterfaceTypeVLAN , &kSCEntNetEthernet, TRUE , doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies|doSMB },
240 #endif // !TARGET_OS_IPHONE
241 { &kSCNetworkInterfaceTypeWWAN , &kSCEntNetModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
242 // ===================================== ================= ========== =============== ======================================= =========================================
243 { &kSCNetworkInterfaceTypeIPv4 , NULL , FALSE, doOverIP, NULL, doNone }
244 };
245
246
247 #define NETWORKINTERFACE_LOCALIZATIONS CFSTR("NetworkInterface")
248 static CFBundleRef bundle = NULL;
249
250
251 static CFTypeID __kSCNetworkInterfaceTypeID = _kCFRuntimeNotATypeID;
252
253
254 static const CFRuntimeClass __SCNetworkInterfaceClass = {
255 0, // version
256 "SCNetworkInterface", // className
257 NULL, // init
258 NULL, // copy
259 __SCNetworkInterfaceDeallocate, // dealloc
260 __SCNetworkInterfaceEqual, // equal
261 __SCNetworkInterfaceHash, // hash
262 NULL, // copyFormattingDesc
263 __SCNetworkInterfaceCopyDescription // copyDebugDesc
264 };
265
266
267 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
268 static pthread_once_t iokit_quiet = PTHREAD_ONCE_INIT;
269
270
271 static mach_port_t masterPort = MACH_PORT_NULL;
272
273
274 static CFStringRef
275 __SCNetworkInterfaceCopyDescription(CFTypeRef cf)
276 {
277 CFAllocatorRef allocator = CFGetAllocator(cf);
278 CFMutableStringRef result;
279 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)cf;
280
281 result = CFStringCreateMutable(allocator, 0);
282 CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkInterface %p [%p]> {"), cf, allocator);
283 CFStringAppendFormat(result, NULL, CFSTR("type = %@"), interfacePrivate->interface_type);
284 CFStringAppendFormat(result, NULL, CFSTR(", entity_device = %@"), interfacePrivate->entity_device);
285 if (interfacePrivate->entity_device_unique != NULL) {
286 CFStringAppendFormat(result, NULL, CFSTR("+%@"), interfacePrivate->entity_device_unique);
287 }
288 CFStringAppendFormat(result, NULL, CFSTR(", entity_type = %@"), interfacePrivate->entity_type);
289 if (interfacePrivate->entity_subtype != NULL) {
290 CFStringAppendFormat(result, NULL, CFSTR(" / %@"), interfacePrivate->entity_subtype);
291 }
292 if (interfacePrivate->name != NULL) {
293 CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), interfacePrivate->name);
294 }
295 if (interfacePrivate->localized_name != NULL) {
296 CFStringAppendFormat(result, NULL, CFSTR(", name(l) = %@"), interfacePrivate->localized_name);
297 } else {
298 if (interfacePrivate->localized_key != NULL) {
299 CFStringAppendFormat(result, NULL, CFSTR(", name(k) = \"%@\""), interfacePrivate->localized_key);
300 if (interfacePrivate->localized_arg1 != NULL) {
301 CFStringAppendFormat(result, NULL, CFSTR("+\"%@\""), interfacePrivate->localized_arg1);
302 }
303 if (interfacePrivate->localized_arg2 != NULL) {
304 CFStringAppendFormat(result, NULL, CFSTR("+\"%@\""), interfacePrivate->localized_arg2);
305 }
306 }
307 }
308 if (interfacePrivate->address != NULL) {
309 const uint8_t *data;
310 CFIndex dataLen;
311 CFIndex i;
312
313 CFStringAppendFormat(result, NULL, CFSTR(", address = 0x"));
314
315 data = CFDataGetBytePtr(interfacePrivate->address);
316 dataLen = CFDataGetLength(interfacePrivate->address);
317 for (i = 0; i < dataLen; i++) {
318 CFStringAppendFormat(result, NULL, CFSTR("%02x"), data[i]);
319 }
320 }
321 CFStringAppendFormat(result, NULL, CFSTR(", builtin = %s"), interfacePrivate->builtin ? "TRUE" : "FALSE");
322 if (interfacePrivate->modemIsV92) {
323 CFStringAppendFormat(result, NULL, CFSTR(", v.92"));
324 }
325 if (interfacePrivate->location != NULL) {
326 CFStringAppendFormat(result, NULL, CFSTR(", location = %@"), interfacePrivate->location);
327 }
328 if (interfacePrivate->path != NULL) {
329 CFStringAppendFormat(result, NULL, CFSTR(", path = %@"), interfacePrivate->path);
330 }
331 if (interfacePrivate->type != NULL) {
332 CFStringAppendFormat(result, NULL, CFSTR(", type = %@"), interfacePrivate->type);
333 }
334 if (interfacePrivate->unit != NULL) {
335 CFStringAppendFormat(result, NULL, CFSTR(", unit = %@"), interfacePrivate->unit);
336 }
337 if ((interfacePrivate->usb.vid != NULL) || (interfacePrivate->usb.pid != NULL)) {
338 int pid;
339 int vid;
340
341 if (!isA_CFNumber(interfacePrivate->usb.pid) ||
342 !CFNumberGetValue(interfacePrivate->usb.vid, kCFNumberIntType, &pid)) {
343 pid = 0;
344 }
345 if (!isA_CFNumber(interfacePrivate->usb.vid) ||
346 !CFNumberGetValue(interfacePrivate->usb.vid, kCFNumberIntType, &vid)) {
347 vid = 0;
348 }
349
350 CFStringAppendFormat(result, NULL, CFSTR(", USB%s%@ vid/pid = 0x%0x/0x%0x"),
351 interfacePrivate->usb.name != NULL ? " name = " : "",
352 interfacePrivate->usb.name != NULL ? interfacePrivate->usb.name : CFSTR(""),
353 interfacePrivate->usb.vid,
354 interfacePrivate->usb.pid);
355 }
356 if (interfacePrivate->configurationAction != NULL) {
357 CFStringAppendFormat(result, NULL, CFSTR(", action = %@"), interfacePrivate->configurationAction);
358 }
359 if (interfacePrivate->overrides != NULL) {
360 CFStringAppendFormat(result, NULL, CFSTR(", overrides = %p"), interfacePrivate->overrides);
361 }
362 CFStringAppendFormat(result, NULL, CFSTR(", order = %d"), interfacePrivate->sort_order);
363 if (interfacePrivate->prefs != NULL) {
364 CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), interfacePrivate->prefs);
365 }
366 if (interfacePrivate->serviceID != NULL) {
367 CFStringAppendFormat(result, NULL, CFSTR(", service = %@"), interfacePrivate->serviceID);
368 }
369 if (interfacePrivate->interface != NULL) {
370 CFStringAppendFormat(result, NULL, CFSTR(", interface = %@"), interfacePrivate->interface);
371 }
372 if (interfacePrivate->unsaved != NULL) {
373 CFStringAppendFormat(result, NULL, CFSTR(", unsaved = %@"), interfacePrivate->unsaved);
374 }
375 #if !TARGET_OS_IPHONE
376 if (interfacePrivate->bond.interfaces != NULL) {
377 CFIndex i;
378 CFIndex n;
379
380 n = CFArrayGetCount(interfacePrivate->bond.interfaces);
381 for (i = 0; i < n; i++) {
382 SCNetworkInterfaceRef member;
383
384 member = CFArrayGetValueAtIndex(interfacePrivate->bond.interfaces, i);
385 CFStringAppendFormat(result, NULL,
386 CFSTR("%s%@"),
387 (i == 0) ? ", interfaces = " : ", ",
388 SCNetworkInterfaceGetBSDName(member));
389 }
390 }
391 if (interfacePrivate->bond.mode != NULL) {
392 CFStringAppendFormat(result, NULL, CFSTR(", mode = %@"), interfacePrivate->bond.mode);
393 }
394 if (interfacePrivate->bond.options != NULL) {
395 CFStringAppendFormat(result, NULL, CFSTR(", options = %@"), interfacePrivate->bond.options);
396 }
397 if (interfacePrivate->bond.mode != NULL) {
398 CFStringAppendFormat(result, NULL, CFSTR(", mode = %@"), interfacePrivate->bond.mode);
399 }
400 if (interfacePrivate->vlan.interface != NULL) {
401 CFStringAppendFormat(result, NULL,
402 CFSTR(", interface = %@"),
403 SCNetworkInterfaceGetBSDName(interfacePrivate->vlan.interface));
404 }
405 if (interfacePrivate->vlan.tag != NULL) {
406 CFStringAppendFormat(result, NULL, CFSTR(", tag = %@"), interfacePrivate->vlan.tag);
407 }
408 if (interfacePrivate->vlan.options != NULL) {
409 CFStringAppendFormat(result, NULL, CFSTR(", options = %@"), interfacePrivate->vlan.options);
410 }
411 #endif // !TARGET_OS_IPHONE
412 CFStringAppendFormat(result, NULL, CFSTR("}"));
413
414 return result;
415 }
416
417
418 static void
419 __SCNetworkInterfaceDeallocate(CFTypeRef cf)
420 {
421 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)cf;
422
423 /* release resources */
424
425 if (interfacePrivate->interface != NULL)
426 CFRelease(interfacePrivate->interface);
427
428 if (interfacePrivate->name != NULL)
429 CFRelease(interfacePrivate->name);
430
431 if (interfacePrivate->localized_name != NULL)
432 CFRelease(interfacePrivate->localized_name);
433
434 if (interfacePrivate->localized_arg1 != NULL)
435 CFRelease(interfacePrivate->localized_arg1);
436
437 if (interfacePrivate->localized_arg2 != NULL)
438 CFRelease(interfacePrivate->localized_arg2);
439
440 if (interfacePrivate->prefs != NULL)
441 CFRelease(interfacePrivate->prefs);
442
443 if (interfacePrivate->serviceID != NULL)
444 CFRelease(interfacePrivate->serviceID);
445
446 if (interfacePrivate->unsaved != NULL)
447 CFRelease(interfacePrivate->unsaved);
448
449 if (interfacePrivate->entity_device != NULL)
450 CFRelease(interfacePrivate->entity_device);
451
452 if (interfacePrivate->entity_device_unique != NULL)
453 CFRelease(interfacePrivate->entity_device_unique);
454
455 if (interfacePrivate->supported_interface_types != NULL)
456 CFRelease(interfacePrivate->supported_interface_types);
457
458 if (interfacePrivate->supported_protocol_types != NULL)
459 CFRelease(interfacePrivate->supported_protocol_types);
460
461 if (interfacePrivate->address != NULL)
462 CFRelease(interfacePrivate->address);
463
464 if (interfacePrivate->addressString != NULL)
465 CFRelease(interfacePrivate->addressString);
466
467 if (interfacePrivate->location != NULL)
468 CFRelease(interfacePrivate->location);
469
470 if (interfacePrivate->path != NULL)
471 CFRelease(interfacePrivate->path);
472
473 if (interfacePrivate->configurationAction != NULL)
474 CFRelease(interfacePrivate->configurationAction);
475
476 if (interfacePrivate->overrides != NULL)
477 CFRelease(interfacePrivate->overrides);
478
479 if (interfacePrivate->type != NULL)
480 CFRelease(interfacePrivate->type);
481
482 if (interfacePrivate->unit != NULL)
483 CFRelease(interfacePrivate->unit);
484
485 if (interfacePrivate->usb.name != NULL)
486 CFRelease(interfacePrivate->usb.name);
487
488 if (interfacePrivate->usb.pid != NULL)
489 CFRelease(interfacePrivate->usb.pid);
490
491 if (interfacePrivate->usb.vid != NULL)
492 CFRelease(interfacePrivate->usb.vid);
493
494 #if !TARGET_OS_IPHONE
495 if (interfacePrivate->bond.interfaces != NULL)
496 CFRelease(interfacePrivate->bond.interfaces);
497
498 if (interfacePrivate->bond.mode != NULL)
499 CFRelease(interfacePrivate->bond.mode);
500
501 if (interfacePrivate->bond.options != NULL)
502 CFRelease(interfacePrivate->bond.options);
503
504 if (interfacePrivate->vlan.interface != NULL)
505 CFRelease(interfacePrivate->vlan.interface);
506
507 if (interfacePrivate->vlan.tag != NULL)
508 CFRelease(interfacePrivate->vlan.tag);
509
510 if (interfacePrivate->vlan.options != NULL)
511 CFRelease(interfacePrivate->vlan.options);
512 #endif // !TARGET_OS_IPHONE
513
514 return;
515 }
516
517
518 static Boolean
519 __SCNetworkInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2)
520 {
521 SCNetworkInterfacePrivateRef if1 = (SCNetworkInterfacePrivateRef)cf1;
522 SCNetworkInterfacePrivateRef if2 = (SCNetworkInterfacePrivateRef)cf2;
523
524 if (if1 == if2)
525 return TRUE;
526
527 if (!CFEqual(if1->interface_type, if2->interface_type)) {
528 return FALSE; // if not the same interface type
529 }
530
531 if (!_SC_CFEqual(if1->entity_device, if2->entity_device)) {
532 return FALSE; // if not the same device
533 }
534
535 if ((if1->entity_device_unique != NULL) && (if2->entity_device_unique != NULL)) {
536 if (!_SC_CFEqual(if1->entity_device_unique, if2->entity_device_unique)) {
537 return FALSE; // if not the same device unique identifier
538 }
539 } else if ((if1->entity_device_unique != NULL) || (if2->entity_device_unique != NULL)) {
540 CFStringRef name1;
541 CFStringRef name2;
542
543 name1 = __SCNetworkInterfaceGetNonLocalizedDisplayName((SCNetworkInterfaceRef)if1);
544 name2 = __SCNetworkInterfaceGetNonLocalizedDisplayName((SCNetworkInterfaceRef)if2);
545 if ((name1 != NULL) && (name2 != NULL) && !_SC_CFEqual(name1, name2)) {
546 return FALSE; // if same device but not the same display name
547 }
548 }
549
550 #if !TARGET_OS_IPHONE
551 if (CFEqual(if1->interface_type, kSCNetworkInterfaceTypeBond)) {
552 if (!_SC_CFEqual(if1->bond.interfaces, if2->bond.interfaces)) {
553 return FALSE; // if not the same interfaces
554 }
555 if (!_SC_CFEqual(if1->bond.mode, if2->bond.mode)) {
556 return FALSE; // if not the same mode
557 }
558 }
559
560 if (CFEqual(if1->interface_type, kSCNetworkInterfaceTypeVLAN)) {
561 if (!_SC_CFEqual(if1->vlan.interface, if2->vlan.interface)) {
562 return FALSE; // if not the same physical interface
563 }
564 if (!_SC_CFEqual(if1->vlan.tag, if2->vlan.tag)) {
565 return FALSE; // if not the same tag
566 }
567 }
568 #endif // !TARGET_OS_IPHONE
569
570 if (!_SC_CFEqual(if1->interface, if2->interface)) {
571 return FALSE; // if not the same layering
572 }
573
574 return TRUE;
575 }
576
577
578 static CFHashCode
579 __SCNetworkInterfaceHash(CFTypeRef cf)
580 {
581 CFHashCode hash = 0;
582 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)cf;
583
584 if (interfacePrivate->entity_device != NULL) {
585 if (interfacePrivate->entity_device_unique == NULL) {
586 hash = CFHash(interfacePrivate->entity_device);
587 } else {
588 CFStringRef str;
589
590 str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@+%@"),
591 interfacePrivate->entity_device,
592 interfacePrivate->entity_device_unique);
593 hash = CFHash(str);
594 CFRelease(str);
595 }
596 }
597
598 return hash;
599 }
600
601
602 static void
603 __SCNetworkInterfaceInitialize(void)
604 {
605 kern_return_t kr;
606
607 // register w/CF
608 __kSCNetworkInterfaceTypeID = _CFRuntimeRegisterClass(&__SCNetworkInterfaceClass);
609
610 // initialize __kSCNetworkInterfaceIPv4
611 _CFRuntimeSetInstanceTypeID(&__kSCNetworkInterfaceIPv4, __kSCNetworkInterfaceTypeID);
612 __kSCNetworkInterfaceIPv4.interface_type = kSCNetworkInterfaceTypeIPv4;
613 __kSCNetworkInterfaceIPv4.localized_key = CFSTR("ipv4");
614
615 // get CFBundleRef for SystemConfiguration.framework
616 bundle = _SC_CFBundleGet();
617
618 // get mach port used to communication with IOKit
619 kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
620 if (kr != KERN_SUCCESS) {
621 SCLog(TRUE, LOG_DEBUG,
622 CFSTR("__SCNetworkInterfaceInitialize(), could not get IOMasterPort, kr = 0x%x"),
623 kr);
624 }
625
626 return;
627 }
628
629
630 __private_extern__
631 SCNetworkInterfacePrivateRef
632 __SCNetworkInterfaceCreatePrivate(CFAllocatorRef allocator,
633 SCNetworkInterfaceRef interface,
634 SCPreferencesRef prefs,
635 CFStringRef serviceID,
636 io_string_t path)
637 {
638 SCNetworkInterfacePrivateRef interfacePrivate;
639 uint32_t size;
640
641 /* initialize runtime */
642 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
643
644 /* allocate target */
645 size = sizeof(SCNetworkInterfacePrivate) - sizeof(CFRuntimeBase);
646 interfacePrivate = (SCNetworkInterfacePrivateRef)_CFRuntimeCreateInstance(allocator,
647 __kSCNetworkInterfaceTypeID,
648 size,
649 NULL);
650 if (interfacePrivate == NULL) {
651 return NULL;
652 }
653
654 interfacePrivate->interface_type = NULL;
655 interfacePrivate->name = NULL;
656 interfacePrivate->localized_name = NULL;
657 interfacePrivate->localized_key = NULL;
658 interfacePrivate->localized_arg1 = NULL;
659 interfacePrivate->localized_arg2 = NULL;
660 interfacePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL;
661 interfacePrivate->prefs = (prefs != NULL) ? CFRetain(prefs) : NULL;
662 interfacePrivate->serviceID = (serviceID != NULL) ? CFRetain(serviceID) : NULL;
663 interfacePrivate->unsaved = NULL;
664 interfacePrivate->entity_device = NULL;
665 interfacePrivate->entity_device_unique = NULL;
666 interfacePrivate->entity_type = NULL;
667 interfacePrivate->entity_subtype = NULL;
668 interfacePrivate->supported_interface_types = NULL;
669 interfacePrivate->supported_protocol_types = NULL;
670 interfacePrivate->address = NULL;
671 interfacePrivate->addressString = NULL;
672 interfacePrivate->builtin = FALSE;
673 interfacePrivate->configurationAction = NULL;
674 interfacePrivate->path = (path != NULL) ? CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8)
675 : NULL;
676 interfacePrivate->location = NULL;
677 interfacePrivate->overrides = NULL;
678 interfacePrivate->modemIsV92 = FALSE;
679 interfacePrivate->type = NULL;
680 interfacePrivate->unit = NULL;
681 interfacePrivate->usb.name = NULL;
682 interfacePrivate->usb.vid = NULL;
683 interfacePrivate->usb.pid = NULL;
684 interfacePrivate->sort_order = kSortUnknown;
685 #if !TARGET_OS_IPHONE
686 interfacePrivate->supportsBond = FALSE;
687 interfacePrivate->bond.interfaces = NULL;
688 interfacePrivate->bond.mode = NULL;
689 interfacePrivate->bond.options = NULL;
690 interfacePrivate->supportsVLAN = FALSE;
691 interfacePrivate->vlan.interface = NULL;
692 interfacePrivate->vlan.tag = NULL;
693 interfacePrivate->vlan.options = NULL;
694 #endif // !TARGET_OS_IPHONE
695
696 return interfacePrivate;
697 }
698
699
700 #if !TARGET_OS_IPHONE
701 __private_extern__
702 Boolean
703 __SCNetworkInterfaceSupportsVLAN(CFStringRef bsd_if)
704 {
705 char * buf = NULL;
706 size_t buf_len = 0;
707 struct if_msghdr * ifm;
708 char * if_name = NULL;
709 unsigned int if_index;
710 int mib[6];
711 Boolean vlanOK = FALSE;
712
713 // get the interface index
714 if_name = _SC_cfstring_to_cstring(bsd_if, NULL, 0, kCFStringEncodingASCII);
715 if (if_name == NULL) {
716 return FALSE; // if conversion error
717 }
718 if_index = if_nametoindex(if_name);
719 if (if_index == 0) {
720 goto done; // if unknown interface
721 }
722
723 // get information for the specified interface
724 mib[0] = CTL_NET;
725 mib[1] = PF_ROUTE;
726 mib[2] = 0;
727 mib[3] = AF_LINK;
728 mib[4] = NET_RT_IFLIST;
729 mib[5] = if_index; /* ask for exactly one interface */
730
731 if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) == -1) {
732 SCLog(TRUE, LOG_ERR, CFSTR("sysctl() size failed: %s"), strerror(errno));
733 goto done;
734 }
735 buf = CFAllocatorAllocate(NULL, buf_len, 0);
736 if (sysctl(mib, 6, buf, &buf_len, NULL, 0) == -1) {
737 SCLog(TRUE, LOG_ERR, CFSTR("sysctl() failed: %s"), strerror(errno));
738 goto done;
739 }
740
741 // check the link type and hwassist flags
742 ifm = (struct if_msghdr *)buf;
743 switch (ifm->ifm_type) {
744 case RTM_IFINFO : {
745 #if defined(IF_HWASSIST_VLAN_TAGGING) && defined(IF_HWASSIST_VLAN_MTU)
746 struct if_data *if_data = &ifm->ifm_data;
747
748 if (if_data->ifi_hwassist & (IF_HWASSIST_VLAN_TAGGING | IF_HWASSIST_VLAN_MTU)) {
749 vlanOK = TRUE;
750 }
751 #endif
752 break;
753 }
754 }
755
756 done :
757
758 if (if_name != NULL) CFAllocatorDeallocate(NULL, if_name);
759 if (buf != NULL) CFAllocatorDeallocate(NULL, buf);
760
761 return vlanOK;
762 }
763
764
765 __private_extern__
766 SCNetworkInterfacePrivateRef
767 _SCBondInterfaceCreatePrivate(CFAllocatorRef allocator,
768 CFStringRef bond_if)
769 {
770 SCNetworkInterfacePrivateRef interfacePrivate;
771
772 interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL, NULL);
773 if (interfacePrivate == NULL) {
774 return NULL;
775 }
776
777 interfacePrivate->interface_type = kSCNetworkInterfaceTypeBond;
778 interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
779 interfacePrivate->entity_device = CFStringCreateCopy(allocator, bond_if);
780 interfacePrivate->builtin = TRUE;
781 interfacePrivate->supportsVLAN = __SCNetworkInterfaceSupportsVLAN(bond_if);
782 interfacePrivate->sort_order = kSortBond;
783
784 interfacePrivate->localized_key = CFSTR("bond");
785 interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device);
786
787 interfacePrivate->bond.interfaces = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
788 // interfacePrivate->bond.mode = NULL;
789 // interfacePrivate->bond.options = NULL;
790
791 return interfacePrivate;
792 }
793
794
795 __private_extern__
796 SCNetworkInterfacePrivateRef
797 _SCVLANInterfaceCreatePrivate(CFAllocatorRef allocator,
798 CFStringRef vlan_if)
799 {
800 SCNetworkInterfacePrivateRef interfacePrivate;
801
802 interfacePrivate = __SCNetworkInterfaceCreatePrivate(allocator, NULL, NULL, NULL, NULL);
803 if (interfacePrivate == NULL) {
804 return NULL;
805 }
806
807 interfacePrivate->interface_type = kSCNetworkInterfaceTypeVLAN;
808 interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
809 interfacePrivate->entity_device = CFStringCreateCopy(allocator, vlan_if);
810 interfacePrivate->builtin = TRUE;
811 interfacePrivate->sort_order = kSortVLAN;
812
813 interfacePrivate->localized_key = CFSTR("vlan");
814 interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device);
815
816 // interfacePrivate->vlan.interface = NULL;
817 // interfacePrivate->vlan.tag = NULL;
818 // interfacePrivate->vlan.options = NULL;
819
820 return interfacePrivate;
821 }
822 #endif // !TARGET_OS_IPHONE
823
824
825 #pragma mark -
826 #pragma mark Interface ordering
827
828
829 static CFArrayRef
830 split_path(CFStringRef path)
831 {
832 CFArrayRef components;
833 CFMutableStringRef nPath;
834
835 // turn '@'s into '/'s
836 nPath = CFStringCreateMutableCopy(NULL, 0, path);
837 (void) CFStringFindAndReplace(nPath,
838 CFSTR("@"),
839 CFSTR("/"),
840 CFRangeMake(0, CFStringGetLength(nPath)),
841 0);
842
843 // split path into components to be compared
844 components = CFStringCreateArrayBySeparatingStrings(NULL, nPath, CFSTR("/"));
845 CFRelease(nPath);
846
847 return components;
848 }
849
850
851 CFComparisonResult
852 _SCNetworkInterfaceCompare(const void *val1, const void *val2, void *context)
853 {
854 SCNetworkInterfacePrivateRef dev1 = (SCNetworkInterfacePrivateRef)val1;
855 SCNetworkInterfacePrivateRef dev2 = (SCNetworkInterfacePrivateRef)val2;
856 CFComparisonResult res = kCFCompareEqualTo;
857
858 /* sort by interface type */
859 if (dev1->sort_order != dev2->sort_order) {
860 if (dev1->sort_order < dev2->sort_order) {
861 res = kCFCompareLessThan;
862 } else {
863 res = kCFCompareGreaterThan;
864 }
865 return (res);
866 }
867
868 /* built-in interfaces sort first */
869 if (dev1->builtin != dev2->builtin) {
870 if (dev1->builtin) {
871 res = kCFCompareLessThan;
872 } else {
873 res = kCFCompareGreaterThan;
874 }
875 return (res);
876 }
877
878 /* ... and then, sort built-in interfaces by "location" */
879 if (dev1->builtin) {
880 if (dev1->location != dev2->location) {
881 if (isA_CFString(dev1->location)) {
882 if (isA_CFString(dev2->location)) {
883 res = CFStringCompare(dev1->location, dev2->location, 0);
884 } else {
885 res = kCFCompareLessThan;
886 }
887 } else {
888 res = kCFCompareGreaterThan;
889 }
890
891 if (res != kCFCompareEqualTo) {
892 return (res);
893 }
894 }
895 }
896
897 /* ... and, then sort by IOPathMatch */
898 if ((dev1->path != NULL) && (dev2->path != NULL)) {
899 CFArrayRef elements1;
900 CFArrayRef elements2;
901 CFIndex i;
902 CFIndex n;
903 CFIndex n1;
904 CFIndex n2;
905
906 elements1 = split_path(dev1->path);
907 n1 = CFArrayGetCount(elements1);
908
909 elements2 = split_path(dev2->path);
910 n2 = CFArrayGetCount(elements2);
911
912 n = (n1 <= n2) ? n1 : n2;
913 for (i = 0; i < n; i++) {
914 CFStringRef e1;
915 CFStringRef e2;
916 char *end;
917 quad_t q1;
918 quad_t q2;
919 char *str;
920 Boolean isNum;
921
922 e1 = CFArrayGetValueAtIndex(elements1, i);
923 e2 = CFArrayGetValueAtIndex(elements2, i);
924
925 str = _SC_cfstring_to_cstring(e1, NULL, 0, kCFStringEncodingUTF8);
926 errno = 0;
927 q1 = strtoq(str, &end, 16);
928 isNum = ((*str != '\0') && (*end == '\0') && (errno == 0));
929 CFAllocatorDeallocate(NULL, str);
930
931 if (isNum) {
932 // if e1 is a valid numeric string
933 str = _SC_cfstring_to_cstring(e2, NULL, 0, kCFStringEncodingUTF8);
934 errno = 0;
935 q2 = strtoq(str, &end, 16);
936 isNum = ((*str != '\0') && (*end == '\0') && (errno == 0));
937 CFAllocatorDeallocate(NULL, str);
938
939 if (isNum) {
940 // if e2 is also a valid numeric string
941
942 if (q1 == q2) {
943 res = kCFCompareEqualTo;
944 continue;
945 } else if (q1 < q2) {
946 res = kCFCompareLessThan;
947 } else {
948 res = kCFCompareGreaterThan;
949 }
950 break;
951 }
952 }
953
954 res = CFStringCompare(e1, e2, 0);
955 if (res != kCFCompareEqualTo) {
956 break;
957 }
958 }
959
960 if (res == kCFCompareEqualTo) {
961 if (n1 < n2) {
962 res = kCFCompareLessThan;
963 } else if (n1 < n2) {
964 res = kCFCompareGreaterThan;
965 }
966 }
967
968 CFRelease(elements1);
969 CFRelease(elements2);
970
971 if (res != kCFCompareEqualTo) {
972 return (res);
973 }
974 }
975
976 /* ... and, then sort by BSD interface name */
977 if ((dev1->entity_device != NULL) && (dev2->entity_device != NULL)) {
978 res = CFStringCompare(dev1->entity_device, dev2->entity_device, 0);
979 if (res != kCFCompareEqualTo) {
980 return (res);
981 }
982 }
983
984 /* ... and lastly, sort by BSD interface unique identifier */
985 if ((dev1->entity_device_unique != NULL) && (dev2->entity_device_unique != NULL)) {
986 res = CFStringCompare(dev1->entity_device_unique, dev2->entity_device_unique, 0);
987 // if (res != kCFCompareEqualTo) {
988 // return (res);
989 // }
990 }
991
992 return res;
993 }
994
995
996 static void
997 sort_interfaces(CFMutableArrayRef all_interfaces)
998 {
999 int n = CFArrayGetCount(all_interfaces);
1000
1001 if (n < 2) {
1002 return;
1003 }
1004
1005 CFArraySortValues(all_interfaces, CFRangeMake(0, n), _SCNetworkInterfaceCompare, NULL);
1006 return;
1007 }
1008
1009
1010 __private_extern__
1011 int
1012 __SCNetworkInterfaceOrder(SCNetworkInterfaceRef interface)
1013 {
1014 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
1015
1016 return interfacePrivate->sort_order;
1017 }
1018
1019
1020 #pragma mark -
1021 #pragma mark Interface details
1022
1023
1024 static CFStringRef
1025 IOCopyCFStringValue(CFTypeRef ioVal)
1026 {
1027 if (isA_CFString(ioVal)) {
1028 return CFStringCreateCopy(NULL, ioVal);
1029 }
1030
1031 if (isA_CFData(ioVal)) {
1032 return CFStringCreateWithCString(NULL,
1033 (const char *)CFDataGetBytePtr(ioVal),
1034 kCFStringEncodingUTF8);
1035 }
1036
1037 return NULL;
1038 }
1039
1040
1041 static CFStringRef
1042 IODictionaryCopyCFStringValue(CFDictionaryRef io_dict, CFStringRef io_key)
1043 {
1044 CFTypeRef ioVal;
1045
1046 ioVal = CFDictionaryGetValue(io_dict, io_key);
1047 return IOCopyCFStringValue(ioVal);
1048 }
1049
1050
1051 static Boolean
1052 IOStringValueHasPrefix(CFTypeRef ioVal, CFStringRef prefix)
1053 {
1054 Boolean match = FALSE;
1055 CFIndex prefixLen = CFStringGetLength(prefix);
1056 CFStringRef str = NULL;
1057
1058 if (!isA_CFString(ioVal)) {
1059 if (isA_CFData(ioVal)) {
1060 str = CFStringCreateWithCStringNoCopy(NULL,
1061 (const char *)CFDataGetBytePtr(ioVal),
1062 kCFStringEncodingUTF8,
1063 kCFAllocatorNull);
1064 ioVal = str;
1065 } else {
1066 return FALSE;
1067 }
1068 }
1069
1070 if ((ioVal != NULL) &&
1071 (CFStringGetLength(ioVal) >= prefixLen) &&
1072 (CFStringCompareWithOptions(ioVal,
1073 prefix,
1074 CFRangeMake(0, prefixLen),
1075 kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
1076 match = TRUE;
1077 }
1078
1079 if (str != NULL) CFRelease(str);
1080 return match;
1081 }
1082
1083
1084 static const struct {
1085 const CFStringRef name;
1086 const CFStringRef slot;
1087 } slot_mappings[] = {
1088 // Beige G3
1089 { CFSTR("A1") , CFSTR("1") },
1090 { CFSTR("B1") , CFSTR("2") },
1091 { CFSTR("C1") , CFSTR("3") },
1092
1093 // Blue&White G3, Yikes G4
1094 { CFSTR("J12"), CFSTR("1") },
1095 { CFSTR("J11"), CFSTR("2") },
1096 { CFSTR("J10"), CFSTR("3") },
1097 { CFSTR("J9"), CFSTR("4") },
1098
1099 // AGP G4
1100 { CFSTR("A") , CFSTR("1") },
1101 { CFSTR("B") , CFSTR("2") },
1102 { CFSTR("C") , CFSTR("3") },
1103 { CFSTR("D") , CFSTR("4") },
1104
1105 // Digital Audio G4 (and later models)
1106 { CFSTR("1") , CFSTR("1") },
1107 { CFSTR("2") , CFSTR("2") },
1108 { CFSTR("3") , CFSTR("3") },
1109 { CFSTR("4") , CFSTR("4") },
1110 { CFSTR("5") , CFSTR("5") }
1111 };
1112
1113
1114 static CFStringRef
1115 pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name)
1116 {
1117 kern_return_t kr;
1118 io_registry_entry_t parent;
1119 CFMutableStringRef slot;
1120 CFTypeRef slot_name;
1121
1122 slot = NULL;
1123 if (pci_slot_name != NULL) *pci_slot_name = NULL;
1124
1125 slot_name = IORegistryEntryCreateCFProperty(interface, CFSTR("AAPL,slot-name"), NULL, 0);
1126 if (slot_name != NULL) {
1127 CFIndex i;
1128
1129 slot = CFStringCreateMutable(NULL, 0);
1130 if (isA_CFString(slot_name)) {
1131 if (pci_slot_name != NULL) *pci_slot_name = CFStringCreateCopy(NULL, slot_name);
1132 CFStringAppend(slot, slot_name);
1133 } else if (isA_CFData(slot_name)) {
1134 if (pci_slot_name != NULL) *pci_slot_name = CFDataCreateCopy(NULL, slot_name);
1135 CFStringAppendCString(slot,
1136 (const char *)CFDataGetBytePtr(slot_name),
1137 kCFStringEncodingUTF8);
1138 }
1139
1140 if (CFStringGetLength(slot) > 5) {
1141 (void) CFStringFindAndReplace(slot,
1142 CFSTR("slot-"),
1143 CFSTR(""),
1144 CFRangeMake(0, 5),
1145 kCFCompareCaseInsensitive|kCFCompareAnchored);
1146 }
1147
1148 for (i = 0; i < sizeof(slot_mappings)/sizeof(slot_mappings[0]); i++) {
1149 if (CFStringCompare(slot,
1150 slot_mappings[i].name,
1151 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
1152 CFRelease(slot);
1153 slot = (CFMutableStringRef)CFRetain(slot_mappings[i].slot);
1154 break;
1155 }
1156 }
1157
1158 CFRelease(slot_name);
1159 }
1160
1161 kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &parent);
1162 switch (kr) {
1163 case kIOReturnSuccess : {
1164 CFTypeRef parent_pci_slot_name = NULL;
1165 CFStringRef parent_slot;
1166
1167 parent_slot = pci_slot(parent, &parent_pci_slot_name);
1168 if (parent_slot != NULL) {
1169 if (slot != NULL) CFRelease(slot);
1170 slot = (CFMutableStringRef)parent_slot;
1171
1172 if (pci_slot_name != NULL) {
1173 if (*pci_slot_name != NULL) CFRelease(*pci_slot_name);
1174 *pci_slot_name = parent_pci_slot_name;
1175 } else {
1176 CFRelease(parent_pci_slot_name);
1177 }
1178 }
1179
1180 IOObjectRelease(parent);
1181 break;
1182 }
1183 case kIOReturnNoDevice :
1184 // if we have hit the root node
1185 break;
1186 default :
1187 SCLog(TRUE, LOG_DEBUG, CFSTR("pci_slot IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
1188 break;
1189 }
1190
1191 return slot;
1192 }
1193
1194
1195 static CFComparisonResult
1196 compare_bsdNames(const void *val1, const void *val2, void *context)
1197 {
1198 CFStringRef bsd1 = (CFStringRef)val1;
1199 CFStringRef bsd2 = (CFStringRef)val2;
1200
1201 return CFStringCompare(bsd1, bsd2, 0);
1202 }
1203
1204
1205 static CFStringRef
1206 pci_port(CFTypeRef slot_name, CFStringRef bsdName)
1207 {
1208 CFIndex n;
1209 CFStringRef port_name = NULL;
1210 CFMutableArrayRef port_names;
1211
1212 kern_return_t kr;
1213 CFStringRef match_keys[2];
1214 CFTypeRef match_vals[2];
1215 CFDictionaryRef match_dict;
1216 CFDictionaryRef matching;
1217 io_registry_entry_t slot;
1218 io_iterator_t slot_iterator = MACH_PORT_NULL;
1219
1220 match_keys[0] = CFSTR("AAPL,slot-name");
1221 match_vals[0] = slot_name;
1222
1223 match_dict = CFDictionaryCreate(NULL,
1224 (const void **)match_keys,
1225 (const void **)match_vals,
1226 1,
1227 &kCFTypeDictionaryKeyCallBacks,
1228 &kCFTypeDictionaryValueCallBacks);
1229
1230 match_keys[0] = CFSTR(kIOProviderClassKey);
1231 match_vals[0] = CFSTR("IOPCIDevice");
1232
1233 match_keys[1] = CFSTR(kIOPropertyMatchKey);
1234 match_vals[1] = match_dict;
1235
1236 // note: the "matching" dictionary will be consumed by the following
1237 matching = CFDictionaryCreate(NULL,
1238 (const void **)match_keys,
1239 (const void **)match_vals,
1240 sizeof(match_keys)/sizeof(match_keys[0]),
1241 &kCFTypeDictionaryKeyCallBacks,
1242 &kCFTypeDictionaryValueCallBacks);
1243 CFRelease(match_dict);
1244
1245 kr = IOServiceGetMatchingServices(masterPort, matching, &slot_iterator);
1246 if (kr != kIOReturnSuccess) {
1247 SCLog(TRUE, LOG_DEBUG, CFSTR("pci_port IOServiceGetMatchingServices() failed, kr = 0x%x"), kr);
1248 return MACH_PORT_NULL;
1249 }
1250
1251 port_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1252
1253 while ((slot = IOIteratorNext(slot_iterator)) != MACH_PORT_NULL) {
1254 io_registry_entry_t child;
1255 io_iterator_t child_iterator = MACH_PORT_NULL;
1256
1257 kr = IORegistryEntryCreateIterator(slot,
1258 kIOServicePlane,
1259 kIORegistryIterateRecursively,
1260 &child_iterator);
1261 if (kr != kIOReturnSuccess) {
1262 SCLog(TRUE, LOG_DEBUG, CFSTR("pci_port IORegistryEntryCreateIterator() failed, kr = 0x%x"), kr);
1263 CFRelease(port_names);
1264 return MACH_PORT_NULL;
1265 }
1266
1267 while ((child = IOIteratorNext(child_iterator)) != MACH_PORT_NULL) {
1268 if (IOObjectConformsTo(child, kIONetworkInterfaceClass)) {
1269 CFStringRef if_bsdName;
1270
1271 if_bsdName = IORegistryEntryCreateCFProperty(child,
1272 CFSTR(kIOBSDNameKey),
1273 NULL,
1274 0);
1275 if (if_bsdName != NULL) {
1276 CFArrayAppendValue(port_names, if_bsdName);
1277 CFRelease(if_bsdName);
1278 }
1279 }
1280 IOObjectRelease(child);
1281 }
1282 IOObjectRelease(child_iterator);
1283 IOObjectRelease(slot);
1284 }
1285 IOObjectRelease(slot_iterator);
1286
1287 n = CFArrayGetCount(port_names);
1288 if (n > 1) {
1289 CFArraySortValues(port_names, CFRangeMake(0, n), compare_bsdNames, NULL);
1290 n = CFArrayGetFirstIndexOfValue(port_names, CFRangeMake(0, n), bsdName);
1291 if (n != kCFNotFound) {
1292 port_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), n + 1);
1293 }
1294 }
1295
1296 CFRelease(port_names);
1297 return port_name;
1298 }
1299
1300
1301 static Boolean
1302 pci_slot_info(io_registry_entry_t interface, CFStringRef *slot_name, CFStringRef *port_name)
1303 {
1304 CFStringRef bsd_name;
1305 Boolean ok = FALSE;
1306 CFTypeRef pci_slot_name;
1307
1308 *slot_name = NULL;
1309 *port_name = NULL;
1310
1311 bsd_name = IORegistryEntryCreateCFProperty(interface, CFSTR(kIOBSDNameKey), NULL, 0);
1312 if (bsd_name == NULL) {
1313 return FALSE;
1314 }
1315
1316 *slot_name = pci_slot(interface, &pci_slot_name);
1317 if (*slot_name != NULL) {
1318 if (pci_slot_name != NULL) {
1319 *port_name = pci_port(pci_slot_name, bsd_name);
1320 CFRelease(pci_slot_name);
1321 }
1322 ok = TRUE;
1323 }
1324
1325 CFRelease(bsd_name);
1326 return ok;
1327 }
1328
1329
1330 static Boolean
1331 isBuiltin(io_registry_entry_t interface)
1332 {
1333 CFStringRef slot;
1334
1335 slot = pci_slot(interface, NULL);
1336 if (slot != NULL) {
1337 // interfaces which have a "slot" are not built-in
1338 CFRelease(slot);
1339 return FALSE;
1340 }
1341
1342 return TRUE;
1343 }
1344
1345
1346 static Boolean
1347 isBluetoothBuiltin(Boolean *haveController)
1348 {
1349 Boolean builtin = FALSE;
1350 io_object_t hciController;
1351 io_iterator_t iter = MACH_PORT_NULL;
1352 kern_return_t kr;
1353
1354 kr = IOServiceGetMatchingServices(masterPort,
1355 IOServiceMatching("IOBluetoothHCIController"),
1356 &iter);
1357 if ((kr != kIOReturnSuccess) || (iter == MACH_PORT_NULL)) {
1358 if (kr != kIOReturnSuccess) {
1359 SCLog(TRUE, LOG_DEBUG, CFSTR("isBluetoothBuiltin IOServiceGetMatchingServices() failed, kr = 0x%x"), kr);
1360 }
1361 *haveController = FALSE;
1362 return FALSE;
1363 }
1364 *haveController = TRUE;
1365
1366 hciController = IOIteratorNext(iter);
1367 IOObjectRelease(iter);
1368 if(hciController != MACH_PORT_NULL) {
1369 CFNumberRef idVendor;
1370
1371 idVendor = IORegistryEntryCreateCFProperty(hciController, CFSTR(kUSBVendorID), NULL, 0);
1372 if (idVendor != NULL) {
1373 int idVendorVal;
1374
1375 if (isA_CFNumber(idVendor) &&
1376 CFNumberGetValue(idVendor, kCFNumberIntType, &idVendorVal) &&
1377 (idVendorVal == kIOUSBVendorIDAppleComputer)) {
1378 builtin = TRUE;
1379 }
1380
1381 CFRelease(idVendor);
1382 }
1383
1384 IOObjectRelease(hciController);
1385 }
1386
1387 return builtin;
1388 }
1389
1390
1391 static void
1392 processUSBInterface(SCNetworkInterfacePrivateRef interfacePrivate,
1393 io_registry_entry_t interface,
1394 CFDictionaryRef interface_dict,
1395 io_registry_entry_t controller,
1396 CFDictionaryRef controller_dict,
1397 io_registry_entry_t bus,
1398 CFDictionaryRef bus_dict)
1399 {
1400 // capture USB info
1401 interfacePrivate->usb.name = IORegistryEntrySearchCFProperty(interface,
1402 kIOServicePlane,
1403 CFSTR(kUSBProductString),
1404 NULL,
1405 kIORegistryIterateRecursively | kIORegistryIterateParents);
1406 interfacePrivate->usb.vid = IORegistryEntrySearchCFProperty(interface,
1407 kIOServicePlane,
1408 CFSTR(kUSBVendorID),
1409 NULL,
1410 kIORegistryIterateRecursively | kIORegistryIterateParents);
1411 interfacePrivate->usb.pid = IORegistryEntrySearchCFProperty(interface,
1412 kIOServicePlane,
1413 CFSTR(kUSBProductID),
1414 NULL,
1415 kIORegistryIterateRecursively | kIORegistryIterateParents);
1416
1417 return;
1418 }
1419
1420
1421 #pragma mark -
1422 #pragma mark Interface enumeration
1423
1424
1425 typedef Boolean (*processInterface)(SCNetworkInterfacePrivateRef interfacePrivate,
1426 io_registry_entry_t interface,
1427 CFDictionaryRef interface_dict,
1428 io_registry_entry_t controller,
1429 CFDictionaryRef controller_dict,
1430 io_registry_entry_t bus,
1431 CFDictionaryRef bus_dict);
1432
1433
1434 static Boolean
1435 processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate,
1436 io_registry_entry_t interface,
1437 CFDictionaryRef interface_dict,
1438 io_registry_entry_t controller,
1439 CFDictionaryRef controller_dict,
1440 io_registry_entry_t bus,
1441 CFDictionaryRef bus_dict)
1442 {
1443 CFDataRef data;
1444 int ift = -1;
1445 int iVal;
1446 CFNumberRef num;
1447 CFStringRef str;
1448 CFBooleanRef val;
1449
1450 // interface type
1451 num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceType));
1452 if (isA_CFNumber(num) &&
1453 CFNumberGetValue(num, kCFNumberIntType, &ift)) {
1454 interfacePrivate->type = CFRetain(num);
1455 } else {
1456 SCLog(TRUE, LOG_DEBUG, CFSTR("processNetworkInterface() failed, no interface type"));
1457 return FALSE;
1458 }
1459
1460 switch (ift) {
1461 case IFT_ETHER :
1462 // Type, Hardware
1463
1464 if ((IOObjectConformsTo(controller, "IO80211Controller")) ||
1465 (IOObjectConformsTo(controller, "AirPortPCI" )) ||
1466 (IOObjectConformsTo(controller, "AirPortDriver" ))) {
1467 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
1468 interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
1469 interfacePrivate->sort_order = kSortAirPort;
1470 } else if (IOObjectConformsTo(controller, "IOBluetoothBNEPDriver")) {
1471 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
1472 interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
1473 interfacePrivate->sort_order = kSortBluetoothPAN;
1474 } else if (IOObjectConformsTo(controller, "AppleUSBEthernetHost")) {
1475 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
1476 interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
1477 interfacePrivate->sort_order = kSortTethered;
1478 } else if (IOObjectConformsTo(controller, "AppleUSBCDCECMData")) {
1479 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
1480 interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
1481 interfacePrivate->sort_order = kSortWWANEthernet;
1482 } else {
1483 str = IODictionaryCopyCFStringValue(bus_dict, CFSTR("name"));
1484 if ((str != NULL) && CFEqual(str, CFSTR("radio"))) {
1485 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; // ??
1486 interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
1487 interfacePrivate->sort_order = kSortOtherWireless;
1488 } else {
1489 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
1490 interfacePrivate->entity_type = kSCValNetInterfaceTypeEthernet;
1491 interfacePrivate->sort_order = kSortEthernet;
1492
1493 #if !TARGET_OS_IPHONE
1494 // BOND support only enabled for ethernet devices
1495 interfacePrivate->supportsBond = TRUE;
1496 #endif // !TARGET_OS_IPHONE
1497 }
1498
1499 if (str != NULL) CFRelease(str);
1500 }
1501
1502 // built-in
1503 val = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOBuiltin)));
1504 if (val == NULL) {
1505 val = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOPrimaryInterface)));
1506 }
1507 if (val != NULL) {
1508 interfacePrivate->builtin = CFBooleanGetValue(val);
1509 } else {
1510 interfacePrivate->builtin = isBuiltin(interface);
1511 }
1512
1513 if (!interfacePrivate->builtin &&
1514 CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) {
1515 // always treat AirPort interfaces as built-in
1516 interfacePrivate->builtin = TRUE;
1517 }
1518
1519 // location
1520 interfacePrivate->location = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOLocation));
1521
1522 #if !TARGET_OS_IPHONE
1523 // VLAN support
1524 num = CFDictionaryGetValue(controller_dict, CFSTR(kIOFeatures));
1525 if (isA_CFNumber(num) &&
1526 CFNumberGetValue(num, kCFNumberIntType, & iVal)) {
1527 if (iVal & (kIONetworkFeatureHardwareVlan | kIONetworkFeatureSoftwareVlan)) {
1528 interfacePrivate->supportsVLAN = TRUE;
1529 }
1530 }
1531 #endif // !TARGET_OS_IPHONE
1532
1533 // localized name
1534 if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) {
1535 interfacePrivate->localized_key = CFSTR("airport");
1536 } else if (interfacePrivate->sort_order == kSortBluetoothPAN) {
1537 interfacePrivate->localized_key = CFSTR("bluetooth-pan");
1538 } else if (interfacePrivate->sort_order == kSortOtherWireless) {
1539 interfacePrivate->localized_key = CFSTR("wireless");
1540 interfacePrivate->localized_arg1 = CFRetain(CFSTR("")); // ??
1541 } else if (interfacePrivate->builtin) {
1542 if ((interfacePrivate->location == NULL) ||
1543 (CFStringGetLength(interfacePrivate->location) == 0)) {
1544 interfacePrivate->localized_key = CFSTR("ether");
1545 } else {
1546 interfacePrivate->localized_key = CFSTR("multiether");
1547 interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->location);
1548 }
1549 } else {
1550 CFStringRef provider;
1551
1552 // check provider class
1553 provider = IORegistryEntrySearchCFProperty(interface,
1554 kIOServicePlane,
1555 CFSTR(kIOProviderClassKey),
1556 NULL,
1557 kIORegistryIterateRecursively | kIORegistryIterateParents);
1558 if (provider != NULL) {
1559 if (CFEqual(provider, CFSTR("IOPCIDevice"))) {
1560 CFStringRef port_name;
1561 CFStringRef slot_name;
1562
1563 if (pci_slot_info(interface, &slot_name, &port_name)) {
1564 if (port_name == NULL) {
1565 interfacePrivate->localized_key = CFSTR("pci-ether");
1566 interfacePrivate->localized_arg1 = slot_name;
1567 } else {
1568 interfacePrivate->localized_key = CFSTR("pci-multiether");
1569 interfacePrivate->localized_arg1 = slot_name;
1570 interfacePrivate->localized_arg2 = port_name;
1571 }
1572 }
1573 } else if (CFEqual(provider, CFSTR("IOUSBDevice")) ||
1574 CFEqual(provider, CFSTR("IOUSBInterface"))) {
1575
1576 processUSBInterface(interfacePrivate,
1577 interface,
1578 interface_dict,
1579 controller,
1580 controller_dict,
1581 bus,
1582 bus_dict);
1583
1584 // check if a "Product Name" has been provided
1585 val = IORegistryEntrySearchCFProperty(interface,
1586 kIOServicePlane,
1587 CFSTR(kIOPropertyProductNameKey),
1588 NULL,
1589 kIORegistryIterateRecursively | kIORegistryIterateParents);
1590 if ((val == NULL) && (interfacePrivate->usb.name != NULL)) {
1591 // else, use "USB Product Name" if available
1592 val = CFRetain(interfacePrivate->usb.name);
1593 }
1594 if (val != NULL) {
1595 CFStringRef productName;
1596
1597 productName = IOCopyCFStringValue(val);
1598 CFRelease(val);
1599
1600 if (productName != NULL) {
1601 if (CFStringGetLength(productName) > 0) {
1602 // if we have a [somewhat reasonable?] product name
1603 if (interfacePrivate->name != NULL) {
1604 CFRelease(interfacePrivate->name);
1605 }
1606 interfacePrivate->name = CFRetain(productName);
1607 if (interfacePrivate->localized_name != NULL) {
1608 CFRelease(interfacePrivate->localized_name);
1609 }
1610 interfacePrivate->localized_name = copy_interface_string(bundle, productName, TRUE);
1611 }
1612
1613 CFRelease(productName);
1614 }
1615 } else {
1616 interfacePrivate->localized_key = CFSTR("usb-ether");
1617 interfacePrivate->localized_arg1 = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey));
1618 }
1619 }
1620 CFRelease(provider);
1621 }
1622
1623 if (interfacePrivate->localized_key == NULL) {
1624 // if no provider, not a PCI device, or no slot information
1625 interfacePrivate->localized_key = CFSTR("generic-ether");
1626 interfacePrivate->localized_arg1 = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey));
1627 }
1628 }
1629
1630 break;
1631 case IFT_IEEE1394 :
1632 // Type
1633 interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire;
1634
1635 // Entity
1636 interfacePrivate->entity_type = kSCValNetInterfaceTypeFireWire;
1637
1638 // built-in
1639 interfacePrivate->builtin = isBuiltin(interface);
1640
1641 // sort order
1642 interfacePrivate->sort_order = kSortFireWire;
1643
1644 // localized name
1645 if (interfacePrivate->builtin) {
1646 interfacePrivate->localized_key = CFSTR("firewire");
1647 } else {
1648 CFStringRef slot_name;
1649
1650 slot_name = pci_slot(interface, NULL);
1651 if (slot_name != NULL) {
1652 interfacePrivate->localized_key = CFSTR("pci-firewire");
1653 interfacePrivate->localized_arg1 = slot_name;
1654 }
1655 }
1656
1657 break;
1658 default :
1659 SCLog(TRUE, LOG_DEBUG, CFSTR("processNetworkInterface() failed, unknown interface type = %d"), ift);
1660 return FALSE;
1661 }
1662
1663 // Device
1664 interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey));
1665
1666 // Hardware (MAC) address
1667 data = CFDictionaryGetValue(controller_dict, CFSTR(kIOMACAddress));
1668 if (isA_CFData(data)) {
1669 interfacePrivate->address = CFRetain(data);
1670 }
1671
1672 // interface unit
1673 num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceUnit));
1674 if (isA_CFNumber(num) &&
1675 CFNumberGetValue(num, kCFNumberIntType, & iVal)) {
1676 interfacePrivate->unit = CFRetain(num);
1677 }
1678
1679 return TRUE;
1680 }
1681
1682
1683 static void
1684 set_connection_script(SCNetworkInterfacePrivateRef interfacePrivate, CFStringRef script)
1685 {
1686 CFDictionaryRef dict;
1687 CFMutableDictionaryRef newDict;
1688
1689 if (interfacePrivate->overrides == NULL) {
1690 interfacePrivate->overrides = CFDictionaryCreateMutable(NULL,
1691 0,
1692 &kCFTypeDictionaryKeyCallBacks,
1693 &kCFTypeDictionaryValueCallBacks);
1694 }
1695
1696 dict = CFDictionaryGetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem);
1697 if (dict != NULL) {
1698 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
1699 } else {
1700 newDict = CFDictionaryCreateMutable(NULL,
1701 0,
1702 &kCFTypeDictionaryKeyCallBacks,
1703 &kCFTypeDictionaryValueCallBacks);
1704 }
1705 if (script != NULL) {
1706 CFDictionarySetValue(newDict, kSCPropNetModemConnectionScript, script);
1707 } else {
1708 CFDictionaryRemoveValue(newDict, kSCPropNetModemConnectionScript);
1709 }
1710 if (CFDictionaryGetCount(newDict) > 0) {
1711 CFDictionarySetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem, newDict);
1712 } else {
1713 CFDictionaryRemoveValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem);
1714 }
1715 CFRelease(newDict);
1716
1717 if (CFDictionaryGetCount(interfacePrivate->overrides) == 0) {
1718 CFRelease(interfacePrivate->overrides);
1719 interfacePrivate->overrides = NULL;
1720 }
1721 return;
1722 }
1723
1724
1725 static Boolean
1726 is_valid_connection_script(CFStringRef script)
1727 {
1728 char ccl[MAXPATHLEN];
1729 char path[MAXPATHLEN];
1730 NSSearchPathEnumerationState state;
1731
1732 (void) _SC_cfstring_to_cstring(script,
1733 ccl,
1734 sizeof(ccl),
1735 kCFStringEncodingUTF8);
1736
1737 state = NSStartSearchPathEnumeration(NSLibraryDirectory,
1738 NSLocalDomainMask|NSSystemDomainMask);
1739 while ((state = NSGetNextSearchPathEnumeration(state, path))) {
1740 size_t n;
1741 struct stat statBuf;
1742
1743 if (ccl[0] == '/') {
1744 path[0] = '\0'; // if modemCCL is a full path
1745 } else {
1746 strlcat(path, "/Modem Scripts/", sizeof(path));
1747 }
1748 strlcat(path, ccl, sizeof(path));
1749
1750 if (stat(path, &statBuf) != 0) {
1751 if (errno == ENOENT) {
1752 goto bundle;
1753 }
1754
1755 SCLog(TRUE, LOG_DEBUG,
1756 CFSTR("processSerialInterface stat() failed: %s"),
1757 strerror(errno));
1758 continue;
1759 }
1760 if (S_ISREG(statBuf.st_mode)) {
1761 // if we have a valid CCL script
1762 return TRUE;
1763 }
1764
1765 #define BUNDLE_EXT ".ccl"
1766 #define BUNDLE_EXT_LEN sizeof(BUNDLE_EXT) - 1
1767
1768 bundle :
1769
1770 n = strlen(path);
1771 if ((n <= BUNDLE_EXT_LEN) ||
1772 (strstr(&path[n - BUNDLE_EXT_LEN], BUNDLE_EXT) == NULL)) {
1773 strlcat(path, BUNDLE_EXT, sizeof(path));
1774 if (stat(path, &statBuf) != 0) {
1775 if (errno == ENOENT) {
1776 continue;
1777 }
1778
1779 SCLog(TRUE, LOG_DEBUG,
1780 CFSTR("processSerialInterface stat() failed: %s"),
1781 strerror(errno));
1782 continue;
1783 }
1784 }
1785 if (S_ISDIR(statBuf.st_mode)) {
1786 // if we have a valid CCL bundle
1787 return TRUE;
1788 }
1789 }
1790
1791 return FALSE;
1792 }
1793
1794
1795 static Boolean
1796 processSerialInterface(SCNetworkInterfacePrivateRef interfacePrivate,
1797 io_registry_entry_t interface,
1798 CFDictionaryRef interface_dict,
1799 io_registry_entry_t controller,
1800 CFDictionaryRef controller_dict,
1801 io_registry_entry_t bus,
1802 CFDictionaryRef bus_dict)
1803 {
1804 CFStringRef base = NULL;
1805 CFStringRef ift;
1806 Boolean isModem = FALSE;
1807 Boolean isWWAN = FALSE;
1808 CFStringRef modemCCL = NULL;
1809 Boolean ok = FALSE;
1810 CFTypeRef val;
1811
1812 // check if hidden
1813 val = IORegistryEntrySearchCFProperty(interface,
1814 kIOServicePlane,
1815 CFSTR("HiddenPort"),
1816 NULL,
1817 kIORegistryIterateRecursively | kIORegistryIterateParents);
1818 if (val != NULL) {
1819 CFRelease(val);
1820 return FALSE; // if this interface should not be exposed
1821 }
1822
1823 // check if initializing
1824 val = IORegistryEntrySearchCFProperty(interface,
1825 kIOServicePlane,
1826 CFSTR("Initializing"),
1827 NULL,
1828 kIORegistryIterateRecursively | kIORegistryIterateParents);
1829 if (val != NULL) {
1830 Boolean initializing;
1831
1832 initializing = isA_CFBoolean(val) && CFBooleanGetValue(val);
1833 CFRelease(val);
1834 if (initializing) {
1835 return FALSE; // if this interface is still initializing
1836 }
1837 }
1838
1839 // check if WWAN
1840 val = IORegistryEntrySearchCFProperty(interface,
1841 kIOServicePlane,
1842 CFSTR("WWAN"),
1843 NULL,
1844 kIORegistryIterateRecursively | kIORegistryIterateParents);
1845 if (val != NULL) {
1846 isWWAN = isA_CFBoolean(val) && CFBooleanGetValue(val);
1847 CFRelease(val);
1848 }
1849
1850 // Entity (Device)
1851 interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOTTYDeviceKey));
1852 if (interfacePrivate->entity_device == NULL) {
1853 return FALSE;
1854 }
1855
1856 base = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOTTYBaseNameKey));
1857 if (base == NULL) {
1858 base = CFRetain(interfacePrivate->entity_device);
1859 }
1860
1861 /*
1862 * From MoreSCF:
1863 *
1864 * Exclude ports named "irda" because otherwise the IrDA ports on the
1865 * original iMac (rev's A through D) show up as serial ports. Given
1866 * that only the rev A actually had an IrDA port, and Mac OS X doesn't
1867 * even support it, these ports definitely shouldn't be listed.
1868 */
1869 if (CFStringCompare(base,
1870 CFSTR("irda"),
1871 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
1872 goto done;
1873 }
1874
1875 if (IOStringValueHasPrefix(base, CFSTR("bluetooth"))) {
1876 Boolean haveController = FALSE;
1877
1878 // Bluetooth
1879 interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth;
1880 interfacePrivate->sort_order = kSortBluetooth;
1881 interfacePrivate->builtin = isBluetoothBuiltin(&haveController);
1882 if (!haveController) {
1883 // if device with no controller present
1884 goto done;
1885 }
1886 } else if (IOStringValueHasPrefix(base, CFSTR("irda-ircomm"))) {
1887 // IrDA
1888 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA;
1889 interfacePrivate->sort_order = kSortIrDA;
1890 } else if (isWWAN) {
1891 // WWAN
1892 interfacePrivate->interface_type = kSCNetworkInterfaceTypeWWAN;
1893 interfacePrivate->sort_order = kSortWWAN;
1894 } else {
1895 // Modem
1896 interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem;
1897 interfacePrivate->sort_order = kSortModem;
1898
1899 // V.92 support
1900 val = IORegistryEntrySearchCFProperty(interface,
1901 kIOServicePlane,
1902 CFSTR(kIODeviceSupportsHoldKey),
1903 NULL,
1904 kIORegistryIterateRecursively | kIORegistryIterateParents);
1905 if (val != NULL) {
1906 uint32_t v92;
1907
1908 if (isA_CFNumber(val) &&
1909 CFNumberGetValue(val, kCFNumberSInt32Type, &v92)) {
1910 interfacePrivate->modemIsV92 = (v92 == 1);
1911 }
1912 CFRelease(val);
1913 }
1914 }
1915
1916 // Entity (Type)
1917 interfacePrivate->entity_type = kSCEntNetModem;
1918
1919 // Entity (Hardware)
1920 ift = CFDictionaryGetValue(interface_dict, CFSTR(kIOSerialBSDTypeKey));
1921 if (!isA_CFString(ift)) {
1922 goto done;
1923 }
1924
1925 if (CFEqual(ift, CFSTR(kIOSerialBSDModemType))) {
1926 // if modem
1927 isModem = TRUE;
1928
1929 if (CFEqual(base, CFSTR("modem"))) {
1930 interfacePrivate->builtin = TRUE;
1931 interfacePrivate->sort_order = kSortInternalModem;
1932 } else if (CFEqual(base, CFSTR("usbmodem"))) {
1933 interfacePrivate->sort_order = kSortUSBModem;
1934 }
1935 } else if (CFEqual(ift, CFSTR(kIOSerialBSDRS232Type))) {
1936 // if serial port
1937 interfacePrivate->sort_order = kSortSerialPort;
1938 } else {
1939 goto done;
1940 }
1941
1942 // configuration template overrides
1943 val = IORegistryEntrySearchCFProperty(interface,
1944 kIOServicePlane,
1945 CFSTR("DevicePPPOverrides"),
1946 NULL,
1947 kIORegistryIterateRecursively | kIORegistryIterateParents);
1948 if (val != NULL) {
1949 if (isA_CFDictionary(val)) {
1950 if (interfacePrivate->overrides == NULL) {
1951 interfacePrivate->overrides = CFDictionaryCreateMutable(NULL,
1952 0,
1953 &kCFTypeDictionaryKeyCallBacks,
1954 &kCFTypeDictionaryValueCallBacks);
1955 }
1956 CFDictionarySetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypePPP, val);
1957 }
1958 CFRelease(val);
1959 }
1960
1961 val = IORegistryEntrySearchCFProperty(interface,
1962 kIOServicePlane,
1963 CFSTR("DeviceModemOverrides"),
1964 NULL,
1965 kIORegistryIterateRecursively | kIORegistryIterateParents);
1966 if (val != NULL) {
1967 if (isA_CFDictionary(val)) {
1968 CFStringRef uniqueID;
1969
1970 if (interfacePrivate->overrides == NULL) {
1971 interfacePrivate->overrides = CFDictionaryCreateMutable(NULL,
1972 0,
1973 &kCFTypeDictionaryKeyCallBacks,
1974 &kCFTypeDictionaryValueCallBacks);
1975 }
1976 CFDictionarySetValue(interfacePrivate->overrides, kSCNetworkInterfaceTypeModem, val);
1977
1978 modemCCL = CFDictionaryGetValue(val, kSCPropNetModemConnectionScript);
1979 modemCCL = isA_CFString(modemCCL);
1980
1981 uniqueID = CFDictionaryGetValue(val, CFSTR("UniqueIdentifier"));
1982 uniqueID = isA_CFString(uniqueID);
1983 if (uniqueID != NULL) {
1984 // retain the device's base name and the unique id
1985 CFRelease(interfacePrivate->entity_device);
1986 interfacePrivate->entity_device = CFRetain(base);
1987 interfacePrivate->entity_device_unique = CFStringCreateCopy(NULL, uniqueID);
1988 }
1989 }
1990 CFRelease(val);
1991 }
1992
1993 // if not part of the DeviceModemOverrides, look harder for the modem CCL
1994 if (modemCCL == NULL) {
1995 val = IORegistryEntrySearchCFProperty(interface,
1996 kIOServicePlane,
1997 CFSTR("ModemCCL"),
1998 NULL,
1999 kIORegistryIterateRecursively | kIORegistryIterateParents);
2000 if (val != NULL) {
2001 modemCCL = IOCopyCFStringValue(val);
2002 if (modemCCL != NULL) {
2003 set_connection_script(interfacePrivate, modemCCL);
2004 CFRelease(modemCCL);
2005 }
2006
2007 CFRelease(val);
2008 }
2009 }
2010
2011 // localized name
2012 if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIrDA)) {
2013 interfacePrivate->localized_key = CFSTR("irda");
2014 } else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBluetooth)) {
2015 interfacePrivate->localized_key = CFSTR("bluetooth");
2016 } else {
2017 CFStringRef localized = NULL;
2018 CFStringRef name = NULL;
2019 CFMutableStringRef port;
2020
2021 port = CFStringCreateMutableCopy(NULL, 0, base);
2022 CFStringLowercase(port, NULL);
2023
2024 if (!isModem) {
2025 CFStringAppend(port, CFSTR("-port"));
2026 }
2027
2028 // set non-localized name
2029 if (bundle != NULL) {
2030 name = copy_interface_string(bundle, port, FALSE);
2031 }
2032 if (name != NULL) {
2033 if (!CFEqual(port, name)) {
2034 // if [English] localization available
2035 interfacePrivate->name = name;
2036 } else {
2037 // if no [English] localization available, use TTY base name
2038 CFRelease(name);
2039 interfacePrivate->name = CFStringCreateCopy(NULL, base);
2040 }
2041 } else {
2042 interfacePrivate->name = CFStringCreateCopy(NULL, base);
2043 }
2044
2045 // set localized name
2046 if (bundle != NULL) {
2047 localized = copy_interface_string(bundle, port, TRUE);
2048 }
2049 if (localized != NULL) {
2050 if (!CFEqual(port, localized)) {
2051 // if localization available
2052 interfacePrivate->localized_name = localized;
2053 } else {
2054 // if no localization available, use TTY base name
2055 CFRelease(localized);
2056 interfacePrivate->localized_name = CFStringCreateCopy(NULL, base);
2057 }
2058 } else {
2059 interfacePrivate->localized_name = CFStringCreateCopy(NULL, base);
2060 }
2061
2062 if (!isModem || !CFEqual(base, CFSTR("modem"))) {
2063 CFStringRef productName;
2064
2065 // check if a "Product Name" has been provided
2066 val = IORegistryEntrySearchCFProperty(interface,
2067 kIOServicePlane,
2068 CFSTR(kIOPropertyProductNameKey),
2069 NULL,
2070 kIORegistryIterateRecursively | kIORegistryIterateParents);
2071 if (val == NULL) {
2072 // check if a "USB Product Name" has been provided
2073 val = IORegistryEntrySearchCFProperty(interface,
2074 kIOServicePlane,
2075 CFSTR(kUSBProductString),
2076 NULL,
2077 kIORegistryIterateRecursively | kIORegistryIterateParents);
2078 }
2079 if (val != NULL) {
2080 productName = IOCopyCFStringValue(val);
2081 CFRelease(val);
2082
2083 if (productName != NULL) {
2084 if (CFStringGetLength(productName) > 0) {
2085 // if we have a [somewhat reasonable?] product name
2086 if (interfacePrivate->name != NULL) {
2087 CFRelease(interfacePrivate->name);
2088 }
2089 interfacePrivate->name = CFRetain(productName);
2090 if (interfacePrivate->localized_name != NULL) {
2091 CFRelease(interfacePrivate->localized_name);
2092 }
2093 interfacePrivate->localized_name = copy_interface_string(bundle, productName, TRUE);
2094
2095 // if not provided, also check if the product name
2096 // matches a CCL script
2097 if ((modemCCL == NULL) &&
2098 is_valid_connection_script(productName)) {
2099 set_connection_script(interfacePrivate, productName);
2100 }
2101 }
2102
2103 CFRelease(productName);
2104 }
2105 }
2106 }
2107
2108 CFRelease(port);
2109 }
2110
2111 ok = TRUE;
2112
2113 done :
2114
2115 if (!ok && (interfacePrivate->entity_device != NULL)) {
2116 CFRelease(interfacePrivate->entity_device);
2117 interfacePrivate->entity_device = NULL;
2118 }
2119 if (base != NULL) CFRelease(base);
2120
2121 return ok;
2122 }
2123
2124
2125 static SCNetworkInterfaceRef
2126 createInterface(io_registry_entry_t interface, processInterface func)
2127 {
2128 io_registry_entry_t bus = MACH_PORT_NULL;
2129 CFMutableDictionaryRef bus_dict = NULL;
2130 io_registry_entry_t controller = MACH_PORT_NULL;
2131 CFMutableDictionaryRef controller_dict = NULL;
2132 SCNetworkInterfacePrivateRef interfacePrivate = NULL;
2133 CFMutableDictionaryRef interface_dict = NULL;
2134 kern_return_t kr;
2135 io_string_t path;
2136
2137 kr = IORegistryEntryGetPath(interface, kIOServicePlane, path);
2138 if (kr != kIOReturnSuccess) {
2139 SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetPath() failed, kr = 0x%x"), kr);
2140 goto done;
2141 }
2142
2143 kr = IORegistryEntryCreateCFProperties(interface, &interface_dict, NULL, kNilOptions);
2144 if (kr != kIOReturnSuccess) {
2145 SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
2146 goto done;
2147 }
2148
2149 /* get the controller node */
2150 kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &controller);
2151 if (kr != KERN_SUCCESS) {
2152 SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
2153 goto done;
2154 }
2155
2156 /* get the dictionary associated with the node */
2157 kr = IORegistryEntryCreateCFProperties(controller, &controller_dict, NULL, kNilOptions);
2158 if (kr != KERN_SUCCESS) {
2159 SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
2160 goto done;
2161 }
2162
2163 /* get the bus node */
2164 kr = IORegistryEntryGetParentEntry(controller, kIOServicePlane, &bus);
2165 if (kr != KERN_SUCCESS) {
2166 SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
2167 goto done;
2168 }
2169
2170 /* get the dictionary associated with the node */
2171 kr = IORegistryEntryCreateCFProperties(bus, &bus_dict, NULL, kNilOptions);
2172 if (kr != KERN_SUCCESS) {
2173 SCLog(TRUE, LOG_DEBUG, CFSTR("createInterface IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
2174 goto done;
2175 }
2176
2177 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL, path);
2178
2179 if ((*func)(interfacePrivate, interface, interface_dict, controller, controller_dict, bus, bus_dict)) {
2180 CFTypeRef val;
2181
2182 /* check user-notification / auto-configuration preferences */
2183 val = IORegistryEntrySearchCFProperty(interface,
2184 kIOServicePlane,
2185 kSCNetworkInterfaceConfigurationActionKey,
2186 NULL,
2187 kIORegistryIterateRecursively | kIORegistryIterateParents);
2188 if (val != NULL) {
2189 if (isA_CFString(val)) {
2190 interfacePrivate->configurationAction = CFRetain(val);
2191 }
2192 CFRelease(val);
2193 }
2194 } else {
2195 CFRelease(interfacePrivate);
2196 interfacePrivate = NULL;
2197 }
2198
2199 done :
2200
2201 if (interface_dict != NULL) CFRelease(interface_dict);
2202
2203 if (controller != MACH_PORT_NULL) IOObjectRelease(controller);
2204 if (controller_dict != NULL) CFRelease(controller_dict);
2205
2206 if (bus != MACH_PORT_NULL) IOObjectRelease(bus);
2207 if (bus_dict != NULL) CFRelease(bus_dict);
2208
2209 return (SCNetworkInterfaceRef)interfacePrivate;
2210 }
2211
2212
2213 static CFArrayRef
2214 findMatchingInterfaces(CFDictionaryRef matching, processInterface func)
2215 {
2216 CFMutableArrayRef interfaces;
2217 io_registry_entry_t interface;
2218 kern_return_t kr;
2219 io_iterator_t iterator = MACH_PORT_NULL;
2220
2221 kr = IOServiceGetMatchingServices(masterPort, matching, &iterator);
2222 if (kr != kIOReturnSuccess) {
2223 SCLog(TRUE, LOG_DEBUG, CFSTR("findMatchingInterfaces IOServiceGetMatchingServices() failed, kr = 0x%x"), kr);
2224 return NULL;
2225 }
2226
2227 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2228
2229 while ((interface = IOIteratorNext(iterator)) != MACH_PORT_NULL) {
2230 SCNetworkInterfaceRef match;
2231
2232 match = createInterface(interface, func);
2233 if (match != NULL) {
2234 CFArrayAppendValue(interfaces, match);
2235 CFRelease(match);
2236 }
2237
2238 IOObjectRelease(interface);
2239 }
2240
2241 IOObjectRelease(iterator);
2242
2243 return interfaces;
2244 }
2245
2246
2247 #pragma mark -
2248 #pragma mark helper functions
2249
2250
2251 static CFIndex
2252 findConfiguration(CFStringRef interface_type)
2253 {
2254 CFIndex i;
2255
2256 for (i = 0; i < sizeof(configurations)/sizeof(configurations[0]); i++) {
2257 if (CFEqual(interface_type, *configurations[i].interface_type)) {
2258 return i;
2259 }
2260 }
2261
2262 return kCFNotFound;
2263 }
2264
2265
2266 __private_extern__
2267 CFStringRef
2268 __SCNetworkInterfaceGetDefaultConfigurationType(SCNetworkInterfaceRef interface)
2269 {
2270 CFIndex interfaceIndex;
2271 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2272
2273 if (interfacePrivate->serviceID == NULL) {
2274 // if not associated with a service (yet)
2275 _SCErrorSet(kSCStatusInvalidArgument);
2276 return NULL;
2277 }
2278
2279 interfaceIndex = findConfiguration(interfacePrivate->interface_type);
2280 if (interfaceIndex == kCFNotFound) {
2281 // unknown interface type, use per-service configuration preferences
2282 return interfacePrivate->interface_type; // entity
2283 }
2284
2285 if (configurations[interfaceIndex].entity_hardware != NULL) {
2286 // if configuration information can be associated with this interface type
2287 return *configurations[interfaceIndex].entity_hardware;
2288 }
2289
2290 _SCErrorSet(kSCStatusInvalidArgument);
2291 return NULL;
2292 }
2293
2294
2295 __private_extern__
2296 Boolean
2297 __SCNetworkInterfaceIsValidExtendedConfigurationType(SCNetworkInterfaceRef interface,
2298 CFStringRef extendedType,
2299 Boolean requirePerInterface)
2300 {
2301 CFStringRef defaultType;
2302 CFIndex extendedIndex;
2303 CFIndex interfaceIndex;
2304 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2305 Boolean isL2TP = FALSE;
2306 Boolean ok = FALSE;
2307
2308 defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
2309 if (defaultType == NULL) {
2310 goto done;
2311 }
2312
2313 if (CFEqual(extendedType, defaultType)) {
2314 // extended and default configuration types cannot conflict
2315 goto done;
2316 }
2317
2318 interfaceIndex = findConfiguration(interfacePrivate->interface_type);
2319 if (interfaceIndex == kCFNotFound) {
2320 // configuration information for unknown interface type's
2321 // are stored along with the service and we don't allow
2322 // per-service extended configurations
2323 goto done;
2324 }
2325
2326 if (CFEqual(extendedType, kSCEntNetIPSec)) {
2327 CFStringRef interfaceType;
2328
2329 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
2330 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
2331 SCNetworkInterfaceRef child;
2332
2333 child = SCNetworkInterfaceGetInterface(interface);
2334 if (child != NULL) {
2335 interfaceType = SCNetworkInterfaceGetInterfaceType(child);
2336 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
2337 isL2TP = TRUE;
2338 }
2339 }
2340 }
2341 }
2342
2343 if (requirePerInterface &&
2344 !configurations[interfaceIndex].per_interface_config &&
2345 !isL2TP) {
2346 // we don't allow per-service extended configurations (except
2347 // that we do allow IPSec as an extended type for PPP->L2TP)
2348 goto done;
2349 }
2350
2351 extendedIndex = findConfiguration(extendedType);
2352 if ((extendedIndex != kCFNotFound) && !isL2TP) {
2353 // extended type cannot match a known interface type (except
2354 // that we do allow IPSec as an extended type for PPP->L2TP)
2355 goto done;
2356 }
2357
2358 /*
2359 * ???
2360 * Do we match specific/known extended configuration types (e.g. EAPOL)
2361 * and ensure that any non-standard extended configuration types be of
2362 * the form com.myCompany.myType?
2363 * ???
2364 */
2365
2366 ok = TRUE;
2367
2368 done :
2369
2370 if (!ok) {
2371 _SCErrorSet(kSCStatusInvalidArgument);
2372 }
2373 return ok;
2374 }
2375
2376
2377 typedef struct {
2378 CFStringRef defaultType;
2379 CFMutableArrayRef types;
2380 } extendedConfiguration, *extendedConfigurationRef;
2381
2382
2383 static void
2384 __addExtendedConfigurationType(const void *key, const void *value, void *context)
2385 {
2386 CFStringRef extendedType = (CFStringRef)key;
2387 extendedConfigurationRef myContextRef = (extendedConfigurationRef)context;
2388
2389 if (CFEqual(extendedType, myContextRef->defaultType)) {
2390 // do not include the default configuration type
2391 return;
2392 }
2393
2394 if (CFArrayContainsValue(myContextRef->types,
2395 CFRangeMake(0, CFArrayGetCount(myContextRef->types)),
2396 extendedType)) {
2397 // if extendedType already has already been added
2398 return;
2399 }
2400
2401 CFArrayAppendValue(myContextRef->types, extendedType);
2402
2403 return;
2404 }
2405
2406
2407 static CFArrayRef
2408 extendedConfigurationTypes(SCNetworkInterfaceRef interface)
2409 {
2410 CFIndex i;
2411 CFIndex interfaceIndex;
2412 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2413 extendedConfiguration myContext;
2414 SCNetworkServiceRef service;
2415 CFArrayRef sets;
2416 CFIndex n;
2417
2418 myContext.defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
2419 if (myContext.defaultType == NULL) {
2420 myContext.types = NULL;
2421 goto done;
2422 }
2423
2424 myContext.types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2425
2426 if (interfacePrivate->serviceID == NULL) {
2427 // if not associated with a service (yet)
2428 goto done;
2429 }
2430
2431 interfaceIndex = findConfiguration(interfacePrivate->interface_type);
2432 if (interfaceIndex == kCFNotFound) {
2433 // we don't allow per-service extended configurations
2434 goto done;
2435 }
2436
2437 if (!configurations[interfaceIndex].per_interface_config) {
2438 // known interface type but we still don't allow
2439 // per-service extended configurations
2440 goto done;
2441 }
2442
2443 service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
2444 interfacePrivate->prefs,
2445 interfacePrivate->serviceID,
2446 interface);
2447
2448 sets = SCNetworkSetCopyAll(interfacePrivate->prefs);
2449 n = (sets != NULL) ? CFArrayGetCount(sets) : 0;
2450
2451 for (i = 0; i < n; i++) {
2452 CFDictionaryRef configs;
2453 Boolean found;
2454 CFStringRef path;
2455 CFArrayRef services;
2456 SCNetworkSetRef set;
2457
2458 set = CFArrayGetValueAtIndex(sets, i);
2459 services = SCNetworkSetCopyServices(set);
2460 found = CFArrayContainsValue(services,
2461 CFRangeMake(0, CFArrayGetCount(services)),
2462 service);
2463 CFRelease(services);
2464
2465 if (!found) {
2466 continue;
2467 }
2468
2469 // add stored extended configuration types
2470 path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator
2471 SCNetworkSetGetSetID(set), // set
2472 interfacePrivate->entity_device, // service
2473 NULL); // entity
2474 configs = __getPrefsConfiguration(interfacePrivate->prefs, path);
2475 CFRelease(path);
2476 if (isA_CFDictionary(configs)) {
2477 CFDictionaryApplyFunction(configs,
2478 __addExtendedConfigurationType,
2479 &myContext);
2480 }
2481
2482 // add not-yet-stored extended configuration types
2483 if (interfacePrivate->unsaved != NULL) {
2484 CFDictionaryApplyFunction(interfacePrivate->unsaved,
2485 __addExtendedConfigurationType,
2486 &myContext);
2487 }
2488
2489 break;
2490 }
2491
2492 CFRelease(service);
2493 if (sets != NULL) CFRelease(sets);
2494
2495 done :
2496
2497 return myContext.types;
2498 }
2499
2500
2501 static CFArrayRef
2502 copyConfigurationPaths(SCNetworkInterfacePrivateRef interfacePrivate,
2503 CFStringRef extendedType)
2504 {
2505 CFMutableArrayRef array;
2506 CFIndex i;
2507 CFIndex interfaceIndex;
2508 CFIndex n;
2509 CFStringRef path;
2510 SCNetworkServiceRef service;
2511 CFArrayRef sets;
2512
2513 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2514
2515 interfaceIndex = findConfiguration(interfacePrivate->interface_type);
2516 if (interfaceIndex == kCFNotFound) {
2517 // unknown interface type, use per-service configuration preferences
2518 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
2519 interfacePrivate->serviceID, // service
2520 extendedType); // entity
2521 CFArrayAppendValue(array, path);
2522 CFRelease(path);
2523 return array;
2524 }
2525
2526 if (!configurations[interfaceIndex].per_interface_config) {
2527 // known interface type, per-service configuration preferences
2528 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
2529 interfacePrivate->serviceID, // service
2530 extendedType); // entity
2531 CFArrayAppendValue(array, path);
2532 CFRelease(path);
2533 return array;
2534 }
2535
2536 // known interface type, per-interface configuration preferences
2537 //
2538 // 1. look for all sets which contain the associated service
2539 // 2. add a per-set path for the interface configuration for
2540 // each set.
2541
2542 service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
2543 interfacePrivate->prefs,
2544 interfacePrivate->serviceID,
2545 (SCNetworkInterfaceRef)interfacePrivate);
2546
2547 sets = SCNetworkSetCopyAll(interfacePrivate->prefs);
2548 n = (sets != NULL) ? CFArrayGetCount(sets) : 0;
2549
2550 for (i = 0; i < n; i++) {
2551 CFArrayRef services;
2552 SCNetworkSetRef set;
2553
2554 set = CFArrayGetValueAtIndex(sets, i);
2555 services = SCNetworkSetCopyServices(set);
2556 if (CFArrayContainsValue(services,
2557 CFRangeMake(0, CFArrayGetCount(services)),
2558 service)) {
2559 path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator
2560 SCNetworkSetGetSetID(set), // set
2561 interfacePrivate->entity_device, // service
2562 extendedType); // entity
2563 CFArrayAppendValue(array, path);
2564 CFRelease(path);
2565 }
2566 CFRelease(services);
2567 }
2568
2569 if (CFArrayGetCount(array) == 0) {
2570 CFRelease(array);
2571 array = NULL;
2572 }
2573
2574 CFRelease(service);
2575 if (sets != NULL) CFRelease(sets);
2576 return array;
2577 }
2578
2579
2580 #pragma mark -
2581 #pragma mark SCNetworkInterface <--> preferences entity
2582
2583
2584 __private_extern__
2585 CFDictionaryRef
2586 __SCNetworkInterfaceCopyInterfaceEntity(SCNetworkInterfaceRef interface)
2587 {
2588 CFMutableDictionaryRef entity;
2589 CFIndex interfaceIndex;
2590 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2591
2592 entity = CFDictionaryCreateMutable(NULL,
2593 0,
2594 &kCFTypeDictionaryKeyCallBacks,
2595 &kCFTypeDictionaryValueCallBacks);
2596 if (interfacePrivate->entity_type != NULL) {
2597 CFDictionarySetValue(entity,
2598 kSCPropNetInterfaceType,
2599 interfacePrivate->entity_type);
2600 }
2601 if (interfacePrivate->entity_subtype != NULL) {
2602 CFDictionarySetValue(entity,
2603 kSCPropNetInterfaceSubType,
2604 interfacePrivate->entity_subtype);
2605 }
2606 if (interfacePrivate->entity_device != NULL) {
2607 CFDictionarySetValue(entity,
2608 kSCPropNetInterfaceDeviceName,
2609 interfacePrivate->entity_device);
2610 }
2611 if (interfacePrivate->entity_device_unique != NULL) {
2612 CFDictionarySetValue(entity,
2613 CFSTR("DeviceUniqueIdentifier"),
2614 interfacePrivate->entity_device_unique);
2615 }
2616
2617 // match the "hardware" with the lowest layer
2618 while (TRUE) {
2619 SCNetworkInterfaceRef nextInterface;
2620
2621 nextInterface = SCNetworkInterfaceGetInterface(interface);
2622 if (nextInterface == NULL) {
2623 break;
2624 }
2625
2626 interface = nextInterface;
2627 }
2628 interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2629
2630 if (CFEqual(interface, kSCNetworkInterfaceIPv4)) {
2631 return entity;
2632 }
2633
2634 interfaceIndex = findConfiguration(interfacePrivate->interface_type);
2635 if (interfaceIndex != kCFNotFound) {
2636 if (configurations[interfaceIndex].entity_hardware != NULL) {
2637 CFDictionarySetValue(entity,
2638 kSCPropNetInterfaceHardware,
2639 *configurations[interfaceIndex].entity_hardware);
2640 }
2641 } else {
2642 CFDictionarySetValue(entity,
2643 kSCPropNetInterfaceHardware,
2644 interfacePrivate->interface_type);
2645 }
2646
2647 // add the localized display name (which will only be used when/if the
2648 // interface is removed from the system)
2649 CFDictionarySetValue(entity,
2650 kSCPropUserDefinedName,
2651 SCNetworkInterfaceGetLocalizedDisplayName(interface));
2652
2653 // note that this is a V.92 capable modem
2654 if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeModem) &&
2655 interfacePrivate->modemIsV92) {
2656 int one = 1;
2657 CFNumberRef num;
2658
2659 num = CFNumberCreate(NULL, kCFNumberIntType, &one);
2660 CFDictionarySetValue(entity,
2661 kSCPropNetInterfaceSupportsModemOnHold,
2662 num);
2663 CFRelease(num);
2664 }
2665
2666 return entity;
2667 }
2668
2669
2670 #if !TARGET_OS_IPHONE
2671 static SCNetworkInterfaceRef
2672 findInterface(CFArrayRef interfaces, CFStringRef match_if)
2673 {
2674 CFIndex i;
2675 CFIndex n;
2676
2677 n = CFArrayGetCount(interfaces);
2678 for (i = 0; i < n; i++) {
2679 SCNetworkInterfaceRef interface = CFArrayGetValueAtIndex(interfaces, i);
2680 CFStringRef interfaceName;
2681
2682 interfaceName = SCNetworkInterfaceGetBSDName(interface);
2683 if ((interfaceName != NULL) && CFEqual(interfaceName, match_if)) {
2684 CFRetain(interface);
2685 return interface;
2686 }
2687 }
2688
2689 return NULL;
2690 }
2691
2692
2693 static SCNetworkInterfaceRef
2694 findBondInterface(SCPreferencesRef prefs, CFStringRef ifDevice)
2695 {
2696 CFArrayRef bonds;
2697 SCNetworkInterfaceRef interface = NULL;
2698
2699 if (prefs == NULL) {
2700 return (NULL);
2701 }
2702
2703 // check if the interface is an Ethernet Bond
2704 bonds = SCBondInterfaceCopyAll(prefs);
2705 if (bonds != NULL) {
2706 interface = findInterface(bonds, ifDevice);
2707 CFRelease(bonds);
2708 }
2709 return interface;
2710 }
2711
2712 static SCNetworkInterfaceRef
2713 findVLANInterface(SCPreferencesRef prefs, CFStringRef ifDevice)
2714 {
2715 SCNetworkInterfaceRef interface = NULL;
2716 CFArrayRef vlans;
2717
2718 if (prefs == NULL) {
2719 return (NULL);
2720 }
2721
2722 // check if the interface is a VLAN
2723 vlans = SCVLANInterfaceCopyAll(prefs);
2724 if (vlans != NULL) {
2725 interface = findInterface(vlans, ifDevice);
2726 CFRelease(vlans);
2727 }
2728 return interface;
2729 }
2730 #endif // !TARGET_OS_IPHONE
2731
2732
2733 SCNetworkInterfaceRef
2734 _SCNetworkInterfaceCreateWithBSDName(CFAllocatorRef allocator,
2735 CFStringRef bsdName,
2736 UInt32 flags)
2737 {
2738 CFMutableDictionaryRef entity;
2739 SCNetworkInterfaceRef interface;
2740
2741 entity = CFDictionaryCreateMutable(NULL,
2742 0,
2743 &kCFTypeDictionaryKeyCallBacks,
2744 &kCFTypeDictionaryValueCallBacks);
2745 CFDictionarySetValue(entity, kSCPropNetInterfaceDeviceName, bsdName);
2746 #if !TARGET_OS_IPHONE
2747 if ((flags & kIncludeBondInterfaces) == 0) {
2748 CFDictionarySetValue(entity, CFSTR("_NO_BOND_INTERFACES_"), kCFBooleanTrue);
2749 }
2750 if ((flags & kIncludeVLANInterfaces) == 0) {
2751 CFDictionarySetValue(entity, CFSTR("_NO_VLAN_INTERFACES_"), kCFBooleanTrue);
2752 }
2753 #endif // !TARGET_OS_IPHONE
2754 interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, NULL);
2755 CFRelease(entity);
2756
2757 return interface;
2758 }
2759
2760
2761 static void
2762 __SCNetworkInterfaceSetService(SCNetworkInterfaceRef interface,
2763 SCNetworkServiceRef service)
2764 {
2765 SCNetworkInterfacePrivateRef interfacePrivate;
2766 SCNetworkServicePrivateRef servicePrivate;
2767
2768 interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2769 if (interfacePrivate->prefs != NULL) {
2770 CFRelease(interfacePrivate->prefs);
2771 interfacePrivate->prefs = NULL;
2772 }
2773 if (interfacePrivate->serviceID != NULL) {
2774 CFRelease(interfacePrivate->serviceID);
2775 interfacePrivate->serviceID = NULL;
2776 }
2777
2778 servicePrivate = (SCNetworkServicePrivateRef)service;
2779 if (servicePrivate->prefs != NULL) {
2780 interfacePrivate->prefs = CFRetain(servicePrivate->prefs);
2781 }
2782 if (servicePrivate->serviceID != NULL) {
2783 interfacePrivate->serviceID = CFRetain(servicePrivate->serviceID);
2784 }
2785
2786 return;
2787 }
2788
2789
2790 static Boolean
2791 _SCNetworkInterfaceMatchesName(CFStringRef name, CFStringRef key)
2792 {
2793 Boolean match;
2794 CFStringRef str;
2795
2796 if (bundle == NULL) {
2797 // if no bundle
2798 return FALSE;
2799 }
2800
2801 if (!isA_CFString(name)) {
2802 // if no interface "name"
2803 return FALSE;
2804 }
2805
2806 // check non-localized name for a match
2807 str = copy_interface_string(bundle, key, FALSE);
2808 if (str != NULL) {
2809 match = CFEqual(name, str);
2810 CFRelease(str);
2811 if (match) {
2812 return TRUE;
2813 }
2814 }
2815
2816 // check localized name for a match
2817 str = copy_interface_string(bundle, key, TRUE);
2818 if (str != NULL) {
2819 match = CFEqual(name, str);
2820 CFRelease(str);
2821 if (match) {
2822 return TRUE;
2823 }
2824 }
2825
2826 return FALSE;
2827 }
2828
2829
2830 SCNetworkInterfaceRef
2831 _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator,
2832 CFDictionaryRef interface_entity,
2833 SCNetworkServiceRef service)
2834 {
2835 SCNetworkInterfacePrivateRef interfacePrivate = NULL;
2836 CFStringRef ifDevice;
2837 CFStringRef ifName = NULL;
2838 CFStringRef ifSubType;
2839 CFStringRef ifType;
2840 CFStringRef ifUnique;
2841 CFArrayRef matching_interfaces = NULL;
2842
2843 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2844 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2845
2846 ifType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceType);
2847 if (ifType == NULL) {
2848 /*
2849 * The interface "Type" was not specified. We'll make an
2850 * assumption that this is an "Ethernet" interface. If a
2851 * real interface exists with the provided interface name
2852 * then the actual type will be set accordingly. If not, we'll
2853 * end up crafting an "Ethernet" SCNetworkInterface which
2854 * will keep the rest of the configuration APIs happy.
2855 */
2856 ifType = kSCValNetInterfaceTypeEthernet;
2857 }
2858
2859 if (!isA_CFString(ifType)) {
2860 return NULL;
2861 }
2862
2863 ifSubType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceSubType);
2864 if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
2865 if (!isA_CFString(ifSubType)) {
2866 return NULL;
2867 }
2868 }
2869
2870 ifDevice = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceDeviceName);
2871 ifUnique = CFDictionaryGetValue(interface_entity, CFSTR("DeviceUniqueIdentifier"));
2872
2873 if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet) ||
2874 CFEqual(ifType, kSCValNetInterfaceTypeFireWire) ||
2875 (CFEqual(ifType, kSCValNetInterfaceTypePPP) && CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE))) {
2876 char bsdName[IFNAMSIZ + 1];
2877 CFMutableDictionaryRef matching;
2878
2879 if (!isA_CFString(ifDevice)) {
2880 return NULL;
2881 }
2882
2883 if (_SC_cfstring_to_cstring(ifDevice, bsdName, sizeof(bsdName), kCFStringEncodingASCII) == NULL) {
2884 goto done;
2885 }
2886
2887 matching = IOBSDNameMatching(masterPort, 0, bsdName);
2888 if (matching == NULL) {
2889 goto done;
2890 }
2891
2892 // note: the "matching" dictionary will be consumed by the following
2893 matching_interfaces = findMatchingInterfaces(matching, processNetworkInterface);
2894
2895 } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
2896 if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) {
2897 CFDictionaryRef matching;
2898 CFStringRef match_keys[2];
2899 CFStringRef match_vals[2];
2900
2901 if (!isA_CFString(ifDevice)) {
2902 return NULL;
2903 }
2904
2905 match_keys[0] = CFSTR(kIOProviderClassKey);
2906 match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
2907
2908 match_keys[1] = CFSTR(kIOTTYBaseNameKey);
2909 match_vals[1] = ifDevice;
2910
2911 matching = CFDictionaryCreate(NULL,
2912 (const void **)match_keys,
2913 (const void **)match_vals,
2914 sizeof(match_keys)/sizeof(match_keys[0]),
2915 &kCFTypeDictionaryKeyCallBacks,
2916 &kCFTypeDictionaryValueCallBacks);
2917
2918 // note: the "matching" dictionary will be consumed by the following
2919 matching_interfaces = findMatchingInterfaces(matching, processSerialInterface);
2920
2921 if (ifUnique == NULL) {
2922 CFIndex n;
2923 Boolean useDeviceName = TRUE;
2924
2925 n = (matching_interfaces != NULL) ? CFArrayGetCount(matching_interfaces) : 0;
2926 if (n > 0) {
2927 CFIndex i;
2928
2929 for (i = 0; i < n; i++) {
2930 SCNetworkInterfacePrivateRef scanPrivate;
2931
2932 scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i);
2933 if (scanPrivate->entity_device_unique != NULL) {
2934 useDeviceName = FALSE;
2935 break;
2936 }
2937 }
2938 }
2939
2940 if (useDeviceName) {
2941 if (matching_interfaces != NULL) {
2942 CFRelease(matching_interfaces);
2943 }
2944
2945 match_keys[1] = CFSTR(kIOTTYDeviceKey);
2946 matching = CFDictionaryCreate(NULL,
2947 (const void **)match_keys,
2948 (const void **)match_vals,
2949 sizeof(match_keys)/sizeof(match_keys[0]),
2950 &kCFTypeDictionaryKeyCallBacks,
2951 &kCFTypeDictionaryValueCallBacks);
2952
2953 // note: the "matching" dictionary will be consumed by the following
2954 matching_interfaces = findMatchingInterfaces(matching, processSerialInterface);
2955 }
2956 }
2957 } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypeL2TP)) {
2958 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
2959 kSCNetworkInterfaceTypeL2TP);
2960 } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPTP)) {
2961 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
2962 kSCNetworkInterfaceTypePPTP);
2963 } else {
2964 // XXX do we allow non-Apple variants of PPP??? XXX
2965 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
2966 ifSubType);
2967 }
2968 } else if (CFEqual(ifType, kSCValNetInterfaceType6to4)) {
2969 if (!isA_CFString(ifDevice)) {
2970 return NULL;
2971 }
2972
2973 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
2974 kSCNetworkInterfaceType6to4);
2975 } else if (CFEqual(ifType, kSCValNetInterfaceTypeIPSec)) {
2976 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
2977 kSCNetworkInterfaceTypeIPSec);
2978 } else if ((CFStringFind(ifType, CFSTR("."), 0).location != kCFNotFound) && (ifDevice == NULL)) {
2979 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
2980 ifType);
2981 }
2982
2983 if (matching_interfaces != NULL) {
2984 CFIndex n;
2985 SCPreferencesRef prefs;
2986
2987 n = CFArrayGetCount(matching_interfaces);
2988 switch (n) {
2989 case 1 :
2990 interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0);
2991 if (_SC_CFEqual(ifUnique, interfacePrivate->entity_device_unique)) {
2992 // if the unique ID's match
2993 CFRetain(interfacePrivate);
2994 break;
2995 }
2996
2997 interfacePrivate = NULL;
2998 // fall through
2999 case 0 :
3000 if (!CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) {
3001 break;
3002 }
3003 prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterface"), NULL);
3004 if (prefs == NULL) {
3005 break;
3006 }
3007 #if !TARGET_OS_IPHONE
3008 if (!CFDictionaryContainsKey(interface_entity, CFSTR("_NO_VLAN_INTERFACES_"))) {
3009 interfacePrivate = (SCNetworkInterfacePrivateRef)findVLANInterface(prefs, ifDevice);
3010 }
3011 if ((interfacePrivate == NULL)
3012 && !CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BOND_INTERFACES_"))) {
3013 interfacePrivate = (SCNetworkInterfacePrivateRef)findBondInterface(prefs, ifDevice);
3014 }
3015 #endif // !TARGET_OS_IPHONE
3016 CFRelease(prefs);
3017 break;
3018 default :
3019 if (ifUnique != NULL) {
3020 CFIndex i;
3021
3022 // we are looking for an interface with a unique ID
3023 // so let's try to focus our choices
3024 for (i = 0; i < n; i++) {
3025 SCNetworkInterfacePrivateRef scanPrivate;
3026
3027 scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i);
3028 if (_SC_CFEqual(ifUnique, scanPrivate->entity_device_unique)) {
3029 if (interfacePrivate != NULL) {
3030 // if we've matched more than one interface
3031 interfacePrivate = NULL;
3032 break;
3033 }
3034 interfacePrivate = scanPrivate;
3035 }
3036 }
3037 } else if (CFDictionaryGetValueIfPresent(interface_entity,
3038 kSCPropUserDefinedName,
3039 (const void **)&ifName)) {
3040 CFIndex i;
3041
3042 // we don't have a unique ID but do have an interface
3043 // name. If the matching interfaces do have IDs than
3044 // we can try to focus our choices using the name
3045 for (i = 0; i < n; i++) {
3046 SCNetworkInterfacePrivateRef scanPrivate;
3047
3048 scanPrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, i);
3049 if (scanPrivate->entity_device_unique != NULL) {
3050 SCNetworkInterfaceRef scan = (SCNetworkInterfaceRef)scanPrivate;
3051 CFStringRef scanName;
3052
3053 scanName = __SCNetworkInterfaceGetNonLocalizedDisplayName(scan);
3054 if ((scanName != NULL) && !_SC_CFEqual(ifName, scanName)) {
3055 continue; // if not the same display name
3056 }
3057 }
3058
3059 if (interfacePrivate != NULL) {
3060 // if we've matched more than one interface
3061 interfacePrivate = NULL;
3062 break;
3063 }
3064 interfacePrivate = scanPrivate;
3065 }
3066 }
3067 if (interfacePrivate == NULL) {
3068 SCLog(TRUE, LOG_ERR, CFSTR("_SCNetworkInterfaceCreateWithEntity() failed, more than one interface matches %@"), ifDevice);
3069 interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0);
3070 }
3071 CFRetain(interfacePrivate);
3072 break;
3073 }
3074 CFRelease(matching_interfaces);
3075 }
3076
3077 done :
3078
3079 if (interfacePrivate == NULL) {
3080 /*
3081 * if device not present on this system
3082 */
3083 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL, NULL);
3084 interfacePrivate->entity_type = ifType;
3085 interfacePrivate->entity_subtype = ifSubType;
3086 interfacePrivate->entity_device = (ifDevice != NULL) ? CFStringCreateCopy(NULL, ifDevice) : NULL;
3087 interfacePrivate->entity_device_unique = (ifUnique != NULL) ? CFStringCreateCopy(NULL, ifUnique) : NULL;
3088
3089 if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) {
3090 CFStringRef entity_hardware;
3091
3092 entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware);
3093 if (isA_CFString((entity_hardware)) &&
3094 CFEqual(entity_hardware, kSCEntNetAirPort)) {
3095 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
3096 interfacePrivate->sort_order = kSortAirPort;
3097 } else {
3098 CFStringRef name;
3099
3100 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
3101
3102 name = CFDictionaryGetValue(interface_entity, kSCPropUserDefinedName);
3103 if (_SCNetworkInterfaceMatchesName(name, CFSTR("iPhone"))) {
3104 interfacePrivate->sort_order = kSortTethered;
3105 } else if (_SCNetworkInterfaceMatchesName(name, CFSTR("bluetooth-pan"))) {
3106 interfacePrivate->sort_order = kSortBluetoothPAN;
3107 } else {
3108 interfacePrivate->sort_order = kSortEthernet;
3109 }
3110 }
3111 } else if (CFEqual(ifType, kSCValNetInterfaceTypeFireWire)) {
3112 interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire;
3113 interfacePrivate->sort_order = kSortFireWire;
3114 } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
3115 if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE)) {
3116 CFStringRef entity_hardware;
3117
3118 entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware);
3119 if (isA_CFString((entity_hardware)) &&
3120 CFEqual(entity_hardware, kSCEntNetAirPort)) {
3121 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
3122 interfacePrivate->sort_order = kSortAirPort;
3123 } else {
3124 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
3125 interfacePrivate->sort_order = kSortEthernet;
3126 }
3127 } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) {
3128 if (CFStringHasPrefix(ifDevice, CFSTR("Bluetooth"))) {
3129 interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth;
3130 interfacePrivate->sort_order = kSortBluetooth;
3131 } else if (CFStringHasPrefix(ifDevice, CFSTR("irda"))) {
3132 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA;
3133 interfacePrivate->sort_order = kSortIrDA;
3134 } else if (CFStringHasPrefix(ifDevice, CFSTR("wwan"))) {
3135 interfacePrivate->interface_type = kSCNetworkInterfaceTypeWWAN;
3136 interfacePrivate->sort_order = kSortWWAN;
3137 } else {
3138 interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem;
3139 interfacePrivate->sort_order = kSortModem;
3140 }
3141 } else {
3142 // PPTP, L2TP, ...
3143 CFRelease(interfacePrivate);
3144 interfacePrivate = (SCNetworkInterfacePrivateRef)kSCNetworkInterfaceIPv4;
3145 CFRetain(interfacePrivate);
3146 }
3147 } else if (CFStringFind(ifType, CFSTR("."), 0).location != kCFNotFound) {
3148 // if vendor interface
3149 interfacePrivate->interface_type = ifType;
3150 } else {
3151 // if unknown interface
3152 CFRelease(interfacePrivate);
3153 interfacePrivate = NULL;
3154 }
3155 }
3156
3157 if ((interfacePrivate != NULL) && (service != NULL)) {
3158 __SCNetworkInterfaceSetService((SCNetworkInterfaceRef)interfacePrivate,
3159 service);
3160 #if !TARGET_OS_IPHONE
3161 // set prefs & serviceID to VLANs and Bonds
3162 if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBond)) {
3163 CFIndex i;
3164 CFArrayRef members;
3165 CFIndex n;
3166
3167 members = SCBondInterfaceGetMemberInterfaces((SCNetworkInterfaceRef)interfacePrivate);
3168 n = (members != NULL) ? CFArrayGetCount(members) : 0;
3169 for (i = 0; i < n; i++) {
3170 SCNetworkInterfaceRef member;
3171
3172 member = CFArrayGetValueAtIndex(members, i);
3173 __SCNetworkInterfaceSetService(member, service);
3174 }
3175 } else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeVLAN)) {
3176 SCNetworkInterfaceRef vlan_physical;
3177
3178 vlan_physical = SCVLANInterfaceGetPhysicalInterface((SCNetworkInterfaceRef)interfacePrivate);
3179 if (vlan_physical != NULL) {
3180 __SCNetworkInterfaceSetService(vlan_physical, service);
3181 }
3182 }
3183 #endif // !TARGET_OS_IPHONE
3184 }
3185
3186 if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
3187 SCNetworkInterfaceRef parent;
3188
3189 // create parent
3190 parent = SCNetworkInterfaceCreateWithInterface((SCNetworkInterfaceRef)interfacePrivate,
3191 kSCNetworkInterfaceTypePPP);
3192 CFRelease(interfacePrivate);
3193 interfacePrivate = (SCNetworkInterfacePrivateRef)parent;
3194 }
3195
3196 return (SCNetworkInterfaceRef)interfacePrivate;
3197 }
3198
3199
3200 #pragma mark -
3201 #pragma mark SCNetworkInterface APIs
3202
3203
3204 __private_extern__
3205 CFArrayRef
3206 __SCNetworkInterfaceCopyAll_IONetworkInterface(void)
3207 {
3208 CFDictionaryRef matching;
3209 CFArrayRef new_interfaces;
3210
3211 // get Ethernet, Firewire, and AirPort interfaces
3212
3213 matching = IOServiceMatching(kIONetworkInterfaceClass);
3214 new_interfaces = findMatchingInterfaces(matching, processNetworkInterface);
3215
3216 return new_interfaces;
3217 }
3218
3219
3220 static
3221 CFArrayRef
3222 __SCNetworkInterfaceCopyAll_Modem()
3223 {
3224 CFDictionaryRef matching;
3225 CFStringRef match_keys[2];
3226 CFStringRef match_vals[2];
3227 CFArrayRef new_interfaces;
3228
3229 match_keys[0] = CFSTR(kIOProviderClassKey);
3230 match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
3231
3232 match_keys[1] = CFSTR(kIOSerialBSDTypeKey);
3233 match_vals[1] = CFSTR(kIOSerialBSDModemType);
3234
3235 matching = CFDictionaryCreate(NULL,
3236 (const void **)match_keys,
3237 (const void **)match_vals,
3238 sizeof(match_keys)/sizeof(match_keys[0]),
3239 &kCFTypeDictionaryKeyCallBacks,
3240 &kCFTypeDictionaryValueCallBacks);
3241 new_interfaces = findMatchingInterfaces(matching, processSerialInterface);
3242
3243 return new_interfaces;
3244 }
3245
3246
3247 static
3248 CFArrayRef
3249 __SCNetworkInterfaceCopyAll_RS232()
3250 {
3251 CFDictionaryRef matching;
3252 CFStringRef match_keys[2];
3253 CFStringRef match_vals[2];
3254 CFArrayRef new_interfaces;
3255
3256 match_keys[0] = CFSTR(kIOProviderClassKey);
3257 match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
3258
3259 match_keys[1] = CFSTR(kIOSerialBSDTypeKey);
3260 match_vals[1] = CFSTR(kIOSerialBSDRS232Type);
3261
3262 matching = CFDictionaryCreate(NULL,
3263 (const void **)match_keys,
3264 (const void **)match_vals,
3265 sizeof(match_keys)/sizeof(match_keys[0]),
3266 &kCFTypeDictionaryKeyCallBacks,
3267 &kCFTypeDictionaryValueCallBacks);
3268 new_interfaces = findMatchingInterfaces(matching, processSerialInterface);
3269
3270 return new_interfaces;
3271 }
3272
3273
3274 static void
3275 add_interfaces(CFMutableArrayRef all_interfaces, CFArrayRef new_interfaces)
3276 {
3277 CFIndex i;
3278 CFIndex n;
3279
3280 n = CFArrayGetCount(new_interfaces);
3281 for (i = 0; i < n; i++) {
3282 CFStringRef bsdName;
3283 SCNetworkInterfaceRef interface;
3284
3285 interface = CFArrayGetValueAtIndex(new_interfaces, i);
3286 bsdName = SCNetworkInterfaceGetBSDName(interface);
3287 if (bsdName != NULL) {
3288 CFArrayAppendValue(all_interfaces, interface);
3289 }
3290 }
3291
3292 return;
3293 }
3294
3295
3296 static void
3297 __waitForInterfaces()
3298 {
3299 CFStringRef key;
3300 CFArrayRef keys;
3301 Boolean ok;
3302 SCDynamicStoreRef store;
3303
3304 store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkInterfaceCopyAll"), NULL, NULL);
3305 if (store == NULL) {
3306 return;
3307 }
3308
3309 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" "InterfaceNamer"), kSCDynamicStoreDomainPlugin);
3310 keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
3311 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
3312 CFRelease(keys);
3313 if (!ok) {
3314 SCLog(TRUE, LOG_ERR,
3315 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"), SCErrorString(SCError()));
3316 goto done;
3317 }
3318
3319 while (TRUE) {
3320 CFArrayRef changedKeys;
3321 CFDictionaryRef dict;
3322 Boolean quiet = FALSE;
3323
3324 // check if quiet
3325 dict = SCDynamicStoreCopyValue(store, key);
3326 if (dict != NULL) {
3327 if (isA_CFDictionary(dict) &&
3328 (CFDictionaryContainsKey(dict, CFSTR("*QUIET*")) ||
3329 CFDictionaryContainsKey(dict, CFSTR("*TIMEOUT*")))) {
3330 quiet = TRUE;
3331 }
3332 CFRelease(dict);
3333 }
3334 if (quiet) {
3335 break;
3336 }
3337
3338 ok = SCDynamicStoreNotifyWait(store);
3339 if (!ok) {
3340 SCLog(TRUE, LOG_ERR,
3341 CFSTR("SCDynamicStoreNotifyWait() failed: %s"), SCErrorString(SCError()));
3342 goto done;
3343 }
3344
3345 changedKeys = SCDynamicStoreCopyNotifiedKeys(store);
3346 if (changedKeys != NULL) {
3347 CFRelease(changedKeys);
3348 }
3349 }
3350
3351 done :
3352
3353 CFRelease(key);
3354 CFRelease(store);
3355 return;
3356 }
3357
3358
3359 CFArrayRef /* of SCNetworkInterfaceRef's */
3360 SCNetworkInterfaceCopyAll()
3361 {
3362 CFMutableArrayRef all_interfaces;
3363 CFArrayRef new_interfaces;
3364 #if !TARGET_OS_IPHONE
3365 SCPreferencesRef prefs;
3366 #endif // !TARGET_OS_IPHONE
3367
3368 /* initialize runtime */
3369 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
3370
3371 /* wait for IOKit to quiesce */
3372 pthread_once(&iokit_quiet, __waitForInterfaces);
3373
3374 all_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3375
3376 // get Ethernet, Firewire, and AirPort interfaces
3377 new_interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface();
3378 if (new_interfaces != NULL) {
3379 add_interfaces(all_interfaces, new_interfaces);
3380 CFRelease(new_interfaces);
3381 }
3382
3383 // get Modem interfaces
3384 new_interfaces = __SCNetworkInterfaceCopyAll_Modem();
3385 if (new_interfaces != NULL) {
3386 add_interfaces(all_interfaces, new_interfaces);
3387 CFRelease(new_interfaces);
3388 }
3389
3390 // get serial (RS232) interfaces
3391 new_interfaces = __SCNetworkInterfaceCopyAll_RS232();
3392 if (new_interfaces != NULL) {
3393 add_interfaces(all_interfaces, new_interfaces);
3394 CFRelease(new_interfaces);
3395 }
3396
3397 #if !TARGET_OS_IPHONE
3398 // get virtual network interfaces (Bond, VLAN)
3399 prefs = SCPreferencesCreate(NULL, CFSTR("SCNetworkInterfaceCopyAll"), NULL);
3400 if (prefs != NULL) {
3401 new_interfaces = SCBondInterfaceCopyAll(prefs);
3402 if (new_interfaces != NULL) {
3403 add_interfaces(all_interfaces, new_interfaces);
3404 CFRelease(new_interfaces);
3405 }
3406
3407 new_interfaces = SCVLANInterfaceCopyAll(prefs);
3408 if (new_interfaces != NULL) {
3409 add_interfaces(all_interfaces, new_interfaces);
3410 CFRelease(new_interfaces);
3411 }
3412
3413 CFRelease(prefs);
3414 }
3415 #endif // !TARGET_OS_IPHONE
3416
3417 // all interfaces have been identified, order and return
3418 sort_interfaces(all_interfaces);
3419
3420 return all_interfaces;
3421 }
3422
3423
3424 CFArrayRef /* of kSCNetworkInterfaceTypeXXX CFStringRef's */
3425 SCNetworkInterfaceGetSupportedInterfaceTypes(SCNetworkInterfaceRef interface)
3426 {
3427 CFIndex i;
3428 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3429
3430 if (!isA_SCNetworkInterface(interface)) {
3431 _SCErrorSet(kSCStatusInvalidArgument);
3432 return NULL;
3433 }
3434
3435 if (interfacePrivate->supported_interface_types != NULL) {
3436 goto done;
3437 }
3438
3439 i = findConfiguration(interfacePrivate->interface_type);
3440 if (i != kCFNotFound) {
3441 if (configurations[i].supported_interfaces != doNone) {
3442 interfacePrivate->supported_interface_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3443 if (configurations[i].supported_interfaces & do6to4) {
3444 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceType6to4);
3445 }
3446 if (configurations[i].supported_interfaces & doL2TP) {
3447 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeL2TP);
3448 }
3449 if (configurations[i].supported_interfaces & doPPP) {
3450 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPP);
3451 }
3452 if (configurations[i].supported_interfaces & doPPTP) {
3453 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPTP);
3454 }
3455 if (configurations[i].supported_interfaces & doIPSec) {
3456 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeIPSec);
3457 }
3458 }
3459 }
3460
3461 done :
3462
3463 return interfacePrivate->supported_interface_types;
3464 }
3465
3466
3467 CFArrayRef /* of kSCNetworkProtocolTypeXXX CFStringRef's */
3468 SCNetworkInterfaceGetSupportedProtocolTypes(SCNetworkInterfaceRef interface)
3469 {
3470 CFIndex i;
3471 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3472
3473 if (!isA_SCNetworkInterface(interface)) {
3474 _SCErrorSet(kSCStatusInvalidArgument);
3475 return NULL;
3476 }
3477
3478 if (interfacePrivate->supported_protocol_types != NULL) {
3479 goto done;
3480 }
3481
3482 i = findConfiguration(interfacePrivate->interface_type);
3483 if (i != kCFNotFound) {
3484 if (configurations[i].supported_protocols != doNone) {
3485 interfacePrivate->supported_protocol_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3486 #if !TARGET_OS_IPHONE
3487 if (configurations[i].supported_protocols & doAppleTalk) {
3488 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeAppleTalk);
3489 }
3490 #endif // !TARGET_OS_IPHONE
3491 if (configurations[i].supported_protocols & doDNS) {
3492 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeDNS);
3493 }
3494 if (configurations[i].supported_protocols & doIPv4) {
3495 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv4);
3496 }
3497 if (configurations[i].supported_protocols & doIPv6) {
3498 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv6);
3499 }
3500 if (configurations[i].supported_protocols & doProxies) {
3501 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeProxies);
3502 }
3503 #if !TARGET_OS_IPHONE
3504 if (configurations[i].supported_protocols & doSMB) {
3505 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeSMB);
3506 }
3507 #endif // !TARGET_OS_IPHONE
3508 }
3509 }
3510
3511 done :
3512
3513 return interfacePrivate->supported_protocol_types;
3514 }
3515
3516
3517 SCNetworkInterfaceRef
3518 SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef interfaceType)
3519 {
3520 SCNetworkInterfacePrivateRef childPrivate = (SCNetworkInterfacePrivateRef)child;
3521 CFIndex childIndex;
3522 SCNetworkInterfacePrivateRef parentPrivate;
3523
3524 if (!isA_SCNetworkInterface(child)) {
3525 _SCErrorSet(kSCStatusInvalidArgument);
3526 return NULL;
3527 }
3528
3529 if (!isA_CFString(interfaceType)) {
3530 _SCErrorSet(kSCStatusInvalidArgument);
3531 return NULL;
3532 }
3533
3534 childIndex = findConfiguration(childPrivate->interface_type);
3535
3536 parentPrivate = __SCNetworkInterfaceCreatePrivate(NULL,
3537 child,
3538 childPrivate->prefs,
3539 childPrivate->serviceID,
3540 NULL);
3541 if (parentPrivate == NULL) {
3542 _SCErrorSet(kSCStatusFailed);
3543 return NULL;
3544 }
3545
3546 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
3547 parentPrivate->interface_type = kSCNetworkInterfaceTypePPP;
3548 parentPrivate->entity_type = kSCValNetInterfaceTypePPP;
3549
3550 // entity subtype
3551 if (childIndex != kCFNotFound) {
3552 if (configurations[childIndex].ppp_subtype != NULL) {
3553 parentPrivate->entity_subtype = *configurations[childIndex].ppp_subtype;
3554 } else {
3555 // sorry, the child interface does not support PPP
3556 goto fail;
3557 }
3558 } else {
3559 // if the child's interface type not known, use the child entities "Type"
3560 parentPrivate->entity_subtype = childPrivate->entity_type;
3561 }
3562
3563 if (childPrivate->entity_device != NULL) {
3564 parentPrivate->entity_device = CFStringCreateCopy(NULL, childPrivate->entity_device);
3565 }
3566
3567 if (childPrivate->entity_device_unique != NULL) {
3568 parentPrivate->entity_device_unique = CFStringCreateCopy(NULL, childPrivate->entity_device_unique);
3569 }
3570 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
3571 if ((childIndex == kCFNotFound) ||
3572 ((configurations[childIndex].supported_interfaces & doL2TP) != doL2TP)) {
3573 // if the child interface does not support L2TP
3574 goto fail;
3575 }
3576 parentPrivate->interface_type = kSCNetworkInterfaceTypeL2TP;
3577 parentPrivate->localized_key = CFSTR("l2tp");
3578 parentPrivate->entity_type = kSCEntNetL2TP; // interface config goes into "L2TP"
3579 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) {
3580 if ((childIndex == kCFNotFound) ||
3581 ((configurations[childIndex].supported_interfaces & doPPTP) != doPPTP)) {
3582 // if the child interface does not support PPTP
3583 goto fail;
3584 }
3585 parentPrivate->interface_type = kSCNetworkInterfaceTypePPTP;
3586 parentPrivate->localized_key = CFSTR("pptp");
3587 parentPrivate->entity_type = kSCEntNetPPTP; // interface config goes into "PPTP"
3588 } else if (CFEqual(interfaceType, kSCNetworkInterfaceType6to4)) {
3589 if ((childIndex == kCFNotFound) ||
3590 ((configurations[childIndex].supported_interfaces & do6to4) != do6to4)) {
3591 // if the child interface does not support 6to4
3592 goto fail;
3593 }
3594
3595 parentPrivate->interface_type = kSCNetworkInterfaceType6to4;
3596 parentPrivate->localized_key = CFSTR("6to4");
3597 parentPrivate->entity_type = kSCValNetInterfaceType6to4;
3598 parentPrivate->entity_device = CFRetain(CFSTR("stf0"));
3599 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
3600 if ((childIndex == kCFNotFound) ||
3601 ((configurations[childIndex].supported_interfaces & doIPSec) != doIPSec)) {
3602 // if the child interface does not support IPSec
3603 goto fail;
3604 }
3605 parentPrivate->interface_type = kSCNetworkInterfaceTypeIPSec;
3606 parentPrivate->localized_key = CFSTR("ipsec");
3607 parentPrivate->entity_type = kSCValNetInterfaceTypeIPSec;
3608 } else if (CFStringFind(interfaceType, CFSTR("."), 0).location != kCFNotFound) {
3609 // if custom interface type
3610 parentPrivate->interface_type = interfaceType;
3611 parentPrivate->entity_type = interfaceType; // interface config goes into a
3612 // a dictionary with the same
3613 // name as the interfaceType
3614 } else {
3615 // unknown interface type
3616 goto fail;
3617 }
3618
3619 if (childPrivate->overrides != NULL) {
3620 parentPrivate->overrides = CFDictionaryCreateMutableCopy(NULL, 0, childPrivate->overrides);
3621 }
3622
3623 // The following change handles the case where a user has both an Ethernet and
3624 // PPPoE network service. Because a PPPoE service is typically associated with
3625 // an ISP we want it to be sorted higher in the service order.
3626 if ((parentPrivate->entity_subtype != NULL) &&
3627 (CFEqual(parentPrivate->entity_subtype, kSCValNetInterfaceSubTypePPPoE))) {
3628 if ((childPrivate->interface_type != NULL) &&
3629 (CFEqual(childPrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211))) {
3630 parentPrivate->sort_order = kSortAirportPPP;
3631 } else {
3632 parentPrivate->sort_order = kSortEthernetPPP;
3633 }
3634 } else {
3635 // set sort order of the parent to match the child interface
3636 parentPrivate->sort_order = childPrivate->sort_order;
3637 }
3638
3639 return (SCNetworkInterfaceRef)parentPrivate;
3640
3641 fail :
3642
3643 CFRelease(parentPrivate);
3644 _SCErrorSet(kSCStatusInvalidArgument);
3645 return NULL;
3646 }
3647
3648
3649 __private_extern__
3650 CFDictionaryRef
3651 __SCNetworkInterfaceGetDefaultConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
3652 {
3653 CFDictionaryRef config = NULL;
3654 CFStringRef defaultType;
3655 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3656
3657 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
3658 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
3659
3660 defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
3661 if (defaultType != NULL) {
3662 if (set != NULL) {
3663 CFStringRef path;
3664
3665 path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator
3666 SCNetworkSetGetSetID(set), // set
3667 interfacePrivate->entity_device, // interface
3668 defaultType); // entity
3669 if (path != NULL) {
3670 config = __getPrefsConfiguration(interfacePrivate->prefs, path);
3671 CFRelease(path);
3672
3673 if (config == NULL) {
3674 // if the "set" does not have a saved configuration, use
3675 // the [template] "interface" configuration
3676 if (interfacePrivate->unsaved != NULL) {
3677 config = CFDictionaryGetValue(interfacePrivate->unsaved, defaultType);
3678 if (config == (CFDictionaryRef)kCFNull) {
3679 config = NULL;
3680 }
3681 }
3682 }
3683 if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
3684 config = NULL;
3685 }
3686 }
3687 }
3688 }
3689
3690 return config;
3691 }
3692
3693
3694 static CFDictionaryRef
3695 __SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface,
3696 CFStringRef extendedType)
3697 {
3698 CFDictionaryRef config = NULL;
3699 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3700 CFArrayRef paths;
3701
3702 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
3703 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
3704
3705 paths = copyConfigurationPaths(interfacePrivate, extendedType);
3706 if (paths != NULL) {
3707 CFStringRef path;
3708
3709 path = CFArrayGetValueAtIndex(paths, 0);
3710 config = __getPrefsConfiguration(interfacePrivate->prefs, path);
3711
3712 CFRelease(paths);
3713 } else {
3714 if (interfacePrivate->unsaved != NULL) {
3715 config = CFDictionaryGetValue(interfacePrivate->unsaved, extendedType);
3716 if (config == (CFDictionaryRef)kCFNull) {
3717 config = NULL;
3718 }
3719 }
3720 }
3721
3722 if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
3723 config = NULL;
3724 }
3725
3726 return config;
3727 }
3728
3729
3730 CFDictionaryRef
3731 SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface)
3732 {
3733 CFDictionaryRef config;
3734 CFStringRef defaultType;
3735
3736 if (!isA_SCNetworkInterface(interface)) {
3737 _SCErrorSet(kSCStatusInvalidArgument);
3738 return NULL;
3739 }
3740
3741 defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
3742 if (defaultType == NULL) {
3743 return NULL;
3744 }
3745
3746 config = __SCNetworkInterfaceGetConfiguration(interface, defaultType);
3747 if (config == NULL) {
3748 if (CFEqual(defaultType, kSCEntNetAirPort)) {
3749 SCNetworkInterfacePrivateRef interfacePrivate;
3750 CFStringRef path;
3751
3752 // if AirPort interface, check for a per-service config
3753 interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3754 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
3755 interfacePrivate->serviceID, // service
3756 kSCEntNetAirPort); // entity
3757 config = __getPrefsConfiguration(interfacePrivate->prefs, path);
3758 CFRelease(path);
3759 }
3760 }
3761 if (config == NULL) {
3762 _SCErrorSet(kSCStatusOK);
3763 }
3764
3765 return config;
3766 }
3767
3768
3769 CFDictionaryRef
3770 SCNetworkInterfaceGetExtendedConfiguration(SCNetworkInterfaceRef interface,
3771 CFStringRef extendedType)
3772 {
3773 CFDictionaryRef config;
3774
3775 if (!isA_SCNetworkInterface(interface)) {
3776 _SCErrorSet(kSCStatusInvalidArgument);
3777 return NULL;
3778 }
3779
3780 if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, TRUE)) {
3781 _SCErrorSet(kSCStatusInvalidArgument);
3782 return NULL;
3783 }
3784
3785 config = __SCNetworkInterfaceGetConfiguration(interface, extendedType);
3786 if (config == NULL) {
3787 _SCErrorSet(kSCStatusOK);
3788 }
3789
3790 return config;
3791 }
3792
3793
3794 CFStringRef
3795 SCNetworkInterfaceGetBSDName(SCNetworkInterfaceRef interface)
3796 {
3797 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3798
3799 if (!isA_SCNetworkInterface(interface)) {
3800 _SCErrorSet(kSCStatusInvalidArgument);
3801 return NULL;
3802 }
3803
3804 if ((interfacePrivate->interface != NULL) &&
3805 (interfacePrivate->interface != kSCNetworkInterfaceIPv4)) {
3806 _SCErrorSet(kSCStatusOK);
3807 return NULL;
3808 }
3809
3810 return interfacePrivate->entity_device;
3811 }
3812
3813
3814 CFStringRef
3815 SCNetworkInterfaceGetHardwareAddressString(SCNetworkInterfaceRef interface)
3816 {
3817 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3818
3819 if (!isA_SCNetworkInterface(interface)) {
3820 _SCErrorSet(kSCStatusInvalidArgument);
3821 return NULL;
3822 }
3823
3824 if ((interfacePrivate->address != NULL) &&
3825 (interfacePrivate->addressString == NULL)) {
3826 uint8_t *bp;
3827 char *cp;
3828 CFIndex n;
3829 char mac[sizeof("xx:xx:xx:xx:xx:xx:xx:xx")];
3830 char *mac_p = mac;
3831
3832 bp = (uint8_t *)CFDataGetBytePtr(interfacePrivate->address);
3833 n = CFDataGetLength(interfacePrivate->address) * 3;
3834
3835 if (n > sizeof(mac)) {
3836 mac_p = CFAllocatorAllocate(NULL, 0, n);
3837 }
3838
3839 for (cp = mac_p; n > 0; n -= 3) {
3840 cp += snprintf(cp, n, "%2.2x:", *bp++);
3841 }
3842
3843 interfacePrivate->addressString = CFStringCreateWithCString(NULL, mac_p, kCFStringEncodingUTF8);
3844 if (mac_p != mac) CFAllocatorDeallocate(NULL, mac_p);
3845 }
3846
3847 return interfacePrivate->addressString;
3848 }
3849
3850
3851 SCNetworkInterfaceRef
3852 SCNetworkInterfaceGetInterface(SCNetworkInterfaceRef interface)
3853 {
3854 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3855
3856 if (!isA_SCNetworkInterface(interface)) {
3857 _SCErrorSet(kSCStatusInvalidArgument);
3858 return NULL;
3859 }
3860
3861 return interfacePrivate->interface;
3862 }
3863
3864
3865 CFStringRef
3866 SCNetworkInterfaceGetInterfaceType(SCNetworkInterfaceRef interface)
3867 {
3868 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3869
3870 if (!isA_SCNetworkInterface(interface)) {
3871 _SCErrorSet(kSCStatusInvalidArgument);
3872 return NULL;
3873 }
3874
3875 return interfacePrivate->interface_type;
3876 }
3877
3878
3879 static CFStringRef
3880 copy_interface_string(CFBundleRef bundle, CFStringRef key, Boolean localized)
3881 {
3882 CFStringRef str = NULL;
3883
3884 if (localized) {
3885 str = CFBundleCopyLocalizedString(bundle,
3886 key,
3887 key,
3888 NETWORKINTERFACE_LOCALIZATIONS);
3889 } else {
3890 str = _SC_CFBundleCopyNonLocalizedString(bundle,
3891 key,
3892 key,
3893 NETWORKINTERFACE_LOCALIZATIONS);
3894 }
3895
3896 return str;
3897 }
3898
3899
3900 static CFStringRef
3901 copy_display_name(SCNetworkInterfaceRef interface, Boolean localized, Boolean oldLocalization)
3902 {
3903 CFMutableStringRef local;
3904 CFStringRef name;
3905
3906 local = CFStringCreateMutable(NULL, 0);
3907
3908 while (interface != NULL) {
3909 Boolean added = FALSE;
3910 SCNetworkInterfaceRef child = NULL;
3911 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
3912
3913 if ((interfacePrivate->interface != NULL) &&
3914 (interfacePrivate->interface != kSCNetworkInterfaceIPv4)) {
3915 child = interfacePrivate->interface;
3916 }
3917
3918 if ((bundle != NULL) && (interfacePrivate->localized_key != NULL)) {
3919 CFStringRef fmt;
3920 CFStringRef key = interfacePrivate->localized_key;
3921
3922 if (oldLocalization) {
3923 key = CFStringCreateWithFormat(NULL, NULL, CFSTR("X-%@"),
3924 interfacePrivate->localized_key);
3925 }
3926 fmt = copy_interface_string(bundle, key, localized);
3927 if (fmt != NULL) {
3928 CFStringAppendFormat(local,
3929 NULL,
3930 fmt,
3931 interfacePrivate->localized_arg1,
3932 interfacePrivate->localized_arg2);
3933 CFRelease(fmt);
3934 added = TRUE;
3935 }
3936 if (oldLocalization) {
3937 CFRelease(key);
3938 }
3939 }
3940
3941 if (!added &&
3942 (interfacePrivate->prefs != NULL) &&
3943 (interfacePrivate->serviceID != NULL) &&
3944 (child == NULL)) {
3945 CFDictionaryRef entity;
3946 CFStringRef path;
3947
3948 // check for (and use) the name of the interface when it
3949 // was last available
3950 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
3951 interfacePrivate->serviceID,
3952 kSCEntNetInterface);
3953 entity = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
3954 CFRelease(path);
3955 if (isA_CFDictionary(entity)) {
3956 CFStringRef name;
3957
3958 name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
3959 if (isA_CFString(name)) {
3960 CFStringAppend(local, name);
3961 added = TRUE;
3962 }
3963 }
3964 }
3965
3966 if (!added) {
3967 // create (non-)localized name based on the interface type
3968 CFStringAppend(local, interfacePrivate->interface_type);
3969
3970 // ... and, if this is a leaf node, the interface device
3971 if ((interfacePrivate->entity_device != NULL) && (child == NULL)) {
3972 CFStringAppendFormat(local, NULL, CFSTR(" (%@)"), interfacePrivate->entity_device);
3973 }
3974 }
3975
3976 if (child != NULL) {
3977 // if this interface is layered over another
3978 CFStringAppend(local, CFSTR(" --> "));
3979 }
3980
3981 interface = child;
3982 }
3983
3984 name = CFStringCreateCopy(NULL, local);
3985 CFRelease(local);
3986
3987 return name;
3988 }
3989
3990
3991 __private_extern__
3992 CFStringRef
3993 __SCNetworkInterfaceCopyXLocalizedDisplayName(SCNetworkInterfaceRef interface)
3994 {
3995 CFStringRef name;
3996
3997 if (!isA_SCNetworkInterface(interface)) {
3998 _SCErrorSet(kSCStatusInvalidArgument);
3999 return NULL;
4000 }
4001
4002 name = copy_display_name(interface, TRUE, TRUE);
4003 return name;
4004 }
4005
4006
4007 __private_extern__
4008 CFStringRef
4009 __SCNetworkInterfaceCopyXNonLocalizedDisplayName(SCNetworkInterfaceRef interface)
4010 {
4011 CFStringRef localized_name;
4012
4013 if (!isA_SCNetworkInterface(interface)) {
4014 _SCErrorSet(kSCStatusInvalidArgument);
4015 return NULL;
4016 }
4017
4018 localized_name = copy_display_name(interface, FALSE, TRUE);
4019 return localized_name;
4020 }
4021
4022
4023 __private_extern__
4024 CFStringRef
4025 __SCNetworkInterfaceGetNonLocalizedDisplayName(SCNetworkInterfaceRef interface)
4026 {
4027 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
4028
4029 if (!isA_SCNetworkInterface(interface)) {
4030 _SCErrorSet(kSCStatusInvalidArgument);
4031 return NULL;
4032 }
4033
4034 if (interfacePrivate->name == NULL) {
4035 interfacePrivate->name = copy_display_name(interface, FALSE, FALSE);
4036 }
4037
4038 return interfacePrivate->name;
4039 }
4040
4041
4042 CFStringRef
4043 SCNetworkInterfaceGetLocalizedDisplayName(SCNetworkInterfaceRef interface)
4044 {
4045 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
4046
4047 if (!isA_SCNetworkInterface(interface)) {
4048 _SCErrorSet(kSCStatusInvalidArgument);
4049 return NULL;
4050 }
4051
4052 if (interfacePrivate->localized_name == NULL) {
4053 interfacePrivate->localized_name = copy_display_name(interface, TRUE, FALSE);
4054 }
4055
4056 return interfacePrivate->localized_name;
4057 }
4058
4059
4060 __private_extern__
4061 CFDictionaryRef
4062 __SCNetworkInterfaceGetTemplateOverrides(SCNetworkInterfaceRef interface, CFStringRef interfaceType)
4063 {
4064 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
4065 CFDictionaryRef overrides = NULL;
4066
4067 if (interfacePrivate->overrides != NULL) {
4068 overrides = CFDictionaryGetValue(interfacePrivate->overrides, interfaceType);
4069 }
4070
4071 return overrides;
4072 }
4073
4074
4075 CFTypeID
4076 SCNetworkInterfaceGetTypeID(void)
4077 {
4078 pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* initialize runtime */
4079 return __kSCNetworkInterfaceTypeID;
4080 }
4081
4082
4083 __private_extern__
4084 Boolean
4085 __SCNetworkInterfaceSetDefaultConfiguration(SCNetworkSetRef set,
4086 SCNetworkInterfaceRef interface,
4087 CFStringRef defaultType,
4088 CFDictionaryRef config,
4089 Boolean okToHold)
4090 {
4091 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
4092 Boolean ok = FALSE;
4093
4094 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
4095 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
4096
4097 if (defaultType == NULL) {
4098 defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
4099 if (defaultType == NULL) {
4100 return FALSE;
4101 }
4102 }
4103
4104 if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
4105 config = NULL;
4106 }
4107
4108 if (set != NULL) {
4109 CFStringRef path;
4110
4111 path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator
4112 SCNetworkSetGetSetID(set), // set
4113 interfacePrivate->entity_device, // interface
4114 defaultType); // entity
4115 if (path != NULL) {
4116 ok = __setPrefsConfiguration(interfacePrivate->prefs, path, config, FALSE);
4117 CFRelease(path);
4118 if (ok) {
4119 // if configuration has been saved
4120 if (interfacePrivate->unsaved != NULL) {
4121 CFDictionaryRemoveValue(interfacePrivate->unsaved, defaultType);
4122 if (CFDictionaryGetCount(interfacePrivate->unsaved) == 0) {
4123 CFRelease(interfacePrivate->unsaved);
4124 interfacePrivate->unsaved = NULL;
4125 }
4126 }
4127 }
4128 } else {
4129 if (okToHold) {
4130 if (config == NULL) {
4131 // remember that we are clearing the configuration
4132 config = (CFDictionaryRef)kCFNull;
4133 }
4134
4135 if (interfacePrivate->unsaved == NULL) {
4136 interfacePrivate->unsaved = CFDictionaryCreateMutable(NULL,
4137 0,
4138 &kCFTypeDictionaryKeyCallBacks,
4139 &kCFTypeDictionaryValueCallBacks);
4140 }
4141 CFDictionarySetValue(interfacePrivate->unsaved, defaultType, config);
4142 ok = TRUE;
4143 } else {
4144 _SCErrorSet(kSCStatusNoKey);
4145 }
4146 }
4147 }
4148
4149 return ok;
4150 }
4151
4152
4153 __private_extern__
4154 Boolean
4155 __SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface,
4156 CFStringRef extendedType,
4157 CFDictionaryRef config,
4158 Boolean okToHold)
4159 {
4160 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
4161 Boolean ok = FALSE;
4162 CFArrayRef paths;
4163
4164 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
4165 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
4166
4167 if (extendedType == NULL) {
4168 extendedType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
4169 if (extendedType == NULL) {
4170 return FALSE;
4171 }
4172 }
4173
4174 if (isA_CFDictionary(config) && (CFDictionaryGetCount(config) == 0)) {
4175 config = NULL;
4176 }
4177
4178 paths = copyConfigurationPaths(interfacePrivate, extendedType);
4179 if (paths != NULL) {
4180 CFIndex i;
4181 CFIndex n;
4182
4183 n = CFArrayGetCount(paths);
4184 for (i = 0; i < n; i++) {
4185 CFStringRef path;
4186
4187 path = CFArrayGetValueAtIndex(paths, i);
4188 ok = __setPrefsConfiguration(interfacePrivate->prefs, path, config, FALSE);
4189 if (!ok) {
4190 break;
4191 }
4192 }
4193
4194 if (ok) {
4195 // if configuration has been saved
4196 if (interfacePrivate->unsaved != NULL) {
4197 CFDictionaryRemoveValue(interfacePrivate->unsaved, extendedType);
4198 if (CFDictionaryGetCount(interfacePrivate->unsaved) == 0) {
4199 CFRelease(interfacePrivate->unsaved);
4200 interfacePrivate->unsaved = NULL;
4201 }
4202 }
4203 }
4204
4205 CFRelease(paths);
4206 } else {
4207 if (okToHold) {
4208 if (config == NULL) {
4209 // remember that we are clearing the configuration
4210 config = (CFDictionaryRef)kCFNull;
4211 }
4212
4213 if (interfacePrivate->unsaved == NULL) {
4214 interfacePrivate->unsaved = CFDictionaryCreateMutable(NULL,
4215 0,
4216 &kCFTypeDictionaryKeyCallBacks,
4217 &kCFTypeDictionaryValueCallBacks);
4218 }
4219 CFDictionarySetValue(interfacePrivate->unsaved, extendedType, config);
4220 ok = TRUE;
4221 } else {
4222 _SCErrorSet(kSCStatusNoKey);
4223 }
4224 }
4225
4226 return ok;
4227 }
4228
4229
4230 Boolean
4231 SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config)
4232 {
4233 CFStringRef defaultType;
4234
4235 if (!isA_SCNetworkInterface(interface)) {
4236 _SCErrorSet(kSCStatusInvalidArgument);
4237 return FALSE;
4238 }
4239
4240 defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
4241 if (defaultType == NULL) {
4242 return FALSE;
4243 }
4244
4245 return __SCNetworkInterfaceSetConfiguration(interface, defaultType, config, FALSE);
4246 }
4247
4248
4249 Boolean
4250 SCNetworkInterfaceSetExtendedConfiguration(SCNetworkInterfaceRef interface,
4251 CFStringRef extendedType,
4252 CFDictionaryRef config)
4253 {
4254 if (!isA_SCNetworkInterface(interface)) {
4255 _SCErrorSet(kSCStatusInvalidArgument);
4256 return FALSE;
4257 }
4258
4259 if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, TRUE)) {
4260 return FALSE;
4261 }
4262
4263 return __SCNetworkInterfaceSetConfiguration(interface, extendedType, config, FALSE);
4264 }
4265
4266
4267 #pragma mark -
4268 #pragma mark SCNetworkInterface [Refresh Configuration] API
4269
4270
4271 #ifndef kSCEntNetRefreshConfiguration
4272 #define kSCEntNetRefreshConfiguration CFSTR("RefreshConfiguration")
4273 #endif // kSCEntNetRefreshConfiguration
4274
4275 Boolean
4276 _SCNetworkInterfaceForceConfigurationRefresh(CFStringRef ifName)
4277 {
4278 CFStringRef key;
4279 Boolean ok = FALSE;
4280 SCDynamicStoreRef store;
4281
4282 if (!isA_CFString(ifName)) {
4283 _SCErrorSet(kSCStatusInvalidArgument);
4284 return FALSE;
4285 }
4286
4287 store = SCDynamicStoreCreate(NULL, CFSTR("_SCNetworkInterfaceForceConfigurationRefresh"), NULL, NULL);
4288 if (store == NULL) {
4289 return FALSE;
4290 }
4291
4292 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
4293 kSCDynamicStoreDomainState,
4294 ifName,
4295 kSCEntNetRefreshConfiguration);
4296 ok = SCDynamicStoreNotifyValue(store, key);
4297 CFRelease(key);
4298 CFRelease(store);
4299 return ok;
4300 }
4301
4302
4303 static Boolean
4304 __SCNetworkInterfaceForceConfigurationRefresh_helper(SCPreferencesRef prefs, CFStringRef ifName)
4305 {
4306 CFDataRef data = NULL;
4307 Boolean ok;
4308 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
4309 uint32_t status = kSCStatusOK;
4310 CFDataRef reply = NULL;
4311
4312 if (prefsPrivate->helper == -1) {
4313 ok = __SCPreferencesCreate_helper(prefs);
4314 if (!ok) {
4315 return FALSE;
4316 }
4317 }
4318
4319 // serialize the interface name
4320 ok = _SCSerializeString(ifName, &data, NULL, NULL);
4321 if (!ok) {
4322 goto fail;
4323 }
4324
4325 // have the helper "refresh" the configuration
4326 status = kSCStatusOK;
4327 reply = NULL;
4328 ok = _SCHelperExec(prefsPrivate->helper,
4329 SCHELPER_MSG_INTERFACE_REFRESH,
4330 data,
4331 &status,
4332 NULL);
4333 if (data != NULL) CFRelease(data);
4334 if (!ok) {
4335 goto fail;
4336 }
4337
4338 if (status != kSCStatusOK) {
4339 goto error;
4340 }
4341
4342 return TRUE;
4343
4344 fail :
4345
4346 // close helper
4347 if (prefsPrivate->helper != -1) {
4348 _SCHelperClose(prefsPrivate->helper);
4349 prefsPrivate->helper = -1;
4350 }
4351
4352 status = kSCStatusAccessError;
4353
4354 error :
4355
4356 // return error
4357 _SCErrorSet(status);
4358 return FALSE;
4359 }
4360
4361
4362 Boolean
4363 SCNetworkInterfaceForceConfigurationRefresh(SCNetworkInterfaceRef interface)
4364 {
4365 CFStringRef ifName;
4366 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
4367
4368 if (!isA_SCNetworkInterface(interface)) {
4369 _SCErrorSet(kSCStatusInvalidArgument);
4370 return FALSE;
4371 }
4372
4373 ifName = SCNetworkInterfaceGetBSDName(interface);
4374 if (ifName == NULL) {
4375 _SCErrorSet(kSCStatusInvalidArgument);
4376 return FALSE;
4377 }
4378
4379 if (interfacePrivate->prefs != NULL) {
4380 SCPreferencesRef prefs = interfacePrivate->prefs;
4381 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
4382
4383 if (prefsPrivate->authorizationData != NULL) {
4384 return __SCNetworkInterfaceForceConfigurationRefresh_helper(prefs, ifName);
4385 }
4386 }
4387
4388 return _SCNetworkInterfaceForceConfigurationRefresh(ifName);
4389 }
4390
4391
4392 Boolean
4393 SCNetworkInterfaceRefreshConfiguration(CFStringRef ifName)
4394 {
4395 return _SCNetworkInterfaceForceConfigurationRefresh(ifName);
4396 }
4397
4398
4399 #pragma mark -
4400 #pragma mark SCNetworkInterface Password APIs
4401
4402
4403 static CFStringRef
4404 getPasswordID(CFDictionaryRef config, CFStringRef serviceID)
4405 {
4406 CFStringRef unique_id = NULL;
4407
4408 if (config != NULL) {
4409 CFStringRef encryption;
4410
4411 encryption = CFDictionaryGetValue(config, kSCPropNetPPPAuthPasswordEncryption);
4412 if (isA_CFString(encryption) &&
4413 CFEqual(encryption, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
4414 unique_id = CFDictionaryGetValue(config, kSCPropNetPPPAuthPassword);
4415 }
4416 }
4417 if (unique_id == NULL) {
4418 unique_id = serviceID;
4419 }
4420
4421 return unique_id;
4422 }
4423
4424
4425 static CFStringRef
4426 copySharedSecretID(CFDictionaryRef config, CFStringRef serviceID)
4427 {
4428 CFMutableStringRef shared_id = NULL;
4429
4430 if (config != NULL) {
4431 CFStringRef encryption;
4432
4433 encryption = CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecretEncryption);
4434 if (isA_CFString(encryption) &&
4435 CFEqual(encryption, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
4436 shared_id = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecret);
4437 if (shared_id != NULL) {
4438 CFRetain(shared_id);
4439 }
4440 }
4441 }
4442
4443 if (shared_id == NULL) {
4444 CFStringRef unique_id;
4445
4446 unique_id = getPasswordID(config, serviceID);
4447 shared_id = CFStringCreateMutableCopy(NULL, 0, unique_id);
4448 CFStringAppend(shared_id, CFSTR(".SS"));
4449 }
4450
4451 return shared_id;
4452 }
4453
4454
4455 static CFStringRef
4456 copyXAuthID(CFDictionaryRef config, CFStringRef serviceID)
4457 {
4458 CFMutableStringRef xauth_id = NULL;
4459
4460 if (config != NULL) {
4461 CFStringRef encryption;
4462
4463 encryption = CFDictionaryGetValue(config, kSCPropNetIPSecXAuthPasswordEncryption);
4464 if (isA_CFString(encryption) &&
4465 CFEqual(encryption, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) {
4466 xauth_id = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecXAuthPassword);
4467 if (xauth_id != NULL) {
4468 CFRetain(xauth_id);
4469 }
4470 }
4471 }
4472
4473 if (xauth_id == NULL) {
4474 CFStringRef unique_id;
4475
4476 unique_id = getPasswordID(config, serviceID);
4477 xauth_id = CFStringCreateMutableCopy(NULL, 0, unique_id);
4478 CFStringAppend(xauth_id, CFSTR(".XAUTH"));
4479 }
4480
4481 return xauth_id;
4482 }
4483
4484
4485 static Boolean
4486 checkInterfacePassword(SCNetworkInterfaceRef interface,
4487 SCNetworkInterfacePasswordType passwordType,
4488 SCPreferencesRef *prefs,
4489 CFStringRef *serviceID)
4490 {
4491 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
4492
4493 if (!isA_SCNetworkInterface(interface)) {
4494 goto error;
4495 }
4496
4497 *serviceID = interfacePrivate->serviceID;
4498 if (*serviceID == NULL) {
4499 goto error;
4500 }
4501
4502 *prefs = interfacePrivate->prefs;
4503 if (*prefs == NULL) {
4504 goto error;
4505 }
4506
4507 switch (passwordType) {
4508 case kSCNetworkInterfacePasswordTypePPP : {
4509 CFStringRef interfaceType;
4510
4511 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
4512 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
4513 // if PPP
4514 break;
4515 }
4516
4517 goto error;
4518 }
4519
4520 case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
4521 CFStringRef interfaceType;
4522
4523 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
4524 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
4525 interface = SCNetworkInterfaceGetInterface(interface);
4526 if (interface != NULL) {
4527 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
4528 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
4529 // if PPP->L2TP interface
4530 break;
4531 }
4532 }
4533 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
4534 // if IPSec interface
4535 break;
4536 }
4537
4538 goto error;
4539 }
4540
4541 case kSCNetworkInterfacePasswordTypeEAPOL : {
4542 break;
4543 }
4544
4545 case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
4546 CFStringRef interfaceType;
4547
4548 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
4549 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
4550 // if IPSec interface
4551 break;
4552 }
4553
4554 goto error;
4555 }
4556
4557 default :
4558 break;
4559 }
4560
4561 return TRUE;
4562
4563 error :
4564
4565 _SCErrorSet(kSCStatusInvalidArgument);
4566 return FALSE;
4567 }
4568
4569
4570 Boolean
4571 SCNetworkInterfaceCheckPassword(SCNetworkInterfaceRef interface,
4572 SCNetworkInterfacePasswordType passwordType)
4573 {
4574 Boolean exists = FALSE;
4575 SCPreferencesRef prefs = NULL;
4576 CFStringRef serviceID = NULL;
4577
4578 if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
4579 return FALSE;
4580 }
4581
4582 switch (passwordType) {
4583 case kSCNetworkInterfacePasswordTypePPP : {
4584 CFDictionaryRef config;
4585 CFStringRef unique_id;
4586
4587 // get configuration
4588 config = SCNetworkInterfaceGetConfiguration(interface);
4589
4590 // get serviceID
4591 unique_id = getPasswordID(config, serviceID);
4592
4593 // check
4594 exists = __extract_password(prefs,
4595 config,
4596 kSCPropNetPPPAuthPassword,
4597 kSCPropNetPPPAuthPasswordEncryption,
4598 kSCValNetPPPAuthPasswordEncryptionKeychain,
4599 unique_id,
4600 NULL);
4601 break;
4602 }
4603
4604 case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
4605 CFDictionaryRef config;
4606 Boolean extended;
4607 CFStringRef shared_id;
4608
4609 // get configuration
4610 extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
4611 if (extended) {
4612 config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
4613 } else {
4614 config = SCNetworkInterfaceGetConfiguration(interface);
4615 }
4616
4617 // get sharedSecret ID
4618 shared_id = copySharedSecretID(config, serviceID);
4619
4620 // check
4621 exists = __extract_password(prefs,
4622 config,
4623 kSCPropNetIPSecSharedSecret,
4624 kSCPropNetIPSecSharedSecretEncryption,
4625 kSCValNetIPSecSharedSecretEncryptionKeychain,
4626 shared_id,
4627 NULL);
4628 CFRelease(shared_id);
4629 break;
4630 }
4631
4632 case kSCNetworkInterfacePasswordTypeEAPOL : {
4633 CFDictionaryRef config;
4634 CFStringRef unique_id = NULL;
4635
4636 // get configuration
4637 config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
4638
4639 // get 802.1X identifier
4640 if (config != NULL) {
4641 unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
4642 }
4643 if (!isA_CFString(unique_id)) {
4644 return FALSE;
4645 }
4646
4647 // check password
4648 exists = _SCPreferencesSystemKeychainPasswordItemExists(prefs, unique_id);
4649 break;
4650 }
4651
4652 case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
4653 CFDictionaryRef config;
4654 CFStringRef xauth_id;
4655
4656 // get configuration
4657 config = SCNetworkInterfaceGetConfiguration(interface);
4658
4659 // get XAuth ID
4660 xauth_id = copyXAuthID(config, serviceID);
4661
4662 // check
4663 exists = __extract_password(prefs,
4664 config,
4665 kSCPropNetIPSecXAuthPassword,
4666 kSCPropNetIPSecXAuthPasswordEncryption,
4667 kSCValNetIPSecXAuthPasswordEncryptionKeychain,
4668 xauth_id,
4669 NULL);
4670 CFRelease(xauth_id);
4671 break;
4672 }
4673
4674 default :
4675 _SCErrorSet(kSCStatusInvalidArgument);
4676 return FALSE;
4677 }
4678
4679 return exists;
4680 }
4681
4682
4683 CFDataRef
4684 SCNetworkInterfaceCopyPassword(SCNetworkInterfaceRef interface,
4685 SCNetworkInterfacePasswordType passwordType)
4686 {
4687 CFDataRef password = NULL;
4688 SCPreferencesRef prefs = NULL;
4689 CFStringRef serviceID = NULL;
4690
4691 if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
4692 return NULL;
4693 }
4694
4695 switch (passwordType) {
4696 case kSCNetworkInterfacePasswordTypePPP : {
4697 CFDictionaryRef config;
4698 CFStringRef unique_id;
4699
4700 // get configuration
4701 config = SCNetworkInterfaceGetConfiguration(interface);
4702
4703 // get serviceID
4704 unique_id = getPasswordID(config, serviceID);
4705
4706 // extract
4707 (void) __extract_password(prefs,
4708 config,
4709 kSCPropNetPPPAuthPassword,
4710 kSCPropNetPPPAuthPasswordEncryption,
4711 kSCValNetPPPAuthPasswordEncryptionKeychain,
4712 unique_id,
4713 &password);
4714 break;
4715 }
4716
4717 case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
4718 CFDictionaryRef config;
4719 Boolean extended;
4720 CFStringRef shared_id;
4721
4722 // get configuration
4723 extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
4724 if (extended) {
4725 config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
4726 } else {
4727 config = SCNetworkInterfaceGetConfiguration(interface);
4728 }
4729
4730 // get sharedSecret ID
4731 shared_id = copySharedSecretID(config, serviceID);
4732
4733 // extract
4734 (void) __extract_password(prefs,
4735 config,
4736 kSCPropNetIPSecSharedSecret,
4737 kSCPropNetIPSecSharedSecretEncryption,
4738 kSCValNetIPSecSharedSecretEncryptionKeychain,
4739 shared_id,
4740 &password);
4741
4742 CFRelease(shared_id);
4743 break;
4744 }
4745
4746 case kSCNetworkInterfacePasswordTypeEAPOL : {
4747 CFDictionaryRef config;
4748 CFStringRef unique_id = NULL;
4749
4750 // get configuration
4751 config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
4752
4753 // get 802.1X identifier
4754 if (config != NULL) {
4755 unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
4756 }
4757 if (!isA_CFString(unique_id)) {
4758 _SCErrorSet(kSCStatusFailed);
4759 return NULL;
4760 }
4761
4762 // copy password
4763 password = _SCPreferencesSystemKeychainPasswordItemCopy(prefs, unique_id);
4764 break;
4765 }
4766
4767 case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
4768 CFDictionaryRef config;
4769 CFStringRef xauth_id;
4770
4771 // get configuration
4772 config = SCNetworkInterfaceGetConfiguration(interface);
4773
4774 // get XAuth ID
4775 xauth_id = copyXAuthID(config, serviceID);
4776
4777 // extract
4778 (void) __extract_password(prefs,
4779 config,
4780 kSCPropNetIPSecXAuthPassword,
4781 kSCPropNetIPSecXAuthPasswordEncryption,
4782 kSCValNetIPSecXAuthPasswordEncryptionKeychain,
4783 xauth_id,
4784 &password);
4785 CFRelease(xauth_id);
4786 break;
4787 }
4788
4789 default :
4790 _SCErrorSet(kSCStatusInvalidArgument);
4791 return NULL;
4792 }
4793
4794 return password;
4795 }
4796
4797
4798 Boolean
4799 SCNetworkInterfaceRemovePassword(SCNetworkInterfaceRef interface,
4800 SCNetworkInterfacePasswordType passwordType)
4801 {
4802 Boolean ok = FALSE;
4803 SCPreferencesRef prefs = NULL;
4804 CFStringRef serviceID = NULL;
4805
4806 if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
4807 return FALSE;
4808 }
4809
4810 switch (passwordType) {
4811 case kSCNetworkInterfacePasswordTypePPP : {
4812 CFDictionaryRef config;
4813 CFDictionaryRef newConfig = NULL;
4814 CFStringRef unique_id;
4815
4816 // get configuration
4817 config = SCNetworkInterfaceGetConfiguration(interface);
4818
4819 // get serviceID
4820 unique_id = getPasswordID(config, serviceID);
4821
4822 // remove password
4823 ok = __remove_password(prefs,
4824 config,
4825 kSCPropNetPPPAuthPassword,
4826 kSCPropNetPPPAuthPasswordEncryption,
4827 kSCValNetPPPAuthPasswordEncryptionKeychain,
4828 unique_id,
4829 &newConfig);
4830 if (ok) {
4831 ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
4832 if (newConfig != NULL) CFRelease(newConfig);
4833 }
4834
4835 break;
4836 }
4837
4838 case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
4839 CFDictionaryRef config;
4840 Boolean extended;
4841 CFDictionaryRef newConfig = NULL;
4842 CFStringRef shared_id;
4843
4844 // get configuration
4845 extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
4846 if (extended) {
4847 config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
4848 } else {
4849 config = SCNetworkInterfaceGetConfiguration(interface);
4850 }
4851
4852 // get sharedSecret ID
4853 shared_id = copySharedSecretID(config, serviceID);
4854
4855 // remove password
4856 ok = __remove_password(prefs,
4857 config,
4858 kSCPropNetIPSecSharedSecret,
4859 kSCPropNetIPSecSharedSecretEncryption,
4860 kSCValNetIPSecSharedSecretEncryptionKeychain,
4861 shared_id,
4862 &newConfig);
4863 if (ok) {
4864 if (extended) {
4865 ok = SCNetworkInterfaceSetExtendedConfiguration(interface,
4866 kSCEntNetIPSec,
4867 newConfig);
4868 } else {
4869 ok = SCNetworkInterfaceSetConfiguration(interface,
4870 newConfig);
4871 }
4872 if (newConfig != NULL) CFRelease(newConfig);
4873 }
4874
4875 CFRelease(shared_id);
4876 break;
4877 }
4878
4879 case kSCNetworkInterfacePasswordTypeEAPOL : {
4880 CFDictionaryRef config;
4881 CFStringRef unique_id = NULL;
4882
4883 // get configuration
4884 config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
4885
4886 // get 802.1X identifier
4887 if (config != NULL) {
4888 unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
4889 }
4890 if (!isA_CFString(unique_id)) {
4891 _SCErrorSet(kSCStatusFailed);
4892 return FALSE;
4893 }
4894
4895 // remove password
4896 ok = _SCPreferencesSystemKeychainPasswordItemRemove(prefs, unique_id);
4897 break;
4898 }
4899
4900 case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
4901 CFDictionaryRef config;
4902 CFDictionaryRef newConfig = NULL;
4903 CFStringRef xauth_id;
4904
4905 // get configuration
4906 config = SCNetworkInterfaceGetConfiguration(interface);
4907
4908 // get XAuth ID
4909 xauth_id = copyXAuthID(config, serviceID);
4910
4911 // remove password
4912 ok = __remove_password(prefs,
4913 config,
4914 kSCPropNetIPSecXAuthPassword,
4915 kSCPropNetIPSecXAuthPasswordEncryption,
4916 kSCValNetIPSecXAuthPasswordEncryptionKeychain,
4917 xauth_id,
4918 &newConfig);
4919 if (ok) {
4920 ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
4921 if (newConfig != NULL) CFRelease(newConfig);
4922 }
4923
4924 CFRelease(xauth_id);
4925 break;
4926 }
4927
4928 default :
4929 _SCErrorSet(kSCStatusInvalidArgument);
4930 return FALSE;
4931 }
4932
4933 return ok;
4934 }
4935
4936
4937 Boolean
4938 SCNetworkInterfaceSetPassword(SCNetworkInterfaceRef interface,
4939 SCNetworkInterfacePasswordType passwordType,
4940 CFDataRef password,
4941 CFDictionaryRef options)
4942 {
4943 CFStringRef account = NULL;
4944 CFDictionaryRef config;
4945 CFStringRef description = NULL;
4946 CFStringRef label = NULL;
4947 Boolean ok = FALSE;
4948 SCPreferencesRef prefs = NULL;
4949 CFStringRef serviceID = NULL;
4950
4951 if (!checkInterfacePassword(interface, passwordType, &prefs, &serviceID)) {
4952 return FALSE;
4953 }
4954
4955 switch (passwordType) {
4956 case kSCNetworkInterfacePasswordTypePPP : {
4957 SCNetworkServiceRef service = NULL;
4958 CFStringRef unique_id;
4959
4960 // get configuration
4961 config = SCNetworkInterfaceGetConfiguration(interface);
4962
4963 // get serviceID
4964 unique_id = getPasswordID(config, serviceID);
4965
4966 // get "Account", "Name", "Kind"
4967 if (config != NULL) {
4968 // auth name --> keychain "Account"
4969 account = CFDictionaryGetValue(config, kSCPropNetPPPAuthName);
4970
4971 // PPP [user defined] "name" --> keychain "Name"
4972 label = CFDictionaryGetValue(config, kSCPropUserDefinedName);
4973 }
4974
4975 if (label == NULL) {
4976 // service name --> keychain "Name"
4977 service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
4978 prefs,
4979 serviceID,
4980 interface);
4981
4982 label = SCNetworkServiceGetName(service);
4983 if (label == NULL) {
4984 // interface name --> keychain "Name"
4985 label = SCNetworkInterfaceGetLocalizedDisplayName(interface);
4986 }
4987 }
4988
4989 if (bundle != NULL) {
4990 // "PPP Password" --> keychain "Kind"
4991 description = CFBundleCopyLocalizedString(bundle,
4992 CFSTR("KEYCHAIN_KIND_PPP_PASSWORD"),
4993 CFSTR("PPP Password"),
4994 NULL);
4995 }
4996
4997 // store password
4998 ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
4999 unique_id,
5000 (label != NULL) ? label : CFSTR("Network Connection"),
5001 (description != NULL) ? description : CFSTR("PPP Password"),
5002 account,
5003 password,
5004 options);
5005 if (ok) {
5006 CFMutableDictionaryRef newConfig;
5007
5008 if (config != NULL) {
5009 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
5010 } else {
5011 newConfig = CFDictionaryCreateMutable(NULL,
5012 0,
5013 &kCFTypeDictionaryKeyCallBacks,
5014 &kCFTypeDictionaryValueCallBacks);
5015 }
5016 CFDictionarySetValue(newConfig,
5017 kSCPropNetPPPAuthPassword,
5018 unique_id);
5019 CFDictionarySetValue(newConfig,
5020 kSCPropNetPPPAuthPasswordEncryption,
5021 kSCValNetPPPAuthPasswordEncryptionKeychain);
5022 ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
5023 CFRelease(newConfig);
5024 }
5025
5026 if (description != NULL) CFRelease(description);
5027 if (service != NULL) CFRelease(service);
5028 break;
5029 }
5030
5031 case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
5032 CFDictionaryRef baseConfig = NULL;
5033 Boolean extended;
5034 SCNetworkServiceRef service = NULL;
5035 CFStringRef shared_id;
5036
5037 // get configuration
5038 extended = CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypePPP);
5039 config = SCNetworkInterfaceGetConfiguration(interface);
5040 if (extended) {
5041 baseConfig = config;
5042 config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
5043 }
5044
5045 // get sharedSecret ID
5046 shared_id = copySharedSecretID(config, serviceID);
5047
5048 // get "Account", "Name", "Kind"
5049 if (config != NULL) {
5050 CFStringRef localIdentifier;
5051 CFStringRef localIdentifierType;
5052
5053 if (CFDictionaryGetValueIfPresent(config,
5054 kSCPropNetIPSecLocalIdentifierType,
5055 (const void **)&localIdentifierType)
5056 && CFEqual(localIdentifierType, kSCValNetIPSecLocalIdentifierTypeKeyID)
5057 && CFDictionaryGetValueIfPresent(config,
5058 kSCPropNetIPSecLocalIdentifier,
5059 (const void **)&localIdentifier)
5060 && isA_CFString(localIdentifier)) {
5061 // local identifier --> keychain "Account"
5062 account = localIdentifier;
5063 }
5064
5065 // PPP [user defined] "name" --> keychain "Name"
5066 if (!extended) {
5067 label = CFDictionaryGetValue(config, kSCPropUserDefinedName);
5068 } else {
5069 if (baseConfig != NULL) {
5070 label = CFDictionaryGetValue(baseConfig, kSCPropUserDefinedName);
5071 }
5072 }
5073 }
5074
5075 if (label == NULL) {
5076 // service name --> keychain "Name"
5077 service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
5078 prefs,
5079 serviceID,
5080 interface);
5081
5082 label = SCNetworkServiceGetName(service);
5083 if (label == NULL) {
5084 // interface name --> keychain "Name"
5085 label = SCNetworkInterfaceGetLocalizedDisplayName(interface);
5086 }
5087 }
5088
5089 if (bundle != NULL) {
5090 // "IPSec Shared Secret" --> keychain "Kind"
5091 description = CFBundleCopyLocalizedString(bundle,
5092 CFSTR("KEYCHAIN_KIND_IPSEC_SHARED_SECRET"),
5093 CFSTR("IPSec Shared Secret"),
5094 NULL);
5095 }
5096
5097 // set password
5098 ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
5099 shared_id,
5100 (label != NULL) ? label : CFSTR("VPN Connection"),
5101 (description != NULL) ? description : CFSTR("IPSec Shared Secret"),
5102 account,
5103 password,
5104 options);
5105 if (ok) {
5106 CFMutableDictionaryRef newConfig = NULL;
5107
5108 if (config != NULL) {
5109 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
5110 } else {
5111 newConfig = CFDictionaryCreateMutable(NULL,
5112 0,
5113 &kCFTypeDictionaryKeyCallBacks,
5114 &kCFTypeDictionaryValueCallBacks);
5115 }
5116 CFDictionarySetValue(newConfig,
5117 kSCPropNetIPSecSharedSecret,
5118 shared_id);
5119 CFDictionarySetValue(newConfig,
5120 kSCPropNetIPSecSharedSecretEncryption,
5121 kSCValNetIPSecSharedSecretEncryptionKeychain);
5122 if (extended) {
5123 ok = SCNetworkInterfaceSetExtendedConfiguration(interface,
5124 kSCEntNetIPSec,
5125 newConfig);
5126 } else {
5127 ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
5128 }
5129 CFRelease(newConfig);
5130 }
5131
5132 if (description != NULL) CFRelease(description);
5133 if (service != NULL) CFRelease(service);
5134 CFRelease(shared_id);
5135 break;
5136 }
5137
5138 case kSCNetworkInterfacePasswordTypeEAPOL : {
5139 CFStringRef account = NULL;
5140 CFStringRef unique_id = NULL;
5141
5142 // get configuration
5143 config = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetEAPOL);
5144
5145 // get 802.1X identifier
5146 if (config != NULL) {
5147 unique_id = CFDictionaryGetValue(config, kEAPClientPropUserPasswordKeychainItemID);
5148 }
5149 if (isA_CFString(unique_id)) {
5150 CFRetain(unique_id);
5151 } else {
5152 CFUUIDRef uuid;
5153
5154 uuid = CFUUIDCreate(NULL);
5155 unique_id = CFUUIDCreateString(NULL, uuid);
5156 CFRelease(uuid);
5157 }
5158
5159 // 802.1x UserName --> keychain "Account"
5160 if (config != NULL) {
5161 account = CFDictionaryGetValue(config, kEAPClientPropUserName);
5162 }
5163
5164 // get "Name", "Kind"
5165 if (bundle != NULL) {
5166 CFStringRef interface_name;
5167
5168 // "Network Connection (%@)" --> keychain "Name"
5169 interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
5170 if (interface_name != NULL) {
5171 CFStringRef label_fmt;
5172
5173 label_fmt = CFBundleCopyLocalizedString(bundle,
5174 CFSTR("KEYCHAIN_DESCRIPTION_EAPOL_INTERFACE"),
5175 CFSTR("Network Connection (%@)"),
5176 NULL);
5177 label = CFStringCreateWithFormat(NULL, NULL, label_fmt, interface_name);
5178 CFRelease(label_fmt);
5179 } else {
5180 label = CFBundleCopyLocalizedString(bundle,
5181 CFSTR("KEYCHAIN_DESCRIPTION_EAPOL"),
5182 CFSTR("Network Connection"),
5183 NULL);
5184 }
5185
5186 // "802.1X Password" --> keychain "Kind"
5187 description = CFBundleCopyLocalizedString(bundle,
5188 CFSTR("KEYCHAIN_KIND_EAPOL"),
5189 CFSTR("802.1X Password"),
5190 NULL);
5191 }
5192
5193 // set password
5194 ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
5195 unique_id,
5196 (label != NULL) ? label : CFSTR("Network Connection"),
5197 (description != NULL) ? description : CFSTR("802.1X Password"),
5198 account,
5199 password,
5200 options);
5201 if (ok) {
5202 CFMutableDictionaryRef newConfig = NULL;
5203
5204 if (config != NULL) {
5205 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
5206 } else {
5207 newConfig = CFDictionaryCreateMutable(NULL,
5208 0,
5209 &kCFTypeDictionaryKeyCallBacks,
5210 &kCFTypeDictionaryValueCallBacks);
5211 }
5212 CFDictionarySetValue(newConfig,
5213 kEAPClientPropUserPasswordKeychainItemID,
5214 unique_id);
5215 ok = SCNetworkInterfaceSetExtendedConfiguration(interface,
5216 kSCEntNetEAPOL,
5217 newConfig);
5218 CFRelease(newConfig);
5219 }
5220
5221 CFRelease(unique_id);
5222 if (label != NULL) CFRelease(label);
5223 if (description != NULL) CFRelease(description);
5224 break;
5225 }
5226
5227 case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
5228 SCNetworkServiceRef service = NULL;
5229 CFStringRef xauth_id;
5230
5231 // get configuration
5232 config = SCNetworkInterfaceGetConfiguration(interface);
5233
5234 // get XAuth ID
5235 xauth_id = copyXAuthID(config, serviceID);
5236
5237 // get "Account", "Name", "Kind"
5238 if (config != NULL) {
5239 // auth name --> keychain "Account"
5240 account = CFDictionaryGetValue(config, kSCPropNetIPSecXAuthName);
5241
5242 // IPSec [user defined] "name" --> keychain "Name"
5243 label = CFDictionaryGetValue(config, kSCPropUserDefinedName);
5244 }
5245
5246 if (label == NULL) {
5247 // service name --> keychain "Name"
5248 service = (SCNetworkServiceRef)__SCNetworkServiceCreatePrivate(NULL,
5249 prefs,
5250 serviceID,
5251 interface);
5252
5253 label = SCNetworkServiceGetName(service);
5254 if (label == NULL) {
5255 // interface name --> keychain "Name"
5256 label = SCNetworkInterfaceGetLocalizedDisplayName(interface);
5257 }
5258 }
5259
5260 if (bundle != NULL) {
5261 // "IPSec XAuth Password" --> keychain "Kind"
5262 description = CFBundleCopyLocalizedString(bundle,
5263 CFSTR("KEYCHAIN_KIND_IPSEC_XAUTH_PASSWORD"),
5264 CFSTR("IPSec XAuth Password"),
5265 NULL);
5266 }
5267
5268 // store password
5269 ok = _SCPreferencesSystemKeychainPasswordItemSet(prefs,
5270 xauth_id,
5271 (label != NULL) ? label : CFSTR("VPN Connection"),
5272 (description != NULL) ? description : CFSTR("IPSec XAuth Password"),
5273 account,
5274 password,
5275 options);
5276 if (ok) {
5277 CFMutableDictionaryRef newConfig;
5278
5279 if (config != NULL) {
5280 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
5281 } else {
5282 newConfig = CFDictionaryCreateMutable(NULL,
5283 0,
5284 &kCFTypeDictionaryKeyCallBacks,
5285 &kCFTypeDictionaryValueCallBacks);
5286 }
5287 CFDictionarySetValue(newConfig,
5288 kSCPropNetIPSecXAuthPassword,
5289 xauth_id);
5290 CFDictionarySetValue(newConfig,
5291 kSCPropNetIPSecXAuthPasswordEncryption,
5292 kSCValNetIPSecXAuthPasswordEncryptionKeychain);
5293 ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
5294 CFRelease(newConfig);
5295 }
5296
5297 CFRelease(xauth_id);
5298 if (description != NULL) CFRelease(description);
5299 if (service != NULL) CFRelease(service);
5300 break;
5301 }
5302
5303 default :
5304 _SCErrorSet(kSCStatusInvalidArgument);
5305 break;
5306 }
5307
5308 return ok;
5309 }
5310
5311
5312 #pragma mark -
5313 #pragma mark SCNetworkInterface [InterfaceNamer] SPIs
5314
5315
5316 CFDictionaryRef
5317 _SCNetworkInterfaceCopyInterfaceInfo(SCNetworkInterfaceRef interface)
5318 {
5319 CFMutableDictionaryRef info;
5320 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5321 CFStringRef name;
5322
5323 info = CFDictionaryCreateMutable(NULL,
5324 0,
5325 &kCFTypeDictionaryKeyCallBacks,
5326 &kCFTypeDictionaryValueCallBacks);
5327
5328 // add non-localized interface name
5329 name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
5330 if (name != NULL) {
5331 CFDictionaryAddValue(info, kSCPropUserDefinedName, name);
5332 }
5333
5334 // add USB info
5335 if ((interfacePrivate->usb.vid != NULL) || (interfacePrivate->usb.pid != NULL)) {
5336 if (interfacePrivate->usb.name != NULL) {
5337 CFDictionaryAddValue(info, CFSTR(kUSBProductString), interfacePrivate->usb.name);
5338 }
5339 if (interfacePrivate->usb.vid != NULL) {
5340 CFDictionaryAddValue(info, CFSTR(kUSBVendorID), interfacePrivate->usb.vid);
5341 }
5342 if (interfacePrivate->usb.pid != NULL) {
5343 CFDictionaryAddValue(info, CFSTR(kUSBProductID), interfacePrivate->usb.pid);
5344 }
5345 }
5346
5347 if (CFDictionaryGetCount(info) == 0) {
5348 // do not return an empty dictionary
5349 CFRelease(info);
5350 info = NULL;
5351 }
5352
5353 return info;
5354 }
5355
5356
5357 SCNetworkInterfaceRef
5358 _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(io_object_t if_obj)
5359 {
5360 SCNetworkInterfaceRef interface = NULL;
5361
5362 /* initialize runtime */
5363 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
5364
5365 if (IOObjectConformsTo(if_obj, kIONetworkInterfaceClass)) {
5366 interface = createInterface(if_obj, processNetworkInterface);
5367 } else if (IOObjectConformsTo(if_obj, kIOSerialBSDServiceValue)) {
5368 interface = createInterface(if_obj, processSerialInterface);
5369 }
5370
5371 return interface;
5372 }
5373
5374
5375 CFStringRef
5376 _SCNetworkInterfaceGetConfigurationAction(SCNetworkInterfaceRef interface)
5377 {
5378 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5379
5380 return interfacePrivate->configurationAction;
5381 }
5382
5383
5384 CFDataRef
5385 _SCNetworkInterfaceGetHardwareAddress(SCNetworkInterfaceRef interface)
5386 {
5387 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5388
5389 return interfacePrivate->address;
5390 }
5391
5392
5393 CFNumberRef
5394 _SCNetworkInterfaceGetIOInterfaceType(SCNetworkInterfaceRef interface)
5395 {
5396 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5397
5398 return interfacePrivate->type;
5399 }
5400
5401
5402 CFNumberRef
5403 _SCNetworkInterfaceGetIOInterfaceUnit(SCNetworkInterfaceRef interface)
5404 {
5405 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5406
5407 return interfacePrivate->unit;
5408 }
5409
5410
5411 CFStringRef
5412 _SCNetworkInterfaceGetIOPath(SCNetworkInterfaceRef interface)
5413 {
5414 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5415
5416 return interfacePrivate->path;
5417 }
5418
5419
5420 Boolean
5421 _SCNetworkInterfaceIsBuiltin(SCNetworkInterfaceRef interface)
5422 {
5423 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5424
5425 return interfacePrivate->builtin;
5426 }
5427
5428
5429 #pragma mark -
5430 #pragma mark SCNetworkInterface SPIs
5431
5432
5433 CFStringRef
5434 _SCNetworkInterfaceCopySlashDevPath(SCNetworkInterfaceRef interface)
5435 {
5436 io_registry_entry_t device;
5437 io_iterator_t device_iterator = MACH_PORT_NULL;
5438 CFStringRef device_path = NULL;
5439 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5440 kern_return_t kr;
5441 CFStringRef match_keys[2];
5442 CFTypeRef match_vals[2];
5443 CFDictionaryRef match_dict;
5444 CFDictionaryRef matching;
5445
5446 if (interfacePrivate->entity_device == NULL) {
5447 return NULL;
5448 }
5449
5450 if (interfacePrivate->entity_device_unique == NULL) {
5451 goto done;
5452 }
5453
5454 match_keys[0] = CFSTR(kIOTTYBaseNameKey);
5455 match_vals[0] = interfacePrivate->entity_device;
5456 match_dict = CFDictionaryCreate(NULL,
5457 (const void **)match_keys,
5458 (const void **)match_vals,
5459 1,
5460 &kCFTypeDictionaryKeyCallBacks,
5461 &kCFTypeDictionaryValueCallBacks);
5462
5463 match_keys[0] = CFSTR(kIOProviderClassKey);
5464 match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
5465 match_keys[1] = CFSTR(kIOPropertyMatchKey);
5466 match_vals[1] = match_dict;
5467 matching = CFDictionaryCreate(NULL,
5468 (const void **)match_keys,
5469 (const void **)match_vals,
5470 sizeof(match_keys)/sizeof(match_keys[0]),
5471 &kCFTypeDictionaryKeyCallBacks,
5472 &kCFTypeDictionaryValueCallBacks);
5473 CFRelease(match_dict);
5474
5475 // note: this "matching" dictionary will be consumed by the call to IOServiceGetMatchingServices
5476 kr = IOServiceGetMatchingServices(masterPort, matching, &device_iterator);
5477 if (kr != kIOReturnSuccess) {
5478 SCLog(TRUE, LOG_DEBUG, CFSTR("IOServiceGetMatchingServices() failed, kr = 0x%x"), kr);
5479 goto done;
5480 }
5481
5482 while ((device_path == NULL) &&
5483 ((device = IOIteratorNext(device_iterator)) != MACH_PORT_NULL)) {
5484 CFDictionaryRef overrides;
5485
5486 overrides = IORegistryEntrySearchCFProperty(device,
5487 kIOServicePlane,
5488 CFSTR("DeviceModemOverrides"),
5489 NULL,
5490 kIORegistryIterateRecursively | kIORegistryIterateParents);
5491 if (overrides != NULL) {
5492 if (isA_CFDictionary(overrides)) {
5493 CFStringRef matchIdentifier;
5494
5495 matchIdentifier = CFDictionaryGetValue(overrides, CFSTR("UniqueIdentifier"));
5496 if (isA_CFString(matchIdentifier) &&
5497 CFEqual(interfacePrivate->entity_device_unique, matchIdentifier)) {
5498 device_path = IORegistryEntryCreateCFProperty(device,
5499 CFSTR(kIOTTYDeviceKey),
5500 NULL,
5501 0);
5502 }
5503 }
5504 CFRelease(overrides);
5505 }
5506 IOObjectRelease(device);
5507 }
5508
5509 IOObjectRelease(device_iterator);
5510
5511 done :
5512
5513 if (device_path == NULL) {
5514 // if we haven't found an exact match to our UniqueIdentifier
5515 // so we simply return the base name.
5516 device_path = SCNetworkInterfaceGetBSDName(interface);
5517 if (device_path != NULL) {
5518 CFRetain(device_path);
5519 }
5520 }
5521
5522 return device_path;
5523 }
5524
5525
5526 Boolean
5527 _SCNetworkInterfaceIsBluetoothPAN(SCNetworkInterfaceRef interface)
5528 {
5529 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5530
5531 return (interfacePrivate->sort_order == kSortBluetoothPAN);
5532 }
5533
5534
5535 Boolean
5536 _SCNetworkInterfaceIsModemV92(SCNetworkInterfaceRef interface)
5537 {
5538 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5539
5540 return interfacePrivate->modemIsV92;
5541 }
5542
5543
5544 Boolean
5545 _SCNetworkInterfaceIsTethered(SCNetworkInterfaceRef interface)
5546 {
5547 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
5548
5549 return (interfacePrivate->sort_order == kSortTethered);
5550 }
5551
5552
5553 #pragma mark -
5554 #pragma mark SCNetworkInterface [internal] SPIs
5555
5556
5557 __private_extern__
5558 SCNetworkInterfacePrivateRef
5559 __SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator,
5560 SCNetworkInterfaceRef interface,
5561 SCPreferencesRef prefs,
5562 CFStringRef serviceID)
5563 {
5564 SCNetworkInterfacePrivateRef oldPrivate = (SCNetworkInterfacePrivateRef)interface;
5565 SCNetworkInterfacePrivateRef newPrivate;
5566
5567 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
5568 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
5569
5570 if (interface == kSCNetworkInterfaceIPv4) {
5571 return (SCNetworkInterfacePrivateRef)CFRetain(interface);
5572 }
5573
5574 newPrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, prefs, serviceID, NULL);
5575 newPrivate->interface_type = oldPrivate->interface_type;
5576 if (oldPrivate->interface != NULL) {
5577 newPrivate->interface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL, // allocator
5578 oldPrivate->interface, // interface
5579 prefs, // [new] prefs
5580 serviceID); // [new] serviceID
5581 }
5582 if (oldPrivate->name != NULL) {
5583 newPrivate->name = CFRetain(oldPrivate->name);
5584 }
5585 if (oldPrivate->localized_name != NULL) {
5586 newPrivate->localized_name = CFRetain(oldPrivate->localized_name);
5587 }
5588 newPrivate->localized_key = oldPrivate->localized_key;
5589 if (oldPrivate->localized_arg1 != NULL) {
5590 newPrivate->localized_arg1 = CFRetain(oldPrivate->localized_arg1);
5591 }
5592 if (oldPrivate->localized_arg2 != NULL) {
5593 newPrivate->localized_arg2 = CFRetain(oldPrivate->localized_arg2);
5594 }
5595 if (oldPrivate->unsaved != NULL) {
5596 newPrivate->unsaved = CFDictionaryCreateMutableCopy(NULL, 0, oldPrivate->unsaved);
5597 }
5598 if (oldPrivate->entity_device != NULL) {
5599 newPrivate->entity_device = CFRetain(oldPrivate->entity_device);
5600 }
5601 if (oldPrivate->entity_device_unique != NULL) {
5602 newPrivate->entity_device_unique = CFRetain(oldPrivate->entity_device_unique);
5603 }
5604 newPrivate->entity_type = oldPrivate->entity_type;
5605 newPrivate->entity_subtype = oldPrivate->entity_subtype;
5606 if (oldPrivate->supported_interface_types != NULL) {
5607 newPrivate->supported_interface_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_interface_types);
5608 }
5609 if (oldPrivate->supported_protocol_types != NULL) {
5610 newPrivate->supported_protocol_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_protocol_types);
5611 }
5612 if (oldPrivate->address != NULL) {
5613 newPrivate->address = CFRetain(oldPrivate->address);
5614 }
5615 newPrivate->builtin = oldPrivate->builtin;
5616 if (oldPrivate->configurationAction != NULL) {
5617 newPrivate->configurationAction = CFRetain(oldPrivate->configurationAction);
5618 }
5619 if (oldPrivate->location != NULL) {
5620 newPrivate->location = CFRetain(oldPrivate->location);
5621 }
5622 if (oldPrivate->path != NULL) {
5623 newPrivate->path = CFRetain(oldPrivate->path);
5624 }
5625 if (oldPrivate->overrides != NULL) {
5626 newPrivate->overrides = CFDictionaryCreateMutableCopy(NULL, 0, oldPrivate->overrides);
5627 }
5628 newPrivate->modemIsV92 = oldPrivate->modemIsV92;
5629 if (oldPrivate->type != NULL) {
5630 newPrivate->type = CFRetain(oldPrivate->type);
5631 }
5632 if (oldPrivate->unit != NULL) {
5633 newPrivate->unit = CFRetain(oldPrivate->unit);
5634 }
5635 if (oldPrivate->usb.name != NULL) {
5636 newPrivate->usb.name = CFRetain(oldPrivate->usb.name);
5637 }
5638 if (oldPrivate->usb.vid != NULL) {
5639 newPrivate->usb.vid = CFRetain(oldPrivate->usb.vid);
5640 }
5641 if (oldPrivate->usb.pid != NULL) {
5642 newPrivate->usb.pid = CFRetain(oldPrivate->usb.pid);
5643 }
5644 newPrivate->sort_order = oldPrivate->sort_order;
5645 #if !TARGET_OS_IPHONE
5646 newPrivate->supportsBond = oldPrivate->supportsBond;
5647 if (oldPrivate->bond.interfaces != NULL) {
5648 newPrivate->bond.interfaces = CFRetain(oldPrivate->bond.interfaces);
5649 }
5650 if (oldPrivate->bond.mode != NULL) {
5651 newPrivate->bond.mode = CFRetain(oldPrivate->bond.mode);
5652 }
5653 if (oldPrivate->bond.options != NULL) {
5654 newPrivate->bond.options = CFRetain(oldPrivate->bond.options);
5655 }
5656 newPrivate->supportsVLAN = oldPrivate->supportsVLAN;
5657 if (oldPrivate->vlan.interface != NULL) {
5658 newPrivate->vlan.interface = CFRetain(oldPrivate->vlan.interface);
5659 }
5660 if (oldPrivate->vlan.tag != NULL) {
5661 newPrivate->vlan.tag = CFRetain(oldPrivate->vlan.tag);
5662 }
5663 if (oldPrivate->vlan.options != NULL) {
5664 newPrivate->vlan.options = CFRetain(oldPrivate->vlan.options);
5665 }
5666 #endif // !TARGET_OS_IPHONE
5667
5668 return newPrivate;
5669 }
5670
5671
5672 __private_extern__
5673 CFArrayRef
5674 __SCNetworkInterfaceCopyDeepConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
5675 {
5676 CFMutableArrayRef configs;
5677
5678 configs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5679
5680 while (interface != NULL) {
5681 CFStringRef defaultType;
5682 CFMutableDictionaryRef interfaceConfiguration;
5683
5684 interfaceConfiguration = CFDictionaryCreateMutable(NULL,
5685 0,
5686 &kCFTypeDictionaryKeyCallBacks,
5687 &kCFTypeDictionaryValueCallBacks);
5688
5689 defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
5690 if (defaultType != NULL) {
5691 CFDictionaryRef config;
5692 CFArrayRef extendedTypes;
5693
5694 if (set == NULL) {
5695 config = __SCNetworkInterfaceGetConfiguration(interface, defaultType);
5696 } else {
5697 config = __SCNetworkInterfaceGetDefaultConfiguration(set, interface);
5698 }
5699 if (config == NULL) {
5700 config = (CFDictionaryRef)kCFNull;
5701 }
5702 CFDictionarySetValue(interfaceConfiguration, defaultType, config);
5703
5704 extendedTypes = extendedConfigurationTypes(interface);
5705 if (extendedTypes != NULL) {
5706 CFIndex i;
5707 CFIndex n;
5708
5709 n = CFArrayGetCount(extendedTypes);
5710 for (i = 0; i < n; i++) {
5711 CFStringRef extendedType;
5712
5713 extendedType = CFArrayGetValueAtIndex(extendedTypes, i);
5714 config = __SCNetworkInterfaceGetConfiguration(interface, extendedType);
5715 if (config == NULL) {
5716 config = (CFDictionaryRef)kCFNull;
5717 }
5718 CFDictionarySetValue(interfaceConfiguration, extendedType, config);
5719 }
5720
5721 CFRelease(extendedTypes);
5722 }
5723 }
5724
5725 CFArrayAppendValue(configs, interfaceConfiguration);
5726 CFRelease(interfaceConfiguration);
5727
5728 interface = SCNetworkInterfaceGetInterface(interface);
5729 }
5730
5731 return configs;
5732 }
5733
5734
5735 __private_extern__
5736 void
5737 __SCNetworkInterfaceSetDeepConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface, CFArrayRef configs)
5738 {
5739 CFIndex i;
5740
5741 for (i = 0; interface != NULL; i++) {
5742 CFStringRef defaultType;
5743 CFDictionaryRef interfaceConfiguration;
5744
5745 interfaceConfiguration = (configs != NULL) ? CFArrayGetValueAtIndex(configs, i) : NULL;
5746
5747 defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
5748 if (defaultType != NULL) {
5749 CFDictionaryRef config;
5750 CFArrayRef extendedTypes;
5751
5752 config = (interfaceConfiguration != NULL) ? CFDictionaryGetValue(interfaceConfiguration, defaultType)
5753 : NULL;
5754 if (config == (CFDictionaryRef)kCFNull) {
5755 config = NULL;
5756 }
5757 if (set == NULL) {
5758 // if service is not associated with the set
5759 if (!__SCNetworkInterfaceSetConfiguration(interface, defaultType, config, TRUE)) {
5760 SCLog(TRUE, LOG_DEBUG,
5761 CFSTR("__SCNetworkInterfaceSetDeepConfiguration __SCNetworkInterfaceSetConfiguration() failed, interface=%@, type=%@"),
5762 interface,
5763 defaultType);
5764 }
5765 } else {
5766 // apply default configuration to this set
5767 if (!__SCNetworkInterfaceSetDefaultConfiguration(set, interface, defaultType, config, TRUE)) {
5768 SCLog(TRUE, LOG_DEBUG,
5769 CFSTR("__SCNetworkInterfaceSetDeepConfiguration __SCNetworkInterfaceSetDefaultConfiguration() failed, interface=%@, type=%@"),
5770 interface,
5771 defaultType);
5772 }
5773 }
5774
5775 extendedTypes = extendedConfigurationTypes(interface);
5776 if (extendedTypes != NULL) {
5777 CFIndex j;
5778 CFIndex n;
5779
5780 n = CFArrayGetCount(extendedTypes);
5781 for (j = 0; j < n; j++) {
5782 CFStringRef extendedType;
5783
5784 extendedType = CFArrayGetValueAtIndex(extendedTypes, j);
5785 config = (interfaceConfiguration != NULL) ? CFDictionaryGetValue(interfaceConfiguration, extendedType)
5786 : NULL;
5787 if (config == (CFDictionaryRef)kCFNull) {
5788 config = NULL;
5789 }
5790 if (!__SCNetworkInterfaceSetConfiguration(interface, extendedType, config, TRUE)) {
5791 SCLog(TRUE, LOG_DEBUG,
5792 CFSTR("__SCNetworkInterfaceSetDeepConfiguration __SCNetworkInterfaceSetConfiguration() failed, interface=%@, type=%@"),
5793 interface,
5794 defaultType);
5795 }
5796 }
5797
5798 CFRelease(extendedTypes);
5799 }
5800 }
5801
5802 interface = SCNetworkInterfaceGetInterface(interface);
5803 }
5804
5805 return;
5806 }