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