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