1/* 2 * Copyright (c) 2001-2013 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 aslmsg 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_free(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(); 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(); 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 594static void 595updateBTPANInformation(const void *value, void *context) 596{ CFDictionaryRef dict = (CFDictionaryRef)value; 597 CFStringRef if_name; 598 CFDictionaryRef info; 599 CFStringRef name; 600 601 if_name = CFDictionaryGetValue(dict, CFSTR(kIOBSDNameKey)); 602 if (!isA_CFString(if_name)) { 603 // if no BSD name 604 return; 605 } 606 607 info = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceInfo)); 608 if (!isA_CFDictionary(info)) { 609 // if no SCNetworkInterface info 610 return; 611 } 612 613 name = CFDictionaryGetValue(info, kSCPropUserDefinedName); 614 if (!isA_CFString(name) || !CFEqual(name, CFSTR(BT_PAN_NAME))) { 615 // if not BT-PAN interface 616 return; 617 } 618 619 CFDictionaryAddValue(S_state, CFSTR("_" BT_PAN_NAME "_"), if_name); 620 return; 621} 622#endif // !TARGET_OS_EMBEDDED 623 624static CFDictionaryRef 625createInterfaceDict(SCNetworkInterfaceRef interface) 626{ 627 CFMutableDictionaryRef new_if; 628 CFTypeRef val; 629 630 new_if = CFDictionaryCreateMutable(NULL, 631 0, 632 &kCFTypeDictionaryKeyCallBacks, 633 &kCFTypeDictionaryValueCallBacks); 634 635 val = _SCNetworkInterfaceCopyInterfaceInfo(interface); 636 if (val != NULL) { 637 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceInfo), val); 638 CFRelease(val); 639 } 640 641 val = _SCNetworkInterfaceGetIOPath(interface); 642 if (val != NULL) { 643 CFDictionarySetValue(new_if, CFSTR(kIOPathMatchKey), val); 644 } 645 646 val = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface); 647 if (val != NULL) { 648 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceNamePrefix), val); 649 } 650 651 val = _SCNetworkInterfaceGetIOInterfaceType(interface); 652 if (val != NULL) { 653 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceType), val); 654 } 655 656 val = _SCNetworkInterfaceGetIOInterfaceUnit(interface); 657 if (val != NULL) { 658 CFDictionarySetValue(new_if, CFSTR(kIOInterfaceUnit), val); 659 } 660 661 val = _SCNetworkInterfaceGetHardwareAddress(interface); 662 if (val != NULL) { 663 CFDictionarySetValue(new_if, CFSTR(kIOMACAddress), val); 664 } 665 666 val = SCNetworkInterfaceGetBSDName(interface); 667 if (val != NULL) { 668 CFDictionarySetValue(new_if, CFSTR(kIOBSDNameKey), val); 669 } 670 671 val = SCNetworkInterfaceGetInterfaceType(interface); 672 if (val != NULL) { 673 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceType), val); 674 } 675 676 CFDictionarySetValue(new_if, 677 CFSTR(kIOBuiltin), 678 _SCNetworkInterfaceIsBuiltin(interface) ? kCFBooleanTrue : kCFBooleanFalse); 679 680 CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceActive), kCFBooleanTrue); 681 682 return new_if; 683} 684 685static CFDictionaryRef 686lookupInterfaceByAddress(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where) 687{ 688 CFDataRef addr; 689 CFIndex i; 690 CFIndex n; 691 CFNumberRef type; 692 693 if (db_list == NULL) { 694 return (NULL); 695 } 696 type = _SCNetworkInterfaceGetIOInterfaceType(interface); 697 addr = _SCNetworkInterfaceGetHardwareAddress(interface); 698 if (type == NULL || addr == NULL) { 699 return (NULL); 700 } 701 702 n = CFArrayGetCount(db_list); 703 for (i = 0; i < n; i++) { 704 CFDataRef a; 705 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i); 706 CFNumberRef t; 707 708 t = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); 709 a = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); 710 if (t == NULL || a == NULL) 711 continue; 712 713 if (CFEqual(type, t) && CFEqual(addr, a)) { 714 if (where) { 715 *where = i; 716 } 717 return (dict); 718 } 719 } 720 return (NULL); 721} 722 723static CFDictionaryRef 724lookupInterfaceByUnit(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where) 725{ 726 CFIndex i; 727 CFIndex n; 728 CFNumberRef type; 729 CFNumberRef unit; 730 731 if (db_list == NULL) { 732 return (NULL); 733 } 734 type = _SCNetworkInterfaceGetIOInterfaceType(interface); 735 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); 736 if (type == NULL || unit == NULL) { 737 return (NULL); 738 } 739 740 n = CFArrayGetCount(db_list); 741 for (i = 0; i < n; i++) { 742 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i); 743 CFNumberRef t; 744 CFNumberRef u; 745 746 t = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); 747 u = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit)); 748 if (t == NULL || u == NULL) { 749 continue; 750 } 751 752 if (CFEqual(type, t) && CFEqual(unit, u)) { 753 if (where) 754 *where = i; 755 return (dict); 756 } 757 } 758 return (NULL); 759} 760 761typedef struct { 762 CFDictionaryRef match_info; 763 CFStringRef match_type; 764 CFBooleanRef match_builtin; 765 CFMutableArrayRef matches; 766} matchContext, *matchContextRef; 767 768static CF_RETURNS_RETAINED CFDictionaryRef 769thinInterfaceInfo(CFDictionaryRef info) 770{ 771 CFNumberRef num; 772 int vid; 773 774 if (CFDictionaryGetValueIfPresent(info, CFSTR(kUSBVendorID), (const void **)&num) 775 && isA_CFNumber(num) 776 && CFNumberGetValue(num, kCFNumberIntType, &vid) 777 && (vid == kIOUSBVendorIDAppleComputer)) { 778 CFMutableDictionaryRef thin; 779 780 // if this is an Apple USB device than we trust that 781 // the non-localized name will be correct. 782 thin = CFDictionaryCreateMutableCopy(NULL, 0, info); 783 CFDictionaryRemoveValue(thin, CFSTR(kUSBProductString)); 784 CFDictionaryRemoveValue(thin, CFSTR(kUSBVendorID)); 785 CFDictionaryRemoveValue(thin, CFSTR(kUSBProductID)); 786 return thin; 787 } 788 789 return CFRetain(info); 790} 791 792static Boolean 793matchInterfaceInfo(CFDictionaryRef known_info, CFDictionaryRef match_info) 794{ 795 Boolean match; 796 797 match = _SC_CFEqual(known_info, match_info); 798 if (!match && 799 isA_CFDictionary(known_info) && 800 isA_CFDictionary(match_info)) { 801 802 // if not an exact match, try thinning 803 known_info = thinInterfaceInfo(known_info); 804 match_info = thinInterfaceInfo(match_info); 805 match = _SC_CFEqual(known_info, match_info); 806 if (known_info != NULL) CFRelease(known_info); 807 if (match_info != NULL) CFRelease(match_info); 808 } 809 810 return match; 811} 812 813static void 814matchKnown(const void *value, void *context) 815{ 816 CFDictionaryRef known_dict = (CFDictionaryRef)value; 817 matchContextRef match_context = (matchContextRef)context; 818 819 // match interface type 820 { 821 CFStringRef known_type; 822 823 known_type = CFDictionaryGetValue(known_dict, CFSTR(kSCNetworkInterfaceType)); 824 if (!_SC_CFEqual(known_type, match_context->match_type)) { 825 return; 826 } 827 } 828 829 // match SCNetworkInterfaceInfo 830 { 831 CFDictionaryRef known_info; 832 833 known_info = CFDictionaryGetValue(known_dict, CFSTR(kSCNetworkInterfaceInfo)); 834 if (!matchInterfaceInfo(known_info, match_context->match_info)) { 835 return; 836 } 837 } 838 839 // if requested, match [non-]builtin 840 if (match_context->match_builtin != NULL) { 841 CFBooleanRef known_builtin; 842 843 known_builtin = CFDictionaryGetValue(known_dict, CFSTR(kIOBuiltin)); 844 if (!isA_CFBoolean(known_builtin)) { 845 known_builtin = kCFBooleanFalse; 846 } 847 if (!_SC_CFEqual(known_builtin, match_context->match_builtin)) { 848 return; 849 } 850 } 851 852 // if we have a match 853 if (match_context->matches == NULL) { 854 match_context->matches = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 855 } 856 CFArrayAppendValue(match_context->matches, known_dict); 857 858 return; 859} 860 861static void 862matchUnnamed(const void *value, void *context) 863{ 864 SCNetworkInterfaceRef known_if = (SCNetworkInterfaceRef)value; 865 matchContextRef match_context = (matchContextRef)context; 866 867 if (match_context->matches == NULL) { 868 return; 869 } 870 871 // match interface type 872 { 873 CFStringRef known_type; 874 875 known_type = SCNetworkInterfaceGetInterfaceType(known_if); 876 if (!_SC_CFEqual(known_type, match_context->match_type)) { 877 return; 878 } 879 } 880 881 // match SCNetworkInterfaceInfo 882 { 883 CFDictionaryRef known_info; 884 Boolean match; 885 886 known_info = _SCNetworkInterfaceCopyInterfaceInfo(known_if); 887 match = matchInterfaceInfo(known_info, match_context->match_info); 888 if (known_info != NULL) CFRelease(known_info); 889 if (!match) { 890 return; 891 } 892 } 893 894 // if requested, match [non-]builtin 895 if (match_context->match_builtin != NULL) { 896 CFBooleanRef known_builtin; 897 898 known_builtin = _SCNetworkInterfaceIsBuiltin(known_if) ? kCFBooleanTrue 899 : kCFBooleanFalse; 900 if (!_SC_CFEqual(known_builtin, match_context->match_builtin)) { 901 return; 902 } 903 } 904 905 // if we have a match 906 CFRelease(match_context->matches); 907 match_context->matches = NULL; 908 909 return; 910} 911 912static Boolean 913interfaceExists(CFStringRef prefix, CFNumberRef unit) 914{ 915 Boolean found = FALSE; 916 CFDictionaryRef match_dict; 917 CFStringRef match_keys[2]; 918 CFTypeRef match_vals[2]; 919 CFDictionaryRef matching; 920 921 922 923 io_registry_entry_t entry = MACH_PORT_NULL; 924 io_iterator_t iterator = MACH_PORT_NULL; 925 kern_return_t kr; 926 mach_port_t masterPort = MACH_PORT_NULL; 927 928 kr = IOMasterPort(bootstrap_port, &masterPort); 929 if (kr != KERN_SUCCESS) { 930 SCLog(TRUE, LOG_ERR, 931 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"), 932 kr); 933 goto error; 934 } 935 936 // look for kIONetworkInterface with matching prefix and unit 937 match_keys[0] = CFSTR(kIOInterfaceNamePrefix); 938 match_vals[0] = prefix; 939 match_keys[1] = CFSTR(kIOInterfaceUnit); 940 match_vals[1] = unit; 941 match_dict = CFDictionaryCreate(NULL, 942 (const void **)match_keys, 943 (const void **)match_vals, 944 2, 945 &kCFTypeDictionaryKeyCallBacks, 946 &kCFTypeDictionaryValueCallBacks); 947 948 match_keys[0] = CFSTR(kIOProviderClassKey); 949 match_vals[0] = CFSTR(kIONetworkInterfaceClass); 950 match_keys[1] = CFSTR(kIOPropertyMatchKey); 951 match_vals[1] = match_dict; 952 matching = CFDictionaryCreate(NULL, 953 (const void **)match_keys, 954 (const void **)match_vals, 955 sizeof(match_keys)/sizeof(match_keys[0]), 956 &kCFTypeDictionaryKeyCallBacks, 957 &kCFTypeDictionaryValueCallBacks); 958 CFRelease(match_dict); 959 960 // note: the "matching" dictionary will be consumed by the following 961 kr = IOServiceGetMatchingServices(masterPort, matching, &iterator); 962 if ((kr != kIOReturnSuccess) || (iterator == MACH_PORT_NULL)) { 963 // if no interface 964 goto error; 965 } 966 967 entry = IOIteratorNext(iterator); 968 if (entry == MACH_PORT_NULL) { 969 // if no interface 970 goto error; 971 } 972 973 found = TRUE; 974 975error: 976 if (masterPort != MACH_PORT_NULL) { 977 mach_port_deallocate(mach_task_self(), masterPort); 978 } 979 if (entry != MACH_PORT_NULL) { 980 IOObjectRelease(entry); 981 } 982 if (iterator != MACH_PORT_NULL) { 983 IOObjectRelease(iterator); 984 } 985 986 return (found); 987} 988 989/* 990 * lookupMatchingInterface 991 * 992 * Looks at the interfaces that have already been [or need to be] named with 993 * the goal of allowing a system using a single network interface/adaptor of 994 * a given type (vendor, model, ...) to not care about the specific adaptor 995 * that is used (i.e. swapping dongle's is OK). Once a system has had more 996 * than one interface/adaptor connected at the same time than we assume that 997 * the network configuration is being setup for multi-homing that should be 998 * maintained. 999 * 1000 * If no matches are found or if more than one match is found, return NULL. 1001 * If a single match is found, return the match. 1002 */ 1003static CFDictionaryRef 1004lookupMatchingInterface(SCNetworkInterfaceRef interface, 1005 CFArrayRef db_list, // already named 1006 CFArrayRef if_list, // to be named 1007 CFIndex if_list_index, 1008 CFBooleanRef builtin) 1009{ 1010 CFStringRef if_type; 1011 CFDictionaryRef match = NULL; 1012 matchContext match_context; 1013 1014 if_type = SCNetworkInterfaceGetInterfaceType(interface); 1015 if (if_type == NULL) { 1016 return NULL; 1017 } 1018 1019 match_context.match_type = if_type; 1020 match_context.match_info = _SCNetworkInterfaceCopyInterfaceInfo(interface); 1021 match_context.match_builtin = builtin; 1022 match_context.matches = NULL; 1023 1024 // check for matches to interfaces that have already been named 1025 // ... and append each match that we find to match_context.matches 1026 if (db_list != NULL) { 1027 CFArrayApplyFunction(db_list, 1028 CFRangeMake(0, CFArrayGetCount(db_list)), 1029 matchKnown, 1030 &match_context); 1031 } 1032 1033 // check for matches to interfaces that will be named 1034 // ... and CFRelease match_context.matches if we find another network 1035 // interface of the same type that also needs to be named 1036 if (if_list != NULL) { 1037 CFIndex if_list_count; 1038 1039 if_list_count = CFArrayGetCount(if_list); 1040 if (if_list_index < if_list_count) { 1041 CFArrayApplyFunction(if_list, 1042 CFRangeMake(if_list_index, if_list_count - if_list_index), 1043 matchUnnamed, 1044 &match_context); 1045 } 1046 } 1047 1048 // check if we have a single match 1049 if (match_context.matches != NULL) { 1050 if (CFArrayGetCount(match_context.matches) == 1) { 1051 match = CFArrayGetValueAtIndex(match_context.matches, 0); 1052 } 1053 CFRelease(match_context.matches); 1054 } 1055 1056 if (match != NULL) { 1057 Boolean active = TRUE; 1058 CFStringRef name; 1059 1060 name = CFDictionaryGetValue(match, CFSTR(kIOBSDNameKey)); 1061 if (isA_CFString(name)) { 1062 CFStringRef prefix; 1063 CFNumberRef unit; 1064 1065 prefix = CFDictionaryGetValue(match, CFSTR(kIOInterfaceNamePrefix)); 1066 unit = CFDictionaryGetValue(match, CFSTR(kIOInterfaceUnit)); 1067 if (isA_CFString(prefix) && isA_CFNumber(unit)) { 1068 if (!interfaceExists(prefix, unit)) { 1069 active = FALSE; 1070 } 1071 } 1072 } 1073 1074 if (active) { 1075 match = NULL; 1076 } 1077 } 1078 1079 if (match_context.match_info != NULL) CFRelease(match_context.match_info); 1080 return match; 1081} 1082 1083static void 1084insertInterface(CFMutableArrayRef db_list, SCNetworkInterfaceRef interface) 1085{ 1086 CFIndex i; 1087 CFDictionaryRef if_dict; 1088 CFStringRef if_name; 1089 CFNumberRef if_type; 1090 CFNumberRef if_unit; 1091 CFIndex n = CFArrayGetCount(db_list); 1092 CFComparisonResult res; 1093 1094 if_name = SCNetworkInterfaceGetBSDName(interface); 1095 if (if_name != NULL) { 1096 addTimestamp(S_state, if_name); 1097 } 1098 1099 if_dict = createInterfaceDict(interface); 1100 if_type = _SCNetworkInterfaceGetIOInterfaceType(interface); 1101 if_unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); 1102 if ((if_type == NULL) || (if_unit == NULL)) { 1103 CFRelease(if_dict); 1104 return; 1105 } 1106 1107 for (i = 0; i < n; i++) { 1108 CFNumberRef db_type; 1109 CFNumberRef db_unit; 1110 CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i); 1111 1112 db_type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); 1113 db_unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit)); 1114 res = CFNumberCompare(if_type, db_type, NULL); 1115 if (res == kCFCompareLessThan 1116 || (res == kCFCompareEqualTo 1117 && (CFNumberCompare(if_unit, db_unit, NULL) 1118 == kCFCompareLessThan))) { 1119 CFArrayInsertValueAtIndex(db_list, i, if_dict); 1120 CFRelease(if_dict); 1121 return; 1122 } 1123 } 1124 1125 CFArrayAppendValue(S_dblist, if_dict); 1126 1127#if !TARGET_OS_EMBEDDED 1128 updateBTPANInformation(if_dict, NULL); 1129#endif // !TARGET_OS_EMBEDDED 1130 1131 CFRelease(if_dict); 1132 return; 1133} 1134 1135static void 1136replaceInterface(SCNetworkInterfaceRef interface) 1137{ 1138 int n = 0; 1139 CFIndex where; 1140 1141 if (S_dblist == NULL) { 1142 S_dblist = CFArrayCreateMutable(NULL, 0, 1143 &kCFTypeArrayCallBacks); 1144 } 1145 // remove any dict that has our type/addr 1146 while (lookupInterfaceByAddress(S_dblist, interface, &where) != NULL) { 1147 CFArrayRemoveValueAtIndex(S_dblist, where); 1148 n++; 1149 } 1150 // remove any dict that has the same type/unit 1151 while (lookupInterfaceByUnit(S_dblist, interface, &where) != NULL) { 1152 CFArrayRemoveValueAtIndex(S_dblist, where); 1153 n++; 1154 } 1155 insertInterface(S_dblist, interface); 1156 1157 if (n > 1) { 1158 CFStringRef issue; 1159 1160 issue = CFStringCreateWithFormat(NULL, NULL, 1161 CFSTR("n = %d, %@"), 1162 n, 1163 interface); 1164 reportIssue("Multiple interfaces updated", issue); 1165 CFRelease(issue); 1166 } 1167 1168 return; 1169} 1170 1171static CFNumberRef 1172getHighestUnitForType(CFNumberRef if_type) 1173{ 1174 int i; 1175 CFIndex n; 1176 CFNumberRef ret_unit = NULL; 1177 1178 if (S_dblist == NULL) { 1179 return (NULL); 1180 } 1181 1182 n = CFArrayGetCount(S_dblist); 1183 for (i = 0; i < n; i++) { 1184 CFDictionaryRef dict = CFArrayGetValueAtIndex(S_dblist, i); 1185 CFNumberRef type; 1186 1187 type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); 1188 if (CFEqual(type, if_type)) { 1189 CFNumberRef unit; 1190 1191 unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit)); 1192 if (ret_unit == NULL 1193 || (CFNumberCompare(unit, ret_unit, NULL) 1194 == kCFCompareGreaterThan)) { 1195 ret_unit = unit; 1196 } 1197 } 1198 } 1199 1200 return (ret_unit); 1201} 1202 1203/* 1204 * Function: ensureInterfaceHasUnit 1205 * Purpose: 1206 * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't, 1207 * release the interface and return NULL. 1208 */ 1209static SCNetworkInterfaceRef 1210ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if) 1211{ 1212 if (net_if != NULL 1213 && _SCNetworkInterfaceGetIOInterfaceUnit(net_if) == NULL) { 1214 CFRelease(net_if); 1215 net_if = NULL; 1216 } 1217 return (net_if); 1218} 1219 1220#ifdef USE_REGISTRY_ENTRY_ID 1221static kern_return_t 1222registerInterfaceWithIORegistryEntryID(io_connect_t connect, 1223 uint64_t entryID, 1224 CFNumberRef unit, 1225 const int command) 1226{ 1227 CFDataRef data; 1228 CFMutableDictionaryRef dict; 1229 kern_return_t kr; 1230 CFNumberRef num; 1231 1232 dict = CFDictionaryCreateMutable(NULL, 0, 1233 &kCFTypeDictionaryKeyCallBacks, 1234 &kCFTypeDictionaryValueCallBacks); 1235 num = CFNumberCreate(NULL, kCFNumberIntType, &command); 1236 CFDictionarySetValue(dict, CFSTR(kIONetworkStackUserCommandKey), num); 1237 CFRelease(num); 1238 data = CFDataCreate(NULL, (void *) &entryID, sizeof(entryID)); 1239 CFDictionarySetValue(dict, CFSTR(kIORegistryEntryIDKey), data); 1240 CFRelease(data); 1241 CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit); 1242 kr = IOConnectSetCFProperties(connect, dict); 1243 CFRelease(dict); 1244 return kr; 1245} 1246 1247static SCNetworkInterfaceRef 1248copyInterfaceForIORegistryEntryID(uint64_t entryID) 1249{ 1250 io_registry_entry_t entry = MACH_PORT_NULL; 1251 SCNetworkInterfaceRef interface = NULL; 1252 io_iterator_t iterator = MACH_PORT_NULL; 1253 kern_return_t kr; 1254 mach_port_t masterPort = MACH_PORT_NULL; 1255 1256 kr = IOMasterPort(bootstrap_port, &masterPort); 1257 if (kr != KERN_SUCCESS) { 1258 SCLog(TRUE, LOG_ERR, 1259 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"), 1260 kr); 1261 goto error; 1262 } 1263 1264 kr = IOServiceGetMatchingServices(masterPort, 1265 IORegistryEntryIDMatching(entryID), 1266 &iterator); 1267 if ((kr != KERN_SUCCESS) || (iterator == MACH_PORT_NULL)) { 1268 SCLog(TRUE, LOG_ERR, 1269 CFSTR(MY_PLUGIN_NAME ": IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d"), 1270 entryID, 1271 kr, 1272 iterator); 1273 goto error; 1274 } 1275 1276 entry = IOIteratorNext(iterator); 1277 if (entry == MACH_PORT_NULL) { 1278 SCLog(TRUE, LOG_ERR, 1279 CFSTR(MY_PLUGIN_NAME ": IORegistryEntryIDMatching(0x%llx) failed"), 1280 entryID); 1281 goto error; 1282 } 1283 1284 interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry); 1285 1286 error: 1287 if (masterPort != MACH_PORT_NULL) { 1288 mach_port_deallocate(mach_task_self(), masterPort); 1289 } 1290 if (entry != MACH_PORT_NULL) { 1291 IOObjectRelease(entry); 1292 } 1293 if (iterator != MACH_PORT_NULL) { 1294 IOObjectRelease(iterator); 1295 } 1296 return (interface); 1297} 1298 1299static SCNetworkInterfaceRef 1300copyNamedInterfaceForIORegistryEntryID(uint64_t entryID) 1301{ 1302 SCNetworkInterfaceRef net_if; 1303 1304 net_if = copyInterfaceForIORegistryEntryID(entryID); 1305 return (ensureInterfaceHasUnit(net_if)); 1306} 1307 1308#else // USE_REGISTRY_ENTRY_ID 1309/* 1310 * Function: registerInterface 1311 * Purpose: 1312 * Register a single interface with the given service path to the 1313 * data link layer (BSD), using the specified unit number. 1314 */ 1315static kern_return_t 1316registerInterfaceWithIOServicePath(io_connect_t connect, 1317 CFStringRef path, 1318 CFNumberRef unit, 1319 const int command) 1320{ 1321 CFMutableDictionaryRef dict; 1322 kern_return_t kr; 1323 CFNumberRef num; 1324 1325 dict = CFDictionaryCreateMutable(NULL, 0, 1326 &kCFTypeDictionaryKeyCallBacks, 1327 &kCFTypeDictionaryValueCallBacks); 1328 num = CFNumberCreate(NULL, kCFNumberIntType, &command); 1329 CFDictionarySetValue(dict, CFSTR(kIONetworkStackUserCommandKey), num); 1330 CFRelease(num); 1331 CFDictionarySetValue(dict, CFSTR(kIOPathMatchKey), path); 1332 CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit); 1333 kr = IOConnectSetCFProperties(connect, dict); 1334 CFRelease(dict); 1335 return kr; 1336} 1337 1338static SCNetworkInterfaceRef 1339copyInterfaceForIOKitPath(CFStringRef if_path) 1340{ 1341 io_registry_entry_t entry = MACH_PORT_NULL; 1342 SCNetworkInterfaceRef interface = NULL; 1343 kern_return_t kr; 1344 mach_port_t masterPort = MACH_PORT_NULL; 1345 io_string_t path; 1346 1347 kr = IOMasterPort(bootstrap_port, &masterPort); 1348 if (kr != KERN_SUCCESS) { 1349 SCLog(TRUE, LOG_ERR, 1350 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"), 1351 kr); 1352 goto error; 1353 } 1354 _SC_cfstring_to_cstring(if_path, path, sizeof(path), kCFStringEncodingASCII); 1355 entry = IORegistryEntryFromPath(masterPort, path); 1356 if (entry == MACH_PORT_NULL) { 1357 SCLog(TRUE, LOG_ERR, 1358 CFSTR(MY_PLUGIN_NAME ": IORegistryEntryFromPath(%@) failed"), 1359 if_path); 1360 goto error; 1361 } 1362 1363 interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry); 1364 1365 error: 1366 if (masterPort != MACH_PORT_NULL) { 1367 mach_port_deallocate(mach_task_self(), masterPort); 1368 } 1369 if (entry != MACH_PORT_NULL) { 1370 IOObjectRelease(entry); 1371 } 1372 return (interface); 1373 1374} 1375 1376static SCNetworkInterfaceRef 1377copyNamedInterfaceForIOKitPath(CFStringRef if_path) 1378{ 1379 SCNetworkInterfaceRef net_if; 1380 1381 net_if = copyInterfaceForIOKitPath(if_path); 1382 return (ensureInterfaceHasUnit(net_if)); 1383} 1384 1385#endif // USE_REGISTRY_ENTRY_ID 1386 1387static void 1388displayInterface(SCNetworkInterfaceRef interface) 1389{ 1390 CFStringRef addr; 1391 CFStringRef name; 1392 CFNumberRef type; 1393 CFNumberRef unit; 1394 1395 name = SCNetworkInterfaceGetBSDName(interface); 1396 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); 1397 type = _SCNetworkInterfaceGetIOInterfaceType(interface); 1398 addr = SCNetworkInterfaceGetHardwareAddressString(interface); 1399 1400 SCLog(TRUE, LOG_INFO, 1401 CFSTR(MY_PLUGIN_NAME ": %s%@%sType: %@, %s%@%sMAC address: %@"), 1402 (name != NULL) ? "BSD Name: " : "", 1403 (name != NULL) ? name : CFSTR(""), 1404 (name != NULL) ? ", " : "", 1405 type, 1406 (unit != NULL) ? "Unit: " : "", 1407 (unit != NULL) ? (CFTypeRef)unit : (CFTypeRef)CFSTR(""), 1408 (unit != NULL) ? ", " : "", 1409 addr); 1410} 1411 1412static Boolean 1413builtinAvailable(SCNetworkInterfaceRef interface, // new interface 1414 CFNumberRef if_unit) // desired unit 1415{ 1416 CFIndex i; 1417 CFNumberRef if_type = _SCNetworkInterfaceGetIOInterfaceType(interface); 1418 CFIndex n; 1419 1420 n = (S_dblist != NULL) ? CFArrayGetCount(S_dblist) : 0; 1421 for (i = 0; i < n; i++) { 1422 CFStringRef if_path; 1423 CFDictionaryRef known_dict = CFArrayGetValueAtIndex(S_dblist, i); 1424 CFStringRef known_path; 1425 CFNumberRef known_type; 1426 CFNumberRef known_unit; 1427 1428 known_type = CFDictionaryGetValue(known_dict, CFSTR(kIOInterfaceType)); 1429 if (!_SC_CFEqual(if_type, known_type)) { 1430 continue; // if not the same interface type 1431 } 1432 1433 known_unit = CFDictionaryGetValue(known_dict, CFSTR(kIOInterfaceUnit)); 1434 if (!_SC_CFEqual(if_unit, known_unit)) { 1435 continue; // if not the same interface unit 1436 } 1437 1438 if_path = _SCNetworkInterfaceGetIOPath(interface); 1439 known_path = CFDictionaryGetValue(known_dict, CFSTR(kIOPathMatchKey)); 1440 if (!_SC_CFEqual(if_path, known_path)) { 1441 // if different IORegistry path 1442 return FALSE; 1443 } 1444 1445 // if same type, same unit, same path 1446 return TRUE; 1447 } 1448 1449 // if interface type/unit not found 1450 return TRUE; 1451} 1452 1453static int 1454builtinCount(CFArrayRef if_list, CFIndex last, CFNumberRef if_type) 1455{ 1456 CFIndex i; 1457 int n = 0; 1458 1459 for (i = 0; i < last; i++) { 1460 SCNetworkInterfaceRef builtin_if; 1461 CFNumberRef builtin_type; 1462 1463 builtin_if = CFArrayGetValueAtIndex(if_list, i); 1464 builtin_type = _SCNetworkInterfaceGetIOInterfaceType(builtin_if); 1465 if (CFEqual(if_type, builtin_type)) { 1466 if (_SCNetworkInterfaceIsBuiltin(builtin_if)) { 1467 n++; // if built-in interface 1468 } 1469 } 1470 } 1471 1472 return n; 1473} 1474 1475static __inline__ boolean_t 1476isQuiet(void) 1477{ 1478 return (S_quiet == MACH_PORT_NULL); 1479} 1480 1481static void 1482nameInterfaces(CFMutableArrayRef if_list) 1483{ 1484 CFIndex i; 1485 CFIndex n = CFArrayGetCount(if_list); 1486 1487 for (i = 0; i < n; i++) { 1488 uint64_t entryID; 1489 SCNetworkInterfaceRef interface; 1490 SCNetworkInterfaceRef new_interface; 1491 CFStringRef path; 1492 CFStringRef str; 1493 CFNumberRef type; 1494 CFNumberRef unit; 1495 CFIndex where; 1496 1497 interface = CFArrayGetValueAtIndex(if_list, i); 1498 path = _SCNetworkInterfaceGetIOPath(interface); 1499 type = _SCNetworkInterfaceGetIOInterfaceType(interface); 1500 unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); 1501 entryID = _SCNetworkInterfaceGetIORegistryEntryID(interface); 1502 1503 if (unit != NULL) { 1504 if (S_debug) { 1505 CFStringRef if_name; 1506 1507 if_name = SCNetworkInterfaceGetBSDName(interface); 1508 if ((if_name == NULL) || !CFDictionaryContainsKey(S_state, if_name)) { 1509 SCLog(TRUE, LOG_INFO, 1510 CFSTR(MY_PLUGIN_NAME ": Interface already has a unit number")); 1511 displayInterface(interface); 1512 } 1513 } 1514 1515 // update the list of interfaces that were previously named 1516 if ((S_prev_active_list != NULL) 1517 && lookupInterfaceByAddress(S_prev_active_list, interface, &where) != NULL) { 1518 CFArrayRemoveValueAtIndex(S_prev_active_list, where); 1519 } 1520 1521 replaceInterface(interface); 1522 } else { 1523 CFDictionaryRef dbdict; 1524 boolean_t is_builtin; 1525 kern_return_t kr; 1526 int retries = 0; 1527 1528 dbdict = lookupInterfaceByAddress(S_dblist, interface, NULL); 1529 if (dbdict != NULL) { 1530 unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit)); 1531 CFRetain(unit); 1532 1533 SCLog(S_debug, LOG_INFO, 1534 CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (from database)"), 1535 unit); 1536 } 1537 1538 if ((dbdict == NULL) && !isQuiet()) { 1539 // if new interface, wait until quiet before naming 1540 addTimestamp(S_state, path); 1541 continue; 1542 } 1543 1544 is_builtin = _SCNetworkInterfaceIsBuiltin(interface); 1545 1546 if (dbdict == NULL) { 1547 dbdict = lookupMatchingInterface(interface, 1548 S_dblist, 1549 if_list, 1550 i + 1, 1551 is_builtin ? kCFBooleanTrue : kCFBooleanFalse); 1552 if (dbdict != NULL) { 1553 unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit)); 1554 CFRetain(unit); 1555 1556 SCLog(S_debug, LOG_INFO, 1557 CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (updating database)"), 1558 unit); 1559 } 1560 } 1561 1562 if ((dbdict != NULL) && (S_prev_active_list != NULL)) { 1563 // update the list of interfaces that were previously named 1564 where = CFArrayGetFirstIndexOfValue(S_prev_active_list, 1565 CFRangeMake(0, CFArrayGetCount(S_prev_active_list)), 1566 dbdict); 1567 if (where != kCFNotFound) { 1568 CFArrayRemoveValueAtIndex(S_prev_active_list, where); 1569 } 1570 } 1571 1572 if (dbdict == NULL) { 1573 int next_unit = 0; 1574 1575 if (is_builtin) { 1576 // built-in interface, try to use the reserved slots 1577 next_unit = builtinCount(if_list, i, type); 1578 1579 // But, before claiming a reserved slot we check to see if the 1580 // slot had previously been used. If so, and if the slot had been 1581 // assigned to the same type of interface, then we will perform a 1582 // replacement (e.g. assume that this was a board swap). But, if 1583 // the new interface is a different type then we assume that the 1584 // built-in configuration has changed and allocate a new unit from 1585 // the non-reserved slots. 1586 1587 unit = CFNumberCreate(NULL, kCFNumberIntType, &next_unit); 1588 if (!builtinAvailable(interface, unit)) { 1589 // if [built-in] unit not available 1590 SCLog(S_debug, LOG_INFO, 1591 CFSTR(MY_PLUGIN_NAME ": Interface not assigned [built-in] unit %@"), 1592 unit); 1593 CFRelease(unit); 1594 unit = NULL; 1595 } 1596 } 1597 1598 if (unit == NULL) { 1599 // not built-in (or built-in unit not available), allocate from 1600 // the non-reserved slots 1601 next_unit = builtinCount(if_list, n, type); 1602 1603 unit = getHighestUnitForType(type); 1604 if (unit != NULL) { 1605 int high_unit; 1606 1607 CFNumberGetValue(unit, kCFNumberIntType, &high_unit); 1608 if (high_unit >= next_unit) { 1609 next_unit = high_unit + 1; 1610 } 1611 } 1612 1613 unit = CFNumberCreate(NULL, kCFNumberIntType, &next_unit); 1614 } 1615 1616 SCLog(S_debug, LOG_INFO, 1617 CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (%s)"), 1618 unit, 1619 is_builtin ? "built-in" : "next available"); 1620 } 1621 1622 retry : 1623 1624#ifdef USE_REGISTRY_ENTRY_ID 1625 kr = registerInterfaceWithIORegistryEntryID(S_connect, 1626 entryID, 1627 unit, 1628 (dbdict == NULL) ? kIONetworkStackRegisterInterfaceWithLowestUnit 1629 : kIONetworkStackRegisterInterfaceWithUnit); 1630 new_interface = copyNamedInterfaceForIORegistryEntryID(entryID); 1631#else // USE_REGISTRY_ENTRY_ID 1632 kr = registerInterfaceWithIOServicePath(S_connect, 1633 path, 1634 unit, 1635 (dbdict == NULL) ? kRegisterInterface 1636 : kRegisterInterfaceWithFixedUnit); 1637 new_interface = copyNamedInterfaceForIOKitPath(path); 1638#endif // USE_REGISTRY_ENTRY_ID 1639 if (new_interface == NULL) { 1640 const char *signature; 1641 1642 signature = (dbdict == NULL) ? "failed to name new interface" 1643 : "failed to name known interface"; 1644 1645 SCLog(TRUE, LOG_ERR, 1646 CFSTR(MY_PLUGIN_NAME ": %s, kr=0x%x\n" 1647 MY_PLUGIN_NAME ": path = %@\n" 1648 MY_PLUGIN_NAME ": id = 0x%llx\n" 1649 MY_PLUGIN_NAME ": unit = %@"), 1650 signature, 1651 kr, 1652 path, 1653 entryID, 1654 unit); 1655 1656 if (S_debug) { 1657 displayInterface(interface); 1658 } 1659 1660 // report issue w/MessageTracer 1661 str = CFStringCreateWithFormat(NULL, NULL, 1662 CFSTR("kr=0x%x, path=%@, unit=%@"), 1663 kr, 1664 path, 1665 unit); 1666 reportIssue(signature, str); 1667 CFRelease(str); 1668 1669 if ((dbdict != NULL) && (retries++ < 5)) { 1670 usleep(50 * 1000); // sleep 50ms between attempts 1671 goto retry; 1672 } 1673 } 1674 else { 1675 CFNumberRef new_unit; 1676 1677 if (retries > 0) { 1678 SCLog(TRUE, LOG_ERR, 1679 CFSTR(MY_PLUGIN_NAME ": %s interface named after %d %s\n" 1680 MY_PLUGIN_NAME ": path = %@\n" 1681 MY_PLUGIN_NAME ": unit = %@"), 1682 (dbdict == NULL) ? "New" : "Known", 1683 retries, 1684 (retries == 1) ? "try" : "tries", 1685 path, 1686 unit); 1687 1688#ifdef SHOW_NAMING_FAILURE 1689 str = CFStringCreateWithFormat(NULL, 1690 NULL, 1691 CFSTR("\"%s\" interface named after %d %s, unit = %@"), 1692 (dbdict == NULL) ? "New" : "Known", 1693 retries, 1694 (retries == 1) ? "try" : "tries", 1695 unit); 1696 CFUserNotificationDisplayNotice(0, 1697 kCFUserNotificationStopAlertLevel, 1698 NULL, 1699 NULL, 1700 NULL, 1701 str, 1702 CFSTR("Please report repeated failures."), 1703 NULL); 1704 CFRelease(str); 1705#endif // SHOW_NAMING_FAILURE 1706 } 1707 1708 new_unit = _SCNetworkInterfaceGetIOInterfaceUnit(new_interface); 1709 if (CFEqual(unit, new_unit) == FALSE) { 1710 SCLog(S_debug, LOG_INFO, 1711 CFSTR(MY_PLUGIN_NAME 1712 ": interface type %@ assigned " 1713 "unit %@ instead of %@"), 1714 type, new_unit, unit); 1715 } 1716 if (S_debug) { 1717 displayInterface(new_interface); 1718 } 1719 1720 // update if_list (with the interface name & unit) 1721 CFArraySetValueAtIndex(if_list, i, new_interface); 1722 CFRelease(new_interface); 1723 interface = new_interface; // if_list holds the reference 1724 1725 if (is_builtin && (S_prev_active_list != NULL)) { 1726 CFIndex where; 1727 1728 // update the list of [built-in] interfaces that were previously named 1729 if (lookupInterfaceByUnit(S_prev_active_list, interface, &where) != NULL) { 1730 SCLog(S_debug, LOG_INFO, 1731 CFSTR(MY_PLUGIN_NAME ": and updated database (new address)")); 1732 CFArrayRemoveValueAtIndex(S_prev_active_list, where); 1733 } 1734 } 1735 replaceInterface(interface); 1736 } 1737 CFRelease(unit); 1738 } 1739 } 1740 return; 1741} 1742 1743#if !TARGET_OS_IPHONE 1744static void 1745updateNetworkConfiguration(CFArrayRef if_list) 1746{ 1747 Boolean do_commit = FALSE; 1748 CFIndex i; 1749 CFIndex n; 1750 SCPreferencesRef prefs = NULL; 1751 SCNetworkSetRef set = NULL; 1752 1753 prefs = SCPreferencesCreate(NULL, CFSTR("SCMonitor"), NULL); 1754 1755 set = SCNetworkSetCopyCurrent(prefs); 1756 if (set == NULL) { 1757 SCLog(TRUE, LOG_ERR, CFSTR(MY_PLUGIN_NAME ": No current set")); 1758 goto done; 1759 } 1760 1761 n = CFArrayGetCount(if_list); 1762 for (i = 0; i < n; i++) { 1763 SCNetworkInterfaceRef interface; 1764 1765 interface = CFArrayGetValueAtIndex(if_list, i); 1766 if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set, interface)) { 1767 SCLog(TRUE, LOG_INFO, 1768 CFSTR(MY_PLUGIN_NAME ": adding default configuration for %s"), 1769 SCNetworkInterfaceGetBSDName(interface)); 1770 do_commit = TRUE; 1771 } 1772 } 1773 1774 if (do_commit) { 1775 Boolean ok; 1776 1777 ok = SCPreferencesCommitChanges(prefs); 1778 if (!ok) { 1779 SCLog(TRUE, LOG_INFO, 1780 CFSTR(MY_PLUGIN_NAME ": updateNetworkConfiguration: SCPreferencesCommitChanges() failed: %s"), 1781 SCErrorString(SCError())); 1782 goto done; 1783 } 1784 1785 ok = SCPreferencesApplyChanges(prefs); 1786 if (!ok) { 1787 SCLog(TRUE, LOG_INFO, 1788 CFSTR(MY_PLUGIN_NAME ": updateNetworkConfiguration: SCPreferencesApplyChanges() failed: %s"), 1789 SCErrorString(SCError())); 1790 goto done; 1791 } 1792 } 1793 1794 done : 1795 1796 if (set != NULL) { 1797 CFRelease(set); 1798 set = NULL; 1799 } 1800 1801 if (prefs != NULL) { 1802 CFRelease(prefs); 1803 prefs = NULL; 1804 } 1805 1806 return; 1807} 1808#endif // !TARGET_OS_IPHONE 1809 1810static void 1811updateInterfaces() 1812{ 1813 if (S_connect == MACH_PORT_NULL) { 1814 // if we don't have the "IONetworkStack" connect object 1815 return; 1816 } 1817 1818 if (S_iflist != NULL) { 1819 CFIndex n; 1820 1821 n = CFArrayGetCount(S_iflist); 1822 if (n > 1) { 1823 CFArraySortValues(S_iflist, CFRangeMake(0, n), _SCNetworkInterfaceCompare, NULL); 1824 } 1825 nameInterfaces(S_iflist); 1826 } 1827 1828 if (isQuiet()) { 1829 /* 1830 * The registry [matching] has quiesced so let's 1831 * - save the DB with the interfaces that have been named 1832 * - update the VLAN/BOND configuration 1833 * - tell everyone that we've finished (at least for now) 1834 * - log those interfaces which are no longer present 1835 * in the HW config (or have yet to show up). 1836 */ 1837 writeInterfaceList(S_dblist); 1838 updateVirtualNetworkInterfaceConfiguration(NULL, kSCPreferencesNotificationApply, NULL); 1839 1840#if !TARGET_OS_IPHONE 1841 if (access("/usr/libexec/UserEventAgent", X_OK) == -1 1842 && errno == ENOENT) { 1843 /* 1844 * We are most likely booted into the Recovery OS with no "SCMonitor" 1845 * UserEventAgent plugin running so let's make sure we update the 1846 * network configuration for new interfaces. 1847 */ 1848 updateNetworkConfiguration(S_iflist); 1849 } 1850#endif // !TARGET_OS_IPHONE 1851 1852 updateStore(); 1853 1854 if (S_iflist != NULL) { 1855 CFRelease(S_iflist); 1856 S_iflist = NULL; 1857 } 1858 1859 if (S_prev_active_list != NULL) { 1860 if (S_debug) { 1861 CFIndex i; 1862 CFIndex n; 1863 1864 n = CFArrayGetCount(S_prev_active_list); 1865 if (n > 0) { 1866 SCLog(TRUE, LOG_INFO, 1867 CFSTR(MY_PLUGIN_NAME ": Interface%s not [yet] active"), 1868 (n > 1) ? "s" : ""); 1869 } 1870 for (i = 0; i < n; i++) { 1871 CFDictionaryRef if_dict; 1872 CFStringRef name; 1873 CFNumberRef type; 1874 CFNumberRef unit; 1875 1876 if_dict = CFArrayGetValueAtIndex(S_prev_active_list, i); 1877 name = CFDictionaryGetValue(if_dict, CFSTR(kIOBSDNameKey)); 1878 type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType)); 1879 unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit)); 1880 SCLog(TRUE, LOG_INFO, 1881 CFSTR(MY_PLUGIN_NAME ": %s%@%sType: %@, Unit: %@"), 1882 (name != NULL) ? "BSD Name: " : "", 1883 (name != NULL) ? name : CFSTR(""), 1884 (name != NULL) ? ", " : "", 1885 type, 1886 unit); 1887 } 1888 } 1889 CFRelease(S_prev_active_list); 1890 S_prev_active_list = NULL; 1891 } 1892 } else { 1893 if ((S_prev_active_list != NULL) && (CFArrayGetCount(S_prev_active_list) == 0)) { 1894 /* 1895 * if we've named all of the interfaces that 1896 * were used during the previous boot. 1897 */ 1898 addTimestamp(S_state, CFSTR("*RELEASE*")); 1899 SCLog(S_debug, LOG_INFO, 1900 CFSTR(MY_PLUGIN_NAME ": last boot interfaces have been named")); 1901 updateStore(); 1902 CFRelease(S_prev_active_list); 1903 S_prev_active_list = NULL; 1904 } 1905 } 1906 1907 return; 1908} 1909 1910#if !TARGET_OS_EMBEDDED 1911static CFComparisonResult 1912compareMacAddress(const void *val1, const void *val2, void *context) 1913{ 1914 CFDataRef mac1 = (CFDataRef)val1; 1915 CFDataRef mac2 = (CFDataRef)val2; 1916 CFIndex n1; 1917 CFIndex n2; 1918 CFComparisonResult res; 1919 1920 n1 = CFDataGetLength(mac1); 1921 n2 = CFDataGetLength(mac2); 1922 if (n1 < n2) { 1923 res = kCFCompareLessThan; 1924 } else if (n2 > n1) { 1925 res = kCFCompareGreaterThan; 1926 } else { 1927 res = bcmp(CFDataGetBytePtr(mac1), CFDataGetBytePtr(mac2), n1); 1928 } 1929 1930 return res; 1931} 1932 1933static CFStringRef 1934copyEthernetUUID() 1935{ 1936 CFDataRef addr; 1937 CFMutableArrayRef addrs = NULL; 1938 CFStringRef guid = NULL; 1939 CFIndex i; 1940 CFIndex n; 1941 1942 addrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1943 n = (S_dblist != NULL) ? CFArrayGetCount(S_dblist) : 0; 1944 for (i = 0; i < n; i++) { 1945 CFBooleanRef builtin; 1946 CFDictionaryRef dict; 1947 CFStringRef type; 1948 1949 dict = CFArrayGetValueAtIndex(S_dblist, i); 1950 type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType)); 1951 if (!isA_CFString(type) || !CFEqual(type, kSCNetworkInterfaceTypeEthernet)) { 1952 continue; 1953 } 1954 builtin = CFDictionaryGetValue(dict, CFSTR(kIOBuiltin)); 1955 if (!isA_CFBoolean(builtin) || !CFBooleanGetValue(builtin)) { 1956 continue; 1957 } 1958 addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); 1959 if (!isA_CFData(addr) || (CFDataGetLength(addr) != ETHER_ADDR_LEN)) { 1960 continue; 1961 } 1962 CFArrayAppendValue(addrs, addr); 1963 } 1964 1965 if (CFArrayGetCount(addrs) == 0) { 1966 // if no ethernet interfaces, look for wireless 1967 for (i = 0; i < n; i++) { 1968 CFDictionaryRef dict; 1969 CFStringRef type; 1970 1971 dict = CFArrayGetValueAtIndex(S_dblist, i); 1972 type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType)); 1973 if (!isA_CFString(type) || !CFEqual(type, kSCNetworkInterfaceTypeIEEE80211)) { 1974 continue; 1975 } 1976 addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); 1977 if (!isA_CFData(addr) || (CFDataGetLength(addr) != ETHER_ADDR_LEN)) { 1978 continue; 1979 } 1980 CFArrayAppendValue(addrs, addr); 1981 } 1982 } 1983 1984 n = CFArrayGetCount(addrs); 1985 switch (n) { 1986 case 0 : 1987 // if no network interfaces 1988 break; 1989 default : 1990 // sort by MAC address 1991 CFArraySortValues(addrs, CFRangeMake(0, n), compareMacAddress, NULL); 1992 1993 // fall through 1994 case 1 : { 1995 CFUUIDBytes bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 1996 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 1997 CFUUIDRef uuid; 1998 1999 // set GUID 2000 addr = CFArrayGetValueAtIndex(addrs, 0); 2001 bcopy(CFDataGetBytePtr(addr), 2002 (void *)&bytes + sizeof(bytes) - ETHER_ADDR_LEN, 2003 ETHER_ADDR_LEN); 2004 uuid = CFUUIDCreateFromUUIDBytes(NULL, bytes); 2005 guid = CFUUIDCreateString(NULL, uuid); 2006 CFRelease(uuid); 2007 2008 SCLog(TRUE, LOG_INFO, 2009 CFSTR(MY_PLUGIN_NAME ": setting platform UUID [MAC] = %@"), 2010 guid); 2011 break; 2012 } 2013 } 2014 2015 if (addrs != NULL) CFRelease(addrs); 2016 return guid; 2017} 2018 2019#ifndef kIOPlatformUUIDKey 2020#define kIOPlatformUUIDKey "IOPlatformUUID" 2021#endif 2022static void 2023updatePlatformUUID() 2024{ 2025 CFStringRef guid = NULL; 2026 kern_return_t kr; 2027 io_registry_entry_t platform; 2028 2029 platform = IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreePlane ":/"); 2030 if (platform == MACH_PORT_NULL) { 2031 goto done; 2032 } 2033 2034 guid = IORegistryEntryCreateCFProperty(platform, CFSTR(kIOPlatformUUIDKey), NULL, 0); 2035 if (guid != NULL) { 2036 // if GUID already defined 2037 goto done; 2038 } 2039 2040 guid = copyEthernetUUID(); 2041 if (guid == NULL) { 2042 CFUUIDRef uuid; 2043 2044 uuid = CFUUIDCreate(NULL); 2045 guid = CFUUIDCreateString(NULL, uuid); 2046 CFRelease(uuid); 2047 2048 SCLog(TRUE, LOG_INFO, 2049 CFSTR(MY_PLUGIN_NAME ": setting platform UUID [random] = %@"), 2050 guid); 2051 } 2052 2053if (getenv("DO_NOT_SET_PLATFORM_UUID") == NULL) { 2054 kr = IORegistryEntrySetCFProperty(platform, CFSTR(kIOPlatformUUIDKey), guid); 2055 if (kr != KERN_SUCCESS) { 2056 SCLog(TRUE, LOG_ERR, 2057 CFSTR(MY_PLUGIN_NAME ": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"), 2058 kr); 2059 } 2060} 2061 2062 addTimestamp(S_state, CFSTR("*PLATFORM-UUID*")); 2063 updateStore(); 2064 2065 done : 2066 2067 if (S_vproc_transaction != NULL) { 2068 vproc_transaction_end(NULL, S_vproc_transaction); 2069 S_vproc_transaction = NULL; 2070 } 2071 2072 if (platform != MACH_PORT_NULL) IOObjectRelease(platform); 2073 if (guid != NULL) CFRelease(guid); 2074 return; 2075} 2076#endif // !TARGET_OS_EMBEDDED 2077 2078static void 2079interfaceArrivalCallback(void *refcon, io_iterator_t iter) 2080{ 2081 io_object_t obj; 2082 2083 while ((obj = IOIteratorNext(iter)) != MACH_PORT_NULL) { 2084 SCNetworkInterfaceRef interface; 2085 2086 interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj); 2087 if (interface != NULL) { 2088 if (S_iflist == NULL) { 2089 S_iflist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 2090 } 2091 CFArrayAppendValue(S_iflist, interface); 2092 CFRelease(interface); 2093 } 2094 IOObjectRelease(obj); 2095 } 2096 2097 updateInterfaces(); 2098 return; 2099} 2100 2101/* 2102 * Function: stackCallback 2103 * Purpose: 2104 * Get a reference to the single IONetworkStack object instance in 2105 * the kernel. Naming requests must be sent to this object, which is 2106 * attached as a client to all network interface objects in the system. 2107 * Note: 2108 * Call IOObjectRelease on the returned object. 2109 */ 2110static void 2111stackCallback(void *refcon, io_iterator_t iter) 2112{ 2113 kern_return_t kr; 2114 io_object_t stack; 2115 2116 stack = IOIteratorNext(iter); 2117 if (stack == MACH_PORT_NULL) { 2118 goto error; 2119 } 2120 2121 kr = IOServiceOpen(stack, mach_task_self(), 0, &S_connect); 2122 if (kr != KERN_SUCCESS) { 2123 SCLog(TRUE, LOG_ERR, 2124 CFSTR(MY_PLUGIN_NAME ": IOServiceOpen returned 0x%x"), 2125 kr); 2126 goto error; 2127 } 2128 2129 addTimestamp(S_state, CFSTR("*STACK*")); 2130 SCLog(S_debug, LOG_INFO, 2131 CFSTR(MY_PLUGIN_NAME ": IONetworkStack found")); 2132 2133 if (S_stack != MACH_PORT_NULL) { 2134 IOObjectRelease(S_stack); 2135 S_stack = MACH_PORT_NULL; 2136 } 2137 2138 if ((S_timer != NULL) && CFRunLoopTimerIsValid(S_timer)) { 2139 // With the IONetworkStack object now available we can 2140 // reset (shorten?) the time we are willing to wait for 2141 // IOKit to quiesce. 2142 CFRunLoopTimerSetNextFireDate(S_timer, 2143 CFAbsoluteTimeGetCurrent() + S_quiet_timeout); 2144 } 2145 2146 updateInterfaces(); 2147 2148 error: 2149 if (stack != MACH_PORT_NULL) { 2150 IOObjectRelease(stack); 2151 } 2152 2153 return; 2154} 2155 2156static void 2157quietCallback(void *refcon, 2158 io_service_t service, 2159 natural_t messageType, 2160 void *messageArgument) 2161{ 2162 if (messageArgument != NULL) { 2163 // if not yet quiet 2164 return; 2165 } 2166 2167 if (messageType == kIOMessageServiceBusyStateChange) { 2168 addTimestamp(S_state, CFSTR("*QUIET*")); 2169 SCLog(S_debug, LOG_INFO, 2170 CFSTR(MY_PLUGIN_NAME ": IOKit quiet")); 2171 } 2172 2173 if (S_connect == MACH_PORT_NULL) { 2174 SCLog(TRUE, LOG_ERR, 2175 CFSTR(MY_PLUGIN_NAME ": No network stack object")); 2176 return; 2177 } 2178 2179 if (S_quiet != MACH_PORT_NULL) { 2180 IOObjectRelease(S_quiet); 2181 S_quiet = MACH_PORT_NULL; 2182 } 2183 2184 if (S_timer != NULL) { 2185 CFRunLoopTimerInvalidate(S_timer); 2186 CFRelease(S_timer); 2187 S_timer = NULL; 2188 } 2189 2190 // grab (and name) any additional interfaces. 2191 interfaceArrivalCallback((void *)S_notify, S_iter); 2192 2193#if !TARGET_OS_EMBEDDED 2194 updatePlatformUUID(); 2195#endif // !TARGET_OS_EMBEDDED 2196 2197 return; 2198} 2199 2200static void 2201iterateRegistryBusy(io_iterator_t iterator, CFArrayRef nodes, CFMutableStringRef snapshot, int *count) 2202{ 2203 kern_return_t kr = kIOReturnSuccess;; 2204 io_object_t obj; 2205 2206 while ((kr == kIOReturnSuccess) && 2207 ((obj = IOIteratorNext(iterator)) != MACH_PORT_NULL)) { 2208 uint64_t accumulated_busy_time; 2209 uint32_t busy_state; 2210 io_name_t location; 2211 io_name_t name; 2212 CFMutableArrayRef newNodes; 2213 uint64_t state; 2214 CFMutableStringRef str = NULL; 2215 2216 if (nodes == NULL) { 2217 newNodes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 2218 } else { 2219 newNodes = CFArrayCreateMutableCopy(NULL, 0, nodes); 2220 } 2221 assert(newNodes != NULL); 2222 2223 kr = IORegistryEntryGetName(obj, name); 2224 if (kr != kIOReturnSuccess) { 2225 SCLog(TRUE, LOG_ERR, 2226 CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryEntryGetName returned 0x%x"), 2227 kr); 2228 goto next; 2229 } 2230 2231 str = CFStringCreateMutable(NULL, 0); 2232 CFStringAppendCString(str, name, kCFStringEncodingUTF8); 2233 2234 kr = IORegistryEntryGetLocationInPlane(obj, kIOServicePlane, location); 2235 switch (kr) { 2236 case kIOReturnSuccess : 2237 CFStringAppendCString(str, "@", kCFStringEncodingUTF8); 2238 CFStringAppendCString(str, location, kCFStringEncodingUTF8); 2239 break; 2240 case kIOReturnNotFound : 2241 break; 2242 default : 2243 SCLog(TRUE, LOG_ERR, 2244 CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryEntryGetLocationInPlane returned 0x%x"), 2245 kr); 2246 CFRelease(str); 2247 goto next; 2248 } 2249 2250 CFArrayAppendValue(newNodes, str); 2251 CFRelease(str); 2252 2253 kr = IOServiceGetBusyStateAndTime(obj, &state, &busy_state, &accumulated_busy_time); 2254 if (kr != kIOReturnSuccess) { 2255 SCLog(TRUE, LOG_ERR, 2256 CFSTR(MY_PLUGIN_NAME ": captureBusy IOServiceGetBusyStateAndTime returned 0x%x"), 2257 kr); 2258 goto next; 2259 } 2260 2261#ifdef TEST_SNAPSHOT 2262 // report all nodes 2263 busy_state = 1; 2264#endif // TEST_SNAPSHOT 2265 2266 if (busy_state != 0) { 2267 CFStringRef path; 2268 2269 if ((*count)++ == 0) { 2270 CFStringAppend(snapshot, CFSTR("Busy services :")); 2271 } 2272 2273 path = CFStringCreateByCombiningStrings(NULL, newNodes, CFSTR("/")); 2274 CFStringAppendFormat(snapshot, NULL, 2275 CFSTR("\n %@ [%s%s%s%d, %lld ms]"), 2276 path, 2277 (state & kIOServiceRegisteredState) ? "" : "!registered, ", 2278 (state & kIOServiceMatchedState) ? "" : "!matched, ", 2279 (state & kIOServiceInactiveState) ? "inactive, " : "", 2280 busy_state, 2281 accumulated_busy_time / kMillisecondScale); 2282 CFRelease(path); 2283 } 2284 2285 kr = IORegistryIteratorEnterEntry(iterator); 2286 if (kr != kIOReturnSuccess) { 2287 SCLog(TRUE, LOG_ERR, 2288 CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryIteratorEnterEntry returned 0x%x"), 2289 kr); 2290 goto next; 2291 } 2292 2293 iterateRegistryBusy(iterator, newNodes, snapshot, count); 2294 2295 kr = IORegistryIteratorExitEntry(iterator); 2296 if (kr != kIOReturnSuccess) { 2297 SCLog(TRUE, LOG_ERR, 2298 CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryIteratorExitEntry returned 0x%x"), 2299 kr); 2300 } 2301 2302 next : 2303 2304 CFRelease(newNodes); 2305 IOObjectRelease(obj); 2306 } 2307 2308 return; 2309} 2310 2311static CF_RETURNS_RETAINED CFStringRef 2312captureBusy() 2313{ 2314 int count = 0; 2315 io_iterator_t iterator = MACH_PORT_NULL; 2316 kern_return_t kr; 2317 CFMutableStringRef snapshot; 2318 2319 snapshot = CFStringCreateMutable(NULL, 0); 2320 2321 kr = IORegistryCreateIterator(kIOMasterPortDefault, 2322 kIOServicePlane, 2323 0, 2324 &iterator); 2325 if (kr != kIOReturnSuccess) { 2326 SCLog(TRUE, LOG_ERR, 2327 CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryCreateIterator returned 0x%x"), 2328 kr); 2329 return snapshot; 2330 } 2331 2332 iterateRegistryBusy(iterator, NULL, snapshot, &count); 2333 if (count == 0) { 2334 CFStringAppend(snapshot, CFSTR("w/no busy services")); 2335 } 2336 2337 IOObjectRelease(iterator); 2338 return snapshot; 2339} 2340 2341static void 2342timerCallback(CFRunLoopTimerRef timer, void *info) 2343{ 2344 CFStringRef snapshot; 2345 2346 // We've been waiting for IOKit to quiesce and it just 2347 // hasn't happenned. Time to just move on! 2348 addTimestamp(S_state, CFSTR("*TIMEOUT*")); 2349 2350 // log busy nodes 2351 snapshot = captureBusy(); 2352 SCLog(TRUE, LOG_ERR, 2353 CFSTR(MY_PLUGIN_NAME ": timed out waiting for IOKit to quiesce\n%@"), 2354 snapshot); 2355 reportIssue("timed out waiting for IOKit to quiesce", snapshot); 2356 CFRelease(snapshot); 2357 2358 quietCallback((void *)S_notify, MACH_PORT_NULL, 0, NULL); 2359 return; 2360} 2361 2362static Boolean 2363setup_IOKit(CFBundleRef bundle) 2364{ 2365 uint32_t busy; 2366 kern_return_t kr; 2367 mach_port_t masterPort = MACH_PORT_NULL; 2368 Boolean ok = FALSE; 2369 io_object_t root = MACH_PORT_NULL; 2370 2371 // read DB of previously named network interfaces 2372 S_dblist = readInterfaceList(); 2373 if (S_dblist != NULL) { 2374 CFIndex n; 2375 2376 n = CFArrayGetCount(S_dblist); 2377 if (n > 1) { 2378 CFArraySortValues(S_dblist, CFRangeMake(0, n), if_unit_compare, NULL); 2379 } 2380 } 2381 2382 // get interfaces that were named during the last boot 2383 S_prev_active_list = previouslyActiveInterfaces(); 2384 2385 // track how long we've waited to see each interface. 2386 S_state = CFDictionaryCreateMutable(NULL, 2387 0, 2388 &kCFTypeDictionaryKeyCallBacks, 2389 &kCFTypeDictionaryValueCallBacks); 2390 addTimestamp(S_state, CFSTR("*START*")); 2391 2392 // Creates and returns a notification object for receiving IOKit 2393 // notifications of new devices or state changes. 2394 kr = IOMasterPort(bootstrap_port, &masterPort); 2395 if (kr != KERN_SUCCESS) { 2396 SCLog(TRUE, LOG_ERR, 2397 CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"), 2398 kr); 2399 goto done; 2400 } 2401 2402 S_notify = IONotificationPortCreate(masterPort); 2403 if (S_notify == NULL) { 2404 SCLog(TRUE, LOG_ERR, 2405 CFSTR(MY_PLUGIN_NAME ": IONotificationPortCreate failed")); 2406 goto done; 2407 } 2408 2409 // watch IOKit matching activity 2410 root = IORegistryEntryFromPath(masterPort, kIOServicePlane ":/"); 2411 if (root == MACH_PORT_NULL) { 2412 SCLog(TRUE, LOG_ERR, 2413 CFSTR(MY_PLUGIN_NAME ": IORegistryEntryFromPath failed")); 2414 goto done; 2415 } 2416 2417 kr = IOServiceAddInterestNotification(S_notify, 2418 root, 2419 kIOBusyInterest, 2420 &quietCallback, 2421 (void *)S_notify, // refCon 2422 &S_quiet); // notification 2423 if (kr != KERN_SUCCESS) { 2424 SCLog(TRUE, LOG_ERR, 2425 CFSTR(MY_PLUGIN_NAME ": IOServiceAddInterestNotification returned 0x%x"), 2426 kr); 2427 goto done; 2428 } 2429 2430 kr = IOServiceGetBusyState(root, &busy); 2431 if (kr != KERN_SUCCESS) { 2432 SCLog(TRUE, LOG_ERR, 2433 CFSTR(MY_PLUGIN_NAME ": IOServiceGetBusyState returned 0x%x"), 2434 kr); 2435 goto done; 2436 } 2437 2438 // add a timer so we don't wait forever for IOKit to quiesce 2439 S_timer = CFRunLoopTimerCreate(NULL, 2440 CFAbsoluteTimeGetCurrent() + S_stack_timeout, 2441 0, 2442 0, 2443 0, 2444 timerCallback, 2445 NULL); 2446 if (S_timer == NULL) { 2447 SCLog(TRUE, LOG_ERR, 2448 CFSTR(MY_PLUGIN_NAME ": CFRunLoopTimerCreate failed")); 2449 goto done; 2450 } 2451 2452 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, kCFRunLoopDefaultMode); 2453 2454 // watch for the introduction of the IONetworkStack 2455 kr = IOServiceAddMatchingNotification(S_notify, 2456 kIOFirstMatchNotification, 2457 IOServiceMatching("IONetworkStack"), 2458 &stackCallback, 2459 (void *)S_notify, // refCon 2460 &S_stack); // notification 2461 if (kr != KERN_SUCCESS) { 2462 SCLog(TRUE, LOG_ERR, 2463 CFSTR(MY_PLUGIN_NAME ": IOServiceAddMatchingNotification returned 0x%x"), 2464 kr); 2465 goto done; 2466 } 2467 2468 // check and see if the stack is already available and arm the 2469 // notification for its introduction. 2470 stackCallback((void *)S_notify, S_stack); 2471 2472 // watch for the introduction of new network interfaces 2473 kr = IOServiceAddMatchingNotification(S_notify, 2474 kIOFirstMatchNotification, 2475 IOServiceMatching("IONetworkInterface"), 2476 &interfaceArrivalCallback, 2477 (void *)S_notify, // refCon 2478 &S_iter); // notification 2479 if (kr != KERN_SUCCESS) { 2480 SCLog(TRUE, LOG_ERR, 2481 CFSTR(MY_PLUGIN_NAME ": IOServiceAddMatchingNotification returned 0x%x"), 2482 kr); 2483 goto done; 2484 } 2485 2486 // Get the current list of matches and arm the notification for 2487 // future interface arrivals. 2488 interfaceArrivalCallback((void *)S_notify, S_iter); 2489 2490 // Check if IOKit has already quiesced. 2491 quietCallback((void *)S_notify, 2492 MACH_PORT_NULL, 2493 kIOMessageServiceBusyStateChange, 2494 (void *)(uintptr_t)busy); 2495 2496 CFRunLoopAddSource(CFRunLoopGetCurrent(), 2497 IONotificationPortGetRunLoopSource(S_notify), 2498 kCFRunLoopDefaultMode); 2499 2500#ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET 2501 /* 2502 * Start the wheels turning until we've named all of 2503 * the interfaces that were used during the previous 2504 * boot, until IOKit [matching] has quiesced, or 2505 * until we've waited long enough. 2506 */ 2507 CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, MY_PLUGIN_ID); 2508 CFRunLoopAddSource(CFRunLoopGetCurrent(), 2509 IONotificationPortGetRunLoopSource(S_notify), 2510 MY_PLUGIN_ID); 2511 while (S_prev_active_list != NULL) { 2512 int rlStatus; 2513 2514 rlStatus = CFRunLoopRunInMode(MY_PLUGIN_ID, 1.0e10, TRUE); 2515 } 2516#endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */ 2517 2518#if !TARGET_OS_EMBEDDED 2519 if (S_dblist != NULL) { 2520 // apply special handling for the BT-PAN interface (if present) 2521 CFArrayApplyFunction(S_dblist, 2522 CFRangeMake(0, CFArrayGetCount(S_dblist)), 2523 updateBTPANInformation, 2524 NULL); 2525 } 2526#endif // !TARGET_OS_EMBEDDED 2527 2528 ok = TRUE; 2529 2530 done: 2531 if (root != MACH_PORT_NULL) { 2532 IOObjectRelease(root); 2533 } 2534 if (masterPort != MACH_PORT_NULL) { 2535 mach_port_deallocate(mach_task_self(), masterPort); 2536 } 2537 2538 return ok; 2539} 2540 2541static Boolean 2542setup_Virtual(CFBundleRef bundle) 2543{ 2544 // open a SCPreferences session 2545 S_prefs = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME), NULL); 2546 if (S_prefs == NULL) { 2547 SCLog(TRUE, LOG_ERR, 2548 CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate() failed: %s"), 2549 SCErrorString(SCError())); 2550 return FALSE; 2551 } 2552 2553 // register for change notifications. 2554 if (!SCPreferencesSetCallback(S_prefs, updateVirtualNetworkInterfaceConfiguration, NULL)) { 2555 SCLog(TRUE, LOG_ERR, 2556 CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetCallBack() failed: %s"), 2557 SCErrorString(SCError())); 2558 CFRelease(S_prefs); 2559 return FALSE; 2560 } 2561 2562 // schedule 2563 if (!SCPreferencesScheduleWithRunLoop(S_prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { 2564 if (SCError() != kSCStatusNoStoreServer) { 2565 SCLog(TRUE, LOG_ERR, 2566 CFSTR(MY_PLUGIN_NAME ": SCPreferencesScheduleWithRunLoop() failed: %s"), 2567 SCErrorString(SCError())); 2568 CFRelease(S_prefs); 2569 return FALSE; 2570 } 2571 } 2572 2573 return TRUE; 2574} 2575 2576static void * 2577exec_InterfaceNamer(void *arg) 2578{ 2579 CFBundleRef bundle = (CFBundleRef)arg; 2580 CFDictionaryRef dict; 2581 2582 pthread_setname_np(MY_PLUGIN_NAME " thread"); 2583 2584 dict = CFBundleGetInfoDictionary(bundle); 2585 if (isA_CFDictionary(dict)) { 2586 CFNumberRef num; 2587 2588 num = CFDictionaryGetValue(dict, CFSTR(WAIT_STACK_TIMEOUT_KEY)); 2589 if (num != NULL) { 2590 if (!isA_CFNumber(num) || 2591 !CFNumberGetValue(num, kCFNumberDoubleType, &S_stack_timeout) || 2592 (S_stack_timeout <= 0.0)) { 2593 SCLog(TRUE, LOG_ERR, 2594 CFSTR(MY_PLUGIN_NAME ": " WAIT_STACK_TIMEOUT_KEY " value error")); 2595 S_stack_timeout = WAIT_STACK_TIMEOUT_DEFAULT; 2596 } 2597 } 2598 2599 num = CFDictionaryGetValue(dict, CFSTR(WAIT_QUIET_TIMEOUT_KEY)); 2600 if (num != NULL) { 2601 if (!isA_CFNumber(num) || 2602 !CFNumberGetValue(num, kCFNumberDoubleType, &S_quiet_timeout) || 2603 (S_quiet_timeout <= 0.0)) { 2604 SCLog(TRUE, LOG_ERR, 2605 CFSTR(MY_PLUGIN_NAME ": " WAIT_QUIET_TIMEOUT_KEY " value error")); 2606 S_quiet_timeout = WAIT_QUIET_TIMEOUT_DEFAULT; 2607 } 2608 } 2609 } 2610 2611 // setup virtual network interface monitoring 2612 if (!setup_Virtual(bundle)) { 2613 goto error; 2614 } 2615 2616 // setup [IOKit] network interface monitoring 2617 if (!setup_IOKit(bundle)) { 2618 goto error; 2619 } 2620 2621#if !TARGET_OS_EMBEDDED 2622 // keep launchd from SIGKILL'ing us until after the platform-uuid has 2623 // been updated 2624 S_vproc_transaction = vproc_transaction_begin(NULL); 2625#endif // !TARGET_OS_EMBEDDED 2626 2627 goto done; 2628 2629 error : 2630 if (S_connect != MACH_PORT_NULL) { 2631 IOServiceClose(S_connect); 2632 S_connect = MACH_PORT_NULL; 2633 } 2634 if (S_dblist != NULL) { 2635 CFRelease(S_dblist); 2636 S_dblist = NULL; 2637 } 2638 if (S_iter != MACH_PORT_NULL) { 2639 IOObjectRelease(S_iter); 2640 S_iter = MACH_PORT_NULL; 2641 } 2642 if (S_notify != MACH_PORT_NULL) { 2643 IONotificationPortDestroy(S_notify); 2644 } 2645 if (S_quiet != MACH_PORT_NULL) { 2646 IOObjectRelease(S_quiet); 2647 S_quiet = MACH_PORT_NULL; 2648 } 2649 if (S_stack != MACH_PORT_NULL) { 2650 IOObjectRelease(S_stack); 2651 S_stack = MACH_PORT_NULL; 2652 } 2653 if (S_state != NULL) { 2654 CFRelease(S_state); 2655 S_state = NULL; 2656 } 2657 if (S_timer != NULL) { 2658 CFRunLoopTimerInvalidate(S_timer); 2659 CFRelease(S_timer); 2660 S_timer = NULL; 2661 } 2662 2663 done : 2664 CFRelease(bundle); 2665 CFRunLoopRun(); 2666 2667 return NULL; 2668} 2669 2670__private_extern__ 2671void 2672load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose) 2673{ 2674 pthread_attr_t tattr; 2675 pthread_t tid; 2676 2677 if (bundleVerbose) { 2678 S_debug = TRUE; 2679 } 2680 2681 CFRetain(bundle); // released in exec_InterfaceNamer 2682 2683 pthread_attr_init(&tattr); 2684 pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM); 2685 pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 2686// pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack 2687 pthread_create(&tid, &tattr, exec_InterfaceNamer, bundle); 2688 pthread_attr_destroy(&tattr); 2689 2690 return; 2691} 2692 2693//------------------------------------------------------------------------ 2694// Main function. 2695#ifdef MAIN 2696int 2697main(int argc, char ** argv) 2698{ 2699 CFBundleRef bundle; 2700 2701 _sc_log = FALSE; 2702 _sc_verbose = (argc > 1) ? TRUE : FALSE; 2703 2704 S_debug = _sc_verbose; 2705 2706 bundle = CFBundleGetMainBundle(); 2707 CFRetain(bundle); // released in exec_InterfaceNamer 2708 2709 (void)exec_InterfaceNamer(); 2710 2711 /* not reached */ 2712 exit(0); 2713 return 0; 2714} 2715#endif /* MAIN */ 2716 2717#ifdef TEST_PLATFORM_UUID 2718int 2719main(int argc, char ** argv) 2720{ 2721 CFStringRef guid; 2722 CFArrayRef interfaces; 2723 2724 _sc_log = FALSE; 2725 _sc_verbose = (argc > 1) ? TRUE : FALSE; 2726 2727 S_dblist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 2728 interfaces = SCNetworkInterfaceCopyAll(); 2729 if (interfaces != NULL) { 2730 CFIndex i; 2731 CFIndex n; 2732 2733 n = CFArrayGetCount(interfaces); 2734 for (i = 0; i < n; i++) { 2735 CFDictionaryRef dict; 2736 SCNetworkInterfaceRef interface; 2737 2738 interface = CFArrayGetValueAtIndex(interfaces, i); 2739 dict = createInterfaceDict(interface); 2740 CFArrayAppendValue(S_dblist, dict); 2741 CFRelease(dict); 2742 } 2743 CFRelease(interfaces); 2744 } 2745 2746 guid = copyEthernetUUID(); 2747 SCPrint(TRUE, stdout, CFSTR("copyEthernetUUID() = %@\n"), (guid != NULL) ? guid : CFSTR("NULL")); 2748 if (guid != NULL) CFRelease(guid); 2749 2750 updatePlatformUUID(); 2751 CFRelease(S_dblist); 2752 exit(0); 2753 return 0; 2754} 2755#endif /* TEST_PLATFORM_UUID */ 2756 2757#ifdef TEST_SNAPSHOT 2758int 2759main(int argc, char ** argv) 2760{ 2761 CFStringRef snapshot; 2762 2763 _sc_log = FALSE; 2764 _sc_verbose = (argc > 1) ? TRUE : FALSE; 2765 2766 snapshot = captureBusy(); 2767 SCPrint(TRUE, stdout, CFSTR("%@\n"), snapshot); 2768 CFRelease(snapshot); 2769 2770 exit(0); 2771 return 0; 2772} 2773#endif /* TEST_SNAPSHOT */ 2774 2775