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