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