]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkInterface.c
configd-130.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkInterface.c
1 /*
2 * Copyright (c) 2004 Apple Computer, 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 * Elizaabeth Douglas <elizabeth@apple.com>
32 * Quinn <eskimo1@apple.com>
33 */
34
35
36 #include <CoreFoundation/CoreFoundation.h>
37 #include <CoreFoundation/CFRuntime.h>
38 #include <SystemConfiguration/SystemConfiguration.h>
39 #include <SystemConfiguration/SCNetworkConfigurationInternal.h>
40 #include <SystemConfiguration/SCValidation.h>
41 #include <SystemConfiguration/SCPrivate.h>
42 #include <SystemConfiguration/BondConfiguration.h>
43 #include <SystemConfiguration/VLANConfiguration.h>
44
45 #include <IOKit/IOKitLib.h>
46 #include <IOKit/IOCFBundle.h>
47 #include <IOKit/IOBSD.h>
48 #include <IOKit/network/IONetworkController.h>
49 #include <IOKit/network/IONetworkInterface.h>
50 #include <IOKit/network/IOEthernetInterface.h> // for kIOEthernetInterfaceClass
51 #include <IOKit/serial/IOSerialKeys.h>
52 #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
53 #include "dy_framework.h"
54
55 #ifndef kIODeviceSupportsHoldKey
56 #define kIODeviceSupportsHoldKey "V92Modem"
57 #endif
58
59 #include "SCNetworkConfiguration.h"
60 #include "SCNetworkConfigurationInternal.h"
61
62 #include <mach/mach.h>
63 #include <net/if.h>
64 #include <net/if_types.h>
65 #include <pthread.h>
66
67
68 static CFStringRef __SCNetworkInterfaceCopyDescription (CFTypeRef cf);
69 static void __SCNetworkInterfaceDeallocate (CFTypeRef cf);
70 static Boolean __SCNetworkInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2);
71
72
73 enum {
74 kSortInternalModem,
75 kSortUSBModem,
76 kSortModem,
77 kSortBluetooth,
78 kSortIrDA,
79 kSortSerialPort,
80 kSortEthernet,
81 kSortFireWire,
82 kSortAirPort,
83 kSortOtherWireless,
84 kSortBond,
85 kSortVLAN,
86 kSortUnknown
87 };
88
89
90 const CFStringRef kSCNetworkInterfaceType6to4 = CFSTR("6to4");
91 const CFStringRef kSCNetworkInterfaceTypeBluetooth = CFSTR("Bluetooth");
92 const CFStringRef kSCNetworkInterfaceTypeBond = CFSTR("Bond");
93 const CFStringRef kSCNetworkInterfaceTypeEthernet = CFSTR("Ethernet");
94 const CFStringRef kSCNetworkInterfaceTypeFireWire = CFSTR("FireWire");
95 const CFStringRef kSCNetworkInterfaceTypeIEEE80211 = CFSTR("IEEE80211"); // IEEE 802.11, AirPort
96 const CFStringRef kSCNetworkInterfaceTypeIrDA = CFSTR("IrDA");
97 const CFStringRef kSCNetworkInterfaceTypeL2TP = CFSTR("L2TP");
98 const CFStringRef kSCNetworkInterfaceTypeModem = CFSTR("Modem");
99 const CFStringRef kSCNetworkInterfaceTypePPP = CFSTR("PPP");
100 const CFStringRef kSCNetworkInterfaceTypePPTP = CFSTR("PPTP");
101 const CFStringRef kSCNetworkInterfaceTypeSerial = CFSTR("Serial");
102 const CFStringRef kSCNetworkInterfaceTypeVLAN = CFSTR("VLAN");
103
104 const CFStringRef kSCNetworkInterfaceTypeIPv4 = CFSTR("IPv4");
105
106 static SCNetworkInterfacePrivate __kSCNetworkInterfaceIPv4 = {
107 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), // cfBase
108 NULL, // interface type
109 NULL, // localized name
110 NULL, // localization key
111 NULL, // localization arg1
112 NULL, // localization arg2
113 NULL, // [layered] interface
114 NULL, // service
115 NULL, // unsaved
116 NULL, // entity_device
117 NULL, // entity_hardware
118 NULL, // entity_type
119 NULL, // entity_subtype
120 NULL, // supported_interface_types
121 NULL, // supported_protocol_types
122 NULL, // address
123 FALSE, // builtin
124 NULL, // location
125 NULL, // path
126 FALSE, // supportsDeviceOnHold
127 FALSE, // supportsBond
128 FALSE, // supportsVLAN
129 kSortUnknown // sort_order
130 };
131
132 const SCNetworkInterfaceRef kSCNetworkInterfaceIPv4 = (SCNetworkInterfaceRef)&__kSCNetworkInterfaceIPv4;
133
134 #define doNone 0
135
136 #define do6to4 1<<0
137 #define doL2TP 1<<1
138 #define doPPP 1<<2
139 #define doPPTP 1<<3
140
141 #define doAppleTalk 1<<0
142 #define doDNS 1<<1
143 #define doIPv4 1<<2
144 #define doIPv6 1<<3
145 #define doProxies 1<<4
146
147 static const struct {
148 const CFStringRef *interface_type;
149 Boolean per_interface_config;
150 uint32_t supported_interfaces;
151 const CFStringRef *ppp_subtype;
152 uint32_t supported_protocols;
153 } configurations[] = {
154 // interface type if config? interface types PPP sub-type interface protocols
155 // ===================================== ========== ======================= ======================================= =========================================
156 { &kSCNetworkInterfaceType6to4 , FALSE, doNone, NULL, doIPv6 },
157 { &kSCNetworkInterfaceTypeBluetooth , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
158 { &kSCNetworkInterfaceTypeBond , TRUE, doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies },
159 { &kSCNetworkInterfaceTypeEthernet , TRUE, doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies },
160 { &kSCNetworkInterfaceTypeFireWire , TRUE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies },
161 { &kSCNetworkInterfaceTypeIEEE80211 , TRUE, doPPP, &kSCValNetInterfaceSubTypePPPoE, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies },
162 { &kSCNetworkInterfaceTypeIrDA , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
163 { &kSCNetworkInterfaceTypeL2TP , FALSE, doPPP, &kSCValNetInterfaceSubTypeL2TP, doNone },
164 { &kSCNetworkInterfaceTypeModem , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
165 { &kSCNetworkInterfaceTypePPP , FALSE, doNone, NULL, doDNS|doIPv4|doIPv6|doProxies },
166 { &kSCNetworkInterfaceTypePPTP , FALSE, doPPP, &kSCValNetInterfaceSubTypePPTP, doNone },
167 { &kSCNetworkInterfaceTypeSerial , FALSE, doPPP, &kSCValNetInterfaceSubTypePPPSerial, doNone },
168 { &kSCNetworkInterfaceTypeVLAN , TRUE, doNone, NULL, doAppleTalk|doDNS|doIPv4|doIPv6|doProxies },
169 // ===================================== ========== ======================= ======================================= =========================================
170 { &kSCNetworkInterfaceTypeIPv4 , FALSE, do6to4|doPPTP|doL2TP, NULL, doNone }
171 };
172
173
174 #define SYSTEMCONFIGURATION_BUNDLE_ID CFSTR("com.apple.SystemConfiguration")
175 #define NETWORKINTERFACE_LOCALIZATIONS CFSTR("NetworkInterface")
176 static CFBundleRef bundle = NULL;
177
178
179 static CFTypeID __kSCNetworkInterfaceTypeID = _kCFRuntimeNotATypeID;
180
181
182 static const CFRuntimeClass __SCNetworkInterfaceClass = {
183 0, // version
184 "SCNetworkInterface", // className
185 NULL, // init
186 NULL, // copy
187 __SCNetworkInterfaceDeallocate, // dealloc
188 __SCNetworkInterfaceEqual, // equal
189 NULL, // hash
190 NULL, // copyFormattingDesc
191 __SCNetworkInterfaceCopyDescription // copyDebugDesc
192 };
193
194
195 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
196
197
198 static __inline__ CFTypeRef
199 isA_SCNetworkInterface(CFTypeRef obj)
200 {
201 return (isA_CFType(obj, SCNetworkInterfaceGetTypeID()));
202 }
203
204
205 static CFStringRef
206 __SCNetworkInterfaceCopyDescription(CFTypeRef cf)
207 {
208 CFAllocatorRef allocator = CFGetAllocator(cf);
209 CFMutableStringRef result;
210 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)cf;
211
212 result = CFStringCreateMutable(allocator, 0);
213 CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkInterface %p [%p]> { "), cf, allocator);
214 CFStringAppendFormat(result, NULL, CFSTR("type = %@"), interfacePrivate->interface_type);
215 CFStringAppendFormat(result, NULL, CFSTR(", entity = %@ / %@ / %@"),
216 interfacePrivate->entity_device,
217 interfacePrivate->entity_hardware,
218 interfacePrivate->entity_type);
219 if (interfacePrivate->entity_subtype != NULL) {
220 CFStringAppendFormat(result, NULL, CFSTR(" / %@"), interfacePrivate->entity_subtype);
221 }
222 if (interfacePrivate->localized_name != NULL) {
223 CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), interfacePrivate->localized_name);
224 } else {
225 if (interfacePrivate->localized_key != NULL) {
226 CFStringAppendFormat(result, NULL, CFSTR(", name = \"%@\""), interfacePrivate->localized_key);
227 if (interfacePrivate->localized_arg1 != NULL) {
228 CFStringAppendFormat(result, NULL, CFSTR("+\"%@\""), interfacePrivate->localized_arg1);
229 }
230 if (interfacePrivate->localized_arg2 != NULL) {
231 CFStringAppendFormat(result, NULL, CFSTR("+\"%@\""), interfacePrivate->localized_arg2);
232 }
233 }
234 }
235 if (interfacePrivate->address != NULL) {
236 CFStringAppendFormat(result, NULL, CFSTR(", address = %@"), interfacePrivate->address);
237 }
238 CFStringAppendFormat(result, NULL, CFSTR(", builtin = %s"), interfacePrivate->builtin ? "TRUE" : "FALSE");
239 if (interfacePrivate->location != NULL) {
240 CFStringAppendFormat(result, NULL, CFSTR(", location = %@"), interfacePrivate->location);
241 }
242 CFStringAppendFormat(result, NULL, CFSTR(", path = %@"), interfacePrivate->path);
243 CFStringAppendFormat(result, NULL, CFSTR(", order = %d"), interfacePrivate->sort_order);
244
245 if (interfacePrivate->service != NULL) {
246 CFStringAppendFormat(result, NULL, CFSTR(", service=%@"), interfacePrivate->service);
247 }
248
249 if (interfacePrivate->interface != NULL) {
250 CFStringAppendFormat(result, NULL, CFSTR(", interface=%@"), interfacePrivate->interface);
251 }
252
253 if (interfacePrivate->unsaved != NULL) {
254 CFStringAppendFormat(result, NULL, CFSTR(", unsaved=%@"), interfacePrivate->unsaved);
255 }
256 CFStringAppendFormat(result, NULL, CFSTR(" }"));
257
258 return result;
259 }
260
261
262 static void
263 __SCNetworkInterfaceDeallocate(CFTypeRef cf)
264 {
265 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)cf;
266
267 /* release resources */
268
269 if (interfacePrivate->interface != NULL)
270 CFRelease(interfacePrivate->interface);
271
272 if (interfacePrivate->localized_name != NULL)
273 CFRelease(interfacePrivate->localized_name);
274
275 if (interfacePrivate->localized_arg1 != NULL)
276 CFRelease(interfacePrivate->localized_arg1);
277
278 if (interfacePrivate->localized_arg2 != NULL)
279 CFRelease(interfacePrivate->localized_arg2);
280
281 if (interfacePrivate->unsaved != NULL)
282 CFRelease(interfacePrivate->unsaved);
283
284 if (interfacePrivate->entity_device != NULL)
285 CFRelease(interfacePrivate->entity_device);
286
287 if (interfacePrivate->supported_interface_types != NULL)
288 CFRelease(interfacePrivate->supported_interface_types);
289
290 if (interfacePrivate->supported_protocol_types != NULL)
291 CFRelease(interfacePrivate->supported_protocol_types);
292
293 if (interfacePrivate->address != NULL)
294 CFRelease(interfacePrivate->address);
295
296 if (interfacePrivate->location != NULL)
297 CFRelease(interfacePrivate->location);
298
299 if (interfacePrivate->path != NULL)
300 CFRelease(interfacePrivate->path);
301
302 return;
303 }
304
305
306 static Boolean
307 __SCNetworkInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2)
308 {
309 SCNetworkInterfacePrivateRef if1 = (SCNetworkInterfacePrivateRef)cf1;
310 SCNetworkInterfacePrivateRef if2 = (SCNetworkInterfacePrivateRef)cf2;
311
312 if (if1 == if2)
313 return TRUE;
314
315 if (!CFEqual(if1->interface_type, if2->interface_type)) {
316 return FALSE; // if not the same interface type
317 }
318
319 if (if1->entity_device != if2->entity_device) {
320 if ((if1->entity_device != NULL) && (if2->entity_device != NULL)) {
321 if (!CFEqual(if1->entity_device, if2->entity_device)) {
322 return FALSE; // if not the same device
323 }
324 } else {
325 return FALSE; // if only one interface has a device
326 }
327 }
328
329 return TRUE;
330 }
331
332
333 static void
334 __SCNetworkInterfaceInitialize(void)
335 {
336 // register w/CF
337 __kSCNetworkInterfaceTypeID = _CFRuntimeRegisterClass(&__SCNetworkInterfaceClass);
338
339 // initialize __kSCNetworkInterfaceIPv4
340 _CFRuntimeSetInstanceTypeID(&__kSCNetworkInterfaceIPv4, __kSCNetworkInterfaceTypeID);
341 __kSCNetworkInterfaceIPv4.interface_type = kSCNetworkInterfaceTypeIPv4;
342 __kSCNetworkInterfaceIPv4.localized_key = CFSTR("ipv4");
343
344 // get CFBundleRef for SystemConfiguration.framework
345 bundle = CFBundleGetBundleWithIdentifier(SYSTEMCONFIGURATION_BUNDLE_ID);
346 if (bundle == NULL) {
347 // try a bit harder
348 CFURLRef url;
349
350 url = CFURLCreateWithFileSystemPath(NULL,
351 CFSTR("/System/Library/Frameworks/SystemConfiguration.framework"),
352 kCFURLPOSIXPathStyle,
353 TRUE);
354 bundle = CFBundleCreate(NULL, url);
355 CFRelease(url);
356 }
357
358 return;
359 }
360
361
362 __private_extern__ SCNetworkInterfacePrivateRef
363 __SCNetworkInterfaceCreatePrivate(CFAllocatorRef allocator,
364 SCNetworkInterfaceRef interface,
365 SCNetworkServiceRef service,
366 io_string_t path)
367 {
368 SCNetworkInterfacePrivateRef interfacePrivate;
369 uint32_t size;
370
371 /* initialize runtime */
372 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
373
374 /* allocate target */
375 size = sizeof(SCNetworkInterfacePrivate) - sizeof(CFRuntimeBase);
376 interfacePrivate = (SCNetworkInterfacePrivateRef)_CFRuntimeCreateInstance(allocator,
377 __kSCNetworkInterfaceTypeID,
378 size,
379 NULL);
380 if (interfacePrivate == NULL) {
381 return NULL;
382 }
383
384 interfacePrivate->interface_type = NULL;
385 interfacePrivate->localized_name = NULL;
386 interfacePrivate->localized_key = NULL;
387 interfacePrivate->localized_arg1 = NULL;
388 interfacePrivate->localized_arg2 = NULL;
389 interfacePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL;
390 interfacePrivate->service = service;
391 interfacePrivate->unsaved = NULL;
392 interfacePrivate->entity_device = NULL;
393 interfacePrivate->entity_hardware = NULL;
394 interfacePrivate->entity_type = NULL;
395 interfacePrivate->entity_subtype = NULL;
396 interfacePrivate->supported_interface_types = NULL;
397 interfacePrivate->supported_protocol_types = NULL;
398 interfacePrivate->address = NULL;
399 interfacePrivate->builtin = FALSE;
400 interfacePrivate->path = (path != NULL) ? CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8)
401 : NULL;
402 interfacePrivate->location = NULL;
403 interfacePrivate->supportsDeviceOnHold = FALSE;
404 interfacePrivate->supportsBond = FALSE;
405 interfacePrivate->supportsVLAN = FALSE;
406 interfacePrivate->sort_order = kSortUnknown;
407
408 return interfacePrivate;
409 }
410
411
412 /* ---------- ordering ---------- */
413
414
415 static CFArrayRef
416 split_path(CFStringRef path)
417 {
418 CFArrayRef components;
419 CFMutableStringRef nPath;
420
421 // turn '@'s into '/'s
422 nPath = CFStringCreateMutableCopy(NULL, 0, path);
423 (void) CFStringFindAndReplace(nPath,
424 CFSTR("@"),
425 CFSTR("/"),
426 CFRangeMake(0, CFStringGetLength(nPath)),
427 0);
428
429 // split path into components to be compared
430 components = CFStringCreateArrayBySeparatingStrings(NULL, nPath, CFSTR("/"));
431 CFRelease(nPath);
432
433 return components;
434 }
435
436
437 static CFComparisonResult
438 compare_interfaces(const void *val1, const void *val2, void *context)
439 {
440 SCNetworkInterfacePrivateRef dev1 = (SCNetworkInterfacePrivateRef)val1;
441 SCNetworkInterfacePrivateRef dev2 = (SCNetworkInterfacePrivateRef)val2;
442 CFComparisonResult res = kCFCompareEqualTo;
443
444 /* sort by interface type */
445 if (dev1->sort_order != dev2->sort_order) {
446 if (dev1->sort_order < dev2->sort_order) {
447 res = kCFCompareLessThan;
448 } else {
449 res = kCFCompareGreaterThan;
450 }
451 return (res);
452 }
453
454 /* built-in interfaces sort first */
455 if (dev1->builtin != dev2->builtin) {
456 if (dev1->builtin) {
457 res = kCFCompareLessThan;
458 } else {
459 res = kCFCompareGreaterThan;
460 }
461 return (res);
462 }
463
464 /* ... and then, sort built-in interfaces by "location" */
465 if (dev1->builtin) {
466 if (dev1->location != dev2->location) {
467 if (isA_CFString(dev1->location)) {
468 if (isA_CFString(dev2->location)) {
469 res = CFStringCompare(dev1->location, dev2->location, 0);
470 } else {
471 res = kCFCompareLessThan;
472 }
473 } else {
474 res = kCFCompareGreaterThan;
475 }
476
477 if (res != kCFCompareEqualTo) {
478 return (res);
479 }
480 }
481 }
482
483 /* ... and, then sort by IOPathMatch */
484 if ((dev1->path != NULL) && (dev2->path != NULL)) {
485 CFArrayRef elements1;
486 CFArrayRef elements2;
487 CFIndex i;
488 CFIndex n;
489 CFIndex n1;
490 CFIndex n2;
491
492 elements1 = split_path(dev1->path);
493 n1 = CFArrayGetCount(elements1);
494
495 elements2 = split_path(dev2->path);
496 n2 = CFArrayGetCount(elements2);
497
498 n = (n1 <= n2) ? n1 : n2;
499 for (i = 0; i < n; i++) {
500 CFStringRef e1;
501 CFStringRef e2;
502 char *end;
503 quad_t q1;
504 quad_t q2;
505 char *str;
506 Boolean isNum;
507
508 e1 = CFArrayGetValueAtIndex(elements1, i);
509 e2 = CFArrayGetValueAtIndex(elements2, i);
510
511 str = _SC_cfstring_to_cstring(e1, NULL, 0, kCFStringEncodingUTF8);
512 errno = 0;
513 q1 = strtoq(str, &end, 16);
514 isNum = ((*str != '\0') && (*end == '\0') && (errno == 0));
515 CFAllocatorDeallocate(NULL, str);
516
517 if (isNum) {
518 // if e1 is a valid numeric string
519 str = _SC_cfstring_to_cstring(e2, NULL, 0, kCFStringEncodingUTF8);
520 errno = 0;
521 q2 = strtoq(str, &end, 16);
522 isNum = ((*str != '\0') && (*end == '\0') && (errno == 0));
523 CFAllocatorDeallocate(NULL, str);
524
525 if (isNum) {
526 // if e2 is also a valid numeric string
527
528 if (q1 == q2) {
529 res = kCFCompareEqualTo;
530 continue;
531 } else if (q1 < q2) {
532 res = kCFCompareLessThan;
533 } else {
534 res = kCFCompareGreaterThan;
535 }
536 break;
537 }
538 }
539
540 res = CFStringCompare(e1, e2, 0);
541 if (res != kCFCompareEqualTo) {
542 break;
543 }
544 }
545
546 if (res == kCFCompareEqualTo) {
547 if (n1 < n2) {
548 res = kCFCompareLessThan;
549 } else if (n1 < n2) {
550 res = kCFCompareGreaterThan;
551 }
552 }
553
554 CFRelease(elements1);
555 CFRelease(elements2);
556
557 if (res != kCFCompareEqualTo) {
558 return (res);
559 }
560 }
561
562 /* ... and lastly, sort by BSD interface name */
563 if ((dev1->entity_device != NULL) && (dev2->entity_device != NULL)) {
564 res = CFStringCompare(dev1->entity_device, dev2->entity_device, 0);
565 }
566
567 return res;
568 }
569
570
571 static void
572 sort_interfaces(CFMutableArrayRef all_interfaces)
573 {
574 int n = CFArrayGetCount(all_interfaces);
575
576 if (n < 2) {
577 return;
578 }
579
580 CFArraySortValues(all_interfaces, CFRangeMake(0, n), compare_interfaces, NULL);
581 return;
582 }
583
584
585 /* ---------- interface details ---------- */
586
587
588 static CFStringRef
589 IOCopyCFStringValue(CFTypeRef ioVal)
590 {
591 if (isA_CFString(ioVal)) {
592 return CFStringCreateCopy(NULL, ioVal);
593 }
594
595 if (isA_CFData(ioVal)) {
596 return CFStringCreateWithCString(NULL, CFDataGetBytePtr(ioVal), kCFStringEncodingUTF8);
597 }
598
599 return NULL;
600 }
601
602
603 static CFStringRef
604 IODictionaryCopyCFStringValue(CFDictionaryRef io_dict, CFStringRef io_key)
605 {
606 CFTypeRef ioVal;
607
608 ioVal = CFDictionaryGetValue(io_dict, io_key);
609 return IOCopyCFStringValue(ioVal);
610 }
611
612
613 static Boolean
614 IOStringValueHasPrefix(CFTypeRef ioVal, CFStringRef prefix)
615 {
616 Boolean match = FALSE;
617 CFIndex prefixLen = CFStringGetLength(prefix);
618 CFStringRef str = ioVal;
619
620 if (!isA_CFString(ioVal)) {
621 if (isA_CFData(ioVal)) {
622 str = CFStringCreateWithCStringNoCopy(NULL,
623 (const char *)CFDataGetBytePtr(ioVal),
624 kCFStringEncodingUTF8,
625 kCFAllocatorNull);
626 } else {
627 return FALSE;
628 }
629 }
630
631 if ((str != NULL) &&
632 (CFStringGetLength(str) >= prefixLen) &&
633 (CFStringCompareWithOptions(str,
634 prefix,
635 CFRangeMake(0, prefixLen),
636 kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
637 match = TRUE;
638 }
639
640 if (str != ioVal) CFRelease(str);
641 return match;
642 }
643
644
645 static CFStringRef
646 copyMACAddress(CFDictionaryRef controller_dict)
647 {
648 CFStringRef address = NULL;
649 uint8_t *bp;
650 char *cp;
651 CFDataRef data;
652 CFIndex n;
653 char mac[sizeof("xx:xx:xx:xx:xx:xx:xx:xx")];
654 char *mac_p = mac;
655
656 data = CFDictionaryGetValue(controller_dict, CFSTR(kIOMACAddress));
657 if (data == NULL) {
658 return NULL;
659 }
660
661 bp = (uint8_t *)CFDataGetBytePtr(data);
662 n = CFDataGetLength(data) * 3;
663
664 if (n > sizeof(mac)) {
665 mac_p = CFAllocatorAllocate(NULL, 0, n);
666 }
667
668 for (cp = mac_p; n > 0; n -= 3) {
669 cp += snprintf(cp, n, "%2.2x:", *bp++);
670 }
671
672 address = CFStringCreateWithCString(NULL, mac_p, kCFStringEncodingUTF8);
673 if (mac_p != mac) CFAllocatorDeallocate(NULL, mac_p);
674 return address;
675 }
676
677
678 static const struct {
679 const CFStringRef name;
680 const CFStringRef slot;
681 } slot_mappings[] = {
682 // Beige G3
683 { CFSTR("A1") , CFSTR("1") },
684 { CFSTR("B1") , CFSTR("2") },
685 { CFSTR("C1") , CFSTR("3") },
686
687 // Blue&White G3, Yikes G4
688 { CFSTR("J12"), CFSTR("1") },
689 { CFSTR("J11"), CFSTR("2") },
690 { CFSTR("J10"), CFSTR("3") },
691 { CFSTR("J9"), CFSTR("4") },
692
693 // AGP G4
694 { CFSTR("A") , CFSTR("1") },
695 { CFSTR("B") , CFSTR("2") },
696 { CFSTR("C") , CFSTR("3") },
697 { CFSTR("D") , CFSTR("4") },
698
699 // Digital Audio G4 (and later models)
700 { CFSTR("1") , CFSTR("1") },
701 { CFSTR("2") , CFSTR("2") },
702 { CFSTR("3") , CFSTR("3") },
703 { CFSTR("4") , CFSTR("4") },
704 { CFSTR("5") , CFSTR("5") }
705 };
706
707
708 static CFStringRef
709 pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name)
710 {
711 kern_return_t kr;
712 io_registry_entry_t slot = interface;
713
714 if (pci_slot_name != NULL) *pci_slot_name = NULL;
715
716 while (slot != MACH_PORT_NULL) {
717 io_registry_entry_t parent;
718 CFTypeRef slot_name;
719
720 slot_name = IORegistryEntryCreateCFProperty(slot, CFSTR("AAPL,slot-name"), NULL, 0);
721 if (slot_name != NULL) {
722 Boolean found;
723
724 found = IOStringValueHasPrefix(slot_name, CFSTR("slot"));
725 if (found) {
726 CFIndex i;
727 CFMutableStringRef name;
728
729 // if we found a slot #
730 name = CFStringCreateMutable(NULL, 0);
731 if (isA_CFString(slot_name)) {
732 if (pci_slot_name != NULL) *pci_slot_name = CFStringCreateCopy(NULL, slot_name);
733 CFStringAppend(name, slot_name);
734 } else if (isA_CFData(slot_name)) {
735 if (pci_slot_name != NULL) *pci_slot_name = CFDataCreateCopy(NULL, slot_name);
736 CFStringAppendCString(name, CFDataGetBytePtr(slot_name), kCFStringEncodingUTF8);
737 }
738
739 (void) CFStringFindAndReplace(name,
740 CFSTR("slot-"),
741 CFSTR(""),
742 CFRangeMake(0, 5),
743 kCFCompareCaseInsensitive|kCFCompareAnchored);
744 for (i = 0; i < sizeof(slot_mappings)/sizeof(slot_mappings[0]); i++) {
745 if (CFStringCompareWithOptions(name,
746 slot_mappings[i].name,
747 CFRangeMake(0, CFStringGetLength(slot_mappings[i].name)),
748 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
749 CFRelease(name);
750 name = (CFMutableStringRef)CFRetain(slot_mappings[i].slot);
751 break;
752 }
753 }
754
755 CFRelease(slot_name);
756 if (slot != interface) IOObjectRelease(slot);
757 return name;
758 }
759
760 CFRelease(slot_name);
761 }
762
763 kr = IORegistryEntryGetParentEntry(slot, kIOServicePlane, &parent);
764 if (slot != interface) IOObjectRelease(slot);
765 switch (kr) {
766 case kIOReturnSuccess :
767 slot = parent;
768 break;
769 case kIOReturnNoDevice :
770 // if we have hit the root node without finding a slot #
771 goto done;
772 default :
773 SCLog(TRUE, LOG_INFO, CFSTR("pci_slot IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
774 goto done;
775 }
776 }
777
778 done :
779
780 return NULL;
781 }
782
783
784 static CFComparisonResult
785 compare_bsdNames(const void *val1, const void *val2, void *context)
786 {
787 CFStringRef bsd1 = (CFStringRef)val1;
788 CFStringRef bsd2 = (CFStringRef)val2;
789
790 return CFStringCompare(bsd1, bsd2, 0);
791 }
792
793
794 static CFStringRef
795 pci_port(mach_port_t masterPort, CFTypeRef slot_name, CFStringRef bsdName)
796 {
797 CFIndex n;
798 CFStringRef port_name = NULL;
799 CFMutableArrayRef port_names;
800
801 kern_return_t kr;
802 CFStringRef match_keys[2];
803 CFTypeRef match_vals[2];
804 CFDictionaryRef match_dict;
805 CFDictionaryRef matching;
806 io_registry_entry_t slot;
807 io_iterator_t slot_iterator = MACH_PORT_NULL;
808
809 match_keys[0] = CFSTR("AAPL,slot-name");
810 match_vals[0] = slot_name;
811
812 match_dict = CFDictionaryCreate(NULL,
813 (const void **)match_keys,
814 (const void **)match_vals,
815 1,
816 &kCFTypeDictionaryKeyCallBacks,
817 &kCFTypeDictionaryValueCallBacks);
818
819 match_keys[0] = CFSTR(kIOProviderClassKey);
820 match_vals[0] = CFSTR("IOPCIDevice");
821
822 match_keys[1] = CFSTR(kIOPropertyMatchKey);
823 match_vals[1] = match_dict;
824
825 // note: the "matching" dictionary will be consumed by the following
826 matching = CFDictionaryCreate(NULL,
827 (const void **)match_keys,
828 (const void **)match_vals,
829 sizeof(match_keys)/sizeof(match_keys[0]),
830 &kCFTypeDictionaryKeyCallBacks,
831 &kCFTypeDictionaryValueCallBacks);
832 CFRelease(match_dict);
833
834 kr = IOServiceGetMatchingServices(masterPort, matching, &slot_iterator);
835 if (kr != kIOReturnSuccess) {
836 SCPrint(TRUE, stderr, CFSTR("IOServiceGetMatchingServices() failed, kr = 0x%x\n"), kr);
837 return MACH_PORT_NULL;
838 }
839
840 port_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
841
842 while ((slot = IOIteratorNext(slot_iterator)) != MACH_PORT_NULL) {
843 io_registry_entry_t child;
844 io_iterator_t child_iterator = MACH_PORT_NULL;
845
846 kr = IORegistryEntryCreateIterator(slot,
847 kIOServicePlane,
848 kIORegistryIterateRecursively,
849 &child_iterator);
850 if (kr != kIOReturnSuccess) {
851 SCPrint(TRUE, stderr, CFSTR("IORegistryEntryCreateIterator() failed, kr = 0x%x\n"), kr);
852 return MACH_PORT_NULL;
853 }
854
855 while ((child = IOIteratorNext(child_iterator)) != MACH_PORT_NULL) {
856 if (IOObjectConformsTo(child, kIONetworkInterfaceClass)) {
857 CFStringRef if_bsdName;
858
859 if_bsdName = IORegistryEntryCreateCFProperty(child,
860 CFSTR(kIOBSDNameKey),
861 NULL,
862 0);
863 if (if_bsdName != NULL) {
864 CFArrayAppendValue(port_names, if_bsdName);
865 CFRelease(if_bsdName);
866 }
867 }
868 IOObjectRelease(child);
869 }
870 IOObjectRelease(child_iterator);
871 IOObjectRelease(slot);
872 }
873 IOObjectRelease(slot_iterator);
874
875 n = CFArrayGetCount(port_names);
876 if (n > 1) {
877 CFArraySortValues(port_names, CFRangeMake(0, n), compare_bsdNames, NULL);
878 n = CFArrayGetFirstIndexOfValue(port_names, CFRangeMake(0, n), bsdName);
879 if (n != kCFNotFound) {
880 port_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), n + 1);
881 }
882 }
883
884 CFRelease(port_names);
885 return port_name;
886 }
887
888
889 static Boolean
890 pci_slot_info(mach_port_t masterPort, io_registry_entry_t interface, CFStringRef *slot_name, CFStringRef *port_name)
891 {
892 CFStringRef bsd_name;
893 Boolean ok = FALSE;
894 CFTypeRef pci_slot_name;
895
896 *slot_name = NULL;
897 *port_name = NULL;
898
899 bsd_name = IORegistryEntryCreateCFProperty(interface, CFSTR(kIOBSDNameKey), NULL, 0);
900 if (bsd_name == NULL) {
901 return FALSE;
902 }
903
904 *slot_name = pci_slot(interface, &pci_slot_name);
905 if (*slot_name != NULL) {
906 if (pci_slot_name != NULL) {
907 *port_name = pci_port(masterPort, pci_slot_name, bsd_name);
908 CFRelease(pci_slot_name);
909 }
910 ok = TRUE;
911 }
912
913 CFRelease(bsd_name);
914 return ok;
915 }
916
917
918 static Boolean
919 isBuiltIn(io_registry_entry_t interface)
920 {
921 kern_return_t kr;
922 io_registry_entry_t slot = interface;
923
924 while (slot != MACH_PORT_NULL) {
925 io_registry_entry_t parent;
926 CFTypeRef slot_name;
927
928 slot_name = IORegistryEntryCreateCFProperty(slot, CFSTR("AAPL,slot-name"), NULL, 0);
929 if (slot_name != NULL) {
930 Boolean found;
931
932 found = IOStringValueHasPrefix(slot_name, CFSTR("slot"));
933 CFRelease(slot_name);
934
935 if (found) {
936 // if we found a slot # then this is not a built-in interface
937 if (slot != interface) IOObjectRelease(slot);
938 return FALSE;
939 }
940 }
941
942 kr = IORegistryEntryGetParentEntry(slot, kIOServicePlane, &parent);
943 if (slot != interface) IOObjectRelease(slot);
944 switch (kr) {
945 case kIOReturnSuccess :
946 slot = parent;
947 break;
948 case kIOReturnNoDevice :
949 // if we have hit the root node without finding a slot #
950 return TRUE;
951 default :
952 SCLog(TRUE, LOG_INFO, CFSTR("isBuiltIn IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
953 return FALSE;
954 }
955 }
956
957 return FALSE;
958 }
959
960
961 /* ---------- interface enumeration ---------- */
962
963
964 typedef Boolean (*processInterface)(mach_port_t masterPort,
965 SCNetworkInterfacePrivateRef interfacePrivate,
966 io_registry_entry_t interface,
967 CFDictionaryRef interface_dict,
968 io_registry_entry_t controller,
969 CFDictionaryRef controller_dict,
970 io_registry_entry_t bus,
971 CFDictionaryRef bus_dict);
972
973
974 static Boolean
975 processNetworkInterface(mach_port_t masterPort,
976 SCNetworkInterfacePrivateRef interfacePrivate,
977 io_registry_entry_t interface,
978 CFDictionaryRef interface_dict,
979 io_registry_entry_t controller,
980 CFDictionaryRef controller_dict,
981 io_registry_entry_t bus,
982 CFDictionaryRef bus_dict)
983 {
984 CFBooleanRef bVal;
985 io_name_t c_IOClass;
986 io_name_t c_IOName;
987 io_name_t i_IOClass;
988 int ift = -1;
989 int iVal;
990 CFNumberRef num;
991 CFStringRef str;
992
993 // get the interface type
994
995 num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceType));
996 if (!isA_CFNumber(num) ||
997 !CFNumberGetValue(num, kCFNumberIntType, &ift)) {
998 SCPrint(TRUE, stderr, CFSTR("Could not get interface type\n"));
999 return FALSE;
1000 }
1001
1002 switch (ift) {
1003 case IFT_ETHER :
1004 // Type, Hardware
1005
1006 if (IOObjectGetClass(interface, i_IOClass) != KERN_SUCCESS) {
1007 i_IOClass[0] = '\0';
1008 }
1009 if (IOObjectGetClass(controller, c_IOClass) != KERN_SUCCESS) {
1010 c_IOClass[0] = '\0';
1011 }
1012 if (IORegistryEntryGetName(controller, c_IOName) != KERN_SUCCESS) {
1013 c_IOName[0] = '\0';
1014 }
1015
1016 if ((strcmp(i_IOClass, "IO80211Interface" ) == 0) ||
1017 (strcmp(c_IOClass, "AirPortPCI" ) == 0) ||
1018 (strcmp(c_IOClass, "AirPortDriver" ) == 0) ||
1019 (strcmp(c_IOName , "AppleWireless80211") == 0)) {
1020 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
1021 interfacePrivate->entity_type = kSCEntNetEthernet;
1022 interfacePrivate->entity_hardware = kSCEntNetAirPort;
1023 interfacePrivate->sort_order = kSortAirPort;
1024 } else {
1025 str = IODictionaryCopyCFStringValue(bus_dict, CFSTR("name"));
1026 if ((str != NULL) && CFEqual(str, CFSTR("radio"))) {
1027 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; // ??
1028 interfacePrivate->entity_type = kSCEntNetEthernet;
1029 interfacePrivate->entity_hardware = kSCEntNetEthernet; // ??
1030 interfacePrivate->sort_order = kSortOtherWireless;
1031 } else {
1032 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
1033 interfacePrivate->entity_type = kSCEntNetEthernet;
1034 interfacePrivate->entity_hardware = kSCEntNetEthernet;
1035 interfacePrivate->sort_order = kSortEthernet;
1036
1037 // BOND support only enabled for ethernet devices
1038 interfacePrivate->supportsBond = TRUE;
1039 }
1040
1041 if (str != NULL) CFRelease(str);
1042 }
1043
1044 // built-in
1045 bVal = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOBuiltin)));
1046 if ((bVal == NULL) || !CFBooleanGetValue(bVal)) {
1047 bVal = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOPrimaryInterface)));
1048 }
1049 if (bVal != NULL) {
1050 interfacePrivate->builtin = CFBooleanGetValue(bVal);
1051 } else {
1052 interfacePrivate->builtin = isBuiltIn(interface);
1053 }
1054
1055 // location
1056 interfacePrivate->location = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOLocation));
1057
1058 // VLAN support
1059 num = CFDictionaryGetValue(controller_dict, CFSTR(kIOFeatures));
1060 if (isA_CFNumber(num) &&
1061 CFNumberGetValue(num, kCFNumberIntType, & iVal)) {
1062 if (iVal & (kIONetworkFeatureHardwareVlan | kIONetworkFeatureSoftwareVlan)) {
1063 interfacePrivate->supportsVLAN = TRUE;
1064 }
1065 }
1066
1067 // localized name
1068 if (interfacePrivate->builtin) {
1069 if ((interfacePrivate->location == NULL) ||
1070 (CFStringGetLength(interfacePrivate->location) == 0)) {
1071 interfacePrivate->localized_key = CFSTR("ether");
1072 } else {
1073 interfacePrivate->localized_key = CFSTR("multiether");
1074 interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->location);
1075 }
1076 } else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) {
1077 interfacePrivate->localized_key = CFSTR("airport");
1078 } else if (interfacePrivate->sort_order == kSortOtherWireless) {
1079 interfacePrivate->localized_key = CFSTR("wireless");
1080 interfacePrivate->localized_arg1 = CFRetain(CFSTR("")); // ??
1081 } else {
1082 CFStringRef provider;
1083
1084 // check provider class
1085 provider = IORegistryEntrySearchCFProperty(interface,
1086 kIOServicePlane,
1087 CFSTR(kIOProviderClassKey),
1088 NULL,
1089 kIORegistryIterateRecursively | kIORegistryIterateParents);
1090 if (provider != NULL) {
1091 if (CFEqual(provider, CFSTR("IOPCIDevice"))) {
1092 CFStringRef port_name;
1093 CFStringRef slot_name;
1094
1095 if (pci_slot_info(masterPort, interface, &slot_name, &port_name)) {
1096 if (port_name == NULL) {
1097 interfacePrivate->localized_key = CFSTR("pci-ether");
1098 interfacePrivate->localized_arg1 = slot_name;
1099 } else {
1100 interfacePrivate->localized_key = CFSTR("pci-multiether");
1101 interfacePrivate->localized_arg1 = slot_name;
1102 interfacePrivate->localized_arg2 = port_name;
1103 }
1104 }
1105 }
1106 CFRelease(provider);
1107 }
1108
1109 if (interfacePrivate->localized_key == NULL) {
1110 // if no provider, not a PCI device, or no slot information
1111 interfacePrivate->localized_key = CFSTR("generic-ether");
1112 interfacePrivate->localized_arg1 = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey));
1113 }
1114 }
1115
1116 break;
1117 case IFT_IEEE1394 :
1118 // Type
1119 interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire;
1120
1121 // Entity
1122 interfacePrivate->entity_type = kSCEntNetFireWire;
1123 interfacePrivate->entity_hardware = kSCEntNetFireWire;
1124
1125 // built-in
1126 interfacePrivate->builtin = isBuiltIn(interface);
1127
1128 // sort order
1129 interfacePrivate->sort_order = kSortFireWire;
1130
1131 // localized name
1132 if (interfacePrivate->builtin) {
1133 interfacePrivate->localized_key = CFSTR("firewire");
1134 } else {
1135 CFStringRef slot_name;
1136
1137 slot_name = pci_slot(interface, NULL);
1138 if (slot_name != NULL) {
1139 interfacePrivate->localized_key = CFSTR("pci-firewire");
1140 interfacePrivate->localized_arg1 = slot_name;
1141 }
1142 }
1143
1144 break;
1145 default :
1146 SCPrint(TRUE, stderr, CFSTR("Unknown interface type = %d\n"), ift);
1147 return FALSE;
1148 }
1149
1150 // Device
1151 interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey));
1152
1153 // Hardware (MAC) address
1154 interfacePrivate->address = copyMACAddress(controller_dict);
1155
1156 return TRUE;
1157 }
1158
1159
1160 static Boolean
1161 processSerialInterface(mach_port_t masterPort,
1162 SCNetworkInterfacePrivateRef interfacePrivate,
1163 io_registry_entry_t interface,
1164 CFDictionaryRef interface_dict,
1165 io_registry_entry_t controller,
1166 CFDictionaryRef controller_dict,
1167 io_registry_entry_t bus,
1168 CFDictionaryRef bus_dict)
1169 {
1170 CFStringRef ift;
1171 Boolean isModem = FALSE;
1172 CFStringRef str;
1173 CFTypeRef val;
1174
1175 // check if hidden
1176 val = IORegistryEntrySearchCFProperty(interface,
1177 kIOServicePlane,
1178 CFSTR("HiddenPort"),
1179 NULL,
1180 kIORegistryIterateRecursively | kIORegistryIterateParents);
1181 if (val != NULL) {
1182 CFRelease(val);
1183 return FALSE; // if this interface should not be exposed
1184 }
1185
1186 // Type
1187 str = CFDictionaryGetValue(interface_dict, CFSTR(kIOTTYBaseNameKey));
1188 if (str == NULL) {
1189 return FALSE;
1190 }
1191
1192 /*
1193 * From MoreSCF:
1194 *
1195 * Exclude ports named "irda" because otherwise the IrDA ports on the
1196 * original iMac (rev's A through D) show up as serial ports. Given
1197 * that only the rev A actually had an IrDA port, and Mac OS X doesn't
1198 * even support it, these ports definitely shouldn't be listed.
1199 */
1200 if (CFStringCompare(str,
1201 CFSTR("irda"),
1202 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
1203 return FALSE;
1204 }
1205
1206 if (IOStringValueHasPrefix(str, CFSTR("irda-ircomm"))) {
1207 // IrDA
1208 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA;
1209 interfacePrivate->sort_order = kSortIrDA;
1210 } else if (IOStringValueHasPrefix(str, CFSTR("bluetooth"))) {
1211 // Bluetooth
1212 interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth;
1213 interfacePrivate->sort_order = kSortBluetooth;
1214 } else {
1215 // Modem
1216 interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem;
1217
1218 // DeviceOnHold support
1219 val = IORegistryEntrySearchCFProperty(interface,
1220 kIOServicePlane,
1221 CFSTR(kIODeviceSupportsHoldKey),
1222 NULL,
1223 kIORegistryIterateRecursively | kIORegistryIterateParents);
1224 if (val != NULL) {
1225 uint32_t supportsHold;
1226
1227 if (isA_CFNumber(val) &&
1228 CFNumberGetValue(val, kCFNumberSInt32Type, &supportsHold)) {
1229 interfacePrivate->supportsDeviceOnHold = (supportsHold == 1);
1230 }
1231 CFRelease(val);
1232 }
1233 }
1234
1235 // Entity (Type)
1236 interfacePrivate->entity_type = kSCEntNetModem;
1237
1238 // Entity (Hardware)
1239 ift = CFDictionaryGetValue(interface_dict, CFSTR(kIOSerialBSDTypeKey));
1240 if (!isA_CFString(ift)) {
1241 return FALSE;
1242 }
1243
1244 if (CFEqual(ift, CFSTR(kIOSerialBSDModemType))) {
1245 // if modem
1246 isModem = TRUE;
1247 interfacePrivate->entity_hardware = kSCEntNetModem;
1248
1249 if (CFEqual(str, CFSTR("modem"))) {
1250 interfacePrivate->builtin = TRUE;
1251 interfacePrivate->sort_order = kSortInternalModem;
1252 } else if (CFEqual(str, CFSTR("usbmodem"))) {
1253 interfacePrivate->sort_order = kSortUSBModem;
1254 } else {
1255 interfacePrivate->sort_order = kSortModem;
1256 }
1257 } else if (CFEqual(ift, CFSTR(kIOSerialBSDRS232Type))) {
1258 // if serial port
1259 interfacePrivate->entity_hardware = kSCEntNetModem;
1260 interfacePrivate->sort_order = kSortSerialPort;
1261 } else {
1262 return FALSE;
1263 }
1264
1265 // Entity (Device)
1266 interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOTTYDeviceKey));
1267
1268 // localized name
1269 if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIrDA)) {
1270 interfacePrivate->localized_key = CFSTR("irda");
1271 } else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBluetooth)) {
1272 interfacePrivate->localized_key = CFSTR("bluetooth");
1273 } else {
1274 CFStringRef localized;
1275 CFMutableStringRef port;
1276
1277 port = CFStringCreateMutableCopy(NULL, 0, str);
1278 CFStringLowercase(port, NULL);
1279
1280 if (!isModem) {
1281 CFStringAppend(port, CFSTR("-port"));
1282 }
1283
1284 localized = CFBundleCopyLocalizedString(bundle,
1285 port,
1286 port,
1287 NETWORKINTERFACE_LOCALIZATIONS);
1288 if (localized != NULL) {
1289 if (!CFEqual(port, localized)) {
1290 // if localization available
1291 interfacePrivate->localized_name = localized;
1292 } else {
1293 // if no localization available, use TTY base name
1294 CFRelease(localized);
1295 interfacePrivate->localized_name = CFStringCreateCopy(NULL, str);
1296 }
1297 } else {
1298 interfacePrivate->localized_name = CFStringCreateCopy(NULL, str);
1299 }
1300
1301 if (!isModem || !CFEqual(str, CFSTR("modem"))) {
1302 CFStringRef productName;
1303
1304 // check if a "Product Name" has been provided
1305 val = IORegistryEntrySearchCFProperty(interface,
1306 kIOServicePlane,
1307 CFSTR(kIOPropertyProductNameKey),
1308 NULL,
1309 kIORegistryIterateRecursively | kIORegistryIterateParents);
1310 if (val != NULL) {
1311 productName = IOCopyCFStringValue(val);
1312 CFRelease(val);
1313
1314 if (productName != NULL) {
1315 if (CFStringGetLength(productName) > 0) {
1316 // if we have a [somewhat reasonable?] product name
1317 CFRelease(interfacePrivate->localized_name);
1318 interfacePrivate->localized_name = CFRetain(productName);
1319 }
1320 CFRelease(productName);
1321 }
1322 }
1323 }
1324
1325 CFRelease(port);
1326 }
1327
1328 return TRUE;
1329 }
1330
1331
1332 static CFArrayRef
1333 findMatchingInterfaces(mach_port_t masterPort, CFDictionaryRef matching, processInterface func)
1334 {
1335 CFMutableArrayRef interfaces;
1336 io_registry_entry_t interface;
1337 kern_return_t kr;
1338 io_iterator_t iterator = MACH_PORT_NULL;
1339
1340 kr = IOServiceGetMatchingServices(masterPort, matching, &iterator);
1341 if (kr != kIOReturnSuccess) {
1342 SCPrint(TRUE, stderr, CFSTR("IOServiceGetMatchingServices() failed, kr = 0x%x\n"), kr);
1343 return NULL;
1344 }
1345
1346 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1347
1348 while ((interface = IOIteratorNext(iterator)) != MACH_PORT_NULL) {
1349 io_registry_entry_t bus = MACH_PORT_NULL;
1350 CFMutableDictionaryRef bus_dict = NULL;
1351 io_registry_entry_t controller = MACH_PORT_NULL;
1352 CFMutableDictionaryRef controller_dict = NULL;
1353 SCNetworkInterfacePrivateRef interfacePrivate = NULL;
1354 CFMutableDictionaryRef interface_dict = NULL;
1355 io_string_t path;
1356
1357 kr = IORegistryEntryGetPath(interface, kIOServicePlane, path);
1358 if (kr != kIOReturnSuccess) {
1359 SCPrint(TRUE, stderr, CFSTR("IORegistryEntryGetPath() failed, kr = 0x%x"), kr);
1360 goto done;
1361 }
1362
1363 kr = IORegistryEntryCreateCFProperties(interface, &interface_dict, NULL, kNilOptions);
1364 if (kr != kIOReturnSuccess) {
1365 SCPrint(TRUE, stderr, CFSTR("IORegistryEntryCreateCFProperties() failed, kr = 0x%x\n"), kr);
1366 goto done;
1367 }
1368
1369 /* get the controller node */
1370 kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &controller);
1371 if (kr != KERN_SUCCESS) {
1372 SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
1373 goto done;
1374 }
1375
1376 /* get the dictionary associated with the node */
1377 kr = IORegistryEntryCreateCFProperties(controller, &controller_dict, NULL, kNilOptions);
1378 if (kr != KERN_SUCCESS) {
1379 SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
1380 goto done;
1381 }
1382
1383 /* get the bus node */
1384 kr = IORegistryEntryGetParentEntry(controller, kIOServicePlane, &bus);
1385 if (kr != KERN_SUCCESS) {
1386 SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
1387 goto done;
1388 }
1389
1390 /* get the dictionary associated with the node */
1391 kr = IORegistryEntryCreateCFProperties(bus, &bus_dict, NULL, kNilOptions);
1392 if (kr != KERN_SUCCESS) {
1393 SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
1394 goto done;
1395 }
1396
1397 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, path);
1398
1399 if ((*func)(masterPort, interfacePrivate, interface, interface_dict, controller, controller_dict, bus, bus_dict)) {
1400 CFArrayAppendValue(interfaces, (SCNetworkInterfaceRef)interfacePrivate);
1401 }
1402
1403 CFRelease(interfacePrivate);
1404
1405 done:
1406
1407 if (interface != MACH_PORT_NULL) IOObjectRelease(interface);
1408 if (interface_dict != NULL) CFRelease(interface_dict);
1409
1410 if (controller != MACH_PORT_NULL) IOObjectRelease(controller);
1411 if (controller_dict != NULL) CFRelease(controller_dict);
1412
1413 if (bus != MACH_PORT_NULL) IOObjectRelease(bus);
1414 if (bus_dict != NULL) CFRelease(bus_dict);
1415 }
1416
1417 IOObjectRelease(iterator);
1418
1419 return interfaces;
1420 }
1421
1422
1423 /* ---------- Bond configuration ---------- */
1424
1425 Boolean
1426 SCNetworkInterfaceSupportsBonding(SCNetworkInterfaceRef interface)
1427 {
1428 return ((SCNetworkInterfacePrivateRef)interface)->supportsBond;
1429 }
1430
1431
1432 SCNetworkInterfaceRef
1433 SCNetworkInterfaceCreateWithBond(BondInterfaceRef bond)
1434 {
1435 SCNetworkInterfacePrivateRef interfacePrivate;
1436 CFStringRef bond_if;
1437
1438 bond_if = BondInterfaceGetInterface(bond);
1439 if (bond_if == NULL) {
1440 return NULL;
1441 }
1442
1443 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
1444 if (interfacePrivate == NULL) {
1445 return NULL;
1446 }
1447
1448 interfacePrivate->interface_type = kSCNetworkInterfaceTypeBond;
1449 interfacePrivate->entity_type = kSCEntNetEthernet;
1450 interfacePrivate->entity_hardware = kSCEntNetEthernet;
1451 interfacePrivate->entity_device = CFStringCreateCopy(NULL, bond_if);
1452 interfacePrivate->builtin = TRUE;
1453 interfacePrivate->sort_order = kSortBond;
1454
1455 interfacePrivate->localized_key = CFSTR("bond");
1456 interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device);
1457
1458 return (SCNetworkInterfaceRef)interfacePrivate;
1459 }
1460
1461
1462 static CFArrayRef
1463 findBondInterfaces(CFStringRef match)
1464 {
1465 CFMutableArrayRef interfaces = NULL;
1466 CFIndex i;
1467 CFIndex n;
1468 BondPreferencesRef prefs;
1469 CFArrayRef bonds = NULL;
1470
1471 prefs = BondPreferencesCreate(NULL);
1472 if (prefs == NULL) {
1473 // if no bonds
1474 return NULL;
1475 }
1476
1477 bonds = BondPreferencesCopyInterfaces(prefs);
1478 if (bonds == NULL) {
1479 // if no bonds
1480 goto done;
1481 }
1482
1483 n = CFArrayGetCount(bonds);
1484 if (n == 0) {
1485 // if no bonds
1486 goto done;
1487 }
1488
1489 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1490
1491 for (i = 0; i < n; i++) {
1492 SCNetworkInterfaceRef interface;
1493 BondInterfaceRef bond = CFArrayGetValueAtIndex(bonds, i);
1494 CFStringRef bond_if;
1495
1496 bond_if = BondInterfaceGetInterface(bond);
1497 if (bond_if == NULL) {
1498 continue;
1499 }
1500
1501 if ((match != NULL) && !CFEqual(bond_if, match)) {
1502 continue;
1503 }
1504
1505 interface = SCNetworkInterfaceCreateWithBond(bond);
1506 CFArrayAppendValue(interfaces, interface);
1507 CFRelease(interface);
1508 }
1509
1510 done :
1511
1512 if (bonds != NULL) CFRelease(bonds);
1513 CFRelease(prefs);
1514 return interfaces;
1515 }
1516
1517
1518 /* ---------- VLAN configuration ---------- */
1519
1520 SCNetworkInterfaceRef
1521 SCNetworkInterfaceCreateWithVLAN(VLANInterfaceRef vlan)
1522 {
1523 SCNetworkInterfacePrivateRef interfacePrivate;
1524 CFStringRef vlan_if;
1525
1526 vlan_if = VLANInterfaceGetInterface(vlan);
1527 if (vlan_if == NULL) {
1528 return NULL;
1529 }
1530
1531 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
1532 if (interfacePrivate == NULL) {
1533 return NULL;
1534 }
1535
1536 interfacePrivate->interface_type = kSCNetworkInterfaceTypeVLAN;
1537 interfacePrivate->entity_type = kSCEntNetEthernet;
1538 interfacePrivate->entity_hardware = kSCEntNetEthernet;
1539 interfacePrivate->entity_device = CFStringCreateCopy(NULL, vlan_if);
1540 interfacePrivate->builtin = TRUE;
1541 interfacePrivate->sort_order = kSortVLAN;
1542
1543 interfacePrivate->localized_key = CFSTR("vlan");
1544 interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device);
1545
1546 return (SCNetworkInterfaceRef)interfacePrivate;
1547 }
1548
1549
1550 static CFArrayRef
1551 findVLANInterfaces(CFStringRef match)
1552 {
1553 CFMutableArrayRef interfaces = NULL;
1554 CFIndex i;
1555 CFIndex n;
1556 VLANPreferencesRef prefs;
1557 CFArrayRef vlans = NULL;
1558
1559 prefs = VLANPreferencesCreate(NULL);
1560 if (prefs == NULL) {
1561 // if no VLANs
1562 return NULL;
1563 }
1564
1565 vlans = VLANPreferencesCopyInterfaces(prefs);
1566 if (vlans == NULL) {
1567 // if no VLANs
1568 goto done;
1569 }
1570
1571 n = CFArrayGetCount(vlans);
1572 if (n == 0) {
1573 // if no VLANs
1574 goto done;
1575 }
1576
1577 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1578
1579 for (i = 0; i < n; i++) {
1580 SCNetworkInterfaceRef interface;
1581 VLANInterfaceRef vlan = CFArrayGetValueAtIndex(vlans, i);
1582 CFStringRef vlan_if;
1583
1584 vlan_if = VLANInterfaceGetInterface(vlan);
1585 if (vlan_if == NULL) {
1586 continue;
1587 }
1588
1589 if ((match != NULL) && !CFEqual(vlan_if, match)) {
1590 continue;
1591 }
1592
1593 interface = SCNetworkInterfaceCreateWithVLAN(vlan);
1594 CFArrayAppendValue(interfaces, interface);
1595 CFRelease(interface);
1596 }
1597
1598 done :
1599
1600 if (vlans != NULL) CFRelease(vlans);
1601 CFRelease(prefs);
1602 return interfaces;
1603 }
1604
1605
1606 /* ---------- interface from preferences ---------- */
1607
1608
1609 __private_extern__ SCNetworkInterfaceRef
1610 __SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator,
1611 CFDictionaryRef interface_entity,
1612 SCNetworkServiceRef service)
1613 {
1614 SCNetworkInterfacePrivateRef interfacePrivate = NULL;
1615 CFStringRef ifDevice;
1616 CFStringRef ifSubType;
1617 CFStringRef ifType;
1618 static mach_port_t masterPort = MACH_PORT_NULL;
1619 CFArrayRef matching_interfaces = NULL;
1620
1621 if (masterPort == MACH_PORT_NULL) {
1622 kern_return_t kr;
1623
1624 kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
1625 if (kr != KERN_SUCCESS) {
1626 return NULL;
1627 }
1628 }
1629
1630 ifType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceType);
1631 if (!isA_CFString(ifType)) {
1632 return NULL;
1633 }
1634
1635 ifSubType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceSubType);
1636 if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
1637 if (!isA_CFString(ifSubType)) {
1638 return NULL;
1639 }
1640 }
1641
1642 ifDevice = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceDeviceName);
1643
1644 if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet) ||
1645 CFEqual(ifType, kSCValNetInterfaceTypeFireWire) ||
1646 (CFEqual(ifType, kSCValNetInterfaceTypePPP) && CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE))) {
1647 char bsdName[IFNAMSIZ + 1];
1648 CFMutableDictionaryRef matching;
1649
1650 if (!isA_CFString(ifDevice)) {
1651 return NULL;
1652 }
1653
1654 if (_SC_cfstring_to_cstring(ifDevice, bsdName, sizeof(bsdName), kCFStringEncodingASCII) == NULL) {
1655 goto done;
1656 }
1657
1658 matching = IOBSDNameMatching(masterPort, 0, bsdName);
1659 if (matching == NULL) {
1660 goto done;
1661 }
1662
1663 // note: the "matching" dictionary will be consumed by the following
1664 matching_interfaces = findMatchingInterfaces(masterPort, matching, processNetworkInterface);
1665
1666 } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
1667 if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) {
1668 CFDictionaryRef matching;
1669 CFStringRef match_keys[2];
1670 CFStringRef match_vals[2];
1671
1672 if (!isA_CFString(ifDevice)) {
1673 return NULL;
1674 }
1675
1676 match_keys[0] = CFSTR(kIOProviderClassKey);
1677 match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
1678
1679 match_keys[1] = CFSTR(kIOTTYDeviceKey);
1680 match_vals[1] = ifDevice;
1681
1682 matching = CFDictionaryCreate(NULL,
1683 (const void **)match_keys,
1684 (const void **)match_vals,
1685 sizeof(match_keys)/sizeof(match_keys[0]),
1686 &kCFTypeDictionaryKeyCallBacks,
1687 &kCFTypeDictionaryValueCallBacks);
1688
1689 // note: the "matching" dictionary will be consumed by the following
1690 matching_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface);
1691
1692 } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypeL2TP)) {
1693 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
1694 kSCNetworkInterfaceTypeL2TP);
1695 } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPTP)) {
1696 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
1697 kSCNetworkInterfaceTypePPTP);
1698 } else {
1699 // XXX do we allow non-Apple variants of PPP??? XXX
1700 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
1701 ifSubType);
1702 }
1703 } else if (CFEqual(ifType, kSCValNetInterfaceType6to4)) {
1704 if (!isA_CFString(ifDevice)) {
1705 return NULL;
1706 }
1707
1708 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
1709 kSCNetworkInterfaceType6to4);
1710 }
1711
1712 if (matching_interfaces != NULL) {
1713 CFIndex n;
1714
1715 n = CFArrayGetCount(matching_interfaces);
1716 switch (n) {
1717 case 0 :
1718 if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) {
1719 CFArrayRef bonds;
1720 CFArrayRef vlans;
1721
1722 bonds = findBondInterfaces(ifDevice);
1723 if (bonds != NULL) {
1724 if (CFArrayGetCount(bonds) == 1) {
1725 interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(bonds, 0);
1726 CFRetain(interfacePrivate);
1727 }
1728 CFRelease(bonds);
1729 break;
1730 }
1731
1732 vlans = findVLANInterfaces(ifDevice);
1733 if (vlans != NULL) {
1734 if (CFArrayGetCount(vlans) == 1) {
1735 interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(vlans, 0);
1736 CFRetain(interfacePrivate);
1737 }
1738 CFRelease(vlans);
1739 break;
1740 }
1741 }
1742 break;
1743 case 1 :
1744 interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0);
1745 CFRetain(interfacePrivate);
1746 break;
1747 default :
1748 SCPrint(TRUE, stderr, CFSTR("more than one interface matches %@\n"), ifDevice);
1749 if (matching_interfaces != NULL) CFRelease(matching_interfaces);
1750 _SCErrorSet(kSCStatusFailed);
1751 return NULL;
1752 }
1753 CFRelease(matching_interfaces);
1754 }
1755
1756 done :
1757
1758 if (interfacePrivate == NULL) {
1759 /*
1760 * if device not present on this system
1761 */
1762 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
1763 interfacePrivate->entity_type = ifType;
1764 interfacePrivate->entity_subtype = ifSubType;
1765 interfacePrivate->entity_device = (ifDevice != NULL) ? CFStringCreateCopy(NULL, ifDevice) : NULL;
1766 interfacePrivate->entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware);
1767
1768 if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) {
1769 if ((interfacePrivate->entity_hardware != NULL) &&
1770 CFEqual(interfacePrivate->entity_hardware, kSCEntNetAirPort)) {
1771 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
1772 } else {
1773 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
1774 }
1775 } else if (CFEqual(ifType, kSCValNetInterfaceTypeFireWire)) {
1776 interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire;
1777 } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
1778 if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE)) {
1779 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
1780 } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) {
1781 if (CFStringHasPrefix(ifDevice, CFSTR("irda"))) {
1782 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA;
1783 } else if (CFStringHasPrefix(ifDevice, CFSTR("Bluetooth"))) {
1784 interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth;
1785 } else {
1786 interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem;
1787 }
1788 } else {
1789 // PPTP, L2TP, ...
1790 CFRelease(interfacePrivate);
1791 interfacePrivate = (SCNetworkInterfacePrivateRef)kSCNetworkInterfaceIPv4;
1792 CFRetain(interfacePrivate);
1793 }
1794 } else {
1795 // unknown interface type
1796 CFRelease(interfacePrivate);
1797 interfacePrivate = NULL;
1798 }
1799 }
1800
1801 if ((interfacePrivate != NULL) && (service != NULL)) {
1802 interfacePrivate->service = service;
1803 }
1804
1805 if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
1806 SCNetworkInterfaceRef parent;
1807
1808 parent = SCNetworkInterfaceCreateWithInterface((SCNetworkInterfaceRef)interfacePrivate,
1809 kSCNetworkInterfaceTypePPP);
1810 CFRelease(interfacePrivate);
1811 interfacePrivate = (SCNetworkInterfacePrivateRef)parent;
1812 }
1813
1814 return (SCNetworkInterfaceRef)interfacePrivate;
1815 }
1816
1817
1818 /* ---------- helper functions ---------- */
1819
1820
1821 static CFIndex
1822 findConfiguration(CFStringRef interface_type)
1823 {
1824 CFIndex i;
1825
1826 for (i = 0; i < sizeof(configurations)/sizeof(configurations[0]); i++) {
1827 if (CFEqual(interface_type, *configurations[i].interface_type)) {
1828 return i;
1829 }
1830 }
1831
1832 return kCFNotFound;
1833 }
1834
1835
1836 static CFArrayRef
1837 copyConfigurationPaths(SCNetworkInterfacePrivateRef interfacePrivate)
1838 {
1839 CFMutableArrayRef array = NULL;
1840 CFIndex interfaceIndex;
1841 CFStringRef path;
1842 SCNetworkServicePrivateRef servicePrivate;
1843
1844 interfaceIndex = findConfiguration(interfacePrivate->interface_type);
1845 if (interfaceIndex == kCFNotFound) {
1846 // if unknown interface type
1847 return NULL;
1848 }
1849
1850 servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service;
1851 if (servicePrivate == NULL) {
1852 // if not associated with a service (yet)
1853 return NULL;
1854 }
1855
1856 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1857
1858 if (configurations[interfaceIndex].per_interface_config) {
1859 CFIndex i;
1860 CFIndex n;
1861 CFArrayRef sets;
1862
1863 /*
1864 * per-interface configuration preferences
1865 *
1866 * 1. look for all sets which contain the associated service
1867 * 2. add a per-set path for the interface configuration for
1868 * each set.
1869 */
1870
1871 sets = SCNetworkSetCopyAll(servicePrivate->prefs);
1872 n = (sets != NULL) ? CFArrayGetCount(sets) : 0;
1873
1874 for (i = 0; i < n; i++) {
1875 CFArrayRef services;
1876 SCNetworkSetRef set;
1877
1878 set = CFArrayGetValueAtIndex(sets, i);
1879 services = SCNetworkSetCopyServices(set);
1880 if (CFArrayContainsValue(services,
1881 CFRangeMake(0, CFArrayGetCount(services)),
1882 interfacePrivate->service)) {
1883 path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator
1884 SCNetworkSetGetSetID(set), // set
1885 interfacePrivate->entity_device, // service
1886 interfacePrivate->entity_type); // entity
1887 CFArrayAppendValue(array, path);
1888 CFRelease(path);
1889 }
1890 CFRelease(services);
1891 }
1892
1893 if (CFArrayGetCount(array) == 0) {
1894 CFRelease(array);
1895 array = NULL;
1896 }
1897
1898 CFRelease(sets);
1899 } else {
1900 // per-service configuration preferences
1901 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1902 servicePrivate->serviceID, // service
1903 interfacePrivate->entity_type); // entity
1904 CFArrayAppendValue(array, path);
1905 CFRelease(path);
1906 }
1907
1908 return array;
1909 }
1910
1911
1912 /* ---------- SCNetworkInterface APIs ---------- */
1913
1914
1915 CFArrayRef /* of SCNetworkInterfaceRef's */
1916 SCNetworkInterfaceCopyAll()
1917 {
1918 CFMutableArrayRef all_interfaces;
1919 static mach_port_t masterPort = MACH_PORT_NULL;
1920 CFDictionaryRef matching;
1921 CFStringRef match_keys[2];
1922 CFStringRef match_vals[2];
1923 CFArrayRef new_interfaces;
1924
1925 if (masterPort == MACH_PORT_NULL) {
1926 kern_return_t kr;
1927
1928 kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
1929 if (kr != KERN_SUCCESS) {
1930 return NULL;
1931 }
1932 }
1933
1934 all_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1935
1936 // get Ethernet, Firewire, and AirPort interfaces
1937
1938 matching = IOServiceMatching(kIONetworkInterfaceClass);
1939 new_interfaces = findMatchingInterfaces(masterPort, matching, processNetworkInterface);
1940 if (new_interfaces != NULL) {
1941 CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces)));
1942 CFRelease(new_interfaces);
1943 }
1944
1945 // get Modem interfaces
1946
1947 match_keys[0] = CFSTR(kIOProviderClassKey);
1948 match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
1949
1950 match_keys[1] = CFSTR(kIOSerialBSDTypeKey);
1951 match_vals[1] = CFSTR(kIOSerialBSDModemType);
1952
1953 matching = CFDictionaryCreate(NULL,
1954 (const void **)match_keys,
1955 (const void **)match_vals,
1956 sizeof(match_keys)/sizeof(match_keys[0]),
1957 &kCFTypeDictionaryKeyCallBacks,
1958 &kCFTypeDictionaryValueCallBacks);
1959 new_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface);
1960 if (new_interfaces != NULL) {
1961 CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces)));
1962 CFRelease(new_interfaces);
1963 }
1964
1965 // get serial (RS232) interfaces
1966
1967 match_keys[0] = CFSTR(kIOProviderClassKey);
1968 match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
1969
1970 match_keys[1] = CFSTR(kIOSerialBSDTypeKey);
1971 match_vals[1] = CFSTR(kIOSerialBSDRS232Type);
1972
1973 matching = CFDictionaryCreate(NULL,
1974 (const void **)match_keys,
1975 (const void **)match_vals,
1976 sizeof(match_keys)/sizeof(match_keys[0]),
1977 &kCFTypeDictionaryKeyCallBacks,
1978 &kCFTypeDictionaryValueCallBacks);
1979 new_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface);
1980 if (new_interfaces != NULL) {
1981 CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces)));
1982 CFRelease(new_interfaces);
1983 }
1984
1985 new_interfaces = findBondInterfaces(NULL);
1986 if (new_interfaces != NULL) {
1987 CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces)));
1988 CFRelease(new_interfaces);
1989 }
1990
1991 new_interfaces = findVLANInterfaces(NULL);
1992 if (new_interfaces != NULL) {
1993 CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces)));
1994 CFRelease(new_interfaces);
1995 }
1996
1997 sort_interfaces(all_interfaces);
1998
1999 return all_interfaces;
2000 }
2001
2002
2003 CFArrayRef /* of kSCNetworkInterfaceTypeXXX CFStringRef's */
2004 SCNetworkInterfaceGetSupportedInterfaceTypes(SCNetworkInterfaceRef interface)
2005 {
2006 CFIndex i;
2007 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2008
2009 if (interfacePrivate->supported_interface_types != NULL) {
2010 goto done;
2011 }
2012
2013 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2014 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2015
2016 i = findConfiguration(interfacePrivate->interface_type);
2017 if (i != kCFNotFound) {
2018 if (configurations[i].supported_interfaces != doNone) {
2019 interfacePrivate->supported_interface_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2020 if (configurations[i].supported_interfaces & do6to4) {
2021 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceType6to4);
2022 }
2023 if (configurations[i].supported_interfaces & doL2TP) {
2024 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeL2TP);
2025 }
2026 if (configurations[i].supported_interfaces & doPPP) {
2027 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPP);
2028 }
2029 if (configurations[i].supported_interfaces & doPPTP) {
2030 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPTP);
2031 }
2032 }
2033 }
2034
2035 done :
2036
2037 return interfacePrivate->supported_interface_types;
2038 }
2039
2040
2041 CFArrayRef /* of kSCNetworkProtocolTypeXXX CFStringRef's */
2042 SCNetworkInterfaceGetSupportedProtocolTypes(SCNetworkInterfaceRef interface)
2043 {
2044 CFIndex i;
2045 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2046
2047 if (interfacePrivate->supported_protocol_types != NULL) {
2048 goto done;
2049 }
2050
2051 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2052 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2053
2054 i = findConfiguration(interfacePrivate->interface_type);
2055 if (i != kCFNotFound) {
2056 if (configurations[i].supported_protocols != doNone) {
2057 interfacePrivate->supported_protocol_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2058 if (configurations[i].supported_protocols & doAppleTalk) {
2059 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeAppleTalk);
2060 }
2061 if (configurations[i].supported_protocols & doDNS) {
2062 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeDNS);
2063 }
2064 if (configurations[i].supported_protocols & doIPv4) {
2065 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv4);
2066 }
2067 if (configurations[i].supported_protocols & doIPv6) {
2068 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv6);
2069 }
2070 if (configurations[i].supported_protocols & doProxies) {
2071 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeProxies);
2072 }
2073 }
2074 }
2075
2076 done :
2077
2078 return interfacePrivate->supported_protocol_types;
2079 }
2080
2081
2082 SCNetworkInterfaceRef
2083 SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef interfaceType)
2084 {
2085 SCNetworkInterfacePrivateRef childPrivate = (SCNetworkInterfacePrivateRef)child;
2086 CFIndex childIndex;
2087 SCNetworkInterfacePrivateRef parentPrivate;
2088
2089 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2090 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2091
2092 childIndex = findConfiguration(childPrivate->interface_type);
2093
2094 parentPrivate = __SCNetworkInterfaceCreatePrivate(NULL, child, childPrivate->service, NULL);
2095 if (parentPrivate == NULL) {
2096 _SCErrorSet(kSCStatusFailed);
2097 return NULL;
2098 }
2099
2100 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
2101 parentPrivate->interface_type = kSCNetworkInterfaceTypePPP;
2102 parentPrivate->entity_type = kSCEntNetPPP;
2103
2104 // entity subtype
2105 if (childIndex != kCFNotFound) {
2106 if (configurations[childIndex].ppp_subtype != NULL) {
2107 parentPrivate->entity_subtype = *configurations[childIndex].ppp_subtype;
2108 } else {
2109 // sorry, the child interface does not support PPP
2110 goto fail;
2111 }
2112 } else {
2113 // if the child's interface type not known, use the child entities "Type"
2114 parentPrivate->entity_subtype = childPrivate->entity_type;
2115 }
2116
2117 if (childPrivate->entity_device != NULL) {
2118 parentPrivate->entity_device = CFStringCreateCopy(NULL, childPrivate->entity_device);
2119 }
2120 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
2121 if ((childIndex == kCFNotFound) ||
2122 ((configurations[childIndex].supported_interfaces & doL2TP) != doL2TP)) {
2123 // if the child interface does not support L2TP
2124 goto fail;
2125 }
2126 parentPrivate->interface_type = kSCNetworkInterfaceTypeL2TP;
2127 parentPrivate->entity_type = kSCValNetInterfaceSubTypeL2TP; // interface config goes into "L2TP"
2128 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) {
2129 if ((childIndex == kCFNotFound) ||
2130 ((configurations[childIndex].supported_interfaces & doPPTP) != doPPTP)) {
2131 // if the child interface does not support PPTP
2132 goto fail;
2133 }
2134 parentPrivate->interface_type = kSCNetworkInterfaceTypePPTP;
2135 parentPrivate->entity_type = kSCValNetInterfaceSubTypePPTP; // interface config goes into "PPTP"
2136 } else if (CFEqual(interfaceType, kSCNetworkInterfaceType6to4)) {
2137 if ((childIndex == kCFNotFound) ||
2138 ((configurations[childIndex].supported_interfaces & do6to4) != do6to4)) {
2139 // if the child interface does not support 6to4
2140 goto fail;
2141 }
2142
2143 parentPrivate->interface_type = kSCNetworkInterfaceType6to4;
2144 parentPrivate->entity_type = kSCEntNet6to4;
2145 parentPrivate->entity_device = CFRetain(CFSTR("stf0"));
2146 CFRetain(parentPrivate->entity_device);
2147 } else {
2148 // unknown interface type
2149 goto fail;
2150 }
2151
2152 parentPrivate->entity_hardware = childPrivate->entity_hardware;
2153 parentPrivate->sort_order = childPrivate->sort_order;
2154
2155 return (SCNetworkInterfaceRef)parentPrivate;
2156
2157 fail :
2158
2159 CFRelease(parentPrivate);
2160 _SCErrorSet(kSCStatusInvalidArgument);
2161 return NULL;
2162 }
2163
2164
2165 static CFDictionaryRef
2166 __SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface, Boolean okToHold)
2167 {
2168 CFDictionaryRef config = NULL;
2169 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2170 CFArrayRef paths;
2171
2172 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2173 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2174
2175 paths = copyConfigurationPaths(interfacePrivate);
2176 if (paths != NULL) {
2177 CFStringRef path;
2178 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service;
2179
2180 path = CFArrayGetValueAtIndex(paths, 0);
2181 config = __getPrefsConfiguration(servicePrivate->prefs, path);
2182
2183 CFRelease(paths);
2184 } else if (okToHold) {
2185 config = interfacePrivate->unsaved;
2186 }
2187
2188 return config;
2189 }
2190
2191
2192 CFDictionaryRef
2193 SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface)
2194 {
2195 return __SCNetworkInterfaceGetConfiguration(interface, FALSE);
2196 }
2197
2198
2199 CFStringRef
2200 SCNetworkInterfaceGetBSDName(SCNetworkInterfaceRef interface)
2201 {
2202 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2203
2204 if (interfacePrivate->interface != NULL) {
2205 return NULL;
2206 }
2207
2208 return interfacePrivate->entity_device;
2209 }
2210
2211
2212 CFStringRef
2213 SCNetworkInterfaceGetHardwareAddressString(SCNetworkInterfaceRef interface)
2214 {
2215 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2216
2217 return interfacePrivate->address;
2218 }
2219
2220 SCNetworkInterfaceRef
2221 SCNetworkInterfaceGetInterface(SCNetworkInterfaceRef interface)
2222 {
2223 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2224
2225 return interfacePrivate->interface;
2226 }
2227
2228
2229 CFStringRef
2230 SCNetworkInterfaceGetInterfaceType(SCNetworkInterfaceRef interface)
2231 {
2232 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2233
2234 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2235 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2236
2237 return interfacePrivate->interface_type;
2238 }
2239
2240
2241 CFStringRef
2242 SCNetworkInterfaceGetLocalizedDisplayName(SCNetworkInterfaceRef interface)
2243 {
2244 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2245
2246 if (interfacePrivate->localized_name == NULL) {
2247 CFStringRef child = NULL;
2248 CFMutableStringRef local = NULL;
2249
2250 pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* initialize runtime */
2251
2252 if (interfacePrivate->interface != NULL) {
2253 child = SCNetworkInterfaceGetLocalizedDisplayName(interfacePrivate->interface);
2254 }
2255
2256 if (interfacePrivate->localized_key != NULL) {
2257 CFStringRef fmt;
2258
2259 fmt = CFBundleCopyLocalizedString(bundle,
2260 interfacePrivate->localized_key,
2261 interfacePrivate->localized_key,
2262 NETWORKINTERFACE_LOCALIZATIONS);
2263 if (fmt != NULL) {
2264 local = CFStringCreateMutable(NULL, 0);
2265 CFStringAppendFormat(local,
2266 NULL,
2267 fmt,
2268 interfacePrivate->localized_arg1,
2269 interfacePrivate->localized_arg2);
2270 CFRelease(fmt);
2271 }
2272 }
2273
2274 if (local == NULL) {
2275 // create (non-)localized name based on the interface type
2276 local = CFStringCreateMutableCopy(NULL, 0, interfacePrivate->interface_type);
2277
2278 // ... and, if this is a leaf node, the interface device
2279 if ((interfacePrivate->entity_device != NULL) && (child == NULL)) {
2280 CFStringAppendFormat(local, NULL, CFSTR(" (%@)"), interfacePrivate->entity_device);
2281 }
2282 }
2283
2284 if (child == NULL) {
2285 // no child, show just this interfaces localized name
2286 interfacePrivate->localized_name = CFStringCreateCopy(NULL, local);
2287 } else {
2288 // show localized interface name layered over child
2289 interfacePrivate->localized_name = CFStringCreateWithFormat(NULL,
2290 NULL,
2291 CFSTR("%@ --> %@"),
2292 local,
2293 child);
2294 }
2295 CFRelease(local);
2296 }
2297
2298 return interfacePrivate->localized_name;
2299 }
2300
2301
2302 CFTypeID
2303 SCNetworkInterfaceGetTypeID(void)
2304 {
2305 pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* initialize runtime */
2306 return __kSCNetworkInterfaceTypeID;
2307 }
2308
2309
2310 __private_extern__ Boolean
2311 __SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config, Boolean okToHold)
2312 {
2313 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2314 Boolean ok = FALSE;
2315 CFArrayRef paths;
2316
2317 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2318 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2319
2320 paths = copyConfigurationPaths(interfacePrivate);
2321 if (paths != NULL) {
2322 CFIndex i;
2323 CFIndex n;
2324 SCPreferencesRef prefs;
2325 SCNetworkServicePrivateRef servicePrivate;
2326
2327 servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service;
2328 prefs = servicePrivate->prefs;
2329
2330 n = CFArrayGetCount(paths);
2331 for (i = 0; i < n; i++) {
2332 CFStringRef path;
2333
2334 path = CFArrayGetValueAtIndex(paths, i);
2335 ok = __setPrefsConfiguration(prefs, path, config, FALSE);
2336 if (!ok) {
2337 break;
2338 }
2339 }
2340
2341 CFRelease(paths);
2342 } else if (okToHold) {
2343 interfacePrivate->unsaved = config;
2344 ok = TRUE;
2345 } else {
2346 _SCErrorSet(kSCStatusNoKey);
2347 }
2348
2349 return ok;
2350 }
2351
2352
2353 Boolean
2354 SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config)
2355 {
2356 return __SCNetworkInterfaceSetConfiguration(interface, config, FALSE);
2357 }
2358
2359
2360 /* ---------- SCNetworkInterface internal SPIs ---------- */
2361
2362
2363 __private_extern__ SCNetworkInterfacePrivateRef
2364 __SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator,
2365 SCNetworkInterfaceRef interface,
2366 SCNetworkServiceRef service)
2367 {
2368 SCNetworkInterfacePrivateRef oldPrivate = (SCNetworkInterfacePrivateRef)interface;
2369 SCNetworkInterfacePrivateRef newPrivate;
2370
2371 newPrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
2372 newPrivate->interface_type = CFRetain(oldPrivate->interface_type);
2373 if (oldPrivate->interface != NULL) {
2374 newPrivate->interface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL, // allocator
2375 oldPrivate->interface, // interface
2376 service); // [new] service
2377 }
2378 newPrivate->localized_name = (oldPrivate->localized_name != NULL) ? CFRetain(oldPrivate->localized_name) : NULL;
2379 newPrivate->service = service;
2380 newPrivate->unsaved = (oldPrivate->unsaved != NULL) ? CFRetain(oldPrivate->unsaved) : NULL;
2381 newPrivate->entity_device = (oldPrivate->entity_device != NULL) ? CFRetain(oldPrivate->entity_device) : NULL;
2382 newPrivate->entity_hardware = CFRetain(oldPrivate->entity_hardware);
2383 newPrivate->entity_type = oldPrivate->entity_type;
2384 newPrivate->entity_subtype = oldPrivate->entity_subtype;
2385 if (oldPrivate->supported_interface_types != NULL) {
2386 newPrivate->supported_interface_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_interface_types);
2387 }
2388 if (oldPrivate->supported_protocol_types != NULL) {
2389 newPrivate->supported_protocol_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_protocol_types);
2390 }
2391 newPrivate->address = (oldPrivate->address != NULL) ? CFRetain(oldPrivate->address) : NULL;
2392 newPrivate->builtin = oldPrivate->builtin;
2393 newPrivate->path = (oldPrivate->path != NULL) ? CFRetain(oldPrivate->path) : NULL;
2394 newPrivate->location = (oldPrivate->location != NULL) ? CFRetain(oldPrivate->location) : NULL;
2395 newPrivate->supportsDeviceOnHold = oldPrivate->supportsDeviceOnHold;
2396 newPrivate->supportsBond = oldPrivate->supportsBond;
2397 newPrivate->supportsVLAN = oldPrivate->supportsVLAN;
2398 newPrivate->sort_order = oldPrivate->sort_order;
2399
2400 return newPrivate;
2401 }
2402
2403
2404 __private_extern__ CFArrayRef
2405 __SCNetworkInterfaceCopyDeepConfiguration(SCNetworkInterfaceRef interface)
2406 {
2407 CFDictionaryRef config;
2408 CFMutableArrayRef configs;
2409
2410 configs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2411
2412 while (interface != NULL) {
2413 config = __SCNetworkInterfaceGetConfiguration(interface, TRUE);
2414 CFArrayAppendValue(configs,
2415 (config != NULL) ? config : (CFDictionaryRef)kCFNull);
2416 interface = SCNetworkInterfaceGetInterface(interface);
2417 }
2418
2419 return configs;
2420 }
2421
2422
2423 __private_extern__ void
2424 __SCNetworkInterfaceSetDeepConfiguration(SCNetworkInterfaceRef interface, CFArrayRef configs)
2425 {
2426 CFIndex i;
2427
2428 for (i = 0; interface != NULL; i++) {
2429 CFDictionaryRef config;
2430
2431 config = (configs != NULL) ? CFArrayGetValueAtIndex(configs, i) : NULL;
2432 if (!isA_CFDictionary(config) || (CFDictionaryGetCount(config) == 0)) {
2433 config = NULL;
2434 }
2435
2436 (void) __SCNetworkInterfaceSetConfiguration(interface, config, TRUE);
2437 interface = SCNetworkInterfaceGetInterface(interface);
2438 }
2439
2440 return;
2441 }