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