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