1/* 2 * Copyright (c) 2004-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 * November 28, 2005 Allan Nathanson <ajn@apple.com> 28 * - public API 29 * 30 * July 22, 2004 Allan Nathanson <ajn@apple.com> 31 * - initial revision 32 */ 33 34 35#include <CoreFoundation/CoreFoundation.h> 36#include <CoreFoundation/CFRuntime.h> 37 38#include <SystemConfiguration/SystemConfiguration.h> 39#include "SCNetworkConfigurationInternal.h" 40#include "SCPreferencesInternal.h" 41#include <SystemConfiguration/SCValidation.h> 42#include <SystemConfiguration/SCPrivate.h> 43 44#include <ifaddrs.h> 45#include <pthread.h> 46#include <unistd.h> 47#include <sys/types.h> 48#include <sys/ioctl.h> 49#include <sys/socket.h> 50#include <sys/sysctl.h> 51#include <net/ethernet.h> 52#define KERNEL_PRIVATE 53#include <net/if.h> 54#include <net/if_var.h> 55#undef KERNEL_PRIVATE 56#include <net/if_bond_var.h> 57#include <net/if_types.h> 58#include <net/if_media.h> 59#include <net/route.h> 60 61/* ---------- Bond 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 76static int 77siocgifmedia(int s, const char * ifname, int * status, int * active) 78{ 79 struct ifmediareq ifmr; 80 81 *status = 0; 82 *active = 0; 83 bzero(&ifmr, sizeof(ifmr)); 84 strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 85 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) { 86 return (-1); 87 } 88 if (ifmr.ifm_count != 0) { 89 *status = ifmr.ifm_status; 90 *active = ifmr.ifm_active; 91 } 92 return (0); 93} 94 95static struct if_bond_status_req * 96if_bond_status_req_copy(int s, const char * ifname) 97{ 98 void * buf = NULL; 99 struct if_bond_req ibr; 100 struct if_bond_status_req * ibsr_p; 101 struct ifreq ifr; 102 103 bzero(&ifr, sizeof(ifr)); 104 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 105 bzero((char *)&ibr, sizeof(ibr)); 106 ibr.ibr_op = IF_BOND_OP_GET_STATUS; 107 ibsr_p = &ibr.ibr_ibru.ibru_status; 108 ibsr_p->ibsr_version = IF_BOND_STATUS_REQ_VERSION; 109 ifr.ifr_data = (caddr_t)&ibr; 110 111 /* how many of them are there? */ 112 if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) == -1) { 113 goto failed; 114 } 115 buf = malloc(sizeof(struct if_bond_status) * ibsr_p->ibsr_total + sizeof(*ibsr_p)); 116 if (buf == NULL) { 117 goto failed; 118 } 119 if (ibsr_p->ibsr_total == 0) { 120 goto done; 121 } 122 ibsr_p->ibsr_count = ibsr_p->ibsr_total; 123 ibsr_p->ibsr_buffer = buf + sizeof(*ibsr_p); 124 125 /* get the list */ 126 if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) == -1) { 127 goto failed; 128 } 129 done: 130 (*(struct if_bond_status_req *)buf) = *ibsr_p; 131 return ((struct if_bond_status_req *)buf); 132 133 failed: 134 if (buf != NULL) { 135 free(buf); 136 } 137 return (NULL); 138} 139 140 141static void 142add_interface(CFMutableArrayRef *interfaces, CFStringRef if_name, SCPreferencesRef ni_prefs) 143{ 144 SCNetworkInterfaceRef interface = NULL; 145 146 if (*interfaces == NULL) { 147 *interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 148 } 149 if (ni_prefs != NULL) { 150 interface = __SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(NULL, ni_prefs, if_name); 151 } 152 if (interface == NULL) { 153 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, if_name, 154 kIncludeNoVirtualInterfaces); 155 } 156 157 if (interface != NULL) { 158 CFArrayAppendValue(*interfaces, interface); 159 CFRelease(interface); 160 } 161} 162 163 164static Boolean 165_SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode); 166 167 168typedef struct { 169 CFMutableArrayRef bonds; 170 SCPreferencesRef ni_prefs; 171 SCPreferencesRef prefs; 172} addContext, *addContextRef; 173 174 175static void 176add_configured_interface(const void *key, const void *value, void *context) 177{ 178 SCBondInterfaceRef bond; 179 CFStringRef bond_if = (CFStringRef)key; 180 CFDictionaryRef bond_info = (CFDictionaryRef)value; 181 CFDictionaryRef bond_options; 182 CFIndex i; 183 CFArrayRef interfaces; 184 SCNetworkInterfacePrivateRef interfacePrivate; 185 CFMutableArrayRef members = NULL; 186 CFNumberRef mode; 187 addContextRef myContext = (addContextRef)context; 188 CFStringRef name; 189 CFIndex n; 190 191 // create the bond interface 192 bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(NULL, bond_if); 193 194 // add member interfaces 195 interfaces = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondInterfaces); 196 n = isA_CFArray(interfaces) ? CFArrayGetCount(interfaces) : 0; 197 for (i = 0; i < n; i++) { 198 CFStringRef member; 199 200 member = CFArrayGetValueAtIndex(interfaces, i); 201 if (isA_CFString(member)) { 202 add_interface(&members, member, myContext->ni_prefs); 203 } 204 } 205 if (members != NULL) { 206 __SCBondInterfaceSetMemberInterfaces(bond, members); 207 CFRelease(members); 208 } 209 210 // set display name 211 name = CFDictionaryGetValue(bond_info, kSCPropUserDefinedName); 212 if (isA_CFString(name)) { 213 SCBondInterfaceSetLocalizedDisplayName(bond, name); 214 } 215 216 // set options 217 bond_options = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondOptions); 218 if (isA_CFDictionary(bond_options)) { 219 SCBondInterfaceSetOptions(bond, bond_options); 220 } 221 222 // set the mode 223 mode = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondMode); 224 _SCBondInterfaceSetMode(bond, isA_CFNumber(mode)); 225 226 // estabish link to the stored configuration 227 interfacePrivate = (SCNetworkInterfacePrivateRef)bond; 228 interfacePrivate->prefs = CFRetain(myContext->prefs); 229 230 CFArrayAppendValue(myContext->bonds, bond); 231 CFRelease(bond); 232 233 return; 234} 235 236 237 238#pragma mark - 239#pragma mark SCBondInterface APIs 240 241 242static __inline__ void 243my_CFDictionaryApplyFunction(CFDictionaryRef theDict, 244 CFDictionaryApplierFunction applier, 245 void *context) 246{ 247 CFAllocatorRef myAllocator; 248 CFDictionaryRef myDict; 249 250 myAllocator = CFGetAllocator(theDict); 251 myDict = CFDictionaryCreateCopy(myAllocator, theDict); 252 CFDictionaryApplyFunction(myDict, applier, context); 253 CFRelease(myDict); 254 return; 255} 256 257 258CFArrayRef 259SCBondInterfaceCopyAll(SCPreferencesRef prefs) 260{ 261 addContext context; 262 CFDictionaryRef dict; 263 SCPreferencesRef ni_prefs; 264 CFStringRef path; 265 266 if ((prefs == NULL) || 267 (__SCPreferencesUsingDefaultPrefs(prefs) == TRUE)) { 268 ni_prefs = NULL; 269 } 270 else { 271 ni_prefs = __SCPreferencesCreateNIPrefsFromPrefs(prefs); 272 } 273 274 context.bonds = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 275 context.prefs = prefs; 276 context.ni_prefs = ni_prefs; 277 278 path = CFStringCreateWithFormat(NULL, 279 NULL, 280 CFSTR("/%@/%@"), 281 kSCPrefVirtualNetworkInterfaces, 282 kSCNetworkInterfaceTypeBond); 283 dict = SCPreferencesPathGetValue(prefs, path); 284 CFRelease(path); 285 if (isA_CFDictionary(dict)) { 286 my_CFDictionaryApplyFunction(dict, add_configured_interface, &context); 287 } 288 289 if (ni_prefs != NULL) { 290 CFRelease(ni_prefs); 291 } 292 return context.bonds; 293} 294 295 296__private_extern__ void 297__SCBondInterfaceListCollectMembers(CFArrayRef interfaces, CFMutableSetRef set) 298{ 299 CFIndex i; 300 CFIndex n; 301 302 n = CFArrayGetCount(interfaces); 303 for (i = 0; i < n; i++) { 304 SCBondInterfaceRef bondInterface; 305 CFArrayRef members; 306 307 bondInterface = CFArrayGetValueAtIndex(interfaces, i); 308 members = SCBondInterfaceGetMemberInterfaces(bondInterface); 309 if (members != NULL) { 310 CFIndex j; 311 CFIndex n_members; 312 313 // exclude the member interfaces of this bond 314 n_members = CFArrayGetCount(members); 315 for (j = 0; j < n_members; j++) { 316 SCNetworkInterfaceRef member; 317 318 member = CFArrayGetValueAtIndex(members, j); 319 CFSetAddValue(set, member); 320 } 321 } 322 323 } 324 return; 325} 326 327 328CFArrayRef /* of SCNetworkInterfaceRef's */ 329SCBondInterfaceCopyAvailableMemberInterfaces(SCPreferencesRef prefs) 330{ 331 CFMutableArrayRef available; 332 CFMutableSetRef excluded; 333 CFArrayRef interfaces; 334 335 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 336 excluded = CFSetCreateMutable (NULL, 0, &kCFTypeSetCallBacks); 337 338 // exclude Bond [member] interfaces 339 interfaces = SCBondInterfaceCopyAll(prefs); 340 if (interfaces != NULL) { 341 __SCBondInterfaceListCollectMembers(interfaces, excluded); 342 CFRelease(interfaces); 343 } 344 345 // exclude Bridge [member] interfaces 346 interfaces = SCBridgeInterfaceCopyAll(prefs); 347 if (interfaces != NULL) { 348 __SCBridgeInterfaceListCollectMembers(interfaces, excluded); 349 CFRelease(interfaces); 350 } 351 352 // exclude VLAN [physical] interfaces 353 interfaces = SCVLANInterfaceCopyAll(prefs); 354 if (interfaces != NULL) { 355 CFIndex i; 356 CFIndex n; 357 358 n = CFArrayGetCount(interfaces); 359 for (i = 0; i < n; i++) { 360 SCVLANInterfaceRef vlanInterface; 361 SCNetworkInterfaceRef physical; 362 363 // exclude the physical interface of this VLAN 364 vlanInterface = CFArrayGetValueAtIndex(interfaces, i); 365 physical = SCVLANInterfaceGetPhysicalInterface(vlanInterface); 366 CFSetAddValue(excluded, physical); 367 } 368 CFRelease(interfaces); 369 } 370 371 // identify available interfaces 372 interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(); 373 if (interfaces != NULL) { 374 CFIndex i; 375 CFIndex n; 376 377 n = CFArrayGetCount(interfaces); 378 for (i = 0; i < n; i++) { 379 SCNetworkInterfaceRef interface; 380 SCNetworkInterfacePrivateRef interfacePrivate; 381 382 interface = CFArrayGetValueAtIndex(interfaces, i); 383 interfacePrivate = (SCNetworkInterfacePrivateRef)interface; 384 385 if (!interfacePrivate->supportsBond) { 386 // if this interface is not available 387 continue; 388 } 389 390 if (CFSetContainsValue(excluded, interface)) { 391 // if excluded 392 continue; 393 } 394 395 CFArrayAppendValue(available, interface); 396 } 397 CFRelease(interfaces); 398 } 399 400 CFRelease(excluded); 401 402 return available; 403} 404 405 406CFArrayRef 407_SCBondInterfaceCopyActive(void) 408{ 409 struct ifaddrs *ifap; 410 struct ifaddrs *ifp; 411 int s; 412 CFMutableArrayRef bonds = NULL; 413 414 if (getifaddrs(&ifap) == -1) { 415 _SCErrorSet(errno); 416 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno)); 417 return NULL; 418 } 419 420 s = inet_dgram_socket(); 421 if (s == -1) { 422 _SCErrorSet(errno); 423 goto done; 424 } 425 426 bonds = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 427 428 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) { 429 SCBondInterfaceRef bond; 430 CFStringRef bond_if; 431 struct if_bond_status_req *ibsr_p; 432 struct if_data *if_data; 433 int int_val; 434 CFNumberRef mode; 435 CFMutableArrayRef members = NULL; 436 437 if_data = (struct if_data *)ifp->ifa_data; 438 if (if_data == NULL 439 || ifp->ifa_addr->sa_family != AF_LINK 440 || if_data->ifi_type != IFT_IEEE8023ADLAG) { 441 continue; 442 } 443 444 ibsr_p = if_bond_status_req_copy(s, ifp->ifa_name); 445 if (ibsr_p == NULL) { 446 if (errno == EBUSY) { 447 continue; 448 } 449 _SCErrorSet(errno); 450 SCLog(TRUE, LOG_ERR, 451 CFSTR("if_bond_status_req_copy(%s) failed: %s"), 452 ifp->ifa_name, 453 strerror(errno)); 454 CFRelease(bonds); 455 bonds = NULL; 456 goto done; 457 } 458 459 // create the bond interface 460 bond_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII); 461 bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(NULL, bond_if); 462 CFRelease(bond_if); 463 464 // set the mode 465 int_val = ibsr_p->ibsr_mode; 466 mode = CFNumberCreate(NULL, kCFNumberIntType, &int_val); 467 assert(mode != NULL); 468 _SCBondInterfaceSetMode(bond, mode); 469 CFRelease(mode); 470 471 // add member interfaces 472 if (ibsr_p->ibsr_total > 0) { 473 int i; 474 struct if_bond_status * ibs_p; 475 476 // iterate over each member interface 477 ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer; 478 for (i = 0; i < ibsr_p->ibsr_total; i++) { 479 CFStringRef member; 480 481 member = CFStringCreateWithCString(NULL, ibs_p[i].ibs_if_name, kCFStringEncodingASCII); 482 add_interface(&members, member, NULL); 483 CFRelease(member); 484 } 485 } 486 free(ibsr_p); 487 488 if (members != NULL) { 489 __SCBondInterfaceSetMemberInterfaces(bond, members); 490 CFRelease(members); 491 } 492 493 // add bond 494 CFArrayAppendValue(bonds, bond); 495 CFRelease(bond); 496 } 497 498 done : 499 500 if (s != -1) { 501 (void) close(s); 502 } 503 freeifaddrs(ifap); 504 return bonds; 505} 506 507 508SCBondInterfaceRef 509SCBondInterfaceCreate(SCPreferencesRef prefs) 510{ 511 CFAllocatorRef allocator; 512 SCBondInterfaceRef bond = NULL; 513 CFIndex i; 514 515 if (prefs == NULL) { 516 _SCErrorSet(kSCStatusInvalidArgument); 517 return NULL; 518 } 519 520 allocator = CFGetAllocator(prefs); 521 522 // create a new bond using an unused interface name 523 for (i = 0; bond == NULL; i++) { 524 CFDictionaryRef dict; 525 CFStringRef bond_if; 526 SCNetworkInterfacePrivateRef interfacePrivate; 527 CFMutableDictionaryRef newDict; 528 CFArrayRef newInterfaces; 529 Boolean ok; 530 CFStringRef path; 531 532 bond_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("bond%ld"), i); 533 path = CFStringCreateWithFormat(allocator, 534 NULL, 535 CFSTR("/%@/%@/%@"), 536 kSCPrefVirtualNetworkInterfaces, 537 kSCNetworkInterfaceTypeBond, 538 bond_if); 539 dict = SCPreferencesPathGetValue(prefs, path); 540 if (dict != NULL) { 541 // if bond interface name not available 542 CFRelease(path); 543 CFRelease(bond_if); 544 continue; 545 } 546 547 // add the bond to the stored preferences 548 newDict = CFDictionaryCreateMutable(allocator, 549 0, 550 &kCFTypeDictionaryKeyCallBacks, 551 &kCFTypeDictionaryValueCallBacks); 552 newInterfaces = CFArrayCreate(allocator, NULL, 0, &kCFTypeArrayCallBacks); 553 CFDictionaryAddValue(newDict, kSCPropVirtualNetworkInterfacesBondInterfaces, newInterfaces); 554 CFRelease(newInterfaces); 555 ok = SCPreferencesPathSetValue(prefs, path, newDict); 556 CFRelease(newDict); 557 CFRelease(path); 558 if (!ok) { 559 // if the bond could not be saved 560 CFRelease(bond_if); 561 break; 562 } 563 564 // create the SCBondInterfaceRef 565 bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(allocator, bond_if); 566 CFRelease(bond_if); 567 568 // estabish link to the stored configuration 569 interfacePrivate = (SCNetworkInterfacePrivateRef)bond; 570 interfacePrivate->prefs = CFRetain(prefs); 571 } 572 573 return bond; 574} 575 576 577Boolean 578SCBondInterfaceRemove(SCBondInterfaceRef bond) 579{ 580 CFStringRef bond_if; 581 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond; 582 Boolean ok; 583 CFStringRef path; 584 585 if (!isA_SCBondInterface(bond)) { 586 _SCErrorSet(kSCStatusInvalidArgument); 587 return FALSE; 588 } 589 590 if (interfacePrivate->prefs == NULL) { 591 _SCErrorSet(kSCStatusInvalidArgument); 592 return FALSE; 593 } 594 595 bond_if = SCNetworkInterfaceGetBSDName(bond); 596 path = CFStringCreateWithFormat(NULL, 597 NULL, 598 CFSTR("/%@/%@/%@"), 599 kSCPrefVirtualNetworkInterfaces, 600 kSCNetworkInterfaceTypeBond, 601 bond_if); 602 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path); 603 CFRelease(path); 604 605 return ok; 606} 607 608 609CFArrayRef 610SCBondInterfaceGetMemberInterfaces(SCBondInterfaceRef bond) 611{ 612 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond; 613 614 if (!isA_SCBondInterface(bond)) { 615 _SCErrorSet(kSCStatusInvalidArgument); 616 return NULL; 617 } 618 619 return interfacePrivate->bond.interfaces; 620} 621 622 623CFDictionaryRef 624SCBondInterfaceGetOptions(SCBondInterfaceRef bond) 625{ 626 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond; 627 628 if (!isA_SCBondInterface(bond)) { 629 _SCErrorSet(kSCStatusInvalidArgument); 630 return NULL; 631 } 632 633 return interfacePrivate->bond.options; 634} 635 636 637__private_extern__ 638Boolean 639__SCBondInterfaceSetMemberInterfaces(SCBondInterfaceRef bond, CFArrayRef members) 640{ 641 CFIndex i; 642 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond; 643 CFIndex n; 644 CFMutableArrayRef newMembers; 645 Boolean ok = TRUE; 646 647 n = (members != NULL) ? CFArrayGetCount(members) : 0; 648 649 // set member interfaces in the stored preferences 650 if (interfacePrivate->prefs != NULL) { 651 CFDictionaryRef dict; 652 CFMutableDictionaryRef newDict; 653 CFStringRef path; 654 655 path = CFStringCreateWithFormat(NULL, 656 NULL, 657 CFSTR("/%@/%@/%@"), 658 kSCPrefVirtualNetworkInterfaces, 659 kSCNetworkInterfaceTypeBond, 660 interfacePrivate->entity_device); 661 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path); 662 if (!isA_CFDictionary(dict)) { 663 // if the prefs are confused 664 CFRelease(path); 665 _SCErrorSet(kSCStatusFailed); 666 return FALSE; 667 } 668 669 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 670 for (i = 0; i < n; i++) { 671 SCNetworkInterfaceRef interface; 672 CFStringRef memberName; 673 674 interface = CFArrayGetValueAtIndex(members, i); 675 memberName = SCNetworkInterfaceGetBSDName(interface); 676 CFArrayAppendValue(newMembers, memberName); 677 } 678 679 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 680 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBondInterfaces, newMembers); 681 CFRelease(newMembers); 682 if (!CFEqual(dict, newDict)) { 683 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict); 684 } 685 CFRelease(newDict); 686 CFRelease(path); 687 } 688 689 if (ok) { 690 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 691 for (i = 0; i < n; i++) { 692 SCNetworkInterfaceRef member; 693 SCNetworkInterfacePrivateRef newMember; 694 695 member = CFArrayGetValueAtIndex(members, i); 696 newMember = __SCNetworkInterfaceCreateCopy(NULL, 697 member, 698 interfacePrivate->prefs, 699 interfacePrivate->serviceID); 700 CFArrayAppendValue(newMembers, newMember); 701 CFRelease(newMember); 702 } 703 CFRelease(interfacePrivate->bond.interfaces); 704 interfacePrivate->bond.interfaces = newMembers; 705 } 706 707 return ok; 708} 709 710 711Boolean 712SCBondInterfaceSetMemberInterfaces(SCBondInterfaceRef bond, CFArrayRef members) 713{ 714 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond; 715 Boolean ok; 716 int sc_status = kSCStatusOK; 717 718 if (!isA_SCBondInterface(bond)) { 719 _SCErrorSet(kSCStatusInvalidArgument); 720 return FALSE; 721 } 722 723 if ((members != NULL) && !isA_CFArray(members)) { 724 _SCErrorSet(kSCStatusInvalidArgument); 725 return FALSE; 726 } 727 728 if (interfacePrivate->prefs != NULL) { 729 CFArrayRef available; 730 CFArrayRef current; 731 CFIndex i; 732 CFIndex n_available; 733 CFIndex n_current; 734 CFIndex n_members; 735 CFArrayRef services = NULL; 736 737 current = SCBondInterfaceGetMemberInterfaces(bond); 738 n_current = (current != NULL) ? CFArrayGetCount(current) : 0; 739 740 available = SCBondInterfaceCopyAvailableMemberInterfaces(interfacePrivate->prefs); 741 n_available = (available != NULL) ? CFArrayGetCount(available) : 0; 742 743 n_members = (members != NULL) ? CFArrayGetCount(members) : 0; 744 for (i = 0; i < n_members; i++) { 745 SCNetworkInterfaceRef member; 746 747 member = CFArrayGetValueAtIndex(members, i); 748 749 if ((current != NULL) && 750 CFArrayContainsValue(current, CFRangeMake(0, n_current), member)) { 751 // current members are allowed 752 continue; 753 } 754 755 if ((available != NULL) && 756 CFArrayContainsValue(available, CFRangeMake(0, n_available), member)) { 757 // available members are allowed but cannot be associated 758 // with any other network services. 759 760 if (services == NULL) { 761 services = __SCNetworkServiceCopyAllEnabled(interfacePrivate->prefs); 762 } 763 if ((services != NULL) && 764 __SCNetworkServiceExistsForInterface(services, member)) { 765 sc_status = kSCStatusKeyExists; 766 break; 767 } 768 769 // if available 770 continue; 771 } 772 773 // if member not allowed 774 sc_status = kSCStatusInvalidArgument; 775 break; 776 } 777 778 if (available != NULL) CFRelease(available); 779 if (services != NULL) CFRelease(services); 780 } 781 782 if (sc_status != kSCStatusOK) { 783 _SCErrorSet(sc_status); 784 return FALSE; 785 } 786 787 ok = __SCBondInterfaceSetMemberInterfaces(bond, members); 788 return ok; 789} 790 791 792Boolean 793SCBondInterfaceSetLocalizedDisplayName(SCBondInterfaceRef bond, CFStringRef newName) 794{ 795 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond; 796 Boolean ok = TRUE; 797 798 if (!isA_SCBondInterface(bond)) { 799 _SCErrorSet(kSCStatusInvalidArgument); 800 return FALSE; 801 } 802 803 if ((newName != NULL) && !isA_CFString(newName)) { 804 _SCErrorSet(kSCStatusInvalidArgument); 805 return FALSE; 806 } 807 808 // set name in the stored preferences 809 if (interfacePrivate->prefs != NULL) { 810 CFDictionaryRef dict; 811 CFMutableDictionaryRef newDict; 812 CFStringRef path; 813 814 path = CFStringCreateWithFormat(NULL, 815 NULL, 816 CFSTR("/%@/%@/%@"), 817 kSCPrefVirtualNetworkInterfaces, 818 kSCNetworkInterfaceTypeBond, 819 interfacePrivate->entity_device); 820 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path); 821 if (!isA_CFDictionary(dict)) { 822 // if the prefs are confused 823 CFRelease(path); 824 _SCErrorSet(kSCStatusFailed); 825 return FALSE; 826 } 827 828 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 829 if (newName != NULL) { 830 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName); 831 } else { 832 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName); 833 } 834 if (!CFEqual(dict, newDict)) { 835 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict); 836 } 837 CFRelease(newDict); 838 CFRelease(path); 839 } 840 841 // set name in the SCBondInterfaceRef 842 if (ok) { 843 if (interfacePrivate->localized_name != NULL) { 844 CFRelease(interfacePrivate->localized_name); 845 interfacePrivate->localized_name = NULL; 846 } 847 if (newName != NULL) { 848 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName); 849 } 850 } 851 852 return ok; 853} 854 855 856Boolean 857SCBondInterfaceSetOptions(SCBondInterfaceRef bond, CFDictionaryRef newOptions) 858{ 859 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond; 860 Boolean ok = TRUE; 861 862 if (!isA_SCBondInterface(bond)) { 863 _SCErrorSet(kSCStatusInvalidArgument); 864 return FALSE; 865 } 866 867 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) { 868 _SCErrorSet(kSCStatusInvalidArgument); 869 return FALSE; 870 } 871 872 // set options in the stored preferences 873 if (interfacePrivate->prefs != NULL) { 874 CFDictionaryRef dict; 875 CFMutableDictionaryRef newDict; 876 CFStringRef path; 877 878 path = CFStringCreateWithFormat(NULL, 879 NULL, 880 CFSTR("/%@/%@/%@"), 881 kSCPrefVirtualNetworkInterfaces, 882 kSCNetworkInterfaceTypeBond, 883 interfacePrivate->entity_device); 884 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path); 885 if (!isA_CFDictionary(dict)) { 886 // if the prefs are confused 887 CFRelease(path); 888 _SCErrorSet(kSCStatusFailed); 889 return FALSE; 890 } 891 892 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 893 if (newOptions != NULL) { 894 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBondOptions, newOptions); 895 } else { 896 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesBondOptions); 897 } 898 if (!CFEqual(dict, newDict)) { 899 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict); 900 } 901 CFRelease(newDict); 902 CFRelease(path); 903 } 904 905 // set options in the SCBondInterfaceRef 906 if (ok) { 907 if (interfacePrivate->bond.options != NULL) { 908 CFRelease(interfacePrivate->bond.options); 909 interfacePrivate->bond.options = NULL; 910 } 911 if (newOptions != NULL) { 912 interfacePrivate->bond.options = CFDictionaryCreateCopy(NULL, newOptions); 913 } 914 } 915 916 return ok; 917} 918 919 920static Boolean 921_SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode) 922{ 923 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond; 924 Boolean needs_release = FALSE; 925 Boolean ok = TRUE; 926 927 assert(bond != NULL); 928 929 if (mode == NULL) { 930 int mode_num = IF_BOND_MODE_LACP; 931 932 mode = CFNumberCreate(NULL, kCFNumberIntType, &mode_num); 933 needs_release = TRUE; 934 } 935 936 // set mode in the stored preferences 937 if (interfacePrivate->prefs != NULL) { 938 CFDictionaryRef dict; 939 CFMutableDictionaryRef newDict; 940 CFStringRef path; 941 942 path = CFStringCreateWithFormat(NULL, 943 NULL, 944 CFSTR("/%@/%@/%@"), 945 kSCPrefVirtualNetworkInterfaces, 946 kSCNetworkInterfaceTypeBond, 947 interfacePrivate->entity_device); 948 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path); 949 if (!isA_CFDictionary(dict)) { 950 // if the prefs are confused 951 CFRelease(path); 952 _SCErrorSet(kSCStatusFailed); 953 ok = FALSE; 954 goto done; 955 } 956 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 957 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBondMode, mode); 958 if (!CFEqual(dict, newDict)) { 959 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict); 960 } 961 CFRelease(newDict); 962 CFRelease(path); 963 } 964 965 if (ok) { 966 CFRetain(mode); 967 if (interfacePrivate->bond.mode != NULL) { 968 CFRelease(interfacePrivate->bond.mode); 969 } 970 interfacePrivate->bond.mode = mode; 971 } 972 973 done : 974 975 if (needs_release) CFRelease(mode); 976 return ok; 977} 978 979Boolean 980SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode) 981{ 982 int mode_num; 983 984 if (!isA_SCBondInterface(bond) || !isA_CFNumber(mode)) { 985 _SCErrorSet(kSCStatusInvalidArgument); 986 return FALSE; 987 } 988 989 if (CFNumberGetValue(mode, kCFNumberIntType, &mode_num) == FALSE) { 990 _SCErrorSet(kSCStatusInvalidArgument); 991 return FALSE; 992 } 993 994 switch (mode_num) { 995 case IF_BOND_MODE_LACP: 996 case IF_BOND_MODE_STATIC: 997 break; 998 default: 999 _SCErrorSet(kSCStatusInvalidArgument); 1000 return FALSE; 1001 } 1002 1003 return (_SCBondInterfaceSetMode(bond, mode)); 1004} 1005 1006CFNumberRef 1007SCBondInterfaceGetMode(SCBondInterfaceRef bond) 1008{ 1009 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond; 1010 1011 if (!isA_SCBondInterface(bond)) { 1012 _SCErrorSet(kSCStatusInvalidArgument); 1013 return NULL; 1014 } 1015 return (interfacePrivate->bond.mode); 1016} 1017 1018 1019#pragma mark - 1020#pragma mark SCBondStatus APIs 1021 1022 1023typedef struct { 1024 1025 // base CFType information 1026 CFRuntimeBase cfBase; 1027 1028 // bond status 1029 SCBondInterfaceRef bond; 1030 CFDictionaryRef status_bond; 1031 1032 // member interfaces and status 1033 CFArrayRef interfaces; // of SCNetworkInterfaceRef's 1034 CFDictionaryRef status_interfaces; // key = interface, val = interface status) 1035 1036} SCBondStatusPrivate, * SCBondStatusPrivateRef; 1037 1038 1039const CFStringRef kSCBondStatusDeviceAggregationStatus = CFSTR("AggregationStatus"); 1040const CFStringRef kSCBondStatusDeviceCollecting = CFSTR("Collecting"); 1041const CFStringRef kSCBondStatusDeviceDistributing = CFSTR("Distributing"); 1042 1043 1044static CFStringRef __SCBondStatusCopyDescription (CFTypeRef cf); 1045static void __SCBondStatusDeallocate (CFTypeRef cf); 1046static Boolean __SCBondStatusEqual (CFTypeRef cf1, CFTypeRef cf2); 1047 1048 1049static const CFRuntimeClass __SCBondStatusClass = { 1050 0, // version 1051 "BondStatus", // className 1052 NULL, // init 1053 NULL, // copy 1054 __SCBondStatusDeallocate, // dealloc 1055 __SCBondStatusEqual, // equal 1056 NULL, // hash 1057 NULL, // copyFormattingDesc 1058 __SCBondStatusCopyDescription // copyDebugDesc 1059}; 1060 1061 1062static CFTypeID __kSCBondStatusTypeID = _kCFRuntimeNotATypeID; 1063 1064 1065static pthread_once_t bondStatus_init = PTHREAD_ONCE_INIT; 1066 1067 1068static CFStringRef 1069__SCBondStatusCopyDescription(CFTypeRef cf) 1070{ 1071 CFAllocatorRef allocator = CFGetAllocator(cf); 1072 CFMutableStringRef result; 1073 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)cf; 1074 1075 result = CFStringCreateMutable(allocator, 0); 1076 CFStringAppendFormat(result, NULL, CFSTR("<SCBondStatus %p [%p]> {"), cf, allocator); 1077 CFStringAppendFormat(result, NULL, CFSTR(" bond = %@"), statusPrivate->bond); 1078 CFStringAppendFormat(result, NULL, CFSTR(", interface = %@"), statusPrivate->status_bond); 1079 CFStringAppendFormat(result, NULL, CFSTR(", members = %@"), statusPrivate->status_interfaces); 1080 CFStringAppendFormat(result, NULL, CFSTR(" }")); 1081 1082 return result; 1083} 1084 1085 1086static void 1087__SCBondStatusDeallocate(CFTypeRef cf) 1088{ 1089 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)cf; 1090 1091 /* release resources */ 1092 1093 CFRelease(statusPrivate->bond); 1094 CFRelease(statusPrivate->status_bond); 1095 if (statusPrivate->interfaces != NULL) CFRelease(statusPrivate->interfaces); 1096 CFRelease(statusPrivate->status_interfaces); 1097 return; 1098} 1099 1100 1101static Boolean 1102__SCBondStatusEqual(CFTypeRef cf1, CFTypeRef cf2) 1103{ 1104 SCBondStatusPrivateRef status1 = (SCBondStatusPrivateRef)cf1; 1105 SCBondStatusPrivateRef status2 = (SCBondStatusPrivateRef)cf2; 1106 1107 if (status1 == status2) 1108 return TRUE; 1109 1110 if (!CFEqual(status1->bond, status2->bond)) 1111 return FALSE; // if not the same bond 1112 1113 if (!CFEqual(status1->status_bond, status2->status_bond)) 1114 return FALSE; // if not the same interface status 1115 1116 if (!CFEqual(status1->status_interfaces, status2->status_interfaces)) 1117 return FALSE; // if not the same status of the member interfaces 1118 1119 return TRUE; 1120} 1121 1122 1123static void 1124__SCBondStatusInitialize(void) 1125{ 1126 __kSCBondStatusTypeID = _CFRuntimeRegisterClass(&__SCBondStatusClass); 1127 return; 1128} 1129 1130 1131static SCBondStatusRef 1132__SCBondStatusCreatePrivate(CFAllocatorRef allocator, 1133 SCBondInterfaceRef bond, 1134 CFDictionaryRef status_bond, 1135 CFDictionaryRef status_interfaces) 1136{ 1137 SCBondStatusPrivateRef statusPrivate; 1138 uint32_t size; 1139 1140 /* initialize runtime */ 1141 pthread_once(&bondStatus_init, __SCBondStatusInitialize); 1142 1143 /* allocate bond */ 1144 size = sizeof(SCBondStatusPrivate) - sizeof(CFRuntimeBase); 1145 statusPrivate = (SCBondStatusPrivateRef)_CFRuntimeCreateInstance(allocator, 1146 __kSCBondStatusTypeID, 1147 size, 1148 NULL); 1149 if (statusPrivate == NULL) { 1150 return NULL; 1151 } 1152 1153 /* establish the bond status */ 1154 1155 statusPrivate->bond = CFRetain(bond); 1156 statusPrivate->status_bond = CFDictionaryCreateCopy(NULL, status_bond); 1157 1158 statusPrivate->interfaces = NULL; 1159 statusPrivate->status_interfaces = CFDictionaryCreateCopy(NULL, status_interfaces); 1160 1161 return (SCBondStatusRef)statusPrivate; 1162} 1163 1164 1165static __inline__ CFTypeRef 1166isA_SCBondStatus(CFTypeRef obj) 1167{ 1168 return (isA_CFType(obj, SCBondStatusGetTypeID())); 1169} 1170 1171 1172CFTypeID 1173SCBondStatusGetTypeID() 1174{ 1175 pthread_once(&bondStatus_init, __SCBondStatusInitialize); /* initialize runtime */ 1176 return __kSCBondStatusTypeID; 1177} 1178 1179 1180#define N_QUICK 16 1181 1182 1183CFArrayRef /* of SCNetworkInterfaceRef's */ 1184SCBondStatusGetMemberInterfaces(SCBondStatusRef bondStatus) 1185{ 1186 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)bondStatus; 1187 1188 if (!isA_SCBondStatus(bondStatus)) { 1189 return NULL; 1190 } 1191 1192 if (statusPrivate->interfaces == NULL) { 1193 const void * keys_q[N_QUICK]; 1194 const void ** keys = keys_q; 1195 CFIndex n; 1196 1197 n = CFDictionaryGetCount(statusPrivate->status_interfaces); 1198 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { 1199 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); 1200 } 1201 CFDictionaryGetKeysAndValues(statusPrivate->status_interfaces, keys, NULL); 1202 statusPrivate->interfaces = CFArrayCreate(NULL, keys, n, &kCFTypeArrayCallBacks); 1203 if (keys != keys_q) { 1204 CFAllocatorDeallocate(NULL, keys); 1205 } 1206 } 1207 1208 return statusPrivate->interfaces; 1209} 1210 1211 1212CFDictionaryRef 1213SCBondStatusGetInterfaceStatus(SCBondStatusRef bondStatus, SCNetworkInterfaceRef interface) 1214{ 1215 CFDictionaryRef status = NULL; 1216 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)bondStatus; 1217 1218 if (!isA_SCBondStatus(bondStatus)) { 1219 return NULL; 1220 } 1221 1222 if (interface == NULL) { 1223 // return status of the bond 1224 status = statusPrivate->status_bond; 1225 } else { 1226 // return status of the member interface 1227 status = CFDictionaryGetValue(statusPrivate->status_interfaces, interface); 1228 } 1229 1230 return status; 1231} 1232 1233 1234SCBondStatusRef 1235SCBondInterfaceCopyStatus(SCBondInterfaceRef bond) 1236{ 1237 int bond_if_active; 1238 int bond_if_status; 1239 CFIndex i; 1240 struct if_bond_status_req *ibsr_p = NULL; 1241 char if_name[IFNAMSIZ]; 1242 CFIndex n; 1243 CFNumberRef num; 1244 int s; 1245 struct if_bond_status *scan_p; 1246 SCBondStatusRef status = NULL; 1247 CFMutableDictionaryRef status_bond; 1248 CFMutableDictionaryRef status_interfaces; 1249 1250 if (!isA_SCBondInterface(bond)) { 1251 _SCErrorSet(kSCStatusInvalidArgument); 1252 return NULL; 1253 } 1254 1255 s = inet_dgram_socket(); 1256 if (s == -1) { 1257 _SCErrorSet(errno); 1258 goto done; 1259 } 1260 1261 _SC_cfstring_to_cstring(SCNetworkInterfaceGetBSDName(bond), 1262 if_name, 1263 sizeof(if_name), 1264 kCFStringEncodingASCII); 1265 if (siocgifmedia(s, if_name, &bond_if_status, &bond_if_active) == -1) { 1266 _SCErrorSet(errno); 1267 switch (errno) { 1268 case EBUSY : 1269 case ENXIO : 1270 break; 1271 default : 1272 SCLog(TRUE, LOG_ERR, 1273 CFSTR("siocgifmedia(%s) failed: %s"), 1274 if_name, 1275 strerror(errno)); 1276 } 1277 goto done; 1278 } 1279 ibsr_p = if_bond_status_req_copy(s, if_name); 1280 if (ibsr_p == NULL) { 1281 _SCErrorSet(errno); 1282 goto done; 1283 } 1284 1285 status_bond = CFDictionaryCreateMutable(NULL, 1286 0, 1287 &kCFTypeDictionaryKeyCallBacks, 1288 &kCFTypeDictionaryValueCallBacks); 1289 1290 status_interfaces = CFDictionaryCreateMutable(NULL, 1291 0, 1292 &kCFTypeDictionaryKeyCallBacks, 1293 &kCFTypeDictionaryValueCallBacks); 1294 n = ibsr_p->ibsr_total; 1295 for (i = 0, scan_p = (struct if_bond_status *)ibsr_p->ibsr_buffer; i < n; i++, scan_p++) { 1296 int collecting = 0; 1297 int distributing = 0; 1298 SCNetworkInterfaceRef interface; 1299 CFStringRef interface_name; 1300 struct if_bond_partner_state * ps; 1301 CFMutableDictionaryRef status_interface; 1302 int status_val; 1303 1304 ps = &scan_p->ibs_partner_state; 1305 1306 if (lacp_actor_partner_state_in_sync(scan_p->ibs_state)) { 1307 /* we're in-sync */ 1308 status_val = kSCBondStatusOK; 1309 if (lacp_actor_partner_state_in_sync(ps->ibps_state)) { 1310 /* partner is also in-sync */ 1311 if (lacp_actor_partner_state_collecting(scan_p->ibs_state) 1312 && lacp_actor_partner_state_distributing(ps->ibps_state)) { 1313 /* we're able to collect (receive) frames */ 1314 collecting = 1; 1315 } 1316 if (lacp_actor_partner_state_distributing(scan_p->ibs_state) 1317 && lacp_actor_partner_state_collecting(ps->ibps_state)) { 1318 /* we're able to distribute (transmit) frames */ 1319 distributing = 1; 1320 } 1321 } 1322 } else { 1323 int active = 0; 1324 int status = 0; 1325 static lacp_system zeroes = { {0, 0, 0, 0, 0, 0}}; 1326 1327 if (siocgifmedia(s, scan_p->ibs_if_name, &status, &active) == -1) { 1328 switch (errno) { 1329 case EBUSY : 1330 case ENXIO : 1331 break; 1332 default : 1333 SCLog(TRUE, LOG_ERR, 1334 CFSTR("siocgifmedia(%s) failed: %s"), 1335 if_name, 1336 strerror(errno)); 1337 break; 1338 } 1339 } 1340 if (((status & IFM_AVALID) == 0) || 1341 ((status & IFM_ACTIVE) == 0) || 1342 ((active & IFM_FDX ) == 0)) { 1343 /* link down or not full-duplex */ 1344 status_val = kSCBondStatusLinkInvalid; 1345 } else if ((ps->ibps_system_priority == 0) && 1346 (bcmp(&zeroes, &ps->ibps_system, sizeof(zeroes)) == 0)) { 1347 /* no one on the other end of the link */ 1348 status_val = kSCBondStatusNoPartner; 1349 } else if (active != bond_if_active) { 1350 /* the link speed was different */ 1351 status_val = kSCBondStatusLinkInvalid; 1352 } else { 1353 /* partner is not in the active group */ 1354 status_val = kSCBondStatusNotInActiveGroup; 1355 } 1356 } 1357 1358 // interface 1359 strlcpy(if_name, scan_p->ibs_if_name, sizeof(if_name)); 1360 interface_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII); 1361 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, interface_name, 1362 kIncludeNoVirtualInterfaces); 1363 CFRelease(interface_name); 1364 1365 // interface status 1366 status_interface = CFDictionaryCreateMutable(NULL, 1367 0, 1368 &kCFTypeDictionaryKeyCallBacks, 1369 &kCFTypeDictionaryValueCallBacks); 1370 num = CFNumberCreate(NULL, kCFNumberIntType, &status_val); 1371 CFDictionarySetValue(status_interface, kSCBondStatusDeviceAggregationStatus, num); 1372 CFRelease(num); 1373 num = CFNumberCreate(NULL, kCFNumberIntType, &collecting); 1374 CFDictionarySetValue(status_interface, kSCBondStatusDeviceCollecting, num); 1375 CFRelease(num); 1376 num = CFNumberCreate(NULL, kCFNumberIntType, &distributing); 1377 CFDictionarySetValue(status_interface, kSCBondStatusDeviceDistributing, num); 1378 CFRelease(num); 1379 1380 CFDictionarySetValue(status_interfaces, interface, status_interface); 1381 CFRelease(interface); 1382 CFRelease(status_interface); 1383 } 1384 1385 status = __SCBondStatusCreatePrivate(NULL, bond, status_bond, status_interfaces); 1386 CFRelease(status_bond); 1387 CFRelease(status_interfaces); 1388 1389 done: 1390 1391 if (s != -1) { 1392 close(s); 1393 } 1394 if (ibsr_p != NULL) { 1395 free(ibsr_p); 1396 } 1397 return (SCBondStatusRef)status; 1398} 1399 1400 1401#pragma mark - 1402#pragma mark SCBondInterface management 1403 1404 1405static Boolean 1406__bond_set_mode(int s, CFStringRef bond_if, CFNumberRef mode) 1407{ 1408 struct if_bond_req breq; 1409 struct ifreq ifr; 1410 int mode_num; 1411 1412 mode_num = IF_BOND_MODE_LACP; 1413 if (mode != NULL) { 1414 CFNumberGetValue(mode, kCFNumberIntType, &mode_num); 1415 } 1416 1417 // bond interface 1418 bzero(&ifr, sizeof(ifr)); 1419 (void) _SC_cfstring_to_cstring(bond_if, 1420 ifr.ifr_name, 1421 sizeof(ifr.ifr_name), 1422 kCFStringEncodingASCII); 1423 ifr.ifr_data = (caddr_t)&breq; 1424 bzero(&breq, sizeof(breq)); 1425 breq.ibr_op = IF_BOND_OP_SET_MODE; 1426 breq.ibr_ibru.ibru_int_val = mode_num; 1427 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) { 1428 _SCErrorSet(errno); 1429 SCLog(TRUE, LOG_ERR, 1430 CFSTR("could not set mode to %@ on bond \"%@\": %s"), 1431 mode, 1432 bond_if, 1433 strerror(errno)); 1434 return FALSE; 1435 } 1436 1437 return TRUE; 1438} 1439 1440static Boolean 1441__bond_add_interface(int s, CFStringRef bond_if, CFStringRef interface_if) 1442{ 1443 struct if_bond_req breq; 1444 struct ifreq ifr; 1445 1446 // bond interface 1447 bzero(&ifr, sizeof(ifr)); 1448 (void) _SC_cfstring_to_cstring(bond_if, 1449 ifr.ifr_name, 1450 sizeof(ifr.ifr_name), 1451 kCFStringEncodingASCII); 1452 ifr.ifr_data = (caddr_t)&breq; 1453 1454 // new bond member 1455 bzero(&breq, sizeof(breq)); 1456 breq.ibr_op = IF_BOND_OP_ADD_INTERFACE; 1457 (void) _SC_cfstring_to_cstring(interface_if, 1458 breq.ibr_ibru.ibru_if_name, 1459 sizeof(breq.ibr_ibru.ibru_if_name), 1460 kCFStringEncodingASCII); 1461 1462 // add new bond member 1463 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) { 1464 _SCErrorSet(errno); 1465 SCLog(TRUE, LOG_ERR, 1466 CFSTR("could not add interface \"%@\" to bond \"%@\": %s"), 1467 interface_if, 1468 bond_if, 1469 strerror(errno)); 1470 return FALSE; 1471 } 1472 1473 return TRUE; 1474} 1475 1476 1477static Boolean 1478__bond_remove_interface(int s, CFStringRef bond_if, CFStringRef interface_if) 1479{ 1480 struct if_bond_req breq; 1481 struct ifreq ifr; 1482 1483 // bond interface 1484 bzero(&ifr, sizeof(ifr)); 1485 (void) _SC_cfstring_to_cstring(bond_if, 1486 ifr.ifr_name, 1487 sizeof(ifr.ifr_name), 1488 kCFStringEncodingASCII); 1489 ifr.ifr_data = (caddr_t)&breq; 1490 1491 // bond member to remove 1492 bzero(&breq, sizeof(breq)); 1493 breq.ibr_op = IF_BOND_OP_REMOVE_INTERFACE; 1494 (void) _SC_cfstring_to_cstring(interface_if, 1495 breq.ibr_ibru.ibru_if_name, 1496 sizeof(breq.ibr_ibru.ibru_if_name), 1497 kCFStringEncodingASCII); 1498 1499 // remove bond member 1500 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) { 1501 _SCErrorSet(errno); 1502 SCLog(TRUE, LOG_ERR, 1503 CFSTR("could not remove interface \"%@\" from bond \"%@\": %s"), 1504 interface_if, 1505 bond_if, 1506 strerror(errno)); 1507 return FALSE; 1508 } 1509 1510 return TRUE; 1511} 1512 1513 1514Boolean 1515_SCBondInterfaceUpdateConfiguration(SCPreferencesRef prefs) 1516{ 1517 CFArrayRef active = NULL; 1518 CFArrayRef config = NULL; 1519 CFIndex i; 1520 CFIndex nActive; 1521 CFIndex nConfig; 1522 Boolean ok = TRUE; 1523 int s = -1; 1524 1525 if (prefs == NULL) { 1526 _SCErrorSet(kSCStatusInvalidArgument); 1527 return FALSE; 1528 } 1529 1530 /* configured Bonds */ 1531 config = SCBondInterfaceCopyAll(prefs); 1532 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0; 1533 1534 /* active Bonds */ 1535 active = _SCBondInterfaceCopyActive(); 1536 nActive = (active != NULL) ? CFArrayGetCount(active) : 0; 1537 1538 /* 1539 * remove any no-longer-configured bond interfaces and 1540 * any devices associated with a bond that are no longer 1541 * associated with a bond. 1542 */ 1543 for (i = 0; i < nActive; i++) { 1544 SCBondInterfaceRef a_bond; 1545 CFStringRef a_bond_if; 1546 CFIndex j; 1547 Boolean found = FALSE; 1548 1549 a_bond = CFArrayGetValueAtIndex(active, i); 1550 a_bond_if = SCNetworkInterfaceGetBSDName(a_bond); 1551 1552 for (j = 0; j < nConfig; j++) { 1553 SCBondInterfaceRef c_bond; 1554 CFStringRef c_bond_if; 1555 1556 c_bond = CFArrayGetValueAtIndex(config, j); 1557 c_bond_if = SCNetworkInterfaceGetBSDName(c_bond); 1558 1559 if (CFEqual(a_bond_if, c_bond_if)) { 1560 CFIndex a; 1561 CFArrayRef a_bond_interfaces; 1562 CFIndex a_count; 1563 CFArrayRef c_bond_interfaces; 1564 CFIndex c_count; 1565 1566 c_bond_interfaces = SCBondInterfaceGetMemberInterfaces(c_bond); 1567 c_count = (c_bond_interfaces != NULL) ? CFArrayGetCount(c_bond_interfaces) : 0; 1568 1569 a_bond_interfaces = SCBondInterfaceGetMemberInterfaces(a_bond); 1570 a_count = (a_bond_interfaces != NULL) ? CFArrayGetCount(a_bond_interfaces) : 0; 1571 1572 for (a = 0; a < a_count; a++) { 1573 SCNetworkInterfaceRef a_interface; 1574 CFStringRef a_interface_if; 1575 1576 a_interface = CFArrayGetValueAtIndex(a_bond_interfaces, a); 1577 if ((c_count == 0) || 1578 !CFArrayContainsValue(c_bond_interfaces, 1579 CFRangeMake(0, c_count), 1580 a_interface)) { 1581 /* 1582 * if this device is no longer part 1583 * of the bond. 1584 */ 1585 if (s == -1) { 1586 s = inet_dgram_socket(); 1587 if (s == -1) { 1588 _SCErrorSet(errno); 1589 ok = FALSE; 1590 goto done; 1591 } 1592 } 1593 1594 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface); 1595 if (!__bond_remove_interface(s, a_bond_if, a_interface_if)) { 1596 ok = FALSE; 1597 } 1598 } 1599 } 1600 1601 found = TRUE; 1602 break; 1603 } 1604 } 1605 1606 if (!found) { 1607 /* 1608 * if this interface is no longer configured 1609 */ 1610 if (s == -1) { 1611 s = inet_dgram_socket(); 1612 if (s == -1) { 1613 _SCErrorSet(errno); 1614 ok = FALSE; 1615 goto done; 1616 } 1617 } 1618 1619 if (!__destroyInterface(s, a_bond_if)) { 1620 _SCErrorSet(errno); 1621 ok = FALSE; 1622 } 1623 } 1624 } 1625 1626 /* 1627 * add any newly-configured bond interfaces and add any 1628 * devices that should now be associated with the bond. 1629 */ 1630 for (i = 0; i < nConfig; i++) { 1631 CFNumberRef c_bond_mode; 1632 SCBondInterfaceRef c_bond; 1633 CFArrayRef c_bond_interfaces; 1634 CFStringRef c_bond_if; 1635 CFIndex c_count; 1636 Boolean found = FALSE; 1637 CFIndex j; 1638 1639 c_bond = CFArrayGetValueAtIndex(config, i); 1640 c_bond_if = SCNetworkInterfaceGetBSDName(c_bond); 1641 c_bond_interfaces = SCBondInterfaceGetMemberInterfaces(c_bond); 1642 c_bond_mode = SCBondInterfaceGetMode(c_bond); 1643 c_count = (c_bond_interfaces != NULL) ? CFArrayGetCount(c_bond_interfaces) : 0; 1644 1645 for (j = 0; j < nActive; j++) { 1646 SCBondInterfaceRef a_bond; 1647 CFArrayRef a_bond_interfaces; 1648 CFNumberRef a_bond_mode; 1649 CFStringRef a_bond_if; 1650 CFIndex a_count; 1651 1652 a_bond = CFArrayGetValueAtIndex(active, j); 1653 a_bond_if = SCNetworkInterfaceGetBSDName(a_bond); 1654 a_bond_interfaces = SCBondInterfaceGetMemberInterfaces(a_bond); 1655 a_bond_mode = SCBondInterfaceGetMode(a_bond); 1656 a_count = (a_bond_interfaces != NULL) ? CFArrayGetCount(a_bond_interfaces) : 0; 1657 1658 if (CFEqual(c_bond_if, a_bond_if)) { 1659 CFIndex c; 1660 Boolean if_list_change = FALSE; 1661 Boolean mode_change = FALSE; 1662 1663 found = TRUE; 1664 1665 if (!_SC_CFEqual(a_bond_mode, c_bond_mode)) { 1666 mode_change = TRUE; 1667 } 1668 1669 if (!_SC_CFEqual(c_bond_interfaces, a_bond_interfaces)) { 1670 if_list_change = TRUE; 1671 } 1672 if (!mode_change && !if_list_change) { 1673 break; // if no change 1674 } 1675 if (s == -1) { 1676 s = inet_dgram_socket(); 1677 if (s == -1) { 1678 _SCErrorSet(errno); 1679 ok = FALSE; 1680 goto done; 1681 } 1682 } 1683 if (mode_change) { 1684 __bond_set_mode(s, a_bond_if, c_bond_mode); 1685 } 1686 if (!if_list_change) { 1687 break; // no if list changes 1688 } 1689 1690 /* 1691 * ensure that the first device of the bond matches, if 1692 * not then we remove all current devices and add them 1693 * back in the preferred order. 1694 */ 1695 if ((c_count > 0) && 1696 (a_count > 0) && 1697 !CFEqual(CFArrayGetValueAtIndex(c_bond_interfaces, 0), 1698 CFArrayGetValueAtIndex(a_bond_interfaces, 0))) { 1699 CFIndex a; 1700 1701 for (a = 0; a < a_count; a++) { 1702 SCNetworkInterfaceRef a_interface; 1703 CFStringRef a_interface_if; 1704 1705 a_interface = CFArrayGetValueAtIndex(a_bond_interfaces, a); 1706 if (!CFArrayContainsValue(c_bond_interfaces, 1707 CFRangeMake(0, c_count), 1708 a_interface)) { 1709 continue; // if already removed 1710 } 1711 1712 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface); 1713 if (!__bond_remove_interface(s, a_bond_if, a_interface_if)) { 1714 ok = FALSE; 1715 } 1716 } 1717 1718 a_count = 0; // all active devices have been removed 1719 } 1720 1721 /* 1722 * add any devices which are not currently associated 1723 * with the bond interface. 1724 */ 1725 for (c = 0; c < c_count; c++) { 1726 SCNetworkInterfaceRef c_interface; 1727 SCNetworkInterfacePrivateRef c_interfacePrivate; 1728 CFStringRef c_interface_if; 1729 1730 c_interface = CFArrayGetValueAtIndex(c_bond_interfaces, c); 1731 if ((a_count == 0) || 1732 !CFArrayContainsValue(a_bond_interfaces, 1733 CFRangeMake(0, a_count), 1734 c_interface)) { 1735 /* 1736 * check if this member interface can be added to a bond. 1737 */ 1738 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface; 1739 if (!c_interfacePrivate->supportsBond) { 1740 // if member not supported 1741 continue; 1742 } 1743 1744 /* 1745 * if this member interface is not currently part of the bond. 1746 */ 1747 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface); 1748 if (!__bond_add_interface(s, c_bond_if, c_interface_if)) { 1749 // if member could not be added 1750 ok = FALSE; 1751 } 1752 } 1753 } 1754 1755 break; 1756 } 1757 } 1758 1759 if (!found) { 1760 CFIndex c; 1761 1762 if (s == -1) { 1763 s = inet_dgram_socket(); 1764 if (s == -1) { 1765 _SCErrorSet(errno); 1766 ok = FALSE; 1767 goto done; 1768 } 1769 } 1770 1771 /* 1772 * establish the new bond interface. 1773 */ 1774 if (!__createInterface(s, c_bond_if)) { 1775 _SCErrorSet(errno); 1776 ok = FALSE; 1777 continue; 1778 } 1779 1780 /* set the mode */ 1781 __bond_set_mode(s, c_bond_if, c_bond_mode); 1782 1783 /* 1784 * add the member interfaces 1785 */ 1786 for (c = 0; c < c_count; c++) { 1787 SCNetworkInterfaceRef c_interface; 1788 SCNetworkInterfacePrivateRef c_interfacePrivate; 1789 CFStringRef c_interface_if; 1790 1791 c_interface = CFArrayGetValueAtIndex(c_bond_interfaces, c); 1792 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface; 1793 if (!c_interfacePrivate->supportsBond) { 1794 // if member not supported 1795 continue; 1796 } 1797 1798 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface); 1799 if (!__bond_add_interface(s, c_bond_if, c_interface_if)) { 1800 // if member could not be added 1801 ok = FALSE; 1802 } 1803 } 1804 } 1805 1806 } 1807 1808 done : 1809 1810 if (active != NULL) CFRelease(active); 1811 if (config != NULL) CFRelease(config); 1812 if (s != -1) (void) close(s); 1813 1814 return ok; 1815} 1816