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/SCValidation.h>
37 #include <SystemConfiguration/SCPrivate.h>
41 #include <sys/types.h>
42 #define KERNEL_PRIVATE
43 #include <sys/ioctl.h>
45 #include <sys/socket.h>
46 #include <sys/sysctl.h>
47 #include <net/ethernet.h>
48 #define KERNEL_PRIVATE 1
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 _VLAN_create(int s
, CFStringRef interface
)
82 bzero(&ifr
, sizeof(ifr
));
83 (void) _SC_cfstring_to_cstring(interface
,
86 kCFStringEncodingASCII
);
88 if (ioctl(s
, SIOCIFCREATE
, &ifr
) == -1) {
89 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCIFCREATE) failed: %s"), strerror(errno
));
90 _SCErrorSet(kSCStatusFailed
);
95 #else /* SIOCIFCREATE */
97 #endif /* SIOCIFCREATE */
102 _VLAN_destroy(int s
, CFStringRef interface
)
107 bzero(&ifr
, sizeof(ifr
));
108 (void) _SC_cfstring_to_cstring(interface
,
110 sizeof(ifr
.ifr_name
),
111 kCFStringEncodingASCII
);
113 if (ioctl(s
, SIOCIFDESTROY
, &ifr
) == -1) {
114 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCIFDESTROY) failed: %s"), strerror(errno
));
115 _SCErrorSet(kSCStatusFailed
);
120 #else /* SIOCIFDESTROY */
122 #endif /* SIOCIFDESTROY */
127 _VLANDevice_set(int s
, CFStringRef interface
, CFStringRef device
, CFNumberRef tag
)
134 bzero(&ifr
, sizeof(ifr
));
135 bzero(&vreq
, sizeof(vreq
));
138 (void) _SC_cfstring_to_cstring(interface
,
140 sizeof(ifr
.ifr_name
),
141 kCFStringEncodingASCII
);
142 ifr
.ifr_data
= (caddr_t
)&vreq
;
145 (void) _SC_cfstring_to_cstring(device
,
147 sizeof(vreq
.vlr_parent
),
148 kCFStringEncodingASCII
);
151 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
152 vreq
.vlr_tag
= tag_val
;
154 // update parent device and tag
155 if (ioctl(s
, SIOCSETVLAN
, (caddr_t
)&ifr
) == -1) {
156 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCSETVLAN) failed: %s"), strerror(errno
));
157 _SCErrorSet(kSCStatusFailed
);
162 #else /* SIOCSETVLAN */
164 #endif /* SIOCSETVLAN */
169 _VLANDevice_unset(int s
, CFStringRef interface
)
175 bzero(&ifr
, sizeof(ifr
));
176 bzero(&vreq
, sizeof(vreq
));
179 (void) _SC_cfstring_to_cstring(interface
,
181 sizeof(ifr
.ifr_name
),
182 kCFStringEncodingASCII
);
183 ifr
.ifr_data
= (caddr_t
)&vreq
;
185 // clear parent device
186 bzero(&vreq
.vlr_parent
, sizeof(vreq
.vlr_parent
));
191 // update parent device and tag
192 if (ioctl(s
, SIOCSETVLAN
, (caddr_t
)&ifr
) == -1) {
193 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCSETVLAN) failed: %s"), strerror(errno
));
194 _SCErrorSet(kSCStatusFailed
);
199 #else /* SIOCSETVLAN */
201 #endif /* SIOCSETVLAN */
205 /* ---------- VLAN "device" ---------- */
208 IsVLANSupported(CFStringRef device
)
212 struct if_msghdr
* ifm
;
213 char * if_name
= NULL
;
214 unsigned int if_index
;
215 Boolean isVlan
= FALSE
;
218 /* get the interface index */
220 if_name
= _SC_cfstring_to_cstring(device
, NULL
, NULL
, kCFStringEncodingASCII
);
221 if (if_name
== NULL
) {
222 return FALSE
; // if conversion error
224 if_index
= if_nametoindex(if_name
);
226 goto done
; // if unknown interface
229 /* get information for the specified device */
235 mib
[4] = NET_RT_IFLIST
;
236 mib
[5] = if_index
; /* ask for exactly one interface */
238 if (sysctl(mib
, 6, NULL
, &buf_len
, NULL
, 0) < 0) {
239 SCLog(TRUE
, LOG_ERR
, CFSTR("sysctl() size failed: %s"), strerror(errno
));
242 buf
= CFAllocatorAllocate(NULL
, buf_len
, 0);
243 if (sysctl(mib
, 6, buf
, &buf_len
, NULL
, 0) < 0) {
244 SCLog(TRUE
, LOG_ERR
, CFSTR("sysctl() failed: %s"), strerror(errno
));
248 /* check the link type and hwassist flags */
250 ifm
= (struct if_msghdr
*)buf
;
251 switch (ifm
->ifm_type
) {
253 #if defined(IF_HWASSIST_VLAN_TAGGING) && defined(IF_HWASSIST_VLAN_MTU)
254 struct if_data
*if_data
= &ifm
->ifm_data
;
256 if (if_data
->ifi_hwassist
& (IF_HWASSIST_VLAN_TAGGING
| IF_HWASSIST_VLAN_MTU
)) {
266 if (if_name
!= NULL
) CFAllocatorDeallocate(NULL
, if_name
);
267 if (buf
!= NULL
) CFAllocatorDeallocate(NULL
, buf
);
272 /* ---------- VLANInterface ---------- */
276 /* base CFType information */
277 CFRuntimeBase cfBase
;
279 /* vlan interface configuration */
280 CFStringRef ifname
; // e.g. vlan0, vlan1, ...
281 CFStringRef device
; // e.g. en0, en1, ...
282 CFNumberRef tag
; // e.g. 1 <= tag <= 4094
283 CFDictionaryRef options
; // e.g. UserDefinedName
285 } VLANInterfacePrivate
, * VLANInterfacePrivateRef
;
288 static CFStringRef
__VLANInterfaceCopyDescription (CFTypeRef cf
);
289 static void __VLANInterfaceDeallocate (CFTypeRef cf
);
290 static Boolean
__VLANInterfaceEqual (CFTypeRef cf1
, CFTypeRef cf2
);
293 static const CFRuntimeClass __VLANInterfaceClass
= {
295 "VLANInterface", // className
298 __VLANInterfaceDeallocate
, // dealloc
299 __VLANInterfaceEqual
, // equal
301 NULL
, // copyFormattingDesc
302 __VLANInterfaceCopyDescription
// copyDebugDesc
306 static CFTypeID __kVLANInterfaceTypeID
= _kCFRuntimeNotATypeID
;
309 static pthread_once_t vlanInterface_init
= PTHREAD_ONCE_INIT
;
313 __VLANInterfaceCopyDescription(CFTypeRef cf
)
315 CFAllocatorRef allocator
= CFGetAllocator(cf
);
316 CFMutableStringRef result
;
317 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)cf
;
319 result
= CFStringCreateMutable(allocator
, 0);
320 CFStringAppendFormat(result
, NULL
, CFSTR("<VLANInterface %p [%p]> {"), cf
, allocator
);
321 CFStringAppendFormat(result
, NULL
, CFSTR(" if = %@"), vlanPrivate
->ifname
);
322 CFStringAppendFormat(result
, NULL
, CFSTR(", device = %@"), vlanPrivate
->device
);
323 CFStringAppendFormat(result
, NULL
, CFSTR(", tag = %@"), vlanPrivate
->tag
);
324 if (vlanPrivate
->options
!= NULL
) {
325 CFStringAppendFormat(result
, NULL
, CFSTR(", options = %@"), vlanPrivate
->options
);
327 CFStringAppendFormat(result
, NULL
, CFSTR(" }"));
334 __VLANInterfaceDeallocate(CFTypeRef cf
)
336 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)cf
;
338 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__VLANInterfaceDeallocate:"));
340 /* release resources */
342 CFRelease(vlanPrivate
->ifname
);
343 CFRelease(vlanPrivate
->device
);
344 CFRelease(vlanPrivate
->tag
);
345 if (vlanPrivate
->options
) CFRelease(vlanPrivate
->options
);
352 __VLANInterfaceEquiv(CFTypeRef cf1
, CFTypeRef cf2
)
354 VLANInterfacePrivateRef vlan1
= (VLANInterfacePrivateRef
)cf1
;
355 VLANInterfacePrivateRef vlan2
= (VLANInterfacePrivateRef
)cf2
;
360 if (!CFEqual(vlan1
->ifname
, vlan2
->ifname
))
361 return FALSE
; // if not the same interface
363 if (!CFEqual(vlan1
->device
, vlan2
->device
))
364 return FALSE
; // if not the same device
366 if (!CFEqual(vlan1
->tag
, vlan2
->tag
))
367 return FALSE
; // if not the same tag
374 __VLANInterfaceEqual(CFTypeRef cf1
, CFTypeRef cf2
)
376 VLANInterfacePrivateRef vlan1
= (VLANInterfacePrivateRef
)cf1
;
377 VLANInterfacePrivateRef vlan2
= (VLANInterfacePrivateRef
)cf2
;
379 if (!__VLANInterfaceEquiv(vlan1
, vlan2
))
380 return FALSE
; // if not the same VLAN interface/device/tag
382 if (vlan1
->options
!= vlan2
->options
) {
383 // if the options may differ
384 if ((vlan1
->options
!= NULL
) && (vlan2
->options
!= NULL
)) {
385 // if both VLANs have options
386 if (!CFEqual(vlan1
->options
, vlan2
->options
)) {
387 // if the options are not equal
391 // if only one VLAN has options
401 __VLANInterfaceInitialize(void)
403 __kVLANInterfaceTypeID
= _CFRuntimeRegisterClass(&__VLANInterfaceClass
);
408 static __inline__ CFTypeRef
409 isA_VLANInterface(CFTypeRef obj
)
411 return (isA_CFType(obj
, VLANInterfaceGetTypeID()));
416 VLANInterfaceGetTypeID(void)
418 pthread_once(&vlanInterface_init
, __VLANInterfaceInitialize
); /* initialize runtime */
419 return __kVLANInterfaceTypeID
;
423 static VLANInterfaceRef
424 __VLANInterfaceCreatePrivate(CFAllocatorRef allocator
,
428 CFDictionaryRef options
)
430 VLANInterfacePrivateRef vlanPrivate
;
433 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__VLANInterfaceCreatePrivate:"));
435 /* initialize runtime */
436 pthread_once(&vlanInterface_init
, __VLANInterfaceInitialize
);
439 size
= sizeof(VLANInterfacePrivate
) - sizeof(CFRuntimeBase
);
440 vlanPrivate
= (VLANInterfacePrivateRef
)_CFRuntimeCreateInstance(allocator
,
441 __kVLANInterfaceTypeID
,
448 /* establish the vlan */
450 vlanPrivate
->ifname
= CFStringCreateCopy(allocator
, ifname
);
451 vlanPrivate
->device
= CFStringCreateCopy(allocator
, device
);
452 vlanPrivate
->tag
= CFRetain(tag
);
453 if (options
!= NULL
) {
454 vlanPrivate
->options
= CFDictionaryCreateCopy(allocator
, options
);
456 vlanPrivate
->options
= NULL
;
459 return (VLANInterfaceRef
)vlanPrivate
;
464 VLANInterfaceGetInterface(VLANInterfaceRef vlan
)
466 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
467 CFStringRef vlan_if
= NULL
;
469 if (isA_VLANInterface(vlan
)) {
470 vlan_if
= vlanPrivate
->ifname
;
478 VLANInterfaceGetDevice(VLANInterfaceRef vlan
)
480 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
481 CFStringRef vlan_device
= NULL
;
483 if (isA_VLANInterface(vlan
)) {
484 vlan_device
= vlanPrivate
->device
;
492 VLANInterfaceSetDevice(VLANInterfaceRef vlan
, CFStringRef newDevice
)
494 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
496 if (isA_VLANInterface(vlan
)) {
497 CFAllocatorRef allocator
= CFGetAllocator(vlan
);
499 CFRelease(vlanPrivate
->device
);
500 vlanPrivate
->device
= CFStringCreateCopy(allocator
, newDevice
);
508 VLANInterfaceGetTag(VLANInterfaceRef vlan
)
510 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
511 CFNumberRef vlan_tag
= NULL
;
513 if (isA_VLANInterface(vlan
)) {
514 vlan_tag
= vlanPrivate
->tag
;
522 VLANInterfaceSetTag(VLANInterfaceRef vlan
, CFNumberRef newTag
)
524 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
526 if (isA_VLANInterface(vlan
)) {
527 CFRelease(vlanPrivate
->tag
);
528 vlanPrivate
->tag
= CFRetain(newTag
);
536 VLANInterfaceGetOptions(VLANInterfaceRef vlan
)
538 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
539 CFDictionaryRef vlan_options
= NULL
;
541 if (isA_VLANInterface(vlan
)) {
542 vlan_options
= vlanPrivate
->options
;
550 VLANInterfaceSetOptions(VLANInterfaceRef vlan
, CFDictionaryRef newOptions
)
552 VLANInterfacePrivateRef vlanPrivate
= (VLANInterfacePrivateRef
)vlan
;
554 if (isA_VLANInterface(vlan
)) {
555 CFAllocatorRef allocator
= CFGetAllocator(vlan
);
557 if (vlanPrivate
->options
) CFRelease(vlanPrivate
->options
);
558 if (newOptions
!= NULL
) {
559 vlanPrivate
->options
= CFDictionaryCreateCopy(allocator
, newOptions
);
561 vlanPrivate
->options
= NULL
;
569 /* ---------- VLANPreferences ---------- */
571 #define VLAN_PREFERENCES_VLANS CFSTR("VLANs")
573 #define __kVLANInterface_interface CFSTR("interface") // e.g. vlan0, vlan1, ...
574 #define __kVLANInterface_device CFSTR("device") // e.g. en0, en1, ...
575 #define __kVLANInterface_tag CFSTR("tag") // e.g. 1 <= tag <= 4094
576 #define __kVLANInterface_options CFSTR("options") // e.g. UserDefinedName
580 /* base CFType information */
581 CFRuntimeBase cfBase
;
584 pthread_mutex_t lock
;
586 /* underlying preferences */
587 SCPreferencesRef prefs
;
589 /* base VLANs (before any commits) */
592 } VLANPreferencesPrivate
, * VLANPreferencesPrivateRef
;
595 static CFStringRef
__VLANPreferencesCopyDescription (CFTypeRef cf
);
596 static void __VLANPreferencesDeallocate (CFTypeRef cf
);
599 static const CFRuntimeClass __VLANPreferencesClass
= {
601 "VLANPreferences", // className
604 __VLANPreferencesDeallocate
, // dealloc
607 NULL
, // copyFormattingDesc
608 __VLANPreferencesCopyDescription
// copyDebugDesc
612 static CFTypeID __kVLANPreferencesTypeID
= _kCFRuntimeNotATypeID
;
615 static pthread_once_t vlanPreferences_init
= PTHREAD_ONCE_INIT
;
619 __VLANPreferencesCopyDescription(CFTypeRef cf
)
621 CFAllocatorRef allocator
= CFGetAllocator(cf
);
625 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)cf
;
626 CFMutableStringRef result
;
628 result
= CFStringCreateMutable(allocator
, 0);
629 CFStringAppendFormat(result
, NULL
, CFSTR("<VLANPreferences %p [%p]> {"), cf
, allocator
);
631 keys
= SCPreferencesCopyKeyList(prefsPrivate
->prefs
);
632 n
= CFArrayGetCount(keys
);
633 for (i
= 0; i
< n
; i
++) {
635 CFPropertyListRef val
;
637 key
= CFArrayGetValueAtIndex(keys
, i
);
638 val
= SCPreferencesGetValue(prefsPrivate
->prefs
, key
);
640 CFStringAppendFormat(result
, NULL
, CFSTR("%@ : %@"), key
, val
);
644 CFStringAppendFormat(result
, NULL
, CFSTR(" }"));
654 __VLANPreferencesDeallocate(CFTypeRef cf
)
656 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)cf
;
658 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__VLANPreferencesDeallocate:"));
660 /* release resources */
662 pthread_mutex_destroy(&prefsPrivate
->lock
);
664 if (prefsPrivate
->prefs
) CFRelease(prefsPrivate
->prefs
);
665 if (prefsPrivate
->vlBase
) CFRelease(prefsPrivate
->vlBase
);
672 __VLANPreferencesInitialize(void)
674 __kVLANPreferencesTypeID
= _CFRuntimeRegisterClass(&__VLANPreferencesClass
);
679 static __inline__ CFTypeRef
680 isA_VLANPreferences(CFTypeRef obj
)
682 return (isA_CFType(obj
, VLANPreferencesGetTypeID()));
687 _VLANPreferencesCopyActiveInterfaces()
689 CFArrayCallBacks callbacks
;
690 struct ifaddrs
*ifap
;
693 CFMutableArrayRef vlans
= NULL
;
695 if (getifaddrs(&ifap
) == -1) {
696 SCLog(TRUE
, LOG_ERR
, CFSTR("getifaddrs() failed: %s"), strerror(errno
));
697 _SCErrorSet(kSCStatusFailed
);
701 s
= inet_dgram_socket();
703 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
704 _SCErrorSet(kSCStatusFailed
);
708 callbacks
= kCFTypeArrayCallBacks
;
709 callbacks
.equal
= __VLANInterfaceEquiv
;
710 vlans
= CFArrayCreateMutable(NULL
, 0, &callbacks
);
712 for (ifp
= ifap
; ifp
!= NULL
; ifp
= ifp
->ifa_next
) {
713 switch (ifp
->ifa_addr
->sa_family
) {
716 struct if_data
*if_data
;
719 VLANInterfaceRef vlan
;
721 char vlr_parent
[IFNAMSIZ
+1];
725 if_data
= (struct if_data
*)ifp
->ifa_data
;
726 if (if_data
== NULL
) {
727 break; // if no interface data
730 if (if_data
->ifi_type
!= IFT_L2VLAN
) {
731 break; // if not VLAN
734 bzero(&ifr
, sizeof(ifr
));
735 bzero(&vreq
, sizeof(vreq
));
736 strncpy(ifr
.ifr_name
, ifp
->ifa_name
, sizeof(ifr
.ifr_name
));
737 ifr
.ifr_data
= (caddr_t
)&vreq
;
739 if (ioctl(s
, SIOCGETVLAN
, (caddr_t
)&ifr
) == -1) {
740 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl() failed: %s"), strerror(errno
));
741 _SCErrorSet(kSCStatusFailed
);
745 vlr_tag
= vreq
.vlr_tag
;
746 strlcpy(vlr_parent
, vreq
.vlr_parent
, sizeof(vlr_parent
));
748 vlan_if
= CFStringCreateWithCString(NULL
, ifp
->ifa_name
, kCFStringEncodingASCII
);
749 device
= CFStringCreateWithCString(NULL
, vlr_parent
, kCFStringEncodingASCII
);
750 tag
= CFNumberCreate(NULL
, kCFNumberIntType
, &vlr_tag
);
751 vlan
= __VLANInterfaceCreatePrivate(NULL
, vlan_if
, device
, tag
, NULL
);
752 CFArrayAppendValue(vlans
, vlan
);
774 findVLAN(CFArrayRef vlans
, CFStringRef device
, CFNumberRef tag
)
776 CFIndex found
= kCFNotFound
;
780 n
= isA_CFArray(vlans
) ? CFArrayGetCount(vlans
) : 0;
781 for (i
= 0; i
< n
; i
++) {
782 CFDictionaryRef vlan_dict
;
783 CFStringRef vlan_device
;
785 CFNumberRef vlan_tag
;
787 vlan_dict
= CFArrayGetValueAtIndex(vlans
, i
);
788 if (!isA_CFDictionary(vlan_dict
)) {
789 continue; // if the prefs are confused
792 vlan_if
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_interface
);
793 if (!isA_CFString(vlan_if
)) {
794 continue; // if the prefs are confused
797 vlan_device
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_device
);
798 if (isA_CFString(vlan_device
)) {
799 if (!CFEqual(device
, vlan_device
)) {
800 continue; // if not a match
804 vlan_tag
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_tag
);
805 if (isA_CFNumber(vlan_tag
)) {
806 if (!CFEqual(tag
, vlan_tag
)) {
807 continue; // if not a match
811 // if we have found a match
821 setConfigurationChanged(VLANPreferencesRef prefs
)
823 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
826 * to facilitate device configuration we will take
827 * a snapshot of the VLAN preferences before any
828 * changes are made. Then, when the changes are
829 * applied we can compare what we had to what we
830 * want and configured the system accordingly.
832 if (prefsPrivate
->vlBase
== NULL
) {
833 prefsPrivate
->vlBase
= VLANPreferencesCopyInterfaces(prefs
);
841 VLANPreferencesGetTypeID(void)
843 pthread_once(&vlanPreferences_init
, __VLANPreferencesInitialize
); /* initialize runtime */
844 return __kVLANPreferencesTypeID
;
849 VLANPreferencesCreate(CFAllocatorRef allocator
)
852 CFStringRef bundleID
= NULL
;
853 CFStringRef name
= CFSTR("VLANConfiguration");
854 VLANPreferencesPrivateRef prefsPrivate
;
857 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__VLANPreferencesCreate:"));
859 /* initialize runtime */
860 pthread_once(&vlanPreferences_init
, __VLANPreferencesInitialize
);
862 /* allocate preferences */
863 size
= sizeof(VLANPreferencesPrivate
) - sizeof(CFRuntimeBase
);
864 prefsPrivate
= (VLANPreferencesPrivateRef
)_CFRuntimeCreateInstance(allocator
,
865 __kVLANPreferencesTypeID
,
872 /* establish the prefs */
874 pthread_mutex_init(&prefsPrivate
->lock
, NULL
);
876 bundle
= CFBundleGetMainBundle();
878 bundleID
= CFBundleGetIdentifier(bundle
);
884 url
= CFBundleCopyExecutableURL(bundle
);
886 bundleID
= CFURLCopyPath(url
);
893 CFStringRef fullName
;
895 if (CFEqual(bundleID
, CFSTR("/"))) {
897 bundleID
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("(%d)"), getpid());
900 fullName
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%@:%@"), bundleID
, name
);
907 prefsPrivate
->prefs
= SCPreferencesCreate(allocator
, name
, VLAN_PREFERENCES_ID
);
910 prefsPrivate
->vlBase
= NULL
;
912 return (VLANPreferencesRef
)prefsPrivate
;
917 VLANPreferencesCopyInterfaces(VLANPreferencesRef prefs
)
919 CFAllocatorRef allocator
;
920 CFArrayCallBacks callbacks
;
923 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
924 CFMutableArrayRef result
;
927 if (!isA_VLANPreferences(prefs
)) {
928 _SCErrorSet(kSCStatusInvalidArgument
);
932 allocator
= CFGetAllocator(prefs
);
933 callbacks
= kCFTypeArrayCallBacks
;
934 callbacks
.equal
= __VLANInterfaceEquiv
;
935 result
= CFArrayCreateMutable(allocator
, 0, &callbacks
);
937 vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
938 n
= isA_CFArray(vlans
) ? CFArrayGetCount(vlans
) : 0;
939 for (i
= 0; i
< n
; i
++) {
940 CFDictionaryRef vlan_dict
;
942 CFDictionaryRef options
;
944 VLANInterfaceRef vlan
;
947 vlan_dict
= CFArrayGetValueAtIndex(vlans
, i
);
948 if (!isA_CFDictionary(vlan_dict
)) {
949 continue; // if the prefs are confused
952 vlan_if
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_interface
);
953 if (!isA_CFString(vlan_if
)) {
954 continue; // if the prefs are confused
958 device
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_device
);
959 if (!isA_CFString(device
)) {
960 continue; // if the prefs are confused
963 tag
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_tag
);
964 if (!isA_CFNumber(tag
)) {
965 continue; // if the prefs are confused
968 options
= CFDictionaryGetValue(vlan_dict
, __kVLANInterface_options
);
969 if ((options
!= NULL
) && !isA_CFDictionary(options
)) {
970 continue; // if the prefs are confused
973 vlan
= __VLANInterfaceCreatePrivate(allocator
, vlan_if
, device
, tag
, options
);
974 CFArrayAppendValue(result
, vlan
);
983 VLANPreferencesAddInterface(VLANPreferencesRef prefs
,
986 CFDictionaryRef options
)
988 CFArrayRef active_vlans
;
989 CFAllocatorRef allocator
;
990 CFArrayRef config_vlans
;
995 VLANInterfaceRef newVlan
= NULL
;
996 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
998 if (!isA_VLANPreferences(prefs
)) {
999 _SCErrorSet(kSCStatusInvalidArgument
);
1003 if (!isA_CFString(device
)) {
1004 _SCErrorSet(kSCStatusInvalidArgument
);
1008 if (isA_CFNumber(tag
)) {
1011 CFNumberGetValue(tag
, kCFNumberIntType
, &tag_val
);
1012 if ((tag_val
< 1) || (tag_val
> 4094)) {
1013 _SCErrorSet(kSCStatusInvalidArgument
);
1017 _SCErrorSet(kSCStatusInvalidArgument
);
1021 if ((options
!= NULL
) && !isA_CFDictionary(options
)) {
1022 _SCErrorSet(kSCStatusInvalidArgument
);
1026 pthread_mutex_lock(&prefsPrivate
->lock
);
1028 /* get "configured" VLANs (and check to ensure we are not creating a duplicate) */
1029 config_vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
1030 nConfig
= isA_CFArray(config_vlans
) ? CFArrayGetCount(config_vlans
) : 0;
1032 dup_if
= findVLAN(config_vlans
, device
, tag
);
1033 if (dup_if
!= kCFNotFound
) {
1034 // sorry, you can't add a vlan using the same device/tag */
1035 _SCErrorSet(kSCStatusKeyExists
);
1039 /* get "active" VLANs */
1040 active_vlans
= _VLANPreferencesCopyActiveInterfaces();
1041 nActive
= isA_CFArray(active_vlans
) ? CFArrayGetCount(active_vlans
) : 0;
1043 /* create a new vlan using an unused interface name */
1044 allocator
= CFGetAllocator(prefs
);
1046 for (i
= 0; newVlan
== NULL
; i
++) {
1048 CFMutableDictionaryRef newDict
;
1049 CFMutableArrayRef newVlans
;
1050 CFStringRef vlan_if
;
1052 vlan_if
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("vlan%d"), i
);
1054 for (j
= 0; j
< nActive
; j
++) {
1055 CFStringRef active_if
;
1056 VLANInterfaceRef active_vlan
;
1058 active_vlan
= CFArrayGetValueAtIndex(active_vlans
, j
);
1059 active_if
= VLANInterfaceGetInterface(active_vlan
);
1061 if (CFEqual(vlan_if
, active_if
)) {
1062 goto next_if
; // if VLAN interface name not available
1066 for (j
= 0; j
< nConfig
; j
++) {
1067 CFDictionaryRef config
;
1068 CFStringRef config_if
;
1070 config
= CFArrayGetValueAtIndex(config_vlans
, j
);
1071 if (!isA_CFDictionary(config
)) {
1072 continue; // if the prefs are confused
1075 config_if
= CFDictionaryGetValue(config
, __kVLANInterface_interface
);
1076 if (!isA_CFString(config_if
)) {
1077 continue; // if the prefs are confused
1080 if (CFEqual(vlan_if
, config_if
)) {
1081 goto next_if
; // if VLAN interface name not available
1085 /* create the vlan */
1087 newDict
= CFDictionaryCreateMutable(allocator
,
1089 &kCFTypeDictionaryKeyCallBacks
,
1090 &kCFTypeDictionaryValueCallBacks
);
1091 CFDictionaryAddValue(newDict
, __kVLANInterface_interface
, vlan_if
);
1092 CFDictionaryAddValue(newDict
, __kVLANInterface_device
, device
);
1093 CFDictionaryAddValue(newDict
, __kVLANInterface_tag
, tag
);
1094 if (options
!= NULL
) {
1095 CFDictionaryAddValue(newDict
, __kVLANInterface_options
, options
);
1098 /* create the accessor handle to be returned */
1100 newVlan
= __VLANInterfaceCreatePrivate(allocator
, vlan_if
, device
, tag
, options
);
1102 /* save in the prefs */
1105 newVlans
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
1107 newVlans
= CFArrayCreateMutableCopy(allocator
, 0, config_vlans
);
1109 CFArrayAppendValue(newVlans
, newDict
);
1112 (void) SCPreferencesSetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
, newVlans
);
1113 CFRelease(newVlans
);
1115 /* yes, we've change the configuration */
1116 setConfigurationChanged(prefs
);
1122 CFRelease(active_vlans
);
1126 pthread_mutex_unlock(&prefsPrivate
->lock
);
1128 return (VLANInterfaceRef
) newVlan
;
1133 VLANPreferencesUpdateInterface(VLANPreferencesRef prefs
,
1134 VLANInterfaceRef vlan
,
1135 CFStringRef newDevice
,
1137 CFDictionaryRef newOptions
)
1139 CFAllocatorRef allocator
;
1142 CFMutableDictionaryRef newDict
;
1143 CFMutableArrayRef newVlans
;
1145 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1147 CFStringRef vlan_if
;
1149 if (!isA_VLANPreferences(prefs
)) {
1150 _SCErrorSet(kSCStatusInvalidArgument
);
1154 if (!isA_VLANInterface(vlan
)) {
1155 _SCErrorSet(kSCStatusInvalidArgument
);
1159 if ((newDevice
!= NULL
) && !isA_CFString(newDevice
)) {
1160 _SCErrorSet(kSCStatusInvalidArgument
);
1164 if (newTag
!= NULL
) {
1165 if (isA_CFNumber(newTag
)) {
1168 CFNumberGetValue(newTag
, kCFNumberIntType
, &tag_val
);
1169 if ((tag_val
< 1) || (tag_val
> 4094)) {
1170 _SCErrorSet(kSCStatusInvalidArgument
);
1174 _SCErrorSet(kSCStatusInvalidArgument
);
1179 if ((newOptions
!= NULL
)
1180 && !isA_CFDictionary(newOptions
) && (newOptions
!= (CFDictionaryRef
)kCFNull
)) {
1181 _SCErrorSet(kSCStatusInvalidArgument
);
1185 pthread_mutex_lock(&prefsPrivate
->lock
);
1187 vlan_if
= VLANInterfaceGetInterface(vlan
);
1189 vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
1190 if (!isA_CFArray(vlans
)) {
1191 goto done
; // if the prefs are confused
1194 cur_if
= findVLAN(vlans
,
1195 VLANInterfaceGetDevice(vlan
),
1196 VLANInterfaceGetTag (vlan
));
1197 if (cur_if
== kCFNotFound
) {
1198 _SCErrorSet(kSCStatusNoKey
);
1202 dup_if
= findVLAN(vlans
,
1203 newDevice
!= NULL
? newDevice
: VLANInterfaceGetDevice(vlan
),
1204 newTag
!= NULL
? newTag
: VLANInterfaceGetTag (vlan
));
1205 if (dup_if
!= kCFNotFound
) {
1206 // if the same device/tag has already been defined
1207 if (cur_if
!= dup_if
) {
1209 * sorry, you can't update another vlan that is using
1210 * the same device/tag
1212 _SCErrorSet(kSCStatusKeyExists
);
1217 /* update the vlan */
1219 if (newDevice
!= NULL
) {
1220 VLANInterfaceSetDevice(vlan
, newDevice
);
1222 newDevice
= VLANInterfaceGetDevice(vlan
);
1225 if (newTag
!= NULL
) {
1226 VLANInterfaceSetTag(vlan
, newTag
);
1228 newTag
= VLANInterfaceGetTag(vlan
);
1231 if (newOptions
!= NULL
) {
1232 if (newOptions
!= (CFDictionaryRef
)kCFNull
) {
1233 VLANInterfaceSetOptions(vlan
, newOptions
);
1235 VLANInterfaceSetOptions(vlan
, NULL
);
1239 newOptions
= VLANInterfaceGetOptions(vlan
);
1242 /* update the prefs */
1244 allocator
= CFGetAllocator(prefs
);
1245 newDict
= CFDictionaryCreateMutable(allocator
,
1247 &kCFTypeDictionaryKeyCallBacks
,
1248 &kCFTypeDictionaryValueCallBacks
);
1249 CFDictionaryAddValue(newDict
, __kVLANInterface_interface
, vlan_if
);
1250 CFDictionaryAddValue(newDict
, __kVLANInterface_device
, newDevice
);
1251 CFDictionaryAddValue(newDict
, __kVLANInterface_tag
, newTag
);
1252 if (newOptions
!= NULL
) {
1253 CFDictionaryAddValue(newDict
, __kVLANInterface_options
, newOptions
);
1256 /* update the prefs */
1258 newVlans
= CFArrayCreateMutableCopy(allocator
, 0, vlans
);
1259 CFArrayRemoveValueAtIndex(newVlans
, cur_if
);
1260 CFArrayAppendValue(newVlans
, newDict
);
1263 (void) SCPreferencesSetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
, newVlans
);
1264 CFRelease(newVlans
);
1266 /* yes, we've change the configuration */
1267 setConfigurationChanged(prefs
);
1273 pthread_mutex_unlock(&prefsPrivate
->lock
);
1280 VLANPreferencesRemoveInterface(VLANPreferencesRef prefs
,
1281 VLANInterfaceRef vlan
)
1283 CFAllocatorRef allocator
;
1285 CFMutableArrayRef newVlans
;
1287 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1290 if (!isA_VLANPreferences(prefs
)) {
1291 _SCErrorSet(kSCStatusInvalidArgument
);
1295 if (!isA_VLANInterface(vlan
)) {
1296 _SCErrorSet(kSCStatusInvalidArgument
);
1300 pthread_mutex_lock(&prefsPrivate
->lock
);
1302 vlans
= SCPreferencesGetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
);
1303 if (!isA_CFArray(vlans
)) {
1304 _SCErrorSet(kSCStatusNoKey
);
1305 goto done
; // if the prefs are confused
1308 cur_if
= findVLAN(vlans
,
1309 VLANInterfaceGetDevice(vlan
),
1310 VLANInterfaceGetTag (vlan
));
1311 if (cur_if
== kCFNotFound
) {
1312 _SCErrorSet(kSCStatusNoKey
);
1316 /* remove the vlan */
1318 allocator
= CFGetAllocator(prefs
);
1319 newVlans
= CFArrayCreateMutableCopy(allocator
, 0, vlans
);
1320 CFArrayRemoveValueAtIndex(newVlans
, cur_if
);
1322 (void) SCPreferencesSetValue(prefsPrivate
->prefs
, VLAN_PREFERENCES_VLANS
, newVlans
);
1323 CFRelease(newVlans
);
1325 /* yes, we've change the configuration */
1326 setConfigurationChanged(prefs
);
1332 pthread_mutex_unlock(&prefsPrivate
->lock
);
1339 VLANPreferencesCommitChanges(VLANPreferencesRef prefs
)
1342 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1344 if (!isA_VLANPreferences(prefs
)) {
1345 _SCErrorSet(kSCStatusInvalidArgument
);
1349 ok
= SCPreferencesCommitChanges(prefsPrivate
->prefs
);
1354 if (prefsPrivate
->vlBase
!= NULL
) {
1355 CFRelease(prefsPrivate
->vlBase
);
1356 prefsPrivate
->vlBase
= NULL
;
1364 _VLANPreferencesUpdateConfiguration(VLANPreferencesRef prefs
)
1366 CFArrayRef active
= NULL
;
1367 CFArrayRef config
= NULL
;
1368 CFMutableDictionaryRef devices
= NULL
;
1373 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1376 if (!isA_VLANPreferences(prefs
)) {
1377 _SCErrorSet(kSCStatusInvalidArgument
);
1381 /* configured VLANs */
1382 if (prefsPrivate
->vlBase
!= NULL
) {
1384 * updated VLAN preferences have not been committed
1385 * so we ignore any in-progress changes and apply the
1386 * saved preferences.
1388 config
= CFRetain(prefsPrivate
->vlBase
);
1391 * apply the saved preferences
1393 config
= VLANPreferencesCopyInterfaces(prefs
);
1395 nConfig
= CFArrayGetCount(config
);
1397 /* [parent] devices */
1398 devices
= CFDictionaryCreateMutable(NULL
,
1400 &kCFTypeDictionaryKeyCallBacks
,
1401 &kCFTypeDictionaryValueCallBacks
);
1404 active
= _VLANPreferencesCopyActiveInterfaces();
1405 nActive
= CFArrayGetCount(active
);
1407 /* remove any no-longer-configured VLAN interfaces */
1408 for (i
= 0; i
< nActive
; i
++) {
1409 VLANInterfaceRef a_vlan
;
1410 CFStringRef a_vlan_if
;
1412 Boolean found
= FALSE
;
1414 a_vlan
= CFArrayGetValueAtIndex(active
, i
);
1415 a_vlan_if
= VLANInterfaceGetInterface(a_vlan
);
1417 for (j
= 0; j
< nConfig
; j
++) {
1418 VLANInterfaceRef c_vlan
;
1419 CFStringRef c_vlan_if
;
1421 c_vlan
= CFArrayGetValueAtIndex(config
, j
);
1422 c_vlan_if
= VLANInterfaceGetInterface(c_vlan
);
1424 if (CFEqual(a_vlan_if
, c_vlan_if
)) {
1431 // remove VLAN interface
1433 s
= inet_dgram_socket();
1436 ok
= _VLAN_destroy(s
, a_vlan_if
);
1443 /* create (and update) configured VLAN interfaces */
1444 for (i
= 0; i
< nConfig
; i
++) {
1445 VLANInterfaceRef c_vlan
;
1446 CFStringRef c_vlan_device
;
1447 CFStringRef c_vlan_if
;
1448 Boolean found
= FALSE
;
1450 CFBooleanRef supported
;
1452 c_vlan
= CFArrayGetValueAtIndex(config
, i
);
1453 c_vlan_device
= VLANInterfaceGetDevice(c_vlan
);
1454 c_vlan_if
= VLANInterfaceGetInterface(c_vlan
);
1456 // determine if the [parent] device supports VLANs
1457 supported
= CFDictionaryGetValue(devices
, c_vlan_device
);
1458 if (supported
== NULL
) {
1459 supported
= IsVLANSupported(c_vlan_device
) ? kCFBooleanTrue
1461 CFDictionaryAddValue(devices
, c_vlan_device
, supported
);
1464 for (j
= 0; j
< nActive
; j
++) {
1465 VLANInterfaceRef a_vlan
;
1466 CFStringRef a_vlan_if
;
1468 a_vlan
= CFArrayGetValueAtIndex(active
, j
);
1469 a_vlan_if
= VLANInterfaceGetInterface(a_vlan
);
1471 if (CFEqual(c_vlan_if
, a_vlan_if
)) {
1472 if (!__VLANInterfaceEquiv(c_vlan
, a_vlan
)) {
1473 // update VLAN interface;
1475 s
= inet_dgram_socket();
1478 if (CFBooleanGetValue(supported
)) {
1479 // if the new [parent] device supports VLANs
1480 ok
= _VLANDevice_unset(s
, c_vlan_if
);
1485 ok
= _VLANDevice_set(s
,
1488 VLANInterfaceGetTag(c_vlan
));
1493 // if the new [parent] device does not support VLANs
1494 ok
= _VLAN_destroy(s
, c_vlan_if
);
1506 if (!found
&& CFBooleanGetValue(supported
)) {
1507 // if the [parent] device supports VLANs, add new interface
1509 s
= inet_dgram_socket();
1512 ok
= _VLAN_create(s
, c_vlan_if
);
1517 ok
= _VLANDevice_set(s
,
1520 VLANInterfaceGetTag(c_vlan
));
1532 if (active
) CFRelease(active
);
1533 if (config
) CFRelease(config
);
1534 if (devices
) CFRelease(devices
);
1535 if (s
!= -1) (void) close(s
);
1542 VLANPreferencesApplyChanges(VLANPreferencesRef prefs
)
1545 VLANPreferencesPrivateRef prefsPrivate
= (VLANPreferencesPrivateRef
)prefs
;
1547 if (!isA_VLANPreferences(prefs
)) {
1548 _SCErrorSet(kSCStatusInvalidArgument
);
1552 pthread_mutex_lock(&prefsPrivate
->lock
);
1554 /* apply the preferences */
1555 ok
= SCPreferencesApplyChanges(prefsPrivate
->prefs
);
1560 /* apply the VLAN configuration */
1561 ok
= _VLANPreferencesUpdateConfiguration(prefs
);
1570 pthread_mutex_unlock(&prefsPrivate
->lock
);