]> git.saurik.com Git - apple/configd.git/blob - Plugins/InterfaceNamer/ifnamer.c
configd-596.13.tar.gz
[apple/configd.git] / Plugins / InterfaceNamer / ifnamer.c
1 /*
2 * Copyright (c) 2001-2013 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 20, 2006 Joe Liu <joe.liu@apple.com>
28 * Allan Nathanson <ajn@apple.com>
29 * - register interface by entryID (and not path)
30 *
31 * November 6, 2006 Allan Nathanson <ajn@apple.com>
32 * Dan Markarian <markarian@apple.com>
33 * Dieter Siegmund <dieter@apple.com>
34 * - updated code to name interfaces quicker (without need for
35 * calling IOKitWaitQuiet).
36 *
37 * October 3, 2003 Allan Nathanson <ajn@apple.com>
38 * - sort new interfaces by IOKit path (rather than MAC address) to
39 * help facilitate a more predictable interface-->name mapping for
40 * like hardware configurations.
41 *
42 * June 23, 2001 Allan Nathanson <ajn@apple.com>
43 * - update to public SystemConfiguration.framework APIs
44 *
45 * January 23, 2001 Dieter Siegmund <dieter@apple.com>
46 * - initial revision
47 */
48
49 /*
50 * ifnamer.c
51 * - module that receives IOKit Network Interface messages
52 * and names any interface that currently does not have a name
53 * - uses Interface Type and MACAddress as the unique identifying
54 * keys; any interface that doesn't contain both of these properties
55 * is ignored and not processed
56 * - stores the Interface Type, MACAddress, and Unit in permanent storage
57 * to give persistent interface names
58 */
59
60 #include <ctype.h>
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include <unistd.h>
64 #include <fcntl.h>
65 #include <sys/ioctl.h>
66 #include <sys/stat.h>
67 #include <sys/sysctl.h>
68 #include <sys/param.h>
69 #include <mach/mach.h>
70 #include <net/ethernet.h>
71 #include <net/if_types.h>
72 #include <pthread.h>
73 #include <vproc.h>
74
75 #include <CommonCrypto/CommonDigest.h>
76
77 #include <CoreFoundation/CoreFoundation.h>
78
79 #include <SystemConfiguration/SystemConfiguration.h>
80 #include <SystemConfiguration/SCDPlugin.h>
81 #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
82 #include <SystemConfiguration/SCValidation.h>
83
84 #include <IOKit/IOKitLib.h>
85 #include <IOKit/IOKitLibPrivate.h>
86 #include <IOKit/IOBSD.h>
87 #include <IOKit/IOMessage.h>
88 #include <IOKit/network/IONetworkController.h>
89 #include <IOKit/network/IONetworkInterface.h>
90 #include <IOKit/network/IONetworkStack.h>
91 #include <IOKit/usb/USB.h>
92
93 #ifdef kIONetworkStackUserCommandKey
94 #define USE_REGISTRY_ENTRY_ID
95 #endif
96
97 #ifndef USE_REGISTRY_ENTRY_ID
98 // from <IOKit/network/IONetworkStack.h>
99 #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand"
100 enum {
101 kRegisterInterfaceWithFixedUnit = 0,
102 kRegisterInterface,
103 kRegisterAllInterfaces
104 };
105 #endif // !USE_REGISTRY_ENTRY_ID
106
107 #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo"
108 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
109 #define kSCNetworkInterfaceActive "Active"
110
111 #define MY_PLUGIN_NAME "InterfaceNamer"
112 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
113
114 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
115 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
116
117 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
118 #define WAIT_QUIET_TIMEOUT_DEFAULT 60.0
119
120 /*
121 * S_connect
122 * "IONetworkStack" connect object used to "name" an interface.
123 */
124 static io_connect_t S_connect = MACH_PORT_NULL;
125
126 /*
127 * S_dblist
128 * An array of CFDictionary's representing the interfaces
129 * that have been identified and [need to be] named.
130 */
131 static CFMutableArrayRef S_dblist = NULL;
132
133 /*
134 * S_debug
135 * A boolean that enables additional logging.
136 */
137 static boolean_t S_debug = FALSE;
138
139 /*
140 * S_iflist
141 * An array of SCNetworkInterface's representing the
142 * interfaces that have been identified.
143 */
144 static CFMutableArrayRef S_iflist = NULL;
145
146 /*
147 * S_iter
148 * IOServiceAddMatchingNotification object used to watch for
149 * new network interfaces.
150 */
151 static io_iterator_t S_iter = MACH_PORT_NULL;
152
153 /*
154 * S_notify
155 * notification object for receiving IOKit notifications of
156 * new devices or state changes.
157 */
158 static IONotificationPortRef S_notify = NULL;
159
160 /* S_prev_active_list
161 * An array of CFDictionary's representing the previously
162 * named interfaces.
163 */
164 static CFMutableArrayRef S_prev_active_list = NULL;
165
166 /*
167 * S_quiet
168 * IOServiceAddInterestNotification object used to watch for
169 * IOKit matching to quiesce.
170 */
171 static io_object_t S_quiet = MACH_PORT_NULL;
172
173 /*
174 * S_stack
175 * IOServiceAddMatchingNotification object used to watch for
176 * the availability of the "IONetworkStack" object.
177 */
178 static io_iterator_t S_stack = MACH_PORT_NULL;
179
180 /*
181 * S_state
182 * A dictionary containing Information about each network
183 * interface. For now, the key is the BSD name and the
184 * value is a CFNumber noting how long (in milliseconds)
185 * it took for the interface to be recognized/named.
186 */
187 static CFMutableDictionaryRef S_state = NULL;
188
189 /*
190 * S_timer
191 * CFRunLoopTimer tracking how long we are willing to wait
192 * for IOKit matching to quiesce (IOKitWaitQuiet).
193 *
194 * S_stack_timeout
195 * time to wait for the IONetworkStack object to appear before timeout
196 *
197 * S_quiet_timeout
198 * time to wait for the IOKit to quiesce (after the IONetworkStack is
199 * has appeared.
200 */
201 static CFRunLoopTimerRef S_timer = NULL;
202 static double S_stack_timeout = WAIT_STACK_TIMEOUT_DEFAULT;
203 static double S_quiet_timeout = WAIT_QUIET_TIMEOUT_DEFAULT;
204
205 #if !TARGET_OS_EMBEDDED
206 /*
207 * S_vproc_transaction
208 * The vproc transaction used to keep launchd from sending us
209 * a SIGKILL before we've had a chance to set the platform UUID
210 */
211 vproc_transaction_t S_vproc_transaction = NULL;
212 #endif // !TARGET_OS_EMBEDDED
213
214 /*
215 * Virtual network interface configuration
216 * S_prefs : SCPreferences to configuration
217 * S_bonds : most recently actived Bond configuration
218 * S_bridges : most recently actived Bridge configuration
219 * S_vlans : most recently actived VLAN configuration
220 */
221 static SCPreferencesRef S_prefs = NULL;
222 static CFArrayRef S_bonds = NULL;
223 static CFArrayRef S_bridges = NULL;
224 static CFArrayRef S_vlans = NULL;
225
226 static void
227 addTimestamp(CFMutableDictionaryRef dict, CFStringRef key)
228 {
229 CFAbsoluteTime now;
230 CFNumberRef val;
231
232 now = CFAbsoluteTimeGetCurrent();
233 val = CFNumberCreate(NULL, kCFNumberDoubleType, &now);
234 CFDictionaryAddValue(dict, key, val);
235 CFRelease(val);
236 return;
237 }
238
239 #define INTERFACES CFSTR("Interfaces")
240 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
241
242 static CFComparisonResult
243 if_unit_compare(const void *val1, const void *val2, void *context)
244 {
245 CFComparisonResult res;
246 CFNumberRef type1;
247 CFNumberRef type2;
248 CFNumberRef unit1;
249 CFNumberRef unit2;
250
251 type1 = CFDictionaryGetValue((CFDictionaryRef)val1,
252 CFSTR(kIOInterfaceType));
253 type2 = CFDictionaryGetValue((CFDictionaryRef)val2,
254 CFSTR(kIOInterfaceType));
255 res = CFNumberCompare(type1, type2, NULL);
256 if (res != kCFCompareEqualTo) {
257 return (res);
258 }
259 unit1 = CFDictionaryGetValue((CFDictionaryRef)val1,
260 CFSTR(kIOInterfaceUnit));
261 unit2 = CFDictionaryGetValue((CFDictionaryRef)val2,
262 CFSTR(kIOInterfaceUnit));
263 return (CFNumberCompare(unit1, unit2, NULL));
264 }
265
266 static void
267 reportIssue(const char *signature, CFStringRef issue)
268 {
269 aslmsg m;
270
271 m = asl_new(ASL_TYPE_MSG);
272 asl_set(m, "com.apple.message.domain", "com.apple.SystemConfiguration." MY_PLUGIN_NAME);
273 asl_set(m, "com.apple.message.signature", signature);
274 asl_set(m, "com.apple.message.result", "failure");
275 SCLOG(NULL, m, ~ASL_LEVEL_ERR, CFSTR("%s\n%@"), signature, issue);
276 asl_free(m);
277
278 return;
279 }
280
281 static void
282 writeInterfaceList(CFArrayRef if_list)
283 {
284 CFArrayRef cur_list;
285 CFStringRef new_model;
286 CFStringRef old_model;
287 SCPreferencesRef prefs;
288
289 if (isA_CFArray(if_list) == NULL) {
290 return;
291 }
292
293 prefs = SCPreferencesCreate(NULL, MY_PLUGIN_ID, NETWORK_INTERFACES_PREFS);
294 if (prefs == NULL) {
295 SCLog(TRUE, LOG_ERR,
296 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate failed, %s"),
297 SCErrorString(SCError()));
298 return;
299 }
300
301 cur_list = SCPreferencesGetValue(prefs, INTERFACES);
302 if (_SC_CFEqual(cur_list, if_list)) {
303 goto done;
304 }
305
306 old_model = SCPreferencesGetValue(prefs, MODEL);
307 new_model = _SC_hw_model();
308 if ((new_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
309 // if new hardware
310 if ((old_model != NULL) && (cur_list != NULL)) {
311 CFStringRef history;
312 CFStringRef issue;
313
314 // if interface list was created on other hardware
315 history = CFStringCreateWithFormat(NULL, NULL,
316 CFSTR("%@:%@"),
317 INTERFACES,
318 old_model);
319 SCPreferencesSetValue(prefs, history, cur_list);
320 CFRelease(history);
321
322 SCLog(TRUE, LOG_ERR,
323 CFSTR(MY_PLUGIN_NAME ": Hardware model changed\n"
324 MY_PLUGIN_NAME ": created on \"%@\"\n"
325 MY_PLUGIN_NAME ": now on \"%@\""),
326 old_model,
327 new_model);
328
329 issue = CFStringCreateWithFormat(NULL, NULL,
330 CFSTR("%@ --> %@"),
331 old_model,
332 new_model);
333 reportIssue("Hardware model changed", issue);
334 CFRelease(issue);
335 }
336
337 if (!SCPreferencesSetValue(prefs, MODEL, new_model)) {
338 SCLog(TRUE, LOG_ERR,
339 CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetValue failed, %s"),
340 SCErrorString(SCError()));
341 goto done;
342 }
343 }
344
345 if (!SCPreferencesSetValue(prefs, INTERFACES, if_list)) {
346 SCLog(TRUE, LOG_ERR,
347 CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetValue failed, %s"),
348 SCErrorString(SCError()));
349 goto done;
350 }
351
352 if (!SCPreferencesCommitChanges(prefs)) {
353 SCLog((SCError() != EROFS), LOG_ERR,
354 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCommitChanges failed, %s"),
355 SCErrorString(SCError()));
356 goto done;
357 }
358
359 done:
360
361 CFRelease(prefs);
362 return;
363 }
364
365 static CF_RETURNS_RETAINED CFMutableArrayRef
366 readInterfaceList()
367 {
368 CFArrayRef if_list;
369 CFStringRef old_model;
370 CFMutableArrayRef plist = NULL;
371 SCPreferencesRef prefs = NULL;
372
373 prefs = SCPreferencesCreate(NULL, MY_PLUGIN_ID, NETWORK_INTERFACES_PREFS);
374 if (!prefs) {
375 SCLog(TRUE, LOG_ERR,
376 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate failed, %s"),
377 SCErrorString(SCError()));
378 return (NULL);
379 }
380
381 if_list = SCPreferencesGetValue(prefs, INTERFACES);
382 if_list = isA_CFArray(if_list);
383
384 old_model = SCPreferencesGetValue(prefs, MODEL);
385 if (old_model != NULL) {
386 CFStringRef new_model;
387
388 new_model = _SC_hw_model();
389 if (!_SC_CFEqual(old_model, new_model)) {
390 // if interface list was created on other hardware
391 if_list = NULL;
392 }
393 }
394
395 if (if_list != NULL) {
396 CFIndex i;
397 CFIndex n = CFArrayGetCount(if_list);
398
399 plist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
400 for (i = 0; i < n; i++) {
401 CFDictionaryRef dict;
402
403 dict = CFArrayGetValueAtIndex(if_list, i);
404 if (isA_CFDictionary(dict) &&
405 CFDictionaryContainsKey(dict, CFSTR(kIOInterfaceType)) &&
406 CFDictionaryContainsKey(dict, CFSTR(kIOInterfaceUnit)) &&
407 CFDictionaryContainsKey(dict, CFSTR(kIOMACAddress))) {
408 CFArrayAppendValue(plist, dict);
409 }
410 }
411 }
412
413 if (prefs != NULL) {
414 CFRelease(prefs);
415 }
416 return (plist);
417 }
418
419 static CF_RETURNS_RETAINED CFMutableArrayRef
420 previouslyActiveInterfaces()
421 {
422 CFMutableArrayRef active;
423 CFIndex i;
424 CFIndex n;
425
426 if (S_dblist == NULL) {
427 return NULL;
428 }
429
430 active = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
431
432 n = CFArrayGetCount(S_dblist);
433 for (i = 0; i < n; i++) {
434 CFDictionaryRef if_dict;
435
436 if_dict = CFArrayGetValueAtIndex(S_dblist, i);
437 if (CFDictionaryContainsKey(if_dict, CFSTR(kSCNetworkInterfaceActive))) {
438 CFMutableDictionaryRef new_dict;
439
440 new_dict = CFDictionaryCreateMutableCopy(NULL, 0, if_dict);
441 CFDictionaryRemoveValue(new_dict, CFSTR(kSCNetworkInterfaceActive));
442 CFArraySetValueAtIndex(S_dblist, i, new_dict);
443 CFArrayAppendValue(active, new_dict);
444 CFRelease(new_dict);
445 }
446 }
447
448 return active;
449 }
450
451 static void
452 updateStore(void)
453 {
454 CFStringRef key;
455
456 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" MY_PLUGIN_NAME),
457 kSCDynamicStoreDomainPlugin);
458 (void)SCDynamicStoreSetValue(NULL, key, S_state);
459 CFRelease(key);
460
461 return;
462 }
463
464 #if !TARGET_OS_IPHONE
465 static void
466 updateBondInterfaceConfiguration(SCPreferencesRef prefs)
467 {
468 CFArrayRef interfaces;
469
470 interfaces = SCBondInterfaceCopyAll(prefs);
471 if ((interfaces != NULL) && (CFArrayGetCount(interfaces) == 0)) {
472 CFRelease(interfaces);
473 interfaces = NULL;
474 }
475
476 if (_SC_CFEqual(S_bonds, interfaces)) {
477 // if no change
478 if (interfaces != NULL) CFRelease(interfaces);
479 return;
480 }
481
482 if (S_bonds != NULL) CFRelease(S_bonds);
483 S_bonds = interfaces;
484
485 if (!_SCBondInterfaceUpdateConfiguration(prefs)) {
486 SCLog(TRUE, LOG_ERR,
487 CFSTR(MY_PLUGIN_NAME ": _SCBondInterfaceUpdateConfiguration failed, %s"),
488 SCErrorString(SCError()));
489 }
490
491 return;
492 }
493 #endif // !TARGET_OS_IPHONE
494
495 static void
496 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs)
497 {
498 CFArrayRef interfaces;
499
500 interfaces = SCBridgeInterfaceCopyAll(prefs);
501 if ((interfaces != NULL) && (CFArrayGetCount(interfaces) == 0)) {
502 CFRelease(interfaces);
503 interfaces = NULL;
504 }
505
506 if (_SC_CFEqual(S_bridges, interfaces)) {
507 // if no change
508 if (interfaces != NULL) CFRelease(interfaces);
509 return;
510 }
511
512 if (S_bridges != NULL) CFRelease(S_bridges);
513 S_bridges = interfaces;
514
515 if (!_SCBridgeInterfaceUpdateConfiguration(prefs)) {
516 SCLog(TRUE, LOG_ERR,
517 CFSTR(MY_PLUGIN_NAME ": _SCBridgeInterfaceUpdateConfiguration failed, %s"),
518 SCErrorString(SCError()));
519 }
520
521 return;
522 }
523
524 static void
525 updateVLANInterfaceConfiguration(SCPreferencesRef prefs)
526 {
527 CFArrayRef interfaces;
528
529 interfaces = SCVLANInterfaceCopyAll(prefs);
530 if ((interfaces != NULL) && (CFArrayGetCount(interfaces) == 0)) {
531 CFRelease(interfaces);
532 interfaces = NULL;
533 }
534
535 if (_SC_CFEqual(S_vlans, interfaces)) {
536 // if no change
537 if (interfaces != NULL) CFRelease(interfaces);
538 return;
539 }
540
541 if (S_vlans != NULL) CFRelease(S_vlans);
542 S_vlans = interfaces;
543
544 if (!_SCVLANInterfaceUpdateConfiguration(prefs)) {
545 SCLog(TRUE, LOG_ERR,
546 CFSTR(MY_PLUGIN_NAME ": _SCVLANInterfaceUpdateConfiguration failed, %s"),
547 SCErrorString(SCError()));
548 }
549
550 return;
551 }
552
553 static void
554 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs,
555 SCPreferencesNotification notificationType,
556 void *info)
557 {
558 if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) {
559 return;
560 }
561
562 if (prefs == NULL) {
563 // if a new interface has been "named"
564 prefs = S_prefs;
565 if (S_bonds != NULL) {
566 CFRelease(S_bonds);
567 S_bonds = NULL;
568 }
569 if (S_bridges != NULL) {
570 CFRelease(S_bridges);
571 S_bridges = NULL;
572 }
573 if (S_vlans != NULL) {
574 CFRelease(S_vlans);
575 S_vlans = NULL;
576 }
577 }
578
579 #if !TARGET_OS_IPHONE
580 updateBondInterfaceConfiguration (prefs);
581 #endif // !TARGET_OS_IPHONE
582 updateBridgeInterfaceConfiguration(prefs);
583 updateVLANInterfaceConfiguration (prefs);
584
585 // we are finished with current prefs, wait for changes
586 SCPreferencesSynchronize(prefs);
587 return;
588 }
589
590 #if !TARGET_OS_EMBEDDED
591
592 #define BT_PAN_NAME "Bluetooth PAN"
593
594 static void
595 updateBTPANInformation(const void *value, void *context)
596 { CFDictionaryRef dict = (CFDictionaryRef)value;
597 CFStringRef if_name;
598 CFDictionaryRef info;
599 CFStringRef name;
600
601 if_name = CFDictionaryGetValue(dict, CFSTR(kIOBSDNameKey));
602 if (!isA_CFString(if_name)) {
603 // if no BSD name
604 return;
605 }
606
607 info = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceInfo));
608 if (!isA_CFDictionary(info)) {
609 // if no SCNetworkInterface info
610 return;
611 }
612
613 name = CFDictionaryGetValue(info, kSCPropUserDefinedName);
614 if (!isA_CFString(name) || !CFEqual(name, CFSTR(BT_PAN_NAME))) {
615 // if not BT-PAN interface
616 return;
617 }
618
619 CFDictionaryAddValue(S_state, CFSTR("_" BT_PAN_NAME "_"), if_name);
620 return;
621 }
622 #endif // !TARGET_OS_EMBEDDED
623
624 static CFDictionaryRef
625 createInterfaceDict(SCNetworkInterfaceRef interface)
626 {
627 CFMutableDictionaryRef new_if;
628 CFTypeRef val;
629
630 new_if = CFDictionaryCreateMutable(NULL,
631 0,
632 &kCFTypeDictionaryKeyCallBacks,
633 &kCFTypeDictionaryValueCallBacks);
634
635 val = _SCNetworkInterfaceCopyInterfaceInfo(interface);
636 if (val != NULL) {
637 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceInfo), val);
638 CFRelease(val);
639 }
640
641 val = _SCNetworkInterfaceGetIOPath(interface);
642 if (val != NULL) {
643 CFDictionarySetValue(new_if, CFSTR(kIOPathMatchKey), val);
644 }
645
646 val = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface);
647 if (val != NULL) {
648 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceNamePrefix), val);
649 }
650
651 val = _SCNetworkInterfaceGetIOInterfaceType(interface);
652 if (val != NULL) {
653 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceType), val);
654 }
655
656 val = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
657 if (val != NULL) {
658 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceUnit), val);
659 }
660
661 val = _SCNetworkInterfaceGetHardwareAddress(interface);
662 if (val != NULL) {
663 CFDictionarySetValue(new_if, CFSTR(kIOMACAddress), val);
664 }
665
666 val = SCNetworkInterfaceGetBSDName(interface);
667 if (val != NULL) {
668 CFDictionarySetValue(new_if, CFSTR(kIOBSDNameKey), val);
669 }
670
671 val = SCNetworkInterfaceGetInterfaceType(interface);
672 if (val != NULL) {
673 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceType), val);
674 }
675
676 CFDictionarySetValue(new_if,
677 CFSTR(kIOBuiltin),
678 _SCNetworkInterfaceIsBuiltin(interface) ? kCFBooleanTrue : kCFBooleanFalse);
679
680 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceActive), kCFBooleanTrue);
681
682 return new_if;
683 }
684
685 static CFDictionaryRef
686 lookupInterfaceByAddress(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where)
687 {
688 CFDataRef addr;
689 CFIndex i;
690 CFIndex n;
691 CFNumberRef type;
692
693 if (db_list == NULL) {
694 return (NULL);
695 }
696 type = _SCNetworkInterfaceGetIOInterfaceType(interface);
697 addr = _SCNetworkInterfaceGetHardwareAddress(interface);
698 if (type == NULL || addr == NULL) {
699 return (NULL);
700 }
701
702 n = CFArrayGetCount(db_list);
703 for (i = 0; i < n; i++) {
704 CFDataRef a;
705 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i);
706 CFNumberRef t;
707
708 t = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
709 a = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress));
710 if (t == NULL || a == NULL)
711 continue;
712
713 if (CFEqual(type, t) && CFEqual(addr, a)) {
714 if (where) {
715 *where = i;
716 }
717 return (dict);
718 }
719 }
720 return (NULL);
721 }
722
723 static CFDictionaryRef
724 lookupInterfaceByUnit(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where)
725 {
726 CFIndex i;
727 CFIndex n;
728 CFNumberRef type;
729 CFNumberRef unit;
730
731 if (db_list == NULL) {
732 return (NULL);
733 }
734 type = _SCNetworkInterfaceGetIOInterfaceType(interface);
735 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
736 if (type == NULL || unit == NULL) {
737 return (NULL);
738 }
739
740 n = CFArrayGetCount(db_list);
741 for (i = 0; i < n; i++) {
742 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i);
743 CFNumberRef t;
744 CFNumberRef u;
745
746 t = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
747 u = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
748 if (t == NULL || u == NULL) {
749 continue;
750 }
751
752 if (CFEqual(type, t) && CFEqual(unit, u)) {
753 if (where)
754 *where = i;
755 return (dict);
756 }
757 }
758 return (NULL);
759 }
760
761 typedef struct {
762 CFDictionaryRef match_info;
763 CFStringRef match_type;
764 CFBooleanRef match_builtin;
765 CFMutableArrayRef matches;
766 } matchContext, *matchContextRef;
767
768 static CF_RETURNS_RETAINED CFDictionaryRef
769 thinInterfaceInfo(CFDictionaryRef info)
770 {
771 CFNumberRef num;
772 int vid;
773
774 if (CFDictionaryGetValueIfPresent(info, CFSTR(kUSBVendorID), (const void **)&num)
775 && isA_CFNumber(num)
776 && CFNumberGetValue(num, kCFNumberIntType, &vid)
777 && (vid == kIOUSBVendorIDAppleComputer)) {
778 CFMutableDictionaryRef thin;
779
780 // if this is an Apple USB device than we trust that
781 // the non-localized name will be correct.
782 thin = CFDictionaryCreateMutableCopy(NULL, 0, info);
783 CFDictionaryRemoveValue(thin, CFSTR(kUSBProductString));
784 CFDictionaryRemoveValue(thin, CFSTR(kUSBVendorID));
785 CFDictionaryRemoveValue(thin, CFSTR(kUSBProductID));
786 return thin;
787 }
788
789 return CFRetain(info);
790 }
791
792 static Boolean
793 matchInterfaceInfo(CFDictionaryRef known_info, CFDictionaryRef match_info)
794 {
795 Boolean match;
796
797 match = _SC_CFEqual(known_info, match_info);
798 if (!match &&
799 isA_CFDictionary(known_info) &&
800 isA_CFDictionary(match_info)) {
801
802 // if not an exact match, try thinning
803 known_info = thinInterfaceInfo(known_info);
804 match_info = thinInterfaceInfo(match_info);
805 match = _SC_CFEqual(known_info, match_info);
806 if (known_info != NULL) CFRelease(known_info);
807 if (match_info != NULL) CFRelease(match_info);
808 }
809
810 return match;
811 }
812
813 static void
814 matchKnown(const void *value, void *context)
815 {
816 CFDictionaryRef known_dict = (CFDictionaryRef)value;
817 matchContextRef match_context = (matchContextRef)context;
818
819 // match interface type
820 {
821 CFStringRef known_type;
822
823 known_type = CFDictionaryGetValue(known_dict, CFSTR(kSCNetworkInterfaceType));
824 if (!_SC_CFEqual(known_type, match_context->match_type)) {
825 return;
826 }
827 }
828
829 // match SCNetworkInterfaceInfo
830 {
831 CFDictionaryRef known_info;
832
833 known_info = CFDictionaryGetValue(known_dict, CFSTR(kSCNetworkInterfaceInfo));
834 if (!matchInterfaceInfo(known_info, match_context->match_info)) {
835 return;
836 }
837 }
838
839 // if requested, match [non-]builtin
840 if (match_context->match_builtin != NULL) {
841 CFBooleanRef known_builtin;
842
843 known_builtin = CFDictionaryGetValue(known_dict, CFSTR(kIOBuiltin));
844 if (!isA_CFBoolean(known_builtin)) {
845 known_builtin = kCFBooleanFalse;
846 }
847 if (!_SC_CFEqual(known_builtin, match_context->match_builtin)) {
848 return;
849 }
850 }
851
852 // if we have a match
853 if (match_context->matches == NULL) {
854 match_context->matches = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
855 }
856 CFArrayAppendValue(match_context->matches, known_dict);
857
858 return;
859 }
860
861 static void
862 matchUnnamed(const void *value, void *context)
863 {
864 SCNetworkInterfaceRef known_if = (SCNetworkInterfaceRef)value;
865 matchContextRef match_context = (matchContextRef)context;
866
867 if (match_context->matches == NULL) {
868 return;
869 }
870
871 // match interface type
872 {
873 CFStringRef known_type;
874
875 known_type = SCNetworkInterfaceGetInterfaceType(known_if);
876 if (!_SC_CFEqual(known_type, match_context->match_type)) {
877 return;
878 }
879 }
880
881 // match SCNetworkInterfaceInfo
882 {
883 CFDictionaryRef known_info;
884 Boolean match;
885
886 known_info = _SCNetworkInterfaceCopyInterfaceInfo(known_if);
887 match = matchInterfaceInfo(known_info, match_context->match_info);
888 if (known_info != NULL) CFRelease(known_info);
889 if (!match) {
890 return;
891 }
892 }
893
894 // if requested, match [non-]builtin
895 if (match_context->match_builtin != NULL) {
896 CFBooleanRef known_builtin;
897
898 known_builtin = _SCNetworkInterfaceIsBuiltin(known_if) ? kCFBooleanTrue
899 : kCFBooleanFalse;
900 if (!_SC_CFEqual(known_builtin, match_context->match_builtin)) {
901 return;
902 }
903 }
904
905 // if we have a match
906 CFRelease(match_context->matches);
907 match_context->matches = NULL;
908
909 return;
910 }
911
912 static Boolean
913 interfaceExists(CFStringRef prefix, CFNumberRef unit)
914 {
915 Boolean found = FALSE;
916 CFDictionaryRef match_dict;
917 CFStringRef match_keys[2];
918 CFTypeRef match_vals[2];
919 CFDictionaryRef matching;
920
921
922
923 io_registry_entry_t entry = MACH_PORT_NULL;
924 io_iterator_t iterator = MACH_PORT_NULL;
925 kern_return_t kr;
926 mach_port_t masterPort = MACH_PORT_NULL;
927
928 kr = IOMasterPort(bootstrap_port, &masterPort);
929 if (kr != KERN_SUCCESS) {
930 SCLog(TRUE, LOG_ERR,
931 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"),
932 kr);
933 goto error;
934 }
935
936 // look for kIONetworkInterface with matching prefix and unit
937 match_keys[0] = CFSTR(kIOInterfaceNamePrefix);
938 match_vals[0] = prefix;
939 match_keys[1] = CFSTR(kIOInterfaceUnit);
940 match_vals[1] = unit;
941 match_dict = CFDictionaryCreate(NULL,
942 (const void **)match_keys,
943 (const void **)match_vals,
944 2,
945 &kCFTypeDictionaryKeyCallBacks,
946 &kCFTypeDictionaryValueCallBacks);
947
948 match_keys[0] = CFSTR(kIOProviderClassKey);
949 match_vals[0] = CFSTR(kIONetworkInterfaceClass);
950 match_keys[1] = CFSTR(kIOPropertyMatchKey);
951 match_vals[1] = match_dict;
952 matching = CFDictionaryCreate(NULL,
953 (const void **)match_keys,
954 (const void **)match_vals,
955 sizeof(match_keys)/sizeof(match_keys[0]),
956 &kCFTypeDictionaryKeyCallBacks,
957 &kCFTypeDictionaryValueCallBacks);
958 CFRelease(match_dict);
959
960 // note: the "matching" dictionary will be consumed by the following
961 kr = IOServiceGetMatchingServices(masterPort, matching, &iterator);
962 if ((kr != kIOReturnSuccess) || (iterator == MACH_PORT_NULL)) {
963 // if no interface
964 goto error;
965 }
966
967 entry = IOIteratorNext(iterator);
968 if (entry == MACH_PORT_NULL) {
969 // if no interface
970 goto error;
971 }
972
973 found = TRUE;
974
975 error:
976 if (masterPort != MACH_PORT_NULL) {
977 mach_port_deallocate(mach_task_self(), masterPort);
978 }
979 if (entry != MACH_PORT_NULL) {
980 IOObjectRelease(entry);
981 }
982 if (iterator != MACH_PORT_NULL) {
983 IOObjectRelease(iterator);
984 }
985
986 return (found);
987 }
988
989 /*
990 * lookupMatchingInterface
991 *
992 * Looks at the interfaces that have already been [or need to be] named with
993 * the goal of allowing a system using a single network interface/adaptor of
994 * a given type (vendor, model, ...) to not care about the specific adaptor
995 * that is used (i.e. swapping dongle's is OK). Once a system has had more
996 * than one interface/adaptor connected at the same time than we assume that
997 * the network configuration is being setup for multi-homing that should be
998 * maintained.
999 *
1000 * If no matches are found or if more than one match is found, return NULL.
1001 * If a single match is found, return the match.
1002 */
1003 static CFDictionaryRef
1004 lookupMatchingInterface(SCNetworkInterfaceRef interface,
1005 CFArrayRef db_list, // already named
1006 CFArrayRef if_list, // to be named
1007 CFIndex if_list_index,
1008 CFBooleanRef builtin)
1009 {
1010 CFStringRef if_type;
1011 CFDictionaryRef match = NULL;
1012 matchContext match_context;
1013
1014 if_type = SCNetworkInterfaceGetInterfaceType(interface);
1015 if (if_type == NULL) {
1016 return NULL;
1017 }
1018
1019 match_context.match_type = if_type;
1020 match_context.match_info = _SCNetworkInterfaceCopyInterfaceInfo(interface);
1021 match_context.match_builtin = builtin;
1022 match_context.matches = NULL;
1023
1024 // check for matches to interfaces that have already been named
1025 // ... and append each match that we find to match_context.matches
1026 if (db_list != NULL) {
1027 CFArrayApplyFunction(db_list,
1028 CFRangeMake(0, CFArrayGetCount(db_list)),
1029 matchKnown,
1030 &match_context);
1031 }
1032
1033 // check for matches to interfaces that will be named
1034 // ... and CFRelease match_context.matches if we find another network
1035 // interface of the same type that also needs to be named
1036 if (if_list != NULL) {
1037 CFIndex if_list_count;
1038
1039 if_list_count = CFArrayGetCount(if_list);
1040 if (if_list_index < if_list_count) {
1041 CFArrayApplyFunction(if_list,
1042 CFRangeMake(if_list_index, if_list_count - if_list_index),
1043 matchUnnamed,
1044 &match_context);
1045 }
1046 }
1047
1048 // check if we have a single match
1049 if (match_context.matches != NULL) {
1050 if (CFArrayGetCount(match_context.matches) == 1) {
1051 match = CFArrayGetValueAtIndex(match_context.matches, 0);
1052 }
1053 CFRelease(match_context.matches);
1054 }
1055
1056 if (match != NULL) {
1057 Boolean active = TRUE;
1058 CFStringRef name;
1059
1060 name = CFDictionaryGetValue(match, CFSTR(kIOBSDNameKey));
1061 if (isA_CFString(name)) {
1062 CFStringRef prefix;
1063 CFNumberRef unit;
1064
1065 prefix = CFDictionaryGetValue(match, CFSTR(kIOInterfaceNamePrefix));
1066 unit = CFDictionaryGetValue(match, CFSTR(kIOInterfaceUnit));
1067 if (isA_CFString(prefix) && isA_CFNumber(unit)) {
1068 if (!interfaceExists(prefix, unit)) {
1069 active = FALSE;
1070 }
1071 }
1072 }
1073
1074 if (active) {
1075 match = NULL;
1076 }
1077 }
1078
1079 if (match_context.match_info != NULL) CFRelease(match_context.match_info);
1080 return match;
1081 }
1082
1083 static void
1084 insertInterface(CFMutableArrayRef db_list, SCNetworkInterfaceRef interface)
1085 {
1086 CFIndex i;
1087 CFDictionaryRef if_dict;
1088 CFStringRef if_name;
1089 CFNumberRef if_type;
1090 CFNumberRef if_unit;
1091 CFIndex n = CFArrayGetCount(db_list);
1092 CFComparisonResult res;
1093
1094 if_name = SCNetworkInterfaceGetBSDName(interface);
1095 if (if_name != NULL) {
1096 addTimestamp(S_state, if_name);
1097 }
1098
1099 if_dict = createInterfaceDict(interface);
1100 if_type = _SCNetworkInterfaceGetIOInterfaceType(interface);
1101 if_unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
1102 if ((if_type == NULL) || (if_unit == NULL)) {
1103 CFRelease(if_dict);
1104 return;
1105 }
1106
1107 for (i = 0; i < n; i++) {
1108 CFNumberRef db_type;
1109 CFNumberRef db_unit;
1110 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i);
1111
1112 db_type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
1113 db_unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
1114 res = CFNumberCompare(if_type, db_type, NULL);
1115 if (res == kCFCompareLessThan
1116 || (res == kCFCompareEqualTo
1117 && (CFNumberCompare(if_unit, db_unit, NULL)
1118 == kCFCompareLessThan))) {
1119 CFArrayInsertValueAtIndex(db_list, i, if_dict);
1120 CFRelease(if_dict);
1121 return;
1122 }
1123 }
1124
1125 CFArrayAppendValue(S_dblist, if_dict);
1126
1127 #if !TARGET_OS_EMBEDDED
1128 updateBTPANInformation(if_dict, NULL);
1129 #endif // !TARGET_OS_EMBEDDED
1130
1131 CFRelease(if_dict);
1132 return;
1133 }
1134
1135 static void
1136 replaceInterface(SCNetworkInterfaceRef interface)
1137 {
1138 int n = 0;
1139 CFIndex where;
1140
1141 if (S_dblist == NULL) {
1142 S_dblist = CFArrayCreateMutable(NULL, 0,
1143 &kCFTypeArrayCallBacks);
1144 }
1145 // remove any dict that has our type/addr
1146 while (lookupInterfaceByAddress(S_dblist, interface, &where) != NULL) {
1147 CFArrayRemoveValueAtIndex(S_dblist, where);
1148 n++;
1149 }
1150 // remove any dict that has the same type/unit
1151 while (lookupInterfaceByUnit(S_dblist, interface, &where) != NULL) {
1152 CFArrayRemoveValueAtIndex(S_dblist, where);
1153 n++;
1154 }
1155 insertInterface(S_dblist, interface);
1156
1157 if (n > 1) {
1158 CFStringRef issue;
1159
1160 issue = CFStringCreateWithFormat(NULL, NULL,
1161 CFSTR("n = %d, %@"),
1162 n,
1163 interface);
1164 reportIssue("Multiple interfaces updated", issue);
1165 CFRelease(issue);
1166 }
1167
1168 return;
1169 }
1170
1171 static CFNumberRef
1172 getHighestUnitForType(CFNumberRef if_type)
1173 {
1174 int i;
1175 CFIndex n;
1176 CFNumberRef ret_unit = NULL;
1177
1178 if (S_dblist == NULL) {
1179 return (NULL);
1180 }
1181
1182 n = CFArrayGetCount(S_dblist);
1183 for (i = 0; i < n; i++) {
1184 CFDictionaryRef dict = CFArrayGetValueAtIndex(S_dblist, i);
1185 CFNumberRef type;
1186
1187 type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
1188 if (CFEqual(type, if_type)) {
1189 CFNumberRef unit;
1190
1191 unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
1192 if (ret_unit == NULL
1193 || (CFNumberCompare(unit, ret_unit, NULL)
1194 == kCFCompareGreaterThan)) {
1195 ret_unit = unit;
1196 }
1197 }
1198 }
1199
1200 return (ret_unit);
1201 }
1202
1203 /*
1204 * Function: ensureInterfaceHasUnit
1205 * Purpose:
1206 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1207 * release the interface and return NULL.
1208 */
1209 static SCNetworkInterfaceRef
1210 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if)
1211 {
1212 if (net_if != NULL
1213 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if) == NULL) {
1214 CFRelease(net_if);
1215 net_if = NULL;
1216 }
1217 return (net_if);
1218 }
1219
1220 #ifdef USE_REGISTRY_ENTRY_ID
1221 static kern_return_t
1222 registerInterfaceWithIORegistryEntryID(io_connect_t connect,
1223 uint64_t entryID,
1224 CFNumberRef unit,
1225 const int command)
1226 {
1227 CFDataRef data;
1228 CFMutableDictionaryRef dict;
1229 kern_return_t kr;
1230 CFNumberRef num;
1231
1232 dict = CFDictionaryCreateMutable(NULL, 0,
1233 &kCFTypeDictionaryKeyCallBacks,
1234 &kCFTypeDictionaryValueCallBacks);
1235 num = CFNumberCreate(NULL, kCFNumberIntType, &command);
1236 CFDictionarySetValue(dict, CFSTR(kIONetworkStackUserCommandKey), num);
1237 CFRelease(num);
1238 data = CFDataCreate(NULL, (void *) &entryID, sizeof(entryID));
1239 CFDictionarySetValue(dict, CFSTR(kIORegistryEntryIDKey), data);
1240 CFRelease(data);
1241 CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit);
1242 kr = IOConnectSetCFProperties(connect, dict);
1243 CFRelease(dict);
1244 return kr;
1245 }
1246
1247 static SCNetworkInterfaceRef
1248 copyInterfaceForIORegistryEntryID(uint64_t entryID)
1249 {
1250 io_registry_entry_t entry = MACH_PORT_NULL;
1251 SCNetworkInterfaceRef interface = NULL;
1252 io_iterator_t iterator = MACH_PORT_NULL;
1253 kern_return_t kr;
1254 mach_port_t masterPort = MACH_PORT_NULL;
1255
1256 kr = IOMasterPort(bootstrap_port, &masterPort);
1257 if (kr != KERN_SUCCESS) {
1258 SCLog(TRUE, LOG_ERR,
1259 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"),
1260 kr);
1261 goto error;
1262 }
1263
1264 kr = IOServiceGetMatchingServices(masterPort,
1265 IORegistryEntryIDMatching(entryID),
1266 &iterator);
1267 if ((kr != KERN_SUCCESS) || (iterator == MACH_PORT_NULL)) {
1268 SCLog(TRUE, LOG_ERR,
1269 CFSTR(MY_PLUGIN_NAME ": IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d"),
1270 entryID,
1271 kr,
1272 iterator);
1273 goto error;
1274 }
1275
1276 entry = IOIteratorNext(iterator);
1277 if (entry == MACH_PORT_NULL) {
1278 SCLog(TRUE, LOG_ERR,
1279 CFSTR(MY_PLUGIN_NAME ": IORegistryEntryIDMatching(0x%llx) failed"),
1280 entryID);
1281 goto error;
1282 }
1283
1284 interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry);
1285
1286 error:
1287 if (masterPort != MACH_PORT_NULL) {
1288 mach_port_deallocate(mach_task_self(), masterPort);
1289 }
1290 if (entry != MACH_PORT_NULL) {
1291 IOObjectRelease(entry);
1292 }
1293 if (iterator != MACH_PORT_NULL) {
1294 IOObjectRelease(iterator);
1295 }
1296 return (interface);
1297 }
1298
1299 static SCNetworkInterfaceRef
1300 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID)
1301 {
1302 SCNetworkInterfaceRef net_if;
1303
1304 net_if = copyInterfaceForIORegistryEntryID(entryID);
1305 return (ensureInterfaceHasUnit(net_if));
1306 }
1307
1308 #else // USE_REGISTRY_ENTRY_ID
1309 /*
1310 * Function: registerInterface
1311 * Purpose:
1312 * Register a single interface with the given service path to the
1313 * data link layer (BSD), using the specified unit number.
1314 */
1315 static kern_return_t
1316 registerInterfaceWithIOServicePath(io_connect_t connect,
1317 CFStringRef path,
1318 CFNumberRef unit,
1319 const int command)
1320 {
1321 CFMutableDictionaryRef dict;
1322 kern_return_t kr;
1323 CFNumberRef num;
1324
1325 dict = CFDictionaryCreateMutable(NULL, 0,
1326 &kCFTypeDictionaryKeyCallBacks,
1327 &kCFTypeDictionaryValueCallBacks);
1328 num = CFNumberCreate(NULL, kCFNumberIntType, &command);
1329 CFDictionarySetValue(dict, CFSTR(kIONetworkStackUserCommandKey), num);
1330 CFRelease(num);
1331 CFDictionarySetValue(dict, CFSTR(kIOPathMatchKey), path);
1332 CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit);
1333 kr = IOConnectSetCFProperties(connect, dict);
1334 CFRelease(dict);
1335 return kr;
1336 }
1337
1338 static SCNetworkInterfaceRef
1339 copyInterfaceForIOKitPath(CFStringRef if_path)
1340 {
1341 io_registry_entry_t entry = MACH_PORT_NULL;
1342 SCNetworkInterfaceRef interface = NULL;
1343 kern_return_t kr;
1344 mach_port_t masterPort = MACH_PORT_NULL;
1345 io_string_t path;
1346
1347 kr = IOMasterPort(bootstrap_port, &masterPort);
1348 if (kr != KERN_SUCCESS) {
1349 SCLog(TRUE, LOG_ERR,
1350 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"),
1351 kr);
1352 goto error;
1353 }
1354 _SC_cfstring_to_cstring(if_path, path, sizeof(path), kCFStringEncodingASCII);
1355 entry = IORegistryEntryFromPath(masterPort, path);
1356 if (entry == MACH_PORT_NULL) {
1357 SCLog(TRUE, LOG_ERR,
1358 CFSTR(MY_PLUGIN_NAME ": IORegistryEntryFromPath(%@) failed"),
1359 if_path);
1360 goto error;
1361 }
1362
1363 interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry);
1364
1365 error:
1366 if (masterPort != MACH_PORT_NULL) {
1367 mach_port_deallocate(mach_task_self(), masterPort);
1368 }
1369 if (entry != MACH_PORT_NULL) {
1370 IOObjectRelease(entry);
1371 }
1372 return (interface);
1373
1374 }
1375
1376 static SCNetworkInterfaceRef
1377 copyNamedInterfaceForIOKitPath(CFStringRef if_path)
1378 {
1379 SCNetworkInterfaceRef net_if;
1380
1381 net_if = copyInterfaceForIOKitPath(if_path);
1382 return (ensureInterfaceHasUnit(net_if));
1383 }
1384
1385 #endif // USE_REGISTRY_ENTRY_ID
1386
1387 static void
1388 displayInterface(SCNetworkInterfaceRef interface)
1389 {
1390 CFStringRef addr;
1391 CFStringRef name;
1392 CFNumberRef type;
1393 CFNumberRef unit;
1394
1395 name = SCNetworkInterfaceGetBSDName(interface);
1396 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
1397 type = _SCNetworkInterfaceGetIOInterfaceType(interface);
1398 addr = SCNetworkInterfaceGetHardwareAddressString(interface);
1399
1400 SCLog(TRUE, LOG_INFO,
1401 CFSTR(MY_PLUGIN_NAME ": %s%@%sType: %@, %s%@%sMAC address: %@"),
1402 (name != NULL) ? "BSD Name: " : "",
1403 (name != NULL) ? name : CFSTR(""),
1404 (name != NULL) ? ", " : "",
1405 type,
1406 (unit != NULL) ? "Unit: " : "",
1407 (unit != NULL) ? (CFTypeRef)unit : (CFTypeRef)CFSTR(""),
1408 (unit != NULL) ? ", " : "",
1409 addr);
1410 }
1411
1412 static Boolean
1413 builtinAvailable(SCNetworkInterfaceRef interface, // new interface
1414 CFNumberRef if_unit) // desired unit
1415 {
1416 CFIndex i;
1417 CFNumberRef if_type = _SCNetworkInterfaceGetIOInterfaceType(interface);
1418 CFIndex n;
1419
1420 n = (S_dblist != NULL) ? CFArrayGetCount(S_dblist) : 0;
1421 for (i = 0; i < n; i++) {
1422 CFStringRef if_path;
1423 CFDictionaryRef known_dict = CFArrayGetValueAtIndex(S_dblist, i);
1424 CFStringRef known_path;
1425 CFNumberRef known_type;
1426 CFNumberRef known_unit;
1427
1428 known_type = CFDictionaryGetValue(known_dict, CFSTR(kIOInterfaceType));
1429 if (!_SC_CFEqual(if_type, known_type)) {
1430 continue; // if not the same interface type
1431 }
1432
1433 known_unit = CFDictionaryGetValue(known_dict, CFSTR(kIOInterfaceUnit));
1434 if (!_SC_CFEqual(if_unit, known_unit)) {
1435 continue; // if not the same interface unit
1436 }
1437
1438 if_path = _SCNetworkInterfaceGetIOPath(interface);
1439 known_path = CFDictionaryGetValue(known_dict, CFSTR(kIOPathMatchKey));
1440 if (!_SC_CFEqual(if_path, known_path)) {
1441 // if different IORegistry path
1442 return FALSE;
1443 }
1444
1445 // if same type, same unit, same path
1446 return TRUE;
1447 }
1448
1449 // if interface type/unit not found
1450 return TRUE;
1451 }
1452
1453 static int
1454 builtinCount(CFArrayRef if_list, CFIndex last, CFNumberRef if_type)
1455 {
1456 CFIndex i;
1457 int n = 0;
1458
1459 for (i = 0; i < last; i++) {
1460 SCNetworkInterfaceRef builtin_if;
1461 CFNumberRef builtin_type;
1462
1463 builtin_if = CFArrayGetValueAtIndex(if_list, i);
1464 builtin_type = _SCNetworkInterfaceGetIOInterfaceType(builtin_if);
1465 if (CFEqual(if_type, builtin_type)) {
1466 if (_SCNetworkInterfaceIsBuiltin(builtin_if)) {
1467 n++; // if built-in interface
1468 }
1469 }
1470 }
1471
1472 return n;
1473 }
1474
1475 static __inline__ boolean_t
1476 isQuiet(void)
1477 {
1478 return (S_quiet == MACH_PORT_NULL);
1479 }
1480
1481 static void
1482 nameInterfaces(CFMutableArrayRef if_list)
1483 {
1484 CFIndex i;
1485 CFIndex n = CFArrayGetCount(if_list);
1486
1487 for (i = 0; i < n; i++) {
1488 uint64_t entryID;
1489 SCNetworkInterfaceRef interface;
1490 SCNetworkInterfaceRef new_interface;
1491 CFStringRef path;
1492 CFStringRef str;
1493 CFNumberRef type;
1494 CFNumberRef unit;
1495 CFIndex where;
1496
1497 interface = CFArrayGetValueAtIndex(if_list, i);
1498 path = _SCNetworkInterfaceGetIOPath(interface);
1499 type = _SCNetworkInterfaceGetIOInterfaceType(interface);
1500 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
1501 entryID = _SCNetworkInterfaceGetIORegistryEntryID(interface);
1502
1503 if (unit != NULL) {
1504 if (S_debug) {
1505 CFStringRef if_name;
1506
1507 if_name = SCNetworkInterfaceGetBSDName(interface);
1508 if ((if_name == NULL) || !CFDictionaryContainsKey(S_state, if_name)) {
1509 SCLog(TRUE, LOG_INFO,
1510 CFSTR(MY_PLUGIN_NAME ": Interface already has a unit number"));
1511 displayInterface(interface);
1512 }
1513 }
1514
1515 // update the list of interfaces that were previously named
1516 if ((S_prev_active_list != NULL)
1517 && lookupInterfaceByAddress(S_prev_active_list, interface, &where) != NULL) {
1518 CFArrayRemoveValueAtIndex(S_prev_active_list, where);
1519 }
1520
1521 replaceInterface(interface);
1522 } else {
1523 CFDictionaryRef dbdict;
1524 boolean_t is_builtin;
1525 kern_return_t kr;
1526 int retries = 0;
1527
1528 dbdict = lookupInterfaceByAddress(S_dblist, interface, NULL);
1529 if (dbdict != NULL) {
1530 unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit));
1531 CFRetain(unit);
1532
1533 SCLog(S_debug, LOG_INFO,
1534 CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (from database)"),
1535 unit);
1536 }
1537
1538 if ((dbdict == NULL) && !isQuiet()) {
1539 // if new interface, wait until quiet before naming
1540 addTimestamp(S_state, path);
1541 continue;
1542 }
1543
1544 is_builtin = _SCNetworkInterfaceIsBuiltin(interface);
1545
1546 if (dbdict == NULL) {
1547 dbdict = lookupMatchingInterface(interface,
1548 S_dblist,
1549 if_list,
1550 i + 1,
1551 is_builtin ? kCFBooleanTrue : kCFBooleanFalse);
1552 if (dbdict != NULL) {
1553 unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit));
1554 CFRetain(unit);
1555
1556 SCLog(S_debug, LOG_INFO,
1557 CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (updating database)"),
1558 unit);
1559 }
1560 }
1561
1562 if ((dbdict != NULL) && (S_prev_active_list != NULL)) {
1563 // update the list of interfaces that were previously named
1564 where = CFArrayGetFirstIndexOfValue(S_prev_active_list,
1565 CFRangeMake(0, CFArrayGetCount(S_prev_active_list)),
1566 dbdict);
1567 if (where != kCFNotFound) {
1568 CFArrayRemoveValueAtIndex(S_prev_active_list, where);
1569 }
1570 }
1571
1572 if (dbdict == NULL) {
1573 int next_unit = 0;
1574
1575 if (is_builtin) {
1576 // built-in interface, try to use the reserved slots
1577 next_unit = builtinCount(if_list, i, type);
1578
1579 // But, before claiming a reserved slot we check to see if the
1580 // slot had previously been used. If so, and if the slot had been
1581 // assigned to the same type of interface, then we will perform a
1582 // replacement (e.g. assume that this was a board swap). But, if
1583 // the new interface is a different type then we assume that the
1584 // built-in configuration has changed and allocate a new unit from
1585 // the non-reserved slots.
1586
1587 unit = CFNumberCreate(NULL, kCFNumberIntType, &next_unit);
1588 if (!builtinAvailable(interface, unit)) {
1589 // if [built-in] unit not available
1590 SCLog(S_debug, LOG_INFO,
1591 CFSTR(MY_PLUGIN_NAME ": Interface not assigned [built-in] unit %@"),
1592 unit);
1593 CFRelease(unit);
1594 unit = NULL;
1595 }
1596 }
1597
1598 if (unit == NULL) {
1599 // not built-in (or built-in unit not available), allocate from
1600 // the non-reserved slots
1601 next_unit = builtinCount(if_list, n, type);
1602
1603 unit = getHighestUnitForType(type);
1604 if (unit != NULL) {
1605 int high_unit;
1606
1607 CFNumberGetValue(unit, kCFNumberIntType, &high_unit);
1608 if (high_unit >= next_unit) {
1609 next_unit = high_unit + 1;
1610 }
1611 }
1612
1613 unit = CFNumberCreate(NULL, kCFNumberIntType, &next_unit);
1614 }
1615
1616 SCLog(S_debug, LOG_INFO,
1617 CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (%s)"),
1618 unit,
1619 is_builtin ? "built-in" : "next available");
1620 }
1621
1622 retry :
1623
1624 #ifdef USE_REGISTRY_ENTRY_ID
1625 kr = registerInterfaceWithIORegistryEntryID(S_connect,
1626 entryID,
1627 unit,
1628 (dbdict == NULL) ? kIONetworkStackRegisterInterfaceWithLowestUnit
1629 : kIONetworkStackRegisterInterfaceWithUnit);
1630 new_interface = copyNamedInterfaceForIORegistryEntryID(entryID);
1631 #else // USE_REGISTRY_ENTRY_ID
1632 kr = registerInterfaceWithIOServicePath(S_connect,
1633 path,
1634 unit,
1635 (dbdict == NULL) ? kRegisterInterface
1636 : kRegisterInterfaceWithFixedUnit);
1637 new_interface = copyNamedInterfaceForIOKitPath(path);
1638 #endif // USE_REGISTRY_ENTRY_ID
1639 if (new_interface == NULL) {
1640 const char *signature;
1641
1642 signature = (dbdict == NULL) ? "failed to name new interface"
1643 : "failed to name known interface";
1644
1645 SCLog(TRUE, LOG_ERR,
1646 CFSTR(MY_PLUGIN_NAME ": %s, kr=0x%x\n"
1647 MY_PLUGIN_NAME ": path = %@\n"
1648 MY_PLUGIN_NAME ": id = 0x%llx\n"
1649 MY_PLUGIN_NAME ": unit = %@"),
1650 signature,
1651 kr,
1652 path,
1653 entryID,
1654 unit);
1655
1656 if (S_debug) {
1657 displayInterface(interface);
1658 }
1659
1660 // report issue w/MessageTracer
1661 str = CFStringCreateWithFormat(NULL, NULL,
1662 CFSTR("kr=0x%x, path=%@, unit=%@"),
1663 kr,
1664 path,
1665 unit);
1666 reportIssue(signature, str);
1667 CFRelease(str);
1668
1669 if ((dbdict != NULL) && (retries++ < 5)) {
1670 usleep(50 * 1000); // sleep 50ms between attempts
1671 goto retry;
1672 }
1673 }
1674 else {
1675 CFNumberRef new_unit;
1676
1677 if (retries > 0) {
1678 SCLog(TRUE, LOG_ERR,
1679 CFSTR(MY_PLUGIN_NAME ": %s interface named after %d %s\n"
1680 MY_PLUGIN_NAME ": path = %@\n"
1681 MY_PLUGIN_NAME ": unit = %@"),
1682 (dbdict == NULL) ? "New" : "Known",
1683 retries,
1684 (retries == 1) ? "try" : "tries",
1685 path,
1686 unit);
1687
1688 #ifdef SHOW_NAMING_FAILURE
1689 str = CFStringCreateWithFormat(NULL,
1690 NULL,
1691 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
1692 (dbdict == NULL) ? "New" : "Known",
1693 retries,
1694 (retries == 1) ? "try" : "tries",
1695 unit);
1696 CFUserNotificationDisplayNotice(0,
1697 kCFUserNotificationStopAlertLevel,
1698 NULL,
1699 NULL,
1700 NULL,
1701 str,
1702 CFSTR("Please report repeated failures."),
1703 NULL);
1704 CFRelease(str);
1705 #endif // SHOW_NAMING_FAILURE
1706 }
1707
1708 new_unit = _SCNetworkInterfaceGetIOInterfaceUnit(new_interface);
1709 if (CFEqual(unit, new_unit) == FALSE) {
1710 SCLog(S_debug, LOG_INFO,
1711 CFSTR(MY_PLUGIN_NAME
1712 ": interface type %@ assigned "
1713 "unit %@ instead of %@"),
1714 type, new_unit, unit);
1715 }
1716 if (S_debug) {
1717 displayInterface(new_interface);
1718 }
1719
1720 // update if_list (with the interface name & unit)
1721 CFArraySetValueAtIndex(if_list, i, new_interface);
1722 CFRelease(new_interface);
1723 interface = new_interface; // if_list holds the reference
1724
1725 if (is_builtin && (S_prev_active_list != NULL)) {
1726 CFIndex where;
1727
1728 // update the list of [built-in] interfaces that were previously named
1729 if (lookupInterfaceByUnit(S_prev_active_list, interface, &where) != NULL) {
1730 SCLog(S_debug, LOG_INFO,
1731 CFSTR(MY_PLUGIN_NAME ": and updated database (new address)"));
1732 CFArrayRemoveValueAtIndex(S_prev_active_list, where);
1733 }
1734 }
1735 replaceInterface(interface);
1736 }
1737 CFRelease(unit);
1738 }
1739 }
1740 return;
1741 }
1742
1743 #if !TARGET_OS_IPHONE
1744 static void
1745 updateNetworkConfiguration(CFArrayRef if_list)
1746 {
1747 Boolean do_commit = FALSE;
1748 CFIndex i;
1749 CFIndex n;
1750 SCPreferencesRef prefs = NULL;
1751 SCNetworkSetRef set = NULL;
1752
1753 prefs = SCPreferencesCreate(NULL, CFSTR("SCMonitor"), NULL);
1754
1755 set = SCNetworkSetCopyCurrent(prefs);
1756 if (set == NULL) {
1757 SCLog(TRUE, LOG_ERR, CFSTR(MY_PLUGIN_NAME ": No current set"));
1758 goto done;
1759 }
1760
1761 n = CFArrayGetCount(if_list);
1762 for (i = 0; i < n; i++) {
1763 SCNetworkInterfaceRef interface;
1764
1765 interface = CFArrayGetValueAtIndex(if_list, i);
1766 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set, interface)) {
1767 SCLog(TRUE, LOG_INFO,
1768 CFSTR(MY_PLUGIN_NAME ": adding default configuration for %s"),
1769 SCNetworkInterfaceGetBSDName(interface));
1770 do_commit = TRUE;
1771 }
1772 }
1773
1774 if (do_commit) {
1775 Boolean ok;
1776
1777 ok = SCPreferencesCommitChanges(prefs);
1778 if (!ok) {
1779 SCLog(TRUE, LOG_INFO,
1780 CFSTR(MY_PLUGIN_NAME ": updateNetworkConfiguration: SCPreferencesCommitChanges() failed: %s"),
1781 SCErrorString(SCError()));
1782 goto done;
1783 }
1784
1785 ok = SCPreferencesApplyChanges(prefs);
1786 if (!ok) {
1787 SCLog(TRUE, LOG_INFO,
1788 CFSTR(MY_PLUGIN_NAME ": updateNetworkConfiguration: SCPreferencesApplyChanges() failed: %s"),
1789 SCErrorString(SCError()));
1790 goto done;
1791 }
1792 }
1793
1794 done :
1795
1796 if (set != NULL) {
1797 CFRelease(set);
1798 set = NULL;
1799 }
1800
1801 if (prefs != NULL) {
1802 CFRelease(prefs);
1803 prefs = NULL;
1804 }
1805
1806 return;
1807 }
1808 #endif // !TARGET_OS_IPHONE
1809
1810 static void
1811 updateInterfaces()
1812 {
1813 if (S_connect == MACH_PORT_NULL) {
1814 // if we don't have the "IONetworkStack" connect object
1815 return;
1816 }
1817
1818 if (S_iflist != NULL) {
1819 CFIndex n;
1820
1821 n = CFArrayGetCount(S_iflist);
1822 if (n > 1) {
1823 CFArraySortValues(S_iflist, CFRangeMake(0, n), _SCNetworkInterfaceCompare, NULL);
1824 }
1825 nameInterfaces(S_iflist);
1826 }
1827
1828 if (isQuiet()) {
1829 /*
1830 * The registry [matching] has quiesced so let's
1831 * - save the DB with the interfaces that have been named
1832 * - update the VLAN/BOND configuration
1833 * - tell everyone that we've finished (at least for now)
1834 * - log those interfaces which are no longer present
1835 * in the HW config (or have yet to show up).
1836 */
1837 writeInterfaceList(S_dblist);
1838 updateVirtualNetworkInterfaceConfiguration(NULL, kSCPreferencesNotificationApply, NULL);
1839
1840 #if !TARGET_OS_IPHONE
1841 if (access("/usr/libexec/UserEventAgent", X_OK) == -1
1842 && errno == ENOENT) {
1843 /*
1844 * We are most likely booted into the Recovery OS with no "SCMonitor"
1845 * UserEventAgent plugin running so let's make sure we update the
1846 * network configuration for new interfaces.
1847 */
1848 updateNetworkConfiguration(S_iflist);
1849 }
1850 #endif // !TARGET_OS_IPHONE
1851
1852 updateStore();
1853
1854 if (S_iflist != NULL) {
1855 CFRelease(S_iflist);
1856 S_iflist = NULL;
1857 }
1858
1859 if (S_prev_active_list != NULL) {
1860 if (S_debug) {
1861 CFIndex i;
1862 CFIndex n;
1863
1864 n = CFArrayGetCount(S_prev_active_list);
1865 if (n > 0) {
1866 SCLog(TRUE, LOG_INFO,
1867 CFSTR(MY_PLUGIN_NAME ": Interface%s not [yet] active"),
1868 (n > 1) ? "s" : "");
1869 }
1870 for (i = 0; i < n; i++) {
1871 CFDictionaryRef if_dict;
1872 CFStringRef name;
1873 CFNumberRef type;
1874 CFNumberRef unit;
1875
1876 if_dict = CFArrayGetValueAtIndex(S_prev_active_list, i);
1877 name = CFDictionaryGetValue(if_dict, CFSTR(kIOBSDNameKey));
1878 type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType));
1879 unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit));
1880 SCLog(TRUE, LOG_INFO,
1881 CFSTR(MY_PLUGIN_NAME ": %s%@%sType: %@, Unit: %@"),
1882 (name != NULL) ? "BSD Name: " : "",
1883 (name != NULL) ? name : CFSTR(""),
1884 (name != NULL) ? ", " : "",
1885 type,
1886 unit);
1887 }
1888 }
1889 CFRelease(S_prev_active_list);
1890 S_prev_active_list = NULL;
1891 }
1892 } else {
1893 if ((S_prev_active_list != NULL) && (CFArrayGetCount(S_prev_active_list) == 0)) {
1894 /*
1895 * if we've named all of the interfaces that
1896 * were used during the previous boot.
1897 */
1898 addTimestamp(S_state, CFSTR("*RELEASE*"));
1899 SCLog(S_debug, LOG_INFO,
1900 CFSTR(MY_PLUGIN_NAME ": last boot interfaces have been named"));
1901 updateStore();
1902 CFRelease(S_prev_active_list);
1903 S_prev_active_list = NULL;
1904 }
1905 }
1906
1907 return;
1908 }
1909
1910 #if !TARGET_OS_EMBEDDED
1911 static CFComparisonResult
1912 compareMacAddress(const void *val1, const void *val2, void *context)
1913 {
1914 CFDataRef mac1 = (CFDataRef)val1;
1915 CFDataRef mac2 = (CFDataRef)val2;
1916 CFIndex n1;
1917 CFIndex n2;
1918 CFComparisonResult res;
1919
1920 n1 = CFDataGetLength(mac1);
1921 n2 = CFDataGetLength(mac2);
1922 if (n1 < n2) {
1923 res = kCFCompareLessThan;
1924 } else if (n2 > n1) {
1925 res = kCFCompareGreaterThan;
1926 } else {
1927 res = bcmp(CFDataGetBytePtr(mac1), CFDataGetBytePtr(mac2), n1);
1928 }
1929
1930 return res;
1931 }
1932
1933 static CFStringRef
1934 copyEthernetUUID()
1935 {
1936 CFDataRef addr;
1937 CFMutableArrayRef addrs = NULL;
1938 CFStringRef guid = NULL;
1939 CFIndex i;
1940 CFIndex n;
1941
1942 addrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1943 n = (S_dblist != NULL) ? CFArrayGetCount(S_dblist) : 0;
1944 for (i = 0; i < n; i++) {
1945 CFBooleanRef builtin;
1946 CFDictionaryRef dict;
1947 CFStringRef type;
1948
1949 dict = CFArrayGetValueAtIndex(S_dblist, i);
1950 type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType));
1951 if (!isA_CFString(type) || !CFEqual(type, kSCNetworkInterfaceTypeEthernet)) {
1952 continue;
1953 }
1954 builtin = CFDictionaryGetValue(dict, CFSTR(kIOBuiltin));
1955 if (!isA_CFBoolean(builtin) || !CFBooleanGetValue(builtin)) {
1956 continue;
1957 }
1958 addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress));
1959 if (!isA_CFData(addr) || (CFDataGetLength(addr) != ETHER_ADDR_LEN)) {
1960 continue;
1961 }
1962 CFArrayAppendValue(addrs, addr);
1963 }
1964
1965 if (CFArrayGetCount(addrs) == 0) {
1966 // if no ethernet interfaces, look for wireless
1967 for (i = 0; i < n; i++) {
1968 CFDictionaryRef dict;
1969 CFStringRef type;
1970
1971 dict = CFArrayGetValueAtIndex(S_dblist, i);
1972 type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType));
1973 if (!isA_CFString(type) || !CFEqual(type, kSCNetworkInterfaceTypeIEEE80211)) {
1974 continue;
1975 }
1976 addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress));
1977 if (!isA_CFData(addr) || (CFDataGetLength(addr) != ETHER_ADDR_LEN)) {
1978 continue;
1979 }
1980 CFArrayAppendValue(addrs, addr);
1981 }
1982 }
1983
1984 n = CFArrayGetCount(addrs);
1985 switch (n) {
1986 case 0 :
1987 // if no network interfaces
1988 break;
1989 default :
1990 // sort by MAC address
1991 CFArraySortValues(addrs, CFRangeMake(0, n), compareMacAddress, NULL);
1992
1993 // fall through
1994 case 1 : {
1995 CFUUIDBytes bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1996 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1997 CFUUIDRef uuid;
1998
1999 // set GUID
2000 addr = CFArrayGetValueAtIndex(addrs, 0);
2001 bcopy(CFDataGetBytePtr(addr),
2002 (void *)&bytes + sizeof(bytes) - ETHER_ADDR_LEN,
2003 ETHER_ADDR_LEN);
2004 uuid = CFUUIDCreateFromUUIDBytes(NULL, bytes);
2005 guid = CFUUIDCreateString(NULL, uuid);
2006 CFRelease(uuid);
2007
2008 SCLog(TRUE, LOG_INFO,
2009 CFSTR(MY_PLUGIN_NAME ": setting platform UUID [MAC] = %@"),
2010 guid);
2011 break;
2012 }
2013 }
2014
2015 if (addrs != NULL) CFRelease(addrs);
2016 return guid;
2017 }
2018
2019 #ifndef kIOPlatformUUIDKey
2020 #define kIOPlatformUUIDKey "IOPlatformUUID"
2021 #endif
2022 static void
2023 updatePlatformUUID()
2024 {
2025 CFStringRef guid = NULL;
2026 kern_return_t kr;
2027 io_registry_entry_t platform;
2028
2029 platform = IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreePlane ":/");
2030 if (platform == MACH_PORT_NULL) {
2031 goto done;
2032 }
2033
2034 guid = IORegistryEntryCreateCFProperty(platform, CFSTR(kIOPlatformUUIDKey), NULL, 0);
2035 if (guid != NULL) {
2036 // if GUID already defined
2037 goto done;
2038 }
2039
2040 guid = copyEthernetUUID();
2041 if (guid == NULL) {
2042 CFUUIDRef uuid;
2043
2044 uuid = CFUUIDCreate(NULL);
2045 guid = CFUUIDCreateString(NULL, uuid);
2046 CFRelease(uuid);
2047
2048 SCLog(TRUE, LOG_INFO,
2049 CFSTR(MY_PLUGIN_NAME ": setting platform UUID [random] = %@"),
2050 guid);
2051 }
2052
2053 if (getenv("DO_NOT_SET_PLATFORM_UUID") == NULL) {
2054 kr = IORegistryEntrySetCFProperty(platform, CFSTR(kIOPlatformUUIDKey), guid);
2055 if (kr != KERN_SUCCESS) {
2056 SCLog(TRUE, LOG_ERR,
2057 CFSTR(MY_PLUGIN_NAME ": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"),
2058 kr);
2059 }
2060 }
2061
2062 addTimestamp(S_state, CFSTR("*PLATFORM-UUID*"));
2063 updateStore();
2064
2065 done :
2066
2067 if (S_vproc_transaction != NULL) {
2068 vproc_transaction_end(NULL, S_vproc_transaction);
2069 S_vproc_transaction = NULL;
2070 }
2071
2072 if (platform != MACH_PORT_NULL) IOObjectRelease(platform);
2073 if (guid != NULL) CFRelease(guid);
2074 return;
2075 }
2076 #endif // !TARGET_OS_EMBEDDED
2077
2078 static void
2079 interfaceArrivalCallback(void *refcon, io_iterator_t iter)
2080 {
2081 io_object_t obj;
2082
2083 while ((obj = IOIteratorNext(iter)) != MACH_PORT_NULL) {
2084 SCNetworkInterfaceRef interface;
2085
2086 interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj);
2087 if (interface != NULL) {
2088 if (S_iflist == NULL) {
2089 S_iflist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2090 }
2091 CFArrayAppendValue(S_iflist, interface);
2092 CFRelease(interface);
2093 }
2094 IOObjectRelease(obj);
2095 }
2096
2097 updateInterfaces();
2098 return;
2099 }
2100
2101 /*
2102 * Function: stackCallback
2103 * Purpose:
2104 * Get a reference to the single IONetworkStack object instance in
2105 * the kernel. Naming requests must be sent to this object, which is
2106 * attached as a client to all network interface objects in the system.
2107 * Note:
2108 * Call IOObjectRelease on the returned object.
2109 */
2110 static void
2111 stackCallback(void *refcon, io_iterator_t iter)
2112 {
2113 kern_return_t kr;
2114 io_object_t stack;
2115
2116 stack = IOIteratorNext(iter);
2117 if (stack == MACH_PORT_NULL) {
2118 goto error;
2119 }
2120
2121 kr = IOServiceOpen(stack, mach_task_self(), 0, &S_connect);
2122 if (kr != KERN_SUCCESS) {
2123 SCLog(TRUE, LOG_ERR,
2124 CFSTR(MY_PLUGIN_NAME ": IOServiceOpen returned 0x%x"),
2125 kr);
2126 goto error;
2127 }
2128
2129 addTimestamp(S_state, CFSTR("*STACK*"));
2130 SCLog(S_debug, LOG_INFO,
2131 CFSTR(MY_PLUGIN_NAME ": IONetworkStack found"));
2132
2133 if (S_stack != MACH_PORT_NULL) {
2134 IOObjectRelease(S_stack);
2135 S_stack = MACH_PORT_NULL;
2136 }
2137
2138 if ((S_timer != NULL) && CFRunLoopTimerIsValid(S_timer)) {
2139 // With the IONetworkStack object now available we can
2140 // reset (shorten?) the time we are willing to wait for
2141 // IOKit to quiesce.
2142 CFRunLoopTimerSetNextFireDate(S_timer,
2143 CFAbsoluteTimeGetCurrent() + S_quiet_timeout);
2144 }
2145
2146 updateInterfaces();
2147
2148 error:
2149 if (stack != MACH_PORT_NULL) {
2150 IOObjectRelease(stack);
2151 }
2152
2153 return;
2154 }
2155
2156 static void
2157 quietCallback(void *refcon,
2158 io_service_t service,
2159 natural_t messageType,
2160 void *messageArgument)
2161 {
2162 if (messageArgument != NULL) {
2163 // if not yet quiet
2164 return;
2165 }
2166
2167 if (messageType == kIOMessageServiceBusyStateChange) {
2168 addTimestamp(S_state, CFSTR("*QUIET*"));
2169 SCLog(S_debug, LOG_INFO,
2170 CFSTR(MY_PLUGIN_NAME ": IOKit quiet"));
2171 }
2172
2173 if (S_connect == MACH_PORT_NULL) {
2174 SCLog(TRUE, LOG_ERR,
2175 CFSTR(MY_PLUGIN_NAME ": No network stack object"));
2176 return;
2177 }
2178
2179 if (S_quiet != MACH_PORT_NULL) {
2180 IOObjectRelease(S_quiet);
2181 S_quiet = MACH_PORT_NULL;
2182 }
2183
2184 if (S_timer != NULL) {
2185 CFRunLoopTimerInvalidate(S_timer);
2186 CFRelease(S_timer);
2187 S_timer = NULL;
2188 }
2189
2190 // grab (and name) any additional interfaces.
2191 interfaceArrivalCallback((void *)S_notify, S_iter);
2192
2193 #if !TARGET_OS_EMBEDDED
2194 updatePlatformUUID();
2195 #endif // !TARGET_OS_EMBEDDED
2196
2197 return;
2198 }
2199
2200 static void
2201 iterateRegistryBusy(io_iterator_t iterator, CFArrayRef nodes, CFMutableStringRef snapshot, int *count)
2202 {
2203 kern_return_t kr = kIOReturnSuccess;;
2204 io_object_t obj;
2205
2206 while ((kr == kIOReturnSuccess) &&
2207 ((obj = IOIteratorNext(iterator)) != MACH_PORT_NULL)) {
2208 uint64_t accumulated_busy_time;
2209 uint32_t busy_state;
2210 io_name_t location;
2211 io_name_t name;
2212 CFMutableArrayRef newNodes;
2213 uint64_t state;
2214 CFMutableStringRef str = NULL;
2215
2216 if (nodes == NULL) {
2217 newNodes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2218 } else {
2219 newNodes = CFArrayCreateMutableCopy(NULL, 0, nodes);
2220 }
2221 assert(newNodes != NULL);
2222
2223 kr = IORegistryEntryGetName(obj, name);
2224 if (kr != kIOReturnSuccess) {
2225 SCLog(TRUE, LOG_ERR,
2226 CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryEntryGetName returned 0x%x"),
2227 kr);
2228 goto next;
2229 }
2230
2231 str = CFStringCreateMutable(NULL, 0);
2232 CFStringAppendCString(str, name, kCFStringEncodingUTF8);
2233
2234 kr = IORegistryEntryGetLocationInPlane(obj, kIOServicePlane, location);
2235 switch (kr) {
2236 case kIOReturnSuccess :
2237 CFStringAppendCString(str, "@", kCFStringEncodingUTF8);
2238 CFStringAppendCString(str, location, kCFStringEncodingUTF8);
2239 break;
2240 case kIOReturnNotFound :
2241 break;
2242 default :
2243 SCLog(TRUE, LOG_ERR,
2244 CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryEntryGetLocationInPlane returned 0x%x"),
2245 kr);
2246 CFRelease(str);
2247 goto next;
2248 }
2249
2250 CFArrayAppendValue(newNodes, str);
2251 CFRelease(str);
2252
2253 kr = IOServiceGetBusyStateAndTime(obj, &state, &busy_state, &accumulated_busy_time);
2254 if (kr != kIOReturnSuccess) {
2255 SCLog(TRUE, LOG_ERR,
2256 CFSTR(MY_PLUGIN_NAME ": captureBusy IOServiceGetBusyStateAndTime returned 0x%x"),
2257 kr);
2258 goto next;
2259 }
2260
2261 #ifdef TEST_SNAPSHOT
2262 // report all nodes
2263 busy_state = 1;
2264 #endif // TEST_SNAPSHOT
2265
2266 if (busy_state != 0) {
2267 CFStringRef path;
2268
2269 if ((*count)++ == 0) {
2270 CFStringAppend(snapshot, CFSTR("Busy services :"));
2271 }
2272
2273 path = CFStringCreateByCombiningStrings(NULL, newNodes, CFSTR("/"));
2274 CFStringAppendFormat(snapshot, NULL,
2275 CFSTR("\n %@ [%s%s%s%d, %lld ms]"),
2276 path,
2277 (state & kIOServiceRegisteredState) ? "" : "!registered, ",
2278 (state & kIOServiceMatchedState) ? "" : "!matched, ",
2279 (state & kIOServiceInactiveState) ? "inactive, " : "",
2280 busy_state,
2281 accumulated_busy_time / kMillisecondScale);
2282 CFRelease(path);
2283 }
2284
2285 kr = IORegistryIteratorEnterEntry(iterator);
2286 if (kr != kIOReturnSuccess) {
2287 SCLog(TRUE, LOG_ERR,
2288 CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryIteratorEnterEntry returned 0x%x"),
2289 kr);
2290 goto next;
2291 }
2292
2293 iterateRegistryBusy(iterator, newNodes, snapshot, count);
2294
2295 kr = IORegistryIteratorExitEntry(iterator);
2296 if (kr != kIOReturnSuccess) {
2297 SCLog(TRUE, LOG_ERR,
2298 CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryIteratorExitEntry returned 0x%x"),
2299 kr);
2300 }
2301
2302 next :
2303
2304 CFRelease(newNodes);
2305 IOObjectRelease(obj);
2306 }
2307
2308 return;
2309 }
2310
2311 static CF_RETURNS_RETAINED CFStringRef
2312 captureBusy()
2313 {
2314 int count = 0;
2315 io_iterator_t iterator = MACH_PORT_NULL;
2316 kern_return_t kr;
2317 CFMutableStringRef snapshot;
2318
2319 snapshot = CFStringCreateMutable(NULL, 0);
2320
2321 kr = IORegistryCreateIterator(kIOMasterPortDefault,
2322 kIOServicePlane,
2323 0,
2324 &iterator);
2325 if (kr != kIOReturnSuccess) {
2326 SCLog(TRUE, LOG_ERR,
2327 CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryCreateIterator returned 0x%x"),
2328 kr);
2329 return snapshot;
2330 }
2331
2332 iterateRegistryBusy(iterator, NULL, snapshot, &count);
2333 if (count == 0) {
2334 CFStringAppend(snapshot, CFSTR("w/no busy services"));
2335 }
2336
2337 IOObjectRelease(iterator);
2338 return snapshot;
2339 }
2340
2341 static void
2342 timerCallback(CFRunLoopTimerRef timer, void *info)
2343 {
2344 CFStringRef snapshot;
2345
2346 // We've been waiting for IOKit to quiesce and it just
2347 // hasn't happenned. Time to just move on!
2348 addTimestamp(S_state, CFSTR("*TIMEOUT*"));
2349
2350 // log busy nodes
2351 snapshot = captureBusy();
2352 SCLog(TRUE, LOG_ERR,
2353 CFSTR(MY_PLUGIN_NAME ": timed out waiting for IOKit to quiesce\n%@"),
2354 snapshot);
2355 reportIssue("timed out waiting for IOKit to quiesce", snapshot);
2356 CFRelease(snapshot);
2357
2358 quietCallback((void *)S_notify, MACH_PORT_NULL, 0, NULL);
2359 return;
2360 }
2361
2362 static Boolean
2363 setup_IOKit(CFBundleRef bundle)
2364 {
2365 uint32_t busy;
2366 kern_return_t kr;
2367 mach_port_t masterPort = MACH_PORT_NULL;
2368 Boolean ok = FALSE;
2369 io_object_t root = MACH_PORT_NULL;
2370
2371 // read DB of previously named network interfaces
2372 S_dblist = readInterfaceList();
2373 if (S_dblist != NULL) {
2374 CFIndex n;
2375
2376 n = CFArrayGetCount(S_dblist);
2377 if (n > 1) {
2378 CFArraySortValues(S_dblist, CFRangeMake(0, n), if_unit_compare, NULL);
2379 }
2380 }
2381
2382 // get interfaces that were named during the last boot
2383 S_prev_active_list = previouslyActiveInterfaces();
2384
2385 // track how long we've waited to see each interface.
2386 S_state = CFDictionaryCreateMutable(NULL,
2387 0,
2388 &kCFTypeDictionaryKeyCallBacks,
2389 &kCFTypeDictionaryValueCallBacks);
2390 addTimestamp(S_state, CFSTR("*START*"));
2391
2392 // Creates and returns a notification object for receiving IOKit
2393 // notifications of new devices or state changes.
2394 kr = IOMasterPort(bootstrap_port, &masterPort);
2395 if (kr != KERN_SUCCESS) {
2396 SCLog(TRUE, LOG_ERR,
2397 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"),
2398 kr);
2399 goto done;
2400 }
2401
2402 S_notify = IONotificationPortCreate(masterPort);
2403 if (S_notify == NULL) {
2404 SCLog(TRUE, LOG_ERR,
2405 CFSTR(MY_PLUGIN_NAME ": IONotificationPortCreate failed"));
2406 goto done;
2407 }
2408
2409 // watch IOKit matching activity
2410 root = IORegistryEntryFromPath(masterPort, kIOServicePlane ":/");
2411 if (root == MACH_PORT_NULL) {
2412 SCLog(TRUE, LOG_ERR,
2413 CFSTR(MY_PLUGIN_NAME ": IORegistryEntryFromPath failed"));
2414 goto done;
2415 }
2416
2417 kr = IOServiceAddInterestNotification(S_notify,
2418 root,
2419 kIOBusyInterest,
2420 &quietCallback,
2421 (void *)S_notify, // refCon
2422 &S_quiet); // notification
2423 if (kr != KERN_SUCCESS) {
2424 SCLog(TRUE, LOG_ERR,
2425 CFSTR(MY_PLUGIN_NAME ": IOServiceAddInterestNotification returned 0x%x"),
2426 kr);
2427 goto done;
2428 }
2429
2430 kr = IOServiceGetBusyState(root, &busy);
2431 if (kr != KERN_SUCCESS) {
2432 SCLog(TRUE, LOG_ERR,
2433 CFSTR(MY_PLUGIN_NAME ": IOServiceGetBusyState returned 0x%x"),
2434 kr);
2435 goto done;
2436 }
2437
2438 // add a timer so we don't wait forever for IOKit to quiesce
2439 S_timer = CFRunLoopTimerCreate(NULL,
2440 CFAbsoluteTimeGetCurrent() + S_stack_timeout,
2441 0,
2442 0,
2443 0,
2444 timerCallback,
2445 NULL);
2446 if (S_timer == NULL) {
2447 SCLog(TRUE, LOG_ERR,
2448 CFSTR(MY_PLUGIN_NAME ": CFRunLoopTimerCreate failed"));
2449 goto done;
2450 }
2451
2452 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, kCFRunLoopDefaultMode);
2453
2454 // watch for the introduction of the IONetworkStack
2455 kr = IOServiceAddMatchingNotification(S_notify,
2456 kIOFirstMatchNotification,
2457 IOServiceMatching("IONetworkStack"),
2458 &stackCallback,
2459 (void *)S_notify, // refCon
2460 &S_stack); // notification
2461 if (kr != KERN_SUCCESS) {
2462 SCLog(TRUE, LOG_ERR,
2463 CFSTR(MY_PLUGIN_NAME ": IOServiceAddMatchingNotification returned 0x%x"),
2464 kr);
2465 goto done;
2466 }
2467
2468 // check and see if the stack is already available and arm the
2469 // notification for its introduction.
2470 stackCallback((void *)S_notify, S_stack);
2471
2472 // watch for the introduction of new network interfaces
2473 kr = IOServiceAddMatchingNotification(S_notify,
2474 kIOFirstMatchNotification,
2475 IOServiceMatching("IONetworkInterface"),
2476 &interfaceArrivalCallback,
2477 (void *)S_notify, // refCon
2478 &S_iter); // notification
2479 if (kr != KERN_SUCCESS) {
2480 SCLog(TRUE, LOG_ERR,
2481 CFSTR(MY_PLUGIN_NAME ": IOServiceAddMatchingNotification returned 0x%x"),
2482 kr);
2483 goto done;
2484 }
2485
2486 // Get the current list of matches and arm the notification for
2487 // future interface arrivals.
2488 interfaceArrivalCallback((void *)S_notify, S_iter);
2489
2490 // Check if IOKit has already quiesced.
2491 quietCallback((void *)S_notify,
2492 MACH_PORT_NULL,
2493 kIOMessageServiceBusyStateChange,
2494 (void *)(uintptr_t)busy);
2495
2496 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2497 IONotificationPortGetRunLoopSource(S_notify),
2498 kCFRunLoopDefaultMode);
2499
2500 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
2501 /*
2502 * Start the wheels turning until we've named all of
2503 * the interfaces that were used during the previous
2504 * boot, until IOKit [matching] has quiesced, or
2505 * until we've waited long enough.
2506 */
2507 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, MY_PLUGIN_ID);
2508 CFRunLoopAddSource(CFRunLoopGetCurrent(),
2509 IONotificationPortGetRunLoopSource(S_notify),
2510 MY_PLUGIN_ID);
2511 while (S_prev_active_list != NULL) {
2512 int rlStatus;
2513
2514 rlStatus = CFRunLoopRunInMode(MY_PLUGIN_ID, 1.0e10, TRUE);
2515 }
2516 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
2517
2518 #if !TARGET_OS_EMBEDDED
2519 if (S_dblist != NULL) {
2520 // apply special handling for the BT-PAN interface (if present)
2521 CFArrayApplyFunction(S_dblist,
2522 CFRangeMake(0, CFArrayGetCount(S_dblist)),
2523 updateBTPANInformation,
2524 NULL);
2525 }
2526 #endif // !TARGET_OS_EMBEDDED
2527
2528 ok = TRUE;
2529
2530 done:
2531 if (root != MACH_PORT_NULL) {
2532 IOObjectRelease(root);
2533 }
2534 if (masterPort != MACH_PORT_NULL) {
2535 mach_port_deallocate(mach_task_self(), masterPort);
2536 }
2537
2538 return ok;
2539 }
2540
2541 static Boolean
2542 setup_Virtual(CFBundleRef bundle)
2543 {
2544 // open a SCPreferences session
2545 S_prefs = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME), NULL);
2546 if (S_prefs == NULL) {
2547 SCLog(TRUE, LOG_ERR,
2548 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate() failed: %s"),
2549 SCErrorString(SCError()));
2550 return FALSE;
2551 }
2552
2553 // register for change notifications.
2554 if (!SCPreferencesSetCallback(S_prefs, updateVirtualNetworkInterfaceConfiguration, NULL)) {
2555 SCLog(TRUE, LOG_ERR,
2556 CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetCallBack() failed: %s"),
2557 SCErrorString(SCError()));
2558 CFRelease(S_prefs);
2559 return FALSE;
2560 }
2561
2562 // schedule
2563 if (!SCPreferencesScheduleWithRunLoop(S_prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
2564 if (SCError() != kSCStatusNoStoreServer) {
2565 SCLog(TRUE, LOG_ERR,
2566 CFSTR(MY_PLUGIN_NAME ": SCPreferencesScheduleWithRunLoop() failed: %s"),
2567 SCErrorString(SCError()));
2568 CFRelease(S_prefs);
2569 return FALSE;
2570 }
2571 }
2572
2573 return TRUE;
2574 }
2575
2576 static void *
2577 exec_InterfaceNamer(void *arg)
2578 {
2579 CFBundleRef bundle = (CFBundleRef)arg;
2580 CFDictionaryRef dict;
2581
2582 pthread_setname_np(MY_PLUGIN_NAME " thread");
2583
2584 dict = CFBundleGetInfoDictionary(bundle);
2585 if (isA_CFDictionary(dict)) {
2586 CFNumberRef num;
2587
2588 num = CFDictionaryGetValue(dict, CFSTR(WAIT_STACK_TIMEOUT_KEY));
2589 if (num != NULL) {
2590 if (!isA_CFNumber(num) ||
2591 !CFNumberGetValue(num, kCFNumberDoubleType, &S_stack_timeout) ||
2592 (S_stack_timeout <= 0.0)) {
2593 SCLog(TRUE, LOG_ERR,
2594 CFSTR(MY_PLUGIN_NAME ": " WAIT_STACK_TIMEOUT_KEY " value error"));
2595 S_stack_timeout = WAIT_STACK_TIMEOUT_DEFAULT;
2596 }
2597 }
2598
2599 num = CFDictionaryGetValue(dict, CFSTR(WAIT_QUIET_TIMEOUT_KEY));
2600 if (num != NULL) {
2601 if (!isA_CFNumber(num) ||
2602 !CFNumberGetValue(num, kCFNumberDoubleType, &S_quiet_timeout) ||
2603 (S_quiet_timeout <= 0.0)) {
2604 SCLog(TRUE, LOG_ERR,
2605 CFSTR(MY_PLUGIN_NAME ": " WAIT_QUIET_TIMEOUT_KEY " value error"));
2606 S_quiet_timeout = WAIT_QUIET_TIMEOUT_DEFAULT;
2607 }
2608 }
2609 }
2610
2611 // setup virtual network interface monitoring
2612 if (!setup_Virtual(bundle)) {
2613 goto error;
2614 }
2615
2616 // setup [IOKit] network interface monitoring
2617 if (!setup_IOKit(bundle)) {
2618 goto error;
2619 }
2620
2621 #if !TARGET_OS_EMBEDDED
2622 // keep launchd from SIGKILL'ing us until after the platform-uuid has
2623 // been updated
2624 S_vproc_transaction = vproc_transaction_begin(NULL);
2625 #endif // !TARGET_OS_EMBEDDED
2626
2627 goto done;
2628
2629 error :
2630 if (S_connect != MACH_PORT_NULL) {
2631 IOServiceClose(S_connect);
2632 S_connect = MACH_PORT_NULL;
2633 }
2634 if (S_dblist != NULL) {
2635 CFRelease(S_dblist);
2636 S_dblist = NULL;
2637 }
2638 if (S_iter != MACH_PORT_NULL) {
2639 IOObjectRelease(S_iter);
2640 S_iter = MACH_PORT_NULL;
2641 }
2642 if (S_notify != MACH_PORT_NULL) {
2643 IONotificationPortDestroy(S_notify);
2644 }
2645 if (S_quiet != MACH_PORT_NULL) {
2646 IOObjectRelease(S_quiet);
2647 S_quiet = MACH_PORT_NULL;
2648 }
2649 if (S_stack != MACH_PORT_NULL) {
2650 IOObjectRelease(S_stack);
2651 S_stack = MACH_PORT_NULL;
2652 }
2653 if (S_state != NULL) {
2654 CFRelease(S_state);
2655 S_state = NULL;
2656 }
2657 if (S_timer != NULL) {
2658 CFRunLoopTimerInvalidate(S_timer);
2659 CFRelease(S_timer);
2660 S_timer = NULL;
2661 }
2662
2663 done :
2664 CFRelease(bundle);
2665 CFRunLoopRun();
2666
2667 return NULL;
2668 }
2669
2670 __private_extern__
2671 void
2672 load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose)
2673 {
2674 pthread_attr_t tattr;
2675 pthread_t tid;
2676
2677 if (bundleVerbose) {
2678 S_debug = TRUE;
2679 }
2680
2681 CFRetain(bundle); // released in exec_InterfaceNamer
2682
2683 pthread_attr_init(&tattr);
2684 pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
2685 pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
2686 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
2687 pthread_create(&tid, &tattr, exec_InterfaceNamer, bundle);
2688 pthread_attr_destroy(&tattr);
2689
2690 return;
2691 }
2692
2693 //------------------------------------------------------------------------
2694 // Main function.
2695 #ifdef MAIN
2696 int
2697 main(int argc, char ** argv)
2698 {
2699 CFBundleRef bundle;
2700
2701 _sc_log = FALSE;
2702 _sc_verbose = (argc > 1) ? TRUE : FALSE;
2703
2704 S_debug = _sc_verbose;
2705
2706 bundle = CFBundleGetMainBundle();
2707 CFRetain(bundle); // released in exec_InterfaceNamer
2708
2709 (void)exec_InterfaceNamer();
2710
2711 /* not reached */
2712 exit(0);
2713 return 0;
2714 }
2715 #endif /* MAIN */
2716
2717 #ifdef TEST_PLATFORM_UUID
2718 int
2719 main(int argc, char ** argv)
2720 {
2721 CFStringRef guid;
2722 CFArrayRef interfaces;
2723
2724 _sc_log = FALSE;
2725 _sc_verbose = (argc > 1) ? TRUE : FALSE;
2726
2727 S_dblist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2728 interfaces = SCNetworkInterfaceCopyAll();
2729 if (interfaces != NULL) {
2730 CFIndex i;
2731 CFIndex n;
2732
2733 n = CFArrayGetCount(interfaces);
2734 for (i = 0; i < n; i++) {
2735 CFDictionaryRef dict;
2736 SCNetworkInterfaceRef interface;
2737
2738 interface = CFArrayGetValueAtIndex(interfaces, i);
2739 dict = createInterfaceDict(interface);
2740 CFArrayAppendValue(S_dblist, dict);
2741 CFRelease(dict);
2742 }
2743 CFRelease(interfaces);
2744 }
2745
2746 guid = copyEthernetUUID();
2747 SCPrint(TRUE, stdout, CFSTR("copyEthernetUUID() = %@\n"), (guid != NULL) ? guid : CFSTR("NULL"));
2748 if (guid != NULL) CFRelease(guid);
2749
2750 updatePlatformUUID();
2751 CFRelease(S_dblist);
2752 exit(0);
2753 return 0;
2754 }
2755 #endif /* TEST_PLATFORM_UUID */
2756
2757 #ifdef TEST_SNAPSHOT
2758 int
2759 main(int argc, char ** argv)
2760 {
2761 CFStringRef snapshot;
2762
2763 _sc_log = FALSE;
2764 _sc_verbose = (argc > 1) ? TRUE : FALSE;
2765
2766 snapshot = captureBusy();
2767 SCPrint(TRUE, stdout, CFSTR("%@\n"), snapshot);
2768 CFRelease(snapshot);
2769
2770 exit(0);
2771 return 0;
2772 }
2773 #endif /* TEST_SNAPSHOT */
2774