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