]> git.saurik.com Git - apple/configd.git/blob - Plugins/InterfaceNamer/ifnamer.c
configd-289.tar.gz
[apple/configd.git] / Plugins / InterfaceNamer / ifnamer.c
1 /*
2 * Copyright (c) 2001-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * November 6, 2006 Allan Nathanson <ajn@apple.com>
28 * Dan Markarian <markarian@apple.com>
29 * Dieter Siegmund <dieter@apple.com>
30 * - updated code to name interfaces quicker (without need for
31 * calling IOKitWaitQuiet).
32 *
33 * October 3, 2003 Allan Nathanson <ajn@apple.com>
34 * - sort new interfaces by IOKit path (rather than MAC address) to
35 * help facilitate a more predictable interface-->name mapping for
36 * like hardware configurations.
37 *
38 * June 23, 2001 Allan Nathanson <ajn@apple.com>
39 * - update to public SystemConfiguration.framework APIs
40 *
41 * January 23, 2001 Dieter Siegmund <dieter@apple.com>
42 * - initial revision
43 */
44
45 /*
46 * ifnamer.c
47 * - module that receives IOKit Network Interface messages
48 * and names any interface that currently does not have a name
49 * - uses Interface Type and MACAddress as the unique identifying
50 * keys; any interface that doesn't contain both of these properties
51 * is ignored and not processed
52 * - stores the Interface Type, MACAddress, and Unit in permanent storage
53 * to give persistent interface names
54 */
55
56 #include <ctype.h>
57 #include <stdlib.h>
58 #include <stdio.h>
59 #include <unistd.h>
60 #include <fcntl.h>
61 #include <sys/sockio.h>
62 #include <sys/stat.h>
63 #include <sys/param.h>
64 #include <mach/mach.h>
65 #include <net/ethernet.h>
66 #include <net/if_types.h>
67
68 #include <CoreFoundation/CoreFoundation.h>
69
70 #include <SystemConfiguration/SystemConfiguration.h>
71 #include <SystemConfiguration/SCDPlugin.h>
72 #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
73 #include <SystemConfiguration/SCValidation.h>
74
75 #include <IOKit/IOKitLib.h>
76 #include <IOKit/IOBSD.h>
77 #include <IOKit/IOMessage.h>
78 #include <IOKit/network/IONetworkController.h>
79 #include <IOKit/network/IONetworkInterface.h>
80
81 #ifndef kIOBuiltin
82 #define kIOBuiltin "IOBuiltin"
83 #endif
84
85 #define kIONetworkStackUserCommand "IONetworkStackUserCommand"
86 #define kRegisterInterface 1
87
88 #define kSCNetworkInterfaceType "SCNetworkInterfaceType"
89 #define kSCNetworkInterfaceActive "Active"
90
91 #define MY_PLUGIN_NAME "InterfaceNamer"
92 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
93
94 #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout"
95 #define WAIT_QUIET_TIMEOUT_DEFAULT 60.0
96
97 /*
98 * S_connect
99 * "IONetworkStack" connect object used to "name" an interface.
100 */
101 static io_connect_t S_connect = MACH_PORT_NULL;
102
103 /*
104 * S_dblist
105 * An array of CFDictionary's representing the interfaces
106 * that have been identified and [need to be] named.
107 */
108 static CFMutableArrayRef S_dblist = NULL;
109
110 /*
111 * S_debug
112 * A boolean that enables additional logging.
113 */
114 static boolean_t S_debug = FALSE;
115
116 /*
117 * S_iflist
118 * An array of SCNetworkInterface's representing the
119 * interfaces that have been identified.
120 */
121 static CFMutableArrayRef S_iflist = NULL;
122
123 /*
124 * S_iter
125 * IOServiceAddMatchingNotification object used to watch for
126 * new network interfaces.
127 */
128 static io_iterator_t S_iter = MACH_PORT_NULL;
129
130 /*
131 * S_notify
132 * notification object for receiving IOKit notifications of
133 * new devices or state changes.
134 */
135 static IONotificationPortRef S_notify = NULL;
136
137 /* S_prev_active_list
138 * An array of CFDictionary's representing the previously
139 * named interfaces.
140 */
141 static CFMutableArrayRef S_prev_active_list = NULL;
142
143 /*
144 * S_quiet
145 * IOServiceAddInterestNotification object used to watch for
146 * IOKit matching to quiesce.
147 */
148 static io_object_t S_quiet = MACH_PORT_NULL;
149
150 /*
151 * S_stack
152 * IOServiceAddMatchingNotification object used to watch for
153 * the availability of the "IONetworkStack" object.
154 */
155 static io_iterator_t S_stack = MACH_PORT_NULL;
156
157 /*
158 * S_state
159 * A dictionary containing Information about each network
160 * interface. For now, the key is the BSD name and the
161 * value is a CFNumber noting how long (in milliseconds)
162 * it took for the interface to be recognized/named.
163 */
164 static CFMutableDictionaryRef S_state = NULL;
165
166 /*
167 * S_timer
168 * CFRunLoopTimer tracking how long we are willing to wait
169 * for IOKit matching to quiesce (IOKitWaitQuiet).
170 */
171 static CFRunLoopTimerRef S_timer = NULL;
172
173 #if !TARGET_OS_IPHONE
174 /*
175 * Virtual network interface configuration
176 * S_prefs : SCPreferences to configuration
177 * S_bonds : most recently actived Bond configuration
178 * S_vlans : most recently actived VLAN configuration
179 */
180 static SCPreferencesRef S_prefs = NULL;
181 static CFArrayRef S_bonds = NULL;
182 static CFArrayRef S_vlans = NULL;
183 #endif /* !TARGET_OS_IPHONE */
184
185 static void
186 addTimestamp(CFMutableDictionaryRef dict, CFStringRef key)
187 {
188 CFAbsoluteTime now;
189 CFNumberRef val;
190
191 now = CFAbsoluteTimeGetCurrent();
192 val = CFNumberCreate(NULL, kCFNumberDoubleType, &now);
193 CFDictionaryAddValue(dict, key, val);
194 CFRelease(val);
195 return;
196 }
197
198 static CFComparisonResult
199 if_unit_compare(const void *val1, const void *val2, void *context)
200 {
201 CFComparisonResult res;
202 CFNumberRef type1;
203 CFNumberRef type2;
204 CFNumberRef unit1;
205 CFNumberRef unit2;
206
207 type1 = CFDictionaryGetValue((CFDictionaryRef)val1,
208 CFSTR(kIOInterfaceType));
209 type2 = CFDictionaryGetValue((CFDictionaryRef)val2,
210 CFSTR(kIOInterfaceType));
211 res = CFNumberCompare(type1, type2, NULL);
212 if (res != kCFCompareEqualTo) {
213 return (res);
214 }
215 unit1 = CFDictionaryGetValue((CFDictionaryRef)val1,
216 CFSTR(kIOInterfaceUnit));
217 unit2 = CFDictionaryGetValue((CFDictionaryRef)val2,
218 CFSTR(kIOInterfaceUnit));
219 return (CFNumberCompare(unit1, unit2, NULL));
220 }
221
222 static void *
223 read_file(char * filename, size_t * data_length)
224 {
225 void * data = NULL;
226 size_t len = 0;
227 int fd = -1;
228 struct stat sb;
229
230 *data_length = 0;
231 if (stat(filename, &sb) == -1)
232 goto done;
233 len = sb.st_size;
234 if (len == 0)
235 goto done;
236
237 data = malloc(len);
238 if (data == NULL)
239 goto done;
240
241 fd = open(filename, O_RDONLY);
242 if (fd == -1)
243 goto done;
244
245 if (read(fd, data, len) != len) {
246 SCLog(TRUE, LOG_ERR,
247 CFSTR(MY_PLUGIN_NAME ": read %s failed, %s"),
248 filename, strerror(errno));
249 goto done;
250 }
251
252 done:
253 if (fd != -1)
254 close(fd);
255 if (data) {
256 *data_length = len;
257 }
258 return (data);
259 }
260
261 static CFPropertyListRef
262 readPropertyList(char * filename)
263 {
264 void * buf;
265 size_t bufsize;
266 CFDataRef data = NULL;
267 CFPropertyListRef plist = NULL;
268 CFStringRef errorString = NULL;
269
270 buf = read_file(filename, &bufsize);
271 if (buf == NULL) {
272 return (NULL);
273 }
274 data = CFDataCreate(NULL, buf, bufsize);
275 if (data == NULL) {
276 goto error;
277 }
278
279 plist = CFPropertyListCreateFromXMLData(NULL, data,
280 kCFPropertyListMutableContainers,
281 &errorString);
282 if (plist == NULL) {
283 if (errorString != NULL) {
284 SCLog(TRUE, LOG_ERR,
285 CFSTR(MY_PLUGIN_NAME ": %@"),
286 errorString);
287 CFRelease(errorString);
288 }
289 }
290 error:
291 if (data)
292 CFRelease(data);
293 if (buf)
294 free(buf);
295 return (plist);
296 }
297
298 #define INTERFACES CFSTR("Interfaces")
299 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
300 #define OLD_NETWORK_INTERFACES_FILE "/var/db/NetworkInterfaces.xml"
301
302 static void
303 writeInterfaceList(CFArrayRef if_list)
304 {
305 CFArrayRef cur_list;
306 SCPreferencesRef prefs;
307
308 if (isA_CFArray(if_list) == NULL) {
309 return;
310 }
311
312 prefs = SCPreferencesCreate(NULL, MY_PLUGIN_ID, NETWORK_INTERFACES_PREFS);
313 if (prefs == NULL) {
314 SCLog(TRUE, LOG_ERR,
315 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate failed, %s"),
316 SCErrorString(SCError()));
317 return;
318 }
319
320 cur_list = SCPreferencesGetValue(prefs, INTERFACES);
321 if (_SC_CFEqual(cur_list, if_list)) {
322 goto done;
323 }
324
325 if (!SCPreferencesSetValue(prefs, INTERFACES, if_list)) {
326 SCLog(TRUE, LOG_ERR,
327 CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetValue failed, %s"),
328 SCErrorString(SCError()));
329 goto done;
330 }
331
332 if (!SCPreferencesCommitChanges(prefs)) {
333 SCLog((SCError() != EROFS), LOG_ERR,
334 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCommitChanges failed, %s"),
335 SCErrorString(SCError()));
336 goto done;
337 }
338
339 done:
340
341 CFRelease(prefs);
342 return;
343 }
344
345 static CFMutableArrayRef
346 readInterfaceList()
347 {
348 CFArrayRef if_list;
349 CFMutableArrayRef plist = NULL;
350 SCPreferencesRef prefs = NULL;
351
352 prefs = SCPreferencesCreate(NULL, MY_PLUGIN_ID, NETWORK_INTERFACES_PREFS);
353 if (!prefs) {
354 SCLog(TRUE, LOG_ERR,
355 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate failed, %s"),
356 SCErrorString(SCError()));
357 return (NULL);
358 }
359
360 if_list = SCPreferencesGetValue(prefs, INTERFACES);
361 if (!isA_CFArray(if_list)) {
362 if_list = (CFArrayRef)readPropertyList(OLD_NETWORK_INTERFACES_FILE);
363 if (if_list == NULL) {
364 goto done;
365 }
366 if (!isA_CFArray(if_list)) {
367 CFRelease(if_list);
368 if_list = NULL;
369 goto done;
370 }
371 writeInterfaceList(if_list);
372 (void)unlink(OLD_NETWORK_INTERFACES_FILE);
373 }
374
375 done:
376 if (if_list != NULL) {
377 CFIndex i;
378 CFIndex n = CFArrayGetCount(if_list);
379
380 plist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
381 for (i = 0; i < n; i++) {
382 CFDictionaryRef dict;
383
384 dict = CFArrayGetValueAtIndex(if_list, i);
385 if (isA_CFDictionary(dict) &&
386 CFDictionaryContainsKey(dict, CFSTR(kIOInterfaceType)) &&
387 CFDictionaryContainsKey(dict, CFSTR(kIOInterfaceUnit)) &&
388 CFDictionaryContainsKey(dict, CFSTR(kIOMACAddress))) {
389 CFArrayAppendValue(plist, dict);
390 }
391 }
392 }
393 if (prefs) {
394 CFRelease(prefs);
395 }
396 return (plist);
397 }
398
399 static CFMutableArrayRef
400 previouslyActiveInterfaces()
401 {
402 CFMutableArrayRef active;
403 CFIndex i;
404 CFIndex n;
405
406 if (S_dblist == NULL) {
407 return NULL;
408 }
409
410 active = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
411
412 n = CFArrayGetCount(S_dblist);
413 for (i = 0; i < n; i++) {
414 CFDictionaryRef if_dict;
415
416 if_dict = CFArrayGetValueAtIndex(S_dblist, i);
417 if (CFDictionaryContainsKey(if_dict, CFSTR(kSCNetworkInterfaceActive))) {
418 CFMutableDictionaryRef new_dict;
419
420 new_dict = CFDictionaryCreateMutableCopy(NULL, 0, if_dict);
421 CFDictionaryRemoveValue(new_dict, CFSTR(kSCNetworkInterfaceActive));
422 CFArraySetValueAtIndex(S_dblist, i, new_dict);
423 CFArrayAppendValue(active, new_dict);
424 CFRelease(new_dict);
425 }
426 }
427
428 return active;
429 }
430
431 static void
432 updateStore(void)
433 {
434 CFStringRef key;
435 SCDynamicStoreRef store;
436
437 store = SCDynamicStoreCreate(NULL, CFSTR(MY_PLUGIN_NAME), NULL, NULL);
438 if (store == NULL) {
439 return;
440 }
441
442 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" MY_PLUGIN_NAME),
443 kSCDynamicStoreDomainPlugin);
444 (void)SCDynamicStoreSetValue(store, key, S_state);
445 CFRelease(key);
446 CFRelease(store);
447
448 return;
449 }
450
451 #if !TARGET_OS_IPHONE
452 static void
453 updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs,
454 SCPreferencesNotification notificationType,
455 void *info)
456 {
457 CFArrayRef interfaces;
458
459 if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) {
460 return;
461 }
462
463 if (prefs == NULL) {
464 // if a new interface has been "named"
465 prefs = S_prefs;
466 if (S_bonds != NULL) {
467 CFRelease(S_bonds);
468 S_bonds = NULL;
469 }
470 if (S_vlans != NULL) {
471 CFRelease(S_vlans);
472 S_vlans = NULL;
473 }
474 }
475
476 // update Bond configuration
477
478 interfaces = SCBondInterfaceCopyAll(prefs);
479 if ((S_bonds == NULL) && (interfaces == NULL)) {
480 // if no change
481 goto vlan;
482 }
483 if ((S_bonds != NULL) && (interfaces != NULL) && CFEqual(S_bonds, interfaces)) {
484 // if no change
485 CFRelease(interfaces);
486 goto vlan;
487 }
488 if (S_bonds != NULL) CFRelease(S_bonds);
489 S_bonds = interfaces;
490
491 if (!_SCBondInterfaceUpdateConfiguration(prefs)) {
492 SCLog(TRUE, LOG_ERR,
493 CFSTR(MY_PLUGIN_NAME ": _SCBondInterfaceUpdateConfiguration failed, %s"),
494 SCErrorString(SCError()));
495 }
496
497 vlan :
498
499 // update VLAN configuration
500
501 interfaces = SCVLANInterfaceCopyAll(prefs);
502 if ((S_vlans == NULL) && (interfaces == NULL)) {
503 // if no change
504 goto done;
505 }
506 if ((S_vlans != NULL) && (interfaces != NULL) && CFEqual(S_vlans, interfaces)) {
507 // if no change
508 CFRelease(interfaces);
509 goto done;
510 }
511 if (S_vlans != NULL) CFRelease(S_vlans);
512 S_vlans = interfaces;
513
514 if (!_SCVLANInterfaceUpdateConfiguration(prefs)) {
515 SCLog(TRUE, LOG_ERR,
516 CFSTR(MY_PLUGIN_NAME ": _SCVLANInterfaceUpdateConfiguration failed, %s"),
517 SCErrorString(SCError()));
518 }
519
520 done :
521
522 // we are finished with current prefs, wait for changes
523
524 SCPreferencesSynchronize(prefs);
525 return;
526 }
527 #endif /* !TARGET_OS_IPHONE */
528
529 static CFDictionaryRef
530 createInterfaceDict(SCNetworkInterfaceRef interface)
531 {
532 CFMutableDictionaryRef new_if;
533 CFTypeRef val;
534
535 new_if = CFDictionaryCreateMutable(NULL,
536 0,
537 &kCFTypeDictionaryKeyCallBacks,
538 &kCFTypeDictionaryValueCallBacks);
539
540 val = _SCNetworkInterfaceGetIOPath(interface);
541 if (val != NULL) {
542 CFDictionarySetValue(new_if, CFSTR(kIOPathMatchKey), val);
543 }
544
545 val = _SCNetworkInterfaceGetIOInterfaceType(interface);
546 if (val != NULL) {
547 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceType), val);
548 }
549
550 val = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
551 if (val != NULL) {
552 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceUnit), val);
553 }
554
555 val = _SCNetworkInterfaceGetHardwareAddress(interface);
556 if (val != NULL) {
557 CFDictionarySetValue(new_if, CFSTR(kIOMACAddress), val);
558 }
559
560 val = SCNetworkInterfaceGetBSDName(interface);
561 if (val != NULL) {
562 CFDictionarySetValue(new_if, CFSTR(kIOBSDNameKey), val);
563 }
564
565 val = SCNetworkInterfaceGetInterfaceType(interface);
566 if (val != NULL) {
567 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceType), val);
568 }
569
570 CFDictionarySetValue(new_if,
571 CFSTR(kIOBuiltin),
572 _SCNetworkInterfaceIsBuiltin(interface) ? kCFBooleanTrue : kCFBooleanFalse);
573
574 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceActive), kCFBooleanTrue);
575
576 return new_if;
577 }
578
579 static CFDictionaryRef
580 lookupInterfaceByAddress(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where)
581 {
582 CFDataRef addr;
583 CFIndex i;
584 CFIndex n;
585 CFNumberRef type;
586
587 if (db_list == NULL) {
588 return (NULL);
589 }
590 type = _SCNetworkInterfaceGetIOInterfaceType(interface);
591 addr = _SCNetworkInterfaceGetHardwareAddress(interface);
592 if (type == NULL || addr == NULL) {
593 return (NULL);
594 }
595
596 n = CFArrayGetCount(db_list);
597 for (i = 0; i < n; i++) {
598 CFDataRef a;
599 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i);
600 CFNumberRef t;
601
602 t = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
603 a = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress));
604 if (t == NULL || a == NULL)
605 continue;
606
607 if (CFEqual(type, t) && CFEqual(addr, a)) {
608 if (where) {
609 *where = i;
610 }
611 return (dict);
612 }
613 }
614 return (NULL);
615 }
616
617 static CFDictionaryRef
618 lookupInterfaceByUnit(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where)
619 {
620 CFIndex i;
621 CFIndex n;
622 CFNumberRef type;
623 CFNumberRef unit;
624
625 if (db_list == NULL) {
626 return (NULL);
627 }
628 type = _SCNetworkInterfaceGetIOInterfaceType(interface);
629 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
630 if (type == NULL || unit == NULL) {
631 return (NULL);
632 }
633
634 n = CFArrayGetCount(db_list);
635 for (i = 0; i < n; i++) {
636 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i);
637 CFNumberRef t;
638 CFNumberRef u;
639
640 t = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
641 u = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
642 if (t == NULL || u == NULL) {
643 continue;
644 }
645
646 if (CFEqual(type, t) && CFEqual(unit, u)) {
647 if (where)
648 *where = i;
649 return (dict);
650 }
651 }
652 return (NULL);
653 }
654
655 static CFDictionaryRef
656 lookupAirPortInterface(CFArrayRef db_list, CFIndex * where)
657 {
658 CFIndex i;
659 CFIndex n;
660
661 if (db_list == NULL) {
662 return (NULL);
663 }
664 n = CFArrayGetCount(db_list);
665 for (i = 0; i < n; i++) {
666 CFDictionaryRef dict;
667 CFStringRef if_type;
668
669 dict = CFArrayGetValueAtIndex(db_list, i);
670 if_type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType));
671 if (if_type != NULL) {
672 if (CFEqual(if_type, kSCNetworkInterfaceTypeIEEE80211)) {
673 if (where)
674 *where = i;
675 return (dict);
676 }
677 } else {
678 CFStringRef path;
679
680 path = CFDictionaryGetValue(dict, CFSTR(kIOPathMatchKey));
681 if ((CFStringFind(path, CFSTR("IO80211Interface") , 0).location != kCFNotFound) ||
682 (CFStringFind(path, CFSTR("AirPort") , 0).location != kCFNotFound) ||
683 (CFStringFind(path, CFSTR("AppleWireless80211"), 0).location != kCFNotFound)) {
684 if (where)
685 *where = i;
686 return (dict);
687 }
688 }
689 }
690 return (NULL);
691 }
692
693 static void
694 insertInterface(CFMutableArrayRef db_list, SCNetworkInterfaceRef interface)
695 {
696 CFIndex i;
697 CFDictionaryRef if_dict;
698 CFStringRef if_name;
699 CFNumberRef if_type;
700 CFNumberRef if_unit;
701 CFIndex n = CFArrayGetCount(db_list);
702 CFComparisonResult res;
703
704 if_name = SCNetworkInterfaceGetBSDName(interface);
705 if (if_name != NULL) {
706 addTimestamp(S_state, if_name);
707 }
708
709 if_dict = createInterfaceDict(interface);
710 if_type = _SCNetworkInterfaceGetIOInterfaceType(interface);
711 if_unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
712 if ((if_type == NULL) || (if_unit == NULL)) {
713 CFRelease(if_dict);
714 return;
715 }
716
717 for (i = 0; i < n; i++) {
718 CFNumberRef db_type;
719 CFNumberRef db_unit;
720 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i);
721
722 db_type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
723 db_unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
724 res = CFNumberCompare(if_type, db_type, NULL);
725 if (res == kCFCompareLessThan
726 || (res == kCFCompareEqualTo
727 && (CFNumberCompare(if_unit, db_unit, NULL)
728 == kCFCompareLessThan))) {
729 CFArrayInsertValueAtIndex(db_list, i, if_dict);
730 CFRelease(if_dict);
731 return;
732 }
733 }
734
735 CFArrayAppendValue(S_dblist, if_dict);
736 CFRelease(if_dict);
737 return;
738 }
739
740 static void
741 replaceInterface(SCNetworkInterfaceRef interface)
742 {
743 CFIndex where;
744
745 if (S_dblist == NULL) {
746 S_dblist = CFArrayCreateMutable(NULL, 0,
747 &kCFTypeArrayCallBacks);
748 }
749 // remove any dict that has our type/addr
750 if (lookupInterfaceByAddress(S_dblist, interface, &where) != NULL) {
751 CFArrayRemoveValueAtIndex(S_dblist, where);
752 }
753 // remove any dict that has the same type/unit
754 if (lookupInterfaceByUnit(S_dblist, interface, &where) != NULL) {
755 CFArrayRemoveValueAtIndex(S_dblist, where);
756 }
757 insertInterface(S_dblist, interface);
758 return;
759 }
760
761 static CFNumberRef
762 getHighestUnitForType(CFNumberRef if_type)
763 {
764 int i;
765 CFIndex n;
766 CFNumberRef ret_unit = NULL;
767
768 if (S_dblist == NULL) {
769 return (NULL);
770 }
771
772 n = CFArrayGetCount(S_dblist);
773 for (i = 0; i < n; i++) {
774 CFDictionaryRef dict = CFArrayGetValueAtIndex(S_dblist, i);
775 CFNumberRef type;
776
777 type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
778 if (CFEqual(type, if_type)) {
779 CFNumberRef unit;
780
781 unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
782 if (ret_unit == NULL
783 || (CFNumberCompare(unit, ret_unit, NULL)
784 == kCFCompareGreaterThan)) {
785 ret_unit = unit;
786 }
787 }
788 }
789
790 return (ret_unit);
791 }
792
793 /*
794 * Function: registerInterface
795 * Purpose:
796 * Register a single interface with the given service path to the
797 * data link layer (BSD), using the specified unit number.
798 */
799 static kern_return_t
800 registerInterface(io_connect_t connect,
801 CFStringRef path,
802 CFNumberRef unit)
803 {
804 static const int command = kRegisterInterface;
805 CFMutableDictionaryRef dict;
806 kern_return_t kr;
807 CFNumberRef num;
808
809 dict = CFDictionaryCreateMutable(NULL, 0,
810 &kCFTypeDictionaryKeyCallBacks,
811 &kCFTypeDictionaryValueCallBacks);
812 num = CFNumberCreate(NULL, kCFNumberIntType, &command);
813 CFDictionarySetValue(dict, CFSTR(kIONetworkStackUserCommand), num);
814 CFRelease(num);
815 CFDictionarySetValue(dict, CFSTR(kIOPathMatchKey), path);
816 CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit);
817 kr = IOConnectSetCFProperties(connect, dict);
818 CFRelease(dict);
819 return kr;
820 }
821
822 static SCNetworkInterfaceRef
823 lookupIOKitPath(CFStringRef if_path)
824 {
825 io_registry_entry_t entry = MACH_PORT_NULL;
826 SCNetworkInterfaceRef interface = NULL;
827 kern_return_t kr;
828 mach_port_t masterPort = MACH_PORT_NULL;
829 io_string_t path;
830
831 kr = IOMasterPort(bootstrap_port, &masterPort);
832 if (kr != KERN_SUCCESS) {
833 SCLog(TRUE, LOG_ERR,
834 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x\n"),
835 kr);
836 goto error;
837 }
838 _SC_cfstring_to_cstring(if_path, path, sizeof(path), kCFStringEncodingASCII);
839 entry = IORegistryEntryFromPath(masterPort, path);
840 if (entry == MACH_PORT_NULL) {
841 SCLog(TRUE, LOG_ERR,
842 CFSTR(MY_PLUGIN_NAME ": IORegistryEntryFromPath(%@) failed"),
843 if_path);
844 goto error;
845 }
846
847 interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry);
848
849 error:
850 if (masterPort != MACH_PORT_NULL) {
851 mach_port_deallocate(mach_task_self(), masterPort);
852 }
853 if (entry != MACH_PORT_NULL) {
854 IOObjectRelease(entry);
855 }
856 return (interface);
857
858 }
859
860 static void
861 displayInterface(SCNetworkInterfaceRef interface)
862 {
863 CFStringRef addr;
864 CFStringRef name;
865 CFNumberRef type;
866 CFNumberRef unit;
867
868 name = SCNetworkInterfaceGetBSDName(interface);
869 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
870 type = _SCNetworkInterfaceGetIOInterfaceType(interface);
871 addr = SCNetworkInterfaceGetHardwareAddressString(interface);
872
873 SCLog(TRUE, LOG_INFO,
874 CFSTR(MY_PLUGIN_NAME ": %s%@%sType: %@, %s%@%sMAC address: %@"),
875 (name != NULL) ? "BSD Name: " : "",
876 (name != NULL) ? name : CFSTR(""),
877 (name != NULL) ? ", " : "",
878 type,
879 (unit != NULL) ? "Unit: " : "",
880 (unit != NULL) ? (CFTypeRef)unit : (CFTypeRef)CFSTR(""),
881 (unit != NULL) ? ", " : "",
882 addr);
883 }
884
885 static int
886 builtinCount(CFArrayRef if_list, CFIndex last, CFNumberRef if_type)
887 {
888 CFIndex i;
889 int n = 0;
890
891 for (i = 0; i < last; i++) {
892 SCNetworkInterfaceRef builtin_if;
893 CFNumberRef builtin_type;
894
895 builtin_if = CFArrayGetValueAtIndex(if_list, i);
896 builtin_type = _SCNetworkInterfaceGetIOInterfaceType(builtin_if);
897 if (CFEqual(if_type, builtin_type)) {
898 if (_SCNetworkInterfaceIsBuiltin(builtin_if)) {
899 n++; // if built-in interface
900 }
901 }
902 }
903
904 return n;
905 }
906
907 static __inline__ boolean_t
908 isQuiet(void)
909 {
910 return (S_quiet == MACH_PORT_NULL);
911 }
912
913 static void
914 nameInterfaces(CFMutableArrayRef if_list)
915 {
916 CFIndex i;
917 CFIndex n = CFArrayGetCount(if_list);
918
919 for (i = 0; i < n; i++) {
920 SCNetworkInterfaceRef interface;
921 CFStringRef path;
922 CFNumberRef type;
923 CFNumberRef unit;
924 CFIndex where;
925
926 interface = CFArrayGetValueAtIndex(if_list, i);
927 path = _SCNetworkInterfaceGetIOPath(interface);
928 type = _SCNetworkInterfaceGetIOInterfaceType(interface);
929 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface);
930
931 if (unit != NULL) {
932 if (S_debug) {
933 CFStringRef if_name;
934
935 if_name = SCNetworkInterfaceGetBSDName(interface);
936 if ((if_name == NULL) || !CFDictionaryContainsKey(S_state, if_name)) {
937 SCLog(TRUE, LOG_INFO,
938 CFSTR(MY_PLUGIN_NAME ": Interface already has a unit number"));
939 displayInterface(interface);
940 }
941 }
942
943 // update the list of interfaces that were previously named
944 if ((S_prev_active_list != NULL)
945 && lookupInterfaceByAddress(S_prev_active_list, interface, &where) != NULL) {
946 CFArrayRemoveValueAtIndex(S_prev_active_list, where);
947 }
948 } else {
949 CFDictionaryRef dbdict;
950 kern_return_t kr;
951
952 dbdict = lookupInterfaceByAddress(S_dblist, interface, NULL);
953 if (dbdict != NULL) {
954 unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit));
955 CFRetain(unit);
956
957 SCLog(S_debug, LOG_INFO,
958 CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (from database)"),
959 unit);
960 } else {
961 CFStringRef if_type;
962
963 if_type = SCNetworkInterfaceGetInterfaceType(interface);
964 if ((if_type != NULL) &&
965 CFEqual(if_type, kSCNetworkInterfaceTypeIEEE80211)) {
966 dbdict = lookupAirPortInterface(S_dblist, NULL);
967 if (dbdict != NULL) {
968 unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit));
969 CFRetain(unit);
970
971 SCLog(S_debug, LOG_INFO,
972 CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (updating database)"),
973 unit);
974 }
975 }
976 }
977
978 if ((dbdict != NULL) && (S_prev_active_list != NULL)) {
979 // update the list of interfaces that were previously named
980 where = CFArrayGetFirstIndexOfValue(S_prev_active_list,
981 CFRangeMake(0, CFArrayGetCount(S_prev_active_list)),
982 dbdict);
983 if (where != kCFNotFound) {
984 CFArrayRemoveValueAtIndex(S_prev_active_list, where);
985 }
986 }
987
988 if (dbdict == NULL) {
989 boolean_t is_builtin;
990 int next_unit = 0;
991
992 if (!isQuiet()) {
993 // if new interface, wait until quiet before naming
994 addTimestamp(S_state, path);
995 continue;
996 }
997
998 is_builtin = _SCNetworkInterfaceIsBuiltin(interface);
999 next_unit = 0;
1000 if (is_builtin) {
1001 // built-in interface, use the reserved slots
1002 next_unit = builtinCount(if_list, i, type);
1003 } else {
1004 // not built-in, skip over the reserved slots
1005 next_unit = builtinCount(if_list, n, type);
1006
1007 unit = getHighestUnitForType(type);
1008 if (unit != NULL) {
1009 int high_unit;
1010
1011 CFNumberGetValue(unit, kCFNumberIntType, &high_unit);
1012 if (high_unit >= next_unit) {
1013 next_unit = high_unit + 1;
1014 }
1015 }
1016 }
1017 unit = CFNumberCreate(NULL, kCFNumberIntType, &next_unit);
1018
1019 SCLog(S_debug, LOG_INFO,
1020 CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (%s)"),
1021 unit,
1022 is_builtin ? "built-in" : "next available");
1023 }
1024
1025 kr = registerInterface(S_connect, path, unit);
1026 if (kr != KERN_SUCCESS) {
1027 SCLog(TRUE, LOG_ERR,
1028 CFSTR(MY_PLUGIN_NAME ": failed to name the interface, kr=0x%x"),
1029 kr);
1030 if (S_debug) {
1031 displayInterface(interface);
1032 }
1033 } else {
1034 SCNetworkInterfaceRef new_interface;
1035
1036 new_interface = lookupIOKitPath(path);
1037 if (new_interface != NULL) {
1038 CFNumberRef new_unit;
1039
1040 new_unit = _SCNetworkInterfaceGetIOInterfaceUnit(new_interface);
1041 if (CFEqual(unit, new_unit) == FALSE) {
1042 SCLog(S_debug, LOG_INFO,
1043 CFSTR(MY_PLUGIN_NAME
1044 ": interface type %@ assigned "
1045 "unit %@ instead of %@"),
1046 type, new_unit, unit);
1047 }
1048 if (S_debug) {
1049 displayInterface(new_interface);
1050 }
1051
1052 // update if_list (with the interface name & unit)
1053 CFArraySetValueAtIndex(if_list, i, new_interface);
1054 CFRelease(new_interface);
1055 interface = new_interface; // if_list holds the reference
1056 }
1057 }
1058
1059 CFRelease(unit);
1060 }
1061
1062 // update db
1063 replaceInterface(interface);
1064 }
1065 return;
1066 }
1067
1068 static void
1069 updateInterfaces()
1070 {
1071 if (S_connect == MACH_PORT_NULL) {
1072 // if we don't have the "IONetworkStack" connect object
1073 return;
1074 }
1075
1076 if (S_iflist != NULL) {
1077 CFIndex n;
1078
1079 n = CFArrayGetCount(S_iflist);
1080 if (n > 1) {
1081 CFArraySortValues(S_iflist, CFRangeMake(0, n), _SCNetworkInterfaceCompare, NULL);
1082 }
1083 nameInterfaces(S_iflist);
1084 }
1085
1086 if (isQuiet()) {
1087 /*
1088 * The registry [matching] has quiesced so let's
1089 * - save the DB with the interfaces that have been named
1090 * - update the VLAN/BOND configuration
1091 * - tell everyone that we've finished (at least for now)
1092 * - log those interfaces which are no longer present
1093 * in the HW config (or have yet to show up).
1094 */
1095 writeInterfaceList(S_dblist);
1096 #if !TARGET_OS_IPHONE
1097 updateVirtualNetworkInterfaceConfiguration(NULL, kSCPreferencesNotificationApply, NULL);
1098 #endif /* !TARGET_OS_IPHONE */
1099 updateStore();
1100
1101 if (S_iflist != NULL) {
1102 CFRelease(S_iflist);
1103 S_iflist = NULL;
1104 }
1105
1106 if (S_prev_active_list != NULL) {
1107 if (S_debug) {
1108 CFIndex i;
1109 CFIndex n;
1110
1111 n = CFArrayGetCount(S_prev_active_list);
1112 SCLog(TRUE, LOG_INFO,
1113 CFSTR(MY_PLUGIN_NAME ": Interface%s not [yet] active"),
1114 (n > 0) ? "s" : "");
1115 for (i = 0; i < n; i++) {
1116 CFDictionaryRef if_dict;
1117 CFStringRef name;
1118 CFNumberRef type;
1119 CFNumberRef unit;
1120
1121 if_dict = CFArrayGetValueAtIndex(S_prev_active_list, i);
1122 name = CFDictionaryGetValue(if_dict, CFSTR(kIOBSDNameKey));
1123 type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType));
1124 unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit));
1125 SCLog(TRUE, LOG_INFO,
1126 CFSTR(MY_PLUGIN_NAME ": %s%@%sType: %@, Unit: %@"),
1127 (name != NULL) ? "BSD Name: " : "",
1128 (name != NULL) ? name : CFSTR(""),
1129 (name != NULL) ? ", " : "",
1130 type,
1131 unit);
1132 }
1133 }
1134 CFRelease(S_prev_active_list);
1135 S_prev_active_list = NULL;
1136 }
1137 } else {
1138 if ((S_prev_active_list != NULL) && (CFArrayGetCount(S_prev_active_list) == 0)) {
1139 /*
1140 * if we've named all of the interfaces that
1141 * were used during the previous boot.
1142 */
1143 addTimestamp(S_state, CFSTR("*RELEASE*"));
1144 SCLog(S_debug, LOG_INFO,
1145 CFSTR(MY_PLUGIN_NAME ": last boot interfaces have been named"));
1146 updateStore();
1147 CFRelease(S_prev_active_list);
1148 S_prev_active_list = NULL;
1149 }
1150 }
1151
1152 return;
1153 }
1154
1155 static CFComparisonResult
1156 compareMacAddress(const void *val1, const void *val2, void *context)
1157 {
1158 CFDataRef mac1 = (CFDataRef)val1;
1159 CFDataRef mac2 = (CFDataRef)val2;
1160 CFIndex n1;
1161 CFIndex n2;
1162 CFComparisonResult res;
1163
1164 n1 = CFDataGetLength(mac1);
1165 n2 = CFDataGetLength(mac2);
1166 if (n1 < n2) {
1167 res = kCFCompareLessThan;
1168 } else if (n2 > n1) {
1169 res = kCFCompareGreaterThan;
1170 } else {
1171 res = bcmp(CFDataGetBytePtr(mac1), CFDataGetBytePtr(mac2), n1);
1172 }
1173
1174 return res;
1175 }
1176
1177 #ifndef kIOPlatformUUIDKey
1178 #define kIOPlatformUUIDKey "IOPlatformUUID"
1179 #endif
1180 static void
1181 updatePlatformUUID()
1182 {
1183 CFDataRef addr;
1184 CFMutableArrayRef addrs = NULL;
1185 CFStringRef guid;
1186 CFIndex i;
1187 CFIndex n;
1188 io_registry_entry_t platform;
1189
1190 platform = IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreePlane ":/");
1191 if (platform == MACH_PORT_NULL) {
1192 return;
1193 }
1194
1195 guid = IORegistryEntryCreateCFProperty(platform, CFSTR(kIOPlatformUUIDKey), NULL, 0);
1196 if (guid != NULL) {
1197 // if GUID already defined
1198 goto done;
1199 }
1200
1201 addrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1202 n = (S_dblist != NULL) ? CFArrayGetCount(S_dblist) : 0;
1203 for (i = 0; i < n; i++) {
1204 CFBooleanRef builtin;
1205 CFDictionaryRef dict;
1206 CFStringRef type;
1207
1208 dict = CFArrayGetValueAtIndex(S_dblist, i);
1209 type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType));
1210 if (!isA_CFString(type) || !CFEqual(type, kSCNetworkInterfaceTypeEthernet)) {
1211 continue;
1212 }
1213 builtin = CFDictionaryGetValue(dict, CFSTR(kIOBuiltin));
1214 if (!isA_CFBoolean(builtin) || !CFBooleanGetValue(builtin)) {
1215 continue;
1216 }
1217 addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress));
1218 if (!isA_CFData(addr) || (CFDataGetLength(addr) != ETHER_ADDR_LEN)) {
1219 continue;
1220 }
1221 CFArrayAppendValue(addrs, addr);
1222 }
1223
1224 if (CFArrayGetCount(addrs) == 0) {
1225 // if no ethernet interfaces, look for wireless
1226 for (i = 0; i < n; i++) {
1227 CFDictionaryRef dict;
1228 CFStringRef type;
1229
1230 dict = CFArrayGetValueAtIndex(S_dblist, i);
1231 type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType));
1232 if (!isA_CFString(type) || !CFEqual(type, kSCNetworkInterfaceTypeIEEE80211)) {
1233 continue;
1234 }
1235 addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress));
1236 if (!isA_CFData(addr) || (CFDataGetLength(addr) != ETHER_ADDR_LEN)) {
1237 continue;
1238 }
1239 CFArrayAppendValue(addrs, addr);
1240 }
1241 }
1242
1243 n = CFArrayGetCount(addrs);
1244 switch (n) {
1245 case 0 :
1246 SCLog(TRUE, LOG_ERR,
1247 CFSTR(MY_PLUGIN_NAME ": no network interfaces, could not update platform UUID"));
1248 break;
1249 default :
1250 // sort by MAC address
1251 CFArraySortValues(addrs, CFRangeMake(0, n), compareMacAddress, NULL);
1252
1253 // fall through
1254 case 1 : {
1255 CFUUIDBytes bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1256 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1257 kern_return_t kr;
1258 CFUUIDRef uuid;
1259
1260 // set GUID
1261 addr = CFArrayGetValueAtIndex(addrs, 0);
1262 bcopy(CFDataGetBytePtr(addr),
1263 (void *)&bytes + sizeof(bytes) - ETHER_ADDR_LEN,
1264 ETHER_ADDR_LEN);
1265 uuid = CFUUIDCreateFromUUIDBytes(NULL, bytes);
1266 guid = CFUUIDCreateString(NULL, uuid);
1267 CFRelease(uuid);
1268
1269 SCLog(TRUE, LOG_INFO,
1270 CFSTR(MY_PLUGIN_NAME ": setting platform UUID = %@"),
1271 guid);
1272 kr = IORegistryEntrySetCFProperty(platform, CFSTR(kIOPlatformUUIDKey), guid);
1273 if (kr != KERN_SUCCESS) {
1274 SCLog(TRUE, LOG_ERR,
1275 CFSTR(MY_PLUGIN_NAME ": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"),
1276 kr);
1277 }
1278
1279 addTimestamp(S_state, CFSTR("*PLATFORM-UUID*"));
1280 updateStore();
1281 break;
1282 }
1283 }
1284
1285 done :
1286
1287 if (addrs != NULL) CFRelease(addrs);
1288 if (platform != MACH_PORT_NULL) IOObjectRelease(platform);
1289 if (guid != NULL) CFRelease(guid);
1290 return;
1291 }
1292
1293 static void
1294 interfaceArrivalCallback(void *refcon, io_iterator_t iter)
1295 {
1296 io_object_t obj;
1297
1298 while ((obj = IOIteratorNext(iter)) != MACH_PORT_NULL) {
1299 SCNetworkInterfaceRef interface;
1300
1301 interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj);
1302 if (interface != NULL) {
1303 if (S_iflist == NULL) {
1304 S_iflist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1305 }
1306 CFArrayAppendValue(S_iflist, interface);
1307 CFRelease(interface);
1308 }
1309 IOObjectRelease(obj);
1310 }
1311
1312 updateInterfaces();
1313 return;
1314 }
1315
1316 /*
1317 * Function: stackCallback
1318 * Purpose:
1319 * Get a reference to the single IONetworkStack object instance in
1320 * the kernel. Naming requests must be sent to this object, which is
1321 * attached as a client to all network interface objects in the system.
1322 * Note:
1323 * Call IOObjectRelease on the returned object.
1324 */
1325 static void
1326 stackCallback(void *refcon, io_iterator_t iter)
1327 {
1328 kern_return_t kr;
1329 io_object_t stack;
1330
1331 stack = IOIteratorNext(iter);
1332 if (stack == MACH_PORT_NULL) {
1333 goto error;
1334 }
1335
1336 kr = IOServiceOpen(stack, mach_task_self(), 0, &S_connect);
1337 if (kr != KERN_SUCCESS) {
1338 SCLog(TRUE, LOG_ERR,
1339 CFSTR(MY_PLUGIN_NAME ": IOServiceOpen returned 0x%x"),
1340 kr);
1341 goto error;
1342 }
1343
1344 addTimestamp(S_state, CFSTR("*STACK*"));
1345 SCLog(S_debug, LOG_INFO,
1346 CFSTR(MY_PLUGIN_NAME ": IONetworkStack found"));
1347
1348 if (S_stack != MACH_PORT_NULL) {
1349 IOObjectRelease(S_stack);
1350 S_stack = MACH_PORT_NULL;
1351 }
1352
1353 updateInterfaces();
1354
1355 error:
1356 if (stack != MACH_PORT_NULL) {
1357 IOObjectRelease(stack);
1358 }
1359
1360 return;
1361 }
1362
1363 static void
1364 quietCallback(void *refcon,
1365 io_service_t service,
1366 natural_t messageType,
1367 void *messageArgument)
1368 {
1369 if (messageArgument != NULL) {
1370 // if not yet quiet
1371 return;
1372 }
1373
1374 if (messageType == kIOMessageServiceBusyStateChange) {
1375 addTimestamp(S_state, CFSTR("*QUIET*"));
1376 SCLog(S_debug, LOG_INFO,
1377 CFSTR(MY_PLUGIN_NAME ": IOKit quiet"));
1378 }
1379
1380 if (S_connect == MACH_PORT_NULL) {
1381 SCLog(TRUE, LOG_ERR,
1382 CFSTR(MY_PLUGIN_NAME ": No network stack object"));
1383 return;
1384 }
1385
1386 if (S_quiet != MACH_PORT_NULL) {
1387 IOObjectRelease(S_quiet);
1388 S_quiet = MACH_PORT_NULL;
1389 }
1390
1391 if (S_timer != NULL) {
1392 CFRunLoopTimerInvalidate(S_timer);
1393 CFRelease(S_timer);
1394 S_timer = NULL;
1395 }
1396
1397 // grab (and name) any additional interfaces.
1398 interfaceArrivalCallback((void *)S_notify, S_iter);
1399
1400 updatePlatformUUID();
1401
1402 return;
1403 }
1404
1405 static void
1406 iterateRegistryBusy(io_iterator_t iterator, CFArrayRef nodes, int *count)
1407 {
1408 kern_return_t kr = kIOReturnSuccess;;
1409 io_object_t obj;
1410
1411 while ((kr == kIOReturnSuccess) &&
1412 ((obj = IOIteratorNext(iterator)) != MACH_PORT_NULL)) {
1413 uint32_t busy;
1414 io_name_t location;
1415 io_name_t name;
1416 CFMutableArrayRef newNodes;
1417 CFMutableStringRef str = NULL;
1418
1419 if (nodes == NULL) {
1420 newNodes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1421 } else {
1422 newNodes = CFArrayCreateMutableCopy(NULL, 0, nodes);
1423 }
1424
1425 kr = IORegistryEntryGetName(obj, name);
1426 if (kr != kIOReturnSuccess) {
1427 SCLog(TRUE, LOG_ERR,
1428 CFSTR(MY_PLUGIN_NAME ": reportBusy IORegistryEntryGetName returned 0x%x"),
1429 kr);
1430 goto next;
1431 }
1432
1433 str = CFStringCreateMutable(NULL, 0);
1434 CFStringAppendCString(str, name, kCFStringEncodingUTF8);
1435
1436 kr = IORegistryEntryGetLocationInPlane(obj, kIOServicePlane, location);
1437 switch (kr) {
1438 case kIOReturnSuccess :
1439 CFStringAppendCString(str, "@", kCFStringEncodingUTF8);
1440 CFStringAppendCString(str, location, kCFStringEncodingUTF8);
1441 break;
1442 case kIOReturnNotFound :
1443 break;
1444 default :
1445 SCLog(TRUE, LOG_ERR,
1446 CFSTR(MY_PLUGIN_NAME ": reportBusy IORegistryEntryGetLocationInPlane returned 0x%x"),
1447 kr);
1448 CFRelease(str);
1449 goto next;
1450 }
1451
1452 CFArrayAppendValue(newNodes, str);
1453 CFRelease(str);
1454
1455 kr = IOServiceGetBusyState(obj, &busy);
1456 if (kr != kIOReturnSuccess) {
1457 SCLog(TRUE, LOG_ERR,
1458 CFSTR(MY_PLUGIN_NAME ": reportBusy IOServiceGetBusyState returned 0x%x"),
1459 kr);
1460 goto next;
1461 }
1462
1463 if (busy != 0) {
1464 CFStringRef path;
1465
1466 if ((*count)++ == 0) {
1467 SCLog(TRUE, LOG_WARNING, CFSTR(MY_PLUGIN_NAME ": Busy services :"));
1468 }
1469
1470 path = CFStringCreateByCombiningStrings(NULL, newNodes, CFSTR("/"));
1471 SCLog(TRUE, LOG_WARNING, CFSTR(MY_PLUGIN_NAME ": %@ [%d]"), path, busy);
1472 CFRelease(path);
1473 }
1474
1475 kr = IORegistryIteratorEnterEntry(iterator);
1476 if (kr != kIOReturnSuccess) {
1477 SCLog(TRUE, LOG_ERR,
1478 CFSTR(MY_PLUGIN_NAME ": reportBusy IORegistryIteratorEnterEntry returned 0x%x"),
1479 kr);
1480 goto next;
1481 }
1482
1483 iterateRegistryBusy(iterator, newNodes, count);
1484
1485 kr = IORegistryIteratorExitEntry(iterator);
1486 if (kr != kIOReturnSuccess) {
1487 SCLog(TRUE, LOG_ERR,
1488 CFSTR(MY_PLUGIN_NAME ": reportBusy IORegistryIteratorExitEntry returned 0x%x"),
1489 kr);
1490 }
1491
1492 next :
1493
1494 CFRelease(newNodes);
1495 IOObjectRelease(obj);
1496 }
1497
1498 return;
1499 }
1500
1501 static void
1502 reportBusy()
1503 {
1504 int count = 0;
1505 io_iterator_t iterator = MACH_PORT_NULL;
1506 kern_return_t kr;
1507
1508 kr = IORegistryCreateIterator(kIOMasterPortDefault,
1509 kIOServicePlane,
1510 0,
1511 &iterator);
1512 if (kr != kIOReturnSuccess) {
1513 SCLog(TRUE, LOG_ERR,
1514 CFSTR(MY_PLUGIN_NAME ": reportBusy IORegistryCreateIterator returned 0x%x"),
1515 kr);
1516 return;
1517 }
1518
1519 iterateRegistryBusy(iterator, NULL, &count);
1520 SCLog((count == 0), LOG_WARNING,
1521 CFSTR(MY_PLUGIN_NAME ": w/no busy services"));
1522 IOObjectRelease(iterator);
1523 return;
1524 }
1525
1526 static void
1527 timerCallback(CFRunLoopTimerRef timer, void *info)
1528 {
1529 /*
1530 * We've been waiting for IOKit to quiesce and it just
1531 * hasn't happenned. Time to just move on!
1532 */
1533 addTimestamp(S_state, CFSTR("*TIMEOUT*"));
1534 SCLog(TRUE, LOG_ERR,
1535 CFSTR(MY_PLUGIN_NAME ": timed out waiting for IOKit to quiesce"));
1536
1537 reportBusy();
1538 quietCallback((void *)S_notify, MACH_PORT_NULL, 0, NULL);
1539 return;
1540 }
1541
1542 static Boolean
1543 setup_IOKit(CFBundleRef bundle)
1544 {
1545 uint32_t busy;
1546 CFDictionaryRef dict;
1547 kern_return_t kr;
1548 mach_port_t masterPort = MACH_PORT_NULL;
1549 Boolean ok = FALSE;
1550 io_object_t root = MACH_PORT_NULL;
1551 double timeout = WAIT_QUIET_TIMEOUT_DEFAULT;
1552
1553 // read DB of previously named network interfaces
1554 S_dblist = readInterfaceList();
1555 if (S_dblist != NULL) {
1556 CFIndex n;
1557
1558 n = CFArrayGetCount(S_dblist);
1559 if (n > 1) {
1560 CFArraySortValues(S_dblist, CFRangeMake(0, n), if_unit_compare, NULL);
1561 }
1562 }
1563
1564 // get interfaces that were named during the last boot
1565 S_prev_active_list = previouslyActiveInterfaces();
1566
1567 // track how long we've waited to see each interface.
1568 S_state = CFDictionaryCreateMutable(NULL,
1569 0,
1570 &kCFTypeDictionaryKeyCallBacks,
1571 &kCFTypeDictionaryValueCallBacks);
1572 addTimestamp(S_state, CFSTR("*START*"));
1573
1574 // Creates and returns a notification object for receiving IOKit
1575 // notifications of new devices or state changes.
1576 kr = IOMasterPort(bootstrap_port, &masterPort);
1577 if (kr != KERN_SUCCESS) {
1578 SCLog(TRUE, LOG_ERR,
1579 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"),
1580 kr);
1581 goto done;
1582 }
1583
1584 S_notify = IONotificationPortCreate(masterPort);
1585 if (S_notify == NULL) {
1586 SCLog(TRUE, LOG_ERR,
1587 CFSTR(MY_PLUGIN_NAME ": IONotificationPortCreate failed"));
1588 goto done;
1589 }
1590
1591 // watch IOKit matching activity
1592 root = IORegistryEntryFromPath(masterPort, kIOServicePlane ":/");
1593 if (root == MACH_PORT_NULL) {
1594 SCLog(TRUE, LOG_ERR,
1595 CFSTR(MY_PLUGIN_NAME ": IORegistryEntryFromPath failed"));
1596 goto done;
1597 }
1598
1599 kr = IOServiceAddInterestNotification(S_notify,
1600 root,
1601 kIOBusyInterest,
1602 &quietCallback,
1603 (void *)S_notify, // refCon
1604 &S_quiet); // notification
1605 if (kr != KERN_SUCCESS) {
1606 SCLog(TRUE, LOG_ERR,
1607 CFSTR(MY_PLUGIN_NAME ": IOServiceAddInterestNotification returned 0x%x"),
1608 kr);
1609 goto done;
1610 }
1611
1612 kr = IOServiceGetBusyState(root, &busy);
1613 if (kr != KERN_SUCCESS) {
1614 SCLog(TRUE, LOG_ERR,
1615 CFSTR(MY_PLUGIN_NAME ": IOServiceGetBusyState returned 0x%x"),
1616 kr);
1617 goto done;
1618 }
1619
1620 // add a timer so we don't wait forever for IOKit to quiesce
1621 dict = CFBundleGetInfoDictionary(bundle);
1622 if (isA_CFDictionary(dict)) {
1623 CFNumberRef num;
1624
1625 num = CFDictionaryGetValue(dict, CFSTR(WAIT_QUIET_TIMEOUT_KEY));
1626 if (num != NULL) {
1627 if (!isA_CFNumber(num) ||
1628 !CFNumberGetValue(num, kCFNumberDoubleType, &timeout) ||
1629 (timeout <= 0.0)) {
1630 SCLog(TRUE, LOG_ERR,
1631 CFSTR(MY_PLUGIN_NAME ": " WAIT_QUIET_TIMEOUT_KEY " value error"));
1632 timeout = WAIT_QUIET_TIMEOUT_DEFAULT;
1633 }
1634 }
1635 }
1636 S_timer = CFRunLoopTimerCreate(NULL,
1637 CFAbsoluteTimeGetCurrent() + timeout,
1638 0,
1639 0,
1640 0,
1641 timerCallback,
1642 NULL);
1643 if (S_timer == NULL) {
1644 SCLog(TRUE, LOG_ERR,
1645 CFSTR(MY_PLUGIN_NAME ": CFRunLoopTimerCreate failed"));
1646 goto done;
1647 }
1648
1649 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, kCFRunLoopDefaultMode);
1650
1651 // watch for the introduction of the IONetworkStack
1652 kr = IOServiceAddMatchingNotification(S_notify,
1653 kIOFirstMatchNotification,
1654 IOServiceMatching("IONetworkStack"),
1655 &stackCallback,
1656 (void *)S_notify, // refCon
1657 &S_stack); // notification
1658 if (kr != KERN_SUCCESS) {
1659 SCLog(TRUE, LOG_ERR,
1660 CFSTR(MY_PLUGIN_NAME ": IOServiceAddMatchingNotification returned 0x%x"),
1661 kr);
1662 goto done;
1663 }
1664
1665 // check and see if the stack is already available and arm the
1666 // notification for its introduction.
1667 stackCallback((void *)S_notify, S_stack);
1668
1669 // watch for the introduction of new network interfaces
1670 kr = IOServiceAddMatchingNotification(S_notify,
1671 kIOFirstMatchNotification,
1672 IOServiceMatching("IONetworkInterface"),
1673 &interfaceArrivalCallback,
1674 (void *)S_notify, // refCon
1675 &S_iter); // notification
1676 if (kr != KERN_SUCCESS) {
1677 SCLog(TRUE, LOG_ERR,
1678 CFSTR(MY_PLUGIN_NAME ": IOServiceAddMatchingNotification returned 0x%x"),
1679 kr);
1680 goto done;
1681 }
1682
1683 // Get the current list of matches and arm the notification for
1684 // future interface arrivals.
1685 interfaceArrivalCallback((void *)S_notify, S_iter);
1686
1687 // Check if IOKit has already quiesced.
1688 quietCallback((void *)S_notify,
1689 MACH_PORT_NULL,
1690 kIOMessageServiceBusyStateChange,
1691 (void *)(uintptr_t)busy);
1692
1693 CFRunLoopAddSource(CFRunLoopGetCurrent(),
1694 IONotificationPortGetRunLoopSource(S_notify),
1695 kCFRunLoopDefaultMode);
1696
1697 #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET
1698 /*
1699 * Start the wheels turning until we've named all of
1700 * the interfaces that were used during the previous
1701 * boot, until IOKit [matching] has quiesced, or
1702 * until we've waited long enough.
1703 */
1704 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, MY_PLUGIN_ID);
1705 CFRunLoopAddSource(CFRunLoopGetCurrent(),
1706 IONotificationPortGetRunLoopSource(S_notify),
1707 MY_PLUGIN_ID);
1708 while (S_prev_active_list != NULL) {
1709 int rlStatus;
1710
1711 rlStatus = CFRunLoopRunInMode(MY_PLUGIN_ID, 1.0e10, TRUE);
1712 }
1713 #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */
1714
1715 ok = TRUE;
1716
1717 done:
1718 if (root != MACH_PORT_NULL) {
1719 IOObjectRelease(root);
1720 }
1721 if (masterPort != MACH_PORT_NULL) {
1722 mach_port_deallocate(mach_task_self(), masterPort);
1723 }
1724
1725 return ok;
1726 }
1727
1728 #if !TARGET_OS_IPHONE
1729 static Boolean
1730 setup_Virtual(CFBundleRef bundle)
1731 {
1732 // open a SCPreferences session
1733 S_prefs = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME), NULL);
1734 if (S_prefs == NULL) {
1735 SCLog(TRUE, LOG_ERR,
1736 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate() failed: %s"),
1737 SCErrorString(SCError()));
1738 return FALSE;
1739 }
1740
1741 // register for change notifications.
1742 if (!SCPreferencesSetCallback(S_prefs, updateVirtualNetworkInterfaceConfiguration, NULL)) {
1743 SCLog(TRUE, LOG_ERR,
1744 CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetCallBack() failed: %s"),
1745 SCErrorString(SCError()));
1746 CFRelease(S_prefs);
1747 return FALSE;
1748 }
1749
1750 // schedule
1751 if (!SCPreferencesScheduleWithRunLoop(S_prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
1752 if (SCError() != kSCStatusNoStoreServer) {
1753 SCLog(TRUE, LOG_ERR,
1754 CFSTR(MY_PLUGIN_NAME ": SCPreferencesScheduleWithRunLoop() failed: %s"),
1755 SCErrorString(SCError()));
1756 CFRelease(S_prefs);
1757 return FALSE;
1758 }
1759 }
1760
1761 return TRUE;
1762 }
1763 #endif /* !TARGET_OS_IPHONE */
1764
1765 __private_extern__
1766 void
1767 load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose)
1768 {
1769 if (bundleVerbose) {
1770 S_debug = TRUE;
1771 }
1772
1773 #if !TARGET_OS_IPHONE
1774 // setup virtual network interface monitoring
1775 if (!setup_Virtual(bundle)) {
1776 goto error;
1777 }
1778 #endif /* !TARGET_OS_IPHONE */
1779
1780 // setup [IOKit] network interface monitoring
1781 if (!setup_IOKit(bundle)) {
1782 goto error;
1783 }
1784
1785 return;
1786
1787 error :
1788 if (S_connect != MACH_PORT_NULL) {
1789 IOServiceClose(S_connect);
1790 S_connect = MACH_PORT_NULL;
1791 }
1792 if (S_dblist != NULL) {
1793 CFRelease(S_dblist);
1794 S_dblist = NULL;
1795 }
1796 if (S_iter != MACH_PORT_NULL) {
1797 IOObjectRelease(S_iter);
1798 S_iter = MACH_PORT_NULL;
1799 }
1800 if (S_notify != MACH_PORT_NULL) {
1801 IONotificationPortDestroy(S_notify);
1802 }
1803 if (S_quiet != MACH_PORT_NULL) {
1804 IOObjectRelease(S_quiet);
1805 S_quiet = MACH_PORT_NULL;
1806 }
1807 if (S_stack != MACH_PORT_NULL) {
1808 IOObjectRelease(S_stack);
1809 S_stack = MACH_PORT_NULL;
1810 }
1811 if (S_state != NULL) {
1812 CFRelease(S_state);
1813 S_state = NULL;
1814 }
1815 if (S_timer != NULL) {
1816 CFRunLoopTimerInvalidate(S_timer);
1817 CFRelease(S_timer);
1818 S_timer = NULL;
1819 }
1820
1821 return;
1822 }
1823
1824 //------------------------------------------------------------------------
1825 // Main function.
1826 #ifdef MAIN
1827 int
1828 main(int argc, char ** argv)
1829 {
1830 _sc_log = FALSE;
1831 _sc_verbose = (argc > 1) ? TRUE : FALSE;
1832
1833 load_InterfaceNamer(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
1834 CFRunLoopRun();
1835 /* not reached */
1836 exit(0);
1837 return 0;
1838 }
1839 #endif /* MAIN */
1840
1841 #ifdef TEST_PLATFORM_UUID
1842 int
1843 main(int argc, char ** argv)
1844 {
1845 CFArrayRef interfaces;
1846
1847 _sc_log = FALSE;
1848 _sc_verbose = (argc > 1) ? TRUE : FALSE;
1849
1850 S_dblist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1851 interfaces = SCNetworkInterfaceCopyAll();
1852 if (interfaces != NULL) {
1853 CFIndex i;
1854 CFIndex n;
1855
1856 n = CFArrayGetCount(interfaces);
1857 for (i = 0; i < n; i++) {
1858 CFDictionaryRef dict;
1859 SCNetworkInterfaceRef interface;
1860
1861 interface = CFArrayGetValueAtIndex(interfaces, i);
1862 dict = createInterfaceDict(interface);
1863 CFArrayAppendValue(S_dblist, dict);
1864 CFRelease(dict);
1865 }
1866 CFRelease(interfaces);
1867 }
1868 updatePlatformUUID();
1869 CFRelease(S_dblist);
1870 exit(0);
1871 return 0;
1872 }
1873 #endif /* TEST_PLATFORM_UUID */