this repo has no description
at fixPythonPipStalling 896 lines 23 kB view raw
1/* 2 * Copyright (c) 2002-2007, 2011, 2013, 2015-2019 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 * October 21, 2000 Allan Nathanson <ajn@apple.com> 28 * - initial revision 29 */ 30 31 32#include <stdio.h> 33#include <unistd.h> 34#include <sys/ioctl.h> 35#include <sys/socket.h> 36#include <sys/wait.h> 37#include <net/if.h> 38#include <net/if_media.h> 39 40#define SC_LOG_HANDLE __log_LinkConfiguration 41#define SC_LOG_HANDLE_TYPE static 42#include "SCNetworkConfigurationInternal.h" 43#include <SystemConfiguration/SCDPlugin.h> // for _SCDPluginExecCommand 44 45 46static CFMutableDictionaryRef baseSettings = NULL; 47static CFStringRef interfacesKey = NULL; 48static SCDynamicStoreRef store = NULL; 49static CFRunLoopSourceRef rls = NULL; 50static CFMutableDictionaryRef wantSettings = NULL; 51 52 53#pragma mark - 54#pragma mark Logging 55 56 57static os_log_t 58__log_LinkConfiguration(void) 59{ 60 static os_log_t log = NULL; 61 62 if (log == NULL) { 63 log = os_log_create("com.apple.SystemConfiguration", "LinkConfiguration"); 64 } 65 66 return log; 67} 68 69 70#pragma mark - 71#pragma mark Capabilities 72 73 74#define CAPABILITIES_KEY CFSTR("_CAPABILITIES_") 75 76 77__private_extern__ 78Boolean 79_SCNetworkInterfaceSetCapabilities(SCNetworkInterfaceRef interface, 80 CFDictionaryRef options) 81{ 82 CFDictionaryRef baseOptions; 83 int cap_base; 84 int cap_current; 85 int cap_requested; 86 CFStringRef interfaceName; 87 88#ifdef SIOCSIFCAP 89 struct ifreq ifr; 90 int ret; 91 int sock; 92#endif // SIOCSIFCAP 93 94 interfaceName = SCNetworkInterfaceGetBSDName(interface); 95 if (interfaceName == NULL) { 96 /* if no BSD interface name */ 97 return FALSE; 98 } 99 100 cap_current = __SCNetworkInterfaceCreateCapabilities(interface, -1, NULL); 101 if (cap_current == -1) { 102 /* could not get current capabilities */ 103 return FALSE; 104 } 105 106 // get base capabilities 107 cap_base = cap_current; 108 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName); 109 if (baseOptions != NULL) { 110 CFNumberRef num; 111 112 num = CFDictionaryGetValue(baseOptions, CAPABILITIES_KEY); 113 if (num != NULL) { 114 CFNumberGetValue(num, kCFNumberIntType, &cap_base); 115 } 116 } 117 118 cap_requested = __SCNetworkInterfaceCreateCapabilities(interface, cap_base, options); 119 120#ifdef SIOCSIFCAP 121 if (cap_requested == cap_current) { 122 /* if current setting is as requested */ 123 return TRUE; 124 } 125 126 memset((char *)&ifr, 0, sizeof(ifr)); 127 (void)_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII); 128 ifr.ifr_curcap = cap_current; 129 ifr.ifr_reqcap = cap_requested; 130 131 sock = socket(AF_INET, SOCK_DGRAM, 0); 132 if (sock == -1) { 133 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno)); 134 return FALSE; 135 } 136 137 ret = ioctl(sock, SIOCSIFCAP, (caddr_t)&ifr); 138 (void)close(sock); 139 if (ret == -1) { 140 SC_log(LOG_ERR, "%@: ioctl(SIOCSIFCAP) failed: %s", interfaceName, strerror(errno)); 141 return FALSE; 142 } 143#endif // SIOCSIFCAP 144 145 return TRUE; 146} 147 148 149#pragma mark - 150#pragma mark Media options 151 152 153static CFDictionaryRef 154__copyMediaOptions(CFDictionaryRef options) 155{ 156 CFMutableDictionaryRef requested = NULL; 157 CFTypeRef val; 158 159 if (!isA_CFDictionary(options)) { 160 return NULL; 161 } 162 163 val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType); 164 if (isA_CFString(val)) { 165 requested = CFDictionaryCreateMutable(NULL, 166 0, 167 &kCFTypeDictionaryKeyCallBacks, 168 &kCFTypeDictionaryValueCallBacks); 169 CFDictionaryAddValue(requested, kSCPropNetEthernetMediaSubType, val); 170 } else { 171 /* if garbage */; 172 return NULL; 173 } 174 175 val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaOptions); 176 if (isA_CFArray(val)) { 177 CFDictionaryAddValue(requested, kSCPropNetEthernetMediaOptions, val); 178 } else { 179 /* if garbage */; 180 CFRelease(requested); 181 return NULL; 182 } 183 184 return requested; 185} 186 187 188__private_extern__ 189Boolean 190_SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface, 191 CFDictionaryRef options) 192{ 193 CFArrayRef available = NULL; 194 CFDictionaryRef current = NULL; 195 struct ifmediareq ifm; 196 struct ifreq ifr; 197 CFStringRef interfaceName; 198 Boolean ok = FALSE; 199 int newOptions; 200 CFDictionaryRef requested; 201 int sock = -1; 202 203 if (!isA_SCNetworkInterface(interface)) { 204 _SCErrorSet(kSCStatusInvalidArgument); 205 return FALSE; 206 } 207 208 interfaceName = SCNetworkInterfaceGetBSDName(interface); 209 if (interfaceName == NULL) { 210 /* if no BSD interface name */ 211 SC_log(LOG_INFO, "no BSD interface name for %@", interface); 212 _SCErrorSet(kSCStatusInvalidArgument); 213 return FALSE; 214 } 215 216 /* get current & available options */ 217 if (!SCNetworkInterfaceCopyMediaOptions(interface, &current, NULL, &available, FALSE)) { 218 /* could not get current media options */ 219 SC_log(LOG_INFO, "no media options for %@", interfaceName); 220 return FALSE; 221 } 222 223 /* extract just the dictionary key/value pairs of interest */ 224 requested = __copyMediaOptions(options); 225 if (requested == NULL) { 226 CFDictionaryRef baseOptions; 227 228 /* get base options */ 229 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName); 230 requested = __copyMediaOptions(baseOptions); 231 } 232 if (requested == NULL) { 233 /* get base options */ 234 requested = __copyMediaOptions(current); 235 } 236 if (requested == NULL) { 237 /* if no media options to set */ 238 goto done; 239 } 240 241 if ((current != NULL) && CFEqual(current, requested)) { 242 /* if current settings are as requested */ 243 ok = TRUE; 244 goto done; 245 } 246 247 if (!CFArrayContainsValue(available, CFRangeMake(0, CFArrayGetCount(available)), requested)) { 248 /* if requested settings not currently available */ 249 SC_log(LOG_INFO, "requested media settings unavailable for %@", interfaceName); 250 goto done; 251 } 252 253 newOptions = __SCNetworkInterfaceCreateMediaOptions(interface, requested); 254 if (newOptions == -1) { 255 /* since we have just validated, this should never happen */ 256 goto done; 257 } 258 259 sock = socket(AF_INET, SOCK_DGRAM, 0); 260 if (sock == -1) { 261 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno)); 262 goto done; 263 } 264 265 memset((char *)&ifm, 0, sizeof(ifm)); 266 (void)_SC_cfstring_to_cstring(interfaceName, ifm.ifm_name, sizeof(ifm.ifm_name), kCFStringEncodingASCII); 267 268 if (ioctl(sock, SIOCGIFXMEDIA, (caddr_t)&ifm) == -1) { 269 SC_log(LOG_ERR, "%@: ioctl(SIOCGIFXMEDIA) failed: %s", interfaceName, strerror(errno)); 270 goto done; 271 } 272 273 memset((char *)&ifr, 0, sizeof(ifr)); 274 memcpy(ifr.ifr_name, ifm.ifm_name, sizeof(ifr.ifr_name)); 275 ifr.ifr_media = ifm.ifm_current & ~(IFM_NMASK|IFM_TMASK|IFM_OMASK|IFM_GMASK); 276 ifr.ifr_media |= newOptions; 277 278 SC_log(LOG_INFO, "old media settings: 0x%8.8x (0x%8.8x)", ifm.ifm_current, ifm.ifm_active); 279 SC_log(LOG_INFO, "new media settings: 0x%8.8x", ifr.ifr_media); 280 281 if (ioctl(sock, SIOCSIFMEDIA, (caddr_t)&ifr) == -1) { 282 SC_log(LOG_ERR, "%@: ioctl(SIOCSIFMEDIA) failed: %s", interfaceName, strerror(errno)); 283 goto done; 284 } 285 286 ok = TRUE; 287 288 done : 289 290 if (available != NULL) CFRelease(available); 291 if (current != NULL) CFRelease(current); 292 if (requested != NULL) CFRelease(requested); 293 if (sock != -1) (void)close(sock); 294 295 return ok; 296} 297 298 299#pragma mark - 300#pragma mark MTU 301 302 303#ifndef USE_SIOCSIFMTU 304static void 305ifconfig_exit(pid_t pid, int status, struct rusage *rusage, void *context) 306{ 307#pragma unused(pid) 308#pragma unused(rusage) 309 char *if_name = (char *)context; 310 311 if (WIFEXITED(status)) { 312 if (WEXITSTATUS(status) != 0) { 313 SC_log(LOG_NOTICE, "ifconfig %s failed, exit status = %d", 314 if_name, 315 WEXITSTATUS(status)); 316 } 317 } else if (WIFSIGNALED(status)) { 318 SC_log(LOG_NOTICE, "ifconfig %s: terminated w/signal = %d", 319 if_name, 320 WTERMSIG(status)); 321 } else { 322 SC_log(LOG_NOTICE, "ifconfig %s: exit status = %d", 323 if_name, 324 status); 325 } 326 327 CFAllocatorDeallocate(NULL, if_name); 328 return; 329} 330#endif /* !USE_SIOCSIFMTU */ 331 332 333__private_extern__ 334Boolean 335_SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface, 336 CFDictionaryRef options) 337{ 338 CFArrayRef bridge_members = NULL; 339 Boolean bridge_updated = FALSE; 340 CFStringRef interfaceName; 341 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; 342 CFStringRef interfaceType; 343 int mtu_cur = -1; 344 int mtu_max = -1; 345 int mtu_min = -1; 346 Boolean ok = TRUE; 347 int requested; 348 CFNumberRef val; 349 350 interfaceName = SCNetworkInterfaceGetBSDName(interface); 351 if (interfaceName == NULL) { 352 /* if no BSD interface name */ 353 return FALSE; 354 } 355 356 if (!SCNetworkInterfaceCopyMTU(interface, &mtu_cur, &mtu_min, &mtu_max)) { 357 /* could not get current MTU */ 358 return FALSE; 359 } 360 361 val = NULL; 362 if (isA_CFDictionary(options)) { 363 val = CFDictionaryGetValue(options, kSCPropNetEthernetMTU); 364 val = isA_CFNumber(val); 365 } 366 if (val == NULL) { 367 CFDictionaryRef baseOptions; 368 369 /* get base MTU */ 370 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName); 371 if (baseOptions != NULL) { 372 val = CFDictionaryGetValue(baseOptions, kSCPropNetEthernetMTU); 373 } 374 } 375 if (val != NULL) { 376 CFNumberGetValue(val, kCFNumberIntType, &requested); 377 } else { 378 requested = mtu_cur; 379 } 380 381 if (requested == mtu_cur) { 382 /* if current setting is as requested */ 383 return TRUE; 384 } 385 386 if (((mtu_min >= 0) && (requested < mtu_min)) || 387 ((mtu_max >= 0) && (requested > mtu_max))) { 388 /* if requested MTU outside of the valid range */ 389 return FALSE; 390 } 391 392 interfaceType = SCNetworkInterfaceGetInterfaceType(interface); 393 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) { 394 bridge_members = SCBridgeInterfaceGetMemberInterfaces(interface); 395 if ((bridge_members != NULL) && (CFArrayGetCount(bridge_members) == 0)) { 396 /* if no members */ 397 bridge_members = NULL; 398 } 399 if (bridge_members != NULL) { 400 SCNetworkInterfaceRef member0; 401 402 /* temporarily, remove all bridge members */ 403 CFRetain(bridge_members); 404 ok = SCBridgeInterfaceSetMemberInterfaces(interface, NULL); 405 if (!ok) { 406 goto done; 407 } 408 409 /* and update the (bridge) configuration */ 410 ok = _SCBridgeInterfaceUpdateConfiguration(interfacePrivate->prefs); 411 if (!ok) { 412 goto done; 413 } 414 415 /* switch from updating the MTU of the bridge to the first member */ 416 member0 = CFArrayGetValueAtIndex(bridge_members, 0); 417 interfaceName = SCNetworkInterfaceGetBSDName(member0); 418 419 bridge_updated = TRUE; 420 } 421 } 422 423#ifdef USE_SIOCSIFMTU 424{ 425 struct ifreq ifr; 426 int ret; 427 int sock; 428 429 memset((char *)&ifr, 0, sizeof(ifr)); 430 (void)_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII); 431 ifr.ifr_mtu = requested; 432 433 sock = socket(AF_INET, SOCK_DGRAM, 0); 434 if (sock == -1) { 435 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno)); 436 ok = FALSE; 437 goto done; 438 } 439 440 ret = ioctl(sock, SIOCSIFMTU, (caddr_t)&ifr); 441 (void)close(sock); 442 if (ret == -1) { 443 SC_log(LOG_ERR, "%@: ioctl(SIOCSIFMTU) failed: %s", interfaceName, strerror(errno)); 444 ok = FALSE; 445 goto done; 446 } 447} 448#else /* !USE_SIOCSIFMTU */ 449{ 450 char *ifconfig_argv[] = { "ifconfig", NULL, "mtu", NULL, NULL }; 451 pid_t pid; 452 453 ifconfig_argv[1] = _SC_cfstring_to_cstring(interfaceName, NULL, 0, kCFStringEncodingASCII); 454 (void)asprintf(&ifconfig_argv[3], "%d", requested); 455 456 pid = _SCDPluginExecCommand(ifconfig_exit, // callout, 457 ifconfig_argv[1], // context 458 0, // uid 459 0, // gid 460 "/sbin/ifconfig", // path 461 ifconfig_argv // argv 462 ); 463 464// CFAllocatorDeallocate(NULL, ifconfig_argv[1]); // released in ifconfig_exit() 465 free(ifconfig_argv[3]); 466 467 if (pid <= 0) { 468 ok = FALSE; 469 goto done; 470 } 471} 472#endif /* !USE_SIOCSIFMTU */ 473 474 done : 475 476 if (bridge_members != NULL) { 477 /* restore bridge members */ 478 (void) SCBridgeInterfaceSetMemberInterfaces(interface, bridge_members); 479 CFRelease(bridge_members); 480 481 if (bridge_updated) { 482 /* and update the (bridge) configuration */ 483 (void) _SCBridgeInterfaceUpdateConfiguration(interfacePrivate->prefs); 484 } 485 } 486 487 return ok; 488} 489 490 491#pragma mark - 492#pragma mark Update link configuration 493 494 495/* 496 * Function: parse_component 497 * Purpose: 498 * Given a string 'key' and a string prefix 'prefix', 499 * return the next component in the slash '/' separated 500 * key. 501 * 502 * Examples: 503 * 1. key = "a/b/c" prefix = "a/" 504 * returns "b" 505 * 2. key = "a/b/c" prefix = "a/b/" 506 * returns "c" 507 */ 508static CF_RETURNS_RETAINED CFStringRef 509parse_component(CFStringRef key, CFStringRef prefix) 510{ 511 CFMutableStringRef comp; 512 CFRange range; 513 514 if (!CFStringHasPrefix(key, prefix)) { 515 return NULL; 516 } 517 comp = CFStringCreateMutableCopy(NULL, 0, key); 518 CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix))); 519 range = CFStringFind(comp, CFSTR("/"), 0); 520 if (range.location == kCFNotFound) { 521 return comp; 522 } 523 range.length = CFStringGetLength(comp) - range.location; 524 CFStringDelete(comp, range); 525 return comp; 526} 527 528 529static void updateLink(CFStringRef interfaceName, CFDictionaryRef options); 530 531 532static void 533updateInterfaces(CFArrayRef newInterfaces) 534{ 535 CFIndex i; 536 CFIndex n_old; 537 CFIndex n_new; 538 static CFArrayRef oldInterfaces = NULL; 539 540 n_old = (oldInterfaces != NULL) ? CFArrayGetCount(oldInterfaces) : 0; 541 n_new = CFArrayGetCount(newInterfaces); 542 543 for (i = 0; i < n_new; i++) { 544 CFStringRef interfaceName; 545 546 interfaceName = CFArrayGetValueAtIndex(newInterfaces, i); 547 548 if ((n_old == 0) || 549 !CFArrayContainsValue(oldInterfaces, 550 CFRangeMake(0, n_old), 551 interfaceName)) { 552 CFDictionaryRef options; 553 554 // if new interface 555 options = CFDictionaryGetValue(wantSettings, interfaceName); 556 updateLink(interfaceName, options); 557 } 558 } 559 560 if (oldInterfaces != NULL) CFRelease(oldInterfaces); 561 oldInterfaces = CFRetain(newInterfaces); 562} 563 564 565static void 566updateLink(CFStringRef interfaceName, CFDictionaryRef options) 567{ 568 SCNetworkInterfaceRef interface; 569 570 /* retain requested configuration */ 571 if (options != NULL) { 572 CFDictionarySetValue(wantSettings, interfaceName, options); 573 } else { 574 CFDictionaryRemoveValue(wantSettings, interfaceName); 575 } 576 577 /* apply requested configuration */ 578 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, interfaceName, 579 kIncludeAllVirtualInterfaces); 580 if (interface == NULL) { 581 return; 582 } 583 584 if (options != NULL) { 585 if (!CFDictionaryContainsKey(baseSettings, interfaceName)) { 586 int cur_cap = -1; 587 CFDictionaryRef cur_media = NULL; 588 CFMutableDictionaryRef new_media = NULL; 589 int cur_mtu = -1; 590 591 /* preserve current media options */ 592 if (SCNetworkInterfaceCopyMediaOptions(interface, &cur_media, NULL, NULL, FALSE)) { 593 if (cur_media != NULL) { 594 new_media = CFDictionaryCreateMutableCopy(NULL, 0, cur_media); 595 CFRelease(cur_media); 596 } 597 } 598 599 /* preserve current MTU */ 600 if (SCNetworkInterfaceCopyMTU(interface, &cur_mtu, NULL, NULL)) { 601 if (cur_mtu != -1) { 602 CFNumberRef num; 603 604 if (new_media == NULL) { 605 new_media = CFDictionaryCreateMutable(NULL, 606 0, 607 &kCFTypeDictionaryKeyCallBacks, 608 &kCFTypeDictionaryValueCallBacks); 609 } 610 611 num = CFNumberCreate(NULL, kCFNumberIntType, &cur_mtu); 612 CFDictionaryAddValue(new_media, kSCPropNetEthernetMTU, num); 613 CFRelease(num); 614 } 615 } 616 617 /* preserve capabilities */ 618 cur_cap = __SCNetworkInterfaceCreateCapabilities(interface, -1, NULL); 619 if (cur_cap != -1) { 620 CFNumberRef num; 621 622 if (new_media == NULL) { 623 new_media = CFDictionaryCreateMutable(NULL, 624 0, 625 &kCFTypeDictionaryKeyCallBacks, 626 &kCFTypeDictionaryValueCallBacks); 627 } 628 629 num = CFNumberCreate(NULL, kCFNumberIntType, &cur_cap); 630 CFDictionaryAddValue(new_media, CAPABILITIES_KEY, num); 631 CFRelease(num); 632 } 633 634 if (new_media != NULL) { 635 CFDictionarySetValue(baseSettings, interfaceName, new_media); 636 CFRelease(new_media); 637 } 638 } 639 640 /* establish new settings */ 641 (void)_SCNetworkInterfaceSetCapabilities(interface, options); 642 (void)_SCNetworkInterfaceSetMediaOptions(interface, options); 643 (void)_SCNetworkInterfaceSetMTU (interface, options); 644 } else { 645 /* no requested settings */ 646 options = CFDictionaryGetValue(baseSettings, interfaceName); 647 if (options != NULL) { 648 /* restore original settings */ 649 (void)_SCNetworkInterfaceSetCapabilities(interface, options); 650 (void)_SCNetworkInterfaceSetMediaOptions(interface, options); 651 (void)_SCNetworkInterfaceSetMTU (interface, options); 652 CFDictionaryRemoveValue(baseSettings, interfaceName); 653 } 654 } 655 656 CFRelease(interface); 657 return; 658} 659 660 661static void 662linkConfigChangedCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *arg) 663{ 664#pragma unused(arg) 665 CFDictionaryRef changes; 666 CFIndex i; 667 CFIndex n; 668 static CFStringRef prefix = NULL; 669 670 if (prefix == NULL) { 671 prefix = SCDynamicStoreKeyCreate(NULL, 672 CFSTR("%@/%@/%@/"), 673 kSCDynamicStoreDomainSetup, 674 kSCCompNetwork, 675 kSCCompInterface); 676 } 677 678 changes = SCDynamicStoreCopyMultiple(store, changedKeys, NULL); 679 680 n = (changes != NULL) ? CFArrayGetCount(changedKeys) : 0; 681 for (i = 0; i < n; i++) { 682 CFStringRef key; 683 CFDictionaryRef info; 684 685 key = CFArrayGetValueAtIndex(changedKeys, i); 686 info = CFDictionaryGetValue(changes, key); 687 688 if (CFEqual(key, interfacesKey)) { 689 if (isA_CFDictionary(info) != NULL) { 690 CFArrayRef interfaces; 691 692 interfaces = CFDictionaryGetValue(info, kSCPropNetInterfaces); 693 if (isA_CFArray(interfaces)) { 694 updateInterfaces(interfaces); 695 } 696 } 697 } else { 698 CFStringRef interfaceName; 699 700 interfaceName = parse_component(key, prefix); 701 if (interfaceName != NULL) { 702 updateLink(interfaceName, info); 703 CFRelease(interfaceName); 704 } 705 } 706 } 707 708 if (changes != NULL) { 709 CFRelease(changes); 710 } 711 712 return; 713} 714 715 716__private_extern__ 717void 718load_LinkConfiguration(CFBundleRef bundle, Boolean bundleVerbose) 719{ 720#pragma unused(bundleVerbose) 721 CFStringRef key; 722 CFMutableArrayRef keys = NULL; 723 Boolean ok; 724 CFMutableArrayRef patterns = NULL; 725 726 SC_log(LOG_DEBUG, "load() called"); 727 SC_log(LOG_DEBUG, " bundle ID = %@", CFBundleGetIdentifier(bundle)); 728 729 /* initialize a few globals */ 730 731 baseSettings = CFDictionaryCreateMutable(NULL, 732 0, 733 &kCFTypeDictionaryKeyCallBacks, 734 &kCFTypeDictionaryValueCallBacks); 735 wantSettings = CFDictionaryCreateMutable(NULL, 736 0, 737 &kCFTypeDictionaryKeyCallBacks, 738 &kCFTypeDictionaryValueCallBacks); 739 740 /* open a "configd" store to allow cache updates */ 741 store = SCDynamicStoreCreate(NULL, 742 CFSTR("Link Configuraton plug-in"), 743 linkConfigChangedCallback, 744 NULL); 745 if (store == NULL) { 746 SC_log(LOG_ERR, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError())); 747 goto error; 748 } 749 750 /* establish notification keys and patterns */ 751 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 752 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 753 754 /* ...watch for a change in the list of network interfaces */ 755 interfacesKey = SCDynamicStoreKeyCreateNetworkInterface(NULL, 756 kSCDynamicStoreDomainState); 757 CFArrayAppendValue(keys, interfacesKey); 758 759 /* ...watch for (per-interface) AirPort configuration changes */ 760 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 761 kSCDynamicStoreDomainSetup, 762 kSCCompAnyRegex, 763 kSCEntNetAirPort); 764 CFArrayAppendValue(patterns, key); 765 CFRelease(key); 766 767 /* ...watch for (per-interface) Ethernet configuration changes */ 768 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 769 kSCDynamicStoreDomainSetup, 770 kSCCompAnyRegex, 771 kSCEntNetEthernet); 772 CFArrayAppendValue(patterns, key); 773 CFRelease(key); 774 775#if TARGET_OS_OSX 776 /* ...watch for (per-interface) FireWire configuration changes */ 777 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 778 kSCDynamicStoreDomainSetup, 779 kSCCompAnyRegex, 780 kSCEntNetFireWire); 781 CFArrayAppendValue(patterns, key); 782 CFRelease(key); 783#endif // TARGET_OS_OSX 784 785 /* register the keys/patterns */ 786 ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns); 787 CFRelease(keys); 788 CFRelease(patterns); 789 if (!ok) { 790 SC_log(LOG_NOTICE, "SCDynamicStoreSetNotificationKeys() failed: %s", 791 SCErrorString(SCError())); 792 goto error; 793 } 794 795 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); 796 if (rls == NULL) { 797 SC_log(LOG_NOTICE, "SCDynamicStoreCreateRunLoopSource() failed: %s", 798 SCErrorString(SCError())); 799 goto error; 800 } 801 802 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 803 return; 804 805 error : 806 807 if (baseSettings != NULL) CFRelease(baseSettings); 808 if (wantSettings != NULL) CFRelease(wantSettings); 809 if (store != NULL) CFRelease(store); 810 return; 811} 812 813 814#ifdef MAIN 815 816 817#pragma mark - 818#pragma mark Standalone test code 819 820 821int 822main(int argc, char **argv) 823{ 824 SCPreferencesRef prefs; 825 826 _sc_log = FALSE; 827 _sc_verbose = (argc > 1) ? TRUE : FALSE; 828 829 prefs = SCPreferencesCreate(NULL, CFSTR("linkconfig"), NULL); 830 if (prefs != NULL) { 831 SCNetworkSetRef set; 832 833 set = SCNetworkSetCopyCurrent(prefs); 834 if (set != NULL) { 835 CFMutableSetRef seen; 836 CFArrayRef services; 837 838 services = SCNetworkSetCopyServices(set); 839 if (services != NULL) { 840 CFIndex i; 841 CFIndex n; 842 843 seen = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); 844 845 n = CFArrayGetCount(services); 846 for (i = 0; i < n; i++) { 847 SCNetworkInterfaceRef interface; 848 SCNetworkServiceRef service; 849 850 service = CFArrayGetValueAtIndex(services, i); 851 interface = SCNetworkServiceGetInterface(service); 852 if ((interface != NULL) && 853 !CFSetContainsValue(seen, interface)) { 854 CFDictionaryRef capabilities; 855 856 capabilities = SCNetworkInterfaceCopyCapability(interface, NULL); 857 if (capabilities != NULL) { 858 int cap_current; 859 int cap_requested; 860 CFDictionaryRef options; 861 862 options = SCNetworkInterfaceGetConfiguration(interface); 863 cap_current = __SCNetworkInterfaceCreateCapabilities(interface, -1, NULL); 864 cap_requested = __SCNetworkInterfaceCreateCapabilities(interface, cap_current, options); 865 866 SCPrint(TRUE, stdout, 867 CFSTR("%sinterface = %@, current = %p, requested = %p\n%@\n"), 868 (i == 0) ? "" : "\n", 869 SCNetworkInterfaceGetBSDName(interface), 870 (void *)(uintptr_t)cap_current, 871 (void *)(uintptr_t)cap_requested, 872 capabilities); 873 CFRelease(capabilities); 874 } 875 876 CFSetAddValue(seen, interface); 877 } 878 } 879 880 CFRelease(seen); 881 CFRelease(services); 882 } 883 884 CFRelease(set); 885 } 886 887 CFRelease(prefs); 888 } 889 890 load_LinkConfiguration(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE); 891 CFRunLoopRun(); 892 /* not reached */ 893 exit(0); 894 return 0; 895} 896#endif