]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkInterface.c
configd-137.2.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkInterface.c
1 /*
2 * Copyright (c) 2004, 2005 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,
597 (const char *)CFDataGetBytePtr(ioVal),
598 kCFStringEncodingUTF8);
599 }
600
601 return NULL;
602 }
603
604
605 static CFStringRef
606 IODictionaryCopyCFStringValue(CFDictionaryRef io_dict, CFStringRef io_key)
607 {
608 CFTypeRef ioVal;
609
610 ioVal = CFDictionaryGetValue(io_dict, io_key);
611 return IOCopyCFStringValue(ioVal);
612 }
613
614
615 static Boolean
616 IOStringValueHasPrefix(CFTypeRef ioVal, CFStringRef prefix)
617 {
618 Boolean match = FALSE;
619 CFIndex prefixLen = CFStringGetLength(prefix);
620 CFStringRef str = ioVal;
621
622 if (!isA_CFString(ioVal)) {
623 if (isA_CFData(ioVal)) {
624 str = CFStringCreateWithCStringNoCopy(NULL,
625 (const char *)CFDataGetBytePtr(ioVal),
626 kCFStringEncodingUTF8,
627 kCFAllocatorNull);
628 } else {
629 return FALSE;
630 }
631 }
632
633 if ((str != NULL) &&
634 (CFStringGetLength(str) >= prefixLen) &&
635 (CFStringCompareWithOptions(str,
636 prefix,
637 CFRangeMake(0, prefixLen),
638 kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
639 match = TRUE;
640 }
641
642 if (str != ioVal) CFRelease(str);
643 return match;
644 }
645
646
647 static CFStringRef
648 copyMACAddress(CFDictionaryRef controller_dict)
649 {
650 CFStringRef address = NULL;
651 uint8_t *bp;
652 char *cp;
653 CFDataRef data;
654 CFIndex n;
655 char mac[sizeof("xx:xx:xx:xx:xx:xx:xx:xx")];
656 char *mac_p = mac;
657
658 data = CFDictionaryGetValue(controller_dict, CFSTR(kIOMACAddress));
659 if (data == NULL) {
660 return NULL;
661 }
662
663 bp = (uint8_t *)CFDataGetBytePtr(data);
664 n = CFDataGetLength(data) * 3;
665
666 if (n > sizeof(mac)) {
667 mac_p = CFAllocatorAllocate(NULL, 0, n);
668 }
669
670 for (cp = mac_p; n > 0; n -= 3) {
671 cp += snprintf(cp, n, "%2.2x:", *bp++);
672 }
673
674 address = CFStringCreateWithCString(NULL, mac_p, kCFStringEncodingUTF8);
675 if (mac_p != mac) CFAllocatorDeallocate(NULL, mac_p);
676 return address;
677 }
678
679
680 static const struct {
681 const CFStringRef name;
682 const CFStringRef slot;
683 } slot_mappings[] = {
684 // Beige G3
685 { CFSTR("A1") , CFSTR("1") },
686 { CFSTR("B1") , CFSTR("2") },
687 { CFSTR("C1") , CFSTR("3") },
688
689 // Blue&White G3, Yikes G4
690 { CFSTR("J12"), CFSTR("1") },
691 { CFSTR("J11"), CFSTR("2") },
692 { CFSTR("J10"), CFSTR("3") },
693 { CFSTR("J9"), CFSTR("4") },
694
695 // AGP G4
696 { CFSTR("A") , CFSTR("1") },
697 { CFSTR("B") , CFSTR("2") },
698 { CFSTR("C") , CFSTR("3") },
699 { CFSTR("D") , CFSTR("4") },
700
701 // Digital Audio G4 (and later models)
702 { CFSTR("1") , CFSTR("1") },
703 { CFSTR("2") , CFSTR("2") },
704 { CFSTR("3") , CFSTR("3") },
705 { CFSTR("4") , CFSTR("4") },
706 { CFSTR("5") , CFSTR("5") }
707 };
708
709
710 static CFStringRef
711 pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name)
712 {
713 kern_return_t kr;
714 io_registry_entry_t slot = interface;
715
716 if (pci_slot_name != NULL) *pci_slot_name = NULL;
717
718 while (slot != MACH_PORT_NULL) {
719 io_registry_entry_t parent;
720 CFTypeRef slot_name;
721
722 slot_name = IORegistryEntryCreateCFProperty(slot, CFSTR("AAPL,slot-name"), NULL, 0);
723 if (slot_name != NULL) {
724 Boolean found;
725
726 found = IOStringValueHasPrefix(slot_name, CFSTR("slot"));
727 if (found) {
728 CFIndex i;
729 CFMutableStringRef name;
730
731 // if we found a slot #
732 name = CFStringCreateMutable(NULL, 0);
733 if (isA_CFString(slot_name)) {
734 if (pci_slot_name != NULL) *pci_slot_name = CFStringCreateCopy(NULL, slot_name);
735 CFStringAppend(name, slot_name);
736 } else if (isA_CFData(slot_name)) {
737 if (pci_slot_name != NULL) *pci_slot_name = CFDataCreateCopy(NULL, slot_name);
738 CFStringAppendCString(name,
739 (const char *)CFDataGetBytePtr(slot_name),
740 kCFStringEncodingUTF8);
741 }
742
743 (void) CFStringFindAndReplace(name,
744 CFSTR("slot-"),
745 CFSTR(""),
746 CFRangeMake(0, 5),
747 kCFCompareCaseInsensitive|kCFCompareAnchored);
748 for (i = 0; i < sizeof(slot_mappings)/sizeof(slot_mappings[0]); i++) {
749 if (CFStringCompareWithOptions(name,
750 slot_mappings[i].name,
751 CFRangeMake(0, CFStringGetLength(slot_mappings[i].name)),
752 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
753 CFRelease(name);
754 name = (CFMutableStringRef)CFRetain(slot_mappings[i].slot);
755 break;
756 }
757 }
758
759 CFRelease(slot_name);
760 if (slot != interface) IOObjectRelease(slot);
761 return name;
762 }
763
764 CFRelease(slot_name);
765 }
766
767 kr = IORegistryEntryGetParentEntry(slot, kIOServicePlane, &parent);
768 if (slot != interface) IOObjectRelease(slot);
769 switch (kr) {
770 case kIOReturnSuccess :
771 slot = parent;
772 break;
773 case kIOReturnNoDevice :
774 // if we have hit the root node without finding a slot #
775 goto done;
776 default :
777 SCLog(TRUE, LOG_INFO, CFSTR("pci_slot IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
778 goto done;
779 }
780 }
781
782 done :
783
784 return NULL;
785 }
786
787
788 static CFComparisonResult
789 compare_bsdNames(const void *val1, const void *val2, void *context)
790 {
791 CFStringRef bsd1 = (CFStringRef)val1;
792 CFStringRef bsd2 = (CFStringRef)val2;
793
794 return CFStringCompare(bsd1, bsd2, 0);
795 }
796
797
798 static CFStringRef
799 pci_port(mach_port_t masterPort, CFTypeRef slot_name, CFStringRef bsdName)
800 {
801 CFIndex n;
802 CFStringRef port_name = NULL;
803 CFMutableArrayRef port_names;
804
805 kern_return_t kr;
806 CFStringRef match_keys[2];
807 CFTypeRef match_vals[2];
808 CFDictionaryRef match_dict;
809 CFDictionaryRef matching;
810 io_registry_entry_t slot;
811 io_iterator_t slot_iterator = MACH_PORT_NULL;
812
813 match_keys[0] = CFSTR("AAPL,slot-name");
814 match_vals[0] = slot_name;
815
816 match_dict = CFDictionaryCreate(NULL,
817 (const void **)match_keys,
818 (const void **)match_vals,
819 1,
820 &kCFTypeDictionaryKeyCallBacks,
821 &kCFTypeDictionaryValueCallBacks);
822
823 match_keys[0] = CFSTR(kIOProviderClassKey);
824 match_vals[0] = CFSTR("IOPCIDevice");
825
826 match_keys[1] = CFSTR(kIOPropertyMatchKey);
827 match_vals[1] = match_dict;
828
829 // note: the "matching" dictionary will be consumed by the following
830 matching = CFDictionaryCreate(NULL,
831 (const void **)match_keys,
832 (const void **)match_vals,
833 sizeof(match_keys)/sizeof(match_keys[0]),
834 &kCFTypeDictionaryKeyCallBacks,
835 &kCFTypeDictionaryValueCallBacks);
836 CFRelease(match_dict);
837
838 kr = IOServiceGetMatchingServices(masterPort, matching, &slot_iterator);
839 if (kr != kIOReturnSuccess) {
840 SCPrint(TRUE, stderr, CFSTR("IOServiceGetMatchingServices() failed, kr = 0x%x\n"), kr);
841 return MACH_PORT_NULL;
842 }
843
844 port_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
845
846 while ((slot = IOIteratorNext(slot_iterator)) != MACH_PORT_NULL) {
847 io_registry_entry_t child;
848 io_iterator_t child_iterator = MACH_PORT_NULL;
849
850 kr = IORegistryEntryCreateIterator(slot,
851 kIOServicePlane,
852 kIORegistryIterateRecursively,
853 &child_iterator);
854 if (kr != kIOReturnSuccess) {
855 SCPrint(TRUE, stderr, CFSTR("IORegistryEntryCreateIterator() failed, kr = 0x%x\n"), kr);
856 return MACH_PORT_NULL;
857 }
858
859 while ((child = IOIteratorNext(child_iterator)) != MACH_PORT_NULL) {
860 if (IOObjectConformsTo(child, kIONetworkInterfaceClass)) {
861 CFStringRef if_bsdName;
862
863 if_bsdName = IORegistryEntryCreateCFProperty(child,
864 CFSTR(kIOBSDNameKey),
865 NULL,
866 0);
867 if (if_bsdName != NULL) {
868 CFArrayAppendValue(port_names, if_bsdName);
869 CFRelease(if_bsdName);
870 }
871 }
872 IOObjectRelease(child);
873 }
874 IOObjectRelease(child_iterator);
875 IOObjectRelease(slot);
876 }
877 IOObjectRelease(slot_iterator);
878
879 n = CFArrayGetCount(port_names);
880 if (n > 1) {
881 CFArraySortValues(port_names, CFRangeMake(0, n), compare_bsdNames, NULL);
882 n = CFArrayGetFirstIndexOfValue(port_names, CFRangeMake(0, n), bsdName);
883 if (n != kCFNotFound) {
884 port_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), n + 1);
885 }
886 }
887
888 CFRelease(port_names);
889 return port_name;
890 }
891
892
893 static Boolean
894 pci_slot_info(mach_port_t masterPort, io_registry_entry_t interface, CFStringRef *slot_name, CFStringRef *port_name)
895 {
896 CFStringRef bsd_name;
897 Boolean ok = FALSE;
898 CFTypeRef pci_slot_name;
899
900 *slot_name = NULL;
901 *port_name = NULL;
902
903 bsd_name = IORegistryEntryCreateCFProperty(interface, CFSTR(kIOBSDNameKey), NULL, 0);
904 if (bsd_name == NULL) {
905 return FALSE;
906 }
907
908 *slot_name = pci_slot(interface, &pci_slot_name);
909 if (*slot_name != NULL) {
910 if (pci_slot_name != NULL) {
911 *port_name = pci_port(masterPort, pci_slot_name, bsd_name);
912 CFRelease(pci_slot_name);
913 }
914 ok = TRUE;
915 }
916
917 CFRelease(bsd_name);
918 return ok;
919 }
920
921
922 static Boolean
923 isBuiltIn(io_registry_entry_t interface)
924 {
925 kern_return_t kr;
926 io_registry_entry_t slot = interface;
927
928 while (slot != MACH_PORT_NULL) {
929 io_registry_entry_t parent;
930 CFTypeRef slot_name;
931
932 slot_name = IORegistryEntryCreateCFProperty(slot, CFSTR("AAPL,slot-name"), NULL, 0);
933 if (slot_name != NULL) {
934 Boolean found;
935
936 found = IOStringValueHasPrefix(slot_name, CFSTR("slot"));
937 CFRelease(slot_name);
938
939 if (found) {
940 // if we found a slot # then this is not a built-in interface
941 if (slot != interface) IOObjectRelease(slot);
942 return FALSE;
943 }
944 }
945
946 kr = IORegistryEntryGetParentEntry(slot, kIOServicePlane, &parent);
947 if (slot != interface) IOObjectRelease(slot);
948 switch (kr) {
949 case kIOReturnSuccess :
950 slot = parent;
951 break;
952 case kIOReturnNoDevice :
953 // if we have hit the root node without finding a slot #
954 return TRUE;
955 default :
956 SCLog(TRUE, LOG_INFO, CFSTR("isBuiltIn IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
957 return FALSE;
958 }
959 }
960
961 return FALSE;
962 }
963
964
965 /* ---------- interface enumeration ---------- */
966
967
968 typedef Boolean (*processInterface)(mach_port_t masterPort,
969 SCNetworkInterfacePrivateRef interfacePrivate,
970 io_registry_entry_t interface,
971 CFDictionaryRef interface_dict,
972 io_registry_entry_t controller,
973 CFDictionaryRef controller_dict,
974 io_registry_entry_t bus,
975 CFDictionaryRef bus_dict);
976
977
978 static Boolean
979 processNetworkInterface(mach_port_t masterPort,
980 SCNetworkInterfacePrivateRef interfacePrivate,
981 io_registry_entry_t interface,
982 CFDictionaryRef interface_dict,
983 io_registry_entry_t controller,
984 CFDictionaryRef controller_dict,
985 io_registry_entry_t bus,
986 CFDictionaryRef bus_dict)
987 {
988 CFBooleanRef bVal;
989 io_name_t c_IOClass;
990 io_name_t c_IOName;
991 io_name_t i_IOClass;
992 int ift = -1;
993 int iVal;
994 CFNumberRef num;
995 CFStringRef str;
996
997 // get the interface type
998
999 num = CFDictionaryGetValue(interface_dict, CFSTR(kIOInterfaceType));
1000 if (!isA_CFNumber(num) ||
1001 !CFNumberGetValue(num, kCFNumberIntType, &ift)) {
1002 SCPrint(TRUE, stderr, CFSTR("Could not get interface type\n"));
1003 return FALSE;
1004 }
1005
1006 switch (ift) {
1007 case IFT_ETHER :
1008 // Type, Hardware
1009
1010 if (IOObjectGetClass(interface, i_IOClass) != KERN_SUCCESS) {
1011 i_IOClass[0] = '\0';
1012 }
1013 if (IOObjectGetClass(controller, c_IOClass) != KERN_SUCCESS) {
1014 c_IOClass[0] = '\0';
1015 }
1016 if (IORegistryEntryGetName(controller, c_IOName) != KERN_SUCCESS) {
1017 c_IOName[0] = '\0';
1018 }
1019
1020 if ((strcmp(i_IOClass, "IO80211Interface" ) == 0) ||
1021 (strcmp(c_IOClass, "AirPortPCI" ) == 0) ||
1022 (strcmp(c_IOClass, "AirPortDriver" ) == 0) ||
1023 (strcmp(c_IOName , "AppleWireless80211") == 0)) {
1024 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
1025 interfacePrivate->entity_type = kSCEntNetEthernet;
1026 interfacePrivate->entity_hardware = kSCEntNetAirPort;
1027 interfacePrivate->sort_order = kSortAirPort;
1028 } else {
1029 str = IODictionaryCopyCFStringValue(bus_dict, CFSTR("name"));
1030 if ((str != NULL) && CFEqual(str, CFSTR("radio"))) {
1031 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet; // ??
1032 interfacePrivate->entity_type = kSCEntNetEthernet;
1033 interfacePrivate->entity_hardware = kSCEntNetEthernet; // ??
1034 interfacePrivate->sort_order = kSortOtherWireless;
1035 } else {
1036 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
1037 interfacePrivate->entity_type = kSCEntNetEthernet;
1038 interfacePrivate->entity_hardware = kSCEntNetEthernet;
1039 interfacePrivate->sort_order = kSortEthernet;
1040
1041 // BOND support only enabled for ethernet devices
1042 interfacePrivate->supportsBond = TRUE;
1043 }
1044
1045 if (str != NULL) CFRelease(str);
1046 }
1047
1048 // built-in
1049 bVal = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOBuiltin)));
1050 if ((bVal == NULL) || !CFBooleanGetValue(bVal)) {
1051 bVal = isA_CFBoolean(CFDictionaryGetValue(interface_dict, CFSTR(kIOPrimaryInterface)));
1052 }
1053 if (bVal != NULL) {
1054 interfacePrivate->builtin = CFBooleanGetValue(bVal);
1055 } else {
1056 interfacePrivate->builtin = isBuiltIn(interface);
1057 }
1058
1059 // location
1060 interfacePrivate->location = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOLocation));
1061
1062 // VLAN support
1063 num = CFDictionaryGetValue(controller_dict, CFSTR(kIOFeatures));
1064 if (isA_CFNumber(num) &&
1065 CFNumberGetValue(num, kCFNumberIntType, & iVal)) {
1066 if (iVal & (kIONetworkFeatureHardwareVlan | kIONetworkFeatureSoftwareVlan)) {
1067 interfacePrivate->supportsVLAN = TRUE;
1068 }
1069 }
1070
1071 // localized name
1072 if (interfacePrivate->builtin) {
1073 if ((interfacePrivate->location == NULL) ||
1074 (CFStringGetLength(interfacePrivate->location) == 0)) {
1075 interfacePrivate->localized_key = CFSTR("ether");
1076 } else {
1077 interfacePrivate->localized_key = CFSTR("multiether");
1078 interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->location);
1079 }
1080 } else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIEEE80211)) {
1081 interfacePrivate->localized_key = CFSTR("airport");
1082 } else if (interfacePrivate->sort_order == kSortOtherWireless) {
1083 interfacePrivate->localized_key = CFSTR("wireless");
1084 interfacePrivate->localized_arg1 = CFRetain(CFSTR("")); // ??
1085 } else {
1086 CFStringRef provider;
1087
1088 // check provider class
1089 provider = IORegistryEntrySearchCFProperty(interface,
1090 kIOServicePlane,
1091 CFSTR(kIOProviderClassKey),
1092 NULL,
1093 kIORegistryIterateRecursively | kIORegistryIterateParents);
1094 if (provider != NULL) {
1095 if (CFEqual(provider, CFSTR("IOPCIDevice"))) {
1096 CFStringRef port_name;
1097 CFStringRef slot_name;
1098
1099 if (pci_slot_info(masterPort, interface, &slot_name, &port_name)) {
1100 if (port_name == NULL) {
1101 interfacePrivate->localized_key = CFSTR("pci-ether");
1102 interfacePrivate->localized_arg1 = slot_name;
1103 } else {
1104 interfacePrivate->localized_key = CFSTR("pci-multiether");
1105 interfacePrivate->localized_arg1 = slot_name;
1106 interfacePrivate->localized_arg2 = port_name;
1107 }
1108 }
1109 }
1110 CFRelease(provider);
1111 }
1112
1113 if (interfacePrivate->localized_key == NULL) {
1114 // if no provider, not a PCI device, or no slot information
1115 interfacePrivate->localized_key = CFSTR("generic-ether");
1116 interfacePrivate->localized_arg1 = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey));
1117 }
1118 }
1119
1120 break;
1121 case IFT_IEEE1394 :
1122 // Type
1123 interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire;
1124
1125 // Entity
1126 interfacePrivate->entity_type = kSCEntNetFireWire;
1127 interfacePrivate->entity_hardware = kSCEntNetFireWire;
1128
1129 // built-in
1130 interfacePrivate->builtin = isBuiltIn(interface);
1131
1132 // sort order
1133 interfacePrivate->sort_order = kSortFireWire;
1134
1135 // localized name
1136 if (interfacePrivate->builtin) {
1137 interfacePrivate->localized_key = CFSTR("firewire");
1138 } else {
1139 CFStringRef slot_name;
1140
1141 slot_name = pci_slot(interface, NULL);
1142 if (slot_name != NULL) {
1143 interfacePrivate->localized_key = CFSTR("pci-firewire");
1144 interfacePrivate->localized_arg1 = slot_name;
1145 }
1146 }
1147
1148 break;
1149 default :
1150 SCPrint(TRUE, stderr, CFSTR("Unknown interface type = %d\n"), ift);
1151 return FALSE;
1152 }
1153
1154 // Device
1155 interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOBSDNameKey));
1156
1157 // Hardware (MAC) address
1158 interfacePrivate->address = copyMACAddress(controller_dict);
1159
1160 return TRUE;
1161 }
1162
1163
1164 static Boolean
1165 processSerialInterface(mach_port_t masterPort,
1166 SCNetworkInterfacePrivateRef interfacePrivate,
1167 io_registry_entry_t interface,
1168 CFDictionaryRef interface_dict,
1169 io_registry_entry_t controller,
1170 CFDictionaryRef controller_dict,
1171 io_registry_entry_t bus,
1172 CFDictionaryRef bus_dict)
1173 {
1174 CFStringRef ift;
1175 Boolean isModem = FALSE;
1176 CFStringRef str;
1177 CFTypeRef val;
1178
1179 // check if hidden
1180 val = IORegistryEntrySearchCFProperty(interface,
1181 kIOServicePlane,
1182 CFSTR("HiddenPort"),
1183 NULL,
1184 kIORegistryIterateRecursively | kIORegistryIterateParents);
1185 if (val != NULL) {
1186 CFRelease(val);
1187 return FALSE; // if this interface should not be exposed
1188 }
1189
1190 // Type
1191 str = CFDictionaryGetValue(interface_dict, CFSTR(kIOTTYBaseNameKey));
1192 if (str == NULL) {
1193 return FALSE;
1194 }
1195
1196 /*
1197 * From MoreSCF:
1198 *
1199 * Exclude ports named "irda" because otherwise the IrDA ports on the
1200 * original iMac (rev's A through D) show up as serial ports. Given
1201 * that only the rev A actually had an IrDA port, and Mac OS X doesn't
1202 * even support it, these ports definitely shouldn't be listed.
1203 */
1204 if (CFStringCompare(str,
1205 CFSTR("irda"),
1206 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
1207 return FALSE;
1208 }
1209
1210 if (IOStringValueHasPrefix(str, CFSTR("irda-ircomm"))) {
1211 // IrDA
1212 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA;
1213 interfacePrivate->sort_order = kSortIrDA;
1214 } else if (IOStringValueHasPrefix(str, CFSTR("bluetooth"))) {
1215 // Bluetooth
1216 interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth;
1217 interfacePrivate->sort_order = kSortBluetooth;
1218 } else {
1219 // Modem
1220 interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem;
1221
1222 // DeviceOnHold support
1223 val = IORegistryEntrySearchCFProperty(interface,
1224 kIOServicePlane,
1225 CFSTR(kIODeviceSupportsHoldKey),
1226 NULL,
1227 kIORegistryIterateRecursively | kIORegistryIterateParents);
1228 if (val != NULL) {
1229 uint32_t supportsHold;
1230
1231 if (isA_CFNumber(val) &&
1232 CFNumberGetValue(val, kCFNumberSInt32Type, &supportsHold)) {
1233 interfacePrivate->supportsDeviceOnHold = (supportsHold == 1);
1234 }
1235 CFRelease(val);
1236 }
1237 }
1238
1239 // Entity (Type)
1240 interfacePrivate->entity_type = kSCEntNetModem;
1241
1242 // Entity (Hardware)
1243 ift = CFDictionaryGetValue(interface_dict, CFSTR(kIOSerialBSDTypeKey));
1244 if (!isA_CFString(ift)) {
1245 return FALSE;
1246 }
1247
1248 if (CFEqual(ift, CFSTR(kIOSerialBSDModemType))) {
1249 // if modem
1250 isModem = TRUE;
1251 interfacePrivate->entity_hardware = kSCEntNetModem;
1252
1253 if (CFEqual(str, CFSTR("modem"))) {
1254 interfacePrivate->builtin = TRUE;
1255 interfacePrivate->sort_order = kSortInternalModem;
1256 } else if (CFEqual(str, CFSTR("usbmodem"))) {
1257 interfacePrivate->sort_order = kSortUSBModem;
1258 } else {
1259 interfacePrivate->sort_order = kSortModem;
1260 }
1261 } else if (CFEqual(ift, CFSTR(kIOSerialBSDRS232Type))) {
1262 // if serial port
1263 interfacePrivate->entity_hardware = kSCEntNetModem;
1264 interfacePrivate->sort_order = kSortSerialPort;
1265 } else {
1266 return FALSE;
1267 }
1268
1269 // Entity (Device)
1270 interfacePrivate->entity_device = IODictionaryCopyCFStringValue(interface_dict, CFSTR(kIOTTYDeviceKey));
1271
1272 // localized name
1273 if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeIrDA)) {
1274 interfacePrivate->localized_key = CFSTR("irda");
1275 } else if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBluetooth)) {
1276 interfacePrivate->localized_key = CFSTR("bluetooth");
1277 } else {
1278 CFStringRef localized;
1279 CFMutableStringRef port;
1280
1281 port = CFStringCreateMutableCopy(NULL, 0, str);
1282 CFStringLowercase(port, NULL);
1283
1284 if (!isModem) {
1285 CFStringAppend(port, CFSTR("-port"));
1286 }
1287
1288 localized = CFBundleCopyLocalizedString(bundle,
1289 port,
1290 port,
1291 NETWORKINTERFACE_LOCALIZATIONS);
1292 if (localized != NULL) {
1293 if (!CFEqual(port, localized)) {
1294 // if localization available
1295 interfacePrivate->localized_name = localized;
1296 } else {
1297 // if no localization available, use TTY base name
1298 CFRelease(localized);
1299 interfacePrivate->localized_name = CFStringCreateCopy(NULL, str);
1300 }
1301 } else {
1302 interfacePrivate->localized_name = CFStringCreateCopy(NULL, str);
1303 }
1304
1305 if (!isModem || !CFEqual(str, CFSTR("modem"))) {
1306 CFStringRef productName;
1307
1308 // check if a "Product Name" has been provided
1309 val = IORegistryEntrySearchCFProperty(interface,
1310 kIOServicePlane,
1311 CFSTR(kIOPropertyProductNameKey),
1312 NULL,
1313 kIORegistryIterateRecursively | kIORegistryIterateParents);
1314 if (val != NULL) {
1315 productName = IOCopyCFStringValue(val);
1316 CFRelease(val);
1317
1318 if (productName != NULL) {
1319 if (CFStringGetLength(productName) > 0) {
1320 // if we have a [somewhat reasonable?] product name
1321 CFRelease(interfacePrivate->localized_name);
1322 interfacePrivate->localized_name = CFRetain(productName);
1323 }
1324 CFRelease(productName);
1325 }
1326 }
1327 }
1328
1329 CFRelease(port);
1330 }
1331
1332 return TRUE;
1333 }
1334
1335
1336 static CFArrayRef
1337 findMatchingInterfaces(mach_port_t masterPort, CFDictionaryRef matching, processInterface func)
1338 {
1339 CFMutableArrayRef interfaces;
1340 io_registry_entry_t interface;
1341 kern_return_t kr;
1342 io_iterator_t iterator = MACH_PORT_NULL;
1343
1344 kr = IOServiceGetMatchingServices(masterPort, matching, &iterator);
1345 if (kr != kIOReturnSuccess) {
1346 SCPrint(TRUE, stderr, CFSTR("IOServiceGetMatchingServices() failed, kr = 0x%x\n"), kr);
1347 return NULL;
1348 }
1349
1350 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1351
1352 while ((interface = IOIteratorNext(iterator)) != MACH_PORT_NULL) {
1353 io_registry_entry_t bus = MACH_PORT_NULL;
1354 CFMutableDictionaryRef bus_dict = NULL;
1355 io_registry_entry_t controller = MACH_PORT_NULL;
1356 CFMutableDictionaryRef controller_dict = NULL;
1357 SCNetworkInterfacePrivateRef interfacePrivate = NULL;
1358 CFMutableDictionaryRef interface_dict = NULL;
1359 io_string_t path;
1360
1361 kr = IORegistryEntryGetPath(interface, kIOServicePlane, path);
1362 if (kr != kIOReturnSuccess) {
1363 SCPrint(TRUE, stderr, CFSTR("IORegistryEntryGetPath() failed, kr = 0x%x"), kr);
1364 goto done;
1365 }
1366
1367 kr = IORegistryEntryCreateCFProperties(interface, &interface_dict, NULL, kNilOptions);
1368 if (kr != kIOReturnSuccess) {
1369 SCPrint(TRUE, stderr, CFSTR("IORegistryEntryCreateCFProperties() failed, kr = 0x%x\n"), kr);
1370 goto done;
1371 }
1372
1373 /* get the controller node */
1374 kr = IORegistryEntryGetParentEntry(interface, kIOServicePlane, &controller);
1375 if (kr != KERN_SUCCESS) {
1376 SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
1377 goto done;
1378 }
1379
1380 /* get the dictionary associated with the node */
1381 kr = IORegistryEntryCreateCFProperties(controller, &controller_dict, NULL, kNilOptions);
1382 if (kr != KERN_SUCCESS) {
1383 SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
1384 goto done;
1385 }
1386
1387 /* get the bus node */
1388 kr = IORegistryEntryGetParentEntry(controller, kIOServicePlane, &bus);
1389 if (kr != KERN_SUCCESS) {
1390 SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryGetParentEntry() failed, kr = 0x%x"), kr);
1391 goto done;
1392 }
1393
1394 /* get the dictionary associated with the node */
1395 kr = IORegistryEntryCreateCFProperties(bus, &bus_dict, NULL, kNilOptions);
1396 if (kr != KERN_SUCCESS) {
1397 SCLog(TRUE, LOG_INFO, CFSTR("findMatchingInterfaces IORegistryEntryCreateCFProperties() failed, kr = 0x%x"), kr);
1398 goto done;
1399 }
1400
1401 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, path);
1402
1403 if ((*func)(masterPort, interfacePrivate, interface, interface_dict, controller, controller_dict, bus, bus_dict)) {
1404 CFArrayAppendValue(interfaces, (SCNetworkInterfaceRef)interfacePrivate);
1405 }
1406
1407 CFRelease(interfacePrivate);
1408
1409 done:
1410
1411 if (interface != MACH_PORT_NULL) IOObjectRelease(interface);
1412 if (interface_dict != NULL) CFRelease(interface_dict);
1413
1414 if (controller != MACH_PORT_NULL) IOObjectRelease(controller);
1415 if (controller_dict != NULL) CFRelease(controller_dict);
1416
1417 if (bus != MACH_PORT_NULL) IOObjectRelease(bus);
1418 if (bus_dict != NULL) CFRelease(bus_dict);
1419 }
1420
1421 IOObjectRelease(iterator);
1422
1423 return interfaces;
1424 }
1425
1426
1427 /* ---------- Bond configuration ---------- */
1428
1429 Boolean
1430 SCNetworkInterfaceSupportsBonding(SCNetworkInterfaceRef interface)
1431 {
1432 return ((SCNetworkInterfacePrivateRef)interface)->supportsBond;
1433 }
1434
1435
1436 SCNetworkInterfaceRef
1437 SCNetworkInterfaceCreateWithBond(BondInterfaceRef bond)
1438 {
1439 SCNetworkInterfacePrivateRef interfacePrivate;
1440 CFStringRef bond_if;
1441
1442 bond_if = BondInterfaceGetInterface(bond);
1443 if (bond_if == NULL) {
1444 return NULL;
1445 }
1446
1447 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
1448 if (interfacePrivate == NULL) {
1449 return NULL;
1450 }
1451
1452 interfacePrivate->interface_type = kSCNetworkInterfaceTypeBond;
1453 interfacePrivate->entity_type = kSCEntNetEthernet;
1454 interfacePrivate->entity_hardware = kSCEntNetEthernet;
1455 interfacePrivate->entity_device = CFStringCreateCopy(NULL, bond_if);
1456 interfacePrivate->builtin = TRUE;
1457 interfacePrivate->sort_order = kSortBond;
1458
1459 interfacePrivate->localized_key = CFSTR("bond");
1460 interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device);
1461
1462 return (SCNetworkInterfaceRef)interfacePrivate;
1463 }
1464
1465
1466 static CFArrayRef
1467 findBondInterfaces(CFStringRef match)
1468 {
1469 CFMutableArrayRef interfaces = NULL;
1470 CFIndex i;
1471 CFIndex n;
1472 BondPreferencesRef prefs;
1473 CFArrayRef bonds = NULL;
1474
1475 prefs = BondPreferencesCreate(NULL);
1476 if (prefs == NULL) {
1477 // if no bonds
1478 return NULL;
1479 }
1480
1481 bonds = BondPreferencesCopyInterfaces(prefs);
1482 if (bonds == NULL) {
1483 // if no bonds
1484 goto done;
1485 }
1486
1487 n = CFArrayGetCount(bonds);
1488 if (n == 0) {
1489 // if no bonds
1490 goto done;
1491 }
1492
1493 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1494
1495 for (i = 0; i < n; i++) {
1496 SCNetworkInterfaceRef interface;
1497 BondInterfaceRef bond = CFArrayGetValueAtIndex(bonds, i);
1498 CFStringRef bond_if;
1499
1500 bond_if = BondInterfaceGetInterface(bond);
1501 if (bond_if == NULL) {
1502 continue;
1503 }
1504
1505 if ((match != NULL) && !CFEqual(bond_if, match)) {
1506 continue;
1507 }
1508
1509 interface = SCNetworkInterfaceCreateWithBond(bond);
1510 CFArrayAppendValue(interfaces, interface);
1511 CFRelease(interface);
1512 }
1513
1514 done :
1515
1516 if (bonds != NULL) CFRelease(bonds);
1517 CFRelease(prefs);
1518 return interfaces;
1519 }
1520
1521
1522 /* ---------- VLAN configuration ---------- */
1523
1524 SCNetworkInterfaceRef
1525 SCNetworkInterfaceCreateWithVLAN(VLANInterfaceRef vlan)
1526 {
1527 SCNetworkInterfacePrivateRef interfacePrivate;
1528 CFStringRef vlan_if;
1529
1530 vlan_if = VLANInterfaceGetInterface(vlan);
1531 if (vlan_if == NULL) {
1532 return NULL;
1533 }
1534
1535 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
1536 if (interfacePrivate == NULL) {
1537 return NULL;
1538 }
1539
1540 interfacePrivate->interface_type = kSCNetworkInterfaceTypeVLAN;
1541 interfacePrivate->entity_type = kSCEntNetEthernet;
1542 interfacePrivate->entity_hardware = kSCEntNetEthernet;
1543 interfacePrivate->entity_device = CFStringCreateCopy(NULL, vlan_if);
1544 interfacePrivate->builtin = TRUE;
1545 interfacePrivate->sort_order = kSortVLAN;
1546
1547 interfacePrivate->localized_key = CFSTR("vlan");
1548 interfacePrivate->localized_arg1 = CFRetain(interfacePrivate->entity_device);
1549
1550 return (SCNetworkInterfaceRef)interfacePrivate;
1551 }
1552
1553
1554 static CFArrayRef
1555 findVLANInterfaces(CFStringRef match)
1556 {
1557 CFMutableArrayRef interfaces = NULL;
1558 CFIndex i;
1559 CFIndex n;
1560 VLANPreferencesRef prefs;
1561 CFArrayRef vlans = NULL;
1562
1563 prefs = VLANPreferencesCreate(NULL);
1564 if (prefs == NULL) {
1565 // if no VLANs
1566 return NULL;
1567 }
1568
1569 vlans = VLANPreferencesCopyInterfaces(prefs);
1570 if (vlans == NULL) {
1571 // if no VLANs
1572 goto done;
1573 }
1574
1575 n = CFArrayGetCount(vlans);
1576 if (n == 0) {
1577 // if no VLANs
1578 goto done;
1579 }
1580
1581 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1582
1583 for (i = 0; i < n; i++) {
1584 SCNetworkInterfaceRef interface;
1585 VLANInterfaceRef vlan = CFArrayGetValueAtIndex(vlans, i);
1586 CFStringRef vlan_if;
1587
1588 vlan_if = VLANInterfaceGetInterface(vlan);
1589 if (vlan_if == NULL) {
1590 continue;
1591 }
1592
1593 if ((match != NULL) && !CFEqual(vlan_if, match)) {
1594 continue;
1595 }
1596
1597 interface = SCNetworkInterfaceCreateWithVLAN(vlan);
1598 CFArrayAppendValue(interfaces, interface);
1599 CFRelease(interface);
1600 }
1601
1602 done :
1603
1604 if (vlans != NULL) CFRelease(vlans);
1605 CFRelease(prefs);
1606 return interfaces;
1607 }
1608
1609
1610 /* ---------- interface from preferences ---------- */
1611
1612
1613 __private_extern__ SCNetworkInterfaceRef
1614 __SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator,
1615 CFDictionaryRef interface_entity,
1616 SCNetworkServiceRef service)
1617 {
1618 SCNetworkInterfacePrivateRef interfacePrivate = NULL;
1619 CFStringRef ifDevice;
1620 CFStringRef ifSubType;
1621 CFStringRef ifType;
1622 static mach_port_t masterPort = MACH_PORT_NULL;
1623 CFArrayRef matching_interfaces = NULL;
1624
1625 if (masterPort == MACH_PORT_NULL) {
1626 kern_return_t kr;
1627
1628 kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
1629 if (kr != KERN_SUCCESS) {
1630 return NULL;
1631 }
1632 }
1633
1634 ifType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceType);
1635 if (!isA_CFString(ifType)) {
1636 return NULL;
1637 }
1638
1639 ifSubType = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceSubType);
1640 if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
1641 if (!isA_CFString(ifSubType)) {
1642 return NULL;
1643 }
1644 }
1645
1646 ifDevice = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceDeviceName);
1647
1648 if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet) ||
1649 CFEqual(ifType, kSCValNetInterfaceTypeFireWire) ||
1650 (CFEqual(ifType, kSCValNetInterfaceTypePPP) && CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE))) {
1651 char bsdName[IFNAMSIZ + 1];
1652 CFMutableDictionaryRef matching;
1653
1654 if (!isA_CFString(ifDevice)) {
1655 return NULL;
1656 }
1657
1658 if (_SC_cfstring_to_cstring(ifDevice, bsdName, sizeof(bsdName), kCFStringEncodingASCII) == NULL) {
1659 goto done;
1660 }
1661
1662 matching = IOBSDNameMatching(masterPort, 0, bsdName);
1663 if (matching == NULL) {
1664 goto done;
1665 }
1666
1667 // note: the "matching" dictionary will be consumed by the following
1668 matching_interfaces = findMatchingInterfaces(masterPort, matching, processNetworkInterface);
1669
1670 } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
1671 if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) {
1672 CFDictionaryRef matching;
1673 CFStringRef match_keys[2];
1674 CFStringRef match_vals[2];
1675
1676 if (!isA_CFString(ifDevice)) {
1677 return NULL;
1678 }
1679
1680 match_keys[0] = CFSTR(kIOProviderClassKey);
1681 match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
1682
1683 match_keys[1] = CFSTR(kIOTTYDeviceKey);
1684 match_vals[1] = ifDevice;
1685
1686 matching = CFDictionaryCreate(NULL,
1687 (const void **)match_keys,
1688 (const void **)match_vals,
1689 sizeof(match_keys)/sizeof(match_keys[0]),
1690 &kCFTypeDictionaryKeyCallBacks,
1691 &kCFTypeDictionaryValueCallBacks);
1692
1693 // note: the "matching" dictionary will be consumed by the following
1694 matching_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface);
1695
1696 } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypeL2TP)) {
1697 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
1698 kSCNetworkInterfaceTypeL2TP);
1699 } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPTP)) {
1700 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
1701 kSCNetworkInterfaceTypePPTP);
1702 } else {
1703 // XXX do we allow non-Apple variants of PPP??? XXX
1704 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
1705 ifSubType);
1706 }
1707 } else if (CFEqual(ifType, kSCValNetInterfaceType6to4)) {
1708 if (!isA_CFString(ifDevice)) {
1709 return NULL;
1710 }
1711
1712 interfacePrivate = (SCNetworkInterfacePrivateRef)SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,
1713 kSCNetworkInterfaceType6to4);
1714 }
1715
1716 if (matching_interfaces != NULL) {
1717 CFIndex n;
1718
1719 n = CFArrayGetCount(matching_interfaces);
1720 switch (n) {
1721 case 0 :
1722 if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) {
1723 CFArrayRef bonds;
1724 CFArrayRef vlans;
1725
1726 bonds = findBondInterfaces(ifDevice);
1727 if (bonds != NULL) {
1728 if (CFArrayGetCount(bonds) == 1) {
1729 interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(bonds, 0);
1730 CFRetain(interfacePrivate);
1731 }
1732 CFRelease(bonds);
1733 break;
1734 }
1735
1736 vlans = findVLANInterfaces(ifDevice);
1737 if (vlans != NULL) {
1738 if (CFArrayGetCount(vlans) == 1) {
1739 interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(vlans, 0);
1740 CFRetain(interfacePrivate);
1741 }
1742 CFRelease(vlans);
1743 break;
1744 }
1745 }
1746 break;
1747 case 1 :
1748 interfacePrivate = (SCNetworkInterfacePrivateRef)CFArrayGetValueAtIndex(matching_interfaces, 0);
1749 CFRetain(interfacePrivate);
1750 break;
1751 default :
1752 SCPrint(TRUE, stderr, CFSTR("more than one interface matches %@\n"), ifDevice);
1753 if (matching_interfaces != NULL) CFRelease(matching_interfaces);
1754 _SCErrorSet(kSCStatusFailed);
1755 return NULL;
1756 }
1757 CFRelease(matching_interfaces);
1758 }
1759
1760 done :
1761
1762 if (interfacePrivate == NULL) {
1763 /*
1764 * if device not present on this system
1765 */
1766 interfacePrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
1767 interfacePrivate->entity_type = ifType;
1768 interfacePrivate->entity_subtype = ifSubType;
1769 interfacePrivate->entity_device = (ifDevice != NULL) ? CFStringCreateCopy(NULL, ifDevice) : NULL;
1770 interfacePrivate->entity_hardware = CFDictionaryGetValue(interface_entity, kSCPropNetInterfaceHardware);
1771
1772 if (CFEqual(ifType, kSCValNetInterfaceTypeEthernet)) {
1773 if ((interfacePrivate->entity_hardware != NULL) &&
1774 CFEqual(interfacePrivate->entity_hardware, kSCEntNetAirPort)) {
1775 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIEEE80211;
1776 } else {
1777 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
1778 }
1779 } else if (CFEqual(ifType, kSCValNetInterfaceTypeFireWire)) {
1780 interfacePrivate->interface_type = kSCNetworkInterfaceTypeFireWire;
1781 } else if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
1782 if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPoE)) {
1783 interfacePrivate->interface_type = kSCNetworkInterfaceTypeEthernet;
1784 } else if (CFEqual(ifSubType, kSCValNetInterfaceSubTypePPPSerial)) {
1785 if (CFStringHasPrefix(ifDevice, CFSTR("irda"))) {
1786 interfacePrivate->interface_type = kSCNetworkInterfaceTypeIrDA;
1787 } else if (CFStringHasPrefix(ifDevice, CFSTR("Bluetooth"))) {
1788 interfacePrivate->interface_type = kSCNetworkInterfaceTypeBluetooth;
1789 } else {
1790 interfacePrivate->interface_type = kSCNetworkInterfaceTypeModem;
1791 }
1792 } else {
1793 // PPTP, L2TP, ...
1794 CFRelease(interfacePrivate);
1795 interfacePrivate = (SCNetworkInterfacePrivateRef)kSCNetworkInterfaceIPv4;
1796 CFRetain(interfacePrivate);
1797 }
1798 } else {
1799 // unknown interface type
1800 CFRelease(interfacePrivate);
1801 interfacePrivate = NULL;
1802 }
1803 }
1804
1805 if ((interfacePrivate != NULL) && (service != NULL)) {
1806 interfacePrivate->service = service;
1807 }
1808
1809 if (CFEqual(ifType, kSCValNetInterfaceTypePPP)) {
1810 SCNetworkInterfaceRef parent;
1811
1812 parent = SCNetworkInterfaceCreateWithInterface((SCNetworkInterfaceRef)interfacePrivate,
1813 kSCNetworkInterfaceTypePPP);
1814 CFRelease(interfacePrivate);
1815 interfacePrivate = (SCNetworkInterfacePrivateRef)parent;
1816 }
1817
1818 return (SCNetworkInterfaceRef)interfacePrivate;
1819 }
1820
1821
1822 /* ---------- helper functions ---------- */
1823
1824
1825 static CFIndex
1826 findConfiguration(CFStringRef interface_type)
1827 {
1828 CFIndex i;
1829
1830 for (i = 0; i < sizeof(configurations)/sizeof(configurations[0]); i++) {
1831 if (CFEqual(interface_type, *configurations[i].interface_type)) {
1832 return i;
1833 }
1834 }
1835
1836 return kCFNotFound;
1837 }
1838
1839
1840 static CFArrayRef
1841 copyConfigurationPaths(SCNetworkInterfacePrivateRef interfacePrivate)
1842 {
1843 CFMutableArrayRef array = NULL;
1844 CFIndex interfaceIndex;
1845 CFStringRef path;
1846 SCNetworkServicePrivateRef servicePrivate;
1847
1848 interfaceIndex = findConfiguration(interfacePrivate->interface_type);
1849 if (interfaceIndex == kCFNotFound) {
1850 // if unknown interface type
1851 return NULL;
1852 }
1853
1854 servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service;
1855 if (servicePrivate == NULL) {
1856 // if not associated with a service (yet)
1857 return NULL;
1858 }
1859
1860 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1861
1862 if (configurations[interfaceIndex].per_interface_config) {
1863 CFIndex i;
1864 CFIndex n;
1865 CFArrayRef sets;
1866
1867 /*
1868 * per-interface configuration preferences
1869 *
1870 * 1. look for all sets which contain the associated service
1871 * 2. add a per-set path for the interface configuration for
1872 * each set.
1873 */
1874
1875 sets = SCNetworkSetCopyAll(servicePrivate->prefs);
1876 n = (sets != NULL) ? CFArrayGetCount(sets) : 0;
1877
1878 for (i = 0; i < n; i++) {
1879 CFArrayRef services;
1880 SCNetworkSetRef set;
1881
1882 set = CFArrayGetValueAtIndex(sets, i);
1883 services = SCNetworkSetCopyServices(set);
1884 if (CFArrayContainsValue(services,
1885 CFRangeMake(0, CFArrayGetCount(services)),
1886 interfacePrivate->service)) {
1887 path = SCPreferencesPathKeyCreateSetNetworkInterfaceEntity(NULL, // allocator
1888 SCNetworkSetGetSetID(set), // set
1889 interfacePrivate->entity_device, // service
1890 interfacePrivate->entity_type); // entity
1891 CFArrayAppendValue(array, path);
1892 CFRelease(path);
1893 }
1894 CFRelease(services);
1895 }
1896
1897 if (CFArrayGetCount(array) == 0) {
1898 CFRelease(array);
1899 array = NULL;
1900 }
1901
1902 CFRelease(sets);
1903 } else {
1904 // per-service configuration preferences
1905 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1906 servicePrivate->serviceID, // service
1907 interfacePrivate->entity_type); // entity
1908 CFArrayAppendValue(array, path);
1909 CFRelease(path);
1910 }
1911
1912 return array;
1913 }
1914
1915
1916 /* ---------- SCNetworkInterface APIs ---------- */
1917
1918
1919 CFArrayRef /* of SCNetworkInterfaceRef's */
1920 SCNetworkInterfaceCopyAll()
1921 {
1922 CFMutableArrayRef all_interfaces;
1923 static mach_port_t masterPort = MACH_PORT_NULL;
1924 CFDictionaryRef matching;
1925 CFStringRef match_keys[2];
1926 CFStringRef match_vals[2];
1927 CFArrayRef new_interfaces;
1928
1929 if (masterPort == MACH_PORT_NULL) {
1930 kern_return_t kr;
1931
1932 kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
1933 if (kr != KERN_SUCCESS) {
1934 return NULL;
1935 }
1936 }
1937
1938 all_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1939
1940 // get Ethernet, Firewire, and AirPort interfaces
1941
1942 matching = IOServiceMatching(kIONetworkInterfaceClass);
1943 new_interfaces = findMatchingInterfaces(masterPort, matching, processNetworkInterface);
1944 if (new_interfaces != NULL) {
1945 CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces)));
1946 CFRelease(new_interfaces);
1947 }
1948
1949 // get Modem interfaces
1950
1951 match_keys[0] = CFSTR(kIOProviderClassKey);
1952 match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
1953
1954 match_keys[1] = CFSTR(kIOSerialBSDTypeKey);
1955 match_vals[1] = CFSTR(kIOSerialBSDModemType);
1956
1957 matching = CFDictionaryCreate(NULL,
1958 (const void **)match_keys,
1959 (const void **)match_vals,
1960 sizeof(match_keys)/sizeof(match_keys[0]),
1961 &kCFTypeDictionaryKeyCallBacks,
1962 &kCFTypeDictionaryValueCallBacks);
1963 new_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface);
1964 if (new_interfaces != NULL) {
1965 CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces)));
1966 CFRelease(new_interfaces);
1967 }
1968
1969 // get serial (RS232) interfaces
1970
1971 match_keys[0] = CFSTR(kIOProviderClassKey);
1972 match_vals[0] = CFSTR(kIOSerialBSDServiceValue);
1973
1974 match_keys[1] = CFSTR(kIOSerialBSDTypeKey);
1975 match_vals[1] = CFSTR(kIOSerialBSDRS232Type);
1976
1977 matching = CFDictionaryCreate(NULL,
1978 (const void **)match_keys,
1979 (const void **)match_vals,
1980 sizeof(match_keys)/sizeof(match_keys[0]),
1981 &kCFTypeDictionaryKeyCallBacks,
1982 &kCFTypeDictionaryValueCallBacks);
1983 new_interfaces = findMatchingInterfaces(masterPort, matching, processSerialInterface);
1984 if (new_interfaces != NULL) {
1985 CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces)));
1986 CFRelease(new_interfaces);
1987 }
1988
1989 new_interfaces = findBondInterfaces(NULL);
1990 if (new_interfaces != NULL) {
1991 CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces)));
1992 CFRelease(new_interfaces);
1993 }
1994
1995 new_interfaces = findVLANInterfaces(NULL);
1996 if (new_interfaces != NULL) {
1997 CFArrayAppendArray(all_interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces)));
1998 CFRelease(new_interfaces);
1999 }
2000
2001 sort_interfaces(all_interfaces);
2002
2003 return all_interfaces;
2004 }
2005
2006
2007 CFArrayRef /* of kSCNetworkInterfaceTypeXXX CFStringRef's */
2008 SCNetworkInterfaceGetSupportedInterfaceTypes(SCNetworkInterfaceRef interface)
2009 {
2010 CFIndex i;
2011 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2012
2013 if (interfacePrivate->supported_interface_types != NULL) {
2014 goto done;
2015 }
2016
2017 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2018 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2019
2020 i = findConfiguration(interfacePrivate->interface_type);
2021 if (i != kCFNotFound) {
2022 if (configurations[i].supported_interfaces != doNone) {
2023 interfacePrivate->supported_interface_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2024 if (configurations[i].supported_interfaces & do6to4) {
2025 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceType6to4);
2026 }
2027 if (configurations[i].supported_interfaces & doL2TP) {
2028 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypeL2TP);
2029 }
2030 if (configurations[i].supported_interfaces & doPPP) {
2031 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPP);
2032 }
2033 if (configurations[i].supported_interfaces & doPPTP) {
2034 CFArrayAppendValue(interfacePrivate->supported_interface_types, kSCNetworkInterfaceTypePPTP);
2035 }
2036 }
2037 }
2038
2039 done :
2040
2041 return interfacePrivate->supported_interface_types;
2042 }
2043
2044
2045 CFArrayRef /* of kSCNetworkProtocolTypeXXX CFStringRef's */
2046 SCNetworkInterfaceGetSupportedProtocolTypes(SCNetworkInterfaceRef interface)
2047 {
2048 CFIndex i;
2049 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2050
2051 if (interfacePrivate->supported_protocol_types != NULL) {
2052 goto done;
2053 }
2054
2055 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2056 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2057
2058 i = findConfiguration(interfacePrivate->interface_type);
2059 if (i != kCFNotFound) {
2060 if (configurations[i].supported_protocols != doNone) {
2061 interfacePrivate->supported_protocol_types = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2062 if (configurations[i].supported_protocols & doAppleTalk) {
2063 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeAppleTalk);
2064 }
2065 if (configurations[i].supported_protocols & doDNS) {
2066 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeDNS);
2067 }
2068 if (configurations[i].supported_protocols & doIPv4) {
2069 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv4);
2070 }
2071 if (configurations[i].supported_protocols & doIPv6) {
2072 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeIPv6);
2073 }
2074 if (configurations[i].supported_protocols & doProxies) {
2075 CFArrayAppendValue(interfacePrivate->supported_protocol_types, kSCNetworkProtocolTypeProxies);
2076 }
2077 }
2078 }
2079
2080 done :
2081
2082 return interfacePrivate->supported_protocol_types;
2083 }
2084
2085
2086 SCNetworkInterfaceRef
2087 SCNetworkInterfaceCreateWithInterface(SCNetworkInterfaceRef child, CFStringRef interfaceType)
2088 {
2089 SCNetworkInterfacePrivateRef childPrivate = (SCNetworkInterfacePrivateRef)child;
2090 CFIndex childIndex;
2091 SCNetworkInterfacePrivateRef parentPrivate;
2092
2093 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2094 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2095
2096 childIndex = findConfiguration(childPrivate->interface_type);
2097
2098 parentPrivate = __SCNetworkInterfaceCreatePrivate(NULL, child, childPrivate->service, NULL);
2099 if (parentPrivate == NULL) {
2100 _SCErrorSet(kSCStatusFailed);
2101 return NULL;
2102 }
2103
2104 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
2105 parentPrivate->interface_type = kSCNetworkInterfaceTypePPP;
2106 parentPrivate->entity_type = kSCEntNetPPP;
2107
2108 // entity subtype
2109 if (childIndex != kCFNotFound) {
2110 if (configurations[childIndex].ppp_subtype != NULL) {
2111 parentPrivate->entity_subtype = *configurations[childIndex].ppp_subtype;
2112 } else {
2113 // sorry, the child interface does not support PPP
2114 goto fail;
2115 }
2116 } else {
2117 // if the child's interface type not known, use the child entities "Type"
2118 parentPrivate->entity_subtype = childPrivate->entity_type;
2119 }
2120
2121 if (childPrivate->entity_device != NULL) {
2122 parentPrivate->entity_device = CFStringCreateCopy(NULL, childPrivate->entity_device);
2123 }
2124 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
2125 if ((childIndex == kCFNotFound) ||
2126 ((configurations[childIndex].supported_interfaces & doL2TP) != doL2TP)) {
2127 // if the child interface does not support L2TP
2128 goto fail;
2129 }
2130 parentPrivate->interface_type = kSCNetworkInterfaceTypeL2TP;
2131 parentPrivate->entity_type = kSCValNetInterfaceSubTypeL2TP; // interface config goes into "L2TP"
2132 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) {
2133 if ((childIndex == kCFNotFound) ||
2134 ((configurations[childIndex].supported_interfaces & doPPTP) != doPPTP)) {
2135 // if the child interface does not support PPTP
2136 goto fail;
2137 }
2138 parentPrivate->interface_type = kSCNetworkInterfaceTypePPTP;
2139 parentPrivate->entity_type = kSCValNetInterfaceSubTypePPTP; // interface config goes into "PPTP"
2140 } else if (CFEqual(interfaceType, kSCNetworkInterfaceType6to4)) {
2141 if ((childIndex == kCFNotFound) ||
2142 ((configurations[childIndex].supported_interfaces & do6to4) != do6to4)) {
2143 // if the child interface does not support 6to4
2144 goto fail;
2145 }
2146
2147 parentPrivate->interface_type = kSCNetworkInterfaceType6to4;
2148 parentPrivate->entity_type = kSCEntNet6to4;
2149 parentPrivate->entity_device = CFRetain(CFSTR("stf0"));
2150 CFRetain(parentPrivate->entity_device);
2151 } else {
2152 // unknown interface type
2153 goto fail;
2154 }
2155
2156 parentPrivate->entity_hardware = childPrivate->entity_hardware;
2157 parentPrivate->sort_order = childPrivate->sort_order;
2158
2159 return (SCNetworkInterfaceRef)parentPrivate;
2160
2161 fail :
2162
2163 CFRelease(parentPrivate);
2164 _SCErrorSet(kSCStatusInvalidArgument);
2165 return NULL;
2166 }
2167
2168
2169 static CFDictionaryRef
2170 __SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface, Boolean okToHold)
2171 {
2172 CFDictionaryRef config = NULL;
2173 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2174 CFArrayRef paths;
2175
2176 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2177 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2178
2179 paths = copyConfigurationPaths(interfacePrivate);
2180 if (paths != NULL) {
2181 CFStringRef path;
2182 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service;
2183
2184 path = CFArrayGetValueAtIndex(paths, 0);
2185 config = __getPrefsConfiguration(servicePrivate->prefs, path);
2186
2187 CFRelease(paths);
2188 } else if (okToHold) {
2189 config = interfacePrivate->unsaved;
2190 }
2191
2192 return config;
2193 }
2194
2195
2196 CFDictionaryRef
2197 SCNetworkInterfaceGetConfiguration(SCNetworkInterfaceRef interface)
2198 {
2199 return __SCNetworkInterfaceGetConfiguration(interface, FALSE);
2200 }
2201
2202
2203 CFStringRef
2204 SCNetworkInterfaceGetBSDName(SCNetworkInterfaceRef interface)
2205 {
2206 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2207
2208 if (interfacePrivate->interface != NULL) {
2209 return NULL;
2210 }
2211
2212 return interfacePrivate->entity_device;
2213 }
2214
2215
2216 CFStringRef
2217 SCNetworkInterfaceGetHardwareAddressString(SCNetworkInterfaceRef interface)
2218 {
2219 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2220
2221 return interfacePrivate->address;
2222 }
2223
2224 SCNetworkInterfaceRef
2225 SCNetworkInterfaceGetInterface(SCNetworkInterfaceRef interface)
2226 {
2227 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2228
2229 return interfacePrivate->interface;
2230 }
2231
2232
2233 CFStringRef
2234 SCNetworkInterfaceGetInterfaceType(SCNetworkInterfaceRef interface)
2235 {
2236 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2237
2238 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2239 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2240
2241 return interfacePrivate->interface_type;
2242 }
2243
2244
2245 CFStringRef
2246 SCNetworkInterfaceGetLocalizedDisplayName(SCNetworkInterfaceRef interface)
2247 {
2248 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2249
2250 if (interfacePrivate->localized_name == NULL) {
2251 CFStringRef child = NULL;
2252 CFMutableStringRef local = NULL;
2253
2254 pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* initialize runtime */
2255
2256 if (interfacePrivate->interface != NULL) {
2257 child = SCNetworkInterfaceGetLocalizedDisplayName(interfacePrivate->interface);
2258 }
2259
2260 if (interfacePrivate->localized_key != NULL) {
2261 CFStringRef fmt;
2262
2263 fmt = CFBundleCopyLocalizedString(bundle,
2264 interfacePrivate->localized_key,
2265 interfacePrivate->localized_key,
2266 NETWORKINTERFACE_LOCALIZATIONS);
2267 if (fmt != NULL) {
2268 local = CFStringCreateMutable(NULL, 0);
2269 CFStringAppendFormat(local,
2270 NULL,
2271 fmt,
2272 interfacePrivate->localized_arg1,
2273 interfacePrivate->localized_arg2);
2274 CFRelease(fmt);
2275 }
2276 }
2277
2278 if (local == NULL) {
2279 // create (non-)localized name based on the interface type
2280 local = CFStringCreateMutableCopy(NULL, 0, interfacePrivate->interface_type);
2281
2282 // ... and, if this is a leaf node, the interface device
2283 if ((interfacePrivate->entity_device != NULL) && (child == NULL)) {
2284 CFStringAppendFormat(local, NULL, CFSTR(" (%@)"), interfacePrivate->entity_device);
2285 }
2286 }
2287
2288 if (child == NULL) {
2289 // no child, show just this interfaces localized name
2290 interfacePrivate->localized_name = CFStringCreateCopy(NULL, local);
2291 } else {
2292 // show localized interface name layered over child
2293 interfacePrivate->localized_name = CFStringCreateWithFormat(NULL,
2294 NULL,
2295 CFSTR("%@ --> %@"),
2296 local,
2297 child);
2298 }
2299 CFRelease(local);
2300 }
2301
2302 return interfacePrivate->localized_name;
2303 }
2304
2305
2306 CFTypeID
2307 SCNetworkInterfaceGetTypeID(void)
2308 {
2309 pthread_once(&initialized, __SCNetworkInterfaceInitialize); /* initialize runtime */
2310 return __kSCNetworkInterfaceTypeID;
2311 }
2312
2313
2314 __private_extern__ Boolean
2315 __SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config, Boolean okToHold)
2316 {
2317 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
2318 Boolean ok = FALSE;
2319 CFArrayRef paths;
2320
2321 /* initialize runtime (and kSCNetworkInterfaceIPv4) */
2322 pthread_once(&initialized, __SCNetworkInterfaceInitialize);
2323
2324 paths = copyConfigurationPaths(interfacePrivate);
2325 if (paths != NULL) {
2326 CFIndex i;
2327 CFIndex n;
2328 SCPreferencesRef prefs;
2329 SCNetworkServicePrivateRef servicePrivate;
2330
2331 servicePrivate = (SCNetworkServicePrivateRef)interfacePrivate->service;
2332 prefs = servicePrivate->prefs;
2333
2334 n = CFArrayGetCount(paths);
2335 for (i = 0; i < n; i++) {
2336 CFStringRef path;
2337
2338 path = CFArrayGetValueAtIndex(paths, i);
2339 ok = __setPrefsConfiguration(prefs, path, config, FALSE);
2340 if (!ok) {
2341 break;
2342 }
2343 }
2344
2345 CFRelease(paths);
2346 } else if (okToHold) {
2347 interfacePrivate->unsaved = config;
2348 ok = TRUE;
2349 } else {
2350 _SCErrorSet(kSCStatusNoKey);
2351 }
2352
2353 return ok;
2354 }
2355
2356
2357 Boolean
2358 SCNetworkInterfaceSetConfiguration(SCNetworkInterfaceRef interface, CFDictionaryRef config)
2359 {
2360 return __SCNetworkInterfaceSetConfiguration(interface, config, FALSE);
2361 }
2362
2363
2364 /* ---------- SCNetworkInterface internal SPIs ---------- */
2365
2366
2367 __private_extern__ SCNetworkInterfacePrivateRef
2368 __SCNetworkInterfaceCreateCopy(CFAllocatorRef allocator,
2369 SCNetworkInterfaceRef interface,
2370 SCNetworkServiceRef service)
2371 {
2372 SCNetworkInterfacePrivateRef oldPrivate = (SCNetworkInterfacePrivateRef)interface;
2373 SCNetworkInterfacePrivateRef newPrivate;
2374
2375 newPrivate = __SCNetworkInterfaceCreatePrivate(NULL, NULL, NULL, NULL);
2376 newPrivate->interface_type = CFRetain(oldPrivate->interface_type);
2377 if (oldPrivate->interface != NULL) {
2378 newPrivate->interface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL, // allocator
2379 oldPrivate->interface, // interface
2380 service); // [new] service
2381 }
2382 newPrivate->localized_name = (oldPrivate->localized_name != NULL) ? CFRetain(oldPrivate->localized_name) : NULL;
2383 newPrivate->service = service;
2384 newPrivate->unsaved = (oldPrivate->unsaved != NULL) ? CFRetain(oldPrivate->unsaved) : NULL;
2385 newPrivate->entity_device = (oldPrivate->entity_device != NULL) ? CFRetain(oldPrivate->entity_device) : NULL;
2386 newPrivate->entity_hardware = CFRetain(oldPrivate->entity_hardware);
2387 newPrivate->entity_type = oldPrivate->entity_type;
2388 newPrivate->entity_subtype = oldPrivate->entity_subtype;
2389 if (oldPrivate->supported_interface_types != NULL) {
2390 newPrivate->supported_interface_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_interface_types);
2391 }
2392 if (oldPrivate->supported_protocol_types != NULL) {
2393 newPrivate->supported_protocol_types = CFArrayCreateMutableCopy(NULL, 0, oldPrivate->supported_protocol_types);
2394 }
2395 newPrivate->address = (oldPrivate->address != NULL) ? CFRetain(oldPrivate->address) : NULL;
2396 newPrivate->builtin = oldPrivate->builtin;
2397 newPrivate->path = (oldPrivate->path != NULL) ? CFRetain(oldPrivate->path) : NULL;
2398 newPrivate->location = (oldPrivate->location != NULL) ? CFRetain(oldPrivate->location) : NULL;
2399 newPrivate->supportsDeviceOnHold = oldPrivate->supportsDeviceOnHold;
2400 newPrivate->supportsBond = oldPrivate->supportsBond;
2401 newPrivate->supportsVLAN = oldPrivate->supportsVLAN;
2402 newPrivate->sort_order = oldPrivate->sort_order;
2403
2404 return newPrivate;
2405 }
2406
2407
2408 __private_extern__ CFArrayRef
2409 __SCNetworkInterfaceCopyDeepConfiguration(SCNetworkInterfaceRef interface)
2410 {
2411 CFDictionaryRef config;
2412 CFMutableArrayRef configs;
2413
2414 configs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2415
2416 while (interface != NULL) {
2417 config = __SCNetworkInterfaceGetConfiguration(interface, TRUE);
2418 CFArrayAppendValue(configs,
2419 (config != NULL) ? config : (CFDictionaryRef)kCFNull);
2420 interface = SCNetworkInterfaceGetInterface(interface);
2421 }
2422
2423 return configs;
2424 }
2425
2426
2427 __private_extern__ void
2428 __SCNetworkInterfaceSetDeepConfiguration(SCNetworkInterfaceRef interface, CFArrayRef configs)
2429 {
2430 CFIndex i;
2431
2432 for (i = 0; interface != NULL; i++) {
2433 CFDictionaryRef config;
2434
2435 config = (configs != NULL) ? CFArrayGetValueAtIndex(configs, i) : NULL;
2436 if (!isA_CFDictionary(config) || (CFDictionaryGetCount(config) == 0)) {
2437 config = NULL;
2438 }
2439
2440 (void) __SCNetworkInterfaceSetConfiguration(interface, config, TRUE);
2441 interface = SCNetworkInterfaceGetInterface(interface);
2442 }
2443
2444 return;
2445 }