2 * Copyright (c) 2003-2013 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 <SystemConfiguration/SystemConfiguration.h>
39 #include "SCNetworkConfigurationInternal.h"
40 #include <SystemConfiguration/SCValidation.h>
41 #include <SystemConfiguration/SCPrivate.h>
46 #include <sys/types.h>
47 #include <sys/ioctl.h>
48 #include <sys/socket.h>
49 #include <net/ethernet.h>
50 #define KERNEL_PRIVATE
52 #include <net/if_var.h>
54 #include <net/if_vlan_var.h>
55 #include <net/if_types.h>
57 /* ---------- VLAN support ---------- */
64 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
66 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
74 CFMutableArrayRef vlans
;
75 SCPreferencesRef prefs
;
76 } addContext
, *addContextRef
;
80 add_configured_interface(const void *key
, const void *value
, void *context
)
82 SCNetworkInterfacePrivateRef interfacePrivate
;
83 addContextRef myContext
= (addContextRef
)context
;
84 SCVLANInterfaceRef vlan
;
85 CFStringRef vlan_if
= (CFStringRef
)key
;
86 CFDictionaryRef vlan_info
= (CFDictionaryRef
)value
;
87 CFStringRef vlan_name
;
88 CFDictionaryRef vlan_options
;
89 SCNetworkInterfaceRef vlan_physical
;
90 CFStringRef vlan_physical_if
;
93 vlan_physical_if
= CFDictionaryGetValue(vlan_info
, kSCPropVirtualNetworkInterfacesVLANInterface
);
94 if (!isA_CFString(vlan_physical_if
)) {
95 // if prefs are confused
99 vlan_tag
= CFDictionaryGetValue(vlan_info
, kSCPropVirtualNetworkInterfacesVLANTag
);
100 if (!isA_CFNumber(vlan_tag
)) {
101 // if prefs are confused
105 // create the VLAN interface
106 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(NULL
, vlan_if
);
107 assert(vlan
!= NULL
);
109 // set physical interface and tag
110 vlan_physical
= _SCNetworkInterfaceCreateWithBSDName(NULL
, vlan_physical_if
,
111 kIncludeBondInterfaces
);
112 assert(vlan_physical
!= NULL
);
114 // since we KNOW that the physical interface supported VLANs when
115 // it was first established it's OK to force that state here ...
116 // and this is needed for the case when the interface (e.g. a
117 // dongle) is not currently attached to the system
118 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan_physical
;
119 interfacePrivate
->supportsVLAN
= TRUE
;
121 // and now we associate the physical interface and tag
122 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
123 CFRelease(vlan_physical
);
126 vlan_name
= CFDictionaryGetValue(vlan_info
, kSCPropUserDefinedName
);
127 if (isA_CFString(vlan_name
)) {
128 SCVLANInterfaceSetLocalizedDisplayName(vlan
, vlan_name
);
132 vlan_options
= CFDictionaryGetValue(vlan_info
, kSCPropVirtualNetworkInterfacesVLANOptions
);
133 if (isA_CFDictionary(vlan_options
)) {
134 SCVLANInterfaceSetOptions(vlan
, vlan_options
);
137 // estabish link to the stored configuration
138 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
139 interfacePrivate
->prefs
= CFRetain(myContext
->prefs
);
141 CFArrayAppendValue(myContext
->vlans
, vlan
);
148 static SCVLANInterfaceRef
149 findVLANInterfaceAndTag(SCPreferencesRef prefs
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
153 SCVLANInterfaceRef vlan
= NULL
;
156 vlans
= SCVLANInterfaceCopyAll(prefs
);
158 n
= CFArrayGetCount(vlans
);
159 for (i
= 0; i
< n
; i
++) {
160 SCVLANInterfaceRef config_vlan
;
161 SCNetworkInterfaceRef config_physical
;
162 CFNumberRef config_tag
;
164 config_vlan
= CFArrayGetValueAtIndex(vlans
, i
);
165 config_physical
= SCVLANInterfaceGetPhysicalInterface(config_vlan
);
166 config_tag
= SCVLANInterfaceGetTag(config_vlan
);
168 if ((config_physical
!= NULL
) && (config_tag
!= NULL
)) {
169 if (!CFEqual(physical
, config_physical
)) {
170 // if this VLAN has a different physical interface
174 if (!CFEqual(tag
, config_tag
)) {
175 // if this VLAN has a different tag
179 vlan
= CFRetain(config_vlan
);
190 #pragma mark SCVLANInterface APIs
193 static __inline__
void
194 my_CFDictionaryApplyFunction(CFDictionaryRef theDict
,
195 CFDictionaryApplierFunction applier
,
198 CFAllocatorRef myAllocator
;
199 CFDictionaryRef myDict
;
201 myAllocator
= CFGetAllocator(theDict
);
202 myDict
= CFDictionaryCreateCopy(myAllocator
, theDict
);
203 CFDictionaryApplyFunction(myDict
, applier
, context
);
210 SCVLANInterfaceCopyAll(SCPreferencesRef prefs
)
213 CFDictionaryRef dict
;
216 context
.vlans
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
217 context
.prefs
= prefs
;
219 path
= CFStringCreateWithFormat(NULL
,
222 kSCPrefVirtualNetworkInterfaces
,
223 kSCNetworkInterfaceTypeVLAN
);
224 dict
= SCPreferencesPathGetValue(prefs
, path
);
226 if (isA_CFDictionary(dict
)) {
227 my_CFDictionaryApplyFunction(dict
, add_configured_interface
, &context
);
230 return context
.vlans
;
235 addAvailableInterfaces(CFMutableArrayRef available
, CFArrayRef interfaces
,
241 n
= CFArrayGetCount(interfaces
);
242 for (i
= 0; i
< n
; i
++) {
243 SCNetworkInterfaceRef interface
;
244 SCNetworkInterfacePrivateRef interfacePrivate
;
246 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
247 interfacePrivate
= (SCNetworkInterfacePrivateRef
)interface
;
249 if ((excluded
!= NULL
)
250 && CFSetContainsValue(excluded
, interface
)) {
251 // exclude this interface
254 if (interfacePrivate
->supportsVLAN
) {
255 // if this interface is available
256 CFArrayAppendValue(available
, interface
);
265 SCVLANInterfaceCopyAvailablePhysicalInterfaces()
267 CFMutableArrayRef available
;
268 CFArrayRef bond_interfaces
= NULL
;
269 CFArrayRef bridge_interfaces
= NULL
;
270 CFMutableSetRef excluded
= NULL
;
271 CFArrayRef interfaces
;
272 SCPreferencesRef prefs
;
274 available
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
276 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL
);
278 #if !TARGET_OS_IPHONE
279 bond_interfaces
= SCBondInterfaceCopyAll(prefs
);
280 if (bond_interfaces
!= NULL
) {
281 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
282 __SCBondInterfaceListCollectMembers(bond_interfaces
, excluded
);
284 #endif // !TARGET_OS_IPHONE
286 bridge_interfaces
= SCBridgeInterfaceCopyAll(prefs
);
287 if (bridge_interfaces
!= NULL
) {
288 if (excluded
== NULL
) {
289 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
291 __SCBridgeInterfaceListCollectMembers(bridge_interfaces
, excluded
);
297 // add real interfaces that aren't part of a bond or bridge
298 interfaces
= __SCNetworkInterfaceCopyAll_IONetworkInterface();
299 if (interfaces
!= NULL
) {
300 addAvailableInterfaces(available
, interfaces
, excluded
);
301 CFRelease(interfaces
);
304 // add bond interfaces
305 if (bond_interfaces
!= NULL
) {
306 addAvailableInterfaces(available
, bond_interfaces
, NULL
);
307 CFRelease(bond_interfaces
);
310 // add bridge interfaces
311 if (bridge_interfaces
!= NULL
) {
312 addAvailableInterfaces(available
, bridge_interfaces
, NULL
);
313 CFRelease(bridge_interfaces
);
316 if (excluded
!= NULL
) {
325 _SCVLANInterfaceCopyActive(void)
327 struct ifaddrs
*ifap
;
330 CFMutableArrayRef vlans
= NULL
;
332 if (getifaddrs(&ifap
) == -1) {
333 SCLog(TRUE
, LOG_ERR
, CFSTR("getifaddrs() failed: %s"), strerror(errno
));
334 _SCErrorSet(kSCStatusFailed
);
338 s
= inet_dgram_socket();
344 vlans
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
346 for (ifp
= ifap
; ifp
!= NULL
; ifp
= ifp
->ifa_next
) {
347 struct if_data
*if_data
;
349 SCVLANInterfaceRef vlan
;
351 SCNetworkInterfaceRef vlan_physical
;
352 CFStringRef vlan_physical_if
;
353 CFNumberRef vlan_tag
;
354 char vlr_parent
[IFNAMSIZ
];
358 if_data
= (struct if_data
*)ifp
->ifa_data
;
360 || ifp
->ifa_addr
->sa_family
!= AF_LINK
361 || if_data
->ifi_type
!= IFT_L2VLAN
) {
365 bzero(&ifr
, sizeof(ifr
));
366 bzero(&vreq
, sizeof(vreq
));
367 strlcpy(ifr
.ifr_name
, ifp
->ifa_name
, sizeof(ifr
.ifr_name
));
368 ifr
.ifr_data
= (caddr_t
)&vreq
;
370 if (ioctl(s
, SIOCGIFVLAN
, (caddr_t
)&ifr
) == -1) {
371 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl() failed: %s"), strerror(errno
));
374 _SCErrorSet(kSCStatusFailed
);
378 // create the VLAN interface
379 vlan_if
= CFStringCreateWithCString(NULL
, ifp
->ifa_name
, kCFStringEncodingASCII
);
380 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(NULL
, vlan_if
);
381 assert(vlan
!= NULL
);
384 // set the physical interface and tag
385 strlcpy(vlr_parent
, vreq
.vlr_parent
, sizeof(vlr_parent
));
386 vlan_physical_if
= CFStringCreateWithCString(NULL
, vlr_parent
, kCFStringEncodingASCII
);
387 vlan_physical
= _SCNetworkInterfaceCreateWithBSDName(NULL
, vlan_physical_if
,
388 kIncludeBondInterfaces
);
389 assert(vlan_physical
!= NULL
);
390 CFRelease(vlan_physical_if
);
392 vlr_tag
= vreq
.vlr_tag
;
393 vlan_tag
= CFNumberCreate(NULL
, kCFNumberIntType
, &vlr_tag
);
394 assert(vlan_tag
!= NULL
);
396 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
397 CFRelease(vlan_physical
);
401 CFArrayAppendValue(vlans
, vlan
);
416 SCVLANInterfaceCreate(SCPreferencesRef prefs
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
418 CFAllocatorRef allocator
;
420 SCNetworkInterfacePrivateRef interfacePrivate
;
421 SCVLANInterfaceRef vlan
;
424 _SCErrorSet(kSCStatusInvalidArgument
);
428 if (!isA_SCNetworkInterface(physical
)) {
429 _SCErrorSet(kSCStatusInvalidArgument
);
433 interfacePrivate
= (SCNetworkInterfacePrivateRef
)physical
;
434 if (!interfacePrivate
->supportsVLAN
) {
435 _SCErrorSet(kSCStatusInvalidArgument
);
439 if (isA_CFNumber(tag
)) {
442 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
443 if ((tag_val
< 1) || (tag_val
> 4094)) {
444 _SCErrorSet(kSCStatusInvalidArgument
);
448 _SCErrorSet(kSCStatusInvalidArgument
);
452 // make sure that physical interface and tag are not used
453 vlan
= findVLANInterfaceAndTag(prefs
, physical
, tag
);
456 _SCErrorSet(kSCStatusKeyExists
);
460 allocator
= CFGetAllocator(prefs
);
462 // create a new VLAN using an unused interface name
463 for (i
= 0; vlan
== NULL
; i
++) {
464 CFDictionaryRef dict
;
469 vlan_if
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("vlan%ld"), i
);
470 path
= CFStringCreateWithFormat(allocator
,
473 kSCPrefVirtualNetworkInterfaces
,
474 kSCNetworkInterfaceTypeVLAN
,
476 dict
= SCPreferencesPathGetValue(prefs
, path
);
478 // if VLAN interface name not available
484 // add the VLAN to the stored preferences
485 dict
= CFDictionaryCreate(allocator
,
487 &kCFTypeDictionaryKeyCallBacks
,
488 &kCFTypeDictionaryValueCallBacks
);
489 ok
= SCPreferencesPathSetValue(prefs
, path
, dict
);
493 // if the VLAN could not be saved
495 _SCErrorSet(kSCStatusFailed
);
499 // create the SCVLANInterfaceRef
500 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(allocator
, vlan_if
);
503 // estabish link to the stored configuration
504 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
505 interfacePrivate
->prefs
= CFRetain(prefs
);
507 // set physical interface and tag
508 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, physical
, tag
);
516 SCVLANInterfaceRemove(SCVLANInterfaceRef vlan
)
519 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
523 if (!isA_SCVLANInterface(vlan
)) {
524 _SCErrorSet(kSCStatusInvalidArgument
);
528 if (interfacePrivate
->prefs
== NULL
) {
529 _SCErrorSet(kSCStatusInvalidArgument
);
533 vlan_if
= SCNetworkInterfaceGetBSDName(vlan
);
534 path
= CFStringCreateWithFormat(NULL
,
537 kSCPrefVirtualNetworkInterfaces
,
538 kSCNetworkInterfaceTypeVLAN
,
540 ok
= SCPreferencesPathRemoveValue(interfacePrivate
->prefs
, path
);
547 SCNetworkInterfaceRef
548 SCVLANInterfaceGetPhysicalInterface(SCVLANInterfaceRef vlan
)
550 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
552 if (!isA_SCVLANInterface(vlan
)) {
553 _SCErrorSet(kSCStatusInvalidArgument
);
557 return interfacePrivate
->vlan
.interface
;
562 SCVLANInterfaceGetTag(SCVLANInterfaceRef vlan
)
564 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
566 if (!isA_SCVLANInterface(vlan
)) {
567 _SCErrorSet(kSCStatusInvalidArgument
);
571 return interfacePrivate
->vlan
.tag
;
576 SCVLANInterfaceGetOptions(SCVLANInterfaceRef vlan
)
578 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
580 if (!isA_SCVLANInterface(vlan
)) {
581 _SCErrorSet(kSCStatusInvalidArgument
);
585 return interfacePrivate
->vlan
.options
;
590 SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
592 SCNetworkInterfacePrivateRef interfacePrivate
;
595 if (!isA_SCVLANInterface(vlan
)) {
596 _SCErrorSet(kSCStatusInvalidArgument
);
600 if (!isA_SCNetworkInterface(physical
)) {
601 _SCErrorSet(kSCStatusInvalidArgument
);
605 interfacePrivate
= (SCNetworkInterfacePrivateRef
)physical
;
606 if (!interfacePrivate
->supportsVLAN
) {
607 _SCErrorSet(kSCStatusInvalidArgument
);
611 if (isA_CFNumber(tag
)) {
614 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
615 if ((tag_val
< 1) || (tag_val
> 4094)) {
616 _SCErrorSet(kSCStatusInvalidArgument
);
620 _SCErrorSet(kSCStatusInvalidArgument
);
624 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
625 if (interfacePrivate
->prefs
!= NULL
) {
626 SCVLANInterfaceRef config_vlan
;
627 CFDictionaryRef dict
;
628 CFMutableDictionaryRef newDict
;
631 // make sure that physical interface and tag are not used
632 config_vlan
= findVLANInterfaceAndTag(interfacePrivate
->prefs
, physical
, tag
);
633 if (config_vlan
!= NULL
) {
634 if (!CFEqual(vlan
, config_vlan
)) {
635 CFRelease(config_vlan
);
636 _SCErrorSet(kSCStatusKeyExists
);
639 CFRelease(config_vlan
);
642 // set interface/tag in the stored preferences
643 path
= CFStringCreateWithFormat(NULL
,
646 kSCPrefVirtualNetworkInterfaces
,
647 kSCNetworkInterfaceTypeVLAN
,
648 interfacePrivate
->entity_device
);
649 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
650 if (!isA_CFDictionary(dict
)) {
651 // if the prefs are confused
653 _SCErrorSet(kSCStatusFailed
);
657 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
658 CFDictionarySetValue(newDict
,
659 kSCPropVirtualNetworkInterfacesVLANInterface
,
660 SCNetworkInterfaceGetBSDName(physical
));
661 CFDictionarySetValue(newDict
, kSCPropVirtualNetworkInterfacesVLANTag
, tag
);
662 if (!CFEqual(dict
, newDict
)) {
663 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
670 SCNetworkInterfacePrivateRef newInterface
;
673 // set physical interface
674 newInterface
= __SCNetworkInterfaceCreateCopy(NULL
,
676 interfacePrivate
->prefs
,
677 interfacePrivate
->serviceID
);
678 save
= interfacePrivate
->vlan
.interface
;
679 interfacePrivate
->vlan
.interface
= (SCNetworkInterfaceRef
)newInterface
;
680 if (save
!= NULL
) CFRelease(save
);
683 save
= interfacePrivate
->vlan
.tag
;
684 interfacePrivate
->vlan
.tag
= CFRetain(tag
);
685 if (save
!= NULL
) CFRelease(save
);
693 SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan
, CFStringRef newName
)
695 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
698 if (!isA_SCVLANInterface(vlan
)) {
699 _SCErrorSet(kSCStatusInvalidArgument
);
703 if ((newName
!= NULL
) && !isA_CFString(newName
)) {
704 _SCErrorSet(kSCStatusInvalidArgument
);
708 // set name in the stored preferences
709 if (interfacePrivate
->prefs
!= NULL
) {
710 CFDictionaryRef dict
;
711 CFMutableDictionaryRef newDict
;
714 path
= CFStringCreateWithFormat(NULL
,
717 kSCPrefVirtualNetworkInterfaces
,
718 kSCNetworkInterfaceTypeVLAN
,
719 interfacePrivate
->entity_device
);
720 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
721 if (!isA_CFDictionary(dict
)) {
722 // if the prefs are confused
724 _SCErrorSet(kSCStatusFailed
);
728 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
729 if (newName
!= NULL
) {
730 CFDictionarySetValue(newDict
, kSCPropUserDefinedName
, newName
);
732 CFDictionaryRemoveValue(newDict
, kSCPropUserDefinedName
);
734 if (!CFEqual(dict
, newDict
)) {
735 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
741 // set name in the SCVLANInterfaceRef
743 if (interfacePrivate
->localized_name
!= NULL
) {
744 CFRelease(interfacePrivate
->localized_name
);
745 interfacePrivate
->localized_name
= NULL
;
747 if (newName
!= NULL
) {
748 interfacePrivate
->localized_name
= CFStringCreateCopy(NULL
, newName
);
757 SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan
, CFDictionaryRef newOptions
)
759 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
762 if (!isA_SCVLANInterface(vlan
)) {
763 _SCErrorSet(kSCStatusInvalidArgument
);
767 if ((newOptions
!= NULL
) && !isA_CFDictionary(newOptions
)) {
768 _SCErrorSet(kSCStatusInvalidArgument
);
772 // set options in the stored preferences
773 if (interfacePrivate
->prefs
!= NULL
) {
774 CFDictionaryRef dict
;
775 CFMutableDictionaryRef newDict
;
778 path
= CFStringCreateWithFormat(NULL
,
781 kSCPrefVirtualNetworkInterfaces
,
782 kSCNetworkInterfaceTypeVLAN
,
783 interfacePrivate
->entity_device
);
784 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
785 if (!isA_CFDictionary(dict
)) {
786 // if the prefs are confused
788 _SCErrorSet(kSCStatusFailed
);
792 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
793 if (newOptions
!= NULL
) {
794 CFDictionarySetValue(newDict
, kSCPropVirtualNetworkInterfacesVLANOptions
, newOptions
);
796 CFDictionaryRemoveValue(newDict
, kSCPropVirtualNetworkInterfacesVLANOptions
);
798 if (!CFEqual(dict
, newDict
)) {
799 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
805 // set options in the SCVLANInterfaceRef
807 if (interfacePrivate
->vlan
.options
!= NULL
) {
808 CFRelease(interfacePrivate
->vlan
.options
);
809 interfacePrivate
->vlan
.options
= NULL
;
811 if (newOptions
!= NULL
) {
812 interfacePrivate
->vlan
.options
= CFDictionaryCreateCopy(NULL
, newOptions
);
821 #pragma mark SCVLANInterface management
825 __vlan_set(int s
, CFStringRef interface_if
, CFStringRef physical_if
, CFNumberRef tag
)
831 bzero(&ifr
, sizeof(ifr
));
832 bzero(&vreq
, sizeof(vreq
));
835 (void) _SC_cfstring_to_cstring(interface_if
,
837 sizeof(ifr
.ifr_name
),
838 kCFStringEncodingASCII
);
839 ifr
.ifr_data
= (caddr_t
)&vreq
;
841 // physical interface
842 (void) _SC_cfstring_to_cstring(physical_if
,
844 sizeof(vreq
.vlr_parent
),
845 kCFStringEncodingASCII
);
848 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
849 vreq
.vlr_tag
= tag_val
;
851 // update physical interface and tag
852 if (ioctl(s
, SIOCSIFVLAN
, (caddr_t
)&ifr
) == -1) {
853 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno
));
854 _SCErrorSet(kSCStatusFailed
);
863 __vlan_clear(int s
, CFStringRef interface_if
)
868 bzero(&ifr
, sizeof(ifr
));
869 bzero(&vreq
, sizeof(vreq
));
872 (void) _SC_cfstring_to_cstring(interface_if
,
874 sizeof(ifr
.ifr_name
),
875 kCFStringEncodingASCII
);
876 ifr
.ifr_data
= (caddr_t
)&vreq
;
878 // clear physical interface
879 bzero(&vreq
.vlr_parent
, sizeof(vreq
.vlr_parent
));
884 // update physical interface and tag
885 if (ioctl(s
, SIOCSIFVLAN
, (caddr_t
)&ifr
) == -1) {
886 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno
));
887 _SCErrorSet(kSCStatusFailed
);
896 _SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs
)
898 CFArrayRef active
= NULL
;
899 CFArrayRef config
= NULL
;
900 CFMutableDictionaryRef devices
= NULL
;
908 _SCErrorSet(kSCStatusInvalidArgument
);
912 /* configured VLANs */
913 config
= SCVLANInterfaceCopyAll(prefs
);
914 nConfig
= (config
!= NULL
) ? CFArrayGetCount(config
) : 0;
916 /* physical interfaces */
917 devices
= CFDictionaryCreateMutable(NULL
,
919 &kCFTypeDictionaryKeyCallBacks
,
920 &kCFTypeDictionaryValueCallBacks
);
923 active
= _SCVLANInterfaceCopyActive();
924 nActive
= (active
!= NULL
) ? CFArrayGetCount(active
) : 0;
926 /* remove any no-longer-configured VLAN interfaces */
927 for (i
= 0; i
< nActive
; i
++) {
928 SCVLANInterfaceRef a_vlan
;
929 CFStringRef a_vlan_if
;
931 Boolean found
= FALSE
;
933 a_vlan
= CFArrayGetValueAtIndex(active
, i
);
934 a_vlan_if
= SCNetworkInterfaceGetBSDName(a_vlan
);
936 for (j
= 0; j
< nConfig
; j
++) {
937 SCVLANInterfaceRef c_vlan
;
938 CFStringRef c_vlan_if
;
940 c_vlan
= CFArrayGetValueAtIndex(config
, j
);
941 c_vlan_if
= SCNetworkInterfaceGetBSDName(c_vlan
);
943 if (CFEqual(a_vlan_if
, c_vlan_if
)) {
950 // remove VLAN interface
952 s
= inet_dgram_socket();
959 if (!__destroyInterface(s
, a_vlan_if
)) {
966 /* create (and update) configured VLAN interfaces */
967 for (i
= 0; i
< nConfig
; i
++) {
968 SCVLANInterfaceRef c_vlan
;
969 CFStringRef c_vlan_if
;
970 SCNetworkInterfaceRef c_vlan_physical
;
971 Boolean found
= FALSE
;
973 CFBooleanRef supported
;
975 c_vlan
= CFArrayGetValueAtIndex(config
, i
);
976 c_vlan_if
= SCNetworkInterfaceGetBSDName(c_vlan
);
977 c_vlan_physical
= SCVLANInterfaceGetPhysicalInterface(c_vlan
);
979 if (c_vlan_physical
== NULL
) {
982 // determine if the physical interface supports VLANs
983 supported
= CFDictionaryGetValue(devices
, c_vlan_physical
);
984 if (supported
== NULL
) {
985 SCNetworkInterfacePrivateRef c_vlan_physicalPrivate
= (SCNetworkInterfacePrivateRef
)c_vlan_physical
;
987 supported
= c_vlan_physicalPrivate
->supportsVLAN
? kCFBooleanTrue
989 CFDictionaryAddValue(devices
, c_vlan_physical
, supported
);
992 for (j
= 0; j
< nActive
; j
++) {
993 SCVLANInterfaceRef a_vlan
;
994 CFStringRef a_vlan_if
;
996 a_vlan
= CFArrayGetValueAtIndex(active
, j
);
997 a_vlan_if
= SCNetworkInterfaceGetBSDName(a_vlan
);
999 if (CFEqual(c_vlan_if
, a_vlan_if
)) {
1000 if (!CFEqual(c_vlan
, a_vlan
)) {
1001 // update VLAN interface
1003 s
= inet_dgram_socket();
1011 if (!CFBooleanGetValue(supported
)
1012 || !__vlan_clear(s
, c_vlan_if
)
1013 || !__vlan_set(s
, c_vlan_if
,
1014 SCNetworkInterfaceGetBSDName(c_vlan_physical
),
1015 SCVLANInterfaceGetTag(c_vlan
))) {
1016 // something went wrong, try to blow the VLAN away
1017 if (!CFBooleanGetValue(supported
)) {
1018 _SCErrorSet(kSCStatusFailed
);
1020 (void)__destroyInterface(s
, c_vlan_if
);
1030 if (!found
&& CFBooleanGetValue(supported
)) {
1031 // if the physical interface supports VLANs, add new interface
1035 s
= inet_dgram_socket();
1043 created
= __createInterface(s
, c_vlan_if
);
1047 SCNetworkInterfaceGetBSDName(c_vlan_physical
),
1048 SCVLANInterfaceGetTag(c_vlan
))) {
1050 // something went wrong, try to blow the VLAN away
1051 (void)__destroyInterface(s
, c_vlan_if
);
1063 if (active
) CFRelease(active
);
1064 if (config
) CFRelease(config
);
1065 if (devices
) CFRelease(devices
);
1066 if (s
!= -1) (void) close(s
);