2 * Copyright (c) 2003-2013, 2015 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 "SCPreferencesInternal.h"
41 #include <SystemConfiguration/SCValidation.h>
42 #include <SystemConfiguration/SCPrivate.h>
47 #include <sys/types.h>
48 #include <sys/ioctl.h>
49 #include <sys/socket.h>
50 #include <net/ethernet.h>
51 #define KERNEL_PRIVATE
53 #include <net/if_var.h>
55 #include <net/if_vlan_var.h>
56 #include <net/if_types.h>
58 /* ---------- VLAN support ---------- */
65 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
67 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
75 CFMutableArrayRef vlans
;
76 SCPreferencesRef ni_prefs
;
77 SCPreferencesRef prefs
;
78 } addContext
, *addContextRef
;
82 add_configured_interface(const void *key
, const void *value
, void *context
)
84 SCNetworkInterfacePrivateRef interfacePrivate
;
85 addContextRef myContext
= (addContextRef
)context
;
86 SCVLANInterfaceRef vlan
;
87 CFStringRef vlan_if
= (CFStringRef
)key
;
88 CFDictionaryRef vlan_info
= (CFDictionaryRef
)value
;
89 CFStringRef vlan_name
;
90 CFDictionaryRef vlan_options
;
91 SCNetworkInterfaceRef vlan_physical
= NULL
;
92 CFStringRef vlan_physical_if
;
95 vlan_physical_if
= CFDictionaryGetValue(vlan_info
, kSCPropVirtualNetworkInterfacesVLANInterface
);
96 if (!isA_CFString(vlan_physical_if
)) {
97 // if prefs are confused
101 vlan_tag
= CFDictionaryGetValue(vlan_info
, kSCPropVirtualNetworkInterfacesVLANTag
);
102 if (!isA_CFNumber(vlan_tag
)) {
103 // if prefs are confused
107 // create the VLAN interface
108 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(NULL
, vlan_if
);
109 assert(vlan
!= NULL
);
111 // set physical interface and tag
112 if (myContext
->ni_prefs
!= NULL
) {
113 vlan_physical
= __SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(NULL
, myContext
->ni_prefs
,
116 if (vlan_physical
== NULL
) {
117 vlan_physical
= _SCNetworkInterfaceCreateWithBSDName(NULL
, vlan_physical_if
,
118 kIncludeBondInterfaces
);
120 assert(vlan_physical
!= NULL
);
122 // since we KNOW that the physical interface supported VLANs when
123 // it was first established it's OK to force that state here ...
124 // and this is needed for the case when the interface (e.g. a
125 // dongle) is not currently attached to the system
126 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan_physical
;
127 interfacePrivate
->supportsVLAN
= TRUE
;
129 // and now we associate the physical interface and tag
130 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
131 CFRelease(vlan_physical
);
134 vlan_name
= CFDictionaryGetValue(vlan_info
, kSCPropUserDefinedName
);
135 if (isA_CFString(vlan_name
)) {
136 SCVLANInterfaceSetLocalizedDisplayName(vlan
, vlan_name
);
140 vlan_options
= CFDictionaryGetValue(vlan_info
, kSCPropVirtualNetworkInterfacesVLANOptions
);
141 if (isA_CFDictionary(vlan_options
)) {
142 SCVLANInterfaceSetOptions(vlan
, vlan_options
);
145 // estabish link to the stored configuration
146 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
147 interfacePrivate
->prefs
= CFRetain(myContext
->prefs
);
149 CFArrayAppendValue(myContext
->vlans
, vlan
);
156 static SCVLANInterfaceRef
157 findVLANInterfaceAndTag(SCPreferencesRef prefs
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
161 SCVLANInterfaceRef vlan
= NULL
;
164 vlans
= SCVLANInterfaceCopyAll(prefs
);
166 n
= CFArrayGetCount(vlans
);
167 for (i
= 0; i
< n
; i
++) {
168 SCVLANInterfaceRef config_vlan
;
169 SCNetworkInterfaceRef config_physical
;
170 CFNumberRef config_tag
;
172 config_vlan
= CFArrayGetValueAtIndex(vlans
, i
);
173 config_physical
= SCVLANInterfaceGetPhysicalInterface(config_vlan
);
174 config_tag
= SCVLANInterfaceGetTag(config_vlan
);
176 if ((config_physical
!= NULL
) && (config_tag
!= NULL
)) {
177 if (!CFEqual(physical
, config_physical
)) {
178 // if this VLAN has a different physical interface
182 if (!CFEqual(tag
, config_tag
)) {
183 // if this VLAN has a different tag
187 vlan
= CFRetain(config_vlan
);
198 #pragma mark SCVLANInterface APIs
201 static __inline__
void
202 my_CFDictionaryApplyFunction(CFDictionaryRef theDict
,
203 CFDictionaryApplierFunction applier
,
206 CFAllocatorRef myAllocator
;
207 CFDictionaryRef myDict
;
209 myAllocator
= CFGetAllocator(theDict
);
210 myDict
= CFDictionaryCreateCopy(myAllocator
, theDict
);
211 CFDictionaryApplyFunction(myDict
, applier
, context
);
218 SCVLANInterfaceCopyAll(SCPreferencesRef prefs
)
221 CFDictionaryRef dict
;
222 SCPreferencesRef ni_prefs
;
225 if ((prefs
== NULL
) ||
226 (__SCPreferencesUsingDefaultPrefs(prefs
) == TRUE
)) {
230 ni_prefs
= __SCPreferencesCreateNIPrefsFromPrefs(prefs
);
232 context
.vlans
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
233 context
.ni_prefs
= ni_prefs
;
234 context
.prefs
= prefs
;
236 path
= CFStringCreateWithFormat(NULL
,
239 kSCPrefVirtualNetworkInterfaces
,
240 kSCNetworkInterfaceTypeVLAN
);
241 dict
= SCPreferencesPathGetValue(prefs
, path
);
243 if (isA_CFDictionary(dict
)) {
244 my_CFDictionaryApplyFunction(dict
, add_configured_interface
, &context
);
246 if (ni_prefs
!= NULL
) {
249 return context
.vlans
;
254 addAvailableInterfaces(CFMutableArrayRef available
, CFArrayRef interfaces
,
260 n
= CFArrayGetCount(interfaces
);
261 for (i
= 0; i
< n
; i
++) {
262 SCNetworkInterfaceRef interface
;
263 SCNetworkInterfacePrivateRef interfacePrivate
;
265 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
266 interfacePrivate
= (SCNetworkInterfacePrivateRef
)interface
;
268 if ((excluded
!= NULL
)
269 && CFSetContainsValue(excluded
, interface
)) {
270 // exclude this interface
273 if (interfacePrivate
->supportsVLAN
) {
274 // if this interface is available
275 CFArrayAppendValue(available
, interface
);
284 SCVLANInterfaceCopyAvailablePhysicalInterfaces()
286 CFMutableArrayRef available
;
287 CFArrayRef bond_interfaces
= NULL
;
288 CFArrayRef bridge_interfaces
= NULL
;
289 CFMutableSetRef excluded
= NULL
;
290 CFArrayRef interfaces
;
291 SCPreferencesRef prefs
;
293 available
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
295 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL
);
297 #if !TARGET_OS_IPHONE
298 bond_interfaces
= SCBondInterfaceCopyAll(prefs
);
299 if (bond_interfaces
!= NULL
) {
300 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
301 __SCBondInterfaceListCollectMembers(bond_interfaces
, excluded
);
303 #endif // !TARGET_OS_IPHONE
305 bridge_interfaces
= SCBridgeInterfaceCopyAll(prefs
);
306 if (bridge_interfaces
!= NULL
) {
307 if (excluded
== NULL
) {
308 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
310 __SCBridgeInterfaceListCollectMembers(bridge_interfaces
, excluded
);
316 // add real interfaces that aren't part of a bond or bridge
317 interfaces
= __SCNetworkInterfaceCopyAll_IONetworkInterface();
318 if (interfaces
!= NULL
) {
319 addAvailableInterfaces(available
, interfaces
, excluded
);
320 CFRelease(interfaces
);
323 // add bond interfaces
324 if (bond_interfaces
!= NULL
) {
325 addAvailableInterfaces(available
, bond_interfaces
, NULL
);
326 CFRelease(bond_interfaces
);
329 // add bridge interfaces
330 if (bridge_interfaces
!= NULL
) {
331 addAvailableInterfaces(available
, bridge_interfaces
, NULL
);
332 CFRelease(bridge_interfaces
);
335 if (excluded
!= NULL
) {
344 _SCVLANInterfaceCopyActive(void)
346 struct ifaddrs
*ifap
;
349 CFMutableArrayRef vlans
= NULL
;
351 if (getifaddrs(&ifap
) == -1) {
352 SC_log(LOG_NOTICE
, "getifaddrs() failed: %s", strerror(errno
));
353 _SCErrorSet(kSCStatusFailed
);
357 s
= inet_dgram_socket();
363 vlans
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
365 for (ifp
= ifap
; ifp
!= NULL
; ifp
= ifp
->ifa_next
) {
366 struct if_data
*if_data
;
368 SCVLANInterfaceRef vlan
;
370 SCNetworkInterfaceRef vlan_physical
;
371 CFStringRef vlan_physical_if
;
372 CFNumberRef vlan_tag
;
373 char vlr_parent
[IFNAMSIZ
];
377 if_data
= (struct if_data
*)ifp
->ifa_data
;
379 || ifp
->ifa_addr
->sa_family
!= AF_LINK
380 || if_data
->ifi_type
!= IFT_L2VLAN
) {
384 bzero(&ifr
, sizeof(ifr
));
385 bzero(&vreq
, sizeof(vreq
));
386 strlcpy(ifr
.ifr_name
, ifp
->ifa_name
, sizeof(ifr
.ifr_name
));
387 ifr
.ifr_data
= (caddr_t
)&vreq
;
389 if (ioctl(s
, SIOCGIFVLAN
, (caddr_t
)&ifr
) == -1) {
390 SC_log(LOG_NOTICE
, "ioctl(SIOCGIFVLAN) failed: %s", strerror(errno
));
393 _SCErrorSet(kSCStatusFailed
);
397 // create the VLAN interface
398 vlan_if
= CFStringCreateWithCString(NULL
, ifp
->ifa_name
, kCFStringEncodingASCII
);
399 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(NULL
, vlan_if
);
400 assert(vlan
!= NULL
);
403 // set the physical interface and tag
404 strlcpy(vlr_parent
, vreq
.vlr_parent
, sizeof(vlr_parent
));
405 vlan_physical_if
= CFStringCreateWithCString(NULL
, vlr_parent
, kCFStringEncodingASCII
);
406 vlan_physical
= _SCNetworkInterfaceCreateWithBSDName(NULL
, vlan_physical_if
,
407 kIncludeBondInterfaces
);
408 assert(vlan_physical
!= NULL
);
409 CFRelease(vlan_physical_if
);
411 vlr_tag
= vreq
.vlr_tag
;
412 vlan_tag
= CFNumberCreate(NULL
, kCFNumberIntType
, &vlr_tag
);
413 assert(vlan_tag
!= NULL
);
415 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
416 CFRelease(vlan_physical
);
420 CFArrayAppendValue(vlans
, vlan
);
435 SCVLANInterfaceCreate(SCPreferencesRef prefs
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
437 CFAllocatorRef allocator
;
439 SCNetworkInterfacePrivateRef interfacePrivate
;
440 SCVLANInterfaceRef vlan
;
443 _SCErrorSet(kSCStatusInvalidArgument
);
447 if (!isA_SCNetworkInterface(physical
)) {
448 _SCErrorSet(kSCStatusInvalidArgument
);
452 interfacePrivate
= (SCNetworkInterfacePrivateRef
)physical
;
453 if (!interfacePrivate
->supportsVLAN
) {
454 if (__SCPreferencesUsingDefaultPrefs(prefs
) == FALSE
) {
455 interfacePrivate
->supportsVLAN
= TRUE
;
458 _SCErrorSet(kSCStatusInvalidArgument
);
463 if (isA_CFNumber(tag
)) {
466 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
467 if ((tag_val
< 1) || (tag_val
> 4094)) {
468 _SCErrorSet(kSCStatusInvalidArgument
);
472 _SCErrorSet(kSCStatusInvalidArgument
);
476 // make sure that physical interface and tag are not used
477 vlan
= findVLANInterfaceAndTag(prefs
, physical
, tag
);
480 _SCErrorSet(kSCStatusKeyExists
);
484 allocator
= CFGetAllocator(prefs
);
486 // create a new VLAN using an unused interface name
487 for (i
= 0; vlan
== NULL
; i
++) {
488 CFDictionaryRef dict
;
493 vlan_if
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("vlan%ld"), i
);
494 path
= CFStringCreateWithFormat(allocator
,
497 kSCPrefVirtualNetworkInterfaces
,
498 kSCNetworkInterfaceTypeVLAN
,
500 dict
= SCPreferencesPathGetValue(prefs
, path
);
502 // if VLAN interface name not available
508 // add the VLAN to the stored preferences
509 dict
= CFDictionaryCreate(allocator
,
511 &kCFTypeDictionaryKeyCallBacks
,
512 &kCFTypeDictionaryValueCallBacks
);
513 ok
= SCPreferencesPathSetValue(prefs
, path
, dict
);
517 // if the VLAN could not be saved
519 _SCErrorSet(kSCStatusFailed
);
523 // create the SCVLANInterfaceRef
524 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(allocator
, vlan_if
);
527 // estabish link to the stored configuration
528 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
529 interfacePrivate
->prefs
= CFRetain(prefs
);
531 // set physical interface and tag
532 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, physical
, tag
);
540 SCVLANInterfaceRemove(SCVLANInterfaceRef vlan
)
543 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
547 if (!isA_SCVLANInterface(vlan
)) {
548 _SCErrorSet(kSCStatusInvalidArgument
);
552 if (interfacePrivate
->prefs
== NULL
) {
553 _SCErrorSet(kSCStatusInvalidArgument
);
557 vlan_if
= SCNetworkInterfaceGetBSDName(vlan
);
558 path
= CFStringCreateWithFormat(NULL
,
561 kSCPrefVirtualNetworkInterfaces
,
562 kSCNetworkInterfaceTypeVLAN
,
564 ok
= SCPreferencesPathRemoveValue(interfacePrivate
->prefs
, path
);
571 SCNetworkInterfaceRef
572 SCVLANInterfaceGetPhysicalInterface(SCVLANInterfaceRef vlan
)
574 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
576 if (!isA_SCVLANInterface(vlan
)) {
577 _SCErrorSet(kSCStatusInvalidArgument
);
581 return interfacePrivate
->vlan
.interface
;
586 SCVLANInterfaceGetTag(SCVLANInterfaceRef vlan
)
588 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
590 if (!isA_SCVLANInterface(vlan
)) {
591 _SCErrorSet(kSCStatusInvalidArgument
);
595 return interfacePrivate
->vlan
.tag
;
600 SCVLANInterfaceGetOptions(SCVLANInterfaceRef vlan
)
602 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
604 if (!isA_SCVLANInterface(vlan
)) {
605 _SCErrorSet(kSCStatusInvalidArgument
);
609 return interfacePrivate
->vlan
.options
;
614 SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
616 SCNetworkInterfacePrivateRef interfacePrivate
;
618 SCPreferencesRef prefs
;
620 if (!isA_SCVLANInterface(vlan
)) {
621 _SCErrorSet(kSCStatusInvalidArgument
);
625 if (!isA_SCNetworkInterface(physical
)) {
626 _SCErrorSet(kSCStatusInvalidArgument
);
630 interfacePrivate
= (SCNetworkInterfacePrivateRef
)physical
;
631 prefs
= interfacePrivate
->prefs
;
633 if (!interfacePrivate
->supportsVLAN
) {
634 if (__SCPreferencesUsingDefaultPrefs(prefs
) == FALSE
) {
635 interfacePrivate
->supportsVLAN
= TRUE
;
638 _SCErrorSet(kSCStatusInvalidArgument
);
643 if (isA_CFNumber(tag
)) {
646 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
647 if ((tag_val
< 1) || (tag_val
> 4094)) {
648 _SCErrorSet(kSCStatusInvalidArgument
);
652 _SCErrorSet(kSCStatusInvalidArgument
);
656 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
657 if (interfacePrivate
->prefs
!= NULL
) {
658 SCVLANInterfaceRef config_vlan
;
659 CFDictionaryRef dict
;
660 CFMutableDictionaryRef newDict
;
663 // make sure that physical interface and tag are not used
664 config_vlan
= findVLANInterfaceAndTag(interfacePrivate
->prefs
, physical
, tag
);
665 if (config_vlan
!= NULL
) {
666 if (!CFEqual(vlan
, config_vlan
)) {
667 CFRelease(config_vlan
);
668 _SCErrorSet(kSCStatusKeyExists
);
671 CFRelease(config_vlan
);
674 // set interface/tag in the stored preferences
675 path
= CFStringCreateWithFormat(NULL
,
678 kSCPrefVirtualNetworkInterfaces
,
679 kSCNetworkInterfaceTypeVLAN
,
680 interfacePrivate
->entity_device
);
681 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
682 if (!isA_CFDictionary(dict
)) {
683 // if the prefs are confused
685 _SCErrorSet(kSCStatusFailed
);
689 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
690 CFDictionarySetValue(newDict
,
691 kSCPropVirtualNetworkInterfacesVLANInterface
,
692 SCNetworkInterfaceGetBSDName(physical
));
693 CFDictionarySetValue(newDict
, kSCPropVirtualNetworkInterfacesVLANTag
, tag
);
694 if (!CFEqual(dict
, newDict
)) {
695 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
702 SCNetworkInterfacePrivateRef newInterface
;
705 // set physical interface
706 newInterface
= __SCNetworkInterfaceCreateCopy(NULL
,
708 interfacePrivate
->prefs
,
709 interfacePrivate
->serviceID
);
710 save
= interfacePrivate
->vlan
.interface
;
711 interfacePrivate
->vlan
.interface
= (SCNetworkInterfaceRef
)newInterface
;
712 if (save
!= NULL
) CFRelease(save
);
715 save
= interfacePrivate
->vlan
.tag
;
716 interfacePrivate
->vlan
.tag
= CFRetain(tag
);
717 if (save
!= NULL
) CFRelease(save
);
725 SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan
, CFStringRef newName
)
727 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
730 if (!isA_SCVLANInterface(vlan
)) {
731 _SCErrorSet(kSCStatusInvalidArgument
);
735 if ((newName
!= NULL
) && !isA_CFString(newName
)) {
736 _SCErrorSet(kSCStatusInvalidArgument
);
740 // set name in the stored preferences
741 if (interfacePrivate
->prefs
!= NULL
) {
742 CFDictionaryRef dict
;
743 CFMutableDictionaryRef newDict
;
746 path
= CFStringCreateWithFormat(NULL
,
749 kSCPrefVirtualNetworkInterfaces
,
750 kSCNetworkInterfaceTypeVLAN
,
751 interfacePrivate
->entity_device
);
752 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
753 if (!isA_CFDictionary(dict
)) {
754 // if the prefs are confused
756 _SCErrorSet(kSCStatusFailed
);
760 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
761 if (newName
!= NULL
) {
762 CFDictionarySetValue(newDict
, kSCPropUserDefinedName
, newName
);
764 CFDictionaryRemoveValue(newDict
, kSCPropUserDefinedName
);
766 if (!CFEqual(dict
, newDict
)) {
767 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
773 // set name in the SCVLANInterfaceRef
775 if (interfacePrivate
->localized_name
!= NULL
) {
776 CFRelease(interfacePrivate
->localized_name
);
777 interfacePrivate
->localized_name
= NULL
;
779 if (newName
!= NULL
) {
780 interfacePrivate
->localized_name
= CFStringCreateCopy(NULL
, newName
);
789 SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan
, CFDictionaryRef newOptions
)
791 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
794 if (!isA_SCVLANInterface(vlan
)) {
795 _SCErrorSet(kSCStatusInvalidArgument
);
799 if ((newOptions
!= NULL
) && !isA_CFDictionary(newOptions
)) {
800 _SCErrorSet(kSCStatusInvalidArgument
);
804 // set options in the stored preferences
805 if (interfacePrivate
->prefs
!= NULL
) {
806 CFDictionaryRef dict
;
807 CFMutableDictionaryRef newDict
;
810 path
= CFStringCreateWithFormat(NULL
,
813 kSCPrefVirtualNetworkInterfaces
,
814 kSCNetworkInterfaceTypeVLAN
,
815 interfacePrivate
->entity_device
);
816 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
817 if (!isA_CFDictionary(dict
)) {
818 // if the prefs are confused
820 _SCErrorSet(kSCStatusFailed
);
824 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
825 if (newOptions
!= NULL
) {
826 CFDictionarySetValue(newDict
, kSCPropVirtualNetworkInterfacesVLANOptions
, newOptions
);
828 CFDictionaryRemoveValue(newDict
, kSCPropVirtualNetworkInterfacesVLANOptions
);
830 if (!CFEqual(dict
, newDict
)) {
831 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
837 // set options in the SCVLANInterfaceRef
839 if (interfacePrivate
->vlan
.options
!= NULL
) {
840 CFRelease(interfacePrivate
->vlan
.options
);
841 interfacePrivate
->vlan
.options
= NULL
;
843 if (newOptions
!= NULL
) {
844 interfacePrivate
->vlan
.options
= CFDictionaryCreateCopy(NULL
, newOptions
);
853 #pragma mark SCVLANInterface management
857 __vlan_set(int s
, CFStringRef interface_if
, CFStringRef physical_if
, CFNumberRef tag
)
863 bzero(&ifr
, sizeof(ifr
));
864 bzero(&vreq
, sizeof(vreq
));
867 (void) _SC_cfstring_to_cstring(interface_if
,
869 sizeof(ifr
.ifr_name
),
870 kCFStringEncodingASCII
);
871 ifr
.ifr_data
= (caddr_t
)&vreq
;
873 // physical interface
874 (void) _SC_cfstring_to_cstring(physical_if
,
876 sizeof(vreq
.vlr_parent
),
877 kCFStringEncodingASCII
);
880 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
881 vreq
.vlr_tag
= tag_val
;
883 // update physical interface and tag
884 if (ioctl(s
, SIOCSIFVLAN
, (caddr_t
)&ifr
) == -1) {
885 SC_log(LOG_NOTICE
, "ioctl(SIOCSIFVLAN) failed: %s", strerror(errno
));
886 _SCErrorSet(kSCStatusFailed
);
895 __vlan_clear(int s
, CFStringRef interface_if
)
900 bzero(&ifr
, sizeof(ifr
));
901 bzero(&vreq
, sizeof(vreq
));
904 (void) _SC_cfstring_to_cstring(interface_if
,
906 sizeof(ifr
.ifr_name
),
907 kCFStringEncodingASCII
);
908 ifr
.ifr_data
= (caddr_t
)&vreq
;
910 // clear physical interface
911 bzero(&vreq
.vlr_parent
, sizeof(vreq
.vlr_parent
));
916 // update physical interface and tag
917 if (ioctl(s
, SIOCSIFVLAN
, (caddr_t
)&ifr
) == -1) {
918 SC_log(LOG_NOTICE
, "ioctl(SIOCSIFVLAN) failed: %s", strerror(errno
));
919 _SCErrorSet(kSCStatusFailed
);
928 _SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs
)
930 CFArrayRef active
= NULL
;
931 CFArrayRef config
= NULL
;
932 CFMutableDictionaryRef devices
= NULL
;
940 _SCErrorSet(kSCStatusInvalidArgument
);
944 /* configured VLANs */
945 config
= SCVLANInterfaceCopyAll(prefs
);
946 nConfig
= (config
!= NULL
) ? CFArrayGetCount(config
) : 0;
948 /* physical interfaces */
949 devices
= CFDictionaryCreateMutable(NULL
,
951 &kCFTypeDictionaryKeyCallBacks
,
952 &kCFTypeDictionaryValueCallBacks
);
955 active
= _SCVLANInterfaceCopyActive();
956 nActive
= (active
!= NULL
) ? CFArrayGetCount(active
) : 0;
958 /* remove any no-longer-configured VLAN interfaces */
959 for (i
= 0; i
< nActive
; i
++) {
960 SCVLANInterfaceRef a_vlan
;
961 CFStringRef a_vlan_if
;
963 Boolean found
= FALSE
;
965 a_vlan
= CFArrayGetValueAtIndex(active
, i
);
966 a_vlan_if
= SCNetworkInterfaceGetBSDName(a_vlan
);
968 for (j
= 0; j
< nConfig
; j
++) {
969 SCVLANInterfaceRef c_vlan
;
970 CFStringRef c_vlan_if
;
972 c_vlan
= CFArrayGetValueAtIndex(config
, j
);
973 c_vlan_if
= SCNetworkInterfaceGetBSDName(c_vlan
);
975 if (CFEqual(a_vlan_if
, c_vlan_if
)) {
982 // remove VLAN interface
984 s
= inet_dgram_socket();
991 if (!__destroyInterface(s
, a_vlan_if
)) {
998 /* create (and update) configured VLAN interfaces */
999 for (i
= 0; i
< nConfig
; i
++) {
1000 SCVLANInterfaceRef c_vlan
;
1001 CFStringRef c_vlan_if
;
1002 SCNetworkInterfaceRef c_vlan_physical
;
1003 Boolean found
= FALSE
;
1005 CFBooleanRef supported
;
1007 c_vlan
= CFArrayGetValueAtIndex(config
, i
);
1008 c_vlan_if
= SCNetworkInterfaceGetBSDName(c_vlan
);
1009 c_vlan_physical
= SCVLANInterfaceGetPhysicalInterface(c_vlan
);
1011 if (c_vlan_physical
== NULL
) {
1014 // determine if the physical interface supports VLANs
1015 supported
= CFDictionaryGetValue(devices
, c_vlan_physical
);
1016 if (supported
== NULL
) {
1017 SCNetworkInterfacePrivateRef c_vlan_physicalPrivate
= (SCNetworkInterfacePrivateRef
)c_vlan_physical
;
1019 supported
= c_vlan_physicalPrivate
->supportsVLAN
? kCFBooleanTrue
1021 CFDictionaryAddValue(devices
, c_vlan_physical
, supported
);
1024 for (j
= 0; j
< nActive
; j
++) {
1025 SCVLANInterfaceRef a_vlan
;
1026 CFStringRef a_vlan_if
;
1028 a_vlan
= CFArrayGetValueAtIndex(active
, j
);
1029 a_vlan_if
= SCNetworkInterfaceGetBSDName(a_vlan
);
1031 if (CFEqual(c_vlan_if
, a_vlan_if
)) {
1032 if (!CFEqual(c_vlan
, a_vlan
)) {
1033 // update VLAN interface
1035 s
= inet_dgram_socket();
1043 if (!CFBooleanGetValue(supported
)
1044 || !__vlan_clear(s
, c_vlan_if
)
1045 || !__vlan_set(s
, c_vlan_if
,
1046 SCNetworkInterfaceGetBSDName(c_vlan_physical
),
1047 SCVLANInterfaceGetTag(c_vlan
))) {
1048 // something went wrong, try to blow the VLAN away
1049 if (!CFBooleanGetValue(supported
)) {
1050 _SCErrorSet(kSCStatusFailed
);
1052 (void)__destroyInterface(s
, c_vlan_if
);
1062 if (!found
&& CFBooleanGetValue(supported
)) {
1063 // if the physical interface supports VLANs, add new interface
1067 s
= inet_dgram_socket();
1075 created
= __createInterface(s
, c_vlan_if
);
1079 SCNetworkInterfaceGetBSDName(c_vlan_physical
),
1080 SCVLANInterfaceGetTag(c_vlan
))) {
1082 // something went wrong, try to blow the VLAN away
1083 (void)__destroyInterface(s
, c_vlan_if
);
1095 if (active
) CFRelease(active
);
1096 if (config
) CFRelease(config
);
1097 if (devices
) CFRelease(devices
);
1098 if (s
!= -1) (void) close(s
);