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