2 * Copyright (c) 2003 Apple Computer, 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 14, 2003 Allan Nathanson <ajn@apple.com>
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFRuntime.h>
35 #include <SystemConfiguration/SystemConfiguration.h>
36 #include <SystemConfiguration/SCNetworkConfigurationInternal.h>
37 #include <SystemConfiguration/SCValidation.h>
38 #include <SystemConfiguration/SCPrivate.h>
43 #include <sys/types.h>
44 #include <sys/ioctl.h>
45 #include <sys/socket.h>
46 #include <sys/sysctl.h>
47 #include <net/ethernet.h>
48 #define KERNEL_PRIVATE
50 #include <net/if_var.h>
52 #include <net/if_vlan_var.h>
53 #include <net/if_types.h>
54 #include <net/route.h>
56 #include <SystemConfiguration/VLANConfiguration.h>
57 #include <SystemConfiguration/VLANConfigurationPrivate.h>
59 /* ---------- VLAN support ---------- */
66 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
68 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
69 _SCErrorSet(kSCStatusFailed
);
77 _VLANDevice_set(int s
, CFStringRef interface
, CFStringRef device
, CFNumberRef tag
)
83 bzero(&ifr
, sizeof(ifr
));
84 bzero(&vreq
, sizeof(vreq
));
87 (void) _SC_cfstring_to_cstring(interface
,
90 kCFStringEncodingASCII
);
91 ifr
.ifr_data
= (caddr_t
)&vreq
;
94 (void) _SC_cfstring_to_cstring(device
,
96 sizeof(vreq
.vlr_parent
),
97 kCFStringEncodingASCII
);
100 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
101 vreq
.vlr_tag
= tag_val
;
103 // update parent device and tag
104 if (ioctl(s
, SIOCSIFVLAN
, (caddr_t
)&ifr
) == -1) {
105 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno
));
106 _SCErrorSet(kSCStatusFailed
);
110 // mark the parent device "up"
111 if (!__markInterfaceUp(s
, device
)) {
112 _SCErrorSet(kSCStatusFailed
);
121 _VLANDevice_unset(int s
, CFStringRef interface
)
126 bzero(&ifr
, sizeof(ifr
));
127 bzero(&vreq
, sizeof(vreq
));
130 (void) _SC_cfstring_to_cstring(interface
,
132 sizeof(ifr
.ifr_name
),
133 kCFStringEncodingASCII
);
134 ifr
.ifr_data
= (caddr_t
)&vreq
;
136 // clear parent device
137 bzero(&vreq
.vlr_parent
, sizeof(vreq
.vlr_parent
));
142 // update parent device and tag
143 if (ioctl(s
, SIOCSIFVLAN
, (caddr_t
)&ifr
) == -1) {
144 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno
));
145 _SCErrorSet(kSCStatusFailed
);
153 /* ---------- VLAN "device" ---------- */
156 IsVLANSupported(CFStringRef device
)
160 struct if_msghdr
* ifm
;
161 char * if_name
= NULL
;
162 unsigned int if_index
;
163 Boolean isVlan
= FALSE
;
166 /* get the interface index */
168 if_name
= _SC_cfstring_to_cstring(device
, NULL
, 0, kCFStringEncodingASCII
);
169 if (if_name
== NULL
) {
170 return FALSE
; // if conversion error
172 if_index
= if_nametoindex(if_name
);
174 goto done
; // if unknown interface
177 /* get information for the specified device */
183 mib
[4] = NET_RT_IFLIST
;
184 mib
[5] = if_index
; /* ask for exactly one interface */
186 if (sysctl(mib
, 6, NULL
, &buf_len
, NULL
, 0) < 0) {
187 SCLog(TRUE
, LOG_ERR
, CFSTR("sysctl() size failed: %s"), strerror(errno
));
190 buf
= CFAllocatorAllocate(NULL
, buf_len
, 0);
191 if (sysctl(mib
, 6, buf
, &buf_len
, NULL
, 0) < 0) {
192 SCLog(TRUE
, LOG_ERR
, CFSTR("sysctl() failed: %s"), strerror(errno
));
196 /* check the link type and hwassist flags */
198 ifm
= (struct if_msghdr
*)buf
;
199 switch (ifm
->ifm_type
) {
201 #if defined(IF_HWASSIST_VLAN_TAGGING) && defined(IF_HWASSIST_VLAN_MTU)
202 struct if_data
*if_data
= &ifm
->ifm_data
;
204 if (if_data
->ifi_hwassist
& (IF_HWASSIST_VLAN_TAGGING
| IF_HWASSIST_VLAN_MTU
)) {
214 if (if_name
!= NULL
) CFAllocatorDeallocate(NULL
, if_name
);
215 if (buf
!= NULL
) CFAllocatorDeallocate(NULL
, buf
);
220 /* ---------- VLANInterface ---------- */
224 /* base CFType information */
225 CFRuntimeBase cfBase
;
227 /* vlan interface configuration */
228 CFStringRef ifname
; // e.g. vlan0, vlan1, ...
229 CFStringRef device
; // e.g. en0, en1, ...
230 CFNumberRef tag
; // e.g. 1 <= tag <= 4094
231 CFDictionaryRef options
; // e.g. UserDefinedName
233 } VLANInterfacePrivate
, * VLANInterfacePrivateRef
;
236 static CFStringRef
__VLANInterfaceCopyDescription (CFTypeRef cf
);
237 static void __VLANInterfaceDeallocate (CFTypeRef cf
);
238 static Boolean
__VLANInterfaceEqual (CFTypeRef cf1
, CFTypeRef cf2
);
241 static const CFRuntimeClass __VLANInterfaceClass
= {
243 "VLANInterface", // className
246 __VLANInterfaceDeallocate
, // dealloc
247 __VLANInterfaceEqual
, // equal
249 NULL
, // copyFormattingDesc
250 __VLANInterfaceCopyDescription
// copyDebugDesc
254 static CFTypeID __kVLANInterfaceTypeID
= _kCFRuntimeNotATypeID
;
257 static pthread_once_t vlanInterface_init
= PTHREAD_ONCE_INIT
;
261 __VLANInterfaceCopyDescription(CFTypeRef cf
)
263 CFAllocatorRef allocator
= CFGetAllocator(cf
);
264 CFMutableStringRef result
;
265 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)cf
;
267 result
= CFStringCreateMutable(allocator
, 0);
268 CFStringAppendFormat(result
, NULL
, CFSTR("<VLANInterface %p [%p]> {"), cf
, allocator
);
269 CFStringAppendFormat(result
, NULL
, CFSTR(" if = %@"), vlanPrivate
->ifname
);
270 CFStringAppendFormat(result
, NULL
, CFSTR(", device = %@"), vlanPrivate
->device
);
271 CFStringAppendFormat(result
, NULL
, CFSTR(", tag = %@"), vlanPrivate
->tag
);
272 if (vlanPrivate
->options
!= NULL
) {
273 CFStringAppendFormat(result
, NULL
, CFSTR(", options = %@"), vlanPrivate
->options
);
275 CFStringAppendFormat(result
, NULL
, CFSTR(" }"));
282 __VLANInterfaceDeallocate(CFTypeRef cf
)
284 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)cf
;
286 /* release resources */
288 CFRelease(vlanPrivate
->ifname
);
289 CFRelease(vlanPrivate
->device
);
290 CFRelease(vlanPrivate
->tag
);
291 if (vlanPrivate
->options
) CFRelease(vlanPrivate
->options
);
298 __VLANInterfaceEquiv(CFTypeRef cf1
, CFTypeRef cf2
)
300 VLANInterfacePrivateRef vlan1
= (VLANInterfacePrivateRef
)cf1
;
301 VLANInterfacePrivateRef vlan2
= (VLANInterfacePrivateRef
)cf2
;
306 if (!CFEqual(vlan1
->ifname
, vlan2
->ifname
))
307 return FALSE
; // if not the same interface
309 if (!CFEqual(vlan1
->device
, vlan2
->device
))
310 return FALSE
; // if not the same device
312 if (!CFEqual(vlan1
->tag
, vlan2
->tag
))
313 return FALSE
; // if not the same tag
320 __VLANInterfaceEqual(CFTypeRef cf1
, CFTypeRef cf2
)
322 VLANInterfacePrivateRef vlan1
= (VLANInterfacePrivateRef
)cf1
;
323 VLANInterfacePrivateRef vlan2
= (VLANInterfacePrivateRef
)cf2
;
325 if (!__VLANInterfaceEquiv(vlan1
, vlan2
))
326 return FALSE
; // if not the same VLAN interface/device/tag
328 if (vlan1
->options
!= vlan2
->options
) {
329 // if the options may differ
330 if ((vlan1
->options
!= NULL
) && (vlan2
->options
!= NULL
)) {
331 // if both VLANs have options
332 if (!CFEqual(vlan1
->options
, vlan2
->options
)) {
333 // if the options are not equal
337 // if only one VLAN has options
347 __VLANInterfaceInitialize(void)
349 __kVLANInterfaceTypeID
= _CFRuntimeRegisterClass(&__VLANInterfaceClass
);
354 static __inline__ CFTypeRef
355 isA_VLANInterface(CFTypeRef obj
)
357 return (isA_CFType(obj
, VLANInterfaceGetTypeID()));
362 VLANInterfaceGetTypeID(void)
364 pthread_once(&vlanInterface_init
, __VLANInterfaceInitialize
); /* initialize runtime */
365 return __kVLANInterfaceTypeID
;
369 static VLANInterfaceRef
370 __VLANInterfaceCreatePrivate(CFAllocatorRef allocator
,
374 CFDictionaryRef options
)
376 VLANInterfacePrivateRef vlanPrivate
;
379 /* initialize runtime */
380 pthread_once(&vlanInterface_init
, __VLANInterfaceInitialize
);
383 size
= sizeof(VLANInterfacePrivate
) - sizeof(CFRuntimeBase
);
384 vlanPrivate
= (VLANInterfacePrivateRef
)_CFRuntimeCreateInstance(allocator
,
385 __kVLANInterfaceTypeID
,
392 /* establish the vlan */
394 vlanPrivate
->ifname
= CFStringCreateCopy(allocator
, ifname
);
395 vlanPrivate
->device
= CFStringCreateCopy(allocator
, device
);
396 vlanPrivate
->tag
= CFRetain(tag
);
397 if (options
!= NULL
) {
398 vlanPrivate
->options
= CFDictionaryCreateCopy(allocator
, options
);
400 vlanPrivate
->options
= NULL
;
403 return (VLANInterfaceRef
)vlanPrivate
;
408 VLANInterfaceGetInterface(VLANInterfaceRef vlan
)
410 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
411 CFStringRef vlan_if
= NULL
;
413 if (isA_VLANInterface(vlan
)) {
414 vlan_if
= vlanPrivate
->ifname
;
422 VLANInterfaceGetDevice(VLANInterfaceRef vlan
)
424 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
425 CFStringRef vlan_device
= NULL
;
427 if (isA_VLANInterface(vlan
)) {
428 vlan_device
= vlanPrivate
->device
;
436 VLANInterfaceSetDevice(VLANInterfaceRef vlan
, CFStringRef newDevice
)
438 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
440 if (isA_VLANInterface(vlan
)) {
441 CFAllocatorRef allocator
= CFGetAllocator(vlan
);
443 CFRelease(vlanPrivate
->device
);
444 vlanPrivate
->device
= CFStringCreateCopy(allocator
, newDevice
);
452 VLANInterfaceGetTag(VLANInterfaceRef vlan
)
454 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
455 CFNumberRef vlan_tag
= NULL
;
457 if (isA_VLANInterface(vlan
)) {
458 vlan_tag
= vlanPrivate
->tag
;
466 VLANInterfaceSetTag(VLANInterfaceRef vlan
, CFNumberRef newTag
)
468 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
470 if (isA_VLANInterface(vlan
)) {
471 CFRelease(vlanPrivate
->tag
);
472 vlanPrivate
->tag
= CFRetain(newTag
);
480 VLANInterfaceGetOptions(VLANInterfaceRef vlan
)
482 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
483 CFDictionaryRef vlan_options
= NULL
;
485 if (isA_VLANInterface(vlan
)) {
486 vlan_options
= vlanPrivate
->options
;
494 VLANInterfaceSetOptions(VLANInterfaceRef vlan
, CFDictionaryRef newOptions
)
496 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
498 if (isA_VLANInterface(vlan
)) {
499 CFAllocatorRef allocator
= CFGetAllocator(vlan
);
501 if (vlanPrivate
->options
) CFRelease(vlanPrivate
->options
);
502 if (newOptions
!= NULL
) {
503 vlanPrivate
->options
= CFDictionaryCreateCopy(allocator
, newOptions
);
505 vlanPrivate
->options
= NULL
;
513 /* ---------- VLANPreferences ---------- */
515 #define VLAN_PREFERENCES_VLANS CFSTR("VLANs")
517 #define __kVLANInterface_interface CFSTR("interface") // e.g. vlan0, vlan1, ...
518 #define __kVLANInterface_device CFSTR("device") // e.g. en0, en1, ...
519 #define __kVLANInterface_tag CFSTR("tag") // e.g. 1 <= tag <= 4094
520 #define __kVLANInterface_options CFSTR("options") // e.g. UserDefinedName
524 /* base CFType information */
525 CFRuntimeBase cfBase
;
528 pthread_mutex_t lock
;
530 /* underlying preferences */
531 SCPreferencesRef prefs
;
533 /* base VLANs (before any commits) */
536 } VLANPreferencesPrivate
, * VLANPreferencesPrivateRef
;
539 static CFStringRef
__VLANPreferencesCopyDescription (CFTypeRef cf
);
540 static void __VLANPreferencesDeallocate (CFTypeRef cf
);
543 static const CFRuntimeClass __VLANPreferencesClass
= {
545 "VLANPreferences", // className
548 __VLANPreferencesDeallocate
, // dealloc
551 NULL
, // copyFormattingDesc
552 __VLANPreferencesCopyDescription
// copyDebugDesc
556 static CFTypeID __kVLANPreferencesTypeID
= _kCFRuntimeNotATypeID
;
559 static pthread_once_t vlanPreferences_init
= PTHREAD_ONCE_INIT
;
563 __VLANPreferencesCopyDescription(CFTypeRef cf
)
565 CFAllocatorRef allocator
= CFGetAllocator(cf
);
569 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)cf
;
570 CFMutableStringRef result
;
572 result
= CFStringCreateMutable(allocator
, 0);
573 CFStringAppendFormat(result
, NULL
, CFSTR("<VLANPreferences %p [%p]> {"), cf
, allocator
);
575 keys
= SCPreferencesCopyKeyList(prefsPrivate
->prefs
);
576 n
= CFArrayGetCount(keys
);
577 for (i
= 0; i
< n
; i
++) {
579 CFPropertyListRef val
;
581 key
= CFArrayGetValueAtIndex(keys
, i
);
582 val
= SCPreferencesGetValue(prefsPrivate
->prefs
, key
);
584 CFStringAppendFormat(result
, NULL
, CFSTR("%@ : %@"), key
, val
);
588 CFStringAppendFormat(result
, NULL
, CFSTR(" }"));
598 __VLANPreferencesDeallocate(CFTypeRef cf
)
600 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)cf
;
602 /* release resources */
604 pthread_mutex_destroy(&prefsPrivate
->lock
);
606 if (prefsPrivate
->prefs
) CFRelease(prefsPrivate
->prefs
);
607 if (prefsPrivate
->vlBase
) CFRelease(prefsPrivate
->vlBase
);
614 __VLANPreferencesInitialize(void)
616 __kVLANPreferencesTypeID
= _CFRuntimeRegisterClass(&__VLANPreferencesClass
);
621 static __inline__ CFTypeRef
622 isA_VLANPreferences(CFTypeRef obj
)
624 return (isA_CFType(obj
, VLANPreferencesGetTypeID()));
629 _VLANPreferencesCopyActiveInterfaces()
631 CFArrayCallBacks callbacks
;
632 struct ifaddrs
*ifap
;
635 CFMutableArrayRef vlans
= NULL
;
637 if (getifaddrs(&ifap
) == -1) {
638 SCLog(TRUE
, LOG_ERR
, CFSTR("getifaddrs() failed: %s"), strerror(errno
));
639 _SCErrorSet(kSCStatusFailed
);
643 s
= inet_dgram_socket();
645 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
646 _SCErrorSet(kSCStatusFailed
);
650 callbacks
= kCFTypeArrayCallBacks
;
651 callbacks
.equal
= __VLANInterfaceEquiv
;
652 vlans
= CFArrayCreateMutable(NULL
, 0, &callbacks
);
654 for (ifp
= ifap
; ifp
!= NULL
; ifp
= ifp
->ifa_next
) {
655 switch (ifp
->ifa_addr
->sa_family
) {
658 struct if_data
*if_data
;
661 VLANInterfaceRef vlan
;
663 char vlr_parent
[IFNAMSIZ
+1];
667 if_data
= (struct if_data
*)ifp
->ifa_data
;
668 if (if_data
== NULL
) {
669 break; // if no interface data
672 if (if_data
->ifi_type
!= IFT_L2VLAN
) {
673 break; // if not VLAN
676 bzero(&ifr
, sizeof(ifr
));
677 bzero(&vreq
, sizeof(vreq
));
678 strncpy(ifr
.ifr_name
, ifp
->ifa_name
, sizeof(ifr
.ifr_name
));
679 ifr
.ifr_data
= (caddr_t
)&vreq
;
681 if (ioctl(s
, SIOCGIFVLAN
, (caddr_t
)&ifr
) == -1) {
682 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl() failed: %s"), strerror(errno
));
683 _SCErrorSet(kSCStatusFailed
);
687 vlr_tag
= vreq
.vlr_tag
;
688 strlcpy(vlr_parent
, vreq
.vlr_parent
, sizeof(vlr_parent
));
690 vlan_if
= CFStringCreateWithCString(NULL
, ifp
->ifa_name
, kCFStringEncodingASCII
);
691 device
= CFStringCreateWithCString(NULL
, vlr_parent
, kCFStringEncodingASCII
);
692 tag
= CFNumberCreate(NULL
, kCFNumberIntType
, &vlr_tag
);
693 vlan
= __VLANInterfaceCreatePrivate(NULL
, vlan_if
, device
, tag
, NULL
);
694 CFArrayAppendValue(vlans
, vlan
);
716 findVLAN(CFArrayRef vlans
, CFStringRef device
, CFNumberRef tag
)
718 CFIndex found
= kCFNotFound
;
722 n
= isA_CFArray(vlans
) ? CFArrayGetCount(vlans
) : 0;
723 for (i
= 0; i
< n
; i
++) {
724 CFDictionaryRef vlan_dict
;
725 CFStringRef vlan_device
;
727 CFNumberRef vlan_tag
;
729 vlan_dict
= CFArrayGetValueAtIndex(vlans
, i
);
730 if (!isA_CFDictionary(vlan_dict
)) {
731 continue; // if the prefs are confused
734 vlan_if
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_interface
);
735 if (!isA_CFString(vlan_if
)) {
736 continue; // if the prefs are confused
739 vlan_device
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_device
);
740 if (isA_CFString(vlan_device
)) {
741 if (!CFEqual(device
, vlan_device
)) {
742 continue; // if not a match
746 vlan_tag
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_tag
);
747 if (isA_CFNumber(vlan_tag
)) {
748 if (!CFEqual(tag
, vlan_tag
)) {
749 continue; // if not a match
753 // if we have found a match
763 setConfigurationChanged(VLANPreferencesRef prefs
)
765 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
768 * to facilitate device configuration we will take
769 * a snapshot of the VLAN preferences before any
770 * changes are made. Then, when the changes are
771 * applied we can compare what we had to what we
772 * want and configured the system accordingly.
774 if (prefsPrivate
->vlBase
== NULL
) {
775 prefsPrivate
->vlBase
= VLANPreferencesCopyInterfaces(prefs
);
783 VLANPreferencesGetTypeID(void)
785 pthread_once(&vlanPreferences_init
, __VLANPreferencesInitialize
); /* initialize runtime */
786 return __kVLANPreferencesTypeID
;
791 VLANPreferencesCreate(CFAllocatorRef allocator
)
794 CFStringRef bundleID
= NULL
;
795 CFStringRef name
= CFSTR("VLANConfiguration");
796 VLANPreferencesPrivateRef prefsPrivate
;
799 /* initialize runtime */
800 pthread_once(&vlanPreferences_init
, __VLANPreferencesInitialize
);
802 /* allocate preferences */
803 size
= sizeof(VLANPreferencesPrivate
) - sizeof(CFRuntimeBase
);
804 prefsPrivate
= (VLANPreferencesPrivateRef
)_CFRuntimeCreateInstance(allocator
,
805 __kVLANPreferencesTypeID
,
808 if (prefsPrivate
== NULL
) {
812 /* establish the prefs */
814 pthread_mutex_init(&prefsPrivate
->lock
, NULL
);
816 bundle
= CFBundleGetMainBundle();
818 bundleID
= CFBundleGetIdentifier(bundle
);
824 url
= CFBundleCopyExecutableURL(bundle
);
826 bundleID
= CFURLCopyPath(url
);
833 CFStringRef fullName
;
835 if (CFEqual(bundleID
, CFSTR("/"))) {
837 bundleID
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("(%d)"), getpid());
840 fullName
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%@:%@"), bundleID
, name
);
847 prefsPrivate
->prefs
= SCPreferencesCreate(allocator
, name
, VLAN_PREFERENCES_ID
);
850 prefsPrivate
->vlBase
= NULL
;
852 return (VLANPreferencesRef
)prefsPrivate
;
857 VLANPreferencesCopyInterfaces(VLANPreferencesRef prefs
)
859 CFAllocatorRef allocator
;
860 CFArrayCallBacks callbacks
;
863 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
864 CFMutableArrayRef result
;
867 if (!isA_VLANPreferences(prefs
)) {
868 _SCErrorSet(kSCStatusInvalidArgument
);
872 allocator
= CFGetAllocator(prefs
);
873 callbacks
= kCFTypeArrayCallBacks
;
874 callbacks
.equal
= __VLANInterfaceEquiv
;
875 result
= CFArrayCreateMutable(allocator
, 0, &callbacks
);
877 vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
878 n
= isA_CFArray(vlans
) ? CFArrayGetCount(vlans
) : 0;
879 for (i
= 0; i
< n
; i
++) {
880 CFDictionaryRef vlan_dict
;
882 CFDictionaryRef options
;
884 VLANInterfaceRef vlan
;
887 vlan_dict
= CFArrayGetValueAtIndex(vlans
, i
);
888 if (!isA_CFDictionary(vlan_dict
)) {
889 continue; // if the prefs are confused
892 vlan_if
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_interface
);
893 if (!isA_CFString(vlan_if
)) {
894 continue; // if the prefs are confused
898 device
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_device
);
899 if (!isA_CFString(device
)) {
900 continue; // if the prefs are confused
903 tag
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_tag
);
904 if (!isA_CFNumber(tag
)) {
905 continue; // if the prefs are confused
908 options
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_options
);
909 if ((options
!= NULL
) && !isA_CFDictionary(options
)) {
910 continue; // if the prefs are confused
913 vlan
= __VLANInterfaceCreatePrivate(allocator
, vlan_if
, device
, tag
, options
);
914 CFArrayAppendValue(result
, vlan
);
923 VLANPreferencesAddInterface(VLANPreferencesRef prefs
,
926 CFDictionaryRef options
)
928 CFArrayRef active_vlans
;
929 CFAllocatorRef allocator
;
930 CFArrayRef config_vlans
;
935 VLANInterfaceRef newVlan
= NULL
;
936 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
938 if (!isA_VLANPreferences(prefs
)) {
939 _SCErrorSet(kSCStatusInvalidArgument
);
943 if (!isA_CFString(device
)) {
944 _SCErrorSet(kSCStatusInvalidArgument
);
948 if (isA_CFNumber(tag
)) {
951 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
952 if ((tag_val
< 1) || (tag_val
> 4094)) {
953 _SCErrorSet(kSCStatusInvalidArgument
);
957 _SCErrorSet(kSCStatusInvalidArgument
);
961 if ((options
!= NULL
) && !isA_CFDictionary(options
)) {
962 _SCErrorSet(kSCStatusInvalidArgument
);
966 pthread_mutex_lock(&prefsPrivate
->lock
);
968 /* get "configured" VLANs (and check to ensure we are not creating a duplicate) */
969 config_vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
970 nConfig
= isA_CFArray(config_vlans
) ? CFArrayGetCount(config_vlans
) : 0;
972 dup_if
= findVLAN(config_vlans
, device
, tag
);
973 if (dup_if
!= kCFNotFound
) {
974 // sorry, you can't add a vlan using the same device/tag */
975 _SCErrorSet(kSCStatusKeyExists
);
979 /* get "active" VLANs */
980 active_vlans
= _VLANPreferencesCopyActiveInterfaces();
981 nActive
= isA_CFArray(active_vlans
) ? CFArrayGetCount(active_vlans
) : 0;
983 /* create a new vlan using an unused interface name */
984 allocator
= CFGetAllocator(prefs
);
986 for (i
= 0; newVlan
== NULL
; i
++) {
988 CFMutableDictionaryRef newDict
;
989 CFMutableArrayRef newVlans
;
992 vlan_if
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("vlan%d"), i
);
994 for (j
= 0; j
< nActive
; j
++) {
995 CFStringRef active_if
;
996 VLANInterfaceRef active_vlan
;
998 active_vlan
= CFArrayGetValueAtIndex(active_vlans
, j
);
999 active_if
= VLANInterfaceGetInterface(active_vlan
);
1001 if (CFEqual(vlan_if
, active_if
)) {
1002 goto next_if
; // if VLAN interface name not available
1006 for (j
= 0; j
< nConfig
; j
++) {
1007 CFDictionaryRef config
;
1008 CFStringRef config_if
;
1010 config
= CFArrayGetValueAtIndex(config_vlans
, j
);
1011 if (!isA_CFDictionary(config
)) {
1012 continue; // if the prefs are confused
1015 config_if
= CFDictionaryGetValue(config
, __kVLANInterface_interface
);
1016 if (!isA_CFString(config_if
)) {
1017 continue; // if the prefs are confused
1020 if (CFEqual(vlan_if
, config_if
)) {
1021 goto next_if
; // if VLAN interface name not available
1025 /* create the vlan */
1027 newDict
= CFDictionaryCreateMutable(allocator
,
1029 &kCFTypeDictionaryKeyCallBacks
,
1030 &kCFTypeDictionaryValueCallBacks
);
1031 CFDictionaryAddValue(newDict
, __kVLANInterface_interface
, vlan_if
);
1032 CFDictionaryAddValue(newDict
, __kVLANInterface_device
, device
);
1033 CFDictionaryAddValue(newDict
, __kVLANInterface_tag
, tag
);
1034 if (options
!= NULL
) {
1035 CFDictionaryAddValue(newDict
, __kVLANInterface_options
, options
);
1038 /* create the accessor handle to be returned */
1040 newVlan
= __VLANInterfaceCreatePrivate(allocator
, vlan_if
, device
, tag
, options
);
1042 /* yes, we're going to be changing the configuration */
1043 setConfigurationChanged(prefs
);
1045 /* save in the prefs */
1048 newVlans
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
1050 newVlans
= CFArrayCreateMutableCopy(allocator
, 0, config_vlans
);
1052 CFArrayAppendValue(newVlans
, newDict
);
1055 (void) SCPreferencesSetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
, newVlans
);
1056 CFRelease(newVlans
);
1062 CFRelease(active_vlans
);
1066 pthread_mutex_unlock(&prefsPrivate
->lock
);
1068 return (VLANInterfaceRef
) newVlan
;
1073 VLANPreferencesUpdateInterface(VLANPreferencesRef prefs
,
1074 VLANInterfaceRef vlan
,
1075 CFStringRef newDevice
,
1077 CFDictionaryRef newOptions
)
1079 CFAllocatorRef allocator
;
1082 CFMutableDictionaryRef newDict
;
1083 CFMutableArrayRef newVlans
;
1085 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1087 CFStringRef vlan_if
;
1089 if (!isA_VLANPreferences(prefs
)) {
1090 _SCErrorSet(kSCStatusInvalidArgument
);
1094 if (!isA_VLANInterface(vlan
)) {
1095 _SCErrorSet(kSCStatusInvalidArgument
);
1099 if ((newDevice
!= NULL
) && !isA_CFString(newDevice
)) {
1100 _SCErrorSet(kSCStatusInvalidArgument
);
1104 if (newTag
!= NULL
) {
1105 if (isA_CFNumber(newTag
)) {
1108 CFNumberGetValue(newTag
, kCFNumberIntType
, &tag_val
);
1109 if ((tag_val
< 1) || (tag_val
> 4094)) {
1110 _SCErrorSet(kSCStatusInvalidArgument
);
1114 _SCErrorSet(kSCStatusInvalidArgument
);
1119 if ((newOptions
!= NULL
)
1120 && !isA_CFDictionary(newOptions
) && (newOptions
!= (CFDictionaryRef
)kCFNull
)) {
1121 _SCErrorSet(kSCStatusInvalidArgument
);
1125 pthread_mutex_lock(&prefsPrivate
->lock
);
1127 vlan_if
= VLANInterfaceGetInterface(vlan
);
1129 vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
1130 if (!isA_CFArray(vlans
)) {
1131 goto done
; // if the prefs are confused
1134 cur_if
= findVLAN(vlans
,
1135 VLANInterfaceGetDevice(vlan
),
1136 VLANInterfaceGetTag (vlan
));
1137 if (cur_if
== kCFNotFound
) {
1138 _SCErrorSet(kSCStatusNoKey
);
1142 dup_if
= findVLAN(vlans
,
1143 newDevice
!= NULL
? newDevice
: VLANInterfaceGetDevice(vlan
),
1144 newTag
!= NULL
? newTag
: VLANInterfaceGetTag (vlan
));
1145 if (dup_if
!= kCFNotFound
) {
1146 // if the same device/tag has already been defined
1147 if (cur_if
!= dup_if
) {
1149 * sorry, you can't update another vlan that is using
1150 * the same device/tag
1152 _SCErrorSet(kSCStatusKeyExists
);
1157 /* update the vlan */
1159 if (newDevice
!= NULL
) {
1160 VLANInterfaceSetDevice(vlan
, newDevice
);
1162 newDevice
= VLANInterfaceGetDevice(vlan
);
1165 if (newTag
!= NULL
) {
1166 VLANInterfaceSetTag(vlan
, newTag
);
1168 newTag
= VLANInterfaceGetTag(vlan
);
1171 if (newOptions
!= NULL
) {
1172 if (newOptions
!= (CFDictionaryRef
)kCFNull
) {
1173 VLANInterfaceSetOptions(vlan
, newOptions
);
1175 VLANInterfaceSetOptions(vlan
, NULL
);
1179 newOptions
= VLANInterfaceGetOptions(vlan
);
1182 /* update the prefs */
1184 allocator
= CFGetAllocator(prefs
);
1185 newDict
= CFDictionaryCreateMutable(allocator
,
1187 &kCFTypeDictionaryKeyCallBacks
,
1188 &kCFTypeDictionaryValueCallBacks
);
1189 CFDictionaryAddValue(newDict
, __kVLANInterface_interface
, vlan_if
);
1190 CFDictionaryAddValue(newDict
, __kVLANInterface_device
, newDevice
);
1191 CFDictionaryAddValue(newDict
, __kVLANInterface_tag
, newTag
);
1192 if (newOptions
!= NULL
) {
1193 CFDictionaryAddValue(newDict
, __kVLANInterface_options
, newOptions
);
1196 /* yes, we're going to be changing the configuration */
1197 setConfigurationChanged(prefs
);
1199 /* update the prefs */
1201 newVlans
= CFArrayCreateMutableCopy(allocator
, 0, vlans
);
1202 CFArraySetValueAtIndex(newVlans
, cur_if
, newDict
);
1205 (void) SCPreferencesSetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
, newVlans
);
1206 CFRelease(newVlans
);
1212 pthread_mutex_unlock(&prefsPrivate
->lock
);
1219 VLANPreferencesRemoveInterface(VLANPreferencesRef prefs
,
1220 VLANInterfaceRef vlan
)
1222 CFAllocatorRef allocator
;
1224 CFMutableArrayRef newVlans
;
1226 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1229 if (!isA_VLANPreferences(prefs
)) {
1230 _SCErrorSet(kSCStatusInvalidArgument
);
1234 if (!isA_VLANInterface(vlan
)) {
1235 _SCErrorSet(kSCStatusInvalidArgument
);
1239 pthread_mutex_lock(&prefsPrivate
->lock
);
1241 vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
1242 if (!isA_CFArray(vlans
)) {
1243 _SCErrorSet(kSCStatusNoKey
);
1244 goto done
; // if the prefs are confused
1247 cur_if
= findVLAN(vlans
,
1248 VLANInterfaceGetDevice(vlan
),
1249 VLANInterfaceGetTag (vlan
));
1250 if (cur_if
== kCFNotFound
) {
1251 _SCErrorSet(kSCStatusNoKey
);
1255 /* yes, we're going to be changing the configuration */
1256 setConfigurationChanged(prefs
);
1258 /* remove the vlan */
1260 allocator
= CFGetAllocator(prefs
);
1261 newVlans
= CFArrayCreateMutableCopy(allocator
, 0, vlans
);
1262 CFArrayRemoveValueAtIndex(newVlans
, cur_if
);
1264 (void) SCPreferencesSetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
, newVlans
);
1265 CFRelease(newVlans
);
1271 pthread_mutex_unlock(&prefsPrivate
->lock
);
1278 VLANPreferencesCommitChanges(VLANPreferencesRef prefs
)
1281 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1283 if (!isA_VLANPreferences(prefs
)) {
1284 _SCErrorSet(kSCStatusInvalidArgument
);
1288 ok
= SCPreferencesCommitChanges(prefsPrivate
->prefs
);
1293 if (prefsPrivate
->vlBase
!= NULL
) {
1294 CFRelease(prefsPrivate
->vlBase
);
1295 prefsPrivate
->vlBase
= NULL
;
1303 _VLANPreferencesUpdateConfiguration(VLANPreferencesRef prefs
)
1305 CFArrayRef active
= NULL
;
1306 CFArrayRef config
= NULL
;
1307 CFMutableDictionaryRef devices
= NULL
;
1312 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1315 if (!isA_VLANPreferences(prefs
)) {
1316 _SCErrorSet(kSCStatusInvalidArgument
);
1320 /* configured VLANs */
1321 if (prefsPrivate
->vlBase
!= NULL
) {
1323 * updated VLAN preferences have not been committed
1324 * so we ignore any in-progress changes and apply the
1325 * saved preferences.
1327 config
= CFRetain(prefsPrivate
->vlBase
);
1330 * apply the saved preferences
1332 config
= VLANPreferencesCopyInterfaces(prefs
);
1334 nConfig
= CFArrayGetCount(config
);
1336 /* [parent] devices */
1337 devices
= CFDictionaryCreateMutable(NULL
,
1339 &kCFTypeDictionaryKeyCallBacks
,
1340 &kCFTypeDictionaryValueCallBacks
);
1343 active
= _VLANPreferencesCopyActiveInterfaces();
1344 nActive
= CFArrayGetCount(active
);
1346 /* remove any no-longer-configured VLAN interfaces */
1347 for (i
= 0; i
< nActive
; i
++) {
1348 VLANInterfaceRef a_vlan
;
1349 CFStringRef a_vlan_if
;
1351 Boolean found
= FALSE
;
1353 a_vlan
= CFArrayGetValueAtIndex(active
, i
);
1354 a_vlan_if
= VLANInterfaceGetInterface(a_vlan
);
1356 for (j
= 0; j
< nConfig
; j
++) {
1357 VLANInterfaceRef c_vlan
;
1358 CFStringRef c_vlan_if
;
1360 c_vlan
= CFArrayGetValueAtIndex(config
, j
);
1361 c_vlan_if
= VLANInterfaceGetInterface(c_vlan
);
1363 if (CFEqual(a_vlan_if
, c_vlan_if
)) {
1370 // remove VLAN interface
1372 s
= inet_dgram_socket();
1375 ok
= __destroyInterface(s
, a_vlan_if
);
1377 _SCErrorSet(kSCStatusFailed
);
1383 /* create (and update) configured VLAN interfaces */
1384 for (i
= 0; i
< nConfig
; i
++) {
1385 VLANInterfaceRef c_vlan
;
1386 CFStringRef c_vlan_device
;
1387 CFStringRef c_vlan_if
;
1388 Boolean found
= FALSE
;
1390 CFBooleanRef supported
;
1392 c_vlan
= CFArrayGetValueAtIndex(config
, i
);
1393 c_vlan_device
= VLANInterfaceGetDevice(c_vlan
);
1394 c_vlan_if
= VLANInterfaceGetInterface(c_vlan
);
1396 // determine if the [parent] device supports VLANs
1397 supported
= CFDictionaryGetValue(devices
, c_vlan_device
);
1398 if (supported
== NULL
) {
1399 supported
= IsVLANSupported(c_vlan_device
) ? kCFBooleanTrue
1401 CFDictionaryAddValue(devices
, c_vlan_device
, supported
);
1404 for (j
= 0; j
< nActive
; j
++) {
1405 VLANInterfaceRef a_vlan
;
1406 CFStringRef a_vlan_if
;
1408 a_vlan
= CFArrayGetValueAtIndex(active
, j
);
1409 a_vlan_if
= VLANInterfaceGetInterface(a_vlan
);
1411 if (CFEqual(c_vlan_if
, a_vlan_if
)) {
1412 if (!__VLANInterfaceEquiv(c_vlan
, a_vlan
)) {
1413 // update VLAN interface;
1415 s
= inet_dgram_socket();
1418 if (CFBooleanGetValue(supported
)) {
1419 // if the new [parent] device supports VLANs
1420 ok
= _VLANDevice_unset(s
, c_vlan_if
);
1425 ok
= _VLANDevice_set(s
,
1428 VLANInterfaceGetTag(c_vlan
));
1433 // if the new [parent] device does not support VLANs
1434 ok
= __destroyInterface(s
, c_vlan_if
);
1436 _SCErrorSet(kSCStatusFailed
);
1447 if (!found
&& CFBooleanGetValue(supported
)) {
1448 // if the [parent] device supports VLANs, add new interface
1450 s
= inet_dgram_socket();
1453 ok
= __createInterface(s
, c_vlan_if
);
1455 _SCErrorSet(kSCStatusFailed
);
1459 ok
= _VLANDevice_set(s
,
1462 VLANInterfaceGetTag(c_vlan
));
1474 if (active
) CFRelease(active
);
1475 if (config
) CFRelease(config
);
1476 if (devices
) CFRelease(devices
);
1477 if (s
!= -1) (void) close(s
);
1484 VLANPreferencesApplyChanges(VLANPreferencesRef prefs
)
1487 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1489 if (!isA_VLANPreferences(prefs
)) {
1490 _SCErrorSet(kSCStatusInvalidArgument
);
1494 pthread_mutex_lock(&prefsPrivate
->lock
);
1496 /* apply the preferences */
1497 ok
= SCPreferencesApplyChanges(prefsPrivate
->prefs
);
1502 /* apply the VLAN configuration */
1503 ok
= _VLANPreferencesUpdateConfiguration(prefs
);
1510 pthread_mutex_unlock(&prefsPrivate
->lock
);