]> git.saurik.com Git - apple/configd.git/blob - Plugins/InterfaceNamer/ifnamer.c
configd-1109.40.9.tar.gz
[apple/configd.git] / Plugins / InterfaceNamer / ifnamer.c
1 /*
2 * Copyright (c) 2001-2020 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 InterfaceNamePrefix 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 InterfaceNamePrefix, MACAddress, and Unit in permanent storage
57 * to give persistent interface names
58 */
59
60 #include <TargetConditionals.h>
61 #include <ctype.h>
62 #include <stdlib.h>
63 #include <stdio.h>
64 #include <unistd.h>
65 #include <fcntl.h>
66 #if TARGET_OS_IPHONE
67 #include <lockdown.h>
68 #include <notify.h>
69 #endif // TARGET_OS_IPHONE
70 #include <sys/ioctl.h>
71 #include <sys/stat.h>
72 #include <sys/sysctl.h>
73 #include <sys/param.h>
74 #include <mach/mach.h>
75 #include <net/ethernet.h>
76 #include <net/if_types.h>
77 #include <pthread.h>
78
79 #include <CommonCrypto/CommonDigest.h>
80
81 #include <CoreFoundation/CoreFoundation.h>
82
83 #include <SystemConfiguration/SystemConfiguration.h>
84 #include <SystemConfiguration/SCDPlugin.h>
85 #include <SystemConfiguration/SCPrivate.h>
86 #include <SystemConfiguration/SCValidation.h>
87 #include "SCNetworkConfigurationInternal.h"
88 #include "SCPreferencesInternal.h"
89 #include "plugin_shared.h"
90 #if !TARGET_OS_IPHONE
91 #include "InterfaceNamerControlPrefs.h"
92 #endif // !TARGET_OS_IPHONE
93
94 #ifdef TEST_INTERFACE_ASSIGNMENT
95 #undef INTERFACES_DEFAULT_CONFIG
96 #define INTERFACES_DEFAULT_CONFIG CFSTR("/tmp/ifnamer-test-NetworkInterfaces.plist")
97 #endif // TEST_INTERFACE_ASSIGNMENT
98
99 #include <IOKit/IOKitLib.h>
100 #include <IOKit/IOKitLibPrivate.h>
101 #include <IOKit/IOKitKeysPrivate.h>
102 #include <IOKit/IOBSD.h>
103 #include <IOKit/IOMessage.h>
104 #include <IOKit/network/IONetworkController.h>
105 #include <IOKit/network/IONetworkInterface.h>
106 #include <IOKit/network/IONetworkStack.h>
107 #include <IOKit/usb/USB.h>
108
109 #ifdef kIONetworkStackUserCommandKey
110 #define USE_REGISTRY_ENTRY_ID
111 #endif
112
113 #ifndef USE_REGISTRY_ENTRY_ID
114 // from <IOKit/network/IONetworkStack.h>
115 #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand"
116 enum {
117 kRegisterInterfaceWithFixedUnit = 0,
118 kRegisterInterface,
119 kRegisterAllInterfaces
120 };
121 #endif // !USE_REGISTRY_ENTRY_ID
122
123 #define MY_PLUGIN_NAME "InterfaceNamer"
124 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
125
126 #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout"
127 #define WAIT_STACK_TIMEOUT_DEFAULT 300.0
128
129 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
130 #define WAIT_QUIET_TIMEOUT_DEFAULT 240.0
131
132 /*
133 * S_connect
134 * "IONetworkStack" connect object used to "name" an interface.
135 */
136 static io_connect_t S_connect = MACH_PORT_NULL;
137
138 /*
139 * S_dblist
140 * An array of CFDictionary's representing the interfaces
141 * that have been identified and [need to be] named.
142 */
143 static CFMutableArrayRef S_dblist = NULL;
144
145 /*
146 * S_iflist
147 * An array of SCNetworkInterface's representing the
148 * interfaces that have been identified.
149 */
150 static CFMutableArrayRef S_iflist = NULL;
151
152 /*
153 * S_iter
154 * IOServiceAddMatchingNotification object used to watch for
155 * new network interfaces.
156 */
157 static io_iterator_t S_iter = MACH_PORT_NULL;
158
159 #if !TARGET_OS_IPHONE
160 /*
161 * S_locked
162 * An array of CFData(WatchedInfo) objects representing those
163 * interfaces that have been connected to the system while
164 * locked.
165 */
166 static CFMutableArrayRef S_locked = NULL;
167 #endif // !TARGET_OS_IPHONE
168
169 /*
170 * S_notify
171 * notification object for receiving IOKit notifications of
172 * new devices or state changes.
173 */
174 static IONotificationPortRef S_notify = NULL;
175
176 /*
177 * S_preconfigured
178 * An array of CFData(WatchedInfo) objects representing those
179 * pre-configured interfaces that have been connected to the
180 * system.
181 */
182 static CFMutableArrayRef S_preconfigured = NULL;
183
184 /* S_prev_active_list
185 * An array of CFDictionary's representing the previously
186 * named interfaces.
187 */
188 static CFMutableArrayRef S_prev_active_list = NULL;
189
190 /*
191 * S_quiet
192 * IOServiceAddInterestNotification object used to watch for
193 * IOKit matching to quiesce.
194 */
195 static io_object_t S_quiet = MACH_PORT_NULL;
196
197 /*
198 * S_stack
199 * IOServiceAddMatchingNotification object used to watch for
200 * the availability of the "IONetworkStack" object.
201 */
202 static io_iterator_t S_stack = MACH_PORT_NULL;
203
204 /*
205 * S_state
206 * A dictionary containing Information about each network
207 * interface. For now, the key is the BSD name and the
208 * value is a CFNumber noting how long (in milliseconds)
209 * it took for the interface to be recognized/named.
210 */
211 static CFMutableDictionaryRef S_state = NULL;
212
213 #if TARGET_OS_IPHONE
214 /*
215 * S_trustedHostAttached
216 *
217 * Note: this global must only be updated on trustRequired_queue()
218 */
219 static Boolean S_trustedHostAttached = FALSE;
220
221 /*
222 *
223 * Note: this global must only be updated on trustRequired_queue()
224 */
225 static CFIndex S_trustedHostCount = 0;
226
227 /*
228 * S_trustRequired
229 * An array of CFData(WatchedInfo) objects representing those
230 * interfaces that require [lockdownd] trust.
231 */
232 static CFMutableArrayRef S_trustRequired = NULL;
233 #endif // TARGET_OS_IPHONE
234
235 /*
236 * S_timer
237 * CFRunLoopTimer tracking how long we are willing to wait
238 * for IOKit matching to quiesce (IOKitWaitQuiet).
239 *
240 * S_stack_timeout
241 * time to wait for the IONetworkStack object to appear before timeout
242 *
243 * S_quiet_timeout
244 * time to wait for the IOKit to quiesce (after the IONetworkStack is
245 * has appeared.
246 */
247 static CFRunLoopTimerRef S_timer = NULL;
248 static double S_stack_timeout = WAIT_STACK_TIMEOUT_DEFAULT;
249 static double S_quiet_timeout = WAIT_QUIET_TIMEOUT_DEFAULT;
250
251 /*
252 * Virtual network interface configuration
253 * S_prefs : SCPreferences to configuration
254 * S_bonds : most recently actived Bond configuration
255 * S_bridges : most recently actived Bridge configuration
256 * S_vlans : most recently actived VLAN configuration
257 */
258 static SCPreferencesRef S_prefs = NULL;
259 static CFArrayRef S_bonds = NULL;
260 static CFArrayRef S_bridges = NULL;
261 static CFArrayRef S_vlans = NULL;
262
263 /*
264 * Logging
265 */
266 __private_extern__
267 os_log_t
268 __log_InterfaceNamer(void)
269 {
270 static os_log_t log = NULL;
271
272 if (log == NULL) {
273 log = os_log_create("com.apple.SystemConfiguration", "InterfaceNamer");
274 }
275
276 return log;
277 }
278
279
280 static void
281 addTimestamp(CFMutableDictionaryRef dict, CFStringRef key)
282 {
283 CFAbsoluteTime now;
284 CFNumberRef val;
285
286 now = CFAbsoluteTimeGetCurrent();
287 val = CFNumberCreate(NULL, kCFNumberDoubleType, &now);
288 CFDictionaryAddValue(dict, key, val);
289 CFRelease(val);
290 return;
291 }
292
293 static CFComparisonResult
294 if_unit_compare(const void *val1, const void *val2, void *context)
295 {
296 #pragma unused(context)
297 CFStringRef prefix1;
298 CFStringRef prefix2;
299 CFComparisonResult res;
300 CFNumberRef unit1;
301 CFNumberRef unit2;
302
303 prefix1 = CFDictionaryGetValue((CFDictionaryRef)val1,
304 CFSTR(kIOInterfaceNamePrefix));
305 prefix2 = CFDictionaryGetValue((CFDictionaryRef)val2,
306 CFSTR(kIOInterfaceNamePrefix));
307 res = CFStringCompare(prefix1, prefix2, 0);
308 if (res != kCFCompareEqualTo) {
309 return (res);
310 }
311 unit1 = CFDictionaryGetValue((CFDictionaryRef)val1,
312 CFSTR(kIOInterfaceUnit));
313 unit2 = CFDictionaryGetValue((CFDictionaryRef)val2,
314 CFSTR(kIOInterfaceUnit));
315 return (CFNumberCompare(unit1, unit2, NULL));
316 }
317
318 static void
319 writeInterfaceListForModel(SCPreferencesRef prefs, CFStringRef old_model)
320 {
321 Boolean ok;
322 CFPropertyListRef plist;
323 SCPreferencesRef savedPrefs;
324 CFStringRef savedPrefsID;
325
326 savedPrefsID = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-%@"),
327 INTERFACES_DEFAULT_CONFIG,
328 old_model);
329 savedPrefs = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME ":writeInterfaceListForModel"), savedPrefsID);
330 CFRelease(savedPrefsID);
331 if (savedPrefs == NULL) {
332 SC_log(LOG_NOTICE, "SCPreferencesCreate(\"NetworkInterfaces-<model>.plist\") failed: %s", SCErrorString(SCError()));
333 return;
334 }
335
336 plist = SCPreferencesPathGetValue(prefs, CFSTR("/"));
337 ok = SCPreferencesPathSetValue(savedPrefs, CFSTR("/"), plist);
338 if (!ok) {
339 SC_log(LOG_NOTICE, "SCPreferencesPathSetValue() failed: %s", SCErrorString(SCError()));
340 }
341
342 ok = SCPreferencesCommitChanges(savedPrefs);
343 CFRelease(savedPrefs);
344 if (!ok) {
345 SC_log(LOG_NOTICE, "SCPreferencesCommitChanges(\"NetworkInterfaces-<model>.plist\") failed: %s", SCErrorString(SCError()));
346 }
347
348 return;
349 }
350
351 static void
352 writeInterfaceList(CFArrayRef if_list)
353 {
354 CFArrayRef cur_list;
355 CFStringRef new_model;
356 SCPreferencesRef ni_prefs;
357 CFStringRef old_model;
358
359 if (!isA_CFArray(if_list)) {
360 return;
361 }
362
363 ni_prefs = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME ":writeInterfaceList"), INTERFACES_DEFAULT_CONFIG);
364 if (ni_prefs == NULL) {
365 SC_log(LOG_NOTICE, "SCPreferencesCreate(\"NetworkInterfaces.plist\") failed: %s", SCErrorString(SCError()));
366 return;
367 }
368
369 cur_list = SCPreferencesGetValue(ni_prefs, INTERFACES);
370 if (_SC_CFEqual(cur_list, if_list)) {
371 goto done;
372 }
373
374 old_model = SCPreferencesGetValue(ni_prefs, MODEL);
375 new_model = _SC_hw_model(FALSE);
376 if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
377 // if new hardware
378 if ((old_model != NULL) && (cur_list != NULL)) {
379 SC_log(LOG_NOTICE, "Hardware model changed\n"
380 " created on \"%@\"\n"
381 " now on \"%@\"",
382 old_model,
383 new_model);
384
385 // save the interface list that was created on "other" hardware
386 writeInterfaceListForModel(ni_prefs, old_model);
387 }
388
389 SCPreferencesSetValue(ni_prefs, MODEL, new_model);
390 }
391
392 SCPreferencesSetValue(ni_prefs, INTERFACES, if_list);
393
394 if (cur_list == NULL) {
395 const int new_version = NETWORK_CONFIGURATION_VERSION;
396 CFNumberRef version;
397
398 version = CFNumberCreate(NULL, kCFNumberIntType, &new_version);
399 SCPreferencesSetValue(ni_prefs, kSCPrefVersion, version);
400 CFRelease(version);
401 }
402
403 if (!SCPreferencesCommitChanges(ni_prefs)) {
404 if (SCError() != EROFS) {
405 SC_log(LOG_NOTICE, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
406 }
407 goto done;
408 }
409
410 done:
411
412 CFRelease(ni_prefs);
413 return;
414 }
415
416 static CF_RETURNS_RETAINED CFMutableArrayRef
417 readInterfaceList()
418 {
419 CFMutableArrayRef db_list = NULL;
420 CFArrayRef if_list;
421 SCPreferencesRef ni_prefs;
422 CFStringRef old_model;
423
424 ni_prefs = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME ":readInterfaceList"), INTERFACES_DEFAULT_CONFIG);
425 if (ni_prefs == NULL) {
426 SC_log(LOG_NOTICE, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
427 return (NULL);
428 }
429
430 if_list = SCPreferencesGetValue(ni_prefs, INTERFACES);
431 if_list = isA_CFArray(if_list);
432
433 old_model = SCPreferencesGetValue(ni_prefs, MODEL);
434 if (old_model != NULL) {
435 CFStringRef new_model;
436
437 new_model = _SC_hw_model(FALSE);
438 if (!_SC_CFEqual(old_model, new_model)) {
439 /*
440 * If the interface list was created on other hardware then
441 * we start fresh.
442 */
443 if_list = NULL;
444 }
445 }
446
447 if (if_list != NULL) {
448 CFIndex n = CFArrayGetCount(if_list);
449
450 db_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
451 for (CFIndex i = 0; i < n; i++) {
452 CFDictionaryRef dict;
453
454 dict = CFArrayGetValueAtIndex(if_list, i);
455 if (isA_CFDictionary(dict) &&
456 CFDictionaryContainsKey(dict, CFSTR(kIOInterfaceNamePrefix)) &&
457 CFDictionaryContainsKey(dict, CFSTR(kIOInterfaceUnit)) &&
458 CFDictionaryContainsKey(dict, CFSTR(kIOMACAddress))) {
459 CFArrayAppendValue(db_list, dict);
460 }
461 }
462 }
463
464 if (db_list != NULL) {
465 CFIndex n = CFArrayGetCount(db_list);
466
467 if (n > 1) {
468 CFArraySortValues(db_list, CFRangeMake(0, n), if_unit_compare, NULL);
469 }
470 }
471
472 CFRelease(ni_prefs);
473 return (db_list);
474 }
475
476 static CF_RETURNS_RETAINED CFMutableArrayRef
477 previouslyActiveInterfaces()
478 {
479 CFMutableArrayRef active;
480 CFIndex n;
481
482 if (S_dblist == NULL) {
483 return NULL;
484 }
485
486 active = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
487
488 n = CFArrayGetCount(S_dblist);
489 for (CFIndex i = 0; i < n; i++) {
490 CFDictionaryRef if_dict;
491
492 if_dict = CFArrayGetValueAtIndex(S_dblist, i);
493 if (CFDictionaryContainsKey(if_dict, CFSTR(kSCNetworkInterfaceActive))) {
494 CFMutableDictionaryRef new_dict;
495
496 new_dict = CFDictionaryCreateMutableCopy(NULL, 0, if_dict);
497 CFDictionaryRemoveValue(new_dict, CFSTR(kSCNetworkInterfaceActive));
498 CFArraySetValueAtIndex(S_dblist, i, new_dict);
499 CFArrayAppendValue(active, new_dict);
500 CFRelease(new_dict);
501 }
502 }
503
504 return active;
505 }
506
507 static void
508 updateInterfaces(void);
509
510 static void
511 updateStore(void)
512 {
513 CFStringRef key;
514
515 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" MY_PLUGIN_NAME), kSCDynamicStoreDomainPlugin);
516 (void)SCDynamicStoreSetValue(NULL, key, S_state);
517 CFRelease(key);
518
519 return;
520 }
521
522 #if !TARGET_OS_IPHONE
523 static void
524 updateBondInterfaceConfiguration(SCPreferencesRef prefs)
525 {
526 CFArrayRef interfaces;
527
528 interfaces = SCBondInterfaceCopyAll(prefs);
529 if ((interfaces != NULL) && (CFArrayGetCount(interfaces) == 0)) {
530 CFRelease(interfaces);
531 interfaces = NULL;
532 }
533
534 if (_SC_CFEqual(S_bonds, interfaces)) {
535 // if no change
536 if (interfaces != NULL) CFRelease(interfaces);
537 return;
538 }
539
540 if (S_bonds != NULL) CFRelease(S_bonds);
541 S_bonds = interfaces;
542
543 if (!_SCBondInterfaceUpdateConfiguration(prefs)) {
544 SC_log(LOG_NOTICE, "_SCBondInterfaceUpdateConfiguration() failed: %s",
545 SCErrorString(SCError()));
546 }
547
548 return;
549 }
550 #endif // !TARGET_OS_IPHONE
551
552 static void
553 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs)
554 {
555 CFArrayRef interfaces;
556
557 interfaces = SCBridgeInterfaceCopyAll(prefs);
558 if ((interfaces != NULL) && (CFArrayGetCount(interfaces) == 0)) {
559 CFRelease(interfaces);
560 interfaces = NULL;
561 }
562
563 if (_SC_CFEqual(S_bridges, interfaces)) {
564 // if no change
565 if (interfaces != NULL) CFRelease(interfaces);
566 return;
567 }
568
569 if (S_bridges != NULL) CFRelease(S_bridges);
570 S_bridges = interfaces;
571
572 if (!_SCBridgeInterfaceUpdateConfiguration(prefs)) {
573 SC_log(LOG_NOTICE, "_SCBridgeInterfaceUpdateConfiguration() failed: %s",
574 SCErrorString(SCError()));
575 }
576
577 return;
578 }
579
580 static void
581 updateVLANInterfaceConfiguration(SCPreferencesRef prefs)
582 {
583 CFArrayRef interfaces;
584
585 interfaces = SCVLANInterfaceCopyAll(prefs);
586 if ((interfaces != NULL) && (CFArrayGetCount(interfaces) == 0)) {
587 CFRelease(interfaces);
588 interfaces = NULL;
589 }
590
591 if (_SC_CFEqual(S_vlans, interfaces)) {
592 // if no change
593 if (interfaces != NULL) CFRelease(interfaces);
594 return;
595 }
596
597 if (S_vlans != NULL) CFRelease(S_vlans);
598 S_vlans = interfaces;
599
600 if (!_SCVLANInterfaceUpdateConfiguration(prefs)) {
601 SC_log(LOG_NOTICE, "_SCVLANInterfaceUpdateConfiguration() failed: %s",
602 SCErrorString(SCError()));
603 }
604
605 return;
606 }
607
608 static void
609 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs,
610 SCPreferencesNotification notificationType,
611 void *info)
612 {
613 #pragma unused(info)
614 if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) {
615 return;
616 }
617
618 if (prefs == NULL) {
619 // if a new interface has been "named"
620 prefs = S_prefs;
621 if (S_bonds != NULL) {
622 CFRelease(S_bonds);
623 S_bonds = NULL;
624 }
625 if (S_bridges != NULL) {
626 CFRelease(S_bridges);
627 S_bridges = NULL;
628 }
629 if (S_vlans != NULL) {
630 CFRelease(S_vlans);
631 S_vlans = NULL;
632 }
633 }
634
635 #if !TARGET_OS_IPHONE
636 updateBondInterfaceConfiguration (prefs);
637 #endif // !TARGET_OS_IPHONE
638 updateBridgeInterfaceConfiguration(prefs);
639 updateVLANInterfaceConfiguration (prefs);
640
641 // we are finished with current prefs, wait for changes
642 SCPreferencesSynchronize(prefs);
643
644 return;
645 }
646
647 #if TARGET_OS_OSX
648
649 static void
650 updateBTPANInformation(const void *value, void *context)
651 {
652 #pragma unused(context)
653 CFDataRef addr;
654 CFDictionaryRef dict = (CFDictionaryRef)value;
655 CFStringRef if_name;
656 CFDictionaryRef info;
657 CFStringRef name;
658
659 if_name = CFDictionaryGetValue(dict, CFSTR(kIOBSDNameKey));
660 if (!isA_CFString(if_name)) {
661 // if no BSD name
662 return;
663 }
664
665 info = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceInfo));
666 if (!isA_CFDictionary(info)) {
667 // if no SCNetworkInterface info
668 return;
669 }
670
671 name = CFDictionaryGetValue(info, kSCPropUserDefinedName);
672 if (!isA_CFString(name) || !CFEqual(name, CFSTR(BT_PAN_NAME))) {
673 // if not BT-PAN interface
674 return;
675 }
676
677 CFDictionaryAddValue(S_state, kInterfaceNamerKey_BT_PAN_Name, if_name);
678
679 addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress));
680 if (isA_CFData(addr)) {
681 CFDictionaryAddValue(S_state, kInterfaceNamerKey_BT_PAN_Mac, addr);
682 }
683
684 return;
685 }
686 #endif // TARGET_OS_OSX
687
688 static CFDictionaryRef
689 createInterfaceDict(SCNetworkInterfaceRef interface, CFArrayRef matchingMACs)
690 {
691 CFMutableDictionaryRef new_if;
692 CFTypeRef val;
693
694 new_if = CFDictionaryCreateMutable(NULL,
695 0,
696 &kCFTypeDictionaryKeyCallBacks,
697 &kCFTypeDictionaryValueCallBacks);
698
699 val = _SCNetworkInterfaceCopyInterfaceInfo(interface);
700 if (val != NULL) {
701 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceInfo), val);
702 CFRelease(val);
703 }
704
705 val = _SCNetworkInterfaceGetIOPath(interface);
706 if (val != NULL) {
707 CFDictionarySetValue(new_if, CFSTR(kIOPathMatchKey), val);
708 }
709
710 val = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface);
711 if (val != NULL) {
712 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceNamePrefix), val);
713 }
714
715 val = _SCNetworkInterfaceGetIOInterfaceType(interface);
716 if (val != NULL) {
717 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceType), val);
718 }
719
720 val = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
721 if (val != NULL) {
722 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceUnit), val);
723 }
724
725 val = _SCNetworkInterfaceGetHardwareAddress(interface);
726 if (val != NULL) {
727 CFDictionarySetValue(new_if, CFSTR(kIOMACAddress), val);
728 }
729
730 val = SCNetworkInterfaceGetBSDName(interface);
731 if (val != NULL) {
732 CFDictionarySetValue(new_if, CFSTR(kIOBSDNameKey), val);
733 }
734
735 val = SCNetworkInterfaceGetInterfaceType(interface);
736 if (val != NULL) {
737 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceType), val);
738 }
739
740 CFDictionarySetValue(new_if,
741 CFSTR(kIOBuiltin),
742 _SCNetworkInterfaceIsBuiltin(interface) ? kCFBooleanTrue : kCFBooleanFalse);
743
744 if (_SCNetworkInterfaceIsHiddenConfiguration(interface)) {
745 CFDictionarySetValue(new_if, kSCNetworkInterfaceHiddenConfigurationKey, kCFBooleanTrue);
746 }
747
748 if (_SCNetworkInterfaceIsHiddenInterface(interface)) {
749 CFDictionarySetValue(new_if, kSCNetworkInterfaceHiddenInterfaceKey, kCFBooleanTrue);
750 }
751
752 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceActive), kCFBooleanTrue);
753
754 if (matchingMACs != NULL) {
755 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceMatchingMACs), matchingMACs);
756 }
757
758 return new_if;
759 }
760
761 static CFDictionaryRef
762 lookupInterfaceByAddress(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where)
763 {
764 CFDataRef addr;
765 CFIndex n;
766 CFStringRef prefix;
767
768 if (db_list == NULL) {
769 return (NULL);
770 }
771 prefix = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface);
772 addr = _SCNetworkInterfaceGetHardwareAddress(interface);
773 if (prefix == NULL || addr == NULL) {
774 return (NULL);
775 }
776
777 n = CFArrayGetCount(db_list);
778 for (CFIndex i = 0; i < n; i++) {
779 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i);
780 CFDataRef this_addr;
781 CFStringRef this_prefix;
782
783 this_prefix = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceNamePrefix));
784 this_addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress));
785 if (this_prefix == NULL || this_addr == NULL)
786 continue;
787
788 if (CFEqual(prefix, this_prefix) && CFEqual(addr, this_addr)) {
789 if (where != NULL) {
790 *where = i;
791 }
792 return (dict);
793 }
794 }
795 return (NULL);
796 }
797
798 static CFDictionaryRef
799 lookupInterfaceByName(CFArrayRef db_list, CFStringRef bsdName, CFIndex * where)
800 {
801 CFIndex n;
802
803 if (db_list == NULL) {
804 return (NULL);
805 }
806
807 n = CFArrayGetCount(db_list);
808 for (CFIndex i = 0; i < n; i++) {
809 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i);
810 CFStringRef name;
811
812 name = CFDictionaryGetValue(dict, CFSTR(kIOBSDNameKey));
813 if (_SC_CFEqual(name, bsdName)) {
814 if (where != NULL) {
815 *where = i;
816 }
817 return (dict);
818 }
819 }
820 return (NULL);
821 }
822
823 static CFDictionaryRef
824 lookupInterfaceByUnit(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where)
825 {
826 CFIndex n;
827 CFStringRef prefix;
828 CFNumberRef unit;
829
830 if (db_list == NULL) {
831 return (NULL);
832 }
833 prefix = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface);
834 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
835 if (prefix == NULL || unit == NULL) {
836 return (NULL);
837 }
838
839 n = CFArrayGetCount(db_list);
840 for (CFIndex i = 0; i < n; i++) {
841 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i);
842 CFStringRef this_prefix;
843 CFNumberRef this_unit;
844
845 this_prefix = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceNamePrefix));
846 this_unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
847 if (this_prefix == NULL || this_unit == NULL) {
848 continue;
849 }
850
851 if (CFEqual(prefix, this_prefix) && CFEqual(unit, this_unit)) {
852 if (where != NULL) {
853 *where = i;
854 }
855 return (dict);
856 }
857 }
858 return (NULL);
859 }
860
861 typedef struct {
862 CFDictionaryRef match_info;
863 CFStringRef match_type;
864 CFStringRef match_prefix;
865 CFBooleanRef match_builtin;
866 CFMutableArrayRef matches;
867 } matchContext, *matchContextRef;
868
869 static CF_RETURNS_RETAINED CFDictionaryRef
870 thinInterfaceInfo(CFDictionaryRef info)
871 {
872 CFNumberRef num;
873 int vid;
874
875 if (CFDictionaryGetValueIfPresent(info, CFSTR(kUSBVendorID), (const void **)&num)
876 && isA_CFNumber(num)
877 && CFNumberGetValue(num, kCFNumberIntType, &vid)
878 && (vid == kIOUSBAppleVendorID)) {
879 CFMutableDictionaryRef thin;
880
881 // if this is an Apple USB device than we trust that
882 // the non-localized name will be correct.
883 thin = CFDictionaryCreateMutableCopy(NULL, 0, info);
884 CFDictionaryRemoveValue(thin, CFSTR(kUSBProductString));
885 CFDictionaryRemoveValue(thin, CFSTR(kUSBVendorID));
886 CFDictionaryRemoveValue(thin, CFSTR(kUSBProductID));
887 return thin;
888 }
889
890 return CFRetain(info);
891 }
892
893 static Boolean
894 matchInterfaceInfo(CFDictionaryRef known_info, CFDictionaryRef match_info)
895 {
896 Boolean match;
897
898 match = _SC_CFEqual(known_info, match_info);
899 if (!match &&
900 isA_CFDictionary(known_info) &&
901 isA_CFDictionary(match_info)) {
902
903 // if not an exact match, try thinning
904 known_info = thinInterfaceInfo(known_info);
905 match_info = thinInterfaceInfo(match_info);
906 match = _SC_CFEqual(known_info, match_info);
907 if (known_info != NULL) CFRelease(known_info);
908 if (match_info != NULL) CFRelease(match_info);
909 }
910
911 return match;
912 }
913
914 static void
915 matchKnown(const void *value, void *context)
916 {
917 CFDictionaryRef known_dict = (CFDictionaryRef)value;
918 matchContextRef match_context = (matchContextRef)context;
919
920 // match prefix
921 {
922 CFStringRef known_prefix;
923
924 known_prefix
925 = CFDictionaryGetValue(known_dict,
926 CFSTR(kIOInterfaceNamePrefix));
927 if (!_SC_CFEqual(known_prefix, match_context->match_prefix)) {
928 return;
929 }
930 }
931
932 // match interface type
933 {
934 CFStringRef known_type;
935
936 known_type = CFDictionaryGetValue(known_dict, CFSTR(kSCNetworkInterfaceType));
937 if (!_SC_CFEqual(known_type, match_context->match_type)) {
938 return;
939 }
940 }
941
942 // match SCNetworkInterfaceInfo
943 {
944 CFDictionaryRef known_info;
945
946 known_info = CFDictionaryGetValue(known_dict, CFSTR(kSCNetworkInterfaceInfo));
947 if (!matchInterfaceInfo(known_info, match_context->match_info)) {
948 return;
949 }
950 }
951
952 // if requested, match [non-]builtin
953 if (match_context->match_builtin != NULL) {
954 CFBooleanRef known_builtin;
955
956 known_builtin = CFDictionaryGetValue(known_dict, CFSTR(kIOBuiltin));
957 if (!isA_CFBoolean(known_builtin)) {
958 known_builtin = kCFBooleanFalse;
959 }
960 if (!_SC_CFEqual(known_builtin, match_context->match_builtin)) {
961 return;
962 }
963 }
964
965 // if we have a match
966 if (match_context->matches == NULL) {
967 match_context->matches = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
968 }
969 CFArrayAppendValue(match_context->matches, known_dict);
970
971 return;
972 }
973
974 static void
975 matchUnnamed(const void *value, void *context)
976 {
977 SCNetworkInterfaceRef known_if = (SCNetworkInterfaceRef)value;
978 matchContextRef match_context = (matchContextRef)context;
979
980 if (match_context->matches == NULL) {
981 return;
982 }
983
984 // match interface type
985 {
986 CFStringRef known_type;
987
988 known_type = SCNetworkInterfaceGetInterfaceType(known_if);
989 if (!_SC_CFEqual(known_type, match_context->match_type)) {
990 return;
991 }
992 }
993
994 // match SCNetworkInterfaceInfo
995 {
996 CFDictionaryRef known_info;
997 Boolean match;
998
999 known_info = _SCNetworkInterfaceCopyInterfaceInfo(known_if);
1000 match = matchInterfaceInfo(known_info, match_context->match_info);
1001 if (known_info != NULL) CFRelease(known_info);
1002 if (!match) {
1003 return;
1004 }
1005 }
1006
1007 // if requested, match [non-]builtin
1008 if (match_context->match_builtin != NULL) {
1009 CFBooleanRef known_builtin;
1010
1011 known_builtin = _SCNetworkInterfaceIsBuiltin(known_if) ? kCFBooleanTrue
1012 : kCFBooleanFalse;
1013 if (!_SC_CFEqual(known_builtin, match_context->match_builtin)) {
1014 return;
1015 }
1016 }
1017
1018 // if we have a match
1019 CFRelease(match_context->matches);
1020 match_context->matches = NULL;
1021
1022 return;
1023 }
1024
1025 static Boolean
1026 interfaceExists(CFStringRef prefix, CFNumberRef unit)
1027 {
1028 Boolean found = FALSE;
1029 CFDictionaryRef match_dict;
1030 CFStringRef match_keys[2];
1031 CFTypeRef match_vals[2];
1032 CFDictionaryRef matching;
1033
1034
1035
1036 io_registry_entry_t entry = MACH_PORT_NULL;
1037 io_iterator_t iterator = MACH_PORT_NULL;
1038 kern_return_t kr;
1039 mach_port_t masterPort = MACH_PORT_NULL;
1040
1041 kr = IOMasterPort(bootstrap_port, &masterPort);
1042 if (kr != KERN_SUCCESS) {
1043 SC_log(LOG_ERR, "IOMasterPort returned 0x%x", kr);
1044 goto error;
1045 }
1046
1047 // look for kIONetworkInterface with matching prefix and unit
1048 match_keys[0] = CFSTR(kIOInterfaceNamePrefix);
1049 match_vals[0] = prefix;
1050 match_keys[1] = CFSTR(kIOInterfaceUnit);
1051 match_vals[1] = unit;
1052 match_dict = CFDictionaryCreate(NULL,
1053 (const void **)match_keys,
1054 (const void **)match_vals,
1055 2,
1056 &kCFTypeDictionaryKeyCallBacks,
1057 &kCFTypeDictionaryValueCallBacks);
1058
1059 match_keys[0] = CFSTR(kIOProviderClassKey);
1060 match_vals[0] = CFSTR(kIONetworkInterfaceClass);
1061 match_keys[1] = CFSTR(kIOPropertyMatchKey);
1062 match_vals[1] = match_dict;
1063 matching = CFDictionaryCreate(NULL,
1064 (const void **)match_keys,
1065 (const void **)match_vals,
1066 sizeof(match_keys)/sizeof(match_keys[0]),
1067 &kCFTypeDictionaryKeyCallBacks,
1068 &kCFTypeDictionaryValueCallBacks);
1069 CFRelease(match_dict);
1070
1071 // note: the "matching" dictionary will be consumed by the following
1072 kr = IOServiceGetMatchingServices(masterPort, matching, &iterator);
1073 if ((kr != kIOReturnSuccess) || (iterator == MACH_PORT_NULL)) {
1074 // if no interface
1075 goto error;
1076 }
1077
1078 entry = IOIteratorNext(iterator);
1079 if (entry == MACH_PORT_NULL) {
1080 // if no interface
1081 goto error;
1082 }
1083
1084 found = TRUE;
1085
1086 error:
1087 if (masterPort != MACH_PORT_NULL) {
1088 mach_port_deallocate(mach_task_self(), masterPort);
1089 }
1090 if (entry != MACH_PORT_NULL) {
1091 IOObjectRelease(entry);
1092 }
1093 if (iterator != MACH_PORT_NULL) {
1094 IOObjectRelease(iterator);
1095 }
1096
1097 return (found);
1098 }
1099
1100 /*
1101 * lookupMatchingInterface
1102 *
1103 * Looks at the interfaces that have already been [or need to be] named with
1104 * the goal of allowing a system using a single network interface/adaptor of
1105 * a given type (vendor, model, ...) to not care about the specific adaptor
1106 * that is used (i.e. swapping dongle's is OK). Once a system has had more
1107 * than one interface/adaptor connected at the same time than we assume that
1108 * the network configuration is being setup for multi-homing that should be
1109 * maintained.
1110 *
1111 * If no matches are found or if more than one match is found, return NULL.
1112 * If a single match is found, return the match.
1113 */
1114 static CFDictionaryRef
1115 lookupMatchingInterface(SCNetworkInterfaceRef interface,
1116 CFArrayRef db_list, // already named
1117 CFArrayRef if_list, // to be named
1118 CFIndex if_list_index,
1119 CFBooleanRef builtin)
1120 {
1121 CFStringRef if_type;
1122 CFStringRef if_prefix;
1123 CFDictionaryRef match = NULL;
1124 matchContext match_context;
1125
1126 if_type = SCNetworkInterfaceGetInterfaceType(interface);
1127 if (if_type == NULL) {
1128 return NULL;
1129 }
1130 if_prefix = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface);
1131 if (if_prefix == NULL) {
1132 return NULL;
1133 }
1134
1135 match_context.match_type = if_type;
1136 match_context.match_prefix = if_prefix;
1137 match_context.match_info = _SCNetworkInterfaceCopyInterfaceInfo(interface);
1138 match_context.match_builtin = builtin;
1139 match_context.matches = NULL;
1140
1141 // check for matches to interfaces that have already been named
1142 // ... and append each match that we find to match_context.matches
1143 if (db_list != NULL) {
1144 CFArrayApplyFunction(db_list,
1145 CFRangeMake(0, CFArrayGetCount(db_list)),
1146 matchKnown,
1147 &match_context);
1148 }
1149
1150 // check for matches to interfaces that will be named
1151 // ... and CFRelease match_context.matches if we find another network
1152 // interface of the same type that also needs to be named
1153 if (if_list != NULL) {
1154 CFIndex if_list_count;
1155
1156 if_list_count = CFArrayGetCount(if_list);
1157 if (if_list_index < if_list_count) {
1158 CFArrayApplyFunction(if_list,
1159 CFRangeMake(if_list_index, if_list_count - if_list_index),
1160 matchUnnamed,
1161 &match_context);
1162 }
1163 }
1164
1165 // check if we have a single match
1166 if (match_context.matches != NULL) {
1167 if (CFArrayGetCount(match_context.matches) == 1) {
1168 match = CFArrayGetValueAtIndex(match_context.matches, 0);
1169 }
1170 CFRelease(match_context.matches);
1171 }
1172
1173 if (match != NULL) {
1174 Boolean active = TRUE;
1175 CFStringRef name;
1176
1177 name = CFDictionaryGetValue(match, CFSTR(kIOBSDNameKey));
1178 if (isA_CFString(name)) {
1179 CFStringRef prefix;
1180 CFNumberRef unit;
1181
1182 prefix = CFDictionaryGetValue(match, CFSTR(kIOInterfaceNamePrefix));
1183 unit = CFDictionaryGetValue(match, CFSTR(kIOInterfaceUnit));
1184 if (isA_CFString(prefix) && isA_CFNumber(unit)) {
1185 if (!interfaceExists(prefix, unit)) {
1186 active = FALSE;
1187 }
1188 }
1189 }
1190
1191 if (active) {
1192 match = NULL;
1193 }
1194 }
1195
1196 if (match_context.match_info != NULL) CFRelease(match_context.match_info);
1197 return match;
1198 }
1199
1200 static void
1201 insertInterface(CFMutableArrayRef db_list, SCNetworkInterfaceRef interface, CFDictionaryRef db_dict_match)
1202 {
1203 CFIndex i;
1204 CFDictionaryRef if_dict;
1205 CFStringRef if_name;
1206 CFStringRef if_prefix;
1207 CFNumberRef if_unit;
1208 CFArrayRef matchingMACs = NULL;
1209 CFIndex n = CFArrayGetCount(db_list);
1210 CFComparisonResult res;
1211
1212 if_name = SCNetworkInterfaceGetBSDName(interface);
1213 if (if_name != NULL) {
1214 addTimestamp(S_state, if_name);
1215 }
1216
1217 if (!_SCNetworkInterfaceIsBuiltin(interface) && (db_dict_match != NULL)) {
1218 CFDataRef addr_cur;
1219 CFDataRef addr_old;
1220
1221 matchingMACs = CFDictionaryGetValue(db_dict_match, CFSTR(kSCNetworkInterfaceMatchingMACs));
1222 if (matchingMACs != NULL) {
1223 CFRetain(matchingMACs);
1224 }
1225
1226 addr_old = CFDictionaryGetValue(db_dict_match, CFSTR(kIOMACAddress));
1227 addr_cur = _SCNetworkInterfaceGetHardwareAddress(interface);
1228 if ((addr_old != NULL) && (addr_cur != NULL) && !CFEqual(addr_old, addr_cur)) {
1229 CFMutableArrayRef matching_new;
1230
1231 // if MAC address changed, add previous MAC to history
1232 if (matchingMACs != NULL) {
1233 matching_new = CFArrayCreateMutableCopy(NULL, 0, matchingMACs);
1234 CFRelease(matchingMACs);
1235
1236 // remove duplicates of the now current MAC from history
1237 i = CFArrayGetFirstIndexOfValue(matching_new, CFRangeMake(0, CFArrayGetCount(matching_new)), addr_cur);
1238 if (i != kCFNotFound) {
1239 CFArrayRemoveValueAtIndex(matching_new, i);
1240 }
1241
1242 // remove duplicates of the previous MAC from history before re-inserting
1243 i = CFArrayGetFirstIndexOfValue(matching_new, CFRangeMake(0, CFArrayGetCount(matching_new)), addr_old);
1244 if (i != kCFNotFound) {
1245 CFArrayRemoveValueAtIndex(matching_new, i);
1246 }
1247 } else {
1248 matching_new = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1249 }
1250 CFArrayInsertValueAtIndex(matching_new, 0, addr_old);
1251
1252 // limit history size
1253 #define MATCHING_HISTORY_MAXLEN 32
1254 for (i = CFArrayGetCount(matching_new); i > MATCHING_HISTORY_MAXLEN; i--) {
1255 CFArrayRemoveValueAtIndex(matching_new, i - 1);
1256 }
1257
1258 matchingMACs = matching_new;
1259 }
1260 }
1261
1262 if_dict = createInterfaceDict(interface, matchingMACs);
1263 if (matchingMACs != NULL) {
1264 CFRelease(matchingMACs);
1265 }
1266
1267 if_prefix = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface);
1268 if_unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
1269 if ((if_prefix == NULL) || (if_unit == NULL)) {
1270 CFRelease(if_dict);
1271 return;
1272 }
1273
1274 for (i = 0; i < n; i++) {
1275 CFStringRef db_prefix;
1276 CFNumberRef db_unit;
1277 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i);
1278
1279 db_prefix = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceNamePrefix));
1280 db_unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
1281 res = CFStringCompare(if_prefix, db_prefix, 0);
1282 if (res == kCFCompareLessThan
1283 || (res == kCFCompareEqualTo
1284 && (CFNumberCompare(if_unit, db_unit, NULL)
1285 == kCFCompareLessThan))) {
1286 CFArrayInsertValueAtIndex(db_list, i, if_dict);
1287 CFRelease(if_dict);
1288 return;
1289 }
1290 }
1291
1292 CFArrayAppendValue(S_dblist, if_dict);
1293
1294 #if TARGET_OS_OSX
1295 updateBTPANInformation(if_dict, NULL);
1296 #endif // TARGET_OS_OSX
1297
1298 CFRelease(if_dict);
1299 return;
1300 }
1301
1302 static void
1303 removeInterface(CFMutableArrayRef db_list, SCNetworkInterfaceRef interface, CFDictionaryRef *matched)
1304 {
1305 CFDictionaryRef db_dict;
1306 int n = 0;
1307 CFIndex where;
1308
1309 // remove any dict that has our prefix+addr
1310 while (TRUE) {
1311 db_dict = lookupInterfaceByAddress(db_list, interface, &where);
1312 if (db_dict == NULL) {
1313 break;
1314 }
1315 if ((matched != NULL) && (*matched == NULL)) {
1316 *matched = CFRetain(db_dict);
1317 }
1318 CFArrayRemoveValueAtIndex(db_list, where);
1319 n++;
1320 }
1321
1322 // remove any dict that has the same prefix+unit
1323 while (TRUE) {
1324 db_dict = lookupInterfaceByUnit(db_list, interface, &where);
1325 if (db_dict == NULL) {
1326 break;
1327 }
1328 if ((matched != NULL) && (*matched == NULL)) {
1329 *matched = CFRetain(db_dict);
1330 }
1331 CFArrayRemoveValueAtIndex(db_list, where);
1332 n++;
1333 }
1334
1335 if (n > 1) {
1336 SC_log(LOG_ERR, "Multiple interfaces removed from database (n = %d, %@)", n, interface);
1337 }
1338
1339 return;
1340 }
1341
1342 static void
1343 replaceInterface(SCNetworkInterfaceRef interface)
1344 {
1345 CFDictionaryRef matched = NULL;
1346
1347 if (S_dblist == NULL) {
1348 S_dblist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1349 } else {
1350 // remove any matching interfaces
1351 removeInterface(S_dblist, interface, &matched);
1352 }
1353
1354 // [re-]insert the new interface
1355 insertInterface(S_dblist, interface, matched);
1356
1357 if (matched != NULL) {
1358 CFRelease(matched);
1359 }
1360
1361 return;
1362 }
1363
1364 static int
1365 getNextUnitForPrefix(CFStringRef if_prefix, int requested)
1366 {
1367 CFIndex n;
1368
1369 if (S_dblist == NULL) {
1370 return requested;
1371 }
1372
1373 n = CFArrayGetCount(S_dblist);
1374 for (CFIndex i = 0; i < n; i++) {
1375 CFDictionaryRef dict = CFArrayGetValueAtIndex(S_dblist, i);
1376 CFStringRef prefix;
1377
1378 prefix = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceNamePrefix));
1379 if (CFEqual(prefix, if_prefix)) {
1380 int u;
1381 CFNumberRef unit;
1382
1383 unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
1384 if (!isA_CFNumber(unit) ||
1385 !CFNumberGetValue(unit, kCFNumberIntType, &u)) {
1386 u = 0;
1387 }
1388
1389 if (u < requested) {
1390 // if we have not yet found our starting unit #
1391 continue;
1392 }
1393
1394 if (u == requested) {
1395 // our starting (or now proposed) unit # is "in use" so
1396 // let's keep searching
1397 requested++;
1398 continue;
1399 }
1400
1401 // we've found a unit # gap ... so let's re-assign it!
1402 }
1403 }
1404
1405 return requested;
1406 }
1407
1408 /*
1409 * Function: ensureInterfaceHasUnit
1410 * Purpose:
1411 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't,
1412 * release the interface and return NULL.
1413 */
1414 static SCNetworkInterfaceRef
1415 ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if)
1416 {
1417 if (net_if != NULL
1418 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if) == NULL) {
1419 CFRelease(net_if);
1420 net_if = NULL;
1421 }
1422 return (net_if);
1423 }
1424
1425 #ifdef USE_REGISTRY_ENTRY_ID
1426 static kern_return_t
1427 registerInterfaceWithIORegistryEntryID(io_connect_t connect,
1428 uint64_t entryID,
1429 CFNumberRef unit,
1430 const int command)
1431 {
1432 CFDataRef data;
1433 CFMutableDictionaryRef dict;
1434 kern_return_t kr;
1435 CFNumberRef num;
1436
1437 dict = CFDictionaryCreateMutable(NULL, 0,
1438 &kCFTypeDictionaryKeyCallBacks,
1439 &kCFTypeDictionaryValueCallBacks);
1440 num = CFNumberCreate(NULL, kCFNumberIntType, &command);
1441 CFDictionarySetValue(dict, CFSTR(kIONetworkStackUserCommandKey), num);
1442 CFRelease(num);
1443 data = CFDataCreate(NULL, (void *) &entryID, sizeof(entryID));
1444 CFDictionarySetValue(dict, CFSTR(kIORegistryEntryIDKey), data);
1445 CFRelease(data);
1446 CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit);
1447 kr = IOConnectSetCFProperties(connect, dict);
1448 CFRelease(dict);
1449 return kr;
1450 }
1451
1452 static SCNetworkInterfaceRef
1453 copyInterfaceForIORegistryEntryID(uint64_t entryID)
1454 {
1455 io_registry_entry_t entry = MACH_PORT_NULL;
1456 SCNetworkInterfaceRef interface = NULL;
1457 io_iterator_t iterator = MACH_PORT_NULL;
1458 kern_return_t kr;
1459 mach_port_t masterPort = MACH_PORT_NULL;
1460
1461 kr = IOMasterPort(bootstrap_port, &masterPort);
1462 if (kr != KERN_SUCCESS) {
1463 SC_log(LOG_ERR, "IOMasterPort returned 0x%x", kr);
1464 goto error;
1465 }
1466
1467 kr = IOServiceGetMatchingServices(masterPort,
1468 IORegistryEntryIDMatching(entryID),
1469 &iterator);
1470 if ((kr != KERN_SUCCESS) || (iterator == MACH_PORT_NULL)) {
1471 SC_log(LOG_NOTICE, "IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d",
1472 entryID,
1473 kr,
1474 iterator);
1475 goto error;
1476 }
1477
1478 entry = IOIteratorNext(iterator);
1479 if (entry == MACH_PORT_NULL) {
1480 SC_log(LOG_NOTICE, "IORegistryEntryIDMatching(0x%llx) failed", entryID);
1481 goto error;
1482 }
1483
1484 interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry);
1485
1486 error:
1487 if (masterPort != MACH_PORT_NULL) {
1488 mach_port_deallocate(mach_task_self(), masterPort);
1489 }
1490 if (entry != MACH_PORT_NULL) {
1491 IOObjectRelease(entry);
1492 }
1493 if (iterator != MACH_PORT_NULL) {
1494 IOObjectRelease(iterator);
1495 }
1496 return (interface);
1497 }
1498
1499 static SCNetworkInterfaceRef
1500 copyNamedInterfaceForIORegistryEntryID(uint64_t entryID)
1501 {
1502 SCNetworkInterfaceRef net_if;
1503
1504 net_if = copyInterfaceForIORegistryEntryID(entryID);
1505 return (ensureInterfaceHasUnit(net_if));
1506 }
1507
1508 #else // USE_REGISTRY_ENTRY_ID
1509 /*
1510 * Function: registerInterface
1511 * Purpose:
1512 * Register a single interface with the given service path to the
1513 * data link layer (BSD), using the specified unit number.
1514 */
1515 static kern_return_t
1516 registerInterfaceWithIOServicePath(io_connect_t connect,
1517 CFStringRef path,
1518 CFNumberRef unit,
1519 const int command)
1520 {
1521 CFMutableDictionaryRef dict;
1522 kern_return_t kr;
1523 CFNumberRef num;
1524
1525 dict = CFDictionaryCreateMutable(NULL, 0,
1526 &kCFTypeDictionaryKeyCallBacks,
1527 &kCFTypeDictionaryValueCallBacks);
1528 num = CFNumberCreate(NULL, kCFNumberIntType, &command);
1529 CFDictionarySetValue(dict, CFSTR(kIONetworkStackUserCommandKey), num);
1530 CFRelease(num);
1531 CFDictionarySetValue(dict, CFSTR(kIOPathMatchKey), path);
1532 CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit);
1533 kr = IOConnectSetCFProperties(connect, dict);
1534 CFRelease(dict);
1535 return kr;
1536 }
1537
1538 static SCNetworkInterfaceRef
1539 copyInterfaceForIOKitPath(CFStringRef if_path)
1540 {
1541 io_registry_entry_t entry = MACH_PORT_NULL;
1542 SCNetworkInterfaceRef interface = NULL;
1543 kern_return_t kr;
1544 mach_port_t masterPort = MACH_PORT_NULL;
1545 io_string_t path;
1546
1547 kr = IOMasterPort(bootstrap_port, &masterPort);
1548 if (kr != KERN_SUCCESS) {
1549 SC_log(LOG_ERR, "IOMasterPort returned 0x%x", kr);
1550 goto error;
1551 }
1552 _SC_cfstring_to_cstring(if_path, path, sizeof(path), kCFStringEncodingASCII);
1553 entry = IORegistryEntryFromPath(masterPort, path);
1554 if (entry == MACH_PORT_NULL) {
1555 SC_log(LOG_NOTICE, "IORegistryEntryFromPath(%@) failed", if_path);
1556 goto error;
1557 }
1558
1559 interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry);
1560
1561 error:
1562 if (masterPort != MACH_PORT_NULL) {
1563 mach_port_deallocate(mach_task_self(), masterPort);
1564 }
1565 if (entry != MACH_PORT_NULL) {
1566 IOObjectRelease(entry);
1567 }
1568 return (interface);
1569
1570 }
1571
1572 static SCNetworkInterfaceRef
1573 copyNamedInterfaceForIOKitPath(CFStringRef if_path)
1574 {
1575 SCNetworkInterfaceRef net_if;
1576
1577 net_if = copyInterfaceForIOKitPath(if_path);
1578 return (ensureInterfaceHasUnit(net_if));
1579 }
1580
1581 #endif // USE_REGISTRY_ENTRY_ID
1582
1583 static void
1584 displayInterface(SCNetworkInterfaceRef interface)
1585 {
1586 CFStringRef addr;
1587 CFStringRef name;
1588 CFStringRef prefix;
1589 CFNumberRef unit;
1590
1591 name = SCNetworkInterfaceGetBSDName(interface);
1592 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
1593 prefix = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface);
1594 addr = SCNetworkInterfaceGetHardwareAddressString(interface);
1595
1596 SC_log(LOG_INFO, " %s%@%sPrefix: %@, %s%@%sMAC address: %@",
1597 (name != NULL) ? "BSD Name: " : "",
1598 (name != NULL) ? name : CFSTR(""),
1599 (name != NULL) ? ", " : "",
1600 prefix,
1601 (unit != NULL) ? "Unit: " : "",
1602 (unit != NULL) ? (CFTypeRef)unit : (CFTypeRef)CFSTR(""),
1603 (unit != NULL) ? ", " : "",
1604 (addr != NULL) ? addr : CFSTR("?"));
1605 }
1606
1607 static Boolean
1608 builtinAvailable(SCNetworkInterfaceRef interface, // new interface
1609 CFNumberRef if_unit) // desired unit
1610 {
1611 CFIndex i;
1612 CFStringRef if_prefix = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface);
1613 CFIndex n;
1614
1615 n = (S_dblist != NULL) ? CFArrayGetCount(S_dblist) : 0;
1616 for (i = 0; i < n; i++) {
1617 CFStringRef if_path;
1618 CFDictionaryRef known_dict = CFArrayGetValueAtIndex(S_dblist, i);
1619 CFStringRef known_path;
1620 CFStringRef known_prefix;
1621 CFNumberRef known_unit;
1622
1623 known_prefix = CFDictionaryGetValue(known_dict, CFSTR(kIOInterfaceNamePrefix));
1624 if (!_SC_CFEqual(if_prefix, known_prefix)) {
1625 continue; // if not the same interface prefix
1626 }
1627
1628 known_unit = CFDictionaryGetValue(known_dict, CFSTR(kIOInterfaceUnit));
1629 if (!_SC_CFEqual(if_unit, known_unit)) {
1630 continue; // if not the same interface unit
1631 }
1632
1633 if_path = _SCNetworkInterfaceGetIOPath(interface);
1634 known_path = CFDictionaryGetValue(known_dict, CFSTR(kIOPathMatchKey));
1635 if (!_SC_CFEqual(if_path, known_path)) {
1636 // if different IORegistry path
1637 return FALSE;
1638 }
1639
1640 // if same prefix+unit+path
1641 return TRUE;
1642 }
1643
1644 // if interface prefix+unit not found
1645 return TRUE;
1646 }
1647
1648 static int
1649 builtinCount(CFArrayRef if_list, CFIndex last, CFStringRef if_prefix)
1650 {
1651 CFIndex i;
1652 int n = 0;
1653
1654 for (i = 0; i < last; i++) {
1655 SCNetworkInterfaceRef builtin_if;
1656 CFStringRef builtin_prefix;
1657
1658 builtin_if = CFArrayGetValueAtIndex(if_list, i);
1659 builtin_prefix = _SCNetworkInterfaceGetIOInterfaceNamePrefix(builtin_if);
1660 if (CFEqual(if_prefix, builtin_prefix)) {
1661 if (_SCNetworkInterfaceIsBuiltin(builtin_if)) {
1662 n++; // if built-in interface
1663 }
1664 }
1665 }
1666
1667 return n;
1668 }
1669
1670
1671 #pragma mark -
1672 #pragma mark Internet Sharing configuration support
1673
1674
1675 #if TARGET_OS_OSX
1676
1677 static SCPreferencesRef nat_configuration = NULL; // com.apple.nat.plist
1678 static SCPreferencesRef nat_preferences = NULL; // preferences.plist
1679
1680
1681 static void
1682 sharingConfigurationClose(void)
1683 {
1684 if (nat_configuration != NULL) {
1685 CFRelease(nat_configuration);
1686 nat_configuration = NULL;
1687 }
1688
1689 if (nat_preferences != NULL) {
1690 CFRelease(nat_preferences);
1691 nat_preferences = NULL;
1692 }
1693
1694 return;
1695 }
1696
1697
1698 static Boolean
1699 sharingConfigurationUsesInterface(CFStringRef bsdName, Boolean keepOpen)
1700 {
1701 CFDictionaryRef config;
1702 Boolean isShared = FALSE;
1703
1704 if (nat_configuration == NULL) {
1705 nat_configuration = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME ":sharingConfigurationUsesInterface"), CFSTR("com.apple.nat.plist"));
1706 if (nat_configuration == NULL) {
1707 return FALSE;
1708 }
1709 }
1710
1711 config = SCPreferencesGetValue(nat_configuration, CFSTR("NAT"));
1712 if (isA_CFDictionary(config)) {
1713 CFBooleanRef bVal = NULL;
1714 Boolean enabled = FALSE;
1715 CFStringRef sharedFromServiceID = NULL;
1716 CFArrayRef sharedToInterfaces = NULL;
1717
1718 if (CFDictionaryGetValueIfPresent(config,
1719 CFSTR("Enabled"),
1720 (const void **)&bVal) &&
1721 isA_CFBoolean(bVal)) {
1722 enabled = CFBooleanGetValue(bVal);
1723 }
1724
1725 if (enabled &&
1726 CFDictionaryGetValueIfPresent(config,
1727 CFSTR("SharingDevices"),
1728 (const void **)&sharedToInterfaces) &&
1729 isA_CFArray(sharedToInterfaces)) {
1730 CFIndex n;
1731
1732 // if "To computers using" interfaces configured
1733 n = CFArrayGetCount(sharedToInterfaces);
1734 for (CFIndex i = 0; i < n; i++) {
1735 CFStringRef sharedToInterface_bsdName;
1736
1737 sharedToInterface_bsdName = CFArrayGetValueAtIndex(sharedToInterfaces, i);
1738 if (_SC_CFEqual(bsdName, sharedToInterface_bsdName)) {
1739 isShared = TRUE;
1740 break;
1741 }
1742 }
1743 }
1744
1745 if (enabled &&
1746 !isShared &&
1747 CFDictionaryGetValueIfPresent(config,
1748 CFSTR("PrimaryService"),
1749 (const void **)&sharedFromServiceID) &&
1750 isA_CFString(sharedFromServiceID)) {
1751 if (nat_preferences == NULL) {
1752 nat_preferences = SCPreferencesCreateCompanion(nat_configuration, NULL);
1753 }
1754 if (nat_preferences != NULL) {
1755 SCNetworkServiceRef sharedFromService;
1756
1757 // if "Share your connection from" service configured
1758 sharedFromService = SCNetworkServiceCopy(nat_preferences, sharedFromServiceID);
1759 if (sharedFromService != NULL) {
1760 CFStringRef sharedFromService_bsdName;
1761 SCNetworkInterfaceRef sharedFromService_interface;
1762
1763 sharedFromService_interface = SCNetworkServiceGetInterface(sharedFromService);
1764 sharedFromService_bsdName = SCNetworkInterfaceGetBSDName(sharedFromService_interface);
1765 isShared = _SC_CFEqual(bsdName, sharedFromService_bsdName);
1766 CFRelease(sharedFromService);
1767 }
1768 }
1769 }
1770 }
1771
1772 if (!keepOpen) {
1773 sharingConfigurationClose();
1774 }
1775
1776 return isShared;
1777 }
1778
1779 #endif // TARGET_OS_OSX
1780
1781
1782 #pragma mark -
1783 #pragma mark Interface monitoring (e.g. watch for "detach")
1784
1785
1786 typedef struct WatchedInfo *WatchedInfoRef;
1787
1788 typedef void (*InterfaceUpdateCallBack) (
1789 CFDataRef watched,
1790 natural_t messageType,
1791 void *messageArgument
1792 );
1793
1794 typedef struct {
1795 SCNetworkInterfaceRef interface;
1796 io_service_t interface_node;
1797 io_object_t notification;
1798 InterfaceUpdateCallBack callback;
1799 } WatchedInfo;
1800
1801 static void
1802 watcherRelease(CFDataRef watched);
1803
1804 static void
1805 updateWatchedInterface(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
1806 {
1807 #pragma unused(service)
1808 #pragma unused(messageArgument)
1809 switch (messageType) {
1810 case kIOMessageServiceIsTerminated : { // if [watched] interface yanked
1811 SCNetworkInterfaceRef remove;
1812 CFDataRef watched = (CFDataRef)refCon;
1813 WatchedInfo *watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
1814
1815 remove = watchedInfo->interface;
1816 if (_SCNetworkInterfaceIsBuiltin(remove)) {
1817 // if built-in, keep
1818 remove = NULL;
1819 } else if (!_SCNetworkInterfaceIsApplePreconfigured(remove)) {
1820 // if not pre-configured, keep
1821 remove = NULL;
1822 } else {
1823 // if not built-in *and* pre-configured
1824 CFRetain(remove);
1825 }
1826
1827 #if TARGET_OS_OSX
1828 if (remove != NULL) {
1829 CFStringRef bsdName;
1830
1831 bsdName = SCNetworkInterfaceGetBSDName(remove);
1832 if ((bsdName != NULL) && sharingConfigurationUsesInterface(bsdName, FALSE)) {
1833 // if referenced in the Internet Sharing configuration, keep
1834 CFRelease(remove);
1835 remove = NULL;
1836 }
1837 }
1838 #endif // TARGET_OS_OSX
1839
1840 CFRetain(watched);
1841 watchedInfo->callback(watched, messageType, messageArgument);
1842 watcherRelease(watched);
1843 CFRelease(watched);
1844
1845 if (remove != NULL) {
1846 SC_log(LOG_INFO, "Interface released unit %@ (from database)",
1847 _SCNetworkInterfaceGetIOInterfaceUnit(remove));
1848 removeInterface(S_dblist, remove, NULL);
1849 CFRelease(remove);
1850
1851 // update the DB with the [remaining] interfaces that have been named
1852 writeInterfaceList(S_dblist);
1853 }
1854
1855 break;
1856 }
1857
1858 default :
1859 return;
1860 }
1861
1862 return;
1863 }
1864
1865 static CFDataRef
1866 watcherCreate(SCNetworkInterfaceRef interface, InterfaceUpdateCallBack callback)
1867 {
1868 uint64_t entryID;
1869 io_service_t interface_node;
1870 kern_return_t kr;
1871 CFDictionaryRef matching;
1872 CFMutableDataRef watched;
1873 WatchedInfo *watchedInfo;
1874
1875 // get the IORegistry node
1876 entryID = _SCNetworkInterfaceGetIORegistryEntryID(interface);
1877 matching = IORegistryEntryIDMatching(entryID);
1878 interface_node = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
1879 if (interface_node == MACH_PORT_NULL) {
1880 // interface no longer present
1881 return NULL;
1882 }
1883
1884 // create [locked/trusted] interface watcher
1885 watched = CFDataCreateMutable(NULL, sizeof(WatchedInfo));
1886 CFDataSetLength(watched, sizeof(WatchedInfo));
1887 watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
1888 memset(watchedInfo, 0, sizeof(*watchedInfo));
1889
1890 // retain interface
1891 watchedInfo->interface = CFRetain(interface);
1892
1893 // ... and the interface node
1894 watchedInfo->interface_node = interface_node;
1895
1896 // ... and set the callback
1897 watchedInfo->callback = callback;
1898
1899 kr = IOServiceAddInterestNotification(S_notify, // IONotificationPortRef
1900 watchedInfo->interface_node, // io_service_t
1901 kIOGeneralInterest, // interestType
1902 updateWatchedInterface, // IOServiceInterestCallback
1903 (void *)watched, // refCon
1904 &watchedInfo->notification); // notification
1905 if (kr != KERN_SUCCESS) {
1906 SC_log(LOG_ERR,
1907 "IOServiceAddInterestNotification() failed, kr = 0x%x",
1908 kr);
1909 watcherRelease(watched);
1910 CFRelease(watched);
1911 return NULL;
1912 }
1913
1914 return watched;
1915 }
1916
1917 static void
1918 watcherRelease(CFDataRef watched)
1919 {
1920 WatchedInfo *watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
1921
1922 // release watcher
1923 if (watchedInfo->notification != IO_OBJECT_NULL) {
1924 IOObjectRelease(watchedInfo->notification);
1925 watchedInfo->notification = IO_OBJECT_NULL;
1926 }
1927
1928 // release interface node
1929 if (watchedInfo->interface_node != IO_OBJECT_NULL) {
1930 IOObjectRelease(watchedInfo->interface_node);
1931 watchedInfo->interface_node = IO_OBJECT_NULL;
1932 }
1933
1934 // release interface
1935 if (watchedInfo->interface != NULL) {
1936 CFRelease(watchedInfo->interface);
1937 watchedInfo->interface = NULL;
1938 }
1939
1940 return;
1941 }
1942
1943 static Boolean
1944 isWatchedInterface(CFArrayRef watchedInterfaces, SCNetworkInterfaceRef interface)
1945 {
1946 CFIndex n;
1947
1948 n = (watchedInterfaces != NULL) ? CFArrayGetCount(watchedInterfaces) : 0;
1949 for (CFIndex i = 0; i < n; i++) {
1950 CFDataRef watched = CFArrayGetValueAtIndex(watchedInterfaces, i);
1951 WatchedInfo *watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
1952
1953 if (CFEqual((watchedInfo->interface), interface)) {
1954 return TRUE;
1955 }
1956 }
1957
1958 return FALSE;
1959 }
1960
1961
1962 #pragma mark -
1963 #pragma mark Locked device support [macOS]
1964
1965
1966 #if !TARGET_OS_IPHONE
1967 static void
1968 shareLocked(void)
1969 {
1970 CFIndex n;
1971
1972 n = (S_locked != NULL) ? CFArrayGetCount(S_locked) : 0;
1973 if (n > 0) {
1974 CFMutableArrayRef locked;
1975
1976 locked = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1977
1978 for (CFIndex i = 0; i < n; i++) {
1979 CFStringRef addr;
1980 CFStringRef name;
1981 CFStringRef path;
1982 CFStringRef str;
1983 CFDataRef watched = CFArrayGetValueAtIndex(S_locked, i);
1984 WatchedInfo *watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
1985
1986 name = SCNetworkInterfaceGetLocalizedDisplayName(watchedInfo->interface);
1987 addr = SCNetworkInterfaceGetHardwareAddressString(watchedInfo->interface);
1988 path = _SCNetworkInterfaceGetIOPath(watchedInfo->interface);
1989 str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@: %@: %@"),
1990 (name != NULL) ? name : CFSTR("?"),
1991 (addr != NULL) ? addr : CFSTR("?"),
1992 path);
1993 CFArrayAppendValue(locked, str);
1994 CFRelease(str);
1995 }
1996
1997 CFDictionarySetValue(S_state, kInterfaceNamerKey_LockedInterfaces, locked);
1998 CFRelease(locked);
1999 } else {
2000 CFDictionaryRemoveValue(S_state, kInterfaceNamerKey_LockedInterfaces);
2001 }
2002
2003 updateStore();
2004
2005 return;
2006 }
2007
2008 static boolean_t
2009 blockNewInterfaces()
2010 {
2011 static boolean_t allow = TRUE;
2012 static dispatch_once_t once;
2013
2014 dispatch_once(&once, ^{
2015 allow = InterfaceNamerControlPrefsAllowNewInterfaces();
2016 });
2017
2018 return !allow;
2019 }
2020
2021 static boolean_t
2022 isConsoleLocked()
2023 {
2024 CFArrayRef console_sessions;
2025 boolean_t locked = FALSE;
2026 io_registry_entry_t root;
2027
2028 root = IORegistryGetRootEntry(kIOMasterPortDefault);
2029 console_sessions = IORegistryEntryCreateCFProperty(root,
2030 CFSTR(kIOConsoleUsersKey),
2031 NULL,
2032 0);
2033 if (isA_CFArray(console_sessions)) {
2034 CFIndex n;
2035
2036 n = CFArrayGetCount(console_sessions);
2037 for (CFIndex i = 0; i < n; i++) {
2038 CFBooleanRef isLocked;
2039 CFBooleanRef isLoginDone;
2040 CFBooleanRef onConsole;
2041 CFDictionaryRef session;
2042
2043 session = CFArrayGetValueAtIndex(console_sessions, i);
2044 if (!isA_CFDictionary(session)) {
2045 // if not dictionary
2046 continue;
2047 }
2048
2049 if (!CFDictionaryGetValueIfPresent(session,
2050 CFSTR(kIOConsoleSessionOnConsoleKey),
2051 (const void **)&onConsole) ||
2052 !isA_CFBoolean(onConsole) ||
2053 !CFBooleanGetValue(onConsole)) {
2054 // if not "on console" session
2055 continue;
2056 }
2057
2058 if ((n > 1) &&
2059 CFDictionaryGetValueIfPresent(session,
2060 CFSTR(kIOConsoleSessionLoginDoneKey),
2061 (const void **)&isLoginDone) &&
2062 isA_CFBoolean(isLoginDone) &&
2063 !CFBooleanGetValue(isLoginDone)) {
2064 // if @ loginwindow
2065 SC_log(LOG_INFO, "multiple sessions, console @ loginwindow");
2066 locked = TRUE;
2067 goto done;
2068 }
2069
2070 if (CFDictionaryGetValueIfPresent(session,
2071 CFSTR(kIOConsoleSessionScreenIsLockedKey),
2072 (const void **)&isLocked) &&
2073 isA_CFBoolean(isLocked) &&
2074 CFBooleanGetValue(isLocked)) {
2075 // if screen locked
2076 SC_log(LOG_INFO, "console screen locked");
2077 locked = TRUE;
2078 goto done;
2079 }
2080 }
2081 }
2082
2083 SC_log(LOG_INFO, "console not locked");
2084
2085 done :
2086
2087 if (console_sessions != NULL) {
2088 CFRelease(console_sessions);
2089 }
2090 IOObjectRelease(root);
2091
2092 return locked;
2093 }
2094
2095 //#define ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2096 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2097
2098 static CFUserNotificationRef userNotification;
2099 static CFRunLoopSourceRef userRls;
2100
2101 static void
2102 lockedNotification_remove(void)
2103 {
2104 if (userRls != NULL) {
2105 CFRunLoopSourceInvalidate(userRls);
2106 userRls = NULL;
2107 }
2108
2109 if (userNotification != NULL) {
2110 SInt32 status;
2111
2112 status = CFUserNotificationCancel(userNotification);
2113 if (status != 0) {
2114 SC_log(LOG_ERR,
2115 "CFUserNotificationCancel() failed, status=%d",
2116 (int)status);
2117 }
2118 CFRelease(userNotification);
2119 userNotification = NULL;
2120 }
2121
2122 return;
2123 }
2124
2125 #define MY_ICON_PATH "/System/Library/PreferencePanes/Network.prefPane/Contents/Resources/Network.icns"
2126
2127 static void
2128 lockedNotification_reply(CFUserNotificationRef userNotification, CFOptionFlags response_flags)
2129 {
2130 #pragma unused(userNotification)
2131
2132 CFIndex n;
2133
2134 n = (S_locked != NULL) ? CFArrayGetCount(S_locked) : 0;
2135 for (CFIndex i = 0; i < n; i++) {
2136 CFDataRef watched = CFArrayGetValueAtIndex(S_locked, i);
2137 WatchedInfo *watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
2138
2139 // process user response
2140 switch (response_flags & 0x3) {
2141 case kCFUserNotificationDefaultResponse: {
2142 // if OK'd, [re-]process new interfaces
2143 if (i == 0) {
2144 SC_log(LOG_INFO, "Reprocessing %ld [locked] interface%s", n, n == 1 ? "" : "s");
2145
2146 if (S_iflist == NULL) {
2147 S_iflist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2148 }
2149 }
2150
2151 // add the interface to those newly discovered
2152 CFArrayAppendValue(S_iflist, watchedInfo->interface);
2153 break;
2154 }
2155 default: {
2156 // if cancelled, ignore [remaining] new interfaces
2157 SC_log(LOG_INFO, "[locked] interface ignored");
2158 SC_log(LOG_INFO, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo->interface));
2159 break;
2160 }
2161 }
2162
2163 // stop watching
2164 watcherRelease(watched);
2165 }
2166
2167 if (S_locked != NULL) {
2168 CFRelease(S_locked);
2169 S_locked = NULL;
2170 }
2171
2172 lockedNotification_remove();
2173
2174 if (S_iflist != NULL) {
2175 updateInterfaces();
2176 }
2177
2178 return;
2179 }
2180
2181 static void
2182 lockedNotification_add(void)
2183 {
2184 CFBundleRef bundle;
2185 CFMutableDictionaryRef dict;
2186 SInt32 error = 0;
2187 CFMutableArrayRef message;
2188 CFIndex n;
2189 CFURLRef url = NULL;
2190
2191 n = (S_locked != NULL) ? CFArrayGetCount(S_locked) : 0;
2192 if (n == 0) {
2193 // no locked interfaces, no notification needed
2194 return;
2195 }
2196
2197 dict = CFDictionaryCreateMutable(NULL,
2198 0,
2199 &kCFTypeDictionaryKeyCallBacks,
2200 &kCFTypeDictionaryValueCallBacks);
2201
2202 // set localization URL
2203 bundle = _SC_CFBundleGet();
2204 if (bundle != NULL) {
2205 url = CFBundleCopyBundleURL(bundle);
2206 }
2207 if (url != NULL) {
2208 // set URL
2209 CFDictionarySetValue(dict, kCFUserNotificationLocalizationURLKey, url);
2210 CFRelease(url);
2211 } else {
2212 SC_log(LOG_ERR, "can't find bundle");
2213 goto done;
2214 }
2215
2216 // set icon URL
2217 url = CFURLCreateFromFileSystemRepresentation(NULL,
2218 (const UInt8 *)MY_ICON_PATH,
2219 sizeof(MY_ICON_PATH) - 1,
2220 FALSE);
2221 if (url != NULL) {
2222 CFDictionarySetValue(dict, kCFUserNotificationIconURLKey, url);
2223 CFRelease(url);
2224 }
2225
2226 // header
2227 CFDictionarySetValue(dict,
2228 kCFUserNotificationAlertHeaderKey,
2229 (n == 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_HEADER")
2230 : CFSTR("LOCKED_MULTIPLE_INTERFACES_HEADER"));
2231
2232 // message
2233 message = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2234 CFArrayAppendValue(message,
2235 (n == 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_MESSAGE")
2236 : CFSTR("LOCKED_MULTIPLE_INTERFACES_MESSAGE"));
2237 for (CFIndex i = 0; i < n; i++) {
2238 CFStringRef name;
2239 CFStringRef str;
2240 CFDataRef watched = CFArrayGetValueAtIndex(S_locked, i);
2241 WatchedInfo *watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
2242
2243 name = SCNetworkInterfaceGetLocalizedDisplayName(watchedInfo->interface);
2244 str = CFStringCreateWithFormat(NULL, NULL, CFSTR("\n\t%@"), name);
2245 CFArrayAppendValue(message, str);
2246 CFRelease(str);
2247 }
2248 CFDictionarySetValue(dict, kCFUserNotificationAlertMessageKey, message);
2249 CFRelease(message);
2250
2251 // button titles
2252 CFDictionarySetValue(dict,
2253 kCFUserNotificationDefaultButtonTitleKey,
2254 CFSTR("LOCKED_INTERFACES_IGNORE"));
2255 CFDictionarySetValue(dict,
2256 kCFUserNotificationAlternateButtonTitleKey,
2257 (n == 1) ? CFSTR("LOCKED_SINGLE_INTERFACE_ADD")
2258 : CFSTR("LOCKED_MULTIPLE_INTERFACES_ADD"));
2259
2260 // create and post notification
2261 userNotification = CFUserNotificationCreate(NULL,
2262 0,
2263 kCFUserNotificationNoteAlertLevel,
2264 &error,
2265 dict);
2266 if (userNotification == NULL) {
2267 SC_log(LOG_ERR, "CFUserNotificationCreate() failed: %d", (int)error);
2268 goto done;
2269 }
2270
2271 // establish callback
2272 userRls = CFUserNotificationCreateRunLoopSource(NULL,
2273 userNotification,
2274 lockedNotification_reply,
2275 0);
2276 if (userRls == NULL) {
2277 SC_log(LOG_ERR, "CFUserNotificationCreateRunLoopSource() failed");
2278 CFRelease(userNotification);
2279 userNotification = NULL;
2280 goto done;
2281 }
2282 CFRunLoopAddSource(CFRunLoopGetCurrent(), userRls, kCFRunLoopDefaultMode);
2283
2284 done :
2285
2286 if (dict != NULL) CFRelease(dict);
2287 return;
2288 }
2289
2290 static void
2291 lockedNotification_update(void)
2292 {
2293 // if present, remove current notification
2294 lockedNotification_remove();
2295
2296 // post notification (if needed)
2297 lockedNotification_add();
2298
2299 return;
2300 }
2301
2302 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2303
2304 static void
2305 lockedInterfaceUpdated(CFDataRef watched, natural_t messageType, void *messageArgument)
2306 {
2307 #pragma unused(messageArgument)
2308 Boolean updated = FALSE;
2309 WatchedInfo *watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
2310
2311 switch (messageType) {
2312 case kIOMessageServiceIsTerminated : { // if [locked] interface yanked
2313 SC_log(LOG_INFO, "[locked] interface removed");
2314 SC_log(LOG_INFO, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo->interface));
2315
2316 if (S_locked != NULL) {
2317 CFIndex i;
2318 CFIndex n = CFArrayGetCount(S_locked);
2319
2320 i = CFArrayGetFirstIndexOfValue(S_locked, CFRangeMake(0, n), watched);
2321 if (i != kCFNotFound) {
2322 CFArrayRemoveValueAtIndex(S_locked, i);
2323 if (CFArrayGetCount(S_locked) == 0) {
2324 CFRelease(S_locked);
2325 S_locked = NULL;
2326 }
2327 updated = TRUE;
2328 }
2329 }
2330
2331 break;
2332 }
2333
2334 default :
2335 return;
2336 }
2337
2338 if (updated) {
2339 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2340 // update user notification after interface removed
2341 lockedNotification_update();
2342 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2343
2344 // post info about interfaces not added because the console is locked
2345 shareLocked();
2346 }
2347
2348 return;
2349 }
2350
2351 static void
2352 watchLockedInterface(SCNetworkInterfaceRef interface)
2353 {
2354 Boolean updated = FALSE;
2355 CFDataRef watched;
2356
2357 watched = watcherCreate(interface, lockedInterfaceUpdated);
2358 if (watched != NULL) {
2359 SC_log(LOG_INFO, "watching [locked] interface");
2360 SC_log(LOG_INFO, " path = %@", _SCNetworkInterfaceGetIOPath(interface));
2361
2362 if (S_locked == NULL) {
2363 S_locked = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2364 }
2365 CFArrayAppendValue(S_locked, watched);
2366 CFRelease(watched);
2367 updated = TRUE;
2368 }
2369
2370 if (updated) {
2371 // post info about interfaces not added because the console is locked
2372 shareLocked();
2373
2374 #ifdef ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2375 // post/update user notification with new interface
2376 lockedNotification_update();
2377 #endif // ENABLE_LOCKED_CONSOLE_INTERFACE_NOTIFICATIONS
2378 }
2379
2380 return;
2381 }
2382 #endif // !TARGET_OS_IPHONE
2383
2384
2385 #pragma mark -
2386 #pragma mark Trust required support [iOS]
2387
2388
2389 #if TARGET_OS_IPHONE
2390
2391 #include <SoftLinking/WeakLinking.h>
2392 WEAK_LINK_FORCE_IMPORT(lockdown_is_host_trusted);
2393 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationHostAttached);
2394 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationHostDetached);
2395 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationTrustedHostAttached);
2396 WEAK_LINK_FORCE_IMPORT(kLockdownNotificationTrustedPTPAttached);
2397
2398 static Boolean
2399 haveLockdown()
2400 {
2401 Boolean haveLibrary;
2402
2403 haveLibrary = ((lockdown_is_host_trusted != NULL) &&
2404 (&kLockdownNotificationHostAttached != NULL) &&
2405 (&kLockdownNotificationHostDetached != NULL) &&
2406 (&kLockdownNotificationTrustedHostAttached != NULL) &&
2407 (&kLockdownNotificationTrustedPTPAttached != NULL)
2408 );
2409 return haveLibrary;
2410 }
2411
2412 static void
2413 shareExcluded()
2414 {
2415 CFIndex n;
2416
2417 n = (S_trustRequired != NULL) ? CFArrayGetCount(S_trustRequired) : 0;
2418 if ((n > 0) && !S_trustedHostAttached) {
2419 CFMutableArrayRef excluded;
2420
2421 // if we have interfaces that require not [yet] granted "trust".
2422
2423 excluded = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2424
2425 for (CFIndex i = 0; i < n; i++) {
2426 CFStringRef bsdName;
2427 CFDataRef watched = CFArrayGetValueAtIndex(S_trustRequired, i);
2428 WatchedInfo *watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
2429
2430 bsdName = SCNetworkInterfaceGetBSDName(watchedInfo->interface);
2431 if (bsdName == NULL) {
2432 SC_log(LOG_NOTICE, "[trust required] interface w/no BSD name not excluded");
2433 SC_log(LOG_NOTICE, " interface = %@", watchedInfo->interface);
2434 continue;
2435 }
2436 CFArrayAppendValue(excluded, bsdName);
2437 }
2438
2439 CFDictionarySetValue(S_state, kInterfaceNamerKey_ExcludedInterfaces, excluded);
2440 CFRelease(excluded);
2441 } else {
2442 CFDictionaryRemoveValue(S_state, kInterfaceNamerKey_ExcludedInterfaces);
2443 }
2444
2445 updateStore();
2446
2447 return;
2448 }
2449
2450 static dispatch_queue_t
2451 trustRequired_queue()
2452 {
2453 static dispatch_once_t once;
2454 static dispatch_queue_t q;
2455
2456 dispatch_once(&once, ^{
2457 q = dispatch_queue_create("Trust Required queue", NULL);
2458 });
2459
2460 return q;
2461
2462 }
2463
2464 // runs on "Trust Required" dispatch queue
2465 static void
2466 trustRequiredNotification_update(CFRunLoopRef rl, CFStringRef reason)
2467 {
2468 Boolean changed = FALSE;
2469 CFStringRef error = NULL;
2470 CFIndex n;
2471 Boolean trusted;
2472
2473 /*
2474 * determine whether the device has "trusted" the host (or other device)
2475 */
2476 trusted = lockdown_is_host_trusted(MY_PLUGIN_ID, NULL, &error);
2477 n = (S_trustRequired != NULL) ? CFArrayGetCount(S_trustRequired) : 0;
2478 if ((S_trustedHostCount != n) || (S_trustedHostAttached != trusted)) {
2479 changed = TRUE;
2480 }
2481
2482 SC_log(LOG_INFO, "%@, trusted = %s%s%@, %ld interface%s)%s",
2483 reason,
2484 trusted ? "Yes" : "No",
2485 (error != NULL) ? ", error = " : "",
2486 (error != NULL) ? error : CFSTR(""),
2487 n,
2488 (n == 1) ? "" : "s",
2489 changed ? " *" : "");
2490
2491 if (changed) {
2492 S_trustedHostAttached = trusted;
2493 S_trustedHostCount = n;
2494 CFRunLoopPerformBlock(rl, kCFRunLoopDefaultMode, ^{
2495 shareExcluded();
2496 });
2497 CFRunLoopWakeUp(rl);
2498 }
2499
2500 if (error != NULL) {
2501 CFRelease(error);
2502 }
2503
2504 return;
2505 }
2506
2507 static void
2508 trustRequiredInterfaceUpdated(CFDataRef watched, natural_t messageType, void *messageArgument)
2509 {
2510 #pragma unused(messageArgument)
2511 Boolean updated = FALSE;
2512 WatchedInfo *watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
2513
2514 switch (messageType) {
2515 case kIOMessageServiceIsTerminated : { // if [locked] interface yanked
2516 SC_log(LOG_INFO, "[trust required] interface removed");
2517 SC_log(LOG_INFO, " path = %@", _SCNetworkInterfaceGetIOPath(watchedInfo->interface));
2518
2519 if (S_trustRequired != NULL) {
2520 CFIndex i;
2521 CFIndex n = CFArrayGetCount(S_trustRequired);
2522
2523 i = CFArrayGetFirstIndexOfValue(S_trustRequired, CFRangeMake(0, n), watched);
2524 if (i != kCFNotFound) {
2525 CFArrayRemoveValueAtIndex(S_trustRequired, i);
2526 if (CFArrayGetCount(S_trustRequired) == 0) {
2527 CFRelease(S_trustRequired);
2528 S_trustRequired = NULL;
2529 }
2530 updated = TRUE;
2531 }
2532 }
2533
2534 break;
2535 }
2536
2537 default :
2538 return;
2539 }
2540
2541 if (updated) {
2542 CFRunLoopRef rl = CFRunLoopGetCurrent();
2543
2544 CFRetain(rl);
2545 dispatch_async(trustRequired_queue(), ^{
2546 trustRequiredNotification_update(rl, CFSTR("TrustRequired interface removed"));
2547 CFRelease(rl);
2548 });
2549 }
2550
2551 return;
2552 }
2553
2554 static void
2555 watchTrustedStatus(CFStringRef notification, CFStringRef reason)
2556 {
2557 const char * key;
2558 int notify_token = -1;
2559 uint32_t ret;
2560 CFRunLoopRef rl = CFRunLoopGetCurrent();
2561
2562 key = CFStringGetCStringPtr(notification, kCFStringEncodingUTF8);
2563 assert(key != NULL);
2564
2565 CFRetain(rl);
2566 CFRetain(reason);
2567 ret = notify_register_dispatch(key,
2568 &notify_token,
2569 trustRequired_queue(),
2570 ^(int token){
2571 #pragma unused(token)
2572 trustRequiredNotification_update(rl, reason);
2573 });
2574 if (ret != NOTIFY_STATUS_OK) {
2575 SC_log(LOG_ERR, "notify_register_dispatch(%@) failed: %u", notification, ret);
2576 CFRelease(rl);
2577 CFRelease(reason);
2578 }
2579
2580 return;
2581 }
2582
2583 static void
2584 updateTrustRequiredInterfaces(CFArrayRef interfaces)
2585 {
2586 CFIndex n;
2587 Boolean updated = FALSE;
2588
2589 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
2590 for (CFIndex i = 0; i < n; i++) {
2591 SCNetworkInterfaceRef interface;
2592
2593 interface = CFArrayGetValueAtIndex(interfaces, i);
2594 if (_SCNetworkInterfaceIsTrustRequired(interface) &&
2595 !isWatchedInterface(S_trustRequired, interface)) {
2596 CFDataRef watched;
2597
2598 watched = watcherCreate(interface, trustRequiredInterfaceUpdated);
2599 if (watched != NULL) {
2600 CFStringRef bsdName;
2601
2602 bsdName = SCNetworkInterfaceGetBSDName(interface);
2603 if (bsdName != NULL) {
2604 SC_log(LOG_INFO, "watching [trust required] interface: %@", bsdName);
2605 } else {
2606 SC_log(LOG_INFO, "watching [trust required] interface w/no BSD name");
2607 SC_log(LOG_INFO, " interface = %@", interface);
2608 }
2609
2610 if (S_trustRequired == NULL) {
2611 S_trustRequired = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2612 }
2613 CFArrayAppendValue(S_trustRequired, watched);
2614 CFRelease(watched);
2615 updated = TRUE;
2616 }
2617 }
2618 }
2619
2620 if (updated) {
2621 static dispatch_once_t once;
2622 CFRunLoopRef rl = CFRunLoopGetCurrent();
2623
2624 dispatch_once(&once, ^{
2625 // watch for "Host attached"
2626 watchTrustedStatus(kLockdownNotificationHostAttached,
2627 CFSTR("Host attached"));
2628
2629 // watch for "Host detached"
2630 watchTrustedStatus(kLockdownNotificationHostDetached,
2631 CFSTR("Host detached"));
2632
2633 // watch for "Trusted host attached"
2634 watchTrustedStatus(kLockdownNotificationTrustedHostAttached,
2635 CFSTR("Trusted Host attached"));
2636
2637 // watch for "Trusted PDP attached"
2638 watchTrustedStatus(kLockdownNotificationTrustedPTPAttached,
2639 CFSTR("Trusted PTP attached"));
2640 });
2641
2642 CFRetain(rl);
2643 dispatch_async(trustRequired_queue(), ^{
2644 trustRequiredNotification_update(rl, CFSTR("TrustRequired interface added"));
2645 CFRelease(rl);
2646 });
2647 }
2648
2649 return;
2650 }
2651 #endif // TARGET_OS_IPHONE
2652
2653
2654 #pragma mark -
2655 #pragma mark Pre-configured interface support
2656
2657
2658 static void
2659 sharePreconfigured()
2660 {
2661 CFIndex n;
2662
2663 n = (S_preconfigured != NULL) ? CFArrayGetCount(S_preconfigured) : 0;
2664 if (n > 0) {
2665 CFMutableArrayRef preconfigured;
2666
2667 preconfigured = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2668
2669 for (CFIndex i = 0; i < n; i++) {
2670 CFStringRef bsdName;
2671 CFDataRef watched = CFArrayGetValueAtIndex(S_preconfigured, i);
2672 WatchedInfo *watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
2673
2674 bsdName = SCNetworkInterfaceGetBSDName(watchedInfo->interface);
2675 if (bsdName == NULL) {
2676 SC_log(LOG_NOTICE, "pre-configured interface w/no BSD name");
2677 SC_log(LOG_NOTICE, " interface = %@", watchedInfo->interface);
2678 continue;
2679 }
2680 CFArrayAppendValue(preconfigured, bsdName);
2681 }
2682
2683 CFDictionarySetValue(S_state, kInterfaceNamerKey_PreConfiguredInterfaces, preconfigured);
2684 CFRelease(preconfigured);
2685 } else {
2686 CFDictionaryRemoveValue(S_state, kInterfaceNamerKey_PreConfiguredInterfaces);
2687 }
2688
2689 updateStore();
2690
2691 return;
2692 }
2693
2694 static void
2695 preconfiguredInterfaceUpdated(CFDataRef watched, natural_t messageType, void *messageArgument)
2696 {
2697 Boolean updated = FALSE;
2698 WatchedInfo *watchedInfo = (WatchedInfo *)(void *)CFDataGetBytePtr(watched);
2699
2700 #pragma unused(messageArgument)
2701 switch (messageType) {
2702 case kIOMessageServiceIsTerminated : { // if [locked] interface yanked
2703 CFStringRef bsdName;
2704
2705 bsdName = SCNetworkInterfaceGetBSDName(watchedInfo->interface);
2706 if (bsdName != NULL) {
2707 SC_log(LOG_INFO, "[pre-configured] interface removed: %@", bsdName);
2708 } else {
2709 SC_log(LOG_INFO, "[pre-configured] interface w/no BSD name removed");
2710 SC_log(LOG_INFO, " interface = %@", watchedInfo->interface);
2711 }
2712
2713 if (S_preconfigured != NULL) {
2714 CFIndex i;
2715 CFIndex n = CFArrayGetCount(S_preconfigured);
2716
2717 i = CFArrayGetFirstIndexOfValue(S_preconfigured, CFRangeMake(0, n), watched);
2718 if (i != kCFNotFound) {
2719 CFArrayRemoveValueAtIndex(S_preconfigured, i);
2720 if (CFArrayGetCount(S_preconfigured) == 0) {
2721 CFRelease(S_preconfigured);
2722 S_preconfigured = NULL;
2723 }
2724 updated = TRUE;
2725 }
2726 }
2727
2728 break;
2729 }
2730
2731 default :
2732 return;
2733 }
2734
2735 if (updated) {
2736 sharePreconfigured();
2737 }
2738
2739 return;
2740 }
2741
2742 static void
2743 updatePreConfiguredInterfaces(CFArrayRef interfaces)
2744 {
2745 CFIndex n;
2746 Boolean updated = FALSE;
2747
2748 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
2749 for (CFIndex i = 0; i < n; i++) {
2750 SCNetworkInterfaceRef interface;
2751
2752 interface = CFArrayGetValueAtIndex(interfaces, i);
2753 if (_SCNetworkInterfaceIsApplePreconfigured(interface) &&
2754 !isWatchedInterface(S_preconfigured, interface)) {
2755 CFDataRef watched;
2756
2757 watched = watcherCreate(interface, preconfiguredInterfaceUpdated);
2758 if (watched != NULL) {
2759 CFStringRef bsdName;
2760
2761 bsdName = SCNetworkInterfaceGetBSDName(interface);
2762 if (bsdName != NULL) {
2763 SC_log(LOG_INFO, "watching [pre-configured] interface: %@", bsdName);
2764 } else {
2765 SC_log(LOG_INFO, "watching [pre-configured] interface w/no BSD name");
2766 SC_log(LOG_INFO, " interface = %@", interface);
2767 }
2768
2769 if (S_preconfigured == NULL) {
2770 S_preconfigured = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2771 }
2772 CFArrayAppendValue(S_preconfigured, watched);
2773 CFRelease(watched);
2774 updated = TRUE;
2775 }
2776 }
2777 }
2778
2779 if (updated) {
2780 sharePreconfigured();
2781 }
2782
2783 return;
2784 }
2785
2786
2787 #pragma mark -
2788 #pragma mark Interface naming
2789
2790
2791 static __inline__ boolean_t
2792 isQuiet(void)
2793 {
2794 return (S_quiet == MACH_PORT_NULL);
2795 }
2796
2797 static Boolean
2798 wasPreviouslyUsedInterface(CFDictionaryRef dbdict, SCNetworkInterfaceRef interface)
2799 {
2800 CFArrayRef matchingMACs;
2801
2802 matchingMACs = CFDictionaryGetValue(dbdict, CFSTR(kSCNetworkInterfaceMatchingMACs));
2803 if (matchingMACs != NULL) {
2804 CFDataRef addr;
2805
2806 addr = _SCNetworkInterfaceGetHardwareAddress(interface);
2807 if (addr != NULL) {
2808 if (CFArrayContainsValue(matchingMACs,
2809 CFRangeMake(0, CFArrayGetCount(matchingMACs)),
2810 addr)) {
2811 return TRUE;
2812 }
2813 }
2814 }
2815
2816 return FALSE;
2817 }
2818
2819 static void
2820 nameInterfaces(CFMutableArrayRef if_list)
2821 {
2822 CFIndex i;
2823 CFIndex n = CFArrayGetCount(if_list);
2824
2825 for (i = 0; i < n; i++) {
2826 uint64_t entryID;
2827 SCNetworkInterfaceRef interface;
2828 SCNetworkInterfaceRef new_interface;
2829 CFStringRef path;
2830 CFStringRef prefix;
2831 CFNumberRef unit;
2832 CFIndex where;
2833
2834 interface = CFArrayGetValueAtIndex(if_list, i);
2835 path = _SCNetworkInterfaceGetIOPath(interface);
2836 prefix = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface);
2837 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
2838 entryID = _SCNetworkInterfaceGetIORegistryEntryID(interface);
2839
2840 if (unit != NULL) {
2841 CFStringRef if_name;
2842
2843 if_name = SCNetworkInterfaceGetBSDName(interface);
2844 if ((if_name == NULL) || !CFDictionaryContainsKey(S_state, if_name)) {
2845 SC_log(LOG_INFO, "Interface already has a unit number");
2846 displayInterface(interface);
2847 }
2848
2849 // update the list of interfaces that were previously named
2850 if ((S_prev_active_list != NULL)
2851 && lookupInterfaceByAddress(S_prev_active_list, interface, &where) != NULL) {
2852 CFArrayRemoveValueAtIndex(S_prev_active_list, where);
2853 }
2854
2855 replaceInterface(interface);
2856 } else {
2857 CFDictionaryRef dbdict;
2858 boolean_t is_builtin;
2859 kern_return_t kr;
2860 int retries = 0;
2861
2862 dbdict = lookupInterfaceByAddress(S_dblist, interface, NULL);
2863 if (dbdict != NULL) {
2864 unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit));
2865 CFRetain(unit);
2866
2867 SC_log(LOG_INFO, "Interface assigned unit %@ (from database)", unit);
2868 }
2869
2870 if ((dbdict == NULL) && !isQuiet()) {
2871 // if new interface, wait until quiet before naming
2872 addTimestamp(S_state, path);
2873 continue;
2874 }
2875
2876 is_builtin = _SCNetworkInterfaceIsBuiltin(interface);
2877
2878 if (dbdict == NULL) {
2879 dbdict = lookupMatchingInterface(interface,
2880 S_dblist,
2881 if_list,
2882 i + 1,
2883 is_builtin ? kCFBooleanTrue : kCFBooleanFalse);
2884
2885 if ((dbdict != NULL) && wasPreviouslyUsedInterface(dbdict, interface)) {
2886 unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit));
2887 CFRetain(unit);
2888
2889 SC_log(LOG_INFO, "Interface assigned unit %@ (updating database w/previously used interface)", unit);
2890 }
2891
2892 #if !TARGET_OS_IPHONE
2893 if ((unit == NULL) &&
2894 !is_builtin &&
2895 (dbdict != NULL) &&
2896 blockNewInterfaces() &&
2897 !_SCNetworkInterfaceIsApplePreconfigured(interface) &&
2898 isConsoleLocked()) {
2899 CFStringRef addr;
2900
2901 // if new (but matching) interface and console locked, ignore
2902 addr = SCNetworkInterfaceGetHardwareAddressString(interface);
2903 SC_log(LOG_NOTICE, "Console locked, network interface* ignored");
2904 SC_log(LOG_INFO, " path = %@, addr = %@",
2905 path,
2906 (addr != NULL) ? addr : CFSTR("?"));
2907 watchLockedInterface(interface);
2908 continue;
2909 }
2910 #endif // !TARGET_OS_IPHONE
2911
2912 if ((unit == NULL) && (dbdict != NULL)) {
2913 unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit));
2914 CFRetain(unit);
2915
2916 SC_log(LOG_INFO, "Interface assigned unit %@ (updating database w/new interface)", unit);
2917 }
2918 }
2919
2920 if ((dbdict != NULL) && (S_prev_active_list != NULL)) {
2921 // update the list of interfaces that were previously named
2922 where = CFArrayGetFirstIndexOfValue(S_prev_active_list,
2923 CFRangeMake(0, CFArrayGetCount(S_prev_active_list)),
2924 dbdict);
2925 if (where != kCFNotFound) {
2926 CFArrayRemoveValueAtIndex(S_prev_active_list, where);
2927 }
2928 }
2929
2930 if (dbdict == NULL) {
2931 int next_unit = 0;
2932
2933 if (is_builtin) {
2934 // built-in interface, try to use the reserved slots
2935 next_unit = builtinCount(if_list, i, prefix);
2936
2937 // But, before claiming a reserved slot we check to see if the
2938 // slot had previously been used. If so, and if the slot had been
2939 // assigned to the same type of interface, then we will perform a
2940 // replacement (e.g. assume that this was a board swap). But, if
2941 // the new interface is a different type then we assume that the
2942 // built-in configuration has changed and allocate a new unit from
2943 // the non-reserved slots.
2944
2945 unit = CFNumberCreate(NULL, kCFNumberIntType, &next_unit);
2946 if (!builtinAvailable(interface, unit)) {
2947 // if [built-in] unit not available
2948 SC_log(LOG_INFO, "Interface not assigned [built-in] unit %@", unit);
2949 CFRelease(unit);
2950 unit = NULL;
2951 }
2952 }
2953
2954 #if !TARGET_OS_IPHONE
2955 if (!is_builtin &&
2956 (unit == NULL) &&
2957 blockNewInterfaces() &&
2958 !_SCNetworkInterfaceIsApplePreconfigured(interface) &&
2959 isConsoleLocked()) {
2960 CFStringRef addr;
2961
2962 // if new interface and console locked, ignore
2963 addr = SCNetworkInterfaceGetHardwareAddressString(interface);
2964 SC_log(LOG_NOTICE, "Console locked, network interface ignored");
2965 SC_log(LOG_INFO, " path = %@, addr = %@",
2966 path,
2967 (addr != NULL) ? addr : CFSTR("?"));
2968 watchLockedInterface(interface);
2969 continue;
2970 }
2971 #endif // !TARGET_OS_IPHONE
2972
2973 if (unit == NULL) {
2974 // not built-in (or built-in unit not available), allocate from
2975 // the non-reserved slots
2976 next_unit = builtinCount(if_list, n, prefix);
2977 next_unit = getNextUnitForPrefix(prefix, next_unit);
2978 unit = CFNumberCreate(NULL, kCFNumberIntType, &next_unit);
2979 }
2980
2981 SC_log(LOG_INFO, "Interface assigned unit %@ (%s)",
2982 unit,
2983 is_builtin ? "built-in" : "next available");
2984 }
2985
2986 retry :
2987
2988 #ifdef USE_REGISTRY_ENTRY_ID
2989 kr = registerInterfaceWithIORegistryEntryID(S_connect,
2990 entryID,
2991 unit,
2992 (dbdict == NULL) ? kIONetworkStackRegisterInterfaceWithLowestUnit
2993 : kIONetworkStackRegisterInterfaceWithUnit);
2994 new_interface = copyNamedInterfaceForIORegistryEntryID(entryID);
2995 #else // USE_REGISTRY_ENTRY_ID
2996 kr = registerInterfaceWithIOServicePath(S_connect,
2997 path,
2998 unit,
2999 (dbdict == NULL) ? kRegisterInterface
3000 : kRegisterInterfaceWithFixedUnit);
3001 new_interface = copyNamedInterfaceForIOKitPath(path);
3002 #endif // USE_REGISTRY_ENTRY_ID
3003 if (new_interface == NULL) {
3004 const char *signature;
3005
3006 signature = (dbdict == NULL) ? "failed to name new interface"
3007 : "failed to name known interface";
3008
3009 SC_log(LOG_NOTICE, "%s, kr=0x%x\n"
3010 " path = %@\n"
3011 " id = 0x%llx\n"
3012 " unit = %@",
3013 signature,
3014 kr,
3015 path,
3016 entryID,
3017 unit);
3018
3019 displayInterface(interface);
3020
3021 if ((dbdict != NULL) && (retries++ < 5)) {
3022 usleep(50 * 1000); // sleep 50ms between attempts
3023 goto retry;
3024 }
3025 }
3026 else {
3027 CFNumberRef new_unit;
3028
3029 if (retries > 0) {
3030 SC_log(LOG_INFO, "%s interface named after %d %s\n"
3031 " path = %@\n"
3032 " unit = %@",
3033 (dbdict == NULL) ? "New" : "Known",
3034 retries,
3035 (retries == 1) ? "try" : "tries",
3036 path,
3037 unit);
3038
3039 #ifdef SHOW_NAMING_FAILURE
3040 str = CFStringCreateWithFormat(NULL,
3041 NULL,
3042 CFSTR("\"%s\" interface named after %d %s, unit = %@"),
3043 (dbdict == NULL) ? "New" : "Known",
3044 retries,
3045 (retries == 1) ? "try" : "tries",
3046 unit);
3047 CFUserNotificationDisplayNotice(0,
3048 kCFUserNotificationStopAlertLevel,
3049 NULL,
3050 NULL,
3051 NULL,
3052 str,
3053 CFSTR("Please report repeated failures."),
3054 NULL);
3055 CFRelease(str);
3056 #endif // SHOW_NAMING_FAILURE
3057 }
3058
3059 new_unit = _SCNetworkInterfaceGetIOInterfaceUnit(new_interface);
3060 if (!CFEqual(unit, new_unit)) {
3061 SC_log(LOG_INFO, "interface prefix %@ assigned unit %@ instead of %@",
3062 prefix, new_unit, unit);
3063 }
3064
3065 displayInterface(new_interface);
3066
3067 // update if_list (with the interface name & unit)
3068 CFArraySetValueAtIndex(if_list, i, new_interface);
3069 CFRelease(new_interface);
3070 interface = new_interface; // if_list holds the reference
3071
3072 if (is_builtin && (S_prev_active_list != NULL)) {
3073 CFIndex where;
3074
3075 // update the list of [built-in] interfaces that were previously named
3076 if (lookupInterfaceByUnit(S_prev_active_list, interface, &where) != NULL) {
3077 SC_log(LOG_DEBUG, " and updated database (new address)");
3078 CFArrayRemoveValueAtIndex(S_prev_active_list, where);
3079 }
3080 }
3081 replaceInterface(interface);
3082 }
3083 CFRelease(unit);
3084 }
3085 }
3086 return;
3087 }
3088
3089 #if !TARGET_OS_IPHONE
3090
3091 #define INSTALL_ENVIRONMENT "__OSINSTALL_ENVIRONMENT"
3092
3093 static Boolean
3094 isRecoveryOS()
3095 {
3096 static Boolean isRecovery = FALSE;
3097 static dispatch_once_t once;
3098
3099 /*
3100 * We check to see if the __OSINSTALL_ENVIRONMENT env var is present. If
3101 * so, then we are most likely booted into the Recovery OS with no [Aqua]
3102 * "SCMonitor" [UserEventAgent] plugin.
3103 */
3104 dispatch_once(&once, ^{
3105 if (getenv(INSTALL_ENVIRONMENT) != NULL) {
3106 isRecovery = TRUE;
3107 }
3108
3109 });
3110
3111 return isRecovery;
3112 }
3113
3114 static void
3115 updateNetworkConfiguration(CFArrayRef if_list)
3116 {
3117 Boolean do_commit = FALSE;
3118 CFIndex i;
3119 CFIndex n;
3120 SCPreferencesRef prefs = NULL;
3121 SCNetworkSetRef set = NULL;
3122
3123 prefs = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME ":updateNetworkConfiguration"), NULL);
3124 if (prefs == NULL) {
3125 SC_log(LOG_NOTICE, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
3126 return;
3127 }
3128
3129 set = SCNetworkSetCopyCurrent(prefs);
3130 if (set == NULL) {
3131 SC_log(LOG_INFO, "No current set, adding default");
3132 set = _SCNetworkSetCreateDefault(prefs);
3133 if (set == NULL) {
3134 SC_log(LOG_NOTICE, "_SCNetworkSetCreateDefault() failed: %s", SCErrorString(SCError()));
3135 goto done;
3136 }
3137 }
3138
3139 n = (if_list != NULL) ? CFArrayGetCount(if_list) : 0;
3140 for (i = 0; i < n; i++) {
3141 SCNetworkInterfaceRef interface;
3142
3143 interface = CFArrayGetValueAtIndex(if_list, i);
3144 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set, interface)) {
3145 SC_log(LOG_INFO, "adding default configuration for %@",
3146 SCNetworkInterfaceGetBSDName(interface));
3147 do_commit = TRUE;
3148 }
3149 }
3150
3151 if (do_commit) {
3152 Boolean ok;
3153
3154 ok = SCPreferencesCommitChanges(prefs);
3155 if (!ok) {
3156 SC_log(LOG_NOTICE, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError()));
3157 goto done;
3158 }
3159
3160 ok = SCPreferencesApplyChanges(prefs);
3161 if (!ok) {
3162 SC_log(LOG_NOTICE, "SCPreferencesApplyChanges() failed: %s", SCErrorString(SCError()));
3163 goto done;
3164 }
3165 }
3166
3167 done :
3168
3169 if (set != NULL) {
3170 CFRelease(set);
3171 set = NULL;
3172 }
3173
3174 if (prefs != NULL) {
3175 CFRelease(prefs);
3176 prefs = NULL;
3177 }
3178
3179 return;
3180 }
3181 #endif // !TARGET_OS_IPHONE
3182
3183 static void
3184 upgradeNetworkConfiguration()
3185 {
3186 static dispatch_once_t once;
3187
3188 /*
3189 * Once, per start of InterfaceNamer, we check/ensure that the
3190 * configuration has been upgraded.
3191 *
3192 * Note: this check should not be performed until we know that
3193 * the __wait_for_IOKit_to_quiesce() conditions have been
3194 * satisfied.
3195 */
3196
3197 dispatch_once(&once, ^{
3198 SCPreferencesRef ni_prefs;
3199 Boolean updated;
3200
3201 // save the [current] DB with the interfaces that have been named
3202 writeInterfaceList(S_dblist);
3203
3204 // upgrade the configuration
3205 ni_prefs = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME ":upgradeNetworkConfiguration"), INTERFACES_DEFAULT_CONFIG);
3206 if (ni_prefs == NULL) {
3207 SC_log(LOG_NOTICE, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
3208 return;
3209 }
3210 updated = __SCNetworkConfigurationUpgrade(NULL, &ni_prefs, TRUE);
3211 CFRelease(ni_prefs);
3212
3213 if (updated) {
3214 // re-read list of previously named network interfaces
3215 if (S_dblist != NULL) {
3216 CFRelease(S_dblist);
3217 }
3218 S_dblist = readInterfaceList();
3219
3220 addTimestamp(S_state, CFSTR("*UPGRADED*"));
3221 SC_log(LOG_INFO, "network configuration upgraded");
3222 updateStore();
3223 }
3224 });
3225
3226 return;
3227 }
3228
3229 static void
3230 removeInactiveInterfaces(void)
3231 {
3232 CFIndex n;
3233
3234 /*
3235 * remove any previous interfaces that were built-in,
3236 * were active, and were hidden (pre-configured) that
3237 * are no longer plugged in.
3238 */
3239
3240 if ((S_dblist == NULL) || (S_prev_active_list == NULL)) {
3241 return;
3242 }
3243
3244 n = CFArrayGetCount(S_prev_active_list);
3245 for (CFIndex i = n - 1; i >= 0; i--) {
3246 CFBooleanRef builtin;
3247 CFBooleanRef hidden;
3248 CFDictionaryRef if_dict;
3249 CFDictionaryRef info;
3250 CFStringRef name;
3251 CFIndex where;
3252
3253 if_dict = CFArrayGetValueAtIndex(S_prev_active_list, i);
3254
3255 // Note: keep the following logic in sync with _SCNetworkInterfaceIsApplePreconfigured()
3256
3257 name = CFDictionaryGetValue(if_dict, CFSTR(kIOBSDNameKey));
3258 if (!isA_CFString(name)) {
3259 // if no BSD name
3260 continue;
3261 }
3262
3263 hidden = CFDictionaryGetValue(if_dict, kSCNetworkInterfaceHiddenConfigurationKey);
3264 if (!isA_CFBoolean(hidden) || !CFBooleanGetValue(hidden)) {
3265 // if not hidden
3266 continue;
3267 }
3268
3269 builtin = CFDictionaryGetValue(if_dict, CFSTR(kIOBuiltin));
3270 if (isA_CFBoolean(builtin) && CFBooleanGetValue(builtin)) {
3271 // if [hidden] builtin
3272 goto remove;
3273 }
3274
3275 info = CFDictionaryGetValue(if_dict, CFSTR(kSCNetworkInterfaceInfo));
3276 if (isA_CFDictionary(info)) {
3277 int vid;
3278 CFNumberRef vidNum;
3279
3280 if (CFDictionaryGetValueIfPresent(info, CFSTR(kUSBVendorID), (const void **)&vidNum) &&
3281 isA_CFNumber(vidNum) &&
3282 CFNumberGetValue(vidNum, kCFNumberIntType, &vid) &&
3283 (vid == kIOUSBAppleVendorID)) {
3284 // if [hidden] Apple interface
3285
3286 #if TARGET_OS_OSX
3287 if (sharingConfigurationUsesInterface(name, TRUE)) {
3288 // do not remove interfaces referenced in the sharing configuration
3289 continue;
3290 }
3291 #endif // TARGET_OS_OSX
3292
3293 goto remove;
3294 }
3295 }
3296
3297 continue;
3298
3299 remove :
3300
3301 SC_log(LOG_INFO, "Removing no-longer-active \"hidden\" interface: %@", name);
3302
3303 if (lookupInterfaceByName(S_dblist, name, &where) != NULL) {
3304 // remove from the list of interfaces we know about
3305 CFArrayRemoveValueAtIndex(S_dblist, where);
3306 // remove from the previously active list
3307 CFArrayRemoveValueAtIndex(S_prev_active_list, i);
3308 }
3309 }
3310
3311 #if TARGET_OS_OSX
3312 sharingConfigurationClose();
3313 #endif // TARGET_OS_OSX
3314
3315 return;
3316 }
3317
3318 static void
3319 reportInactiveInterfaces(void)
3320 {
3321 CFIndex n;
3322
3323 /*
3324 * report any previous interfaces that are not [yet] active
3325 */
3326
3327 if (S_prev_active_list == NULL) {
3328 return;
3329 }
3330
3331 n = CFArrayGetCount(S_prev_active_list);
3332 if (n > 0) {
3333 SC_log(LOG_INFO, "Interface%s not [yet] active",
3334 (n > 1) ? "s" : "");
3335 }
3336 for (CFIndex i = 0; i < n; i++) {
3337 CFDictionaryRef if_dict;
3338 CFStringRef name;
3339 CFStringRef prefix;
3340 CFNumberRef unit;
3341
3342 if_dict = CFArrayGetValueAtIndex(S_prev_active_list, i);
3343 name = CFDictionaryGetValue(if_dict, CFSTR(kIOBSDNameKey));
3344 prefix = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceNamePrefix));
3345 unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit));
3346 SC_log(LOG_INFO, " %s%@%sPrefix: %@, Unit: %@",
3347 (name != NULL) ? "BSD Name: " : "",
3348 (name != NULL) ? name : CFSTR(""),
3349 (name != NULL) ? ", " : "",
3350 prefix,
3351 unit);
3352 }
3353
3354 return;
3355 }
3356
3357 static void
3358 updateInterfaces(void)
3359 {
3360 if (S_connect == MACH_PORT_NULL) {
3361 // if we don't have the "IONetworkStack" connect object
3362 return;
3363 }
3364
3365 if (S_iflist != NULL) {
3366 CFIndex n;
3367
3368 n = CFArrayGetCount(S_iflist);
3369 if (n > 1) {
3370 CFArraySortValues(S_iflist, CFRangeMake(0, n), _SCNetworkInterfaceCompare, NULL);
3371 }
3372 nameInterfaces(S_iflist);
3373 }
3374
3375 /*
3376 * Update the list of [Apple] pre-configured interfaces
3377 */
3378 updatePreConfiguredInterfaces(S_iflist);
3379
3380 #if TARGET_OS_IPHONE
3381 /*
3382 * Update the list of "trust required" interfaces
3383 */
3384 if (haveLockdown()) {
3385 updateTrustRequiredInterfaces(S_iflist);
3386 }
3387 #endif // TARGET_OS_IPHONE
3388
3389 if (isQuiet()) {
3390 /*
3391 * The registry [matching] has quiesced
3392 */
3393
3394 // remove any inactive interfaces
3395 removeInactiveInterfaces();
3396
3397 // save the DB with the interfaces that have been named
3398 writeInterfaceList(S_dblist);
3399
3400 // update the VLAN/BOND configuration
3401 updateVirtualNetworkInterfaceConfiguration(NULL, kSCPreferencesNotificationApply, NULL);
3402
3403 #if !TARGET_OS_IPHONE
3404 if (isRecoveryOS()) {
3405 /*
3406 * We are most likely booted into the Recovery OS with no "SCMonitor"
3407 * UserEventAgent plugin running so let's make sure we update the
3408 * network configuration for new interfaces.
3409 */
3410 updateNetworkConfiguration(S_iflist);
3411 }
3412 #endif // !TARGET_OS_IPHONE
3413
3414 // tell everyone that we've finished (at least for now)
3415 updateStore();
3416
3417 // log those interfaces which are no longer present in
3418 // the HW config (or have yet to show up).
3419 reportInactiveInterfaces();
3420
3421 if (S_prev_active_list != NULL) {
3422 CFRelease(S_prev_active_list);
3423 S_prev_active_list = NULL;
3424 }
3425
3426 if (S_iflist != NULL) {
3427 CFRelease(S_iflist);
3428 S_iflist = NULL;
3429 }
3430 } else {
3431 if ((S_prev_active_list != NULL) && (CFArrayGetCount(S_prev_active_list) == 0)) {
3432 /*
3433 * if we've named all of the interfaces that
3434 * were used during the previous boot.
3435 */
3436 addTimestamp(S_state, kInterfaceNamerKey_Complete);
3437 SC_log(LOG_INFO, "last boot interfaces have been named");
3438 updateStore();
3439 CFRelease(S_prev_active_list);
3440 S_prev_active_list = NULL;
3441 }
3442 }
3443
3444 return;
3445 }
3446
3447 static void
3448 interfaceArrivalCallback(void *refcon, io_iterator_t iter)
3449 {
3450 #pragma unused(refcon)
3451 io_object_t obj;
3452
3453 while ((obj = IOIteratorNext(iter)) != MACH_PORT_NULL) {
3454 SCNetworkInterfaceRef interface;
3455
3456 interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj);
3457 if (interface != NULL) {
3458 if (S_iflist == NULL) {
3459 S_iflist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3460 }
3461 CFArrayAppendValue(S_iflist, interface);
3462 CFRelease(interface);
3463 }
3464 IOObjectRelease(obj);
3465 }
3466
3467 updateInterfaces();
3468
3469 return;
3470 }
3471
3472 /*
3473 * Function: stackCallback
3474 * Purpose:
3475 * Get a reference to the single IONetworkStack object instance in
3476 * the kernel. Naming requests must be sent to this object, which is
3477 * attached as a client to all network interface objects in the system.
3478 * Note:
3479 * Call IOObjectRelease on the returned object.
3480 */
3481 static void
3482 stackCallback(void *refcon, io_iterator_t iter)
3483 {
3484 #pragma unused(refcon)
3485 kern_return_t kr;
3486 io_object_t stack;
3487
3488 stack = IOIteratorNext(iter);
3489 if (stack == MACH_PORT_NULL) {
3490 goto error;
3491 }
3492
3493 kr = IOServiceOpen(stack, mach_task_self(), 0, &S_connect);
3494 if (kr != KERN_SUCCESS) {
3495 SC_log(LOG_ERR, "IOServiceOpen returned 0x%x", kr);
3496 goto error;
3497 }
3498
3499 addTimestamp(S_state, CFSTR("*STACK*"));
3500 SC_log(LOG_INFO, "IONetworkStack found");
3501
3502 if (S_stack != MACH_PORT_NULL) {
3503 IOObjectRelease(S_stack);
3504 S_stack = MACH_PORT_NULL;
3505 }
3506
3507 if ((S_timer != NULL) && CFRunLoopTimerIsValid(S_timer)) {
3508 // With the IONetworkStack object now available we can
3509 // reset (shorten?) the time we are willing to wait for
3510 // IOKit to quiesce.
3511 CFRunLoopTimerSetNextFireDate(S_timer,
3512 CFAbsoluteTimeGetCurrent() + S_quiet_timeout);
3513 }
3514
3515 updateInterfaces();
3516
3517 error:
3518
3519 if (stack != MACH_PORT_NULL) {
3520 IOObjectRelease(stack);
3521 }
3522
3523 return;
3524 }
3525
3526 static void
3527 quietCallback(void *refcon,
3528 io_service_t service,
3529 natural_t messageType,
3530 void *messageArgument)
3531 {
3532 #pragma unused(refcon)
3533 #pragma unused(service)
3534 if (messageArgument != NULL) {
3535 // if not yet quiet
3536 return;
3537 }
3538
3539 if (messageType == kIOMessageServiceBusyStateChange) {
3540 addTimestamp(S_state, kInterfaceNamerKey_Quiet);
3541 SC_log(LOG_INFO, "IOKit quiet");
3542 }
3543
3544 if (S_connect == MACH_PORT_NULL) {
3545 SC_log(LOG_ERR, "No network stack object");
3546 return;
3547 }
3548
3549 if (S_quiet != MACH_PORT_NULL) {
3550 IOObjectRelease(S_quiet);
3551 S_quiet = MACH_PORT_NULL;
3552 }
3553
3554 if (S_timer != NULL) {
3555 CFRunLoopTimerInvalidate(S_timer);
3556 CFRelease(S_timer);
3557 S_timer = NULL;
3558 }
3559
3560 // grab (and name) any additional interfaces.
3561 interfaceArrivalCallback((void *)S_notify, S_iter);
3562
3563 if (messageType == kIOMessageServiceBusyStateChange) {
3564 addTimestamp(S_state, CFSTR("*QUIET&NAMED*"));
3565 updateStore();
3566 upgradeNetworkConfiguration();
3567 }
3568
3569 return;
3570 }
3571
3572 static void
3573 iterateRegistryBusy(io_iterator_t iterator, CFArrayRef nodes, int *count)
3574 {
3575 kern_return_t kr = kIOReturnSuccess;;
3576 io_object_t obj;
3577
3578 while ((kr == kIOReturnSuccess) &&
3579 ((obj = IOIteratorNext(iterator)) != MACH_PORT_NULL)) {
3580 uint64_t accumulated_busy_time;
3581 uint32_t busy_state;
3582 io_name_t location;
3583 io_name_t name;
3584 CFMutableArrayRef newNodes;
3585 uint64_t state;
3586 CFMutableStringRef str = NULL;
3587
3588 if (nodes == NULL) {
3589 newNodes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3590 } else {
3591 newNodes = CFArrayCreateMutableCopy(NULL, 0, nodes);
3592 }
3593 assert(newNodes != NULL);
3594
3595 kr = IORegistryEntryGetName(obj, name);
3596 if (kr != kIOReturnSuccess) {
3597 SC_log(LOG_NOTICE, "IORegistryEntryGetName() returned 0x%x", kr);
3598 goto next;
3599 }
3600
3601 str = CFStringCreateMutable(NULL, 0);
3602 CFStringAppendCString(str, name, kCFStringEncodingUTF8);
3603
3604 kr = IORegistryEntryGetLocationInPlane(obj, kIOServicePlane, location);
3605 switch (kr) {
3606 case kIOReturnSuccess :
3607 CFStringAppendCString(str, "@", kCFStringEncodingUTF8);
3608 CFStringAppendCString(str, location, kCFStringEncodingUTF8);
3609 break;
3610 case kIOReturnNotFound :
3611 break;
3612 default :
3613 SC_log(LOG_NOTICE, "IORegistryEntryGetLocationInPlane() returned 0x%x", kr);
3614 CFRelease(str);
3615 goto next;
3616 }
3617
3618 CFArrayAppendValue(newNodes, str);
3619 CFRelease(str);
3620
3621 kr = IOServiceGetBusyStateAndTime(obj, &state, &busy_state, &accumulated_busy_time);
3622 if (kr != kIOReturnSuccess) {
3623 SC_log(LOG_NOTICE, "IOServiceGetBusyStateAndTime() returned 0x%x", kr);
3624 goto next;
3625 }
3626
3627 #ifdef TEST_SNAPSHOT
3628 // report all nodes
3629 busy_state = 1;
3630 #endif // TEST_SNAPSHOT
3631
3632 if (busy_state != 0) {
3633 CFStringRef path;
3634
3635 if ((*count)++ == 0) {
3636 SC_log(LOG_ERR, "Busy services :");
3637 }
3638
3639 path = CFStringCreateByCombiningStrings(NULL, newNodes, CFSTR("/"));
3640 SC_log(LOG_ERR, " %@ [%s%s%s%d, %lld ms]",
3641 path,
3642 (state & kIOServiceRegisteredState) ? "" : "!registered, ",
3643 (state & kIOServiceMatchedState) ? "" : "!matched, ",
3644 (state & kIOServiceInactiveState) ? "inactive, " : "",
3645 busy_state,
3646 accumulated_busy_time / kMillisecondScale);
3647 CFRelease(path);
3648 }
3649
3650 kr = IORegistryIteratorEnterEntry(iterator);
3651 if (kr != kIOReturnSuccess) {
3652 SC_log(LOG_NOTICE, "IORegistryIteratorEnterEntry() returned 0x%x", kr);
3653 goto next;
3654 }
3655
3656 iterateRegistryBusy(iterator, newNodes, count);
3657
3658 kr = IORegistryIteratorExitEntry(iterator);
3659 if (kr != kIOReturnSuccess) {
3660 SC_log(LOG_NOTICE, "IORegistryIteratorExitEntry() returned 0x%x", kr);
3661 }
3662
3663 next :
3664
3665 CFRelease(newNodes);
3666 IOObjectRelease(obj);
3667 }
3668
3669 return;
3670 }
3671
3672 static void
3673 captureBusy()
3674 {
3675 int count = 0;
3676 io_iterator_t iterator = MACH_PORT_NULL;
3677 kern_return_t kr;
3678
3679 kr = IORegistryCreateIterator(kIOMasterPortDefault,
3680 kIOServicePlane,
3681 0,
3682 &iterator);
3683 if (kr != kIOReturnSuccess) {
3684 SC_log(LOG_NOTICE, "IORegistryCreateIterator() returned 0x%x", kr);
3685 return;
3686 }
3687
3688 iterateRegistryBusy(iterator, NULL, &count);
3689 if (count == 0) {
3690 SC_log(LOG_ERR, "w/no busy services");
3691 }
3692
3693 IOObjectRelease(iterator);
3694 }
3695
3696 static void
3697 timerCallback(CFRunLoopTimerRef timer, void *info)
3698 {
3699 #pragma unused(timer)
3700 #pragma unused(info)
3701 // We've been waiting for IOKit to quiesce and it just
3702 // hasn't happenned. Time to just move on!
3703 addTimestamp(S_state, kInterfaceNamerKey_Timeout);
3704
3705 // log busy nodes
3706 SC_log(LOG_ERR, "timed out waiting for IOKit to quiesce");
3707 captureBusy();
3708
3709 quietCallback((void *)S_notify, MACH_PORT_NULL, 0, NULL);
3710
3711 addTimestamp(S_state, CFSTR("*TIMEOUT&NAMED*"));
3712 updateStore();
3713 upgradeNetworkConfiguration();
3714
3715 return;
3716 }
3717
3718 static Boolean
3719 setup_IOKit(CFBundleRef bundle)
3720 {
3721 #pragma unused(bundle)
3722 uint32_t busy;
3723 kern_return_t kr;
3724 mach_port_t masterPort = MACH_PORT_NULL;
3725 Boolean ok = FALSE;
3726 io_object_t root = MACH_PORT_NULL;
3727
3728 // read DB of previously named network interfaces
3729 S_dblist = readInterfaceList();
3730
3731 // get interfaces that were named during the last boot
3732 S_prev_active_list = previouslyActiveInterfaces();
3733
3734 // track how long we've waited to see each interface.
3735 S_state = CFDictionaryCreateMutable(NULL,
3736 0,
3737 &kCFTypeDictionaryKeyCallBacks,
3738 &kCFTypeDictionaryValueCallBacks);
3739 addTimestamp(S_state, CFSTR("*START*"));
3740
3741 // Creates and returns a notification object for receiving IOKit
3742 // notifications of new devices or state changes.
3743 kr = IOMasterPort(bootstrap_port, &masterPort);
3744 if (kr != KERN_SUCCESS) {
3745 SC_log(LOG_ERR, "IOMasterPort returned 0x%x", kr);
3746 goto done;
3747 }
3748
3749 S_notify = IONotificationPortCreate(masterPort);
3750 if (S_notify == NULL) {
3751 SC_log(LOG_ERR, "IONotificationPortCreate failed");
3752 goto done;
3753 }
3754
3755 // watch IOKit matching activity
3756 root = IORegistryEntryFromPath(masterPort, kIOServicePlane ":/");
3757 if (root == MACH_PORT_NULL) {
3758 SC_log(LOG_ERR, "IORegistryEntryFromPath failed");
3759 goto done;
3760 }
3761
3762 kr = IOServiceAddInterestNotification(S_notify,
3763 root,
3764 kIOBusyInterest,
3765 &quietCallback,
3766 (void *)S_notify, // refCon
3767 &S_quiet); // notification
3768 if (kr != KERN_SUCCESS) {
3769 SC_log(LOG_ERR, "IOServiceAddInterestNotification returned 0x%x", kr);
3770 goto done;
3771 }
3772
3773 kr = IOServiceGetBusyState(root, &busy);
3774 if (kr != KERN_SUCCESS) {
3775 SC_log(LOG_ERR, "IOServiceGetBusyState returned 0x%x", kr);
3776 goto done;
3777 }
3778
3779 // add a timer so we don't wait forever for IOKit to quiesce
3780 S_timer = CFRunLoopTimerCreate(NULL,
3781 CFAbsoluteTimeGetCurrent() + S_stack_timeout,
3782 0,
3783 0,
3784 0,
3785 timerCallback,
3786 NULL);
3787 if (S_timer == NULL) {
3788 SC_log(LOG_ERR, "CFRunLoopTimerCreate failed");
3789 goto done;
3790 }
3791
3792 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, kCFRunLoopDefaultMode);
3793
3794 // watch for the introduction of the IONetworkStack
3795 kr = IOServiceAddMatchingNotification(S_notify,
3796 kIOFirstMatchNotification,
3797 IOServiceMatching("IONetworkStack"),
3798 &stackCallback,
3799 (void *)S_notify, // refCon
3800 &S_stack); // notification
3801 if (kr != KERN_SUCCESS) {
3802 SC_log(LOG_ERR, "IOServiceAddMatchingNotification returned 0x%x", kr);
3803 goto done;
3804 }
3805
3806 // check and see if the stack is already available and arm the
3807 // notification for its introduction.
3808 stackCallback((void *)S_notify, S_stack);
3809
3810 // watch for the introduction of new network interfaces
3811 kr = IOServiceAddMatchingNotification(S_notify,
3812 kIOFirstMatchNotification,
3813 IOServiceMatching("IONetworkInterface"),
3814 &interfaceArrivalCallback,
3815 (void *)S_notify, // refCon
3816 &S_iter); // notification
3817 if (kr != KERN_SUCCESS) {
3818 SC_log(LOG_ERR, "IOServiceAddMatchingNotification returned 0x%x", kr);
3819 goto done;
3820 }
3821
3822 // Get the current list of matches and arm the notification for
3823 // future interface arrivals.
3824 interfaceArrivalCallback((void *)S_notify, S_iter);
3825
3826 // Check if IOKit has already quiesced.
3827 quietCallback((void *)S_notify,
3828 MACH_PORT_NULL,
3829 kIOMessageServiceBusyStateChange,
3830 (void *)(uintptr_t)busy);
3831
3832 CFRunLoopAddSource(CFRunLoopGetCurrent(),
3833 IONotificationPortGetRunLoopSource(S_notify),
3834 kCFRunLoopDefaultMode);
3835
3836 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
3837 /*
3838 * Start the wheels turning until we've named all of
3839 * the interfaces that were used during the previous
3840 * boot, until IOKit [matching] has quiesced, or
3841 * until we've waited long enough.
3842 */
3843 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, MY_PLUGIN_ID);
3844 CFRunLoopAddSource(CFRunLoopGetCurrent(),
3845 IONotificationPortGetRunLoopSource(S_notify),
3846 MY_PLUGIN_ID);
3847 while (S_prev_active_list != NULL) {
3848 int rlStatus;
3849
3850 rlStatus = CFRunLoopRunInMode(MY_PLUGIN_ID, 1.0e10, TRUE);
3851 }
3852 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
3853
3854 #if TARGET_OS_OSX
3855 if (S_dblist != NULL) {
3856 // apply special handling for the BT-PAN interface (if present)
3857 CFArrayApplyFunction(S_dblist,
3858 CFRangeMake(0, CFArrayGetCount(S_dblist)),
3859 updateBTPANInformation,
3860 NULL);
3861 }
3862 #endif // TARGET_OS_OSX
3863
3864 ok = TRUE;
3865
3866 done:
3867 if (root != MACH_PORT_NULL) {
3868 IOObjectRelease(root);
3869 }
3870 if (masterPort != MACH_PORT_NULL) {
3871 mach_port_deallocate(mach_task_self(), masterPort);
3872 }
3873
3874 return ok;
3875 }
3876
3877 static Boolean
3878 setup_Virtual(CFBundleRef bundle)
3879 {
3880 #pragma unused(bundle)
3881 // open a SCPreferences session
3882 S_prefs = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME ":setup_Virtual"), NULL);
3883 if (S_prefs == NULL) {
3884 SC_log(LOG_ERR, "SCPreferencesCreate() failed: %s",
3885 SCErrorString(SCError()));
3886 return FALSE;
3887 }
3888
3889 // register for change notifications.
3890 if (!SCPreferencesSetCallback(S_prefs, updateVirtualNetworkInterfaceConfiguration, NULL)) {
3891 SC_log(LOG_ERR, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
3892 CFRelease(S_prefs);
3893 return FALSE;
3894 }
3895
3896 // schedule
3897 if (!SCPreferencesScheduleWithRunLoop(S_prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
3898 if (SCError() != kSCStatusNoStoreServer) {
3899 SC_log(LOG_ERR, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
3900 CFRelease(S_prefs);
3901 return FALSE;
3902 }
3903 }
3904
3905 return TRUE;
3906 }
3907
3908 static void *
3909 exec_InterfaceNamer(void *arg)
3910 {
3911 CFBundleRef bundle = (CFBundleRef)arg;
3912 CFDictionaryRef dict;
3913
3914 pthread_setname_np(MY_PLUGIN_NAME " thread");
3915
3916 dict = CFBundleGetInfoDictionary(bundle);
3917 if (isA_CFDictionary(dict)) {
3918 CFNumberRef num;
3919
3920 num = CFDictionaryGetValue(dict, CFSTR(WAIT_STACK_TIMEOUT_KEY));
3921 if (num != NULL) {
3922 if (!isA_CFNumber(num) ||
3923 !CFNumberGetValue(num, kCFNumberDoubleType, &S_stack_timeout) ||
3924 (S_stack_timeout <= 0.0)) {
3925 SC_log(LOG_NOTICE, WAIT_STACK_TIMEOUT_KEY " value error");
3926 S_stack_timeout = WAIT_STACK_TIMEOUT_DEFAULT;
3927 }
3928 }
3929
3930 num = CFDictionaryGetValue(dict, CFSTR(WAIT_QUIET_TIMEOUT_KEY));
3931 if (num != NULL) {
3932 if (!isA_CFNumber(num) ||
3933 !CFNumberGetValue(num, kCFNumberDoubleType, &S_quiet_timeout) ||
3934 (S_quiet_timeout <= 0.0)) {
3935 SC_log(LOG_NOTICE, WAIT_QUIET_TIMEOUT_KEY " value error");
3936 S_quiet_timeout = WAIT_QUIET_TIMEOUT_DEFAULT;
3937 }
3938 }
3939 }
3940
3941 // setup virtual network interface monitoring
3942 if (!setup_Virtual(bundle)) {
3943 goto error;
3944 }
3945
3946 // setup [IOKit] network interface monitoring
3947 if (!setup_IOKit(bundle)) {
3948 goto error;
3949 }
3950
3951 goto done;
3952
3953 error :
3954 if (S_connect != MACH_PORT_NULL) {
3955 IOServiceClose(S_connect);
3956 S_connect = MACH_PORT_NULL;
3957 }
3958 if (S_dblist != NULL) {
3959 CFRelease(S_dblist);
3960 S_dblist = NULL;
3961 }
3962 if (S_iter != MACH_PORT_NULL) {
3963 IOObjectRelease(S_iter);
3964 S_iter = MACH_PORT_NULL;
3965 }
3966 if (S_notify != MACH_PORT_NULL) {
3967 IONotificationPortDestroy(S_notify);
3968 }
3969 if (S_quiet != MACH_PORT_NULL) {
3970 IOObjectRelease(S_quiet);
3971 S_quiet = MACH_PORT_NULL;
3972 }
3973 if (S_stack != MACH_PORT_NULL) {
3974 IOObjectRelease(S_stack);
3975 S_stack = MACH_PORT_NULL;
3976 }
3977 if (S_state != NULL) {
3978 CFRelease(S_state);
3979 S_state = NULL;
3980 }
3981 if (S_timer != NULL) {
3982 CFRunLoopTimerInvalidate(S_timer);
3983 CFRelease(S_timer);
3984 S_timer = NULL;
3985 }
3986
3987 done :
3988 CFRelease(bundle);
3989 CFRunLoopRun();
3990
3991 return NULL;
3992 }
3993
3994 __private_extern__
3995 void
3996 load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose)
3997 {
3998 #pragma unused(bundleVerbose)
3999 pthread_attr_t tattr;
4000 pthread_t tid;
4001
4002 CFRetain(bundle); // released in exec_InterfaceNamer
4003
4004 pthread_attr_init(&tattr);
4005 pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
4006 pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
4007 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
4008 pthread_create(&tid, &tattr, exec_InterfaceNamer, bundle);
4009 pthread_attr_destroy(&tattr);
4010
4011 return;
4012 }
4013
4014 //------------------------------------------------------------------------
4015 // Main function.
4016 #ifdef TEST_INTERFACE_ASSIGNMENT
4017 int
4018 main(int argc, char ** argv)
4019 {
4020 #pragma unused(argv)
4021 CFBundleRef bundle;
4022 CFMutableArrayRef interfaces;
4023 CFArrayRef interfaces_all;
4024 CFIndex n;
4025
4026 _sc_log = kSCLogDestinationFile;
4027 _sc_verbose = (argc > 1) ? TRUE : FALSE;
4028
4029 bundle = CFBundleGetMainBundle();
4030 CFRetain(bundle); // released in exec_InterfaceNamer
4031
4032 // setup
4033 setup_IOKit(bundle);
4034
4035 // but, when running this test we know that the IORegistry has already quiesced
4036 IOObjectRelease(S_quiet);
4037 S_quiet = MACH_PORT_NULL;
4038
4039 // collect the interfaces
4040 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
4041 interfaces_all = SCNetworkInterfaceCopyAll();
4042 n = CFArrayGetCount(interfaces_all);
4043 for (CFIndex i = 0; i < n; i++) {
4044 SCNetworkInterfaceRef interface = CFArrayGetValueAtIndex(interfaces_all, i);
4045 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
4046
4047 if (interfacePrivate->prefix == NULL) {
4048 // skip interfaces with no kIOInterfaceNamePrefix property
4049 continue;
4050 }
4051
4052 if (interfacePrivate->unit != NULL) {
4053 // remove any already assigned unit #
4054 CFRelease(interfacePrivate->unit);
4055 interfacePrivate->unit = NULL;
4056 }
4057
4058 CFArrayAppendValue(interfaces, interface);
4059 }
4060 CFRelease(interfaces_all);
4061 SC_log(LOG_INFO, "interfaces = %@", interfaces);
4062
4063 // exercise the interface naming assignments
4064 nameInterfaces(interfaces);
4065 CFRelease(interfaces);
4066
4067 exit(0);
4068 return 0;
4069 }
4070 #endif /* MAIN */
4071
4072 #ifdef TEST_SNAPSHOT
4073 int
4074 main(int argc, char ** argv)
4075 {
4076 _sc_log = kSCLogDestinationFile;
4077 _sc_verbose = (argc > 1) ? TRUE : FALSE;
4078
4079 captureBusy();
4080
4081 exit(0);
4082 return 0;
4083 }
4084 #endif /* TEST_SNAPSHOT */
4085