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