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