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