]> git.saurik.com Git - apple/configd.git/blob - Plugins/InterfaceNamer/ifnamer.c
configd-130.tar.gz
[apple/configd.git] / Plugins / InterfaceNamer / ifnamer.c
1 /*
2 * Copyright (c) 2001-2003 Apple Computer, 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 * October 3, 2003 Allan Nathanson <ajn@apple.com>
28 * - sort new interfaces by IOKit path (rather than MAC address) to
29 * help facilitate a more predictable interface-->name mapping for
30 * like hardware configurations.
31 *
32 * June 23, 2001 Allan Nathanson <ajn@apple.com>
33 * - update to public SystemConfiguration.framework APIs
34 *
35 * January 23, 2001 Dieter Siegmund <dieter@apple.com>
36 * - initial revision
37 */
38
39 /*
40 * ifnamer.c
41 * - module that receives IOKit Network Interface messages
42 * and names any interface that currently does not have a name
43 * - uses Interface Type and MACAddress as the unique identifying
44 * keys; any interface that doesn't contain both of these properties
45 * is ignored and not processed
46 * - stores the Interface Type, MACAddress, and Unit in permanent storage
47 * to give persistent interface names
48 */
49
50 #include <ctype.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <unistd.h>
54 #include <fcntl.h>
55 #include <sys/sockio.h>
56 #include <sys/stat.h>
57 #include <sys/param.h>
58 #include <mach/mach.h>
59 #include <net/if_types.h>
60
61 #include <CoreFoundation/CoreFoundation.h>
62
63 #include <SystemConfiguration/SystemConfiguration.h>
64 #include <SystemConfiguration/SCDPlugin.h>
65 #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
66 #include <SystemConfiguration/SCValidation.h>
67
68 #include <SystemConfiguration/BondConfiguration.h>
69 #include <SystemConfiguration/BondConfigurationPrivate.h>
70
71 #include <SystemConfiguration/VLANConfiguration.h>
72 #include <SystemConfiguration/VLANConfigurationPrivate.h>
73
74 #include <IOKit/IOKitLib.h>
75 #include <IOKit/IOBSD.h>
76 #include <IOKit/network/IONetworkController.h>
77 #include <IOKit/network/IONetworkInterface.h>
78
79 #ifndef kIOBuiltin
80 #define kIOBuiltin "IOBuiltin"
81 #endif
82
83 #ifndef kIOLocation
84 #define kIOLocation "IOLocation"
85 #endif
86
87 #define kIONetworkStackUserCommand "IONetworkStackUserCommand"
88 #define kIORegisterOne 1
89
90 #define MY_PLUGIN_NAME "InterfaceNamer"
91
92 static boolean_t S_debug = FALSE;
93 static CFMutableArrayRef S_dblist = NULL;
94 static io_connect_t S_connect = MACH_PORT_NULL;
95 static io_iterator_t S_iter = MACH_PORT_NULL;
96 static IONotificationPortRef S_notify = NULL;
97
98 static void
99 writeInterfaceList(CFArrayRef ilist);
100
101 static void
102 displayInterface(CFDictionaryRef if_dict);
103
104 static CFDictionaryRef
105 lookupIOKitPath(CFStringRef if_path);
106
107 static __inline__ CFComparisonResult
108 compareMacAddress(CFDataRef addr1, CFDataRef addr2)
109 {
110 int len1;
111 int len2;
112 int clen;
113 int res;
114
115 len1 = CFDataGetLength(addr1);
116 len2 = CFDataGetLength(addr2);
117
118 if (len1 == len2) {
119 if (len1 == 0)
120 return (kCFCompareEqualTo);
121 return (memcmp(CFDataGetBytePtr(addr1),
122 CFDataGetBytePtr(addr2),
123 len1));
124 }
125 clen = len1;
126 if (len2 < clen)
127 clen = len2;
128 res = memcmp(CFDataGetBytePtr(addr1),
129 CFDataGetBytePtr(addr2),
130 clen);
131 if (res == 0) {
132 return (len1 - len2);
133 }
134 return (res);
135 }
136
137 static CFComparisonResult
138 if_unit_compare(const void *val1, const void *val2, void *context)
139 {
140 CFComparisonResult res;
141 CFNumberRef type1;
142 CFNumberRef type2;
143 CFNumberRef unit1;
144 CFNumberRef unit2;
145
146 type1 = CFDictionaryGetValue((CFDictionaryRef)val1,
147 CFSTR(kIOInterfaceType));
148 type2 = CFDictionaryGetValue((CFDictionaryRef)val2,
149 CFSTR(kIOInterfaceType));
150 res = CFNumberCompare(type1, type2, NULL);
151 if (res != kCFCompareEqualTo) {
152 return (res);
153 }
154 unit1 = CFDictionaryGetValue((CFDictionaryRef)val1,
155 CFSTR(kIOInterfaceUnit));
156 unit2 = CFDictionaryGetValue((CFDictionaryRef)val2,
157 CFSTR(kIOInterfaceUnit));
158 return (CFNumberCompare(unit1, unit2, NULL));
159 }
160
161 static CFArrayRef
162 split_path(CFStringRef path)
163 {
164 CFArrayRef components;
165 CFMutableStringRef nPath;
166
167 // turn '@'s into '/'s
168 nPath = CFStringCreateMutableCopy(NULL, 0, path);
169 (void) CFStringFindAndReplace(nPath,
170 CFSTR("@"),
171 CFSTR("/"),
172 CFRangeMake(0, CFStringGetLength(nPath)),
173 0);
174
175 // split path into components to be compared
176 components = CFStringCreateArrayBySeparatingStrings(NULL, nPath, CFSTR("/"));
177 CFRelease(nPath);
178
179 return components;
180 }
181
182
183 static CFComparisonResult
184 if_path_compare(const void *val1, const void *val2, void *context)
185 {
186 CFBooleanRef builtin;
187 Boolean builtin_val1 = FALSE;
188 Boolean builtin_val2 = FALSE;
189 CFArrayRef elements1 = NULL;
190 CFArrayRef elements2 = NULL;
191 CFIndex i;
192 CFIndex n;
193 CFIndex n1 = 0;
194 CFIndex n2 = 0;
195 CFStringRef path;
196 CFComparisonResult res;
197 CFNumberRef type1;
198 CFNumberRef type2;
199
200 /* sort by interface type */
201
202 type1 = CFDictionaryGetValue((CFDictionaryRef)val1, CFSTR(kIOInterfaceType));
203 type2 = CFDictionaryGetValue((CFDictionaryRef)val2, CFSTR(kIOInterfaceType));
204 res = CFNumberCompare(type1, type2, NULL);
205 if (res != kCFCompareEqualTo) {
206 return (res);
207 }
208
209 /* built-in interfaces sort first */
210 builtin = CFDictionaryGetValue((CFDictionaryRef)val1, CFSTR(kIOBuiltin));
211 if (isA_CFBoolean(builtin) != NULL) {
212 builtin_val1 = CFBooleanGetValue(builtin);
213 }
214 builtin = CFDictionaryGetValue((CFDictionaryRef)val2, CFSTR(kIOBuiltin));
215 if (isA_CFBoolean(builtin) != NULL) {
216 builtin_val2 = CFBooleanGetValue(builtin);
217 }
218 if (builtin_val1 != builtin_val2) {
219 if (builtin_val1) {
220 res = kCFCompareLessThan;
221 } else {
222 res = kCFCompareGreaterThan;
223 }
224 return (res);
225 }
226
227 /* ... and then sort built-in interfaces by "location" */
228 if (builtin_val1) {
229 CFStringRef location1;
230 CFStringRef location2;
231
232 location1 = CFDictionaryGetValue((CFDictionaryRef)val1, CFSTR(kIOLocation));
233 location2 = CFDictionaryGetValue((CFDictionaryRef)val2, CFSTR(kIOLocation));
234 if (location1 != location2) {
235 if (isA_CFString(location1)) {
236 if (isA_CFString(location2)) {
237 res = CFStringCompare(location1, location2, 0);
238 } else {
239 res = kCFCompareLessThan;
240 }
241 } else {
242 res = kCFCompareGreaterThan;
243 }
244
245 if (res != kCFCompareEqualTo) {
246 return (res);
247 }
248 }
249 }
250
251 /* ... and then sort by IOPathMatch */
252
253 path = CFDictionaryGetValue((CFDictionaryRef)val1, CFSTR(kIOPathMatchKey));
254 if (isA_CFString(path)) {
255 elements1 = split_path(path);
256 n1 = CFArrayGetCount(elements1);
257 } else {
258 goto done;
259 }
260
261 path = CFDictionaryGetValue((CFDictionaryRef)val2, CFSTR(kIOPathMatchKey));
262 if (isA_CFString(path)) {
263 elements2 = split_path(path);
264 n2 = CFArrayGetCount(elements2);
265 } else {
266 goto done;
267 }
268
269 n = (n1 <= n2) ? n1 : n2;
270 for (i = 0; i < n; i++) {
271 CFStringRef e1;
272 CFStringRef e2;
273 char *end;
274 quad_t q1;
275 quad_t q2;
276 char *str;
277 Boolean isNum;
278
279 e1 = CFArrayGetValueAtIndex(elements1, i);
280 e2 = CFArrayGetValueAtIndex(elements2, i);
281
282 str = _SC_cfstring_to_cstring(e1, NULL, 0, kCFStringEncodingASCII);
283 errno = 0;
284 q1 = strtoq(str, &end, 16);
285 isNum = ((*str != '\0') && (*end == '\0') && (errno == 0));
286 CFAllocatorDeallocate(NULL, str);
287
288 if (isNum) {
289 // if e1 is a valid numeric string
290 str = _SC_cfstring_to_cstring(e2, NULL, 0, kCFStringEncodingASCII);
291 errno = 0;
292 q2 = strtoq(str, &end, 16);
293 isNum = ((*str != '\0') && (*end == '\0') && (errno == 0));
294 CFAllocatorDeallocate(NULL, str);
295
296 if (isNum) {
297 // if e2 is also a valid numeric string
298
299 if (q1 == q2) {
300 res = kCFCompareEqualTo;
301 continue;
302 } else if (q1 < q2) {
303 res = kCFCompareLessThan;
304 } else {
305 res = kCFCompareGreaterThan;
306 }
307 break;
308 }
309 }
310
311 res = CFStringCompare(e1, e2, 0);
312 if (res != kCFCompareEqualTo) {
313 break;
314 }
315 }
316
317 if (res == kCFCompareEqualTo) {
318 if (n1 < n2) {
319 res = kCFCompareLessThan;
320 } else if (n1 < n2) {
321 res = kCFCompareGreaterThan;
322 }
323 }
324
325 done :
326 if ( elements1 ) CFRelease( elements1 );
327 if ( elements2 ) CFRelease( elements2 );
328
329 return res;
330 }
331
332 static boolean_t
333 addCFStringProperty( CFMutableDictionaryRef dict,
334 const char * key,
335 const char * string )
336 {
337 boolean_t ret = false;
338 CFStringRef valObj, keyObj;
339
340 if ( (string == 0) || (key == 0) || (dict == 0) )
341 return false;
342
343 keyObj = CFStringCreateWithCString(NULL,
344 key,
345 kCFStringEncodingASCII );
346
347 valObj = CFStringCreateWithCString(NULL,
348 string,
349 kCFStringEncodingASCII );
350
351 if (valObj && keyObj) {
352 CFDictionarySetValue( dict, keyObj, valObj );
353 ret = true;
354 }
355
356 if ( keyObj ) CFRelease( keyObj );
357 if ( valObj ) CFRelease( valObj );
358
359 return ret;
360 }
361
362 static boolean_t
363 addCFNumberProperty( CFMutableDictionaryRef dict,
364 const char * key,
365 unsigned int number )
366 {
367 boolean_t ret = false;
368 CFNumberRef numObj;
369 CFStringRef keyObj;
370
371 if ( (key == 0) || (dict == 0) )
372 return false;
373
374 numObj = CFNumberCreate(NULL,
375 kCFNumberLongType,
376 &number);
377
378 keyObj = CFStringCreateWithCString(NULL,
379 key,
380 kCFStringEncodingASCII );
381
382 if ( numObj && keyObj )
383 {
384 CFDictionarySetValue( dict, keyObj, numObj );
385 ret = true;
386 }
387
388 if ( numObj ) CFRelease( numObj );
389 if ( keyObj ) CFRelease( keyObj );
390
391 return ret;
392 }
393
394 static void *
395 read_file(char * filename, size_t * data_length)
396 {
397 void * data = NULL;
398 size_t len = 0;
399 int fd = -1;
400 struct stat sb;
401
402 *data_length = 0;
403 if (stat(filename, &sb) < 0)
404 goto done;
405 len = sb.st_size;
406 if (len == 0)
407 goto done;
408
409 data = malloc(len);
410 if (data == NULL)
411 goto done;
412
413 fd = open(filename, O_RDONLY);
414 if (fd < 0)
415 goto done;
416
417 if (read(fd, data, len) != len) {
418 SCLog(TRUE, LOG_INFO,
419 CFSTR(MY_PLUGIN_NAME ": read %s failed, %s"),
420 filename, strerror(errno));
421 goto done;
422 }
423 done:
424 if (fd >= 0)
425 close(fd);
426 if (data) {
427 *data_length = len;
428 }
429 return (data);
430 }
431
432 static CFPropertyListRef
433 readPropertyList(char * filename)
434 {
435 void * buf;
436 size_t bufsize;
437 CFDataRef data = NULL;
438 CFPropertyListRef plist = NULL;
439 CFStringRef errorString = NULL;
440
441 buf = read_file(filename, &bufsize);
442 if (buf == NULL) {
443 return (NULL);
444 }
445 data = CFDataCreate(NULL, buf, bufsize);
446 if (data == NULL) {
447 goto error;
448 }
449
450 plist = CFPropertyListCreateFromXMLData(NULL, data,
451 kCFPropertyListMutableContainers,
452 &errorString);
453 if (plist == NULL) {
454 if (errorString) {
455 SCLog(TRUE, LOG_INFO,
456 CFSTR(MY_PLUGIN_NAME ":%@"),
457 errorString);
458 CFRelease(errorString);
459 }
460 }
461 error:
462 if (data)
463 CFRelease(data);
464 if (buf)
465 free(buf);
466 return (plist);
467 }
468
469 #define IFNAMER_ID CFSTR("com.apple.SystemConfiguration.InterfaceNamer")
470 #define INTERFACES CFSTR("Interfaces")
471 #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist")
472 #define OLD_NETWORK_INTERFACES_FILE "/var/db/NetworkInterfaces.xml"
473
474 static CFMutableArrayRef
475 readInterfaceList()
476 {
477 CFArrayRef ilist;
478 CFMutableArrayRef plist = NULL;
479 SCPreferencesRef prefs = NULL;
480
481 prefs = SCPreferencesCreate(NULL, IFNAMER_ID, NETWORK_INTERFACES_PREFS);
482 if (!prefs) {
483 SCLog(TRUE, LOG_INFO,
484 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate failed, %s"),
485 SCErrorString(SCError()));
486 return (NULL);
487 }
488
489 ilist = SCPreferencesGetValue(prefs, INTERFACES);
490 if (isA_CFArray(ilist)) {
491 plist = CFArrayCreateMutableCopy(NULL, 0, ilist);
492 } else {
493 plist = (CFMutableArrayRef)readPropertyList(OLD_NETWORK_INTERFACES_FILE);
494 if (plist == NULL) {
495 goto done;
496 }
497 if (isA_CFArray(plist) == NULL) {
498 CFRelease(plist);
499 goto done;
500 }
501 writeInterfaceList(plist);
502 (void)unlink(OLD_NETWORK_INTERFACES_FILE);
503 }
504
505 done:
506 if (prefs) {
507 CFRelease(prefs);
508 }
509 return (plist);
510 }
511
512 static void
513 writeInterfaceList(CFArrayRef ilist)
514 {
515 SCPreferencesRef prefs;
516
517 if (isA_CFArray(ilist) == NULL) {
518 return;
519 }
520
521 prefs = SCPreferencesCreate(NULL, IFNAMER_ID, NETWORK_INTERFACES_PREFS);
522 if (prefs == NULL) {
523 SCLog(TRUE, LOG_INFO,
524 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate failed, %s"),
525 SCErrorString(SCError()));
526 return;
527 }
528
529 if (!SCPreferencesSetValue(prefs, INTERFACES, ilist)) {
530 SCLog(TRUE, LOG_INFO,
531 CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetValue failed, %s"),
532 SCErrorString(SCError()));
533 goto done;
534 }
535
536 if (!SCPreferencesCommitChanges(prefs)) {
537 SCLog(TRUE, LOG_INFO,
538 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCommitChanges failed, %s"),
539 SCErrorString(SCError()));
540 goto done;
541 }
542
543 done:
544
545 CFRelease(prefs);
546 return;
547 }
548
549 static void
550 updateBondConfiguration(void)
551 {
552 BondPreferencesRef prefs;
553
554 prefs = BondPreferencesCreate(NULL);
555 if (prefs == NULL) {
556 SCLog(TRUE, LOG_INFO,
557 CFSTR(MY_PLUGIN_NAME ": BondPreferencesCreate failed, %s"),
558 SCErrorString(SCError()));
559 return;
560 }
561
562 if (!_BondPreferencesUpdateConfiguration(prefs)) {
563 SCLog(TRUE, LOG_INFO,
564 CFSTR(MY_PLUGIN_NAME ": _BondPreferencesUpdateConfiguration failed, %s"),
565 SCErrorString(SCError()));
566 goto done;
567 }
568
569 done:
570
571 CFRelease(prefs);
572 return;
573 }
574
575 static void
576 updateVLANConfiguration(void)
577 {
578 VLANPreferencesRef prefs;
579
580 prefs = VLANPreferencesCreate(NULL);
581 if (prefs == NULL) {
582 SCLog(TRUE, LOG_INFO,
583 CFSTR(MY_PLUGIN_NAME ": VLANPreferencesCreate failed, %s"),
584 SCErrorString(SCError()));
585 return;
586 }
587
588 if (!_VLANPreferencesUpdateConfiguration(prefs)) {
589 SCLog(TRUE, LOG_INFO,
590 CFSTR(MY_PLUGIN_NAME ": _VLANPreferencesUpdateConfiguration failed, %s"),
591 SCErrorString(SCError()));
592 goto done;
593 }
594
595 done:
596
597 CFRelease(prefs);
598 return;
599 }
600
601 #define INDEX_BAD (-1)
602
603 static CFDictionaryRef
604 lookupInterfaceByType(CFArrayRef list, CFDictionaryRef if_dict, int * where)
605 {
606 CFDataRef addr;
607 CFIndex i;
608 CFIndex n;
609 CFNumberRef type;
610
611 if (where) {
612 *where = INDEX_BAD;
613 }
614 if (list == NULL) {
615 return (NULL);
616 }
617 addr = CFDictionaryGetValue(if_dict, CFSTR(kIOMACAddress));
618 type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType));
619 if (type == NULL || addr == NULL) {
620 return (NULL);
621 }
622
623 n = CFArrayGetCount(list);
624 for (i = 0; i < n; i++) {
625 CFDictionaryRef dict = CFArrayGetValueAtIndex(list, i);
626 CFDataRef a;
627 CFNumberRef t;
628
629 a = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress));
630 t = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
631 if (a == NULL || t == NULL)
632 continue;
633
634 if (CFNumberCompare(type, t, NULL) == kCFCompareEqualTo
635 && compareMacAddress(addr, a) == kCFCompareEqualTo) {
636 if (where) {
637 *where = i;
638 }
639 return (dict);
640 }
641 }
642 return (NULL);
643 }
644
645 static CFDictionaryRef
646 lookupInterfaceByUnit(CFArrayRef list, CFDictionaryRef if_dict, int * where)
647 {
648 CFIndex i;
649 CFIndex n;
650 CFNumberRef type;
651 CFNumberRef unit;
652
653 if (where) {
654 *where = INDEX_BAD;
655 }
656 if (list == NULL) {
657 return (NULL);
658 }
659 type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType));
660 unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit));
661 if (type == NULL || unit == NULL) {
662 return (NULL);
663 }
664
665 n = CFArrayGetCount(list);
666 for (i = 0; i < n; i++) {
667 CFDictionaryRef dict = CFArrayGetValueAtIndex(list, i);
668 CFNumberRef t;
669 CFNumberRef u;
670
671 t = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
672 u = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
673 if (t == NULL || u == NULL) {
674 continue;
675 }
676
677 if (CFNumberCompare(type, t, NULL) == kCFCompareEqualTo
678 && CFNumberCompare(unit, u, NULL) == kCFCompareEqualTo) {
679 if (where)
680 *where = i;
681 return (dict);
682 }
683 }
684 return (NULL);
685 }
686
687 #define kAirPortDriverPath CFSTR("AirPort")
688 #define kIO80211InterfacePath CFSTR("IO80211Interface")
689 #define APPLE_WIRELESS_80211 CFSTR("AppleWireless80211")
690
691 static __inline__ boolean_t
692 pathIsAirPort(CFStringRef path)
693 {
694 CFRange r;
695
696 r = CFStringFind(path, kIO80211InterfacePath, 0);
697 if (r.location != kCFNotFound) {
698 return (TRUE);
699 }
700
701 r = CFStringFind(path, kAirPortDriverPath, 0);
702 if (r.location != kCFNotFound) {
703 return (TRUE);
704 }
705
706 r = CFStringFind(path, APPLE_WIRELESS_80211, 0);
707 if (r.location != kCFNotFound) {
708 return (TRUE);
709 }
710
711 return (FALSE);
712 }
713
714 static CFDictionaryRef
715 lookupAirPortInterface(CFArrayRef list, int * where)
716 {
717 CFIndex i;
718 CFIndex n;
719
720 if (where) {
721 *where = INDEX_BAD;
722 }
723 if (list == NULL) {
724 return (NULL);
725 }
726 n = CFArrayGetCount(list);
727 for (i = 0; i < n; i++) {
728 CFDictionaryRef dict = CFArrayGetValueAtIndex(list, i);
729 CFStringRef path;
730
731 path = CFDictionaryGetValue(dict, CFSTR(kIOPathMatchKey));
732 if (path == NULL) {
733 continue;
734 }
735 if (pathIsAirPort(path) == TRUE) {
736 if (where)
737 *where = i;
738 return (dict);
739 }
740 }
741 return (NULL);
742 }
743
744 static void
745 insertInterface(CFMutableArrayRef list, CFDictionaryRef if_dict)
746 {
747 CFIndex i;
748 CFNumberRef if_type;
749 CFNumberRef if_unit;
750 CFIndex n = CFArrayGetCount(list);
751 CFComparisonResult res;
752
753 if_type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType));
754 if_unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit));
755 for (i = 0; i < n; i++) {
756 CFDictionaryRef dict = CFArrayGetValueAtIndex(list, i);
757 CFNumberRef type;
758 CFNumberRef unit;
759
760 type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
761 unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
762 res = CFNumberCompare(if_type, type, NULL);
763 if (res == kCFCompareLessThan
764 || (res == kCFCompareEqualTo
765 && (CFNumberCompare(if_unit, unit, NULL)
766 == kCFCompareLessThan))) {
767 CFArrayInsertValueAtIndex(list, i, if_dict);
768 return;
769 }
770 }
771 CFArrayAppendValue(S_dblist, if_dict);
772 return;
773 }
774
775 static void
776 replaceInterface(CFDictionaryRef if_dict)
777 {
778 int where;
779
780 if (S_dblist == NULL) {
781 S_dblist = CFArrayCreateMutable(NULL, 0,
782 &kCFTypeArrayCallBacks);
783 }
784 /* remove any dict that has our type/addr */
785 if (lookupInterfaceByType(S_dblist, if_dict, &where) != NULL) {
786 CFArrayRemoveValueAtIndex(S_dblist, where);
787 }
788 /* remove any dict that has the same type/unit */
789 if (lookupInterfaceByUnit(S_dblist, if_dict, &where) != NULL) {
790 CFArrayRemoveValueAtIndex(S_dblist, where);
791 }
792 insertInterface(S_dblist, if_dict);
793 return;
794 }
795
796 static CFNumberRef
797 getHighestUnitForType(CFNumberRef if_type)
798 {
799 int i;
800 CFIndex n;
801 CFNumberRef ret_unit = NULL;
802
803 if (S_dblist == NULL)
804 return (NULL);
805
806 n = CFArrayGetCount(S_dblist);
807 for (i = 0; i < n; i++) {
808 CFDictionaryRef dict = CFArrayGetValueAtIndex(S_dblist, i);
809 CFNumberRef type;
810 CFNumberRef unit;
811
812 type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType));
813 if (CFEqual(type, if_type)) {
814 unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit));
815 if (ret_unit == NULL
816 || (CFNumberCompare(unit, ret_unit, NULL)
817 == kCFCompareGreaterThan)) {
818 ret_unit = unit;
819 }
820 }
821 }
822 return (ret_unit);
823 }
824
825 //------------------------------------------------------------------------
826 // Register a single interface with the given service path to the
827 // data link layer (BSD), using the specified unit number.
828
829 static kern_return_t
830 registerInterface(io_connect_t connect,
831 CFStringRef path,
832 CFNumberRef unit)
833 {
834 CFMutableDictionaryRef dict;
835 kern_return_t kr = kIOReturnNoMemory;
836
837 dict = CFDictionaryCreateMutable(NULL, 0,
838 &kCFTypeDictionaryKeyCallBacks,
839 &kCFTypeDictionaryValueCallBacks);
840 if (dict == NULL
841 || addCFNumberProperty(dict, kIONetworkStackUserCommand,
842 kIORegisterOne) == FALSE)
843 ;
844 else {
845 CFDictionarySetValue(dict, CFSTR(kIOPathMatchKey), path);
846 CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit);
847 kr = IOConnectSetCFProperties(connect, dict);
848 }
849 if (dict) CFRelease( dict );
850 return kr;
851 }
852
853 /*
854 * Note: this function blocks all other plug-ins until it completes
855 */
856 static void
857 waitForQuiet(mach_port_t masterPort)
858 {
859 mach_timespec_t t;
860 kern_return_t wait_ret;
861
862 t.tv_sec = 4;
863 t.tv_nsec = 0;
864
865 // kIOReturnTimeout if the wait timed out.
866 // kIOReturnSuccess on success.
867 wait_ret = IOKitWaitQuiet(masterPort, &t);
868 return;
869 }
870
871 /*
872 * Function: createNetworkStackObject
873 * Purpose:
874 * Get a reference to the single IONetworkStack object instance in
875 * the kernel. Naming requests must be sent to this object, which is
876 * attached as a client to all network interface objects in the system.
877 * Note:
878 * Call IOObjectRelease on the returned object.
879 */
880 static io_object_t
881 createNetworkStackObject(mach_port_t masterPort)
882 {
883 io_iterator_t iter = MACH_PORT_NULL;
884 kern_return_t kr;
885 io_object_t stack = MACH_PORT_NULL;
886
887 kr = IOServiceGetMatchingServices(masterPort,
888 IOServiceMatching("IONetworkStack"),
889 &iter);
890 if (iter != MACH_PORT_NULL) {
891 if (kr == KERN_SUCCESS) {
892 stack = IOIteratorNext(iter);
893 }
894 IOObjectRelease(iter);
895 }
896 return stack;
897 }
898
899 static void
900 printMacAddress(CFDataRef data)
901 {
902 int i;
903 CFIndex n = CFDataGetLength(data);
904
905 for (i = 0; i < n; i++) {
906 if (i != 0) SCPrint(TRUE, stdout, CFSTR(":"));
907 SCPrint(TRUE, stdout, CFSTR("%02x"), CFDataGetBytePtr(data)[i]);
908 }
909 return;
910 }
911
912 /*
913 * Function: getMacAddress
914 *
915 * Purpose:
916 * Given an interface object if_obj, return its associated mac address.
917 * The mac address is stored in the parent, the network controller object.
918 *
919 * Returns:
920 * The CFDataRef containing the bytes of the mac address.
921 */
922 static CFDataRef
923 getMacAddress(io_object_t if_obj)
924 {
925 CFMutableDictionaryRef dict = NULL;
926 CFDataRef data = NULL;
927 kern_return_t kr;
928 io_object_t parent_obj = MACH_PORT_NULL;
929
930 /* get the parent node */
931 kr = IORegistryEntryGetParentEntry(if_obj, kIOServicePlane, &parent_obj);
932 if (kr != KERN_SUCCESS) {
933 SCLog(TRUE, LOG_INFO,
934 CFSTR(MY_PLUGIN_NAME
935 ": IORegistryEntryGetParentEntry returned 0x%x"),
936 kr);
937 goto failed;
938 }
939
940 /* get the dictionary associated with the node */
941 kr = IORegistryEntryCreateCFProperties(parent_obj,
942 &dict,
943 NULL,
944 kNilOptions );
945 if (kr != KERN_SUCCESS) {
946 SCLog(TRUE, LOG_INFO,
947 CFSTR(MY_PLUGIN_NAME
948 ": IORegistryEntryCreateCFProperties returned 0x%x"),
949 kr);
950 goto failed;
951 }
952 data = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress));
953 if (data) {
954 CFRetain(data);
955 }
956
957 failed:
958 if (dict)
959 CFRelease(dict);
960 if (parent_obj)
961 IOObjectRelease(parent_obj);
962 return (data);
963 }
964
965 static CFDictionaryRef
966 getInterface(io_object_t if_obj)
967 {
968 CFBooleanRef builtin;
969 kern_return_t kr;
970 CFDataRef mac_address = NULL;
971 CFStringRef location;
972 CFMutableDictionaryRef new_if = NULL;
973 io_string_t path;
974 CFMutableDictionaryRef reginfo_if = NULL;
975 CFDictionaryRef ret_dict = NULL;
976 CFStringRef string;
977 CFNumberRef type;
978 CFNumberRef unit;
979
980 kr = IORegistryEntryGetPath(if_obj, kIOServicePlane, path);
981 if (kr != KERN_SUCCESS) {
982 SCLog(TRUE, LOG_INFO,
983 CFSTR(MY_PLUGIN_NAME
984 ": IORegistryEntryGetPath returned 0x%x"),
985 kr);
986 goto failed;
987 }
988 kr = IORegistryEntryCreateCFProperties(if_obj,
989 &reginfo_if,
990 NULL,
991 kNilOptions);
992 if (kr != KERN_SUCCESS) {
993 SCLog(TRUE, LOG_INFO,
994 CFSTR(MY_PLUGIN_NAME
995 ": IORegistryEntryCreateCFProperties returned 0x%x"),
996 kr);
997 goto failed;
998 }
999 type = isA_CFNumber(CFDictionaryGetValue(reginfo_if,
1000 CFSTR(kIOInterfaceType)));
1001 if (type == NULL) {
1002 goto failed;
1003 }
1004 mac_address = getMacAddress(if_obj);
1005 if (mac_address == NULL) {
1006 goto failed;
1007 }
1008 builtin = isA_CFBoolean(CFDictionaryGetValue(reginfo_if,
1009 CFSTR(kIOBuiltin)));
1010 if ((builtin == NULL) || !CFBooleanGetValue(builtin)) {
1011 builtin = isA_CFBoolean(CFDictionaryGetValue(reginfo_if,
1012 CFSTR(kIOPrimaryInterface)));
1013 }
1014 location = isA_CFString(CFDictionaryGetValue(reginfo_if,
1015 CFSTR(kIOLocation)));
1016
1017 new_if = CFDictionaryCreateMutable(NULL, 0,
1018 &kCFTypeDictionaryKeyCallBacks,
1019 &kCFTypeDictionaryValueCallBacks);
1020 if (new_if == NULL) {
1021 goto failed;
1022 }
1023 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceType), type);
1024 CFDictionarySetValue(new_if, CFSTR(kIOMACAddress), mac_address);
1025 if (builtin) {
1026 CFDictionarySetValue(new_if, CFSTR(kIOBuiltin), builtin);
1027 }
1028 if (location) {
1029 CFDictionarySetValue(new_if, CFSTR(kIOLocation), location);
1030 }
1031 addCFStringProperty(new_if, kIOPathMatchKey, path);
1032
1033 unit = isA_CFNumber(CFDictionaryGetValue(reginfo_if,
1034 CFSTR(kIOInterfaceUnit)));
1035 if (unit) {
1036 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceUnit), unit);
1037 }
1038 string = isA_CFString(CFDictionaryGetValue(reginfo_if, CFSTR(kIOBSDNameKey)));
1039 if (string) {
1040 CFDictionarySetValue(new_if, CFSTR(kIOBSDNameKey), string);
1041 }
1042 ret_dict = new_if;
1043 new_if = NULL;
1044
1045 failed:
1046 if (new_if) {
1047 CFRelease(new_if);
1048 }
1049 if (reginfo_if) {
1050 CFRelease(reginfo_if);
1051 }
1052 if (mac_address) {
1053 CFRelease(mac_address);
1054 }
1055 return (ret_dict);
1056 }
1057
1058 static CFDictionaryRef
1059 lookupIOKitPath(CFStringRef if_path)
1060 {
1061 CFDictionaryRef dict = NULL;
1062 io_registry_entry_t entry = MACH_PORT_NULL;
1063 kern_return_t kr;
1064 mach_port_t masterPort = MACH_PORT_NULL;
1065 io_string_t path;
1066
1067 kr = IOMasterPort(bootstrap_port, &masterPort);
1068 if (kr != KERN_SUCCESS) {
1069 SCLog(TRUE, LOG_INFO,
1070 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x\n"),
1071 kr);
1072 goto error;
1073 }
1074 _SC_cfstring_to_cstring(if_path, path, sizeof(path), kCFStringEncodingASCII);
1075 entry = IORegistryEntryFromPath(masterPort, path);
1076 if (entry == MACH_PORT_NULL) {
1077 SCLog(TRUE, LOG_INFO,
1078 CFSTR(MY_PLUGIN_NAME ": IORegistryEntryFromPath(%@) failed"),
1079 if_path);
1080 goto error;
1081 }
1082 dict = getInterface(entry);
1083
1084 error:
1085 if (masterPort != MACH_PORT_NULL) {
1086 mach_port_deallocate(mach_task_self(), masterPort);
1087 }
1088 if (entry != MACH_PORT_NULL) {
1089 IOObjectRelease(entry);
1090 }
1091 return (dict);
1092
1093 }
1094
1095 static void
1096 displayInterface(CFDictionaryRef if_dict)
1097 {
1098 CFStringRef name;
1099 CFNumberRef type;
1100 CFNumberRef unit;
1101
1102 name = CFDictionaryGetValue(if_dict, CFSTR(kIOBSDNameKey));
1103 if (name) {
1104 SCPrint(TRUE, stdout, CFSTR("BSD Name: %@\n"), name);
1105 }
1106
1107 unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit));
1108 if (unit) {
1109 SCPrint(TRUE, stdout, CFSTR("Unit: %@\n"), unit);
1110 }
1111
1112 type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType));
1113 SCPrint(TRUE, stdout, CFSTR("Type: %@\n"), type);
1114
1115 SCPrint(TRUE, stdout, CFSTR("MAC address: "));
1116 printMacAddress(CFDictionaryGetValue(if_dict, CFSTR(kIOMACAddress)));
1117 SCPrint(TRUE, stdout, CFSTR("\n"));
1118 }
1119
1120 static void
1121 sort_interfaces_by_unit(CFMutableArrayRef if_list)
1122 {
1123 int count = CFArrayGetCount(if_list);
1124 CFRange range = CFRangeMake(0, count);
1125
1126 if (count < 2)
1127 return;
1128 CFArraySortValues(if_list, range, if_unit_compare, NULL);
1129 return;
1130 }
1131
1132 static void
1133 sort_interfaces_by_path(CFMutableArrayRef if_list)
1134 {
1135 int count = CFArrayGetCount(if_list);
1136 CFRange range = CFRangeMake(0, count);
1137
1138 if (count < 2)
1139 return;
1140 CFArraySortValues(if_list, range, if_path_compare, NULL);
1141 return;
1142 }
1143
1144 static void
1145 name_interfaces(CFArrayRef if_list)
1146 {
1147 CFIndex i;
1148 CFIndex n = CFArrayGetCount(if_list);
1149 CFIndex i_builtin = 0;
1150 CFIndex n_builtin = 0;
1151
1152 if (S_debug)
1153 SCPrint(TRUE, stdout, CFSTR("\n"));
1154
1155 for (i = 0; i < n; i++) {
1156 CFBooleanRef builtin;
1157 CFDictionaryRef if_dict;
1158
1159 if_dict = CFArrayGetValueAtIndex(if_list, i);
1160 builtin = CFDictionaryGetValue(if_dict, CFSTR(kIOBuiltin));
1161 if (builtin && CFBooleanGetValue(builtin)) {
1162 n_builtin++; // reserve unit number for built-in interface
1163 }
1164 }
1165
1166 for (i = 0; i < n; i++) {
1167 CFDictionaryRef if_dict;
1168 CFNumberRef type;
1169 CFNumberRef unit;
1170
1171 if (S_debug) {
1172 if (i != 0)
1173 SCPrint(TRUE, stdout, CFSTR("\n"));
1174 }
1175
1176 if_dict = CFArrayGetValueAtIndex(if_list, i);
1177 unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit));
1178 type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType));
1179 if (unit) {
1180 if (S_debug) {
1181 SCPrint(TRUE, stdout, CFSTR("Interface already has a unit number\n"));
1182 displayInterface(if_dict);
1183 }
1184 replaceInterface(if_dict);
1185 }
1186 else {
1187 CFDictionaryRef dbdict = NULL;
1188 kern_return_t kr = KERN_SUCCESS;
1189 CFStringRef path;
1190 CFNumberRef unit = NULL;
1191
1192 path = CFDictionaryGetValue(if_dict, CFSTR(kIOPathMatchKey));
1193 dbdict = lookupInterfaceByType(S_dblist, if_dict, NULL);
1194 if (dbdict == NULL
1195 && pathIsAirPort(path) == TRUE) {
1196 dbdict = lookupAirPortInterface(S_dblist, NULL);
1197 }
1198 if (dbdict != NULL) {
1199 unit = CFDictionaryGetValue(dbdict,
1200 CFSTR(kIOInterfaceUnit));
1201 CFRetain(unit);
1202 }
1203 else {
1204 int if_type;
1205 boolean_t is_builtin = FALSE;
1206 int next_unit = 0;
1207
1208 CFNumberGetValue(type,
1209 kCFNumberIntType, &if_type);
1210 if (if_type == IFT_ETHER) { /* ethernet */
1211 CFBooleanRef builtin;
1212
1213 builtin = CFDictionaryGetValue(if_dict,
1214 CFSTR(kIOBuiltin));
1215 if (builtin && CFBooleanGetValue(builtin)) {
1216 is_builtin = TRUE;
1217 next_unit = i_builtin++;
1218 }
1219 else {
1220 #if defined(__ppc__)
1221 /* skip over slots reserved for built-in ethernet interface(s) */
1222 next_unit = n_builtin;
1223 #endif
1224 }
1225 }
1226 if (is_builtin == FALSE) {
1227 unit = getHighestUnitForType(type);
1228 if (unit) {
1229 int high_unit;
1230
1231 CFNumberGetValue(unit,
1232 kCFNumberIntType, &high_unit);
1233 if (high_unit >= next_unit) {
1234 next_unit = high_unit + 1;
1235 }
1236 }
1237 }
1238 unit = CFNumberCreate(NULL,
1239 kCFNumberIntType, &next_unit);
1240 }
1241 if (S_debug) {
1242 SCPrint(TRUE, stdout, CFSTR("Interface assigned unit %@ %s\n"), unit,
1243 dbdict ? "(from database)" : "(next available)");
1244 }
1245 kr = registerInterface(S_connect, path, unit);
1246 if (kr != KERN_SUCCESS) {
1247 SCLog(TRUE, LOG_INFO,
1248 CFSTR(MY_PLUGIN_NAME
1249 ": failed to name the interface 0x%x"),
1250 kr);
1251 if (S_debug) {
1252 displayInterface(if_dict);
1253 }
1254 }
1255 else {
1256 CFDictionaryRef new_dict;
1257
1258 path = CFDictionaryGetValue(if_dict,
1259 CFSTR(kIOPathMatchKey));
1260 new_dict = lookupIOKitPath(path);
1261 if (new_dict != NULL) {
1262 CFNumberRef new_unit;
1263
1264 new_unit = CFDictionaryGetValue(new_dict,
1265 CFSTR(kIOInterfaceUnit));
1266 if (CFEqual(unit, new_unit) == FALSE) {
1267 SCLog(TRUE, LOG_INFO,
1268 CFSTR(MY_PLUGIN_NAME
1269 ": interface type %@ assigned "
1270 "unit %@ instead of %@"),
1271 type, new_unit, unit);
1272 }
1273 if (S_debug) {
1274 displayInterface(new_dict);
1275 }
1276 replaceInterface(new_dict);
1277 CFRelease(new_dict);
1278 }
1279 }
1280 CFRelease(unit);
1281 }
1282 }
1283 writeInterfaceList(S_dblist);
1284 return;
1285 }
1286
1287 static void
1288 interfaceArrivalCallback( void * refcon, io_iterator_t iter )
1289 {
1290 CFMutableArrayRef if_list = NULL;
1291 io_object_t obj;
1292
1293
1294 while ((obj = IOIteratorNext(iter))) {
1295 CFDictionaryRef dict;
1296
1297 dict = getInterface(obj);
1298 if (dict) {
1299 if (if_list == NULL) {
1300 if_list = CFArrayCreateMutable(NULL, 0,
1301 &kCFTypeArrayCallBacks);
1302 }
1303 if (if_list)
1304 CFArrayAppendValue(if_list, dict);
1305 CFRelease(dict);
1306 }
1307 IOObjectRelease(obj);
1308 }
1309 if (if_list) {
1310 sort_interfaces_by_path(if_list);
1311 name_interfaces(if_list);
1312 updateBondConfiguration();
1313 updateVLANConfiguration();
1314 CFRelease(if_list);
1315 }
1316 return;
1317 }
1318
1319
1320 __private_extern__
1321 void
1322 load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose)
1323 {
1324 kern_return_t kr;
1325 mach_port_t masterPort = MACH_PORT_NULL;
1326 io_object_t stack = MACH_PORT_NULL;
1327
1328 if (bundleVerbose) {
1329 S_debug++;
1330 }
1331
1332 kr = IOMasterPort(bootstrap_port, &masterPort);
1333 if (kr != KERN_SUCCESS) {
1334 SCLog(TRUE, LOG_INFO,
1335 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"),
1336 kr);
1337 goto error;
1338 }
1339
1340 /* synchronize with any drivers that might be loading at boot time */
1341 waitForQuiet(masterPort);
1342
1343 stack = createNetworkStackObject(masterPort);
1344 if (stack == MACH_PORT_NULL) {
1345 SCLog(TRUE, LOG_INFO,
1346 CFSTR(MY_PLUGIN_NAME ": No network stack object"));
1347 goto error;
1348 }
1349 kr = IOServiceOpen(stack, mach_task_self(), 0, &S_connect);
1350 if (kr != KERN_SUCCESS) {
1351 SCPrint(TRUE, stdout, CFSTR(MY_PLUGIN_NAME ": IOServiceOpen returned 0x%x\n"), kr);
1352 goto error;
1353 }
1354
1355 // Creates and returns a notification object for receiving IOKit
1356 // notifications of new devices or state changes.
1357
1358 S_notify = IONotificationPortCreate(masterPort);
1359 if (S_notify == NULL) {
1360 SCLog(TRUE, LOG_INFO,
1361 CFSTR(MY_PLUGIN_NAME ": IONotificationPortCreate failed"));
1362 goto error;
1363 }
1364 kr = IOServiceAddMatchingNotification(S_notify,
1365 kIOFirstMatchNotification,
1366 IOServiceMatching("IONetworkInterface"),
1367 &interfaceArrivalCallback,
1368 (void *) S_notify, /* refCon */
1369 &S_iter ); /* notification */
1370
1371 if (kr != KERN_SUCCESS) {
1372 SCLog(TRUE, LOG_INFO,
1373 CFSTR(MY_PLUGIN_NAME
1374 ": IOServiceAddMatchingNotification returned 0x%x"),
1375 kr);
1376 goto error;
1377 }
1378
1379 S_dblist = readInterfaceList();
1380 if (S_dblist) {
1381 sort_interfaces_by_unit(S_dblist);
1382 }
1383 // Get the current list of matches and arms the notification for
1384 // future interface arrivals.
1385
1386 interfaceArrivalCallback((void *) S_notify, S_iter);
1387
1388 CFRunLoopAddSource(CFRunLoopGetCurrent(),
1389 IONotificationPortGetRunLoopSource(S_notify),
1390 kCFRunLoopDefaultMode);
1391 if (stack != MACH_PORT_NULL) {
1392 IOObjectRelease(stack);
1393 }
1394 if (masterPort != MACH_PORT_NULL) {
1395 mach_port_deallocate(mach_task_self(), masterPort);
1396 }
1397 return;
1398 error:
1399 if (stack != MACH_PORT_NULL) {
1400 IOObjectRelease(stack);
1401 }
1402 if (masterPort != MACH_PORT_NULL) {
1403 mach_port_deallocate(mach_task_self(), masterPort);
1404 }
1405 if (S_connect != MACH_PORT_NULL) {
1406 IOServiceClose(S_connect);
1407 S_connect = MACH_PORT_NULL;
1408 }
1409 if (S_iter != MACH_PORT_NULL) {
1410 IOObjectRelease(S_iter);
1411 S_iter = MACH_PORT_NULL;
1412 }
1413 if (S_notify != MACH_PORT_NULL) {
1414 IONotificationPortDestroy(S_notify);
1415 }
1416 return;
1417 }
1418
1419 //------------------------------------------------------------------------
1420 // Main function.
1421 #ifdef MAIN
1422 int
1423 main(int argc, char ** argv)
1424 {
1425 load_InterfaceNamer(CFBundleGetMainBundle(),
1426 (argc > 1) ? TRUE : FALSE);
1427 CFRunLoopRun();
1428 /* not reached */
1429 exit(0);
1430 return 0;
1431 }
1432 #endif /* MAIN */