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