this repo has no description
at fixPythonPipStalling 1098 lines 28 kB view raw
1/* 2 * Copyright (c) 2003-2013, 2015-2018 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 * November 14, 2003 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 <net/ethernet.h> 48#define KERNEL_PRIVATE 49#include <net/if.h> 50#include <net/if_var.h> 51#undef KERNEL_PRIVATE 52#include <net/if_vlan_var.h> 53#include <net/if_types.h> 54 55/* ---------- VLAN support ---------- */ 56 57static int 58inet_dgram_socket() 59{ 60 int s; 61 62 s = socket(AF_INET, SOCK_DGRAM, 0); 63 if (s == -1) { 64 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno)); 65 } 66 67 return s; 68} 69 70 71typedef struct { 72 CFMutableArrayRef vlans; 73 SCPreferencesRef ni_prefs; 74 SCPreferencesRef prefs; 75} addContext, *addContextRef; 76 77 78static void 79add_configured_interface(const void *key, const void *value, void *context) 80{ 81 SCNetworkInterfacePrivateRef interfacePrivate; 82 addContextRef myContext = (addContextRef)context; 83 SCVLANInterfaceRef vlan; 84 CFStringRef vlan_if = (CFStringRef)key; 85 CFDictionaryRef vlan_info = (CFDictionaryRef)value; 86 CFStringRef vlan_name; 87 CFDictionaryRef vlan_options; 88 SCNetworkInterfaceRef vlan_physical = NULL; 89 CFStringRef vlan_physical_if; 90 CFNumberRef vlan_tag; 91 92 vlan_physical_if = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANInterface); 93 if (!isA_CFString(vlan_physical_if)) { 94 // if prefs are confused 95 return; 96 } 97 98 vlan_tag = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANTag); 99 if (!isA_CFNumber(vlan_tag)) { 100 // if prefs are confused 101 return; 102 } 103 104 // create the VLAN interface 105 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if); 106 assert(vlan != NULL); 107 108 // set physical interface and tag 109 if (myContext->ni_prefs != NULL) { 110 vlan_physical = __SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(NULL, myContext->ni_prefs, 111 vlan_physical_if); 112 } 113 if (vlan_physical == NULL) { 114 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if, 115 kIncludeBondInterfaces); 116 } 117 assert(vlan_physical != NULL); 118 119 // since we KNOW that the physical interface supported VLANs when 120 // it was first established it's OK to force that state here ... 121 // and this is needed for the case when the interface (e.g. a 122 // dongle) is not currently attached to the system 123 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan_physical; 124 interfacePrivate->supportsVLAN = TRUE; 125 126 // and now we associate the physical interface and tag 127 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag); 128 CFRelease(vlan_physical); 129 130 // set display name 131 vlan_name = CFDictionaryGetValue(vlan_info, kSCPropUserDefinedName); 132 if (isA_CFString(vlan_name)) { 133 SCVLANInterfaceSetLocalizedDisplayName(vlan, vlan_name); 134 } 135 136 // set options 137 vlan_options = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANOptions); 138 if (isA_CFDictionary(vlan_options)) { 139 SCVLANInterfaceSetOptions(vlan, vlan_options); 140 } 141 142 // estabish link to the stored configuration 143 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; 144 interfacePrivate->prefs = CFRetain(myContext->prefs); 145 146 CFArrayAppendValue(myContext->vlans, vlan); 147 CFRelease(vlan); 148 149 return; 150} 151 152 153static SCVLANInterfaceRef 154findVLANInterfaceAndTag(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag) 155{ 156 CFIndex i; 157 CFIndex n; 158 SCVLANInterfaceRef vlan = NULL; 159 CFArrayRef vlans; 160 161 vlans = SCVLANInterfaceCopyAll(prefs); 162 163 n = CFArrayGetCount(vlans); 164 for (i = 0; i < n; i++) { 165 SCVLANInterfaceRef config_vlan; 166 SCNetworkInterfaceRef config_physical; 167 CFNumberRef config_tag; 168 169 config_vlan = CFArrayGetValueAtIndex(vlans, i); 170 config_physical = SCVLANInterfaceGetPhysicalInterface(config_vlan); 171 config_tag = SCVLANInterfaceGetTag(config_vlan); 172 173 if ((config_physical != NULL) && (config_tag != NULL)) { 174 if (!CFEqual(physical, config_physical)) { 175 // if this VLAN has a different physical interface 176 continue; 177 } 178 179 if (!CFEqual(tag, config_tag)) { 180 // if this VLAN has a different tag 181 continue; 182 } 183 184 vlan = CFRetain(config_vlan); 185 break; 186 } 187 } 188 CFRelease(vlans); 189 190 return vlan; 191} 192 193 194#pragma mark - 195#pragma mark SCVLANInterface APIs 196 197 198static __inline__ void 199my_CFDictionaryApplyFunction(CFDictionaryRef theDict, 200 CFDictionaryApplierFunction applier, 201 void *context) 202{ 203 CFAllocatorRef myAllocator; 204 CFDictionaryRef myDict; 205 206 myAllocator = CFGetAllocator(theDict); 207 myDict = CFDictionaryCreateCopy(myAllocator, theDict); 208 CFDictionaryApplyFunction(myDict, applier, context); 209 CFRelease(myDict); 210 return; 211} 212 213 214CFArrayRef 215SCVLANInterfaceCopyAll(SCPreferencesRef prefs) 216{ 217 addContext context; 218 CFDictionaryRef dict; 219 SCPreferencesRef ni_prefs; 220 CFStringRef path; 221 222 if (__SCPreferencesUsingDefaultPrefs(prefs)) { 223 ni_prefs = NULL; 224 } else { 225 ni_prefs = __SCPreferencesCreateNIPrefsFromPrefs(prefs); 226 } 227 context.vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 228 context.ni_prefs = ni_prefs; 229 context.prefs = prefs; 230 231 path = CFStringCreateWithFormat(NULL, 232 NULL, 233 CFSTR("/%@/%@"), 234 kSCPrefVirtualNetworkInterfaces, 235 kSCNetworkInterfaceTypeVLAN); 236 dict = SCPreferencesPathGetValue(prefs, path); 237 CFRelease(path); 238 if (isA_CFDictionary(dict)) { 239 my_CFDictionaryApplyFunction(dict, add_configured_interface, &context); 240 } 241 if (ni_prefs != NULL) { 242 CFRelease(ni_prefs); 243 } 244 return context.vlans; 245} 246 247 248static void 249addAvailableInterfaces(CFMutableArrayRef available, CFArrayRef interfaces, 250 CFSetRef excluded) 251{ 252 CFIndex i; 253 CFIndex n; 254 255 n = CFArrayGetCount(interfaces); 256 for (i = 0; i < n; i++) { 257 SCNetworkInterfaceRef interface; 258 SCNetworkInterfacePrivateRef interfacePrivate; 259 260 interface = CFArrayGetValueAtIndex(interfaces, i); 261 interfacePrivate = (SCNetworkInterfacePrivateRef)interface; 262 263 if ((excluded != NULL) 264 && CFSetContainsValue(excluded, interface)) { 265 // exclude this interface 266 continue; 267 } 268 if (interfacePrivate->supportsVLAN) { 269 // if this interface is available 270 CFArrayAppendValue(available, interface); 271 } 272 } 273 274 return; 275} 276 277 278CFArrayRef 279SCVLANInterfaceCopyAvailablePhysicalInterfaces() 280{ 281 CFMutableArrayRef available; 282#if !TARGET_OS_IPHONE 283 CFArrayRef bond_interfaces = NULL; 284#endif // !TARGET_OS_IPHONE 285 CFArrayRef bridge_interfaces = NULL; 286 CFMutableSetRef excluded = NULL; 287 CFArrayRef interfaces; 288 SCPreferencesRef prefs; 289 290 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 291 292 prefs = SCPreferencesCreate(NULL, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL); 293 if (prefs != NULL) { 294#if !TARGET_OS_IPHONE 295 bond_interfaces = SCBondInterfaceCopyAll(prefs); 296 if (bond_interfaces != NULL) { 297 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); 298 __SCBondInterfaceListCollectMembers(bond_interfaces, excluded); 299 } 300#endif // !TARGET_OS_IPHONE 301 302 bridge_interfaces = SCBridgeInterfaceCopyAll(prefs); 303 if (bridge_interfaces != NULL) { 304 if (excluded == NULL) { 305 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); 306 } 307 __SCBridgeInterfaceListCollectMembers(bridge_interfaces, excluded); 308 } 309 310 CFRelease(prefs); 311 } 312 313 // add real interfaces that aren't part of a bond or bridge 314 interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(FALSE); 315 if (interfaces != NULL) { 316 addAvailableInterfaces(available, interfaces, excluded); 317 CFRelease(interfaces); 318 } 319 320#if !TARGET_OS_IPHONE 321 // add bond interfaces 322 if (bond_interfaces != NULL) { 323 addAvailableInterfaces(available, bond_interfaces, NULL); 324 CFRelease(bond_interfaces); 325 } 326#endif // !TARGET_OS_IPHONE 327 328 // add bridge interfaces 329 if (bridge_interfaces != NULL) { 330 addAvailableInterfaces(available, bridge_interfaces, NULL); 331 CFRelease(bridge_interfaces); 332 } 333 334 if (excluded != NULL) { 335 CFRelease(excluded); 336 } 337 338 return available; 339} 340 341 342CFArrayRef 343_SCVLANInterfaceCopyActive(void) 344{ 345 struct ifaddrs *ifap; 346 struct ifaddrs *ifp; 347 int s; 348 CFMutableArrayRef vlans = NULL; 349 350 if (getifaddrs(&ifap) == -1) { 351 SC_log(LOG_NOTICE, "getifaddrs() failed: %s", strerror(errno)); 352 _SCErrorSet(kSCStatusFailed); 353 return NULL; 354 } 355 356 s = inet_dgram_socket(); 357 if (s == -1) { 358 _SCErrorSet(errno); 359 goto done; 360 } 361 362 vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 363 364 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) { 365 struct if_data *if_data; 366 struct ifreq ifr; 367 SCVLANInterfaceRef vlan; 368 CFStringRef vlan_if; 369 SCNetworkInterfaceRef vlan_physical; 370 CFStringRef vlan_physical_if; 371 CFNumberRef vlan_tag; 372 char vlr_parent[IFNAMSIZ]; 373 int vlr_tag; 374 struct vlanreq vreq; 375 376 if_data = (struct if_data *)ifp->ifa_data; 377 if (if_data == NULL 378 || ifp->ifa_addr->sa_family != AF_LINK 379 || if_data->ifi_type != IFT_L2VLAN) { 380 continue; 381 } 382 383 memset(&ifr, 0, sizeof(ifr)); 384 memset(&vreq, 0, sizeof(vreq)); 385 strlcpy(ifr.ifr_name, ifp->ifa_name, sizeof(ifr.ifr_name)); 386 ifr.ifr_data = (caddr_t)&vreq; 387 388 if (ioctl(s, SIOCGIFVLAN, (caddr_t)&ifr) == -1) { 389 SC_log(LOG_NOTICE, "ioctl(SIOCGIFVLAN) failed: %s", strerror(errno)); 390 CFRelease(vlans); 391 vlans = NULL; 392 _SCErrorSet(kSCStatusFailed); 393 goto done; 394 } 395 396 // create the VLAN interface 397 vlan_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII); 398 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if); 399 assert(vlan != NULL); 400 CFRelease(vlan_if); 401 402 // set the physical interface and tag 403 strlcpy(vlr_parent, vreq.vlr_parent, sizeof(vlr_parent)); 404 vlan_physical_if = CFStringCreateWithCString(NULL, vlr_parent, kCFStringEncodingASCII); 405 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if, 406 kIncludeBondInterfaces); 407 assert(vlan_physical != NULL); 408 CFRelease(vlan_physical_if); 409 410 vlr_tag = vreq.vlr_tag; 411 vlan_tag = CFNumberCreate(NULL, kCFNumberIntType, &vlr_tag); 412 assert(vlan_tag != NULL); 413 414 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag); 415 CFRelease(vlan_physical); 416 CFRelease(vlan_tag); 417 418 // add VLAN 419 CFArrayAppendValue(vlans, vlan); 420 CFRelease(vlan); 421 } 422 423 done : 424 425 if (s != -1) { 426 (void) close(s); 427 } 428 freeifaddrs(ifap); 429 return vlans; 430} 431 432 433SCVLANInterfaceRef 434SCVLANInterfaceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag) 435{ 436 CFAllocatorRef allocator; 437 CFIndex i; 438 SCNetworkInterfacePrivateRef interfacePrivate; 439 SCVLANInterfaceRef vlan; 440 441 if (prefs == NULL) { 442 _SCErrorSet(kSCStatusInvalidArgument); 443 return NULL; 444 } 445 446 if (!isA_SCNetworkInterface(physical)) { 447 _SCErrorSet(kSCStatusInvalidArgument); 448 return NULL; 449 } 450 451 interfacePrivate = (SCNetworkInterfacePrivateRef)physical; 452 if (!interfacePrivate->supportsVLAN) { 453 if (!__SCPreferencesUsingDefaultPrefs(prefs)) { 454 interfacePrivate->supportsVLAN = TRUE; 455 } else { 456 _SCErrorSet(kSCStatusInvalidArgument); 457 return NULL; 458 } 459 } 460 461 if (isA_CFNumber(tag)) { 462 int tag_val; 463 464 CFNumberGetValue(tag, kCFNumberIntType, &tag_val); 465 if ((tag_val < 1) || (tag_val > 4094)) { 466 _SCErrorSet(kSCStatusInvalidArgument); 467 return NULL; 468 } 469 } else { 470 _SCErrorSet(kSCStatusInvalidArgument); 471 return NULL; 472 } 473 474 // make sure that physical interface and tag are not used 475 vlan = findVLANInterfaceAndTag(prefs, physical, tag); 476 if (vlan != NULL) { 477 CFRelease(vlan); 478 _SCErrorSet(kSCStatusKeyExists); 479 return NULL; 480 } 481 482 allocator = CFGetAllocator(prefs); 483 484 // create a new VLAN using an unused interface name 485 for (i = 0; vlan == NULL; i++) { 486 CFDictionaryRef dict; 487 CFStringRef vlan_if; 488 Boolean ok; 489 CFStringRef path; 490 491 vlan_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("vlan%ld"), i); 492 path = CFStringCreateWithFormat(allocator, 493 NULL, 494 CFSTR("/%@/%@/%@"), 495 kSCPrefVirtualNetworkInterfaces, 496 kSCNetworkInterfaceTypeVLAN, 497 vlan_if); 498 dict = SCPreferencesPathGetValue(prefs, path); 499 if (dict != NULL) { 500 // if VLAN interface name not available 501 CFRelease(path); 502 CFRelease(vlan_if); 503 continue; 504 } 505 506 // add the VLAN to the stored preferences 507 dict = CFDictionaryCreate(allocator, 508 NULL, NULL, 0, 509 &kCFTypeDictionaryKeyCallBacks, 510 &kCFTypeDictionaryValueCallBacks); 511 ok = SCPreferencesPathSetValue(prefs, path, dict); 512 CFRelease(dict); 513 CFRelease(path); 514 if (!ok) { 515 // if the VLAN could not be saved 516 CFRelease(vlan_if); 517 _SCErrorSet(kSCStatusFailed); 518 break; 519 } 520 521 // create the SCVLANInterfaceRef 522 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(allocator, vlan_if); 523 CFRelease(vlan_if); 524 525 // estabish link to the stored configuration 526 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; 527 interfacePrivate->prefs = CFRetain(prefs); 528 529 // set physical interface and tag 530 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, physical, tag); 531 } 532 533 return vlan; 534} 535 536 537Boolean 538SCVLANInterfaceRemove(SCVLANInterfaceRef vlan) 539{ 540 CFStringRef vlan_if; 541 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; 542 Boolean ok; 543 CFStringRef path; 544 545 if (!isA_SCVLANInterface(vlan)) { 546 _SCErrorSet(kSCStatusInvalidArgument); 547 return FALSE; 548 } 549 550 if (interfacePrivate->prefs == NULL) { 551 _SCErrorSet(kSCStatusInvalidArgument); 552 return FALSE; 553 } 554 555 vlan_if = SCNetworkInterfaceGetBSDName(vlan); 556 path = CFStringCreateWithFormat(NULL, 557 NULL, 558 CFSTR("/%@/%@/%@"), 559 kSCPrefVirtualNetworkInterfaces, 560 kSCNetworkInterfaceTypeVLAN, 561 vlan_if); 562 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path); 563 CFRelease(path); 564 565 return ok; 566} 567 568 569SCNetworkInterfaceRef 570SCVLANInterfaceGetPhysicalInterface(SCVLANInterfaceRef vlan) 571{ 572 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; 573 574 if (!isA_SCVLANInterface(vlan)) { 575 _SCErrorSet(kSCStatusInvalidArgument); 576 return NULL; 577 } 578 579 return interfacePrivate->vlan.interface; 580} 581 582 583CFNumberRef 584SCVLANInterfaceGetTag(SCVLANInterfaceRef vlan) 585{ 586 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; 587 588 if (!isA_SCVLANInterface(vlan)) { 589 _SCErrorSet(kSCStatusInvalidArgument); 590 return NULL; 591 } 592 593 return interfacePrivate->vlan.tag; 594} 595 596 597CFDictionaryRef 598SCVLANInterfaceGetOptions(SCVLANInterfaceRef vlan) 599{ 600 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; 601 602 if (!isA_SCVLANInterface(vlan)) { 603 _SCErrorSet(kSCStatusInvalidArgument); 604 return NULL; 605 } 606 607 return interfacePrivate->vlan.options; 608} 609 610 611Boolean 612SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan, SCNetworkInterfaceRef physical, CFNumberRef tag) 613{ 614 SCNetworkInterfacePrivateRef interfacePrivate; 615 Boolean ok = TRUE; 616 SCPreferencesRef prefs; 617 618 if (!isA_SCVLANInterface(vlan)) { 619 _SCErrorSet(kSCStatusInvalidArgument); 620 return FALSE; 621 } 622 623 if (!isA_SCNetworkInterface(physical)) { 624 _SCErrorSet(kSCStatusInvalidArgument); 625 return FALSE; 626 } 627 628 interfacePrivate = (SCNetworkInterfacePrivateRef)physical; 629 prefs = interfacePrivate->prefs; 630 631 if (!interfacePrivate->supportsVLAN) { 632 if (!__SCPreferencesUsingDefaultPrefs(prefs)) { 633 interfacePrivate->supportsVLAN = TRUE; 634 } else { 635 _SCErrorSet(kSCStatusInvalidArgument); 636 return FALSE; 637 } 638 } 639 640 if (isA_CFNumber(tag)) { 641 int tag_val; 642 643 CFNumberGetValue(tag, kCFNumberIntType, &tag_val); 644 if ((tag_val < 1) || (tag_val > 4094)) { 645 _SCErrorSet(kSCStatusInvalidArgument); 646 return FALSE; 647 } 648 } else { 649 _SCErrorSet(kSCStatusInvalidArgument); 650 return FALSE; 651 } 652 653 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; 654 if (interfacePrivate->prefs != NULL) { 655 SCVLANInterfaceRef config_vlan; 656 CFDictionaryRef dict; 657 CFMutableDictionaryRef newDict; 658 CFStringRef path; 659 660 // make sure that physical interface and tag are not used 661 config_vlan = findVLANInterfaceAndTag(interfacePrivate->prefs, physical, tag); 662 if (config_vlan != NULL) { 663 if (!CFEqual(vlan, config_vlan)) { 664 CFRelease(config_vlan); 665 _SCErrorSet(kSCStatusKeyExists); 666 return FALSE; 667 } 668 CFRelease(config_vlan); 669 } 670 671 // set interface/tag in the stored preferences 672 path = CFStringCreateWithFormat(NULL, 673 NULL, 674 CFSTR("/%@/%@/%@"), 675 kSCPrefVirtualNetworkInterfaces, 676 kSCNetworkInterfaceTypeVLAN, 677 interfacePrivate->entity_device); 678 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path); 679 if (!isA_CFDictionary(dict)) { 680 // if the prefs are confused 681 CFRelease(path); 682 _SCErrorSet(kSCStatusFailed); 683 return FALSE; 684 } 685 686 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 687 CFDictionarySetValue(newDict, 688 kSCPropVirtualNetworkInterfacesVLANInterface, 689 SCNetworkInterfaceGetBSDName(physical)); 690 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANTag, tag); 691 if (!CFEqual(dict, newDict)) { 692 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict); 693 } 694 CFRelease(newDict); 695 CFRelease(path); 696 } 697 698 if (ok) { 699 SCNetworkInterfacePrivateRef newInterface; 700 CFTypeRef save; 701 702 // set physical interface 703 newInterface = __SCNetworkInterfaceCreateCopy(NULL, 704 physical, 705 interfacePrivate->prefs, 706 interfacePrivate->serviceID); 707 save = interfacePrivate->vlan.interface; 708 interfacePrivate->vlan.interface = (SCNetworkInterfaceRef)newInterface; 709 if (save != NULL) CFRelease(save); 710 711 // set tag 712 save = interfacePrivate->vlan.tag; 713 interfacePrivate->vlan.tag = CFRetain(tag); 714 if (save != NULL) CFRelease(save); 715 } 716 717 return ok; 718} 719 720 721Boolean 722SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan, CFStringRef newName) 723{ 724 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; 725 Boolean ok = TRUE; 726 727 if (!isA_SCVLANInterface(vlan)) { 728 _SCErrorSet(kSCStatusInvalidArgument); 729 return FALSE; 730 } 731 732 if ((newName != NULL) && !isA_CFString(newName)) { 733 _SCErrorSet(kSCStatusInvalidArgument); 734 return FALSE; 735 } 736 737 // set name in the stored preferences 738 if (interfacePrivate->prefs != NULL) { 739 CFDictionaryRef dict; 740 CFMutableDictionaryRef newDict; 741 CFStringRef path; 742 743 path = CFStringCreateWithFormat(NULL, 744 NULL, 745 CFSTR("/%@/%@/%@"), 746 kSCPrefVirtualNetworkInterfaces, 747 kSCNetworkInterfaceTypeVLAN, 748 interfacePrivate->entity_device); 749 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path); 750 if (!isA_CFDictionary(dict)) { 751 // if the prefs are confused 752 CFRelease(path); 753 _SCErrorSet(kSCStatusFailed); 754 return FALSE; 755 } 756 757 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 758 if (newName != NULL) { 759 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName); 760 } else { 761 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName); 762 } 763 if (!CFEqual(dict, newDict)) { 764 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict); 765 } 766 CFRelease(newDict); 767 CFRelease(path); 768 } 769 770 // set name in the SCVLANInterfaceRef 771 if (ok) { 772 if (interfacePrivate->localized_name != NULL) { 773 CFRelease(interfacePrivate->localized_name); 774 interfacePrivate->localized_name = NULL; 775 } 776 if (newName != NULL) { 777 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName); 778 } 779 } 780 781 return ok; 782} 783 784 785Boolean 786SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan, CFDictionaryRef newOptions) 787{ 788 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; 789 Boolean ok = TRUE; 790 791 if (!isA_SCVLANInterface(vlan)) { 792 _SCErrorSet(kSCStatusInvalidArgument); 793 return FALSE; 794 } 795 796 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) { 797 _SCErrorSet(kSCStatusInvalidArgument); 798 return FALSE; 799 } 800 801 // set options in the stored preferences 802 if (interfacePrivate->prefs != NULL) { 803 CFDictionaryRef dict; 804 CFMutableDictionaryRef newDict; 805 CFStringRef path; 806 807 path = CFStringCreateWithFormat(NULL, 808 NULL, 809 CFSTR("/%@/%@/%@"), 810 kSCPrefVirtualNetworkInterfaces, 811 kSCNetworkInterfaceTypeVLAN, 812 interfacePrivate->entity_device); 813 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path); 814 if (!isA_CFDictionary(dict)) { 815 // if the prefs are confused 816 CFRelease(path); 817 _SCErrorSet(kSCStatusFailed); 818 return FALSE; 819 } 820 821 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 822 if (newOptions != NULL) { 823 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions, newOptions); 824 } else { 825 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions); 826 } 827 if (!CFEqual(dict, newDict)) { 828 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict); 829 } 830 CFRelease(newDict); 831 CFRelease(path); 832 } 833 834 // set options in the SCVLANInterfaceRef 835 if (ok) { 836 if (interfacePrivate->vlan.options != NULL) { 837 CFRelease(interfacePrivate->vlan.options); 838 interfacePrivate->vlan.options = NULL; 839 } 840 if (newOptions != NULL) { 841 interfacePrivate->vlan.options = CFDictionaryCreateCopy(NULL, newOptions); 842 } 843 } 844 845 return ok; 846} 847 848 849#pragma mark - 850#pragma mark SCVLANInterface management 851 852 853static Boolean 854__vlan_set(int s, CFStringRef interface_if, CFStringRef physical_if, CFNumberRef tag) 855{ 856 struct ifreq ifr; 857 int tag_val; 858 struct vlanreq vreq; 859 860 memset(&ifr, 0, sizeof(ifr)); 861 memset(&vreq, 0, sizeof(vreq)); 862 863 // interface 864 (void) _SC_cfstring_to_cstring(interface_if, 865 ifr.ifr_name, 866 sizeof(ifr.ifr_name), 867 kCFStringEncodingASCII); 868 ifr.ifr_data = (caddr_t)&vreq; 869 870 // physical interface 871 (void) _SC_cfstring_to_cstring(physical_if, 872 vreq.vlr_parent, 873 sizeof(vreq.vlr_parent), 874 kCFStringEncodingASCII); 875 876 // tag 877 CFNumberGetValue(tag, kCFNumberIntType, &tag_val); 878 vreq.vlr_tag = tag_val; 879 880 // update physical interface and tag 881 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) { 882 SC_log(LOG_NOTICE, "ioctl(SIOCSIFVLAN) failed: %s", strerror(errno)); 883 _SCErrorSet(kSCStatusFailed); 884 return FALSE; 885 } 886 887 return TRUE; 888} 889 890 891static Boolean 892__vlan_clear(int s, CFStringRef interface_if) 893{ 894 struct ifreq ifr; 895 struct vlanreq vreq; 896 897 memset(&ifr, 0, sizeof(ifr)); 898 memset(&vreq, 0, sizeof(vreq)); 899 900 // interface 901 (void) _SC_cfstring_to_cstring(interface_if, 902 ifr.ifr_name, 903 sizeof(ifr.ifr_name), 904 kCFStringEncodingASCII); 905 ifr.ifr_data = (caddr_t)&vreq; 906 907 // clear physical interface 908 memset(&vreq.vlr_parent, 0, sizeof(vreq.vlr_parent)); 909 910 // clear tag 911 vreq.vlr_tag = 0; 912 913 // update physical interface and tag 914 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) { 915 SC_log(LOG_NOTICE, "ioctl(SIOCSIFVLAN) failed: %s", strerror(errno)); 916 _SCErrorSet(kSCStatusFailed); 917 return FALSE; 918 } 919 920 return TRUE; 921} 922 923 924Boolean 925_SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs) 926{ 927 CFArrayRef active = NULL; 928 CFArrayRef config = NULL; 929 CFMutableDictionaryRef devices = NULL; 930 CFIndex i; 931 CFIndex nActive; 932 CFIndex nConfig; 933 Boolean ok = TRUE; 934 int s = -1; 935 936 if (prefs == NULL) { 937 _SCErrorSet(kSCStatusInvalidArgument); 938 return FALSE; 939 } 940 941 /* configured VLANs */ 942 config = SCVLANInterfaceCopyAll(prefs); 943 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0; 944 945 /* physical interfaces */ 946 devices = CFDictionaryCreateMutable(NULL, 947 0, 948 &kCFTypeDictionaryKeyCallBacks, 949 &kCFTypeDictionaryValueCallBacks); 950 951 /* active VLANs */ 952 active = _SCVLANInterfaceCopyActive(); 953 nActive = (active != NULL) ? CFArrayGetCount(active) : 0; 954 955 /* remove any no-longer-configured VLAN interfaces */ 956 for (i = 0; i < nActive; i++) { 957 SCVLANInterfaceRef a_vlan; 958 CFStringRef a_vlan_if; 959 CFIndex j; 960 Boolean found = FALSE; 961 962 a_vlan = CFArrayGetValueAtIndex(active, i); 963 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan); 964 965 for (j = 0; j < nConfig; j++) { 966 SCVLANInterfaceRef c_vlan; 967 CFStringRef c_vlan_if; 968 969 c_vlan = CFArrayGetValueAtIndex(config, j); 970 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan); 971 972 if (CFEqual(a_vlan_if, c_vlan_if)) { 973 found = TRUE; 974 break; 975 } 976 } 977 978 if (!found) { 979 // remove VLAN interface 980 if (s == -1) { 981 s = inet_dgram_socket(); 982 if (s == -1) { 983 _SCErrorSet(errno); 984 ok = FALSE; 985 goto done; 986 } 987 } 988 if (!__destroyInterface(s, a_vlan_if)) { 989 ok = FALSE; 990 _SCErrorSet(errno); 991 } 992 } 993 } 994 995 /* create (and update) configured VLAN interfaces */ 996 for (i = 0; i < nConfig; i++) { 997 SCVLANInterfaceRef c_vlan; 998 CFStringRef c_vlan_if; 999 SCNetworkInterfaceRef c_vlan_physical; 1000 Boolean found = FALSE; 1001 CFIndex j; 1002 CFBooleanRef supported; 1003 1004 c_vlan = CFArrayGetValueAtIndex(config, i); 1005 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan); 1006 c_vlan_physical = SCVLANInterfaceGetPhysicalInterface(c_vlan); 1007 1008 if (c_vlan_physical == NULL) { 1009 continue; 1010 } 1011 // determine if the physical interface supports VLANs 1012 supported = CFDictionaryGetValue(devices, c_vlan_physical); 1013 if (supported == NULL) { 1014 SCNetworkInterfacePrivateRef c_vlan_physicalPrivate = (SCNetworkInterfacePrivateRef)c_vlan_physical; 1015 1016 supported = c_vlan_physicalPrivate->supportsVLAN ? kCFBooleanTrue 1017 : kCFBooleanFalse; 1018 CFDictionaryAddValue(devices, c_vlan_physical, supported); 1019 } 1020 1021 for (j = 0; j < nActive; j++) { 1022 SCVLANInterfaceRef a_vlan; 1023 CFStringRef a_vlan_if; 1024 1025 a_vlan = CFArrayGetValueAtIndex(active, j); 1026 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan); 1027 1028 if (CFEqual(c_vlan_if, a_vlan_if)) { 1029 if (!CFEqual(c_vlan, a_vlan)) { 1030 // update VLAN interface 1031 if (s == -1) { 1032 s = inet_dgram_socket(); 1033 if (s == -1) { 1034 _SCErrorSet(errno); 1035 ok = FALSE; 1036 goto done; 1037 } 1038 } 1039 1040 if (!CFBooleanGetValue(supported) 1041 || !__vlan_clear(s, c_vlan_if) 1042 || !__vlan_set(s, c_vlan_if, 1043 SCNetworkInterfaceGetBSDName(c_vlan_physical), 1044 SCVLANInterfaceGetTag(c_vlan))) { 1045 // something went wrong, try to blow the VLAN away 1046 if (!CFBooleanGetValue(supported)) { 1047 _SCErrorSet(kSCStatusFailed); 1048 } 1049 (void)__destroyInterface(s, c_vlan_if); 1050 ok = FALSE; 1051 } 1052 } 1053 1054 found = TRUE; 1055 break; 1056 } 1057 } 1058 1059 if (!found && CFBooleanGetValue(supported)) { 1060 // if the physical interface supports VLANs, add new interface 1061 Boolean created; 1062 1063 if (s == -1) { 1064 s = inet_dgram_socket(); 1065 if (s == -1) { 1066 _SCErrorSet(errno); 1067 ok = FALSE; 1068 goto done; 1069 } 1070 } 1071 1072 created = __createInterface(s, c_vlan_if); 1073 if (!created 1074 || !__vlan_set(s, 1075 c_vlan_if, 1076 SCNetworkInterfaceGetBSDName(c_vlan_physical), 1077 SCVLANInterfaceGetTag(c_vlan))) { 1078 if (created) { 1079 // something went wrong, try to blow the VLAN away 1080 (void)__destroyInterface(s, c_vlan_if); 1081 } else { 1082 _SCErrorSet(errno); 1083 } 1084 ok = FALSE; 1085 } 1086 } 1087 1088 } 1089 1090 done : 1091 1092 if (active) CFRelease(active); 1093 if (config) CFRelease(config); 1094 if (devices) CFRelease(devices); 1095 if (s != -1) (void) close(s); 1096 1097 return ok; 1098}