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