this repo has no description
at fixPythonPipStalling 1280 lines 34 kB view raw
1/* 2 * Copyright (c) 2002-2007, 2010, 2011, 2013, 2015-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 * October 21, 2000 Allan Nathanson <ajn@apple.com> 28 * - initial revision 29 */ 30 31 32#include <unistd.h> 33#define KERNEL_PRIVATE 34#include <sys/ioctl.h> 35#undef KERNEL_PRIVATE 36#include <sys/socket.h> 37#include <net/ethernet.h> 38#include <net/if.h> 39#include <net/if_vlan_var.h> 40#include <net/if_media.h> 41#include <net/if_types.h> 42#include <netinet/in.h> 43#include <netinet/ip6.h> // for IPV6_MMTU 44 45#include "SCNetworkConfigurationInternal.h" // for __SCNetworkInterfaceCreatePrivate 46 47#include <IOKit/IOKitLib.h> 48#include <IOKit/network/IONetworkInterface.h> 49#include <IOKit/network/IONetworkController.h> 50#include "dy_framework.h" 51 52 53#pragma mark - 54#pragma mark Capabilities 55 56 57// the following table needs to keep the capabilitiy names and values 58// between the <SystemConfiguration/SCSchemaDefinitionsPrivate.h> and 59// <net/if.h> headers in sync. 60static const struct { 61 const CFStringRef *name; 62 Boolean readwrite; 63 int val; 64} capabilityMappings[] = { 65#ifdef SIOCGIFCAP 66 { &kSCPropNetEthernetCapabilityRXCSUM, TRUE, IFCAP_RXCSUM }, // can offload checksum on RX 67 { &kSCPropNetEthernetCapabilityTXCSUM, TRUE, IFCAP_TXCSUM }, // can offload checksum on TX 68 { &kSCPropNetEthernetCapabilityVLAN_MTU, FALSE, IFCAP_VLAN_MTU }, // VLAN-compatible MTU 69 { &kSCPropNetEthernetCapabilityVLAN_HWTAGGING, FALSE, IFCAP_VLAN_HWTAGGING }, // hardware VLAN tag support 70 { &kSCPropNetEthernetCapabilityJUMBO_MTU, FALSE, IFCAP_JUMBO_MTU }, // 9000 byte MTU supported 71 { &kSCPropNetEthernetCapabilityTSO, TRUE, IFCAP_TSO }, // can do TCP/TCP6 Segmentation Offload 72 { &kSCPropNetEthernetCapabilityTSO4, FALSE, IFCAP_TSO4 }, // can do TCP Segmentation Offload 73 { &kSCPropNetEthernetCapabilityTSO6, FALSE, IFCAP_TSO6 }, // can do TCP6 Segmentation Offload 74 { &kSCPropNetEthernetCapabilityLRO, TRUE, IFCAP_LRO }, // can do Large Receive Offload 75 { &kSCPropNetEthernetCapabilityAV, TRUE, IFCAP_AV }, // can do 802.1 AV Bridging 76#endif // SIOCGIFCAP 77}; 78 79 80static CFIndex 81findCapability(CFStringRef capability) 82{ 83 for (size_t i = 0; i < sizeof(capabilityMappings) / sizeof(capabilityMappings[0]); i++) { 84 if (CFEqual(capability, *capabilityMappings[i].name)) { 85 return i; 86 } 87 } 88 89 return kCFNotFound; 90} 91 92 93static Boolean 94__getCapabilities(CFStringRef interfaceName, 95 int *current, 96 int *available) 97{ 98#ifdef SIOCGIFCAP 99 struct ifreq ifr; 100 Boolean ok = FALSE; 101 int sock = -1; 102 103 memset((void *)&ifr, 0, sizeof(ifr)); 104 if (_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) == NULL) { 105 SC_log(LOG_NOTICE, "could not convert interface name"); 106 _SCErrorSet(kSCStatusInvalidArgument); 107 return FALSE; 108 } 109 110 sock = socket(AF_INET, SOCK_DGRAM, 0); 111 if (sock == -1) { 112 _SCErrorSet(errno); 113 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno)); 114 return FALSE; 115 } 116 117 if (ioctl(sock, SIOCGIFCAP, (caddr_t)&ifr) == -1) { 118 _SCErrorSet(errno); 119 switch (errno) { 120 case EBUSY : 121 case ENXIO : 122 break; 123 default : 124 SC_log(LOG_NOTICE, "ioctl(SIOCGIFCAP) failed: %s", strerror(errno)); 125 } 126 goto done; 127 } 128 129 if (current != NULL) *current = ifr.ifr_curcap; 130 if (available != NULL) *available = ifr.ifr_reqcap; 131 132 ok = TRUE; 133 134 done : 135 136 (void)close(sock); 137 return ok; 138#else // SIOCGIFCAP 139 if (current != NULL) *current = 0; 140 if (available != NULL) *available = 0; 141 return TRUE; 142#endif // SIOCGIFCAP 143} 144 145 146int 147__SCNetworkInterfaceCreateCapabilities(SCNetworkInterfaceRef interface, 148 int capability_base, 149 CFDictionaryRef capability_options) 150{ 151 int cap_available = 0; 152 int cap_current = capability_base; 153 CFStringRef interfaceName; 154 155 if (!isA_SCNetworkInterface(interface)) { 156 _SCErrorSet(kSCStatusInvalidArgument); 157 goto done; 158 } 159 160 interfaceName = SCNetworkInterfaceGetBSDName(interface); 161 if (interfaceName == NULL) { 162 _SCErrorSet(kSCStatusInvalidArgument); 163 goto done; 164 } 165 166 if (!__getCapabilities(interfaceName, 167 (capability_base == -1) ? &cap_current : NULL, 168 &cap_available)) { 169 goto done; 170 } 171 172 if (cap_available == 0) { 173 goto done; 174 } 175 176 if (capability_options == NULL) { 177 goto done; 178 } 179 180 for (size_t i = 0; i < sizeof(capabilityMappings) / sizeof(capabilityMappings[0]); i++) { 181 int cap_val; 182 CFTypeRef val; 183 184 if (((cap_available & capabilityMappings[i].val) != 0) && 185 capabilityMappings[i].readwrite && 186 CFDictionaryGetValueIfPresent(capability_options, 187 *capabilityMappings[i].name, 188 &val) && 189 isA_CFNumber(val) && 190 CFNumberGetValue(val, kCFNumberIntType, &cap_val)) { 191 // update capability 192 if (cap_val != 0) { 193 cap_current |= (cap_available & capabilityMappings[i].val); 194 } else { 195 cap_current &= ~capabilityMappings[i].val; 196 } 197 198 // don't process again 199 cap_available &= ~capabilityMappings[i].val; 200 } 201 } 202 203 done : 204 205 return cap_current; 206} 207 208 209CFTypeRef 210SCNetworkInterfaceCopyCapability(SCNetworkInterfaceRef interface, 211 CFStringRef capability) 212{ 213 int cap_current = 0; 214 int cap_available = 0; 215 int cap_val; 216 CFStringRef interfaceName; 217 CFTypeRef val = NULL; 218 219 if (!isA_SCNetworkInterface(interface)) { 220 _SCErrorSet(kSCStatusInvalidArgument); 221 return NULL; 222 } 223 224 interfaceName = SCNetworkInterfaceGetBSDName(interface); 225 if (interfaceName == NULL) { 226 _SCErrorSet(kSCStatusInvalidArgument); 227 return NULL; 228 } 229 230 if (!__getCapabilities(interfaceName, &cap_current, &cap_available)) { 231 return NULL; 232 } 233 234 if (capability == NULL) { 235 CFMutableDictionaryRef all = NULL; 236 237 // if ALL capabilities requested 238 for (size_t i = 0; i < sizeof(capabilityMappings) / sizeof(capabilityMappings[0]); i++) { 239 if ((cap_available & capabilityMappings[i].val) == capabilityMappings[i].val) { 240 if (all == NULL) { 241 all = CFDictionaryCreateMutable(NULL, 242 0, 243 &kCFTypeDictionaryKeyCallBacks, 244 &kCFTypeDictionaryValueCallBacks); 245 } 246 cap_val = ((cap_current & capabilityMappings[i].val) == capabilityMappings[i].val) ? 1 : 0; 247 val = CFNumberCreate(NULL, kCFNumberIntType, &cap_val); 248 CFDictionarySetValue(all, *capabilityMappings[i].name, val); 249 CFRelease(val); 250 cap_available &= ~capabilityMappings[i].val; 251 } 252 } 253 254 val = all; 255 } else { 256 CFIndex i; 257 258 i = findCapability(capability); 259 if (i == kCFNotFound) { 260 // if unknown capability 261 _SCErrorSet(kSCStatusInvalidArgument); 262 return NULL; 263 } 264 265 if ((cap_available & capabilityMappings[i].val) != capabilityMappings[i].val) { 266 // if capability not available 267 _SCErrorSet(kSCStatusInvalidArgument); 268 return NULL; 269 } 270 271 cap_val = ((cap_current & capabilityMappings[i].val) == capabilityMappings[i].val) ? 1 : 0; 272 val = CFNumberCreate(NULL, kCFNumberIntType, &cap_val); 273 } 274 275 return val; 276} 277 278 279Boolean 280SCNetworkInterfaceSetCapability(SCNetworkInterfaceRef interface, 281 CFStringRef capability, 282 CFTypeRef newValue) 283{ 284 int cap_available = 0; 285 CFDictionaryRef configuration; 286 CFIndex i; 287 CFStringRef interfaceName; 288 CFMutableDictionaryRef newConfiguration = NULL; 289 Boolean ok = FALSE; 290 291 if (!isA_SCNetworkInterface(interface)) { 292 _SCErrorSet(kSCStatusInvalidArgument); 293 return FALSE; 294 } 295 296 interfaceName = SCNetworkInterfaceGetBSDName(interface); 297 if (interfaceName == NULL) { 298 // if no interface name 299 _SCErrorSet(kSCStatusInvalidArgument); 300 return FALSE; 301 } 302 303 i = findCapability(capability); 304 if (i == kCFNotFound) { 305 // if unknown capability 306 _SCErrorSet(kSCStatusInvalidArgument); 307 return FALSE; 308 } 309 310 if (!capabilityMappings[i].readwrite) { 311 // if not read-write 312 _SCErrorSet(kSCStatusInvalidArgument); 313 return FALSE; 314 } 315 316 if ((newValue != NULL) && !isA_CFNumber(newValue)) { 317 // all values must (for now) be CFNumber[0 or 1]'s 318 _SCErrorSet(kSCStatusInvalidArgument); 319 return FALSE; 320 } 321 322 if (!__getCapabilities(interfaceName, NULL, &cap_available)) { 323 return FALSE; 324 } 325 326 if ((cap_available & capabilityMappings[i].val) == 0) { 327 // if capability not available 328 _SCErrorSet(kSCStatusInvalidArgument); 329 return FALSE; 330 } 331 332 configuration = SCNetworkInterfaceGetConfiguration(interface); 333 if (configuration == NULL) { 334 newConfiguration = CFDictionaryCreateMutable(NULL, 335 0, 336 &kCFTypeDictionaryKeyCallBacks, 337 &kCFTypeDictionaryValueCallBacks); 338 } else { 339 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration); 340 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive); 341 } 342 343 if ((newValue != NULL)) { 344 CFDictionarySetValue(newConfiguration, capability, newValue); 345 } else { 346 CFDictionaryRemoveValue(newConfiguration, capability); 347 if (CFDictionaryGetCount(newConfiguration) == 0) { 348 CFRelease(newConfiguration); 349 newConfiguration = NULL; 350 } 351 } 352 353 ok = SCNetworkInterfaceSetConfiguration(interface, newConfiguration); 354 if (newConfiguration != NULL) CFRelease(newConfiguration); 355 356 return ok; 357} 358 359 360#pragma mark - 361#pragma mark Media Options 362 363 364static const struct ifmedia_description ifm_subtype_shared_descriptions[] = 365 IFM_SUBTYPE_SHARED_DESCRIPTIONS; 366 367static const struct ifmedia_description ifm_subtype_ethernet_descriptions[] = 368 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; 369 370static const struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = 371 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; 372 373static const struct ifmedia_description ifm_shared_option_descriptions[] = 374 IFM_SHARED_OPTION_DESCRIPTIONS; 375 376static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = 377 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; 378 379static const struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = 380 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; 381 382 383static void 384__freeMediaList(struct ifmediareq *ifm) 385{ 386 if (ifm->ifm_ulist != NULL) CFAllocatorDeallocate(NULL, ifm->ifm_ulist); 387 CFAllocatorDeallocate(NULL, ifm); 388 return; 389} 390 391 392static struct ifmediareq * 393__copyMediaList(CFStringRef interfaceName) 394{ 395 struct ifmediareq *ifm; 396 Boolean ok = FALSE; 397 int sock = -1; 398 399 ifm = (struct ifmediareq *)CFAllocatorAllocate(NULL, sizeof(struct ifmediareq), 0); 400 memset((void *)ifm, 0, sizeof(*ifm)); 401 402 if (_SC_cfstring_to_cstring(interfaceName, ifm->ifm_name, sizeof(ifm->ifm_name), kCFStringEncodingASCII) == NULL) { 403 SC_log(LOG_NOTICE, "could not convert interface name"); 404 goto done; 405 } 406 407 sock = socket(AF_INET, SOCK_DGRAM, 0); 408 if (sock == -1) { 409 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno)); 410 goto done; 411 } 412 413 if (ioctl(sock, SIOCGIFXMEDIA, (caddr_t)ifm) == -1) { 414// SC_log(LOG_NOTICE, "ioctl(SIOCGIFXMEDIA) failed: %s", strerror(errno)); 415 goto done; 416 } 417 418 if (ifm->ifm_count > 0) { 419 ifm->ifm_ulist = (int *)CFAllocatorAllocate(NULL, ifm->ifm_count * sizeof(int), 0); 420 if (ioctl(sock, SIOCGIFXMEDIA, (caddr_t)ifm) == -1) { 421 SC_log(LOG_NOTICE, "ioctl(SIOCGIFXMEDIA) failed: %s", strerror(errno)); 422 goto done; 423 } 424 } 425 426 ok = TRUE; 427 428 done : 429 430 if (sock != -1) (void)close(sock); 431 if (!ok) { 432 __freeMediaList(ifm); 433 ifm = NULL; 434 _SCErrorSet(kSCStatusFailed); 435 } 436 return ifm; 437} 438 439 440static CFDictionaryRef 441__createMediaDictionary(int media_options, Boolean filter) 442{ 443 CFMutableDictionaryRef dict = NULL; 444 int i; 445 const struct ifmedia_description *option_descriptions = NULL; 446 CFMutableArrayRef options = NULL; 447 const struct ifmedia_description *subtype_descriptions = NULL; 448 CFStringRef val; 449 450 if (filter && 451 ((IFM_SUBTYPE(media_options) == IFM_NONE) || 452 ((IFM_OPTIONS(media_options) & IFM_LOOP) != 0))) { 453 return NULL; /* filter */ 454 } 455 456 switch (IFM_TYPE(media_options)) { 457 case IFM_ETHER : 458 option_descriptions = ifm_subtype_ethernet_option_descriptions; 459 subtype_descriptions = ifm_subtype_ethernet_descriptions; 460 break; 461 case IFM_IEEE80211 : 462 option_descriptions = ifm_subtype_ieee80211_option_descriptions; 463 subtype_descriptions = ifm_subtype_ieee80211_descriptions; 464 break; 465 default : 466 return NULL; 467 } 468 469 dict = CFDictionaryCreateMutable(NULL, 470 0, 471 &kCFTypeDictionaryKeyCallBacks, 472 &kCFTypeDictionaryValueCallBacks); 473 474 /* subtype */ 475 476 val = NULL; 477 for (i = 0; !val && ifm_subtype_shared_descriptions[i].ifmt_string; i++) { 478 if (IFM_SUBTYPE(media_options) == ifm_subtype_shared_descriptions[i].ifmt_word) { 479 val = CFStringCreateWithCString(NULL, 480 ifm_subtype_shared_descriptions[i].ifmt_string, 481 kCFStringEncodingASCII); 482 break; 483 } 484 } 485 486 if (subtype_descriptions != NULL) { 487 for (i = 0; !val && subtype_descriptions[i].ifmt_string; i++) { 488 if (IFM_SUBTYPE(media_options) == subtype_descriptions[i].ifmt_word) { 489 val = CFStringCreateWithCString(NULL, 490 subtype_descriptions[i].ifmt_string, 491 kCFStringEncodingASCII); 492 break; 493 } 494 } 495 } 496 497 if (val) { 498 CFDictionaryAddValue(dict, kSCPropNetEthernetMediaSubType, val); 499 CFRelease(val); 500 } 501 502 /* options */ 503 504 options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 505 506 for (i = 0; (IFM_OPTIONS(media_options) != 0) && (ifm_shared_option_descriptions[i].ifmt_string != NULL); i++) { 507 if ((media_options & ifm_shared_option_descriptions[i].ifmt_word) != 0) { 508 val = CFStringCreateWithCString(NULL, 509 ifm_shared_option_descriptions[i].ifmt_string, 510 kCFStringEncodingASCII); 511 CFArrayAppendValue(options, val); 512 CFRelease(val); 513 514 media_options &= ~ifm_shared_option_descriptions[i].ifmt_word; 515 } 516 } 517 518 if (option_descriptions != NULL) { 519 for (i = 0; (IFM_OPTIONS(media_options) != 0) && (option_descriptions[i].ifmt_string != NULL); i++) { 520 if ((media_options & option_descriptions[i].ifmt_word) != 0) { 521 val = CFStringCreateWithCString(NULL, 522 option_descriptions[i].ifmt_string, 523 kCFStringEncodingASCII); 524 CFArrayAppendValue(options, val); 525 CFRelease(val); 526 527 media_options &= ~option_descriptions[i].ifmt_word; 528 } 529 } 530 } 531 532 CFDictionaryAddValue(dict, kSCPropNetEthernetMediaOptions, options); 533 CFRelease(options); 534 535 return dict; 536} 537 538 539int 540__SCNetworkInterfaceCreateMediaOptions(SCNetworkInterfaceRef interface, CFDictionaryRef media_options) 541{ 542 CFIndex i; 543 struct ifmediareq *ifm; 544 int ifm_new = -1; 545 CFStringRef interfaceName; 546 Boolean match; 547 CFIndex n; 548 const struct ifmedia_description *option_descriptions = NULL; 549 CFArrayRef options; 550 char *str; 551 const struct ifmedia_description *subtype_descriptions = NULL; 552 CFStringRef val; 553 554 if (!isA_SCNetworkInterface(interface)) { 555 _SCErrorSet(kSCStatusInvalidArgument); 556 return -1; 557 } 558 559 interfaceName = SCNetworkInterfaceGetBSDName(interface); 560 if (interfaceName == NULL) { 561 _SCErrorSet(kSCStatusInvalidArgument); 562 return -1; 563 } 564 565 /* set type */ 566 567 ifm = __copyMediaList(interfaceName); 568 if (ifm != NULL) { 569 if (ifm->ifm_count > 0) { 570 ifm_new = IFM_TYPE(ifm->ifm_ulist[0]); 571 } 572 __freeMediaList(ifm); 573 } 574 575 if (ifm_new == -1) { 576 // if we cannot determine the media type for the interface 577 return -1; 578 } 579 580 switch (IFM_TYPE(ifm_new)) { 581 case IFM_ETHER : 582 option_descriptions = ifm_subtype_ethernet_option_descriptions; 583 subtype_descriptions = ifm_subtype_ethernet_descriptions; 584 break; 585 case IFM_IEEE80211 : 586 option_descriptions = ifm_subtype_ieee80211_option_descriptions; 587 subtype_descriptions = ifm_subtype_ieee80211_descriptions; 588 break; 589 } 590 591 /* set subtype */ 592 593 val = CFDictionaryGetValue(media_options, kSCPropNetEthernetMediaSubType); 594 if (!isA_CFString(val)) { 595 return -1; 596 } 597 598 str = _SC_cfstring_to_cstring(val, NULL, 0, kCFStringEncodingASCII); 599 if (str == NULL) { 600 return -1; 601 } 602 603 match = FALSE; 604 for (i = 0; !match && ifm_subtype_shared_descriptions[i].ifmt_string; i++) { 605 if (strcasecmp(str, ifm_subtype_shared_descriptions[i].ifmt_string) == 0) { 606 ifm_new |= ifm_subtype_shared_descriptions[i].ifmt_word; 607 match = TRUE; 608 break; 609 } 610 } 611 612 if (subtype_descriptions != NULL) { 613 for (i = 0; !match && subtype_descriptions[i].ifmt_string; i++) { 614 if (strcasecmp(str, subtype_descriptions[i].ifmt_string) == 0) { 615 ifm_new |= subtype_descriptions[i].ifmt_word; 616 match = TRUE; 617 break; 618 } 619 } 620 } 621 622 CFAllocatorDeallocate(NULL, str); 623 624 if (!match) { 625 return -1; /* if no subtype */ 626 } 627 628 /* set options */ 629 630 options = CFDictionaryGetValue(media_options, kSCPropNetEthernetMediaOptions); 631 if (!isA_CFArray(options)) { 632 return -1; 633 } 634 635 n = CFArrayGetCount(options); 636 for (i = 0; i < n; i++) { 637 CFIndex j; 638 639 val = CFArrayGetValueAtIndex(options, i); 640 if (!isA_CFString(val)) { 641 return -1; 642 } 643 644 str = _SC_cfstring_to_cstring(val, NULL, 0, kCFStringEncodingASCII); 645 if (str == NULL) { 646 return -1; 647 } 648 649 650 match = FALSE; 651 for (j = 0; !match && ifm_shared_option_descriptions[j].ifmt_string; j++) { 652 if (strcasecmp(str, ifm_shared_option_descriptions[j].ifmt_string) == 0) { 653 ifm_new |= ifm_shared_option_descriptions[j].ifmt_word; 654 match = TRUE; 655 break; 656 } 657 } 658 659 if (option_descriptions != NULL) { 660 for (j = 0; !match && option_descriptions[j].ifmt_string; j++) { 661 if (strcasecmp(str, option_descriptions[j].ifmt_string) == 0) { 662 ifm_new |= option_descriptions[j].ifmt_word; 663 match = TRUE; 664 break; 665 } 666 } 667 } 668 669 CFAllocatorDeallocate(NULL, str); 670 671 if (!match) { 672 return -1; /* if no option */ 673 } 674 } 675 676 return ifm_new; 677} 678 679 680Boolean 681SCNetworkInterfaceCopyMediaOptions(SCNetworkInterfaceRef interface, 682 CFDictionaryRef *current, 683 CFDictionaryRef *active, 684 CFArrayRef *available, 685 Boolean filter) 686{ 687 int i; 688 struct ifmediareq *ifm; 689 CFStringRef interfaceName; 690 691 if (!isA_SCNetworkInterface(interface)) { 692 _SCErrorSet(kSCStatusInvalidArgument); 693 return FALSE; 694 } 695 696 interfaceName = SCNetworkInterfaceGetBSDName(interface); 697 if (interfaceName == NULL) { 698 _SCErrorSet(kSCStatusInvalidArgument); 699 return FALSE; 700 } 701 702 ifm = __copyMediaList(interfaceName); 703 if (ifm == NULL) { 704 return FALSE; 705 } 706 707 if (active != NULL) *active = NULL; 708 if (current != NULL) *current = NULL; 709 if (available != NULL) { 710 CFMutableArrayRef media_options; 711 712 media_options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 713 for (i = 0; i < ifm->ifm_count; i++) { 714 CFDictionaryRef options; 715 716 options = __createMediaDictionary(ifm->ifm_ulist[i], filter); 717 if (options == NULL) { 718 continue; 719 } 720 721 if ((active != NULL) && (*active == NULL) && (ifm->ifm_active == ifm->ifm_ulist[i])) { 722 *active = CFRetain(options); 723 } 724 725 if ((current != NULL) && (*current == NULL) && (ifm->ifm_current == ifm->ifm_ulist[i])) { 726 *current = CFRetain(options); 727 } 728 729 if (!CFArrayContainsValue(media_options, CFRangeMake(0, CFArrayGetCount(media_options)), options)) { 730 CFArrayAppendValue(media_options, options); 731 } 732 733 CFRelease(options); 734 } 735 *available = (CFArrayRef)media_options; 736 } 737 738 if ((active != NULL) && (*active == NULL)) { 739 *active = __createMediaDictionary(ifm->ifm_active, FALSE); 740 } 741 742 if ((current != NULL) && (*current == NULL)) { 743 if ((active != NULL) && (ifm->ifm_active == ifm->ifm_current)) { 744 if (*active != NULL) *current = CFRetain(*active); 745 } else { 746 *current = __createMediaDictionary(ifm->ifm_current, FALSE); 747 } 748 } 749 750 __freeMediaList(ifm); 751 return TRUE; 752} 753 754 755CFArrayRef 756SCNetworkInterfaceCopyMediaSubTypes(CFArrayRef available) 757{ 758 CFIndex i; 759 CFIndex n; 760 CFMutableArrayRef subTypes; 761 762 if (!isA_CFArray(available)) { 763 _SCErrorSet(kSCStatusInvalidArgument); 764 return NULL; 765 } 766 767 subTypes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 768 769 n = CFArrayGetCount(available); 770 for (i = 0; i < n; i++) { 771 CFDictionaryRef options; 772 CFStringRef subType; 773 774 options = CFArrayGetValueAtIndex(available, i); 775 if (!isA_CFDictionary(options)) { 776 continue; 777 } 778 779 subType = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType); 780 if (!isA_CFString(subType)) { 781 continue; 782 } 783 784 if (!CFArrayContainsValue(subTypes, CFRangeMake(0, CFArrayGetCount(subTypes)), subType)) { 785 CFArrayAppendValue(subTypes, subType); 786 } 787 } 788 789 if (CFArrayGetCount(subTypes) == 0) { 790 CFRelease(subTypes); 791 subTypes = NULL; 792 _SCErrorSet(kSCStatusOK); 793 } 794 795 return subTypes; 796} 797 798 799CFArrayRef 800SCNetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available, 801 CFStringRef subType) 802{ 803 CFIndex i; 804 CFIndex n; 805 CFMutableArrayRef subTypeOptions; 806 807 if (!isA_CFArray(available)) { 808 _SCErrorSet(kSCStatusInvalidArgument); 809 return NULL; 810 } 811 812 subTypeOptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 813 814 n = CFArrayGetCount(available); 815 for (i = 0; i < n; i++) { 816 CFDictionaryRef options; 817 CFArrayRef mediaOptions; 818 CFStringRef mediaSubType; 819 820 options = CFArrayGetValueAtIndex(available, i); 821 if (!isA_CFDictionary(options)) { 822 continue; 823 } 824 825 mediaSubType = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType); 826 if (!isA_CFString(mediaSubType) || !CFEqual(subType, mediaSubType)) { 827 continue; 828 } 829 830 mediaOptions = CFDictionaryGetValue(options, kSCPropNetEthernetMediaOptions); 831 if (!isA_CFArray(mediaOptions)) { 832 continue; 833 } 834 835 if (!CFArrayContainsValue(subTypeOptions, CFRangeMake(0, CFArrayGetCount(subTypeOptions)), mediaOptions)) { 836 CFArrayAppendValue(subTypeOptions, mediaOptions); 837 } 838 } 839 840 if (CFArrayGetCount(subTypeOptions) == 0) { 841 CFRelease(subTypeOptions); 842 subTypeOptions = NULL; 843 _SCErrorSet(kSCStatusOK); 844 } 845 846 return subTypeOptions; 847} 848 849 850Boolean 851_SCNetworkInterfaceIsPhysicalEthernet(SCNetworkInterfaceRef interface) 852{ 853 int i; 854 struct ifmediareq *ifm; 855 CFStringRef interfaceName; 856 Boolean realEthernet = FALSE; 857 858 if (!isA_SCNetworkInterface(interface)) { 859 _SCErrorSet(kSCStatusInvalidArgument); 860 return FALSE; 861 } 862 863 interfaceName = SCNetworkInterfaceGetBSDName(interface); 864 if (interfaceName == NULL) { 865 _SCErrorSet(kSCStatusInvalidArgument); 866 return FALSE; 867 } 868 869 ifm = __copyMediaList(interfaceName); 870 if (ifm == NULL) { 871 CFStringRef interfaceType; 872 873 interfaceType = SCNetworkInterfaceGetInterfaceType(interface); 874 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeEthernet) && 875 !_SCNetworkInterfaceIsTethered(interface) && 876 !_SCNetworkInterfaceIsBluetoothPAN(interface)) { 877 // if likely physical ethernet interface 878 return TRUE; 879 } 880 return FALSE; 881 } 882 _SCErrorSet(kSCStatusOK); 883 if (IFM_TYPE(ifm->ifm_current) != IFM_ETHER) { 884 goto done; 885 } 886 if (ifm->ifm_count == 1 887 && IFM_SUBTYPE(ifm->ifm_ulist[0]) == IFM_AUTO) { 888 /* only support autoselect, not really ethernet */ 889 goto done; 890 } 891 for (i = 0; i < ifm->ifm_count; i++) { 892 if ((ifm->ifm_ulist[i] & IFM_FDX) != 0) { 893 realEthernet = TRUE; 894 break; 895 } 896 } 897 done: 898 __freeMediaList(ifm); 899 return (realEthernet); 900} 901 902static Boolean 903__getIOMTULimits(char ifr_name[IFNAMSIZ], 904 int *mtu_min, 905 int *mtu_max) 906{ 907 int ifType = 0; 908 io_iterator_t io_iter = 0; 909 io_registry_entry_t io_interface = 0; 910 io_registry_entry_t io_controller = 0; 911 kern_return_t kr; 912 static mach_port_t masterPort = MACH_PORT_NULL; 913 CFMutableDictionaryRef matchingDict; 914 915 /* look for a matching interface in the IORegistry */ 916 917 if (masterPort == MACH_PORT_NULL) { 918 kr = IOMasterPort(MACH_PORT_NULL, &masterPort); 919 if (kr != KERN_SUCCESS) { 920 return FALSE; 921 } 922 } 923 924 matchingDict = IOBSDNameMatching(masterPort, 0, ifr_name); 925 if (matchingDict) { 926 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */ 927 kr = IOServiceGetMatchingServices(masterPort, matchingDict, &io_iter); 928 if ((kr == KERN_SUCCESS) && io_iter) { 929 /* should only have a single match */ 930 io_interface = IOIteratorNext(io_iter); 931 } 932 if (io_iter) IOObjectRelease(io_iter); 933 } 934 935 if (io_interface) { 936 CFNumberRef num; 937 938 /* 939 * found an interface, get the interface type 940 */ 941 num = IORegistryEntryCreateCFProperty(io_interface, CFSTR(kIOInterfaceType), NULL, kNilOptions); 942 if (num) { 943 if (isA_CFNumber(num)) { 944 CFNumberGetValue(num, kCFNumberIntType, &ifType); 945 } 946 CFRelease(num); 947 } 948 949 /* 950 * ...and the property we are REALLY interested is in the controller, 951 * which is the parent of the interface object. 952 */ 953 (void)IORegistryEntryGetParentEntry(io_interface, kIOServicePlane, &io_controller); 954 IOObjectRelease(io_interface); 955 } else { 956 /* if no matching interface */ 957 return FALSE; 958 } 959 960 if (io_controller) { 961 CFNumberRef num; 962 963 num = IORegistryEntryCreateCFProperty(io_controller, CFSTR(kIOMaxPacketSize), NULL, kNilOptions); 964 if (num) { 965 if (isA_CFNumber(num)) { 966 int value; 967 968 /* 969 * Get the value and subtract the FCS bytes and Ethernet header 970 * sizes from the maximum frame size reported by the controller 971 * to get the MTU size. The 14 byte media header can be found 972 * in the registry, but not the size for the trailing FCS bytes. 973 */ 974 CFNumberGetValue(num, kCFNumberIntType, &value); 975 976 if (ifType == IFT_ETHER) { 977 value -= (ETHER_HDR_LEN + ETHER_CRC_LEN); 978 } 979 980 if (mtu_min) *mtu_min = IF_MINMTU; 981 if (mtu_max) *mtu_max = value; 982 } 983 CFRelease(num); 984 } 985 986 IOObjectRelease(io_controller); 987 } 988 989 return TRUE; 990} 991 992 993Boolean 994SCNetworkInterfaceCopyMTU(SCNetworkInterfaceRef interface, 995 int *mtu_cur, 996 int *mtu_min, 997 int *mtu_max) 998{ 999 struct ifreq ifr; 1000 CFStringRef interfaceName; 1001 Boolean ok = FALSE; 1002 int sock = -1; 1003 1004 if (!isA_SCNetworkInterface(interface)) { 1005 _SCErrorSet(kSCStatusInvalidArgument); 1006 return FALSE; 1007 } 1008 1009 interfaceName = SCNetworkInterfaceGetBSDName(interface); 1010 if (interfaceName == NULL) { 1011 _SCErrorSet(kSCStatusInvalidArgument); 1012 return FALSE; 1013 } 1014 1015 memset((void *)&ifr, 0, sizeof(ifr)); 1016 if (_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) == NULL) { 1017 SC_log(LOG_NOTICE, "could not convert interface name"); 1018 _SCErrorSet(kSCStatusInvalidArgument); 1019 return FALSE; 1020 } 1021 1022 sock = socket(AF_INET, SOCK_DGRAM, 0); 1023 if (sock == -1) { 1024 _SCErrorSet(errno); 1025 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno)); 1026 return FALSE; 1027 } 1028 1029 if (ioctl(sock, SIOCGIFMTU, (caddr_t)&ifr) == -1) { 1030 _SCErrorSet(errno); 1031// SC_log(LOG_NOTICE, "ioctl(SIOCGIFMTU) failed: %s", strerror(errno)); 1032 goto done; 1033 } 1034 1035 if (mtu_cur) *mtu_cur = ifr.ifr_mtu; 1036 if (mtu_min) *mtu_min = ifr.ifr_mtu; 1037 if (mtu_max) *mtu_max = ifr.ifr_mtu; 1038 1039 /* get valid MTU range */ 1040 1041 if (mtu_min != NULL || mtu_max != NULL) { 1042 if (ioctl(sock, SIOCGIFDEVMTU, (caddr_t)&ifr) == 0) { 1043 struct ifdevmtu * devmtu_p; 1044 1045 devmtu_p = &ifr.ifr_devmtu; 1046 if (mtu_min != NULL) { 1047 *mtu_min = (devmtu_p->ifdm_min > IF_MINMTU) 1048 ? devmtu_p->ifdm_min : IF_MINMTU; 1049 } 1050 if (mtu_max != NULL) { 1051 *mtu_max = devmtu_p->ifdm_max; 1052 } 1053 } else { 1054 ok = __getIOMTULimits(ifr.ifr_name, mtu_min, mtu_max); 1055 if (!ok) { 1056 CFStringRef interfaceType; 1057 1058 interfaceType = SCNetworkInterfaceGetInterfaceType(interface); 1059 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) { 1060 CFIndex i; 1061 CFArrayRef members; 1062 CFIndex n; 1063 1064 members = SCBridgeInterfaceGetMemberInterfaces(interface); 1065 n = (members != NULL) ? CFArrayGetCount(members) : 0; 1066 if (n > 1) { 1067 if (mtu_min) *mtu_min = IF_MINMTU; 1068 if (mtu_max) *mtu_max = IF_MAXMTU; 1069 } 1070 for (i = 0; i < n; i++) { 1071 SCNetworkInterfaceRef member; 1072 int member_mtu_min; 1073 int member_mtu_max; 1074 1075 member = CFArrayGetValueAtIndex(members, i); 1076 ok = SCNetworkInterfaceCopyMTU(member, NULL, &member_mtu_min, &member_mtu_max); 1077 if (ok) { 1078 if ((mtu_min != NULL) && (*mtu_min < member_mtu_min)) { 1079 *mtu_min = member_mtu_min; // min MTU needs to be higher 1080 } 1081 if ((mtu_max != NULL) && (*mtu_max > member_mtu_max)) { 1082 *mtu_max = member_mtu_max; // max MTU needs to be lower 1083 } 1084 } 1085 } 1086 } 1087 } 1088 } 1089 1090 if (mtu_min != NULL) { 1091#if IP_MSS > IPV6_MMTU 1092 if (*mtu_min < IP_MSS) { 1093 /* bump up the minimum MTU */ 1094 *mtu_min = IP_MSS/*576*/; 1095 } 1096#else // IP_MSS > IPV6_MMTU 1097 if (*mtu_min < IPV6_MMTU) { 1098 /* bump up the minimum MTU */ 1099 *mtu_min = IPV6_MMTU; 1100 } 1101#endif // IP_MSS > IPV6_MMTU 1102 1103 if ((mtu_cur != NULL) && (*mtu_min > *mtu_cur)) { 1104 /* min must be <= cur */ 1105 *mtu_min = *mtu_cur; 1106 } 1107 1108 if ((mtu_max != NULL) && (*mtu_min > *mtu_max)) { 1109 /* min must be <= max */ 1110 *mtu_min = *mtu_max; 1111 } 1112 } 1113 } 1114 1115 ok = TRUE; 1116 1117 done : 1118 1119 (void)close(sock); 1120 return ok; 1121} 1122 1123 1124Boolean 1125SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface, 1126 CFStringRef subtype, 1127 CFArrayRef options) 1128{ 1129 CFDictionaryRef configuration; 1130 CFMutableDictionaryRef newConfiguration = NULL; 1131 Boolean ok = FALSE; 1132 1133 if (!isA_SCNetworkInterface(interface)) { 1134 _SCErrorSet(kSCStatusInvalidArgument); 1135 return FALSE; 1136 } 1137 1138 configuration = SCNetworkInterfaceGetConfiguration(interface); 1139 if (configuration == NULL) { 1140 newConfiguration = CFDictionaryCreateMutable(NULL, 1141 0, 1142 &kCFTypeDictionaryKeyCallBacks, 1143 &kCFTypeDictionaryValueCallBacks); 1144 } else { 1145 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration); 1146 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive); 1147 } 1148 1149 if (subtype != NULL) { 1150 CFArrayRef available = NULL; 1151 CFArrayRef config_options = options; 1152 CFArrayRef subtypes = NULL; 1153 CFArrayRef subtype_options = NULL; 1154 1155 if (options == NULL) { 1156 config_options = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); 1157 } 1158 1159 if (!SCNetworkInterfaceCopyMediaOptions(interface, NULL, NULL, &available, FALSE)) { 1160 SC_log(LOG_INFO, "media type / options not available"); 1161 goto checked; 1162 } 1163 1164 if (available == NULL) { 1165 _SCErrorSet(kSCStatusInvalidArgument); 1166 goto checked; 1167 } 1168 1169 subtypes = SCNetworkInterfaceCopyMediaSubTypes(available); 1170 if ((subtypes == NULL) || 1171 !CFArrayContainsValue(subtypes, 1172 CFRangeMake(0, CFArrayGetCount(subtypes)), 1173 subtype)) { 1174 SC_log(LOG_INFO, "media type not valid"); 1175 _SCErrorSet(kSCStatusInvalidArgument); 1176 goto checked; 1177 } 1178 1179 subtype_options = SCNetworkInterfaceCopyMediaSubTypeOptions(available, subtype); 1180 if ((subtype_options == NULL) || 1181 !CFArrayContainsValue(subtype_options, 1182 CFRangeMake(0, CFArrayGetCount(subtype_options)), 1183 config_options)) { 1184 SC_log(LOG_INFO, "media options not valid for \"%@\"", subtype); 1185 _SCErrorSet(kSCStatusInvalidArgument); 1186 goto checked; 1187 } 1188 1189 CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMediaSubType, subtype); 1190 CFDictionarySetValue(newConfiguration, 1191 kSCPropNetEthernetMediaOptions, 1192 (options != NULL) ? options : config_options); 1193 1194 ok = TRUE; 1195 1196 checked : 1197 1198 if (available != NULL) CFRelease(available); 1199 if (subtypes != NULL) CFRelease(subtypes); 1200 if (subtype_options != NULL) CFRelease(subtype_options); 1201 if (options == NULL) CFRelease(config_options); 1202 } else if (options == NULL) { 1203 CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMediaSubType); 1204 CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMediaOptions); 1205 if (CFDictionaryGetCount(newConfiguration) == 0) { 1206 CFRelease(newConfiguration); 1207 newConfiguration = NULL; 1208 } 1209 ok = TRUE; 1210 } else { 1211 SC_log(LOG_INFO, "media type must be specified with options"); 1212 _SCErrorSet(kSCStatusInvalidArgument); 1213 } 1214 1215 if (ok) { 1216 ok = SCNetworkInterfaceSetConfiguration(interface, newConfiguration); 1217 } 1218 1219 if (newConfiguration != NULL) CFRelease(newConfiguration); 1220 return ok; 1221} 1222 1223 1224Boolean 1225SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface, 1226 int mtu) 1227{ 1228 CFDictionaryRef configuration; 1229 int mtu_max; 1230 int mtu_min; 1231 CFMutableDictionaryRef newConfiguration = NULL; 1232 Boolean ok = FALSE; 1233 1234 if (!isA_SCNetworkInterface(interface)) { 1235 _SCErrorSet(kSCStatusInvalidArgument); 1236 return FALSE; 1237 } 1238 1239 if (!SCNetworkInterfaceCopyMTU(interface, NULL, &mtu_min, &mtu_max)) { 1240 SC_log(LOG_INFO, "MTU bounds not available"); 1241 return FALSE; 1242 } 1243 1244 configuration = SCNetworkInterfaceGetConfiguration(interface); 1245 if (configuration == NULL) { 1246 newConfiguration = CFDictionaryCreateMutable(NULL, 1247 0, 1248 &kCFTypeDictionaryKeyCallBacks, 1249 &kCFTypeDictionaryValueCallBacks); 1250 } else { 1251 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration); 1252 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive); 1253 } 1254 1255 if ((mtu >= mtu_min) && (mtu <= mtu_max)) { 1256 CFNumberRef num; 1257 1258 num = CFNumberCreate(NULL, kCFNumberIntType, &mtu); 1259 CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMTU, num); 1260 CFRelease(num); 1261 ok = TRUE; 1262 } else if (mtu == 0) { 1263 CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMTU); 1264 if (CFDictionaryGetCount(newConfiguration) == 0) { 1265 CFRelease(newConfiguration); 1266 newConfiguration = NULL; 1267 } 1268 ok = TRUE; 1269 } else { 1270 SC_log(LOG_INFO, "MTU out of range"); 1271 _SCErrorSet(kSCStatusInvalidArgument); 1272 } 1273 1274 if (ok) { 1275 ok = SCNetworkInterfaceSetConfiguration(interface, newConfiguration); 1276 } 1277 1278 if (newConfiguration != NULL) CFRelease(newConfiguration); 1279 return ok; 1280}