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