2 * Copyright (c) 2003-2007 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 #include <SystemConfiguration/VLANConfiguration.h>
59 /* ---------- VLAN support ---------- */
66 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
68 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
76 CFMutableArrayRef vlans
;
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
;
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
);
110 // set physical interface and tag
111 vlan_physical
= _SCNetworkInterfaceCreateWithBSDName(NULL
, vlan_physical_if
,
112 kIncludeBondInterfaces
);
113 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
114 CFRelease(vlan_physical
);
117 vlan_name
= CFDictionaryGetValue(vlan_info
, kSCPropUserDefinedName
);
118 if (isA_CFString(vlan_name
)) {
119 SCVLANInterfaceSetLocalizedDisplayName(vlan
, vlan_name
);
123 vlan_options
= CFDictionaryGetValue(vlan_info
, kSCPropVirtualNetworkInterfacesVLANOptions
);
124 if (isA_CFDictionary(vlan_options
)) {
125 SCVLANInterfaceSetOptions(vlan
, vlan_options
);
128 // estabish link to the stored configuration
129 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
130 interfacePrivate
->prefs
= CFRetain(myContext
->prefs
);
132 CFArrayAppendValue(myContext
->vlans
, vlan
);
140 add_legacy_configuration(addContextRef myContext
)
144 SCPreferencesRef prefs
;
147 #define VLAN_PREFERENCES_ID CFSTR("VirtualNetworkInterfaces.plist")
148 #define VLAN_PREFERENCES_VLANS CFSTR("VLANs")
149 #define __kVLANInterface_interface CFSTR("interface") // e.g. vlan0, vlan1, ...
150 #define __kVLANInterface_device CFSTR("device") // e.g. en0, en1, ...
151 #define __kVLANInterface_tag CFSTR("tag") // e.g. 1 <= tag <= 4094
152 #define __kVLANInterface_options CFSTR("options") // e.g. UserDefinedName
154 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCVLANInterfaceCopyAll"), VLAN_PREFERENCES_ID
);
159 vlans
= SCPreferencesGetValue(prefs
, VLAN_PREFERENCES_VLANS
);
160 if ((vlans
!= NULL
) && !isA_CFArray(vlans
)) {
161 CFRelease(prefs
); // if the prefs are confused
165 n
= (vlans
!= NULL
) ? CFArrayGetCount(vlans
) : 0;
166 for (i
= 0; i
< n
; i
++) {
167 CFDictionaryRef dict
;
168 SCNetworkInterfacePrivateRef interfacePrivate
;
170 CFDictionaryRef options
;
172 SCVLANInterfaceRef vlan
;
174 CFDictionaryRef vlan_dict
;
175 SCNetworkInterfaceRef vlan_physical
;
176 CFStringRef vlan_physical_if
;
177 CFNumberRef vlan_tag
;
179 vlan_dict
= CFArrayGetValueAtIndex(vlans
, i
);
180 if (!isA_CFDictionary(vlan_dict
)) {
181 continue; // if the prefs are confused
184 vlan_if
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_interface
);
185 if (!isA_CFString(vlan_if
)) {
186 continue; // if the prefs are confused
189 vlan_physical_if
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_device
);
190 if (!isA_CFString(vlan_physical_if
)) {
191 continue; // if the prefs are confused
194 vlan_tag
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_tag
);
195 if (!isA_CFNumber(vlan_tag
)) {
196 continue; // if the prefs are confused
199 // check if this VLAN interface has already been allocated
200 path
= CFStringCreateWithFormat(NULL
,
203 kSCPrefVirtualNetworkInterfaces
,
204 kSCNetworkInterfaceTypeVLAN
,
206 dict
= SCPreferencesPathGetValue(myContext
->prefs
, path
);
208 // if VLAN interface name not available
213 // add a placeholder for the VLAN in the stored preferences
214 dict
= CFDictionaryCreate(NULL
,
216 &kCFTypeDictionaryKeyCallBacks
,
217 &kCFTypeDictionaryValueCallBacks
);
218 ok
= SCPreferencesPathSetValue(myContext
->prefs
, path
, dict
);
222 // if the VLAN could not be saved
226 // create the VLAN interface
227 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(NULL
, vlan_if
);
229 // estabish link to the stored configuration
230 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
231 interfacePrivate
->prefs
= CFRetain(myContext
->prefs
);
233 // set the interface and tag (which updates the stored preferences)
234 vlan_physical
= _SCNetworkInterfaceCreateWithBSDName(NULL
, vlan_physical_if
,
235 kIncludeBondInterfaces
);
236 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
237 CFRelease(vlan_physical
);
239 // set display name (which updates the stored preferences)
240 options
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_options
);
241 if (isA_CFDictionary(options
)) {
242 CFStringRef vlan_name
;
244 vlan_name
= CFDictionaryGetValue(options
, CFSTR("VLAN Name"));
245 if (isA_CFString(vlan_name
)) {
246 SCVLANInterfaceSetLocalizedDisplayName(vlan
, vlan_name
);
250 CFArrayAppendValue(myContext
->vlans
, vlan
);
259 static SCVLANInterfaceRef
260 findVLANInterfaceAndTag(SCPreferencesRef prefs
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
264 SCVLANInterfaceRef vlan
= NULL
;
267 vlans
= SCVLANInterfaceCopyAll(prefs
);
269 n
= CFArrayGetCount(vlans
);
270 for (i
= 0; i
< n
; i
++) {
271 SCVLANInterfaceRef config_vlan
;
272 SCNetworkInterfaceRef config_physical
;
273 CFNumberRef config_tag
;
275 config_vlan
= CFArrayGetValueAtIndex(vlans
, i
);
276 config_physical
= SCVLANInterfaceGetPhysicalInterface(config_vlan
);
277 config_tag
= SCVLANInterfaceGetTag(config_vlan
);
279 if ((config_physical
!= NULL
) && (config_tag
!= NULL
)) {
280 if (!CFEqual(physical
, config_physical
)) {
281 // if this VLAN has a different physical interface
285 if (!CFEqual(tag
, config_tag
)) {
286 // if this VLAN has a different tag
290 vlan
= CFRetain(config_vlan
);
301 #pragma mark SCVLANInterface APIs
305 SCVLANInterfaceCopyAll(SCPreferencesRef prefs
)
308 CFDictionaryRef dict
;
311 context
.vlans
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
312 context
.prefs
= prefs
;
314 path
= CFStringCreateWithFormat(NULL
,
317 kSCPrefVirtualNetworkInterfaces
,
318 kSCNetworkInterfaceTypeVLAN
);
319 dict
= SCPreferencesPathGetValue(prefs
, path
);
320 if (isA_CFDictionary(dict
)) {
321 CFDictionaryApplyFunction(dict
, add_configured_interface
, &context
);
323 // no VLAN configuration, upgrade from legacy configuration
324 dict
= CFDictionaryCreate(NULL
,
326 &kCFTypeDictionaryKeyCallBacks
,
327 &kCFTypeDictionaryValueCallBacks
);
328 (void) SCPreferencesPathSetValue(prefs
, path
, dict
);
331 add_legacy_configuration(&context
);
335 return context
.vlans
;
340 addAvailableInterfaces(CFMutableArrayRef available
, CFArrayRef interfaces
,
346 n
= CFArrayGetCount(interfaces
);
347 for (i
= 0; i
< n
; i
++) {
348 SCNetworkInterfaceRef interface
;
349 SCNetworkInterfacePrivateRef interfacePrivate
;
351 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
352 interfacePrivate
= (SCNetworkInterfacePrivateRef
)interface
;
355 && CFSetContainsValue(exclude
, interface
)) {
356 // exclude this interface
359 if (interfacePrivate
->supportsVLAN
) {
360 // if this interface is available
361 CFArrayAppendValue(available
, interface
);
370 SCVLANInterfaceCopyAvailablePhysicalInterfaces()
372 CFMutableArrayRef available
;
373 CFArrayRef bond_interfaces
= NULL
;
374 CFMutableSetRef exclude
= NULL
;
375 CFArrayRef interfaces
;
376 SCPreferencesRef prefs
;
378 available
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
380 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL
);
382 bond_interfaces
= SCBondInterfaceCopyAll(prefs
);
384 if (bond_interfaces
!= NULL
) {
385 exclude
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
386 __SCBondInterfaceListCopyMembers(bond_interfaces
, exclude
);
390 // add real interfaces that aren't part of a bond
391 interfaces
= __SCNetworkInterfaceCopyAll_IONetworkInterface();
392 if (interfaces
!= NULL
) {
393 addAvailableInterfaces(available
, interfaces
, exclude
);
394 CFRelease(interfaces
);
397 // add bond interfaces
398 if (bond_interfaces
!= NULL
) {
399 addAvailableInterfaces(available
, bond_interfaces
, NULL
);
400 CFRelease(bond_interfaces
);
402 if (exclude
!= NULL
) {
411 _SCVLANInterfaceCopyActive(void)
413 struct ifaddrs
*ifap
;
416 CFMutableArrayRef vlans
= NULL
;
418 if (getifaddrs(&ifap
) == -1) {
419 SCLog(TRUE
, LOG_ERR
, CFSTR("getifaddrs() failed: %s"), strerror(errno
));
420 _SCErrorSet(kSCStatusFailed
);
424 s
= inet_dgram_socket();
430 vlans
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
432 for (ifp
= ifap
; ifp
!= NULL
; ifp
= ifp
->ifa_next
) {
433 struct if_data
*if_data
;
435 SCVLANInterfaceRef vlan
;
437 SCNetworkInterfaceRef vlan_physical
;
438 CFStringRef vlan_physical_if
;
439 CFNumberRef vlan_tag
;
440 char vlr_parent
[IFNAMSIZ
+ 1];
444 if_data
= (struct if_data
*)ifp
->ifa_data
;
446 || ifp
->ifa_addr
->sa_family
!= AF_LINK
447 || if_data
->ifi_type
!= IFT_L2VLAN
) {
451 bzero(&ifr
, sizeof(ifr
));
452 bzero(&vreq
, sizeof(vreq
));
453 strncpy(ifr
.ifr_name
, ifp
->ifa_name
, sizeof(ifr
.ifr_name
));
454 ifr
.ifr_data
= (caddr_t
)&vreq
;
456 if (ioctl(s
, SIOCGIFVLAN
, (caddr_t
)&ifr
) == -1) {
457 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl() failed: %s"), strerror(errno
));
460 _SCErrorSet(kSCStatusFailed
);
464 // create the VLAN interface
465 vlan_if
= CFStringCreateWithCString(NULL
, ifp
->ifa_name
, kCFStringEncodingASCII
);
466 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(NULL
, vlan_if
);
469 // set the physical interface and tag
470 bzero(&vlr_parent
, sizeof(vlr_parent
));
471 bcopy(vreq
.vlr_parent
, vlr_parent
, IFNAMSIZ
);
472 vlan_physical_if
= CFStringCreateWithCString(NULL
, vlr_parent
, kCFStringEncodingASCII
);
473 vlan_physical
= _SCNetworkInterfaceCreateWithBSDName(NULL
, vlan_physical_if
,
474 kIncludeBondInterfaces
);
475 CFRelease(vlan_physical_if
);
477 vlr_tag
= vreq
.vlr_tag
;
478 vlan_tag
= CFNumberCreate(NULL
, kCFNumberIntType
, &vlr_tag
);
480 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, vlan_physical
, vlan_tag
);
481 CFRelease(vlan_physical
);
485 CFArrayAppendValue(vlans
, vlan
);
498 SCVLANInterfaceCreate(SCPreferencesRef prefs
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
500 CFAllocatorRef allocator
;
502 SCNetworkInterfacePrivateRef interfacePrivate
;
503 SCVLANInterfaceRef vlan
;
506 _SCErrorSet(kSCStatusInvalidArgument
);
510 if (!isA_SCNetworkInterface(physical
)) {
511 _SCErrorSet(kSCStatusInvalidArgument
);
515 interfacePrivate
= (SCNetworkInterfacePrivateRef
)physical
;
516 if (!interfacePrivate
->supportsVLAN
) {
517 _SCErrorSet(kSCStatusInvalidArgument
);
521 if (isA_CFNumber(tag
)) {
524 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
525 if ((tag_val
< 1) || (tag_val
> 4094)) {
526 _SCErrorSet(kSCStatusInvalidArgument
);
530 _SCErrorSet(kSCStatusInvalidArgument
);
534 // make sure that physical interface and tag are not used
535 vlan
= findVLANInterfaceAndTag(prefs
, physical
, tag
);
538 _SCErrorSet(kSCStatusKeyExists
);
542 allocator
= CFGetAllocator(prefs
);
544 // create a new VLAN using an unused interface name
545 for (i
= 0; vlan
== NULL
; i
++) {
546 CFDictionaryRef dict
;
551 vlan_if
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("vlan%d"), i
);
552 path
= CFStringCreateWithFormat(allocator
,
555 kSCPrefVirtualNetworkInterfaces
,
556 kSCNetworkInterfaceTypeVLAN
,
558 dict
= SCPreferencesPathGetValue(prefs
, path
);
560 // if VLAN interface name not available
566 // add the VLAN to the stored preferences
567 dict
= CFDictionaryCreate(allocator
,
569 &kCFTypeDictionaryKeyCallBacks
,
570 &kCFTypeDictionaryValueCallBacks
);
571 ok
= SCPreferencesPathSetValue(prefs
, path
, dict
);
575 // if the VLAN could not be saved
577 _SCErrorSet(kSCStatusFailed
);
581 // create the SCVLANInterfaceRef
582 vlan
= (SCVLANInterfaceRef
)_SCVLANInterfaceCreatePrivate(allocator
, vlan_if
);
585 // estabish link to the stored configuration
586 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
587 interfacePrivate
->prefs
= CFRetain(prefs
);
589 // set physical interface and tag
590 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan
, physical
, tag
);
598 SCVLANInterfaceRemove(SCVLANInterfaceRef vlan
)
601 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
605 if (!isA_SCVLANInterface(vlan
)) {
606 _SCErrorSet(kSCStatusInvalidArgument
);
610 if (interfacePrivate
->prefs
== NULL
) {
611 _SCErrorSet(kSCStatusInvalidArgument
);
615 vlan_if
= SCNetworkInterfaceGetBSDName(vlan
);
616 path
= CFStringCreateWithFormat(NULL
,
619 kSCPrefVirtualNetworkInterfaces
,
620 kSCNetworkInterfaceTypeVLAN
,
622 ok
= SCPreferencesPathRemoveValue(interfacePrivate
->prefs
, path
);
629 SCNetworkInterfaceRef
630 SCVLANInterfaceGetPhysicalInterface(SCVLANInterfaceRef vlan
)
632 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
634 if (!isA_SCVLANInterface(vlan
)) {
635 _SCErrorSet(kSCStatusInvalidArgument
);
639 return interfacePrivate
->vlan
.interface
;
644 SCVLANInterfaceGetTag(SCVLANInterfaceRef vlan
)
646 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
648 if (!isA_SCVLANInterface(vlan
)) {
649 _SCErrorSet(kSCStatusInvalidArgument
);
653 return interfacePrivate
->vlan
.tag
;
658 SCVLANInterfaceGetOptions(SCVLANInterfaceRef vlan
)
660 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
662 if (!isA_SCVLANInterface(vlan
)) {
663 _SCErrorSet(kSCStatusInvalidArgument
);
667 return interfacePrivate
->vlan
.options
;
672 SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan
, SCNetworkInterfaceRef physical
, CFNumberRef tag
)
674 SCNetworkInterfacePrivateRef interfacePrivate
;
677 if (!isA_SCVLANInterface(vlan
)) {
678 _SCErrorSet(kSCStatusInvalidArgument
);
682 if (!isA_SCNetworkInterface(physical
)) {
683 _SCErrorSet(kSCStatusInvalidArgument
);
687 interfacePrivate
= (SCNetworkInterfacePrivateRef
)physical
;
688 if (!interfacePrivate
->supportsVLAN
) {
689 _SCErrorSet(kSCStatusInvalidArgument
);
693 if (isA_CFNumber(tag
)) {
696 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
697 if ((tag_val
< 1) || (tag_val
> 4094)) {
698 _SCErrorSet(kSCStatusInvalidArgument
);
702 _SCErrorSet(kSCStatusInvalidArgument
);
706 interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
707 if (interfacePrivate
->prefs
!= NULL
) {
708 SCVLANInterfaceRef config_vlan
;
709 CFDictionaryRef dict
;
710 CFMutableDictionaryRef newDict
;
713 // make sure that physical interface and tag are not used
714 config_vlan
= findVLANInterfaceAndTag(interfacePrivate
->prefs
, physical
, tag
);
715 if (config_vlan
!= NULL
) {
716 if (!CFEqual(vlan
, config_vlan
)) {
717 CFRelease(config_vlan
);
718 _SCErrorSet(kSCStatusKeyExists
);
721 CFRelease(config_vlan
);
724 // set interface/tag in the stored preferences
725 path
= CFStringCreateWithFormat(NULL
,
728 kSCPrefVirtualNetworkInterfaces
,
729 kSCNetworkInterfaceTypeVLAN
,
730 interfacePrivate
->entity_device
);
731 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
732 if (!isA_CFDictionary(dict
)) {
733 // if the prefs are confused
735 _SCErrorSet(kSCStatusFailed
);
739 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
740 CFDictionarySetValue(newDict
,
741 kSCPropVirtualNetworkInterfacesVLANInterface
,
742 SCNetworkInterfaceGetBSDName(physical
));
743 CFDictionarySetValue(newDict
, kSCPropVirtualNetworkInterfacesVLANTag
, tag
);
744 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
750 // set physical interface
751 if (interfacePrivate
->vlan
.interface
!= NULL
)
752 CFRelease(interfacePrivate
->vlan
.interface
);
753 interfacePrivate
->vlan
.interface
= CFRetain(physical
);
756 if (interfacePrivate
->vlan
.tag
!= NULL
)
757 CFRelease(interfacePrivate
->vlan
.tag
);
758 interfacePrivate
->vlan
.tag
= CFRetain(tag
);
766 SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan
, CFStringRef newName
)
768 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
771 if (!isA_SCVLANInterface(vlan
)) {
772 _SCErrorSet(kSCStatusInvalidArgument
);
776 if ((newName
!= NULL
) && !isA_CFString(newName
)) {
777 _SCErrorSet(kSCStatusInvalidArgument
);
781 // set name in the stored preferences
782 if (interfacePrivate
->prefs
!= NULL
) {
783 CFDictionaryRef dict
;
784 CFMutableDictionaryRef newDict
;
787 path
= CFStringCreateWithFormat(NULL
,
790 kSCPrefVirtualNetworkInterfaces
,
791 kSCNetworkInterfaceTypeVLAN
,
792 interfacePrivate
->entity_device
);
793 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
794 if (!isA_CFDictionary(dict
)) {
795 // if the prefs are confused
797 _SCErrorSet(kSCStatusFailed
);
801 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
802 if (newName
!= NULL
) {
803 CFDictionarySetValue(newDict
, kSCPropUserDefinedName
, newName
);
805 CFDictionaryRemoveValue(newDict
, kSCPropUserDefinedName
);
807 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
812 // set name in the SCVLANInterfaceRef
814 if (interfacePrivate
->localized_name
!= NULL
) {
815 CFRelease(interfacePrivate
->localized_name
);
816 interfacePrivate
->localized_name
= NULL
;
818 if (newName
!= NULL
) {
819 interfacePrivate
->localized_name
= CFStringCreateCopy(NULL
, newName
);
828 SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan
, CFDictionaryRef newOptions
)
830 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)vlan
;
833 if (!isA_SCVLANInterface(vlan
)) {
834 _SCErrorSet(kSCStatusInvalidArgument
);
838 if ((newOptions
!= NULL
) && !isA_CFDictionary(newOptions
)) {
839 _SCErrorSet(kSCStatusInvalidArgument
);
843 // set options in the stored preferences
844 if (interfacePrivate
->prefs
!= NULL
) {
845 CFDictionaryRef dict
;
846 CFMutableDictionaryRef newDict
;
849 path
= CFStringCreateWithFormat(NULL
,
852 kSCPrefVirtualNetworkInterfaces
,
853 kSCNetworkInterfaceTypeVLAN
,
854 interfacePrivate
->entity_device
);
855 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
856 if (!isA_CFDictionary(dict
)) {
857 // if the prefs are confused
859 _SCErrorSet(kSCStatusFailed
);
863 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
864 if (newOptions
!= NULL
) {
865 CFDictionarySetValue(newDict
, kSCPropVirtualNetworkInterfacesVLANOptions
, newOptions
);
867 CFDictionaryRemoveValue(newDict
, kSCPropVirtualNetworkInterfacesVLANOptions
);
869 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
874 // set options in the SCVLANInterfaceRef
876 if (interfacePrivate
->vlan
.options
!= NULL
) {
877 CFRelease(interfacePrivate
->vlan
.options
);
878 interfacePrivate
->vlan
.options
= NULL
;
880 if (newOptions
!= NULL
) {
881 interfacePrivate
->vlan
.options
= CFDictionaryCreateCopy(NULL
, newOptions
);
890 #pragma mark SCVLANInterface management
894 __vlan_set(int s
, CFStringRef interface_if
, CFStringRef physical_if
, CFNumberRef tag
)
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 // physical interface
911 (void) _SC_cfstring_to_cstring(physical_if
,
913 sizeof(vreq
.vlr_parent
),
914 kCFStringEncodingASCII
);
917 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
918 vreq
.vlr_tag
= tag_val
;
920 // update physical interface and tag
921 if (ioctl(s
, SIOCSIFVLAN
, (caddr_t
)&ifr
) == -1) {
922 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno
));
923 _SCErrorSet(kSCStatusFailed
);
932 __vlan_clear(int s
, CFStringRef interface_if
)
937 bzero(&ifr
, sizeof(ifr
));
938 bzero(&vreq
, sizeof(vreq
));
941 (void) _SC_cfstring_to_cstring(interface_if
,
943 sizeof(ifr
.ifr_name
),
944 kCFStringEncodingASCII
);
945 ifr
.ifr_data
= (caddr_t
)&vreq
;
947 // clear physical interface
948 bzero(&vreq
.vlr_parent
, sizeof(vreq
.vlr_parent
));
953 // update physical interface and tag
954 if (ioctl(s
, SIOCSIFVLAN
, (caddr_t
)&ifr
) == -1) {
955 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno
));
956 _SCErrorSet(kSCStatusFailed
);
965 _SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs
)
967 CFArrayRef active
= NULL
;
968 CFArrayRef config
= NULL
;
969 CFMutableDictionaryRef devices
= NULL
;
977 _SCErrorSet(kSCStatusInvalidArgument
);
981 /* configured VLANs */
982 config
= SCVLANInterfaceCopyAll(prefs
);
983 nConfig
= CFArrayGetCount(config
);
985 /* physical interfaces */
986 devices
= CFDictionaryCreateMutable(NULL
,
988 &kCFTypeDictionaryKeyCallBacks
,
989 &kCFTypeDictionaryValueCallBacks
);
992 active
= _SCVLANInterfaceCopyActive();
993 nActive
= CFArrayGetCount(active
);
995 /* remove any no-longer-configured VLAN interfaces */
996 for (i
= 0; i
< nActive
; i
++) {
997 SCVLANInterfaceRef a_vlan
;
998 CFStringRef a_vlan_if
;
1000 Boolean found
= FALSE
;
1002 a_vlan
= CFArrayGetValueAtIndex(active
, i
);
1003 a_vlan_if
= SCNetworkInterfaceGetBSDName(a_vlan
);
1005 for (j
= 0; j
< nConfig
; j
++) {
1006 SCVLANInterfaceRef c_vlan
;
1007 CFStringRef c_vlan_if
;
1009 c_vlan
= CFArrayGetValueAtIndex(config
, j
);
1010 c_vlan_if
= SCNetworkInterfaceGetBSDName(c_vlan
);
1012 if (CFEqual(a_vlan_if
, c_vlan_if
)) {
1019 // remove VLAN interface
1021 s
= inet_dgram_socket();
1028 if (!__destroyInterface(s
, a_vlan_if
)) {
1035 /* create (and update) configured VLAN interfaces */
1036 for (i
= 0; i
< nConfig
; i
++) {
1037 SCVLANInterfaceRef c_vlan
;
1038 CFStringRef c_vlan_if
;
1039 SCNetworkInterfaceRef c_vlan_physical
;
1040 Boolean found
= FALSE
;
1042 CFBooleanRef supported
;
1044 c_vlan
= CFArrayGetValueAtIndex(config
, i
);
1045 c_vlan_if
= SCNetworkInterfaceGetBSDName(c_vlan
);
1046 c_vlan_physical
= SCVLANInterfaceGetPhysicalInterface(c_vlan
);
1048 if (c_vlan_physical
== NULL
) {
1051 // determine if the physical interface supports VLANs
1052 supported
= CFDictionaryGetValue(devices
, c_vlan_physical
);
1053 if (supported
== NULL
) {
1054 SCNetworkInterfacePrivateRef c_vlan_physicalPrivate
= (SCNetworkInterfacePrivateRef
)c_vlan_physical
;
1056 supported
= c_vlan_physicalPrivate
->supportsVLAN
? kCFBooleanTrue
1058 CFDictionaryAddValue(devices
, c_vlan_physical
, supported
);
1061 for (j
= 0; j
< nActive
; j
++) {
1062 SCVLANInterfaceRef a_vlan
;
1063 CFStringRef a_vlan_if
;
1065 a_vlan
= CFArrayGetValueAtIndex(active
, j
);
1066 a_vlan_if
= SCNetworkInterfaceGetBSDName(a_vlan
);
1068 if (CFEqual(c_vlan_if
, a_vlan_if
)) {
1069 if (!CFEqual(c_vlan
, a_vlan
)) {
1070 // update VLAN interface
1072 s
= inet_dgram_socket();
1080 if (!CFBooleanGetValue(supported
)
1081 || !__vlan_clear(s
, c_vlan_if
)
1082 || !__vlan_set(s
, c_vlan_if
,
1083 SCNetworkInterfaceGetBSDName(c_vlan_physical
),
1084 SCVLANInterfaceGetTag(c_vlan
))) {
1085 // something went wrong, try to blow the VLAN away
1086 if (!CFBooleanGetValue(supported
)) {
1087 _SCErrorSet(kSCStatusFailed
);
1089 (void)__destroyInterface(s
, c_vlan_if
);
1099 if (!found
&& CFBooleanGetValue(supported
)) {
1100 // if the physical interface supports VLANs, add new interface
1104 s
= inet_dgram_socket();
1112 created
= __createInterface(s
, c_vlan_if
);
1116 SCNetworkInterfaceGetBSDName(c_vlan_physical
),
1117 SCVLANInterfaceGetTag(c_vlan
))) {
1119 // something went wrong, try to blow the VLAN away
1120 (void)__destroyInterface(s
, c_vlan_if
);
1132 if (active
) CFRelease(active
);
1133 if (config
) CFRelease(config
);
1134 if (devices
) CFRelease(devices
);
1135 if (s
!= -1) (void) close(s
);
1142 #pragma mark Deprecated SPIs (remove when no longer referenced)
1145 /* ---------- VLAN "device" ---------- */
1148 IsVLANSupported(CFStringRef device
)
1150 return __SCNetworkInterfaceSupportsVLAN(device
);
1153 /* ---------- VLANInterface ---------- */
1157 /* base CFType information */
1158 CFRuntimeBase cfBase
;
1160 /* vlan interface configuration */
1161 CFStringRef ifname
; // e.g. vlan0, vlan1, ...
1162 CFStringRef device
; // e.g. en0, en1, ...
1163 CFNumberRef tag
; // e.g. 1 <= tag <= 4094
1164 CFDictionaryRef options
; // e.g. UserDefinedName
1166 } VLANInterfacePrivate
, * VLANInterfacePrivateRef
;
1169 static CFStringRef
__VLANInterfaceCopyDescription (CFTypeRef cf
);
1170 static void __VLANInterfaceDeallocate (CFTypeRef cf
);
1171 static Boolean
__VLANInterfaceEqual (CFTypeRef cf1
, CFTypeRef cf2
);
1174 static const CFRuntimeClass __VLANInterfaceClass
= {
1176 "VLANInterface", // className
1179 __VLANInterfaceDeallocate
, // dealloc
1180 __VLANInterfaceEqual
, // equal
1182 NULL
, // copyFormattingDesc
1183 __VLANInterfaceCopyDescription
// copyDebugDesc
1187 static CFTypeID __kVLANInterfaceTypeID
= _kCFRuntimeNotATypeID
;
1190 static pthread_once_t vlanInterface_init
= PTHREAD_ONCE_INIT
;
1194 __VLANInterfaceCopyDescription(CFTypeRef cf
)
1196 CFAllocatorRef allocator
= CFGetAllocator(cf
);
1197 CFMutableStringRef result
;
1198 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)cf
;
1200 result
= CFStringCreateMutable(allocator
, 0);
1201 CFStringAppendFormat(result
, NULL
, CFSTR("<VLANInterface %p [%p]> {"), cf
, allocator
);
1202 CFStringAppendFormat(result
, NULL
, CFSTR("if = %@"), vlanPrivate
->ifname
);
1203 CFStringAppendFormat(result
, NULL
, CFSTR(", device = %@"), vlanPrivate
->device
);
1204 CFStringAppendFormat(result
, NULL
, CFSTR(", tag = %@"), vlanPrivate
->tag
);
1205 if (vlanPrivate
->options
!= NULL
) {
1206 CFStringAppendFormat(result
, NULL
, CFSTR(", options = %@"), vlanPrivate
->options
);
1208 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
1215 __VLANInterfaceDeallocate(CFTypeRef cf
)
1217 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)cf
;
1219 /* release resources */
1221 CFRelease(vlanPrivate
->ifname
);
1222 CFRelease(vlanPrivate
->device
);
1223 CFRelease(vlanPrivate
->tag
);
1224 if (vlanPrivate
->options
) CFRelease(vlanPrivate
->options
);
1231 __VLANInterfaceEquiv(CFTypeRef cf1
, CFTypeRef cf2
)
1233 VLANInterfacePrivateRef vlan1
= (VLANInterfacePrivateRef
)cf1
;
1234 VLANInterfacePrivateRef vlan2
= (VLANInterfacePrivateRef
)cf2
;
1239 if (!CFEqual(vlan1
->ifname
, vlan2
->ifname
))
1240 return FALSE
; // if not the same interface
1242 if (!CFEqual(vlan1
->device
, vlan2
->device
))
1243 return FALSE
; // if not the same device
1245 if (!CFEqual(vlan1
->tag
, vlan2
->tag
))
1246 return FALSE
; // if not the same tag
1253 __VLANInterfaceEqual(CFTypeRef cf1
, CFTypeRef cf2
)
1255 VLANInterfacePrivateRef vlan1
= (VLANInterfacePrivateRef
)cf1
;
1256 VLANInterfacePrivateRef vlan2
= (VLANInterfacePrivateRef
)cf2
;
1258 if (!__VLANInterfaceEquiv(vlan1
, vlan2
))
1259 return FALSE
; // if not the same VLAN interface/device/tag
1261 if (vlan1
->options
!= vlan2
->options
) {
1262 // if the options may differ
1263 if ((vlan1
->options
!= NULL
) && (vlan2
->options
!= NULL
)) {
1264 // if both VLANs have options
1265 if (!CFEqual(vlan1
->options
, vlan2
->options
)) {
1266 // if the options are not equal
1270 // if only one VLAN has options
1280 __VLANInterfaceInitialize(void)
1282 __kVLANInterfaceTypeID
= _CFRuntimeRegisterClass(&__VLANInterfaceClass
);
1287 static __inline__ CFTypeRef
1288 isA_VLANInterface(CFTypeRef obj
)
1290 return (isA_CFType(obj
, VLANInterfaceGetTypeID()));
1295 VLANInterfaceGetTypeID(void)
1297 pthread_once(&vlanInterface_init
, __VLANInterfaceInitialize
); /* initialize runtime */
1298 return __kVLANInterfaceTypeID
;
1302 static VLANInterfaceRef
1303 __VLANInterfaceCreatePrivate(CFAllocatorRef allocator
,
1307 CFDictionaryRef options
)
1309 VLANInterfacePrivateRef vlanPrivate
;
1312 /* initialize runtime */
1313 pthread_once(&vlanInterface_init
, __VLANInterfaceInitialize
);
1316 size
= sizeof(VLANInterfacePrivate
) - sizeof(CFRuntimeBase
);
1317 vlanPrivate
= (VLANInterfacePrivateRef
)_CFRuntimeCreateInstance(allocator
,
1318 __kVLANInterfaceTypeID
,
1325 /* establish the vlan */
1327 vlanPrivate
->ifname
= CFStringCreateCopy(allocator
, ifname
);
1328 vlanPrivate
->device
= CFStringCreateCopy(allocator
, device
);
1329 vlanPrivate
->tag
= CFRetain(tag
);
1330 if (options
!= NULL
) {
1331 vlanPrivate
->options
= CFDictionaryCreateCopy(allocator
, options
);
1333 vlanPrivate
->options
= NULL
;
1336 return (VLANInterfaceRef
)vlanPrivate
;
1341 VLANInterfaceGetInterface(VLANInterfaceRef vlan
)
1343 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
1344 CFStringRef vlan_if
= NULL
;
1346 if (isA_VLANInterface(vlan
)) {
1347 vlan_if
= vlanPrivate
->ifname
;
1355 VLANInterfaceGetDevice(VLANInterfaceRef vlan
)
1357 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
1358 CFStringRef vlan_device
= NULL
;
1360 if (isA_VLANInterface(vlan
)) {
1361 vlan_device
= vlanPrivate
->device
;
1369 VLANInterfaceSetDevice(VLANInterfaceRef vlan
, CFStringRef newDevice
)
1371 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
1373 if (isA_VLANInterface(vlan
)) {
1374 CFAllocatorRef allocator
= CFGetAllocator(vlan
);
1376 CFRelease(vlanPrivate
->device
);
1377 vlanPrivate
->device
= CFStringCreateCopy(allocator
, newDevice
);
1385 VLANInterfaceGetTag(VLANInterfaceRef vlan
)
1387 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
1388 CFNumberRef vlan_tag
= NULL
;
1390 if (isA_VLANInterface(vlan
)) {
1391 vlan_tag
= vlanPrivate
->tag
;
1399 VLANInterfaceSetTag(VLANInterfaceRef vlan
, CFNumberRef newTag
)
1401 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
1403 if (isA_VLANInterface(vlan
)) {
1404 CFRelease(vlanPrivate
->tag
);
1405 vlanPrivate
->tag
= CFRetain(newTag
);
1413 VLANInterfaceGetOptions(VLANInterfaceRef vlan
)
1415 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
1416 CFDictionaryRef vlan_options
= NULL
;
1418 if (isA_VLANInterface(vlan
)) {
1419 vlan_options
= vlanPrivate
->options
;
1422 return vlan_options
;
1427 VLANInterfaceSetOptions(VLANInterfaceRef vlan
, CFDictionaryRef newOptions
)
1429 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
1431 if (isA_VLANInterface(vlan
)) {
1432 CFAllocatorRef allocator
= CFGetAllocator(vlan
);
1434 if (vlanPrivate
->options
) CFRelease(vlanPrivate
->options
);
1435 if (newOptions
!= NULL
) {
1436 vlanPrivate
->options
= CFDictionaryCreateCopy(allocator
, newOptions
);
1438 vlanPrivate
->options
= NULL
;
1446 /* ---------- VLANPreferences ---------- */
1450 /* base CFType information */
1451 CFRuntimeBase cfBase
;
1454 pthread_mutex_t lock
;
1456 /* underlying preferences */
1457 SCPreferencesRef prefs
;
1459 /* base VLANs (before any commits) */
1462 } VLANPreferencesPrivate
, * VLANPreferencesPrivateRef
;
1465 static CFStringRef
__VLANPreferencesCopyDescription (CFTypeRef cf
);
1466 static void __VLANPreferencesDeallocate (CFTypeRef cf
);
1469 static const CFRuntimeClass __VLANPreferencesClass
= {
1471 "VLANPreferences", // className
1474 __VLANPreferencesDeallocate
, // dealloc
1477 NULL
, // copyFormattingDesc
1478 __VLANPreferencesCopyDescription
// copyDebugDesc
1482 static CFTypeID __kVLANPreferencesTypeID
= _kCFRuntimeNotATypeID
;
1485 static pthread_once_t vlanPreferences_init
= PTHREAD_ONCE_INIT
;
1489 __VLANPreferencesCopyDescription(CFTypeRef cf
)
1491 CFAllocatorRef allocator
= CFGetAllocator(cf
);
1495 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)cf
;
1496 CFMutableStringRef result
;
1498 result
= CFStringCreateMutable(allocator
, 0);
1499 CFStringAppendFormat(result
, NULL
, CFSTR("<VLANPreferences %p [%p]> {"), cf
, allocator
);
1501 keys
= SCPreferencesCopyKeyList(prefsPrivate
->prefs
);
1502 n
= CFArrayGetCount(keys
);
1503 for (i
= 0; i
< n
; i
++) {
1505 CFPropertyListRef val
;
1507 key
= CFArrayGetValueAtIndex(keys
, i
);
1508 val
= SCPreferencesGetValue(prefsPrivate
->prefs
, key
);
1510 CFStringAppendFormat(result
, NULL
, CFSTR("%@ : %@"), key
, val
);
1514 CFStringAppendFormat(result
, NULL
, CFSTR(" }"));
1524 __VLANPreferencesDeallocate(CFTypeRef cf
)
1526 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)cf
;
1528 /* release resources */
1530 pthread_mutex_destroy(&prefsPrivate
->lock
);
1532 if (prefsPrivate
->prefs
) CFRelease(prefsPrivate
->prefs
);
1533 if (prefsPrivate
->vlBase
) CFRelease(prefsPrivate
->vlBase
);
1540 __VLANPreferencesInitialize(void)
1542 __kVLANPreferencesTypeID
= _CFRuntimeRegisterClass(&__VLANPreferencesClass
);
1547 static __inline__ CFTypeRef
1548 isA_VLANPreferences(CFTypeRef obj
)
1550 return (isA_CFType(obj
, VLANPreferencesGetTypeID()));
1555 _VLANPreferencesCopyActiveInterfaces()
1557 CFArrayCallBacks callbacks
;
1558 struct ifaddrs
*ifap
;
1559 struct ifaddrs
*ifp
;
1561 CFMutableArrayRef vlans
= NULL
;
1563 if (getifaddrs(&ifap
) == -1) {
1564 SCLog(TRUE
, LOG_ERR
, CFSTR("getifaddrs() failed: %s"), strerror(errno
));
1565 _SCErrorSet(kSCStatusFailed
);
1569 s
= inet_dgram_socket();
1575 callbacks
= kCFTypeArrayCallBacks
;
1576 callbacks
.equal
= __VLANInterfaceEquiv
;
1577 vlans
= CFArrayCreateMutable(NULL
, 0, &callbacks
);
1579 for (ifp
= ifap
; ifp
!= NULL
; ifp
= ifp
->ifa_next
) {
1580 switch (ifp
->ifa_addr
->sa_family
) {
1583 struct if_data
*if_data
;
1586 VLANInterfaceRef vlan
;
1587 CFStringRef vlan_if
;
1588 char vlr_parent
[IFNAMSIZ
+ 1];
1590 struct vlanreq vreq
;
1592 if_data
= (struct if_data
*)ifp
->ifa_data
;
1593 if (if_data
== NULL
) {
1594 break; // if no interface data
1597 if (if_data
->ifi_type
!= IFT_L2VLAN
) {
1598 break; // if not VLAN
1601 bzero(&ifr
, sizeof(ifr
));
1602 bzero(&vreq
, sizeof(vreq
));
1603 strncpy(ifr
.ifr_name
, ifp
->ifa_name
, sizeof(ifr
.ifr_name
));
1604 ifr
.ifr_data
= (caddr_t
)&vreq
;
1606 if (ioctl(s
, SIOCGIFVLAN
, (caddr_t
)&ifr
) == -1) {
1607 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl() failed: %s"), strerror(errno
));
1610 _SCErrorSet(kSCStatusFailed
);
1613 vlr_tag
= vreq
.vlr_tag
;
1614 bzero(&vlr_parent
, sizeof(vlr_parent
));
1615 bcopy(vreq
.vlr_parent
, vlr_parent
, IFNAMSIZ
);
1617 vlan_if
= CFStringCreateWithCString(NULL
, ifp
->ifa_name
, kCFStringEncodingASCII
);
1618 device
= CFStringCreateWithCString(NULL
, vlr_parent
, kCFStringEncodingASCII
);
1619 tag
= CFNumberCreate(NULL
, kCFNumberIntType
, &vlr_tag
);
1620 vlan
= __VLANInterfaceCreatePrivate(NULL
, vlan_if
, device
, tag
, NULL
);
1621 CFArrayAppendValue(vlans
, vlan
);
1643 findVLAN(CFArrayRef vlans
, CFStringRef device
, CFNumberRef tag
)
1645 CFIndex found
= kCFNotFound
;
1649 n
= isA_CFArray(vlans
) ? CFArrayGetCount(vlans
) : 0;
1650 for (i
= 0; i
< n
; i
++) {
1651 CFDictionaryRef vlan_dict
;
1652 CFStringRef vlan_device
;
1653 CFStringRef vlan_if
;
1654 CFNumberRef vlan_tag
;
1656 vlan_dict
= CFArrayGetValueAtIndex(vlans
, i
);
1657 if (!isA_CFDictionary(vlan_dict
)) {
1658 continue; // if the prefs are confused
1661 vlan_if
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_interface
);
1662 if (!isA_CFString(vlan_if
)) {
1663 continue; // if the prefs are confused
1666 vlan_device
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_device
);
1667 if (isA_CFString(vlan_device
)) {
1668 if (!CFEqual(device
, vlan_device
)) {
1669 continue; // if not a match
1673 vlan_tag
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_tag
);
1674 if (isA_CFNumber(vlan_tag
)) {
1675 if (!CFEqual(tag
, vlan_tag
)) {
1676 continue; // if not a match
1680 // if we have found a match
1690 setConfigurationChanged(VLANPreferencesRef prefs
)
1692 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1695 * to facilitate device configuration we will take
1696 * a snapshot of the VLAN preferences before any
1697 * changes are made. Then, when the changes are
1698 * applied we can compare what we had to what we
1699 * want and configured the system accordingly.
1701 if (prefsPrivate
->vlBase
== NULL
) {
1702 prefsPrivate
->vlBase
= VLANPreferencesCopyInterfaces(prefs
);
1710 VLANPreferencesGetTypeID(void)
1712 pthread_once(&vlanPreferences_init
, __VLANPreferencesInitialize
); /* initialize runtime */
1713 return __kVLANPreferencesTypeID
;
1718 VLANPreferencesCreate(CFAllocatorRef allocator
)
1721 CFStringRef bundleID
= NULL
;
1722 CFStringRef name
= CFSTR("VLANConfiguration");
1723 VLANPreferencesPrivateRef prefsPrivate
;
1726 /* initialize runtime */
1727 pthread_once(&vlanPreferences_init
, __VLANPreferencesInitialize
);
1729 /* allocate preferences */
1730 size
= sizeof(VLANPreferencesPrivate
) - sizeof(CFRuntimeBase
);
1731 prefsPrivate
= (VLANPreferencesPrivateRef
)_CFRuntimeCreateInstance(allocator
,
1732 __kVLANPreferencesTypeID
,
1735 if (prefsPrivate
== NULL
) {
1739 /* establish the prefs */
1741 pthread_mutex_init(&prefsPrivate
->lock
, NULL
);
1743 bundle
= CFBundleGetMainBundle();
1745 bundleID
= CFBundleGetIdentifier(bundle
);
1751 url
= CFBundleCopyExecutableURL(bundle
);
1753 bundleID
= CFURLCopyPath(url
);
1760 CFStringRef fullName
;
1762 if (CFEqual(bundleID
, CFSTR("/"))) {
1763 CFRelease(bundleID
);
1764 bundleID
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("(%d)"), getpid());
1767 fullName
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%@:%@"), bundleID
, name
);
1769 CFRelease(bundleID
);
1774 prefsPrivate
->prefs
= SCPreferencesCreate(allocator
, name
, VLAN_PREFERENCES_ID
);
1777 prefsPrivate
->vlBase
= NULL
;
1779 return (VLANPreferencesRef
)prefsPrivate
;
1784 VLANPreferencesCopyInterfaces(VLANPreferencesRef prefs
)
1786 CFAllocatorRef allocator
;
1787 CFArrayCallBacks callbacks
;
1790 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1791 CFMutableArrayRef result
;
1794 if (!isA_VLANPreferences(prefs
)) {
1795 _SCErrorSet(kSCStatusInvalidArgument
);
1799 allocator
= CFGetAllocator(prefs
);
1800 callbacks
= kCFTypeArrayCallBacks
;
1801 callbacks
.equal
= __VLANInterfaceEquiv
;
1802 result
= CFArrayCreateMutable(allocator
, 0, &callbacks
);
1804 vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
1805 n
= isA_CFArray(vlans
) ? CFArrayGetCount(vlans
) : 0;
1806 for (i
= 0; i
< n
; i
++) {
1807 CFDictionaryRef vlan_dict
;
1809 CFDictionaryRef options
;
1811 VLANInterfaceRef vlan
;
1812 CFStringRef vlan_if
;
1814 vlan_dict
= CFArrayGetValueAtIndex(vlans
, i
);
1815 if (!isA_CFDictionary(vlan_dict
)) {
1816 continue; // if the prefs are confused
1819 vlan_if
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_interface
);
1820 if (!isA_CFString(vlan_if
)) {
1821 continue; // if the prefs are confused
1825 device
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_device
);
1826 if (!isA_CFString(device
)) {
1827 continue; // if the prefs are confused
1830 tag
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_tag
);
1831 if (!isA_CFNumber(tag
)) {
1832 continue; // if the prefs are confused
1835 options
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_options
);
1836 if ((options
!= NULL
) && !isA_CFDictionary(options
)) {
1837 continue; // if the prefs are confused
1840 vlan
= __VLANInterfaceCreatePrivate(allocator
, vlan_if
, device
, tag
, options
);
1841 CFArrayAppendValue(result
, vlan
);
1850 VLANPreferencesAddInterface(VLANPreferencesRef prefs
,
1853 CFDictionaryRef options
)
1855 CFArrayRef active_vlans
;
1856 CFAllocatorRef allocator
;
1857 CFArrayRef config_vlans
;
1862 VLANInterfaceRef newVlan
= NULL
;
1863 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1865 if (!isA_VLANPreferences(prefs
)) {
1866 _SCErrorSet(kSCStatusInvalidArgument
);
1870 if (!isA_CFString(device
)) {
1871 _SCErrorSet(kSCStatusInvalidArgument
);
1875 if (isA_CFNumber(tag
)) {
1878 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
1879 if ((tag_val
< 1) || (tag_val
> 4094)) {
1880 _SCErrorSet(kSCStatusInvalidArgument
);
1884 _SCErrorSet(kSCStatusInvalidArgument
);
1888 if ((options
!= NULL
) && !isA_CFDictionary(options
)) {
1889 _SCErrorSet(kSCStatusInvalidArgument
);
1893 pthread_mutex_lock(&prefsPrivate
->lock
);
1895 /* get "configured" VLANs (and check to ensure we are not creating a duplicate) */
1896 config_vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
1897 nConfig
= isA_CFArray(config_vlans
) ? CFArrayGetCount(config_vlans
) : 0;
1899 dup_if
= findVLAN(config_vlans
, device
, tag
);
1900 if (dup_if
!= kCFNotFound
) {
1901 // sorry, you can't add a vlan using the same device/tag */
1902 _SCErrorSet(kSCStatusKeyExists
);
1906 /* get "active" VLANs */
1907 active_vlans
= _VLANPreferencesCopyActiveInterfaces();
1908 nActive
= isA_CFArray(active_vlans
) ? CFArrayGetCount(active_vlans
) : 0;
1910 /* create a new vlan using an unused interface name */
1911 allocator
= CFGetAllocator(prefs
);
1913 for (i
= 0; newVlan
== NULL
; i
++) {
1915 CFMutableDictionaryRef newDict
;
1916 CFMutableArrayRef newVlans
;
1917 CFStringRef vlan_if
;
1919 vlan_if
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("vlan%d"), i
);
1921 for (j
= 0; j
< nActive
; j
++) {
1922 CFStringRef active_if
;
1923 VLANInterfaceRef active_vlan
;
1925 active_vlan
= CFArrayGetValueAtIndex(active_vlans
, j
);
1926 active_if
= VLANInterfaceGetInterface(active_vlan
);
1928 if (CFEqual(vlan_if
, active_if
)) {
1929 goto next_if
; // if VLAN interface name not available
1933 for (j
= 0; j
< nConfig
; j
++) {
1934 CFDictionaryRef config
;
1935 CFStringRef config_if
;
1937 config
= CFArrayGetValueAtIndex(config_vlans
, j
);
1938 if (!isA_CFDictionary(config
)) {
1939 continue; // if the prefs are confused
1942 config_if
= CFDictionaryGetValue(config
, __kVLANInterface_interface
);
1943 if (!isA_CFString(config_if
)) {
1944 continue; // if the prefs are confused
1947 if (CFEqual(vlan_if
, config_if
)) {
1948 goto next_if
; // if VLAN interface name not available
1952 /* create the vlan */
1954 newDict
= CFDictionaryCreateMutable(allocator
,
1956 &kCFTypeDictionaryKeyCallBacks
,
1957 &kCFTypeDictionaryValueCallBacks
);
1958 CFDictionaryAddValue(newDict
, __kVLANInterface_interface
, vlan_if
);
1959 CFDictionaryAddValue(newDict
, __kVLANInterface_device
, device
);
1960 CFDictionaryAddValue(newDict
, __kVLANInterface_tag
, tag
);
1961 if (options
!= NULL
) {
1962 CFDictionaryAddValue(newDict
, __kVLANInterface_options
, options
);
1965 /* create the accessor handle to be returned */
1967 newVlan
= __VLANInterfaceCreatePrivate(allocator
, vlan_if
, device
, tag
, options
);
1969 /* yes, we're going to be changing the configuration */
1970 setConfigurationChanged(prefs
);
1972 /* save in the prefs */
1975 newVlans
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
1977 newVlans
= CFArrayCreateMutableCopy(allocator
, 0, config_vlans
);
1979 CFArrayAppendValue(newVlans
, newDict
);
1982 (void) SCPreferencesSetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
, newVlans
);
1983 CFRelease(newVlans
);
1989 CFRelease(active_vlans
);
1993 pthread_mutex_unlock(&prefsPrivate
->lock
);
1995 return (VLANInterfaceRef
) newVlan
;
2000 VLANPreferencesUpdateInterface(VLANPreferencesRef prefs
,
2001 VLANInterfaceRef vlan
,
2002 CFStringRef newDevice
,
2004 CFDictionaryRef newOptions
)
2006 CFAllocatorRef allocator
;
2009 CFMutableDictionaryRef newDict
;
2010 CFMutableArrayRef newVlans
;
2012 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
2014 CFStringRef vlan_if
;
2016 if (!isA_VLANPreferences(prefs
)) {
2017 _SCErrorSet(kSCStatusInvalidArgument
);
2021 if (!isA_VLANInterface(vlan
)) {
2022 _SCErrorSet(kSCStatusInvalidArgument
);
2026 if ((newDevice
!= NULL
) && !isA_CFString(newDevice
)) {
2027 _SCErrorSet(kSCStatusInvalidArgument
);
2031 if (newTag
!= NULL
) {
2032 if (isA_CFNumber(newTag
)) {
2035 CFNumberGetValue(newTag
, kCFNumberIntType
, &tag_val
);
2036 if ((tag_val
< 1) || (tag_val
> 4094)) {
2037 _SCErrorSet(kSCStatusInvalidArgument
);
2041 _SCErrorSet(kSCStatusInvalidArgument
);
2046 if ((newOptions
!= NULL
)
2047 && !isA_CFDictionary(newOptions
) && (newOptions
!= (CFDictionaryRef
)kCFNull
)) {
2048 _SCErrorSet(kSCStatusInvalidArgument
);
2052 pthread_mutex_lock(&prefsPrivate
->lock
);
2054 vlan_if
= VLANInterfaceGetInterface(vlan
);
2056 vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
2057 if (!isA_CFArray(vlans
)) {
2058 goto done
; // if the prefs are confused
2061 cur_if
= findVLAN(vlans
,
2062 VLANInterfaceGetDevice(vlan
),
2063 VLANInterfaceGetTag (vlan
));
2064 if (cur_if
== kCFNotFound
) {
2065 _SCErrorSet(kSCStatusNoKey
);
2069 dup_if
= findVLAN(vlans
,
2070 newDevice
!= NULL
? newDevice
: VLANInterfaceGetDevice(vlan
),
2071 newTag
!= NULL
? newTag
: VLANInterfaceGetTag (vlan
));
2072 if (dup_if
!= kCFNotFound
) {
2073 // if the same device/tag has already been defined
2074 if (cur_if
!= dup_if
) {
2076 * sorry, you can't update another vlan that is using
2077 * the same device/tag
2079 _SCErrorSet(kSCStatusKeyExists
);
2084 /* update the vlan */
2086 if (newDevice
!= NULL
) {
2087 VLANInterfaceSetDevice(vlan
, newDevice
);
2089 newDevice
= VLANInterfaceGetDevice(vlan
);
2092 if (newTag
!= NULL
) {
2093 VLANInterfaceSetTag(vlan
, newTag
);
2095 newTag
= VLANInterfaceGetTag(vlan
);
2098 if (newOptions
!= NULL
) {
2099 if (newOptions
!= (CFDictionaryRef
)kCFNull
) {
2100 VLANInterfaceSetOptions(vlan
, newOptions
);
2102 VLANInterfaceSetOptions(vlan
, NULL
);
2106 newOptions
= VLANInterfaceGetOptions(vlan
);
2109 /* update the prefs */
2111 allocator
= CFGetAllocator(prefs
);
2112 newDict
= CFDictionaryCreateMutable(allocator
,
2114 &kCFTypeDictionaryKeyCallBacks
,
2115 &kCFTypeDictionaryValueCallBacks
);
2116 CFDictionaryAddValue(newDict
, __kVLANInterface_interface
, vlan_if
);
2117 CFDictionaryAddValue(newDict
, __kVLANInterface_device
, newDevice
);
2118 CFDictionaryAddValue(newDict
, __kVLANInterface_tag
, newTag
);
2119 if (newOptions
!= NULL
) {
2120 CFDictionaryAddValue(newDict
, __kVLANInterface_options
, newOptions
);
2123 /* yes, we're going to be changing the configuration */
2124 setConfigurationChanged(prefs
);
2126 /* update the prefs */
2128 newVlans
= CFArrayCreateMutableCopy(allocator
, 0, vlans
);
2129 CFArraySetValueAtIndex(newVlans
, cur_if
, newDict
);
2132 (void) SCPreferencesSetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
, newVlans
);
2133 CFRelease(newVlans
);
2139 pthread_mutex_unlock(&prefsPrivate
->lock
);
2146 VLANPreferencesRemoveInterface(VLANPreferencesRef prefs
,
2147 VLANInterfaceRef vlan
)
2149 CFAllocatorRef allocator
;
2151 CFMutableArrayRef newVlans
;
2153 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
2156 if (!isA_VLANPreferences(prefs
)) {
2157 _SCErrorSet(kSCStatusInvalidArgument
);
2161 if (!isA_VLANInterface(vlan
)) {
2162 _SCErrorSet(kSCStatusInvalidArgument
);
2166 pthread_mutex_lock(&prefsPrivate
->lock
);
2168 vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
2169 if (!isA_CFArray(vlans
)) {
2170 _SCErrorSet(kSCStatusNoKey
);
2171 goto done
; // if the prefs are confused
2174 cur_if
= findVLAN(vlans
,
2175 VLANInterfaceGetDevice(vlan
),
2176 VLANInterfaceGetTag (vlan
));
2177 if (cur_if
== kCFNotFound
) {
2178 _SCErrorSet(kSCStatusNoKey
);
2182 /* yes, we're going to be changing the configuration */
2183 setConfigurationChanged(prefs
);
2185 /* remove the vlan */
2187 allocator
= CFGetAllocator(prefs
);
2188 newVlans
= CFArrayCreateMutableCopy(allocator
, 0, vlans
);
2189 CFArrayRemoveValueAtIndex(newVlans
, cur_if
);
2191 (void) SCPreferencesSetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
, newVlans
);
2192 CFRelease(newVlans
);
2198 pthread_mutex_unlock(&prefsPrivate
->lock
);
2205 VLANPreferencesCommitChanges(VLANPreferencesRef prefs
)
2208 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
2210 if (!isA_VLANPreferences(prefs
)) {
2211 _SCErrorSet(kSCStatusInvalidArgument
);
2215 ok
= SCPreferencesCommitChanges(prefsPrivate
->prefs
);
2220 if (prefsPrivate
->vlBase
!= NULL
) {
2221 CFRelease(prefsPrivate
->vlBase
);
2222 prefsPrivate
->vlBase
= NULL
;
2230 _VLANPreferencesUpdateConfiguration(VLANPreferencesRef prefs
)
2237 VLANPreferencesApplyChanges(VLANPreferencesRef prefs
)
2239 SCPreferencesRef defaultPrefs
;
2241 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
2243 if (!isA_VLANPreferences(prefs
)) {
2244 _SCErrorSet(kSCStatusInvalidArgument
);
2248 pthread_mutex_lock(&prefsPrivate
->lock
);
2250 /* apply the preferences */
2251 ok
= SCPreferencesApplyChanges(prefsPrivate
->prefs
);
2256 /* apply the VLAN configuration */
2257 defaultPrefs
= SCPreferencesCreate(NULL
, CFSTR("VLANPreferencesApplyChanges"), NULL
);
2260 * Note: In an ideal world, we'd simply call SCPreferencesApplyChanges()
2261 * Unfortunately, it's possible that the caller (e.g NetworkCfgTool)
2262 * is holding the lock on the default prefs and since "Apply" attempts
2263 * to grab the lock we could end up in a deadlock situation.
2265 #include "SCPreferencesInternal.h"
2266 SCPreferencesPrivateRef defaultPrefsPrivate
;
2268 defaultPrefsPrivate
= (SCPreferencesPrivateRef
)defaultPrefs
;
2270 pthread_mutex_lock(&defaultPrefsPrivate
->lock
);
2271 if (defaultPrefsPrivate
->session
== NULL
) {
2272 __SCPreferencesAddSession(defaultPrefs
);
2274 pthread_mutex_unlock(&defaultPrefsPrivate
->lock
);
2276 ok
= SCDynamicStoreNotifyValue(defaultPrefsPrivate
->session
, defaultPrefsPrivate
->sessionKeyApply
);
2278 CFRelease(defaultPrefs
);
2285 pthread_mutex_unlock(&prefsPrivate
->lock
);