1/* 2 * Copyright (c) 2009-2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Modification History 26 * 27 * July 27, 2009 Allan Nathanson <ajn@apple.com> 28 * - initial revision 29 */ 30 31 32#include <CoreFoundation/CoreFoundation.h> 33#include <CoreFoundation/CFRuntime.h> 34 35#include <SystemConfiguration/SystemConfiguration.h> 36#include "SCNetworkConfigurationInternal.h" 37#include "SCPreferencesInternal.h" 38#include <SystemConfiguration/SCValidation.h> 39#include <SystemConfiguration/SCPrivate.h> 40 41#include <ifaddrs.h> 42#include <pthread.h> 43#include <unistd.h> 44#include <sys/types.h> 45#include <sys/ioctl.h> 46#include <sys/socket.h> 47#include <sys/sysctl.h> 48#include <net/ethernet.h> 49#define KERNEL_PRIVATE 50#include <net/if.h> 51#include <net/if_var.h> 52#undef KERNEL_PRIVATE 53#include <net/if_types.h> 54#include <net/if_media.h> 55#include <net/route.h> 56 57#ifdef IFT_BRIDGE 58#include <net/if_bridgevar.h> 59#endif // IFT_BRIDGE 60 61/* ---------- Bridge support ---------- */ 62 63static int 64inet_dgram_socket() 65{ 66 int s; 67 68 s = socket(AF_INET, SOCK_DGRAM, 0); 69 if (s == -1) { 70 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno)); 71 } 72 73 return s; 74} 75 76#ifdef IFT_BRIDGE 77static struct ifbifconf * 78ifbifconf_copy(int s, const char * ifname) 79{ 80 void * buf; 81 size_t buflen; 82 struct ifbifconf * ibc_p = NULL; 83 struct ifdrv ifd; 84 uint32_t len = sizeof(struct ifbreq) * 16; 85 86 bzero(&ifd, sizeof(ifd)); 87 strncpy(ifd.ifd_name, ifname, sizeof(ifd.ifd_name)); 88 ifd.ifd_cmd = BRDGGIFS; 89 90 buflen = sizeof(struct ifbifconf) + len; 91 buf = malloc(buflen); 92 while (buf != NULL) { 93 bzero(buf, buflen); 94 ibc_p = (struct ifbifconf *)buf; 95 ibc_p->ifbic_len = len; 96 ibc_p->ifbic_buf = buf + sizeof(*ibc_p); 97 98 ifd.ifd_len = sizeof(*ibc_p); 99 ifd.ifd_data = ibc_p; 100 if (ioctl(s, SIOCGDRVSPEC, (caddr_t)&ifd) == -1) { 101 goto failed; 102 } 103 104 if ((ibc_p->ifbic_len + sizeof(struct ifbreq)) < len) { 105 // if we have room for all of the member interfaces 106 break; 107 } 108 109 len *= 2; 110 buflen = sizeof(struct ifbifconf) + len; 111 buf = reallocf(buf, buflen); 112 } 113 114 if (buf == NULL) { 115 goto failed; 116 } 117 118 return ibc_p; 119 120 failed: 121 if (buf != NULL) { 122 free(buf); 123 } 124 return NULL; 125} 126#endif // IFT_BRIDGE 127 128 129static void 130add_interface(CFMutableArrayRef *interfaces, CFStringRef if_name, SCPreferencesRef ni_prefs) 131{ 132 SCNetworkInterfaceRef interface = NULL; 133 134 if (*interfaces == NULL) { 135 *interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 136 } 137 if (ni_prefs != NULL) { 138 interface = __SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(NULL, ni_prefs, if_name); 139 } 140 if (interface == NULL) { 141 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, if_name, 142 kIncludeNoVirtualInterfaces); 143 } 144 145 if (interface != NULL) { 146 CFArrayAppendValue(*interfaces, interface); 147 CFRelease(interface); 148 } 149} 150 151typedef struct { 152 CFMutableArrayRef bridges; 153 SCPreferencesRef ni_prefs; 154 SCPreferencesRef prefs; 155} addContext, *addContextRef; 156 157 158static void 159add_configured_interface(const void *key, const void *value, void *context) 160{ 161 SCBridgeInterfaceRef bridge; 162 CFStringRef bridge_if = (CFStringRef)key; 163 CFDictionaryRef bridge_info = (CFDictionaryRef)value; 164 CFDictionaryRef bridge_options; 165 CFIndex i; 166 CFArrayRef interfaces; 167 SCNetworkInterfacePrivateRef interfacePrivate; 168 CFMutableArrayRef members = NULL; 169 addContextRef myContext = (addContextRef)context; 170 CFStringRef name; 171 CFStringRef name_auto = NULL; 172 CFIndex n; 173 174 // create the bridge interface 175 bridge = (SCBridgeInterfaceRef)_SCBridgeInterfaceCreatePrivate(NULL, bridge_if); 176 assert(bridge != NULL); 177 178 // estabish link to the stored configuration 179 interfacePrivate = (SCNetworkInterfacePrivateRef)bridge; 180 interfacePrivate->prefs = CFRetain(myContext->prefs); 181 182 // add member interfaces 183 interfaces = CFDictionaryGetValue(bridge_info, kSCPropVirtualNetworkInterfacesBridgeInterfaces); 184 n = isA_CFArray(interfaces) ? CFArrayGetCount(interfaces) : 0; 185 for (i = 0; i < n; i++) { 186 CFStringRef member; 187 188 member = CFArrayGetValueAtIndex(interfaces, i); 189 if (isA_CFString(member)) { 190 add_interface(&members, member, myContext->ni_prefs); 191 } 192 } 193 if (members != NULL) { 194 __SCBridgeInterfaceSetMemberInterfaces(bridge, members); 195 CFRelease(members); 196 } 197 198 // set options 199 bridge_options = CFDictionaryGetValue(bridge_info, kSCPropVirtualNetworkInterfacesBridgeOptions); 200 if (isA_CFDictionary(bridge_options)) { 201 SCBridgeInterfaceSetOptions(bridge, bridge_options); 202 name_auto = CFDictionaryGetValue(bridge_options, CFSTR("__AUTO__")); 203 } 204 205 // set display name 206 name = CFDictionaryGetValue(bridge_info, kSCPropUserDefinedName); 207 if (isA_CFString(name)) { 208 SCBridgeInterfaceSetLocalizedDisplayName(bridge, name); 209 } else if (isA_CFString(name_auto)) { 210 interfacePrivate->localized_key = name_auto; 211 if (interfacePrivate->localized_arg1 != NULL) { 212 CFRelease(interfacePrivate->localized_arg1); 213 interfacePrivate->localized_arg1 = NULL; 214 } 215 } 216 217 CFArrayAppendValue(myContext->bridges, bridge); 218 CFRelease(bridge); 219 220 return; 221} 222 223 224#pragma mark - 225#pragma mark SCBridgeInterface APIs 226 227 228static __inline__ void 229my_CFDictionaryApplyFunction(CFDictionaryRef theDict, 230 CFDictionaryApplierFunction applier, 231 void *context) 232{ 233 CFAllocatorRef myAllocator; 234 CFDictionaryRef myDict; 235 236 myAllocator = CFGetAllocator(theDict); 237 myDict = CFDictionaryCreateCopy(myAllocator, theDict); 238 CFDictionaryApplyFunction(myDict, applier, context); 239 CFRelease(myDict); 240 return; 241} 242 243 244CFArrayRef 245SCBridgeInterfaceCopyAll(SCPreferencesRef prefs) 246{ 247 addContext context; 248 CFDictionaryRef dict; 249 SCPreferencesRef ni_prefs; 250 CFStringRef path; 251 252 if ((prefs == NULL) || 253 (__SCPreferencesUsingDefaultPrefs(prefs) == TRUE)) { 254 ni_prefs = NULL; 255 } 256 else { 257 ni_prefs = __SCPreferencesCreateNIPrefsFromPrefs(prefs); 258 } 259 context.bridges = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 260 context.prefs = prefs; 261 context.ni_prefs = ni_prefs; 262 263 path = CFStringCreateWithFormat(NULL, 264 NULL, 265 CFSTR("/%@/%@"), 266 kSCPrefVirtualNetworkInterfaces, 267 kSCNetworkInterfaceTypeBridge); 268 dict = SCPreferencesPathGetValue(prefs, path); 269 if (isA_CFDictionary(dict)) { 270 my_CFDictionaryApplyFunction(dict, add_configured_interface, &context); 271 } 272 CFRelease(path); 273 if (ni_prefs != NULL) { 274 CFRelease(ni_prefs); 275 } 276 return context.bridges; 277} 278 279 280__private_extern__ void 281__SCBridgeInterfaceListCollectMembers(CFArrayRef interfaces, CFMutableSetRef set) 282{ 283 CFIndex i; 284 CFIndex n; 285 286 n = CFArrayGetCount(interfaces); 287 for (i = 0; i < n; i++) { 288 SCBridgeInterfaceRef bridgeInterface; 289 CFArrayRef members; 290 291 bridgeInterface = CFArrayGetValueAtIndex(interfaces, i); 292 members = SCBridgeInterfaceGetMemberInterfaces(bridgeInterface); 293 if (members != NULL) { 294 CFIndex j; 295 CFIndex n_members; 296 297 // exclude the member interfaces of this bridge 298 n_members = CFArrayGetCount(members); 299 for (j = 0; j < n_members; j++) { 300 SCNetworkInterfaceRef member; 301 302 member = CFArrayGetValueAtIndex(members, j); 303 CFSetAddValue(set, member); 304 } 305 } 306 307 } 308 return; 309} 310 311 312CFArrayRef /* of SCNetworkInterfaceRef's */ 313SCBridgeInterfaceCopyAvailableMemberInterfaces(SCPreferencesRef prefs) 314{ 315 CFMutableArrayRef available; 316 CFMutableSetRef excluded; 317 CFArrayRef interfaces; 318 319 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 320 excluded = CFSetCreateMutable (NULL, 0, &kCFTypeSetCallBacks); 321 322#if !TARGET_OS_IPHONE 323 // exclude Bond [member] interfaces 324 interfaces = SCBondInterfaceCopyAll(prefs); 325 if (interfaces != NULL) { 326 __SCBondInterfaceListCollectMembers(interfaces, excluded); 327 CFRelease(interfaces); 328 } 329#endif // !TARGET_OS_IPHONE 330 331 // exclude Bridge [member] interfaces 332 interfaces = SCBridgeInterfaceCopyAll(prefs); 333 if (interfaces != NULL) { 334 __SCBridgeInterfaceListCollectMembers(interfaces, excluded); 335 CFRelease(interfaces); 336 } 337 338 // exclude VLAN [physical] interfaces 339 interfaces = SCVLANInterfaceCopyAll(prefs); 340 if (interfaces != NULL) { 341 CFIndex i; 342 CFIndex n; 343 344 n = CFArrayGetCount(interfaces); 345 for (i = 0; i < n; i++) { 346 SCVLANInterfaceRef vlanInterface; 347 SCNetworkInterfaceRef physical; 348 349 // exclude the physical interface of this VLAN 350 vlanInterface = CFArrayGetValueAtIndex(interfaces, i); 351 physical = SCVLANInterfaceGetPhysicalInterface(vlanInterface); 352 CFSetAddValue(excluded, physical); 353 } 354 CFRelease(interfaces); 355 } 356 357 // identify available interfaces 358 interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(); 359 if (interfaces != NULL) { 360 CFIndex i; 361 CFIndex n; 362 363 n = CFArrayGetCount(interfaces); 364 for (i = 0; i < n; i++) { 365 SCNetworkInterfaceRef interface; 366 SCNetworkInterfacePrivateRef interfacePrivate; 367 368 interface = CFArrayGetValueAtIndex(interfaces, i); 369 interfacePrivate = (SCNetworkInterfacePrivateRef)interface; 370 371 if (!interfacePrivate->supportsBridge) { 372 // if this interface is not available 373 continue; 374 } 375 376 if (CFSetContainsValue(excluded, interface)) { 377 // if excluded 378 continue; 379 } 380 381 CFArrayAppendValue(available, interface); 382 } 383 CFRelease(interfaces); 384 } 385 386 CFRelease(excluded); 387 388 return available; 389} 390 391 392CFArrayRef 393_SCBridgeInterfaceCopyActive(void) 394{ 395 struct ifaddrs *ifap; 396 struct ifaddrs *ifp; 397 int s; 398 CFMutableArrayRef bridges = NULL; 399 400 if (getifaddrs(&ifap) == -1) { 401 _SCErrorSet(errno); 402 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno)); 403 return NULL; 404 } 405 406 s = inet_dgram_socket(); 407 if (s == -1) { 408 _SCErrorSet(errno); 409 goto done; 410 } 411 412 bridges = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 413 414 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) { 415#ifdef IFT_BRIDGE 416 SCBridgeInterfaceRef bridge; 417 CFStringRef bridge_if; 418 struct ifbifconf *ibc_p; 419 struct if_data *if_data; 420 CFMutableArrayRef members = NULL; 421 size_t n; 422 423 if_data = (struct if_data *)ifp->ifa_data; 424 if (if_data == NULL 425 || ifp->ifa_addr->sa_family != AF_LINK 426 || if_data->ifi_type != IFT_BRIDGE) { 427 continue; 428 } 429 430 // make sure that we leave non-SC configured bridge 431 // interfaces (those with unit #'s >= 100) alone. 432 n = strlen(ifp->ifa_name); 433 if ((n > 3) && 434 isdigit(ifp->ifa_name[n - 1]) && 435 isdigit(ifp->ifa_name[n - 2]) && 436 isdigit(ifp->ifa_name[n - 3])) { 437 // if not SC managed bridge interface 438 continue; 439 } 440 441 ibc_p = ifbifconf_copy(s, ifp->ifa_name); 442 if (ibc_p == NULL) { 443 if (errno == EBUSY) { 444 continue; 445 } 446 _SCErrorSet(errno); 447 SCLog(TRUE, LOG_ERR, 448 CFSTR("ifbifconf_copy(%s) failed: %s"), 449 ifp->ifa_name, 450 strerror(errno)); 451 CFRelease(bridges); 452 bridges = NULL; 453 goto done; 454 } 455 456 // create the bridge interface 457 bridge_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII); 458 bridge = (SCBridgeInterfaceRef)_SCBridgeInterfaceCreatePrivate(NULL, bridge_if); 459 CFRelease(bridge_if); 460 461 // add member interfaces 462 if (ibc_p->ifbic_len > 0) { 463 int i; 464 465 // iterate over each member interface 466 for (i = 0; i < ibc_p->ifbic_len / sizeof(struct ifbreq); i++) { 467 struct ifbreq *ibr_p; 468 CFStringRef member; 469 470 ibr_p = ibc_p->ifbic_req + i; 471 member = CFStringCreateWithCString(NULL, ibr_p->ifbr_ifsname, kCFStringEncodingASCII); 472 add_interface(&members, member, NULL); 473 CFRelease(member); 474 } 475 } 476 free(ibc_p); 477 478 if (members != NULL) { 479 __SCBridgeInterfaceSetMemberInterfaces(bridge, members); 480 CFRelease(members); 481 } 482 483 // add bridge 484 CFArrayAppendValue(bridges, bridge); 485 CFRelease(bridge); 486#endif // IFT_BRIDGE 487 } 488 489 done : 490 491 if (s != -1) { 492 (void) close(s); 493 } 494 freeifaddrs(ifap); 495 return bridges; 496} 497 498 499SCBridgeInterfaceRef 500SCBridgeInterfaceCreate(SCPreferencesRef prefs) 501{ 502 CFAllocatorRef allocator; 503 SCBridgeInterfaceRef bridge = NULL; 504 CFIndex i; 505 506 if (prefs == NULL) { 507 _SCErrorSet(kSCStatusInvalidArgument); 508 return NULL; 509 } 510 511 allocator = CFGetAllocator(prefs); 512 513 // create a new bridge using an unused interface name 514 for (i = 0; bridge == NULL; i++) { 515 CFDictionaryRef dict; 516 CFStringRef bridge_if; 517 SCNetworkInterfacePrivateRef interfacePrivate; 518 CFMutableDictionaryRef newDict; 519 CFArrayRef newInterfaces; 520 Boolean ok; 521 CFStringRef path; 522 523 bridge_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("bridge%ld"), i); 524 path = CFStringCreateWithFormat(allocator, 525 NULL, 526 CFSTR("/%@/%@/%@"), 527 kSCPrefVirtualNetworkInterfaces, 528 kSCNetworkInterfaceTypeBridge, 529 bridge_if); 530 dict = SCPreferencesPathGetValue(prefs, path); 531 if (dict != NULL) { 532 // if bridge interface name not available 533 CFRelease(path); 534 CFRelease(bridge_if); 535 continue; 536 } 537 538 // add the bridge to the stored preferences 539 newDict = CFDictionaryCreateMutable(allocator, 540 0, 541 &kCFTypeDictionaryKeyCallBacks, 542 &kCFTypeDictionaryValueCallBacks); 543 newInterfaces = CFArrayCreate(allocator, NULL, 0, &kCFTypeArrayCallBacks); 544 CFDictionaryAddValue(newDict, kSCPropVirtualNetworkInterfacesBridgeInterfaces, newInterfaces); 545 CFRelease(newInterfaces); 546 ok = SCPreferencesPathSetValue(prefs, path, newDict); 547 CFRelease(newDict); 548 CFRelease(path); 549 if (!ok) { 550 // if the bridge could not be saved 551 CFRelease(bridge_if); 552 break; 553 } 554 555 // create the SCBridgeInterfaceRef 556 bridge = (SCBridgeInterfaceRef)_SCBridgeInterfaceCreatePrivate(allocator, bridge_if); 557 CFRelease(bridge_if); 558 559 // estabish link to the stored configuration 560 interfacePrivate = (SCNetworkInterfacePrivateRef)bridge; 561 interfacePrivate->prefs = CFRetain(prefs); 562 } 563 564 return bridge; 565} 566 567 568Boolean 569SCBridgeInterfaceRemove(SCBridgeInterfaceRef bridge) 570{ 571 CFStringRef bridge_if; 572 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge; 573 Boolean ok; 574 CFStringRef path; 575 576 if (!isA_SCBridgeInterface(bridge)) { 577 _SCErrorSet(kSCStatusInvalidArgument); 578 return FALSE; 579 } 580 581 if (interfacePrivate->prefs == NULL) { 582 _SCErrorSet(kSCStatusInvalidArgument); 583 return FALSE; 584 } 585 586 bridge_if = SCNetworkInterfaceGetBSDName(bridge); 587 path = CFStringCreateWithFormat(NULL, 588 NULL, 589 CFSTR("/%@/%@/%@"), 590 kSCPrefVirtualNetworkInterfaces, 591 kSCNetworkInterfaceTypeBridge, 592 bridge_if); 593 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path); 594 CFRelease(path); 595 596 return ok; 597} 598 599 600CFArrayRef 601SCBridgeInterfaceGetMemberInterfaces(SCBridgeInterfaceRef bridge) 602{ 603 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge; 604 605 if (!isA_SCBridgeInterface(bridge)) { 606 _SCErrorSet(kSCStatusInvalidArgument); 607 return NULL; 608 } 609 610 return interfacePrivate->bridge.interfaces; 611} 612 613 614CFDictionaryRef 615SCBridgeInterfaceGetOptions(SCBridgeInterfaceRef bridge) 616{ 617 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge; 618 619 if (!isA_SCBridgeInterface(bridge)) { 620 _SCErrorSet(kSCStatusInvalidArgument); 621 return NULL; 622 } 623 624 return interfacePrivate->bridge.options; 625} 626 627 628__private_extern__ 629Boolean 630__SCBridgeInterfaceSetMemberInterfaces(SCBridgeInterfaceRef bridge, CFArrayRef members) 631{ 632 CFIndex i; 633 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge; 634 CFIndex n; 635 CFMutableArrayRef newMembers; 636 Boolean ok = TRUE; 637 638 n = (members != NULL) ? CFArrayGetCount(members) : 0; 639 640 // set member interfaces in the stored preferences 641 if (interfacePrivate->prefs != NULL) { 642 CFDictionaryRef dict; 643 CFMutableDictionaryRef newDict; 644 CFStringRef path; 645 646 path = CFStringCreateWithFormat(NULL, 647 NULL, 648 CFSTR("/%@/%@/%@"), 649 kSCPrefVirtualNetworkInterfaces, 650 kSCNetworkInterfaceTypeBridge, 651 interfacePrivate->entity_device); 652 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path); 653 if (!isA_CFDictionary(dict)) { 654 // if the prefs are confused 655 CFRelease(path); 656 _SCErrorSet(kSCStatusFailed); 657 return FALSE; 658 } 659 660 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 661 for (i = 0; i < n; i++) { 662 SCNetworkInterfaceRef interface; 663 CFStringRef memberName; 664 665 interface = CFArrayGetValueAtIndex(members, i); 666 memberName = SCNetworkInterfaceGetBSDName(interface); 667 CFArrayAppendValue(newMembers, memberName); 668 } 669 670 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 671 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBridgeInterfaces, newMembers); 672 CFRelease(newMembers); 673 if (!CFEqual(dict, newDict)) { 674 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict); 675 } 676 CFRelease(newDict); 677 CFRelease(path); 678 } 679 680 if (ok) { 681 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 682 for (i = 0; i < n; i++) { 683 SCNetworkInterfaceRef member; 684 SCNetworkInterfacePrivateRef newMember; 685 686 member = CFArrayGetValueAtIndex(members, i); 687 newMember = __SCNetworkInterfaceCreateCopy(NULL, 688 member, 689 interfacePrivate->prefs, 690 interfacePrivate->serviceID); 691 CFArrayAppendValue(newMembers, newMember); 692 CFRelease(newMember); 693 } 694 CFRelease(interfacePrivate->bridge.interfaces); 695 interfacePrivate->bridge.interfaces = newMembers; 696 } 697 698 return ok; 699} 700 701 702Boolean 703SCBridgeInterfaceSetMemberInterfaces(SCBridgeInterfaceRef bridge, CFArrayRef members) 704{ 705 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge; 706 Boolean ok; 707 int sc_status = kSCStatusOK; 708 709 if (!isA_SCBridgeInterface(bridge)) { 710 _SCErrorSet(kSCStatusInvalidArgument); 711 return FALSE; 712 } 713 714 if ((members != NULL) && !isA_CFArray(members)) { 715 _SCErrorSet(kSCStatusInvalidArgument); 716 return FALSE; 717 } 718 719 if (interfacePrivate->prefs != NULL) { 720 CFArrayRef available; 721 CFArrayRef current; 722 CFIndex i; 723 CFIndex n_available; 724 CFIndex n_current; 725 CFIndex n_members; 726 CFArrayRef services = NULL; 727 728 current = SCBridgeInterfaceGetMemberInterfaces(bridge); 729 n_current = (current != NULL) ? CFArrayGetCount(current) : 0; 730 731 available = SCBridgeInterfaceCopyAvailableMemberInterfaces(interfacePrivate->prefs); 732 n_available = (available != NULL) ? CFArrayGetCount(available) : 0; 733 734 n_members = (members != NULL) ? CFArrayGetCount(members) : 0; 735 for (i = 0; i < n_members; i++) { 736 SCNetworkInterfaceRef member; 737 738 member = CFArrayGetValueAtIndex(members, i); 739 740 if ((current != NULL) && 741 CFArrayContainsValue(current, CFRangeMake(0, n_current), member)) { 742 // current members are allowed 743 continue; 744 } 745 746 if ((available != NULL) && 747 CFArrayContainsValue(available, CFRangeMake(0, n_available), member)) { 748 // available members are allowed but cannot be associated 749 // with any other network services. 750 751 if (services == NULL) { 752 services = __SCNetworkServiceCopyAllEnabled(interfacePrivate->prefs); 753 } 754 if ((services != NULL) && 755 __SCNetworkServiceExistsForInterface(services, member)) { 756 sc_status = kSCStatusKeyExists; 757 break; 758 } 759 760 // if available 761 continue; 762 } 763 764 // if member not allowed 765 sc_status = kSCStatusInvalidArgument; 766 break; 767 } 768 769 if (available != NULL) CFRelease(available); 770 if (services != NULL) CFRelease(services); 771 } 772 773 if (sc_status != kSCStatusOK) { 774 _SCErrorSet(sc_status); 775 return FALSE; 776 } 777 778 ok = __SCBridgeInterfaceSetMemberInterfaces(bridge, members); 779 return ok; 780} 781 782 783Boolean 784SCBridgeInterfaceSetLocalizedDisplayName(SCBridgeInterfaceRef bridge, CFStringRef newName) 785{ 786 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge; 787 Boolean ok = TRUE; 788 789 if (!isA_SCBridgeInterface(bridge)) { 790 _SCErrorSet(kSCStatusInvalidArgument); 791 return FALSE; 792 } 793 794 if ((newName != NULL) && !isA_CFString(newName)) { 795 _SCErrorSet(kSCStatusInvalidArgument); 796 return FALSE; 797 } 798 799 // set name in the stored preferences 800 if (interfacePrivate->prefs != NULL) { 801 CFDictionaryRef dict; 802 CFMutableDictionaryRef newDict; 803 CFStringRef path; 804 805 path = CFStringCreateWithFormat(NULL, 806 NULL, 807 CFSTR("/%@/%@/%@"), 808 kSCPrefVirtualNetworkInterfaces, 809 kSCNetworkInterfaceTypeBridge, 810 interfacePrivate->entity_device); 811 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path); 812 if (!isA_CFDictionary(dict)) { 813 // if the prefs are confused 814 CFRelease(path); 815 _SCErrorSet(kSCStatusFailed); 816 return FALSE; 817 } 818 819 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 820 if (newName != NULL) { 821 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName); 822 } else { 823 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName); 824 } 825 if (!CFEqual(dict, newDict)) { 826 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict); 827 } 828 CFRelease(newDict); 829 CFRelease(path); 830 } 831 832 // set name in the SCBridgeInterfaceRef 833 if (ok) { 834 if (interfacePrivate->localized_name != NULL) { 835 CFRelease(interfacePrivate->localized_name); 836 interfacePrivate->localized_name = NULL; 837 } 838 if (newName != NULL) { 839 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName); 840 } 841 } 842 843 return ok; 844} 845 846 847Boolean 848SCBridgeInterfaceSetOptions(SCBridgeInterfaceRef bridge, CFDictionaryRef newOptions) 849{ 850 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge; 851 Boolean ok = TRUE; 852 853 if (!isA_SCBridgeInterface(bridge)) { 854 _SCErrorSet(kSCStatusInvalidArgument); 855 return FALSE; 856 } 857 858 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) { 859 _SCErrorSet(kSCStatusInvalidArgument); 860 return FALSE; 861 } 862 863 // set options in the stored preferences 864 if (interfacePrivate->prefs != NULL) { 865 CFDictionaryRef dict; 866 CFMutableDictionaryRef newDict; 867 CFStringRef path; 868 869 path = CFStringCreateWithFormat(NULL, 870 NULL, 871 CFSTR("/%@/%@/%@"), 872 kSCPrefVirtualNetworkInterfaces, 873 kSCNetworkInterfaceTypeBridge, 874 interfacePrivate->entity_device); 875 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path); 876 if (!isA_CFDictionary(dict)) { 877 // if the prefs are confused 878 CFRelease(path); 879 _SCErrorSet(kSCStatusFailed); 880 return FALSE; 881 } 882 883 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 884 if (newOptions != NULL) { 885 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBridgeOptions, newOptions); 886 } else { 887 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesBridgeOptions); 888 } 889 if (!CFEqual(dict, newDict)) { 890 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict); 891 } 892 CFRelease(newDict); 893 CFRelease(path); 894 } 895 896 // set options in the SCBridgeInterfaceRef 897 if (ok) { 898 if (interfacePrivate->bridge.options != NULL) { 899 CFRelease(interfacePrivate->bridge.options); 900 interfacePrivate->bridge.options = NULL; 901 } 902 if (newOptions != NULL) { 903 CFStringRef name_auto = NULL; 904 905 interfacePrivate->bridge.options = CFDictionaryCreateCopy(NULL, newOptions); 906 907 // set [auto] display name from options 908 if ((interfacePrivate->localized_name == NULL) && 909 CFDictionaryGetValueIfPresent(newOptions, 910 CFSTR("__AUTO__"), 911 (const void **)&name_auto) && 912 isA_CFString(name_auto)) { 913 // set display name 914 interfacePrivate->localized_key = name_auto; 915 if (interfacePrivate->localized_arg1 != NULL) { 916 CFRelease(interfacePrivate->localized_arg1); 917 interfacePrivate->localized_arg1 = NULL; 918 } 919 } 920 } 921 } 922 923 return ok; 924} 925 926 927#pragma mark - 928#pragma mark SCBridgeInterface management 929 930 931#ifdef IFT_BRIDGE 932static Boolean 933__bridge_add_interface(int s, CFStringRef bridge_if, CFStringRef interface_if) 934{ 935 struct ifbreq breq; 936 struct ifdrv ifd; 937 938 // bridge interface 939 bzero(&ifd, sizeof(ifd)); 940 (void) _SC_cfstring_to_cstring(bridge_if, 941 ifd.ifd_name, 942 sizeof(ifd.ifd_name), 943 kCFStringEncodingASCII); 944 ifd.ifd_cmd = BRDGADD; 945 ifd.ifd_len = sizeof(breq); 946 ifd.ifd_data = (caddr_t)&breq; 947 948 // new bridge member 949 bzero(&breq, sizeof(breq)); 950 (void) _SC_cfstring_to_cstring(interface_if, 951 breq.ifbr_ifsname, 952 sizeof(breq.ifbr_ifsname), 953 kCFStringEncodingASCII); 954 955 // add new bridge member 956 if (ioctl(s, SIOCSDRVSPEC, (caddr_t)&ifd) == -1) { 957 _SCErrorSet(errno); 958 SCLog(TRUE, LOG_ERR, 959 CFSTR("could not add interface \"%@\" to bridge \"%@\": %s"), 960 interface_if, 961 bridge_if, 962 strerror(errno)); 963 return FALSE; 964 } 965 966 return TRUE; 967} 968 969 970static Boolean 971__bridge_remove_interface(int s, CFStringRef bridge_if, CFStringRef interface_if) 972{ 973 struct ifbreq breq; 974 struct ifdrv ifd; 975 976 // bridge interface 977 bzero(&ifd, sizeof(ifd)); 978 (void) _SC_cfstring_to_cstring(bridge_if, 979 ifd.ifd_name, 980 sizeof(ifd.ifd_name), 981 kCFStringEncodingASCII); 982 ifd.ifd_cmd = BRDGDEL; 983 ifd.ifd_len = sizeof(breq); 984 ifd.ifd_data = (caddr_t)&breq; 985 986 // bridge member to remove 987 bzero(&breq, sizeof(breq)); 988 (void) _SC_cfstring_to_cstring(interface_if, 989 breq.ifbr_ifsname, 990 sizeof(breq.ifbr_ifsname), 991 kCFStringEncodingASCII); 992 993 // remove bridge member 994 if (ioctl(s, SIOCSDRVSPEC, (caddr_t)&ifd) == -1) { 995 _SCErrorSet(errno); 996 SCLog(TRUE, LOG_ERR, 997 CFSTR("could not add interface \"%@\" to bridge \"%@\": %s"), 998 interface_if, 999 bridge_if, 1000 strerror(errno)); 1001 return FALSE; 1002 } 1003 1004 return TRUE; 1005} 1006#endif // IFT_BRIDGE 1007 1008 1009Boolean 1010_SCBridgeInterfaceUpdateConfiguration(SCPreferencesRef prefs) 1011{ 1012#ifdef IFT_BRIDGE 1013 CFArrayRef active = NULL; 1014 CFArrayRef config = NULL; 1015 CFIndex i; 1016 CFIndex nActive; 1017 CFIndex nConfig; 1018 Boolean ok = TRUE; 1019 int s = -1; 1020 1021 if (prefs == NULL) { 1022 _SCErrorSet(kSCStatusInvalidArgument); 1023 return FALSE; 1024 } 1025 1026 /* configured Bridges */ 1027 config = SCBridgeInterfaceCopyAll(prefs); 1028 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0; 1029 1030 /* active Bridges */ 1031 active = _SCBridgeInterfaceCopyActive(); 1032 nActive = (active != NULL) ? CFArrayGetCount(active) : 0; 1033 1034 /* 1035 * remove any no-longer-configured bridge interfaces and 1036 * any devices associated with a bridge that are no longer 1037 * associated with a bridge. 1038 */ 1039 for (i = 0; i < nActive; i++) { 1040 SCBridgeInterfaceRef a_bridge; 1041 CFStringRef a_bridge_if; 1042 CFIndex j; 1043 Boolean found = FALSE; 1044 1045 a_bridge = CFArrayGetValueAtIndex(active, i); 1046 a_bridge_if = SCNetworkInterfaceGetBSDName(a_bridge); 1047 1048 for (j = 0; j < nConfig; j++) { 1049 SCBridgeInterfaceRef c_bridge; 1050 CFStringRef c_bridge_if; 1051 1052 c_bridge = CFArrayGetValueAtIndex(config, j); 1053 c_bridge_if = SCNetworkInterfaceGetBSDName(c_bridge); 1054 1055 if (CFEqual(a_bridge_if, c_bridge_if)) { 1056 CFIndex a; 1057 CFArrayRef a_bridge_interfaces; 1058 CFIndex a_count; 1059 CFArrayRef c_bridge_interfaces; 1060 CFIndex c_count; 1061 1062 c_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(c_bridge); 1063 c_count = (c_bridge_interfaces != NULL) ? CFArrayGetCount(c_bridge_interfaces) : 0; 1064 1065 a_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(a_bridge); 1066 a_count = (a_bridge_interfaces != NULL) ? CFArrayGetCount(a_bridge_interfaces) : 0; 1067 1068 for (a = 0; a < a_count; a++) { 1069 SCNetworkInterfaceRef a_interface; 1070 CFStringRef a_interface_if; 1071 1072 a_interface = CFArrayGetValueAtIndex(a_bridge_interfaces, a); 1073 if ((c_count == 0) || 1074 !CFArrayContainsValue(c_bridge_interfaces, 1075 CFRangeMake(0, c_count), 1076 a_interface)) { 1077 /* 1078 * if this device is no longer part 1079 * of the bridge. 1080 */ 1081 if (s == -1) { 1082 s = inet_dgram_socket(); 1083 if (s == -1) { 1084 _SCErrorSet(errno); 1085 ok = FALSE; 1086 goto done; 1087 } 1088 } 1089 1090 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface); 1091 if (!__bridge_remove_interface(s, a_bridge_if, a_interface_if)) { 1092 ok = FALSE; 1093 } 1094 } 1095 } 1096 1097 found = TRUE; 1098 break; 1099 } 1100 } 1101 1102 if (!found) { 1103 /* 1104 * if this interface is no longer configured 1105 */ 1106 if (s == -1) { 1107 s = inet_dgram_socket(); 1108 if (s == -1) { 1109 _SCErrorSet(errno); 1110 ok = FALSE; 1111 goto done; 1112 } 1113 } 1114 1115 if (!__destroyInterface(s, a_bridge_if)) { 1116 _SCErrorSet(errno); 1117 ok = FALSE; 1118 } 1119 } 1120 } 1121 1122 /* 1123 * add any newly-configured bridge interfaces and add any 1124 * devices that should now be associated with the bridge. 1125 */ 1126 for (i = 0; i < nConfig; i++) { 1127 SCBridgeInterfaceRef c_bridge; 1128 CFArrayRef c_bridge_interfaces; 1129 CFStringRef c_bridge_if; 1130 CFIndex c_count; 1131 Boolean found = FALSE; 1132 CFIndex j; 1133 1134 c_bridge = CFArrayGetValueAtIndex(config, i); 1135 c_bridge_if = SCNetworkInterfaceGetBSDName(c_bridge); 1136 c_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(c_bridge); 1137 c_count = (c_bridge_interfaces != NULL) ? CFArrayGetCount(c_bridge_interfaces) : 0; 1138 1139 for (j = 0; j < nActive; j++) { 1140 SCBridgeInterfaceRef a_bridge; 1141 CFArrayRef a_bridge_interfaces; 1142 CFStringRef a_bridge_if; 1143 CFIndex a_count; 1144 1145 a_bridge = CFArrayGetValueAtIndex(active, j); 1146 a_bridge_if = SCNetworkInterfaceGetBSDName(a_bridge); 1147 a_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(a_bridge); 1148 a_count = (a_bridge_interfaces != NULL) ? CFArrayGetCount(a_bridge_interfaces) : 0; 1149 1150 if (CFEqual(c_bridge_if, a_bridge_if)) { 1151 CFIndex c; 1152 Boolean if_list_change = FALSE; 1153 1154 found = TRUE; 1155 1156 if (!_SC_CFEqual(c_bridge_interfaces, a_bridge_interfaces)) { 1157 if_list_change = TRUE; 1158 } 1159 if (!if_list_change) { 1160 break; // if no change 1161 } 1162 if (s == -1) { 1163 s = inet_dgram_socket(); 1164 if (s == -1) { 1165 _SCErrorSet(errno); 1166 ok = FALSE; 1167 goto done; 1168 } 1169 } 1170 if (!if_list_change) { 1171 break; // no if list changes 1172 } 1173 1174 /* 1175 * ensure that the first device of the bridge matches, if 1176 * not then we remove all current devices and add them 1177 * back in the preferred order. 1178 */ 1179 if ((c_count > 0) && 1180 (a_count > 0) && 1181 !CFEqual(CFArrayGetValueAtIndex(c_bridge_interfaces, 0), 1182 CFArrayGetValueAtIndex(a_bridge_interfaces, 0))) { 1183 CFIndex a; 1184 1185 for (a = 0; a < a_count; a++) { 1186 SCNetworkInterfaceRef a_interface; 1187 CFStringRef a_interface_if; 1188 1189 a_interface = CFArrayGetValueAtIndex(a_bridge_interfaces, a); 1190 if (!CFArrayContainsValue(c_bridge_interfaces, 1191 CFRangeMake(0, c_count), 1192 a_interface)) { 1193 continue; // if already removed 1194 } 1195 1196 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface); 1197 if (!__bridge_remove_interface(s, a_bridge_if, a_interface_if)) { 1198 ok = FALSE; 1199 } 1200 } 1201 1202 a_count = 0; // all active devices have been removed 1203 } 1204 1205 /* 1206 * add any devices which are not currently associated 1207 * with the bridge interface. 1208 */ 1209 for (c = 0; c < c_count; c++) { 1210 SCNetworkInterfaceRef c_interface; 1211 SCNetworkInterfacePrivateRef c_interfacePrivate; 1212 CFStringRef c_interface_if; 1213 1214 c_interface = CFArrayGetValueAtIndex(c_bridge_interfaces, c); 1215 if ((a_count == 0) || 1216 !CFArrayContainsValue(a_bridge_interfaces, 1217 CFRangeMake(0, a_count), 1218 c_interface)) { 1219 /* 1220 * check if this member interface can be added to a bridge. 1221 */ 1222 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface; 1223 if (!c_interfacePrivate->supportsBridge) { 1224 // if member not supported 1225 continue; 1226 } 1227 1228 /* 1229 * if this member interface is not currently part of the bridge. 1230 */ 1231 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface); 1232 if (!__bridge_add_interface(s, c_bridge_if, c_interface_if)) { 1233 // if member could not be added 1234 ok = FALSE; 1235 } 1236 } 1237 } 1238 1239 break; 1240 } 1241 } 1242 1243 if (!found) { 1244 CFIndex c; 1245 1246 if (s == -1) { 1247 s = inet_dgram_socket(); 1248 if (s == -1) { 1249 _SCErrorSet(errno); 1250 ok = FALSE; 1251 goto done; 1252 } 1253 } 1254 1255 /* 1256 * establish the new bridge interface. 1257 */ 1258 if (!__createInterface(s, c_bridge_if)) { 1259 _SCErrorSet(errno); 1260 ok = FALSE; 1261 continue; 1262 } 1263 1264 /* 1265 * add the member interfaces 1266 */ 1267 for (c = 0; c < c_count; c++) { 1268 SCNetworkInterfaceRef c_interface; 1269 SCNetworkInterfacePrivateRef c_interfacePrivate; 1270 CFStringRef c_interface_if; 1271 1272 c_interface = CFArrayGetValueAtIndex(c_bridge_interfaces, c); 1273 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface; 1274 if (!c_interfacePrivate->supportsBridge) { 1275 // if member not supported 1276 continue; 1277 } 1278 1279 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface); 1280 if (!__bridge_add_interface(s, c_bridge_if, c_interface_if)) { 1281 // if member could not be added 1282 ok = FALSE; 1283 } 1284 } 1285 } 1286 1287 } 1288 1289 done : 1290 1291 if (active != NULL) CFRelease(active); 1292 if (config != NULL) CFRelease(config); 1293 if (s != -1) (void) close(s); 1294 1295 return ok; 1296#else // IFT_BRIDGE 1297 return TRUE; 1298#endif // IFT_BRIDGE 1299} 1300