2 * Copyright (c) 2003-2013, 2015-2018 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * November 28, 2005 Allan Nathanson <ajn@apple.com>
30 * November 14, 2003 Allan Nathanson <ajn@apple.com>
35 #include <CoreFoundation/CoreFoundation.h>
36 #include <CoreFoundation/CFRuntime.h>
38 #include "SCNetworkConfigurationInternal.h"
39 #include "SCPreferencesInternal.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
50 #include <net/if_var.h>
52 #include <net/if_vlan_var.h>
53 #include <net/if_types.h>
55 /* ---------- VLAN support ---------- */
62 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
64 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
72 CFMutableArrayRef vlans
;
73 SCPreferencesRef ni_prefs
;
74 SCPreferencesRef prefs
;
75 } addContext
, *addContextRef
;
79 add_configured_interface(const void *key
, const void *value
, void *context
)
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
;
92 vlan_physical_if
= CFDictionaryGetValue(vlan_info
, kSCPropVirtualNetworkInterfacesVLANInterface
);
93 if (!isA_CFString(vlan_physical_if
)) {
94 // if prefs are confused
98 vlan_tag
= CFDictionaryGetValue(vlan_info
, kSCPropVirtualNetworkInterfacesVLANTag
);
99 if (!isA_CFNumber(vlan_tag
)) {
100 // if prefs are confused
104 // create the VLAN interface
105 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(NULL
, vlan_if
);
106 assert(vlan
!= NULL
);
108 // set physical interface and tag
109 if (myContext
->ni_prefs
!= NULL
) {
110 vlan_physical
= __SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(NULL
, myContext
->ni_prefs
,
113 if (vlan_physical
== NULL
) {
114 vlan_physical
= _SCNetworkInterfaceCreateWithBSDName(NULL
, vlan_physical_if
,
115 kIncludeBondInterfaces
);
117 assert(vlan_physical
!= NULL
);
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
;
126 // and now we associate the physical interface and tag
127 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
128 CFRelease(vlan_physical
);
131 vlan_name
= CFDictionaryGetValue(vlan_info
, kSCPropUserDefinedName
);
132 if (isA_CFString(vlan_name
)) {
133 SCVLANInterfaceSetLocalizedDisplayName(vlan
, vlan_name
);
137 vlan_options
= CFDictionaryGetValue(vlan_info
, kSCPropVirtualNetworkInterfacesVLANOptions
);
138 if (isA_CFDictionary(vlan_options
)) {
139 SCVLANInterfaceSetOptions(vlan
, vlan_options
);
142 // estabish link to the stored configuration
143 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
144 interfacePrivate
->prefs
= CFRetain(myContext
->prefs
);
146 CFArrayAppendValue(myContext
->vlans
, vlan
);
153 static SCVLANInterfaceRef
154 findVLANInterfaceAndTag(SCPreferencesRef prefs
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
158 SCVLANInterfaceRef vlan
= NULL
;
161 vlans
= SCVLANInterfaceCopyAll(prefs
);
163 n
= CFArrayGetCount(vlans
);
164 for (i
= 0; i
< n
; i
++) {
165 SCVLANInterfaceRef config_vlan
;
166 SCNetworkInterfaceRef config_physical
;
167 CFNumberRef config_tag
;
169 config_vlan
= CFArrayGetValueAtIndex(vlans
, i
);
170 config_physical
= SCVLANInterfaceGetPhysicalInterface(config_vlan
);
171 config_tag
= SCVLANInterfaceGetTag(config_vlan
);
173 if ((config_physical
!= NULL
) && (config_tag
!= NULL
)) {
174 if (!CFEqual(physical
, config_physical
)) {
175 // if this VLAN has a different physical interface
179 if (!CFEqual(tag
, config_tag
)) {
180 // if this VLAN has a different tag
184 vlan
= CFRetain(config_vlan
);
195 #pragma mark SCVLANInterface APIs
198 static __inline__
void
199 my_CFDictionaryApplyFunction(CFDictionaryRef theDict
,
200 CFDictionaryApplierFunction applier
,
203 CFAllocatorRef myAllocator
;
204 CFDictionaryRef myDict
;
206 myAllocator
= CFGetAllocator(theDict
);
207 myDict
= CFDictionaryCreateCopy(myAllocator
, theDict
);
208 CFDictionaryApplyFunction(myDict
, applier
, context
);
215 SCVLANInterfaceCopyAll(SCPreferencesRef prefs
)
218 CFDictionaryRef dict
;
219 SCPreferencesRef ni_prefs
;
222 if (__SCPreferencesUsingDefaultPrefs(prefs
)) {
225 ni_prefs
= __SCPreferencesCreateNIPrefsFromPrefs(prefs
);
227 context
.vlans
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
228 context
.ni_prefs
= ni_prefs
;
229 context
.prefs
= prefs
;
231 path
= CFStringCreateWithFormat(NULL
,
234 kSCPrefVirtualNetworkInterfaces
,
235 kSCNetworkInterfaceTypeVLAN
);
236 dict
= SCPreferencesPathGetValue(prefs
, path
);
238 if (isA_CFDictionary(dict
)) {
239 my_CFDictionaryApplyFunction(dict
, add_configured_interface
, &context
);
241 if (ni_prefs
!= NULL
) {
244 return context
.vlans
;
249 addAvailableInterfaces(CFMutableArrayRef available
, CFArrayRef interfaces
,
255 n
= CFArrayGetCount(interfaces
);
256 for (i
= 0; i
< n
; i
++) {
257 SCNetworkInterfaceRef interface
;
258 SCNetworkInterfacePrivateRef interfacePrivate
;
260 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
261 interfacePrivate
= (SCNetworkInterfacePrivateRef
)interface
;
263 if ((excluded
!= NULL
)
264 && CFSetContainsValue(excluded
, interface
)) {
265 // exclude this interface
268 if (interfacePrivate
->supportsVLAN
) {
269 // if this interface is available
270 CFArrayAppendValue(available
, interface
);
279 SCVLANInterfaceCopyAvailablePhysicalInterfaces()
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
;
290 available
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
292 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), 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
);
300 #endif // !TARGET_OS_IPHONE
302 bridge_interfaces
= SCBridgeInterfaceCopyAll(prefs
);
303 if (bridge_interfaces
!= NULL
) {
304 if (excluded
== NULL
) {
305 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
307 __SCBridgeInterfaceListCollectMembers(bridge_interfaces
, excluded
);
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
);
320 #if !TARGET_OS_IPHONE
321 // add bond interfaces
322 if (bond_interfaces
!= NULL
) {
323 addAvailableInterfaces(available
, bond_interfaces
, NULL
);
324 CFRelease(bond_interfaces
);
326 #endif // !TARGET_OS_IPHONE
328 // add bridge interfaces
329 if (bridge_interfaces
!= NULL
) {
330 addAvailableInterfaces(available
, bridge_interfaces
, NULL
);
331 CFRelease(bridge_interfaces
);
334 if (excluded
!= NULL
) {
343 _SCVLANInterfaceCopyActive(void)
345 struct ifaddrs
*ifap
;
348 CFMutableArrayRef vlans
= NULL
;
350 if (getifaddrs(&ifap
) == -1) {
351 SC_log(LOG_NOTICE
, "getifaddrs() failed: %s", strerror(errno
));
352 _SCErrorSet(kSCStatusFailed
);
356 s
= inet_dgram_socket();
362 vlans
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
364 for (ifp
= ifap
; ifp
!= NULL
; ifp
= ifp
->ifa_next
) {
365 struct if_data
*if_data
;
367 SCVLANInterfaceRef vlan
;
369 SCNetworkInterfaceRef vlan_physical
;
370 CFStringRef vlan_physical_if
;
371 CFNumberRef vlan_tag
;
372 char vlr_parent
[IFNAMSIZ
];
376 if_data
= (struct if_data
*)ifp
->ifa_data
;
378 || ifp
->ifa_addr
->sa_family
!= AF_LINK
379 || if_data
->ifi_type
!= IFT_L2VLAN
) {
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
;
388 if (ioctl(s
, SIOCGIFVLAN
, (caddr_t
)&ifr
) == -1) {
389 SC_log(LOG_NOTICE
, "ioctl(SIOCGIFVLAN) failed: %s", strerror(errno
));
392 _SCErrorSet(kSCStatusFailed
);
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
);
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
);
410 vlr_tag
= vreq
.vlr_tag
;
411 vlan_tag
= CFNumberCreate(NULL
, kCFNumberIntType
, &vlr_tag
);
412 assert(vlan_tag
!= NULL
);
414 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
415 CFRelease(vlan_physical
);
419 CFArrayAppendValue(vlans
, vlan
);
434 SCVLANInterfaceCreate(SCPreferencesRef prefs
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
436 CFAllocatorRef allocator
;
438 SCNetworkInterfacePrivateRef interfacePrivate
;
439 SCVLANInterfaceRef vlan
;
442 _SCErrorSet(kSCStatusInvalidArgument
);
446 if (!isA_SCNetworkInterface(physical
)) {
447 _SCErrorSet(kSCStatusInvalidArgument
);
451 interfacePrivate
= (SCNetworkInterfacePrivateRef
)physical
;
452 if (!interfacePrivate
->supportsVLAN
) {
453 if (!__SCPreferencesUsingDefaultPrefs(prefs
)) {
454 interfacePrivate
->supportsVLAN
= TRUE
;
456 _SCErrorSet(kSCStatusInvalidArgument
);
461 if (isA_CFNumber(tag
)) {
464 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
465 if ((tag_val
< 1) || (tag_val
> 4094)) {
466 _SCErrorSet(kSCStatusInvalidArgument
);
470 _SCErrorSet(kSCStatusInvalidArgument
);
474 // make sure that physical interface and tag are not used
475 vlan
= findVLANInterfaceAndTag(prefs
, physical
, tag
);
478 _SCErrorSet(kSCStatusKeyExists
);
482 allocator
= CFGetAllocator(prefs
);
484 // create a new VLAN using an unused interface name
485 for (i
= 0; vlan
== NULL
; i
++) {
486 CFDictionaryRef dict
;
491 vlan_if
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("vlan%ld"), i
);
492 path
= CFStringCreateWithFormat(allocator
,
495 kSCPrefVirtualNetworkInterfaces
,
496 kSCNetworkInterfaceTypeVLAN
,
498 dict
= SCPreferencesPathGetValue(prefs
, path
);
500 // if VLAN interface name not available
506 // add the VLAN to the stored preferences
507 dict
= CFDictionaryCreate(allocator
,
509 &kCFTypeDictionaryKeyCallBacks
,
510 &kCFTypeDictionaryValueCallBacks
);
511 ok
= SCPreferencesPathSetValue(prefs
, path
, dict
);
515 // if the VLAN could not be saved
517 _SCErrorSet(kSCStatusFailed
);
521 // create the SCVLANInterfaceRef
522 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(allocator
, vlan_if
);
525 // estabish link to the stored configuration
526 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
527 interfacePrivate
->prefs
= CFRetain(prefs
);
529 // set physical interface and tag
530 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, physical
, tag
);
538 SCVLANInterfaceRemove(SCVLANInterfaceRef vlan
)
541 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
545 if (!isA_SCVLANInterface(vlan
)) {
546 _SCErrorSet(kSCStatusInvalidArgument
);
550 if (interfacePrivate
->prefs
== NULL
) {
551 _SCErrorSet(kSCStatusInvalidArgument
);
555 vlan_if
= SCNetworkInterfaceGetBSDName(vlan
);
556 path
= CFStringCreateWithFormat(NULL
,
559 kSCPrefVirtualNetworkInterfaces
,
560 kSCNetworkInterfaceTypeVLAN
,
562 ok
= SCPreferencesPathRemoveValue(interfacePrivate
->prefs
, path
);
569 SCNetworkInterfaceRef
570 SCVLANInterfaceGetPhysicalInterface(SCVLANInterfaceRef vlan
)
572 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
574 if (!isA_SCVLANInterface(vlan
)) {
575 _SCErrorSet(kSCStatusInvalidArgument
);
579 return interfacePrivate
->vlan
.interface
;
584 SCVLANInterfaceGetTag(SCVLANInterfaceRef vlan
)
586 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
588 if (!isA_SCVLANInterface(vlan
)) {
589 _SCErrorSet(kSCStatusInvalidArgument
);
593 return interfacePrivate
->vlan
.tag
;
598 SCVLANInterfaceGetOptions(SCVLANInterfaceRef vlan
)
600 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
602 if (!isA_SCVLANInterface(vlan
)) {
603 _SCErrorSet(kSCStatusInvalidArgument
);
607 return interfacePrivate
->vlan
.options
;
612 SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
614 SCNetworkInterfacePrivateRef interfacePrivate
;
616 SCPreferencesRef prefs
;
618 if (!isA_SCVLANInterface(vlan
)) {
619 _SCErrorSet(kSCStatusInvalidArgument
);
623 if (!isA_SCNetworkInterface(physical
)) {
624 _SCErrorSet(kSCStatusInvalidArgument
);
628 interfacePrivate
= (SCNetworkInterfacePrivateRef
)physical
;
629 prefs
= interfacePrivate
->prefs
;
631 if (!interfacePrivate
->supportsVLAN
) {
632 if (!__SCPreferencesUsingDefaultPrefs(prefs
)) {
633 interfacePrivate
->supportsVLAN
= TRUE
;
635 _SCErrorSet(kSCStatusInvalidArgument
);
640 if (isA_CFNumber(tag
)) {
643 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
644 if ((tag_val
< 1) || (tag_val
> 4094)) {
645 _SCErrorSet(kSCStatusInvalidArgument
);
649 _SCErrorSet(kSCStatusInvalidArgument
);
653 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
654 if (interfacePrivate
->prefs
!= NULL
) {
655 SCVLANInterfaceRef config_vlan
;
656 CFDictionaryRef dict
;
657 CFMutableDictionaryRef newDict
;
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
);
668 CFRelease(config_vlan
);
671 // set interface/tag in the stored preferences
672 path
= CFStringCreateWithFormat(NULL
,
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
682 _SCErrorSet(kSCStatusFailed
);
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
);
699 SCNetworkInterfacePrivateRef newInterface
;
702 // set physical interface
703 newInterface
= __SCNetworkInterfaceCreateCopy(NULL
,
705 interfacePrivate
->prefs
,
706 interfacePrivate
->serviceID
);
707 save
= interfacePrivate
->vlan
.interface
;
708 interfacePrivate
->vlan
.interface
= (SCNetworkInterfaceRef
)newInterface
;
709 if (save
!= NULL
) CFRelease(save
);
712 save
= interfacePrivate
->vlan
.tag
;
713 interfacePrivate
->vlan
.tag
= CFRetain(tag
);
714 if (save
!= NULL
) CFRelease(save
);
722 SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan
, CFStringRef newName
)
724 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
727 if (!isA_SCVLANInterface(vlan
)) {
728 _SCErrorSet(kSCStatusInvalidArgument
);
732 if ((newName
!= NULL
) && !isA_CFString(newName
)) {
733 _SCErrorSet(kSCStatusInvalidArgument
);
737 // set name in the stored preferences
738 if (interfacePrivate
->prefs
!= NULL
) {
739 CFDictionaryRef dict
;
740 CFMutableDictionaryRef newDict
;
743 path
= CFStringCreateWithFormat(NULL
,
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
753 _SCErrorSet(kSCStatusFailed
);
757 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
758 if (newName
!= NULL
) {
759 CFDictionarySetValue(newDict
, kSCPropUserDefinedName
, newName
);
761 CFDictionaryRemoveValue(newDict
, kSCPropUserDefinedName
);
763 if (!CFEqual(dict
, newDict
)) {
764 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
770 // set name in the SCVLANInterfaceRef
772 if (interfacePrivate
->localized_name
!= NULL
) {
773 CFRelease(interfacePrivate
->localized_name
);
774 interfacePrivate
->localized_name
= NULL
;
776 if (newName
!= NULL
) {
777 interfacePrivate
->localized_name
= CFStringCreateCopy(NULL
, newName
);
786 SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan
, CFDictionaryRef newOptions
)
788 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
791 if (!isA_SCVLANInterface(vlan
)) {
792 _SCErrorSet(kSCStatusInvalidArgument
);
796 if ((newOptions
!= NULL
) && !isA_CFDictionary(newOptions
)) {
797 _SCErrorSet(kSCStatusInvalidArgument
);
801 // set options in the stored preferences
802 if (interfacePrivate
->prefs
!= NULL
) {
803 CFDictionaryRef dict
;
804 CFMutableDictionaryRef newDict
;
807 path
= CFStringCreateWithFormat(NULL
,
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
817 _SCErrorSet(kSCStatusFailed
);
821 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
822 if (newOptions
!= NULL
) {
823 CFDictionarySetValue(newDict
, kSCPropVirtualNetworkInterfacesVLANOptions
, newOptions
);
825 CFDictionaryRemoveValue(newDict
, kSCPropVirtualNetworkInterfacesVLANOptions
);
827 if (!CFEqual(dict
, newDict
)) {
828 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
834 // set options in the SCVLANInterfaceRef
836 if (interfacePrivate
->vlan
.options
!= NULL
) {
837 CFRelease(interfacePrivate
->vlan
.options
);
838 interfacePrivate
->vlan
.options
= NULL
;
840 if (newOptions
!= NULL
) {
841 interfacePrivate
->vlan
.options
= CFDictionaryCreateCopy(NULL
, newOptions
);
850 #pragma mark SCVLANInterface management
854 __vlan_set(int s
, CFStringRef interface_if
, CFStringRef physical_if
, CFNumberRef tag
)
860 memset(&ifr
, 0, sizeof(ifr
));
861 memset(&vreq
, 0, sizeof(vreq
));
864 (void) _SC_cfstring_to_cstring(interface_if
,
866 sizeof(ifr
.ifr_name
),
867 kCFStringEncodingASCII
);
868 ifr
.ifr_data
= (caddr_t
)&vreq
;
870 // physical interface
871 (void) _SC_cfstring_to_cstring(physical_if
,
873 sizeof(vreq
.vlr_parent
),
874 kCFStringEncodingASCII
);
877 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
878 vreq
.vlr_tag
= tag_val
;
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
);
892 __vlan_clear(int s
, CFStringRef interface_if
)
897 memset(&ifr
, 0, sizeof(ifr
));
898 memset(&vreq
, 0, sizeof(vreq
));
901 (void) _SC_cfstring_to_cstring(interface_if
,
903 sizeof(ifr
.ifr_name
),
904 kCFStringEncodingASCII
);
905 ifr
.ifr_data
= (caddr_t
)&vreq
;
907 // clear physical interface
908 memset(&vreq
.vlr_parent
, 0, sizeof(vreq
.vlr_parent
));
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
);
925 _SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs
)
927 CFArrayRef active
= NULL
;
928 CFArrayRef config
= NULL
;
929 CFMutableDictionaryRef devices
= NULL
;
937 _SCErrorSet(kSCStatusInvalidArgument
);
941 /* configured VLANs */
942 config
= SCVLANInterfaceCopyAll(prefs
);
943 nConfig
= (config
!= NULL
) ? CFArrayGetCount(config
) : 0;
945 /* physical interfaces */
946 devices
= CFDictionaryCreateMutable(NULL
,
948 &kCFTypeDictionaryKeyCallBacks
,
949 &kCFTypeDictionaryValueCallBacks
);
952 active
= _SCVLANInterfaceCopyActive();
953 nActive
= (active
!= NULL
) ? CFArrayGetCount(active
) : 0;
955 /* remove any no-longer-configured VLAN interfaces */
956 for (i
= 0; i
< nActive
; i
++) {
957 SCVLANInterfaceRef a_vlan
;
958 CFStringRef a_vlan_if
;
960 Boolean found
= FALSE
;
962 a_vlan
= CFArrayGetValueAtIndex(active
, i
);
963 a_vlan_if
= SCNetworkInterfaceGetBSDName(a_vlan
);
965 for (j
= 0; j
< nConfig
; j
++) {
966 SCVLANInterfaceRef c_vlan
;
967 CFStringRef c_vlan_if
;
969 c_vlan
= CFArrayGetValueAtIndex(config
, j
);
970 c_vlan_if
= SCNetworkInterfaceGetBSDName(c_vlan
);
972 if (CFEqual(a_vlan_if
, c_vlan_if
)) {
979 // remove VLAN interface
981 s
= inet_dgram_socket();
988 if (!__destroyInterface(s
, a_vlan_if
)) {
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
;
1002 CFBooleanRef supported
;
1004 c_vlan
= CFArrayGetValueAtIndex(config
, i
);
1005 c_vlan_if
= SCNetworkInterfaceGetBSDName(c_vlan
);
1006 c_vlan_physical
= SCVLANInterfaceGetPhysicalInterface(c_vlan
);
1008 if (c_vlan_physical
== NULL
) {
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
;
1016 supported
= c_vlan_physicalPrivate
->supportsVLAN
? kCFBooleanTrue
1018 CFDictionaryAddValue(devices
, c_vlan_physical
, supported
);
1021 for (j
= 0; j
< nActive
; j
++) {
1022 SCVLANInterfaceRef a_vlan
;
1023 CFStringRef a_vlan_if
;
1025 a_vlan
= CFArrayGetValueAtIndex(active
, j
);
1026 a_vlan_if
= SCNetworkInterfaceGetBSDName(a_vlan
);
1028 if (CFEqual(c_vlan_if
, a_vlan_if
)) {
1029 if (!CFEqual(c_vlan
, a_vlan
)) {
1030 // update VLAN interface
1032 s
= inet_dgram_socket();
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
);
1049 (void)__destroyInterface(s
, c_vlan_if
);
1059 if (!found
&& CFBooleanGetValue(supported
)) {
1060 // if the physical interface supports VLANs, add new interface
1064 s
= inet_dgram_socket();
1072 created
= __createInterface(s
, c_vlan_if
);
1076 SCNetworkInterfaceGetBSDName(c_vlan_physical
),
1077 SCVLANInterfaceGetTag(c_vlan
))) {
1079 // something went wrong, try to blow the VLAN away
1080 (void)__destroyInterface(s
, c_vlan_if
);
1092 if (active
) CFRelease(active
);
1093 if (config
) CFRelease(config
);
1094 if (devices
) CFRelease(devices
);
1095 if (s
!= -1) (void) close(s
);