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