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