2 * Copyright (c) 2003-2011 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
);
108 // set physical interface and tag
109 vlan_physical
= _SCNetworkInterfaceCreateWithBSDName(NULL
, vlan_physical_if
,
110 kIncludeBondInterfaces
);
111 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
112 CFRelease(vlan_physical
);
115 vlan_name
= CFDictionaryGetValue(vlan_info
, kSCPropUserDefinedName
);
116 if (isA_CFString(vlan_name
)) {
117 SCVLANInterfaceSetLocalizedDisplayName(vlan
, vlan_name
);
121 vlan_options
= CFDictionaryGetValue(vlan_info
, kSCPropVirtualNetworkInterfacesVLANOptions
);
122 if (isA_CFDictionary(vlan_options
)) {
123 SCVLANInterfaceSetOptions(vlan
, vlan_options
);
126 // estabish link to the stored configuration
127 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
128 interfacePrivate
->prefs
= CFRetain(myContext
->prefs
);
130 CFArrayAppendValue(myContext
->vlans
, vlan
);
138 add_legacy_configuration(addContextRef myContext
)
142 SCPreferencesRef prefs
;
145 #define VLAN_PREFERENCES_ID CFSTR("VirtualNetworkInterfaces.plist")
146 #define VLAN_PREFERENCES_VLANS CFSTR("VLANs")
147 #define __kVLANInterface_interface CFSTR("interface") // e.g. vlan0, vlan1, ...
148 #define __kVLANInterface_device CFSTR("device") // e.g. en0, en1, ...
149 #define __kVLANInterface_tag CFSTR("tag") // e.g. 1 <= tag <= 4094
150 #define __kVLANInterface_options CFSTR("options") // e.g. UserDefinedName
152 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCVLANInterfaceCopyAll"), VLAN_PREFERENCES_ID
);
157 vlans
= SCPreferencesGetValue(prefs
, VLAN_PREFERENCES_VLANS
);
158 if ((vlans
!= NULL
) && !isA_CFArray(vlans
)) {
159 CFRelease(prefs
); // if the prefs are confused
163 n
= (vlans
!= NULL
) ? CFArrayGetCount(vlans
) : 0;
164 for (i
= 0; i
< n
; i
++) {
165 CFDictionaryRef dict
;
166 SCNetworkInterfacePrivateRef interfacePrivate
;
168 CFDictionaryRef options
;
170 SCVLANInterfaceRef vlan
;
172 CFDictionaryRef vlan_dict
;
173 SCNetworkInterfaceRef vlan_physical
;
174 CFStringRef vlan_physical_if
;
175 CFNumberRef vlan_tag
;
177 vlan_dict
= CFArrayGetValueAtIndex(vlans
, i
);
178 if (!isA_CFDictionary(vlan_dict
)) {
179 continue; // if the prefs are confused
182 vlan_if
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_interface
);
183 if (!isA_CFString(vlan_if
)) {
184 continue; // if the prefs are confused
187 vlan_physical_if
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_device
);
188 if (!isA_CFString(vlan_physical_if
)) {
189 continue; // if the prefs are confused
192 vlan_tag
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_tag
);
193 if (!isA_CFNumber(vlan_tag
)) {
194 continue; // if the prefs are confused
197 // check if this VLAN interface has already been allocated
198 path
= CFStringCreateWithFormat(NULL
,
201 kSCPrefVirtualNetworkInterfaces
,
202 kSCNetworkInterfaceTypeVLAN
,
204 dict
= SCPreferencesPathGetValue(myContext
->prefs
, path
);
206 // if VLAN interface name not available
211 // add a placeholder for the VLAN in the stored preferences
212 dict
= CFDictionaryCreate(NULL
,
214 &kCFTypeDictionaryKeyCallBacks
,
215 &kCFTypeDictionaryValueCallBacks
);
216 ok
= SCPreferencesPathSetValue(myContext
->prefs
, path
, dict
);
220 // if the VLAN could not be saved
224 // create the VLAN interface
225 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(NULL
, vlan_if
);
227 // estabish link to the stored configuration
228 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
229 interfacePrivate
->prefs
= CFRetain(myContext
->prefs
);
231 // set the interface and tag (which updates the stored preferences)
232 vlan_physical
= _SCNetworkInterfaceCreateWithBSDName(NULL
, vlan_physical_if
,
233 kIncludeBondInterfaces
);
234 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
235 CFRelease(vlan_physical
);
237 // set display name (which updates the stored preferences)
238 options
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_options
);
239 if (isA_CFDictionary(options
)) {
240 CFStringRef vlan_name
;
242 vlan_name
= CFDictionaryGetValue(options
, CFSTR("VLAN Name"));
243 if (isA_CFString(vlan_name
)) {
244 SCVLANInterfaceSetLocalizedDisplayName(vlan
, vlan_name
);
248 CFArrayAppendValue(myContext
->vlans
, vlan
);
257 static SCVLANInterfaceRef
258 findVLANInterfaceAndTag(SCPreferencesRef prefs
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
262 SCVLANInterfaceRef vlan
= NULL
;
265 vlans
= SCVLANInterfaceCopyAll(prefs
);
267 n
= CFArrayGetCount(vlans
);
268 for (i
= 0; i
< n
; i
++) {
269 SCVLANInterfaceRef config_vlan
;
270 SCNetworkInterfaceRef config_physical
;
271 CFNumberRef config_tag
;
273 config_vlan
= CFArrayGetValueAtIndex(vlans
, i
);
274 config_physical
= SCVLANInterfaceGetPhysicalInterface(config_vlan
);
275 config_tag
= SCVLANInterfaceGetTag(config_vlan
);
277 if ((config_physical
!= NULL
) && (config_tag
!= NULL
)) {
278 if (!CFEqual(physical
, config_physical
)) {
279 // if this VLAN has a different physical interface
283 if (!CFEqual(tag
, config_tag
)) {
284 // if this VLAN has a different tag
288 vlan
= CFRetain(config_vlan
);
299 #pragma mark SCVLANInterface APIs
303 SCVLANInterfaceCopyAll(SCPreferencesRef prefs
)
306 CFDictionaryRef dict
;
309 context
.vlans
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
310 context
.prefs
= prefs
;
312 path
= CFStringCreateWithFormat(NULL
,
315 kSCPrefVirtualNetworkInterfaces
,
316 kSCNetworkInterfaceTypeVLAN
);
317 dict
= SCPreferencesPathGetValue(prefs
, path
);
318 if (isA_CFDictionary(dict
)) {
319 CFDictionaryApplyFunction(dict
, add_configured_interface
, &context
);
321 // no VLAN configuration, upgrade from legacy configuration
322 dict
= CFDictionaryCreate(NULL
,
324 &kCFTypeDictionaryKeyCallBacks
,
325 &kCFTypeDictionaryValueCallBacks
);
326 (void) SCPreferencesPathSetValue(prefs
, path
, dict
);
329 add_legacy_configuration(&context
);
333 return context
.vlans
;
338 addAvailableInterfaces(CFMutableArrayRef available
, CFArrayRef interfaces
,
344 n
= CFArrayGetCount(interfaces
);
345 for (i
= 0; i
< n
; i
++) {
346 SCNetworkInterfaceRef interface
;
347 SCNetworkInterfacePrivateRef interfacePrivate
;
349 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
350 interfacePrivate
= (SCNetworkInterfacePrivateRef
)interface
;
352 if ((excluded
!= NULL
)
353 && CFSetContainsValue(excluded
, interface
)) {
354 // exclude this interface
357 if (interfacePrivate
->supportsVLAN
) {
358 // if this interface is available
359 CFArrayAppendValue(available
, interface
);
368 SCVLANInterfaceCopyAvailablePhysicalInterfaces()
370 CFMutableArrayRef available
;
371 CFArrayRef bond_interfaces
= NULL
;
372 CFArrayRef bridge_interfaces
= NULL
;
373 CFMutableSetRef excluded
= NULL
;
374 CFArrayRef interfaces
;
375 SCPreferencesRef prefs
;
377 available
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
379 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL
);
381 #if !TARGET_OS_IPHONE
382 bond_interfaces
= SCBondInterfaceCopyAll(prefs
);
383 if (bond_interfaces
!= NULL
) {
384 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
385 __SCBondInterfaceListCollectMembers(bond_interfaces
, excluded
);
387 #endif // !TARGET_OS_IPHONE
389 bridge_interfaces
= SCBridgeInterfaceCopyAll(prefs
);
390 if (bridge_interfaces
!= NULL
) {
391 if (excluded
== NULL
) {
392 excluded
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
394 __SCBridgeInterfaceListCollectMembers(bridge_interfaces
, excluded
);
400 // add real interfaces that aren't part of a bond or bridge
401 interfaces
= __SCNetworkInterfaceCopyAll_IONetworkInterface();
402 if (interfaces
!= NULL
) {
403 addAvailableInterfaces(available
, interfaces
, excluded
);
404 CFRelease(interfaces
);
407 // add bond interfaces
408 if (bond_interfaces
!= NULL
) {
409 addAvailableInterfaces(available
, bond_interfaces
, NULL
);
410 CFRelease(bond_interfaces
);
413 // add bridge interfaces
414 if (bridge_interfaces
!= NULL
) {
415 addAvailableInterfaces(available
, bridge_interfaces
, NULL
);
416 CFRelease(bridge_interfaces
);
419 if (excluded
!= NULL
) {
428 _SCVLANInterfaceCopyActive(void)
430 struct ifaddrs
*ifap
;
433 CFMutableArrayRef vlans
= NULL
;
435 if (getifaddrs(&ifap
) == -1) {
436 SCLog(TRUE
, LOG_ERR
, CFSTR("getifaddrs() failed: %s"), strerror(errno
));
437 _SCErrorSet(kSCStatusFailed
);
441 s
= inet_dgram_socket();
447 vlans
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
449 for (ifp
= ifap
; ifp
!= NULL
; ifp
= ifp
->ifa_next
) {
450 struct if_data
*if_data
;
452 SCVLANInterfaceRef vlan
;
454 SCNetworkInterfaceRef vlan_physical
;
455 CFStringRef vlan_physical_if
;
456 CFNumberRef vlan_tag
;
457 char vlr_parent
[IFNAMSIZ
];
461 if_data
= (struct if_data
*)ifp
->ifa_data
;
463 || ifp
->ifa_addr
->sa_family
!= AF_LINK
464 || if_data
->ifi_type
!= IFT_L2VLAN
) {
468 bzero(&ifr
, sizeof(ifr
));
469 bzero(&vreq
, sizeof(vreq
));
470 strlcpy(ifr
.ifr_name
, ifp
->ifa_name
, sizeof(ifr
.ifr_name
));
471 ifr
.ifr_data
= (caddr_t
)&vreq
;
473 if (ioctl(s
, SIOCGIFVLAN
, (caddr_t
)&ifr
) == -1) {
474 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl() failed: %s"), strerror(errno
));
477 _SCErrorSet(kSCStatusFailed
);
481 // create the VLAN interface
482 vlan_if
= CFStringCreateWithCString(NULL
, ifp
->ifa_name
, kCFStringEncodingASCII
);
483 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(NULL
, vlan_if
);
486 // set the physical interface and tag
487 strlcpy(vlr_parent
, vreq
.vlr_parent
, sizeof(vlr_parent
));
488 vlan_physical_if
= CFStringCreateWithCString(NULL
, vlr_parent
, kCFStringEncodingASCII
);
489 vlan_physical
= _SCNetworkInterfaceCreateWithBSDName(NULL
, vlan_physical_if
,
490 kIncludeBondInterfaces
);
491 CFRelease(vlan_physical_if
);
493 vlr_tag
= vreq
.vlr_tag
;
494 vlan_tag
= CFNumberCreate(NULL
, kCFNumberIntType
, &vlr_tag
);
496 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
497 CFRelease(vlan_physical
);
501 CFArrayAppendValue(vlans
, vlan
);
514 SCVLANInterfaceCreate(SCPreferencesRef prefs
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
516 CFAllocatorRef allocator
;
518 SCNetworkInterfacePrivateRef interfacePrivate
;
519 SCVLANInterfaceRef vlan
;
522 _SCErrorSet(kSCStatusInvalidArgument
);
526 if (!isA_SCNetworkInterface(physical
)) {
527 _SCErrorSet(kSCStatusInvalidArgument
);
531 interfacePrivate
= (SCNetworkInterfacePrivateRef
)physical
;
532 if (!interfacePrivate
->supportsVLAN
) {
533 _SCErrorSet(kSCStatusInvalidArgument
);
537 if (isA_CFNumber(tag
)) {
540 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
541 if ((tag_val
< 1) || (tag_val
> 4094)) {
542 _SCErrorSet(kSCStatusInvalidArgument
);
546 _SCErrorSet(kSCStatusInvalidArgument
);
550 // make sure that physical interface and tag are not used
551 vlan
= findVLANInterfaceAndTag(prefs
, physical
, tag
);
554 _SCErrorSet(kSCStatusKeyExists
);
558 allocator
= CFGetAllocator(prefs
);
560 // create a new VLAN using an unused interface name
561 for (i
= 0; vlan
== NULL
; i
++) {
562 CFDictionaryRef dict
;
567 vlan_if
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("vlan%d"), i
);
568 path
= CFStringCreateWithFormat(allocator
,
571 kSCPrefVirtualNetworkInterfaces
,
572 kSCNetworkInterfaceTypeVLAN
,
574 dict
= SCPreferencesPathGetValue(prefs
, path
);
576 // if VLAN interface name not available
582 // add the VLAN to the stored preferences
583 dict
= CFDictionaryCreate(allocator
,
585 &kCFTypeDictionaryKeyCallBacks
,
586 &kCFTypeDictionaryValueCallBacks
);
587 ok
= SCPreferencesPathSetValue(prefs
, path
, dict
);
591 // if the VLAN could not be saved
593 _SCErrorSet(kSCStatusFailed
);
597 // create the SCVLANInterfaceRef
598 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(allocator
, vlan_if
);
601 // estabish link to the stored configuration
602 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
603 interfacePrivate
->prefs
= CFRetain(prefs
);
605 // set physical interface and tag
606 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, physical
, tag
);
614 SCVLANInterfaceRemove(SCVLANInterfaceRef vlan
)
617 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
621 if (!isA_SCVLANInterface(vlan
)) {
622 _SCErrorSet(kSCStatusInvalidArgument
);
626 if (interfacePrivate
->prefs
== NULL
) {
627 _SCErrorSet(kSCStatusInvalidArgument
);
631 vlan_if
= SCNetworkInterfaceGetBSDName(vlan
);
632 path
= CFStringCreateWithFormat(NULL
,
635 kSCPrefVirtualNetworkInterfaces
,
636 kSCNetworkInterfaceTypeVLAN
,
638 ok
= SCPreferencesPathRemoveValue(interfacePrivate
->prefs
, path
);
645 SCNetworkInterfaceRef
646 SCVLANInterfaceGetPhysicalInterface(SCVLANInterfaceRef vlan
)
648 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
650 if (!isA_SCVLANInterface(vlan
)) {
651 _SCErrorSet(kSCStatusInvalidArgument
);
655 return interfacePrivate
->vlan
.interface
;
660 SCVLANInterfaceGetTag(SCVLANInterfaceRef vlan
)
662 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
664 if (!isA_SCVLANInterface(vlan
)) {
665 _SCErrorSet(kSCStatusInvalidArgument
);
669 return interfacePrivate
->vlan
.tag
;
674 SCVLANInterfaceGetOptions(SCVLANInterfaceRef vlan
)
676 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
678 if (!isA_SCVLANInterface(vlan
)) {
679 _SCErrorSet(kSCStatusInvalidArgument
);
683 return interfacePrivate
->vlan
.options
;
688 SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
690 SCNetworkInterfacePrivateRef interfacePrivate
;
693 if (!isA_SCVLANInterface(vlan
)) {
694 _SCErrorSet(kSCStatusInvalidArgument
);
698 if (!isA_SCNetworkInterface(physical
)) {
699 _SCErrorSet(kSCStatusInvalidArgument
);
703 interfacePrivate
= (SCNetworkInterfacePrivateRef
)physical
;
704 if (!interfacePrivate
->supportsVLAN
) {
705 _SCErrorSet(kSCStatusInvalidArgument
);
709 if (isA_CFNumber(tag
)) {
712 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
713 if ((tag_val
< 1) || (tag_val
> 4094)) {
714 _SCErrorSet(kSCStatusInvalidArgument
);
718 _SCErrorSet(kSCStatusInvalidArgument
);
722 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
723 if (interfacePrivate
->prefs
!= NULL
) {
724 SCVLANInterfaceRef config_vlan
;
725 CFDictionaryRef dict
;
726 CFMutableDictionaryRef newDict
;
729 // make sure that physical interface and tag are not used
730 config_vlan
= findVLANInterfaceAndTag(interfacePrivate
->prefs
, physical
, tag
);
731 if (config_vlan
!= NULL
) {
732 if (!CFEqual(vlan
, config_vlan
)) {
733 CFRelease(config_vlan
);
734 _SCErrorSet(kSCStatusKeyExists
);
737 CFRelease(config_vlan
);
740 // set interface/tag in the stored preferences
741 path
= CFStringCreateWithFormat(NULL
,
744 kSCPrefVirtualNetworkInterfaces
,
745 kSCNetworkInterfaceTypeVLAN
,
746 interfacePrivate
->entity_device
);
747 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
748 if (!isA_CFDictionary(dict
)) {
749 // if the prefs are confused
751 _SCErrorSet(kSCStatusFailed
);
755 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
756 CFDictionarySetValue(newDict
,
757 kSCPropVirtualNetworkInterfacesVLANInterface
,
758 SCNetworkInterfaceGetBSDName(physical
));
759 CFDictionarySetValue(newDict
, kSCPropVirtualNetworkInterfacesVLANTag
, tag
);
760 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
766 SCNetworkInterfacePrivateRef newInterface
;
769 // set physical interface
770 newInterface
= __SCNetworkInterfaceCreateCopy(NULL
,
772 interfacePrivate
->prefs
,
773 interfacePrivate
->serviceID
);
774 save
= interfacePrivate
->vlan
.interface
;
775 interfacePrivate
->vlan
.interface
= (SCNetworkInterfaceRef
)newInterface
;
776 if (save
!= NULL
) CFRelease(save
);
779 save
= interfacePrivate
->vlan
.tag
;
780 interfacePrivate
->vlan
.tag
= CFRetain(tag
);
781 if (save
!= NULL
) CFRelease(save
);
789 SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan
, CFStringRef newName
)
791 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
794 if (!isA_SCVLANInterface(vlan
)) {
795 _SCErrorSet(kSCStatusInvalidArgument
);
799 if ((newName
!= NULL
) && !isA_CFString(newName
)) {
800 _SCErrorSet(kSCStatusInvalidArgument
);
804 // set name 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 (newName
!= NULL
) {
826 CFDictionarySetValue(newDict
, kSCPropUserDefinedName
, newName
);
828 CFDictionaryRemoveValue(newDict
, kSCPropUserDefinedName
);
830 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
835 // set name in the SCVLANInterfaceRef
837 if (interfacePrivate
->localized_name
!= NULL
) {
838 CFRelease(interfacePrivate
->localized_name
);
839 interfacePrivate
->localized_name
= NULL
;
841 if (newName
!= NULL
) {
842 interfacePrivate
->localized_name
= CFStringCreateCopy(NULL
, newName
);
851 SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan
, CFDictionaryRef newOptions
)
853 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
856 if (!isA_SCVLANInterface(vlan
)) {
857 _SCErrorSet(kSCStatusInvalidArgument
);
861 if ((newOptions
!= NULL
) && !isA_CFDictionary(newOptions
)) {
862 _SCErrorSet(kSCStatusInvalidArgument
);
866 // set options in the stored preferences
867 if (interfacePrivate
->prefs
!= NULL
) {
868 CFDictionaryRef dict
;
869 CFMutableDictionaryRef newDict
;
872 path
= CFStringCreateWithFormat(NULL
,
875 kSCPrefVirtualNetworkInterfaces
,
876 kSCNetworkInterfaceTypeVLAN
,
877 interfacePrivate
->entity_device
);
878 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
879 if (!isA_CFDictionary(dict
)) {
880 // if the prefs are confused
882 _SCErrorSet(kSCStatusFailed
);
886 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
887 if (newOptions
!= NULL
) {
888 CFDictionarySetValue(newDict
, kSCPropVirtualNetworkInterfacesVLANOptions
, newOptions
);
890 CFDictionaryRemoveValue(newDict
, kSCPropVirtualNetworkInterfacesVLANOptions
);
892 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
897 // set options in the SCVLANInterfaceRef
899 if (interfacePrivate
->vlan
.options
!= NULL
) {
900 CFRelease(interfacePrivate
->vlan
.options
);
901 interfacePrivate
->vlan
.options
= NULL
;
903 if (newOptions
!= NULL
) {
904 interfacePrivate
->vlan
.options
= CFDictionaryCreateCopy(NULL
, newOptions
);
913 #pragma mark SCVLANInterface management
917 __vlan_set(int s
, CFStringRef interface_if
, CFStringRef physical_if
, CFNumberRef tag
)
923 bzero(&ifr
, sizeof(ifr
));
924 bzero(&vreq
, sizeof(vreq
));
927 (void) _SC_cfstring_to_cstring(interface_if
,
929 sizeof(ifr
.ifr_name
),
930 kCFStringEncodingASCII
);
931 ifr
.ifr_data
= (caddr_t
)&vreq
;
933 // physical interface
934 (void) _SC_cfstring_to_cstring(physical_if
,
936 sizeof(vreq
.vlr_parent
),
937 kCFStringEncodingASCII
);
940 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
941 vreq
.vlr_tag
= tag_val
;
943 // update physical interface and tag
944 if (ioctl(s
, SIOCSIFVLAN
, (caddr_t
)&ifr
) == -1) {
945 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno
));
946 _SCErrorSet(kSCStatusFailed
);
955 __vlan_clear(int s
, CFStringRef interface_if
)
960 bzero(&ifr
, sizeof(ifr
));
961 bzero(&vreq
, sizeof(vreq
));
964 (void) _SC_cfstring_to_cstring(interface_if
,
966 sizeof(ifr
.ifr_name
),
967 kCFStringEncodingASCII
);
968 ifr
.ifr_data
= (caddr_t
)&vreq
;
970 // clear physical interface
971 bzero(&vreq
.vlr_parent
, sizeof(vreq
.vlr_parent
));
976 // update physical interface and tag
977 if (ioctl(s
, SIOCSIFVLAN
, (caddr_t
)&ifr
) == -1) {
978 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno
));
979 _SCErrorSet(kSCStatusFailed
);
988 _SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs
)
990 CFArrayRef active
= NULL
;
991 CFArrayRef config
= NULL
;
992 CFMutableDictionaryRef devices
= NULL
;
1000 _SCErrorSet(kSCStatusInvalidArgument
);
1004 /* configured VLANs */
1005 config
= SCVLANInterfaceCopyAll(prefs
);
1006 nConfig
= (config
!= NULL
) ? CFArrayGetCount(config
) : 0;
1008 /* physical interfaces */
1009 devices
= CFDictionaryCreateMutable(NULL
,
1011 &kCFTypeDictionaryKeyCallBacks
,
1012 &kCFTypeDictionaryValueCallBacks
);
1015 active
= _SCVLANInterfaceCopyActive();
1016 nActive
= (active
!= NULL
) ? CFArrayGetCount(active
) : 0;
1018 /* remove any no-longer-configured VLAN interfaces */
1019 for (i
= 0; i
< nActive
; i
++) {
1020 SCVLANInterfaceRef a_vlan
;
1021 CFStringRef a_vlan_if
;
1023 Boolean found
= FALSE
;
1025 a_vlan
= CFArrayGetValueAtIndex(active
, i
);
1026 a_vlan_if
= SCNetworkInterfaceGetBSDName(a_vlan
);
1028 for (j
= 0; j
< nConfig
; j
++) {
1029 SCVLANInterfaceRef c_vlan
;
1030 CFStringRef c_vlan_if
;
1032 c_vlan
= CFArrayGetValueAtIndex(config
, j
);
1033 c_vlan_if
= SCNetworkInterfaceGetBSDName(c_vlan
);
1035 if (CFEqual(a_vlan_if
, c_vlan_if
)) {
1042 // remove VLAN interface
1044 s
= inet_dgram_socket();
1051 if (!__destroyInterface(s
, a_vlan_if
)) {
1058 /* create (and update) configured VLAN interfaces */
1059 for (i
= 0; i
< nConfig
; i
++) {
1060 SCVLANInterfaceRef c_vlan
;
1061 CFStringRef c_vlan_if
;
1062 SCNetworkInterfaceRef c_vlan_physical
;
1063 Boolean found
= FALSE
;
1065 CFBooleanRef supported
;
1067 c_vlan
= CFArrayGetValueAtIndex(config
, i
);
1068 c_vlan_if
= SCNetworkInterfaceGetBSDName(c_vlan
);
1069 c_vlan_physical
= SCVLANInterfaceGetPhysicalInterface(c_vlan
);
1071 if (c_vlan_physical
== NULL
) {
1074 // determine if the physical interface supports VLANs
1075 supported
= CFDictionaryGetValue(devices
, c_vlan_physical
);
1076 if (supported
== NULL
) {
1077 SCNetworkInterfacePrivateRef c_vlan_physicalPrivate
= (SCNetworkInterfacePrivateRef
)c_vlan_physical
;
1079 supported
= c_vlan_physicalPrivate
->supportsVLAN
? kCFBooleanTrue
1081 CFDictionaryAddValue(devices
, c_vlan_physical
, supported
);
1084 for (j
= 0; j
< nActive
; j
++) {
1085 SCVLANInterfaceRef a_vlan
;
1086 CFStringRef a_vlan_if
;
1088 a_vlan
= CFArrayGetValueAtIndex(active
, j
);
1089 a_vlan_if
= SCNetworkInterfaceGetBSDName(a_vlan
);
1091 if (CFEqual(c_vlan_if
, a_vlan_if
)) {
1092 if (!CFEqual(c_vlan
, a_vlan
)) {
1093 // update VLAN interface
1095 s
= inet_dgram_socket();
1103 if (!CFBooleanGetValue(supported
)
1104 || !__vlan_clear(s
, c_vlan_if
)
1105 || !__vlan_set(s
, c_vlan_if
,
1106 SCNetworkInterfaceGetBSDName(c_vlan_physical
),
1107 SCVLANInterfaceGetTag(c_vlan
))) {
1108 // something went wrong, try to blow the VLAN away
1109 if (!CFBooleanGetValue(supported
)) {
1110 _SCErrorSet(kSCStatusFailed
);
1112 (void)__destroyInterface(s
, c_vlan_if
);
1122 if (!found
&& CFBooleanGetValue(supported
)) {
1123 // if the physical interface supports VLANs, add new interface
1127 s
= inet_dgram_socket();
1135 created
= __createInterface(s
, c_vlan_if
);
1139 SCNetworkInterfaceGetBSDName(c_vlan_physical
),
1140 SCVLANInterfaceGetTag(c_vlan
))) {
1142 // something went wrong, try to blow the VLAN away
1143 (void)__destroyInterface(s
, c_vlan_if
);
1155 if (active
) CFRelease(active
);
1156 if (config
) CFRelease(config
);
1157 if (devices
) CFRelease(devices
);
1158 if (s
!= -1) (void) close(s
);