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