VLANConfiguration.c [plain text]
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFRuntime.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCNetworkConfigurationInternal.h>
#include <SystemConfiguration/SCValidation.h>
#include <SystemConfiguration/SCPrivate.h>
#include <ifaddrs.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/ethernet.h>
#define KERNEL_PRIVATE
#include <net/if.h>
#include <net/if_var.h>
#undef KERNEL_PRIVATE
#include <net/if_vlan_var.h>
#include <net/if_types.h>
#include <net/route.h>
#include <SystemConfiguration/VLANConfiguration.h>
#include <SystemConfiguration/VLANConfigurationPrivate.h>
static int
inet_dgram_socket()
{
int s;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == -1) {
SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
_SCErrorSet(kSCStatusFailed);
}
return s;
}
static Boolean
_VLANDevice_set(int s, CFStringRef interface, CFStringRef device, CFNumberRef tag)
{
struct ifreq ifr;
int tag_val;
struct vlanreq vreq;
bzero(&ifr, sizeof(ifr));
bzero(&vreq, sizeof(vreq));
(void) _SC_cfstring_to_cstring(interface,
ifr.ifr_name,
sizeof(ifr.ifr_name),
kCFStringEncodingASCII);
ifr.ifr_data = (caddr_t)&vreq;
(void) _SC_cfstring_to_cstring(device,
vreq.vlr_parent,
sizeof(vreq.vlr_parent),
kCFStringEncodingASCII);
CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
vreq.vlr_tag = tag_val;
if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
if (!__markInterfaceUp(s, device)) {
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
return TRUE;
}
static Boolean
_VLANDevice_unset(int s, CFStringRef interface)
{
struct ifreq ifr;
struct vlanreq vreq;
bzero(&ifr, sizeof(ifr));
bzero(&vreq, sizeof(vreq));
(void) _SC_cfstring_to_cstring(interface,
ifr.ifr_name,
sizeof(ifr.ifr_name),
kCFStringEncodingASCII);
ifr.ifr_data = (caddr_t)&vreq;
bzero(&vreq.vlr_parent, sizeof(vreq.vlr_parent));
vreq.vlr_tag = 0;
if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
return TRUE;
}
Boolean
IsVLANSupported(CFStringRef device)
{
char * buf = NULL;
size_t buf_len = 0;
struct if_msghdr * ifm;
char * if_name = NULL;
unsigned int if_index;
Boolean isVlan = FALSE;
int mib[6];
if_name = _SC_cfstring_to_cstring(device, NULL, 0, kCFStringEncodingASCII);
if (if_name == NULL) {
return FALSE; }
if_index = if_nametoindex(if_name);
if (if_index == 0) {
goto done; }
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_LINK;
mib[4] = NET_RT_IFLIST;
mib[5] = if_index;
if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) < 0) {
SCLog(TRUE, LOG_ERR, CFSTR("sysctl() size failed: %s"), strerror(errno));
goto done;
}
buf = CFAllocatorAllocate(NULL, buf_len, 0);
if (sysctl(mib, 6, buf, &buf_len, NULL, 0) < 0) {
SCLog(TRUE, LOG_ERR, CFSTR("sysctl() failed: %s"), strerror(errno));
goto done;
}
ifm = (struct if_msghdr *)buf;
switch (ifm->ifm_type) {
case RTM_IFINFO : {
#if defined(IF_HWASSIST_VLAN_TAGGING) && defined(IF_HWASSIST_VLAN_MTU)
struct if_data *if_data = &ifm->ifm_data;
if (if_data->ifi_hwassist & (IF_HWASSIST_VLAN_TAGGING | IF_HWASSIST_VLAN_MTU)) {
isVlan = TRUE;
}
#endif
break;
}
}
done :
if (if_name != NULL) CFAllocatorDeallocate(NULL, if_name);
if (buf != NULL) CFAllocatorDeallocate(NULL, buf);
return isVlan;
}
typedef struct {
CFRuntimeBase cfBase;
CFStringRef ifname; CFStringRef device; CFNumberRef tag; CFDictionaryRef options;
} VLANInterfacePrivate, * VLANInterfacePrivateRef;
static CFStringRef __VLANInterfaceCopyDescription (CFTypeRef cf);
static void __VLANInterfaceDeallocate (CFTypeRef cf);
static Boolean __VLANInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2);
static const CFRuntimeClass __VLANInterfaceClass = {
0, "VLANInterface", NULL, NULL, __VLANInterfaceDeallocate, __VLANInterfaceEqual, NULL, NULL, __VLANInterfaceCopyDescription };
static CFTypeID __kVLANInterfaceTypeID = _kCFRuntimeNotATypeID;
static pthread_once_t vlanInterface_init = PTHREAD_ONCE_INIT;
static CFStringRef
__VLANInterfaceCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)cf;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<VLANInterface %p [%p]> {"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR(" if = %@"), vlanPrivate->ifname);
CFStringAppendFormat(result, NULL, CFSTR(", device = %@"), vlanPrivate->device);
CFStringAppendFormat(result, NULL, CFSTR(", tag = %@"), vlanPrivate->tag);
if (vlanPrivate->options != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", options = %@"), vlanPrivate->options);
}
CFStringAppendFormat(result, NULL, CFSTR(" }"));
return result;
}
static void
__VLANInterfaceDeallocate(CFTypeRef cf)
{
VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)cf;
CFRelease(vlanPrivate->ifname);
CFRelease(vlanPrivate->device);
CFRelease(vlanPrivate->tag);
if (vlanPrivate->options) CFRelease(vlanPrivate->options);
return;
}
static Boolean
__VLANInterfaceEquiv(CFTypeRef cf1, CFTypeRef cf2)
{
VLANInterfacePrivateRef vlan1 = (VLANInterfacePrivateRef)cf1;
VLANInterfacePrivateRef vlan2 = (VLANInterfacePrivateRef)cf2;
if (vlan1 == vlan2)
return TRUE;
if (!CFEqual(vlan1->ifname, vlan2->ifname))
return FALSE;
if (!CFEqual(vlan1->device, vlan2->device))
return FALSE;
if (!CFEqual(vlan1->tag, vlan2->tag))
return FALSE;
return TRUE;
}
static Boolean
__VLANInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2)
{
VLANInterfacePrivateRef vlan1 = (VLANInterfacePrivateRef)cf1;
VLANInterfacePrivateRef vlan2 = (VLANInterfacePrivateRef)cf2;
if (!__VLANInterfaceEquiv(vlan1, vlan2))
return FALSE;
if (vlan1->options != vlan2->options) {
if ((vlan1->options != NULL) && (vlan2->options != NULL)) {
if (!CFEqual(vlan1->options, vlan2->options)) {
return FALSE;
}
} else {
return FALSE;
}
}
return TRUE;
}
static void
__VLANInterfaceInitialize(void)
{
__kVLANInterfaceTypeID = _CFRuntimeRegisterClass(&__VLANInterfaceClass);
return;
}
static __inline__ CFTypeRef
isA_VLANInterface(CFTypeRef obj)
{
return (isA_CFType(obj, VLANInterfaceGetTypeID()));
}
CFTypeID
VLANInterfaceGetTypeID(void)
{
pthread_once(&vlanInterface_init, __VLANInterfaceInitialize);
return __kVLANInterfaceTypeID;
}
static VLANInterfaceRef
__VLANInterfaceCreatePrivate(CFAllocatorRef allocator,
CFStringRef ifname,
CFStringRef device,
CFNumberRef tag,
CFDictionaryRef options)
{
VLANInterfacePrivateRef vlanPrivate;
uint32_t size;
pthread_once(&vlanInterface_init, __VLANInterfaceInitialize);
size = sizeof(VLANInterfacePrivate) - sizeof(CFRuntimeBase);
vlanPrivate = (VLANInterfacePrivateRef)_CFRuntimeCreateInstance(allocator,
__kVLANInterfaceTypeID,
size,
NULL);
if (!vlanPrivate) {
return NULL;
}
vlanPrivate->ifname = CFStringCreateCopy(allocator, ifname);
vlanPrivate->device = CFStringCreateCopy(allocator, device);
vlanPrivate->tag = CFRetain(tag);
if (options != NULL) {
vlanPrivate->options = CFDictionaryCreateCopy(allocator, options);
} else {
vlanPrivate->options = NULL;
}
return (VLANInterfaceRef)vlanPrivate;
}
CFStringRef
VLANInterfaceGetInterface(VLANInterfaceRef vlan)
{
VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
CFStringRef vlan_if = NULL;
if (isA_VLANInterface(vlan)) {
vlan_if = vlanPrivate->ifname;
}
return vlan_if;
}
CFStringRef
VLANInterfaceGetDevice(VLANInterfaceRef vlan)
{
VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
CFStringRef vlan_device = NULL;
if (isA_VLANInterface(vlan)) {
vlan_device = vlanPrivate->device;
}
return vlan_device;
}
static void
VLANInterfaceSetDevice(VLANInterfaceRef vlan, CFStringRef newDevice)
{
VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
if (isA_VLANInterface(vlan)) {
CFAllocatorRef allocator = CFGetAllocator(vlan);
CFRelease(vlanPrivate->device);
vlanPrivate->device = CFStringCreateCopy(allocator, newDevice);
}
return;
}
CFNumberRef
VLANInterfaceGetTag(VLANInterfaceRef vlan)
{
VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
CFNumberRef vlan_tag = NULL;
if (isA_VLANInterface(vlan)) {
vlan_tag = vlanPrivate->tag;
}
return vlan_tag;
}
static void
VLANInterfaceSetTag(VLANInterfaceRef vlan, CFNumberRef newTag)
{
VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
if (isA_VLANInterface(vlan)) {
CFRelease(vlanPrivate->tag);
vlanPrivate->tag = CFRetain(newTag);
}
return;
}
CFDictionaryRef
VLANInterfaceGetOptions(VLANInterfaceRef vlan)
{
VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
CFDictionaryRef vlan_options = NULL;
if (isA_VLANInterface(vlan)) {
vlan_options = vlanPrivate->options;
}
return vlan_options;
}
static void
VLANInterfaceSetOptions(VLANInterfaceRef vlan, CFDictionaryRef newOptions)
{
VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
if (isA_VLANInterface(vlan)) {
CFAllocatorRef allocator = CFGetAllocator(vlan);
if (vlanPrivate->options) CFRelease(vlanPrivate->options);
if (newOptions != NULL) {
vlanPrivate->options = CFDictionaryCreateCopy(allocator, newOptions);
} else {
vlanPrivate->options = NULL;
}
}
return;
}
#define VLAN_PREFERENCES_VLANS CFSTR("VLANs")
#define __kVLANInterface_interface CFSTR("interface") // e.g. vlan0, vlan1, ...
#define __kVLANInterface_device CFSTR("device") // e.g. en0, en1, ...
#define __kVLANInterface_tag CFSTR("tag") // e.g. 1 <= tag <= 4094
#define __kVLANInterface_options CFSTR("options") // e.g. UserDefinedName
typedef struct {
CFRuntimeBase cfBase;
pthread_mutex_t lock;
SCPreferencesRef prefs;
CFArrayRef vlBase;
} VLANPreferencesPrivate, * VLANPreferencesPrivateRef;
static CFStringRef __VLANPreferencesCopyDescription (CFTypeRef cf);
static void __VLANPreferencesDeallocate (CFTypeRef cf);
static const CFRuntimeClass __VLANPreferencesClass = {
0, "VLANPreferences", NULL, NULL, __VLANPreferencesDeallocate, NULL, NULL, NULL, __VLANPreferencesCopyDescription };
static CFTypeID __kVLANPreferencesTypeID = _kCFRuntimeNotATypeID;
static pthread_once_t vlanPreferences_init = PTHREAD_ONCE_INIT;
static CFStringRef
__VLANPreferencesCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFIndex i;
CFArrayRef keys;
CFIndex n;
VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)cf;
CFMutableStringRef result;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<VLANPreferences %p [%p]> {"), cf, allocator);
keys = SCPreferencesCopyKeyList(prefsPrivate->prefs);
n = CFArrayGetCount(keys);
for (i = 0; i < n; i++) {
CFStringRef key;
CFPropertyListRef val;
key = CFArrayGetValueAtIndex(keys, i);
val = SCPreferencesGetValue(prefsPrivate->prefs, key);
CFStringAppendFormat(result, NULL, CFSTR("%@ : %@"), key, val);
}
CFRelease(keys);
CFStringAppendFormat(result, NULL, CFSTR(" }"));
return result;
}
#define N_QUICK 8
static void
__VLANPreferencesDeallocate(CFTypeRef cf)
{
VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)cf;
pthread_mutex_destroy(&prefsPrivate->lock);
if (prefsPrivate->prefs) CFRelease(prefsPrivate->prefs);
if (prefsPrivate->vlBase) CFRelease(prefsPrivate->vlBase);
return;
}
static void
__VLANPreferencesInitialize(void)
{
__kVLANPreferencesTypeID = _CFRuntimeRegisterClass(&__VLANPreferencesClass);
return;
}
static __inline__ CFTypeRef
isA_VLANPreferences(CFTypeRef obj)
{
return (isA_CFType(obj, VLANPreferencesGetTypeID()));
}
CFArrayRef
_VLANPreferencesCopyActiveInterfaces()
{
CFArrayCallBacks callbacks;
struct ifaddrs *ifap;
struct ifaddrs *ifp;
int s;
CFMutableArrayRef vlans = NULL;
if (getifaddrs(&ifap) == -1) {
SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
_SCErrorSet(kSCStatusFailed);
return NULL;
}
s = inet_dgram_socket();
if (s == -1) {
SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
_SCErrorSet(kSCStatusFailed);
goto done;
}
callbacks = kCFTypeArrayCallBacks;
callbacks.equal = __VLANInterfaceEquiv;
vlans = CFArrayCreateMutable(NULL, 0, &callbacks);
for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
switch (ifp->ifa_addr->sa_family) {
case AF_LINK : {
CFStringRef device;
struct if_data *if_data;
struct ifreq ifr;
CFNumberRef tag;
VLANInterfaceRef vlan;
CFStringRef vlan_if;
char vlr_parent[IFNAMSIZ+1];
int vlr_tag;
struct vlanreq vreq;
if_data = (struct if_data *)ifp->ifa_data;
if (if_data == NULL) {
break; }
if (if_data->ifi_type != IFT_L2VLAN) {
break; }
bzero(&ifr, sizeof(ifr));
bzero(&vreq, sizeof(vreq));
strncpy(ifr.ifr_name, ifp->ifa_name, sizeof(ifr.ifr_name));
ifr.ifr_data = (caddr_t)&vreq;
if (ioctl(s, SIOCGIFVLAN, (caddr_t)&ifr) == -1) {
SCLog(TRUE, LOG_ERR, CFSTR("ioctl() failed: %s"), strerror(errno));
_SCErrorSet(kSCStatusFailed);
CFRelease(vlans);
goto done;
}
vlr_tag = vreq.vlr_tag;
strlcpy(vlr_parent, vreq.vlr_parent, sizeof(vlr_parent));
vlan_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
device = CFStringCreateWithCString(NULL, vlr_parent, kCFStringEncodingASCII);
tag = CFNumberCreate(NULL, kCFNumberIntType, &vlr_tag);
vlan = __VLANInterfaceCreatePrivate(NULL, vlan_if, device, tag, NULL);
CFArrayAppendValue(vlans, vlan);
CFRelease(vlan_if);
CFRelease(device);
CFRelease(tag);
CFRelease(vlan);
break;
}
default :
break;
}
}
done :
(void) close(s);
freeifaddrs(ifap);
return vlans;
}
static CFIndex
findVLAN(CFArrayRef vlans, CFStringRef device, CFNumberRef tag)
{
CFIndex found = kCFNotFound;
CFIndex i;
CFIndex n;
n = isA_CFArray(vlans) ? CFArrayGetCount(vlans) : 0;
for (i = 0; i < n; i++) {
CFDictionaryRef vlan_dict;
CFStringRef vlan_device;
CFStringRef vlan_if;
CFNumberRef vlan_tag;
vlan_dict = CFArrayGetValueAtIndex(vlans, i);
if (!isA_CFDictionary(vlan_dict)) {
continue; }
vlan_if = CFDictionaryGetValue(vlan_dict, __kVLANInterface_interface);
if (!isA_CFString(vlan_if)) {
continue; }
vlan_device = CFDictionaryGetValue(vlan_dict, __kVLANInterface_device);
if (isA_CFString(vlan_device)) {
if (!CFEqual(device, vlan_device)) {
continue; }
}
vlan_tag = CFDictionaryGetValue(vlan_dict, __kVLANInterface_tag);
if (isA_CFNumber(vlan_tag)) {
if (!CFEqual(tag, vlan_tag)) {
continue; }
}
found = i;
break;
}
return found;
}
static void
setConfigurationChanged(VLANPreferencesRef prefs)
{
VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
if (prefsPrivate->vlBase == NULL) {
prefsPrivate->vlBase = VLANPreferencesCopyInterfaces(prefs);
}
return;
}
CFTypeID
VLANPreferencesGetTypeID(void)
{
pthread_once(&vlanPreferences_init, __VLANPreferencesInitialize);
return __kVLANPreferencesTypeID;
}
VLANPreferencesRef
VLANPreferencesCreate(CFAllocatorRef allocator)
{
CFBundleRef bundle;
CFStringRef bundleID = NULL;
CFStringRef name = CFSTR("VLANConfiguration");
VLANPreferencesPrivateRef prefsPrivate;
uint32_t size;
pthread_once(&vlanPreferences_init, __VLANPreferencesInitialize);
size = sizeof(VLANPreferencesPrivate) - sizeof(CFRuntimeBase);
prefsPrivate = (VLANPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
__kVLANPreferencesTypeID,
size,
NULL);
if (prefsPrivate == NULL) {
return NULL;
}
pthread_mutex_init(&prefsPrivate->lock, NULL);
bundle = CFBundleGetMainBundle();
if (bundle) {
bundleID = CFBundleGetIdentifier(bundle);
if (bundleID) {
CFRetain(bundleID);
} else {
CFURLRef url;
url = CFBundleCopyExecutableURL(bundle);
if (url) {
bundleID = CFURLCopyPath(url);
CFRelease(url);
}
}
}
if (bundleID) {
CFStringRef fullName;
if (CFEqual(bundleID, CFSTR("/"))) {
CFRelease(bundleID);
bundleID = CFStringCreateWithFormat(allocator, NULL, CFSTR("(%d)"), getpid());
}
fullName = CFStringCreateWithFormat(allocator, NULL, CFSTR("%@:%@"), bundleID, name);
name = fullName;
CFRelease(bundleID);
} else {
CFRetain(name);
}
prefsPrivate->prefs = SCPreferencesCreate(allocator, name, VLAN_PREFERENCES_ID);
CFRelease(name);
prefsPrivate->vlBase = NULL;
return (VLANPreferencesRef)prefsPrivate;
}
CFArrayRef
VLANPreferencesCopyInterfaces(VLANPreferencesRef prefs)
{
CFAllocatorRef allocator;
CFArrayCallBacks callbacks;
CFIndex i;
CFIndex n;
VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
CFMutableArrayRef result;
CFArrayRef vlans;
if (!isA_VLANPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
allocator = CFGetAllocator(prefs);
callbacks = kCFTypeArrayCallBacks;
callbacks.equal = __VLANInterfaceEquiv;
result = CFArrayCreateMutable(allocator, 0, &callbacks);
vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
n = isA_CFArray(vlans) ? CFArrayGetCount(vlans) : 0;
for (i = 0; i < n; i++) {
CFDictionaryRef vlan_dict;
CFStringRef device;
CFDictionaryRef options;
CFNumberRef tag;
VLANInterfaceRef vlan;
CFStringRef vlan_if;
vlan_dict = CFArrayGetValueAtIndex(vlans, i);
if (!isA_CFDictionary(vlan_dict)) {
continue; }
vlan_if = CFDictionaryGetValue(vlan_dict, __kVLANInterface_interface);
if (!isA_CFString(vlan_if)) {
continue; }
device = CFDictionaryGetValue(vlan_dict, __kVLANInterface_device);
if (!isA_CFString(device)) {
continue; }
tag = CFDictionaryGetValue(vlan_dict, __kVLANInterface_tag);
if (!isA_CFNumber(tag)) {
continue; }
options = CFDictionaryGetValue(vlan_dict, __kVLANInterface_options);
if ((options != NULL) && !isA_CFDictionary(options)) {
continue; }
vlan = __VLANInterfaceCreatePrivate(allocator, vlan_if, device, tag, options);
CFArrayAppendValue(result, vlan);
CFRelease(vlan);
}
return result;
}
VLANInterfaceRef
VLANPreferencesAddInterface(VLANPreferencesRef prefs,
CFStringRef device,
CFNumberRef tag,
CFDictionaryRef options)
{
CFArrayRef active_vlans;
CFAllocatorRef allocator;
CFArrayRef config_vlans;
CFIndex dup_if;
CFIndex i;
CFIndex nActive;
CFIndex nConfig;
VLANInterfaceRef newVlan = NULL;
VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
if (!isA_VLANPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (!isA_CFString(device)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (isA_CFNumber(tag)) {
int tag_val;
CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
if ((tag_val < 1) || (tag_val > 4094)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
} else {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if ((options != NULL) && !isA_CFDictionary(options)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
pthread_mutex_lock(&prefsPrivate->lock);
config_vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
nConfig = isA_CFArray(config_vlans) ? CFArrayGetCount(config_vlans) : 0;
dup_if = findVLAN(config_vlans, device, tag);
if (dup_if != kCFNotFound) {
_SCErrorSet(kSCStatusKeyExists);
goto done;
}
active_vlans = _VLANPreferencesCopyActiveInterfaces();
nActive = isA_CFArray(active_vlans) ? CFArrayGetCount(active_vlans) : 0;
allocator = CFGetAllocator(prefs);
for (i = 0; newVlan == NULL; i++) {
CFIndex j;
CFMutableDictionaryRef newDict;
CFMutableArrayRef newVlans;
CFStringRef vlan_if;
vlan_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("vlan%d"), i);
for (j = 0; j < nActive; j++) {
CFStringRef active_if;
VLANInterfaceRef active_vlan;
active_vlan = CFArrayGetValueAtIndex(active_vlans, j);
active_if = VLANInterfaceGetInterface(active_vlan);
if (CFEqual(vlan_if, active_if)) {
goto next_if; }
}
for (j = 0; j < nConfig; j++) {
CFDictionaryRef config;
CFStringRef config_if;
config = CFArrayGetValueAtIndex(config_vlans, j);
if (!isA_CFDictionary(config)) {
continue; }
config_if = CFDictionaryGetValue(config, __kVLANInterface_interface);
if (!isA_CFString(config_if)) {
continue; }
if (CFEqual(vlan_if, config_if)) {
goto next_if; }
}
newDict = CFDictionaryCreateMutable(allocator,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(newDict, __kVLANInterface_interface, vlan_if);
CFDictionaryAddValue(newDict, __kVLANInterface_device, device);
CFDictionaryAddValue(newDict, __kVLANInterface_tag, tag);
if (options != NULL) {
CFDictionaryAddValue(newDict, __kVLANInterface_options, options);
}
newVlan = __VLANInterfaceCreatePrivate(allocator, vlan_if, device, tag, options);
setConfigurationChanged(prefs);
if (nConfig == 0) {
newVlans = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
} else {
newVlans = CFArrayCreateMutableCopy(allocator, 0, config_vlans);
}
CFArrayAppendValue(newVlans, newDict);
CFRelease(newDict);
(void) SCPreferencesSetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS, newVlans);
CFRelease(newVlans);
next_if :
CFRelease(vlan_if);
}
CFRelease(active_vlans);
done :
pthread_mutex_unlock(&prefsPrivate->lock);
return (VLANInterfaceRef) newVlan;
}
Boolean
VLANPreferencesUpdateInterface(VLANPreferencesRef prefs,
VLANInterfaceRef vlan,
CFStringRef newDevice,
CFNumberRef newTag,
CFDictionaryRef newOptions)
{
CFAllocatorRef allocator;
CFIndex cur_if;
CFIndex dup_if;
CFMutableDictionaryRef newDict;
CFMutableArrayRef newVlans;
Boolean ok = FALSE;
VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
CFArrayRef vlans;
CFStringRef vlan_if;
if (!isA_VLANPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_VLANInterface(vlan)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if ((newDevice != NULL) && !isA_CFString(newDevice)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (newTag != NULL) {
if (isA_CFNumber(newTag)) {
int tag_val;
CFNumberGetValue(newTag, kCFNumberIntType, &tag_val);
if ((tag_val < 1) || (tag_val > 4094)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
} else {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
}
if ((newOptions != NULL)
&& !isA_CFDictionary(newOptions) && (newOptions != (CFDictionaryRef)kCFNull)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
pthread_mutex_lock(&prefsPrivate->lock);
vlan_if = VLANInterfaceGetInterface(vlan);
vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
if (!isA_CFArray(vlans)) {
goto done; }
cur_if = findVLAN(vlans,
VLANInterfaceGetDevice(vlan),
VLANInterfaceGetTag (vlan));
if (cur_if == kCFNotFound) {
_SCErrorSet(kSCStatusNoKey);
goto done;
}
dup_if = findVLAN(vlans,
newDevice != NULL ? newDevice : VLANInterfaceGetDevice(vlan),
newTag != NULL ? newTag : VLANInterfaceGetTag (vlan));
if (dup_if != kCFNotFound) {
if (cur_if != dup_if) {
_SCErrorSet(kSCStatusKeyExists);
goto done;
}
}
if (newDevice != NULL) {
VLANInterfaceSetDevice(vlan, newDevice);
} else {
newDevice = VLANInterfaceGetDevice(vlan);
}
if (newTag != NULL) {
VLANInterfaceSetTag(vlan, newTag);
} else {
newTag = VLANInterfaceGetTag(vlan);
}
if (newOptions != NULL) {
if (newOptions != (CFDictionaryRef)kCFNull) {
VLANInterfaceSetOptions(vlan, newOptions);
} else {
VLANInterfaceSetOptions(vlan, NULL);
newOptions = NULL;
}
} else {
newOptions = VLANInterfaceGetOptions(vlan);
}
allocator = CFGetAllocator(prefs);
newDict = CFDictionaryCreateMutable(allocator,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(newDict, __kVLANInterface_interface, vlan_if);
CFDictionaryAddValue(newDict, __kVLANInterface_device, newDevice);
CFDictionaryAddValue(newDict, __kVLANInterface_tag, newTag);
if (newOptions != NULL) {
CFDictionaryAddValue(newDict, __kVLANInterface_options, newOptions);
}
setConfigurationChanged(prefs);
newVlans = CFArrayCreateMutableCopy(allocator, 0, vlans);
CFArraySetValueAtIndex(newVlans, cur_if, newDict);
CFRelease(newDict);
(void) SCPreferencesSetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS, newVlans);
CFRelease(newVlans);
ok = TRUE;
done :
pthread_mutex_unlock(&prefsPrivate->lock);
return ok;
}
Boolean
VLANPreferencesRemoveInterface(VLANPreferencesRef prefs,
VLANInterfaceRef vlan)
{
CFAllocatorRef allocator;
CFIndex cur_if;
CFMutableArrayRef newVlans;
Boolean ok = FALSE;
VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
CFArrayRef vlans;
if (!isA_VLANPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_VLANInterface(vlan)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
pthread_mutex_lock(&prefsPrivate->lock);
vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
if (!isA_CFArray(vlans)) {
_SCErrorSet(kSCStatusNoKey);
goto done; }
cur_if = findVLAN(vlans,
VLANInterfaceGetDevice(vlan),
VLANInterfaceGetTag (vlan));
if (cur_if == kCFNotFound) {
_SCErrorSet(kSCStatusNoKey);
goto done;
}
setConfigurationChanged(prefs);
allocator = CFGetAllocator(prefs);
newVlans = CFArrayCreateMutableCopy(allocator, 0, vlans);
CFArrayRemoveValueAtIndex(newVlans, cur_if);
(void) SCPreferencesSetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS, newVlans);
CFRelease(newVlans);
ok = TRUE;
done :
pthread_mutex_unlock(&prefsPrivate->lock);
return ok;
}
Boolean
VLANPreferencesCommitChanges(VLANPreferencesRef prefs)
{
Boolean ok = FALSE;
VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
if (!isA_VLANPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
ok = SCPreferencesCommitChanges(prefsPrivate->prefs);
if (!ok) {
return ok;
}
if (prefsPrivate->vlBase != NULL) {
CFRelease(prefsPrivate->vlBase);
prefsPrivate->vlBase = NULL;
}
return TRUE;
}
Boolean
_VLANPreferencesUpdateConfiguration(VLANPreferencesRef prefs)
{
CFArrayRef active = NULL;
CFArrayRef config = NULL;
CFMutableDictionaryRef devices = NULL;
CFIndex i;
CFIndex nActive;
CFIndex nConfig;
Boolean ok = FALSE;
VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
int s = -1;
if (!isA_VLANPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (prefsPrivate->vlBase != NULL) {
config = CFRetain(prefsPrivate->vlBase);
} else {
config = VLANPreferencesCopyInterfaces(prefs);
}
nConfig = CFArrayGetCount(config);
devices = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
active = _VLANPreferencesCopyActiveInterfaces();
nActive = CFArrayGetCount(active);
for (i = 0; i < nActive; i++) {
VLANInterfaceRef a_vlan;
CFStringRef a_vlan_if;
CFIndex j;
Boolean found = FALSE;
a_vlan = CFArrayGetValueAtIndex(active, i);
a_vlan_if = VLANInterfaceGetInterface(a_vlan);
for (j = 0; j < nConfig; j++) {
VLANInterfaceRef c_vlan;
CFStringRef c_vlan_if;
c_vlan = CFArrayGetValueAtIndex(config, j);
c_vlan_if = VLANInterfaceGetInterface(c_vlan);
if (CFEqual(a_vlan_if, c_vlan_if)) {
found = TRUE;
break;
}
}
if (!found) {
if (s == -1) {
s = inet_dgram_socket();
}
ok = __destroyInterface(s, a_vlan_if);
if (!ok) {
_SCErrorSet(kSCStatusFailed);
goto done;
}
}
}
for (i = 0; i < nConfig; i++) {
VLANInterfaceRef c_vlan;
CFStringRef c_vlan_device;
CFStringRef c_vlan_if;
Boolean found = FALSE;
CFIndex j;
CFBooleanRef supported;
c_vlan = CFArrayGetValueAtIndex(config, i);
c_vlan_device = VLANInterfaceGetDevice(c_vlan);
c_vlan_if = VLANInterfaceGetInterface(c_vlan);
supported = CFDictionaryGetValue(devices, c_vlan_device);
if (supported == NULL) {
supported = IsVLANSupported(c_vlan_device) ? kCFBooleanTrue
: kCFBooleanFalse;
CFDictionaryAddValue(devices, c_vlan_device, supported);
}
for (j = 0; j < nActive; j++) {
VLANInterfaceRef a_vlan;
CFStringRef a_vlan_if;
a_vlan = CFArrayGetValueAtIndex(active, j);
a_vlan_if = VLANInterfaceGetInterface(a_vlan);
if (CFEqual(c_vlan_if, a_vlan_if)) {
if (!__VLANInterfaceEquiv(c_vlan, a_vlan)) {
if (s == -1) {
s = inet_dgram_socket();
}
if (CFBooleanGetValue(supported)) {
ok = _VLANDevice_unset(s, c_vlan_if);
if (!ok) {
goto done;
}
ok = _VLANDevice_set(s,
c_vlan_if,
c_vlan_device,
VLANInterfaceGetTag(c_vlan));
if (!ok) {
goto done;
}
} else {
ok = __destroyInterface(s, c_vlan_if);
if (!ok) {
_SCErrorSet(kSCStatusFailed);
goto done;
}
}
}
found = TRUE;
break;
}
}
if (!found && CFBooleanGetValue(supported)) {
if (s == -1) {
s = inet_dgram_socket();
}
ok = __createInterface(s, c_vlan_if);
if (!ok) {
_SCErrorSet(kSCStatusFailed);
goto done;
}
ok = _VLANDevice_set(s,
c_vlan_if,
c_vlan_device,
VLANInterfaceGetTag(c_vlan));
if (!ok) {
goto done;
}
}
}
ok = TRUE;
done :
if (active) CFRelease(active);
if (config) CFRelease(config);
if (devices) CFRelease(devices);
if (s != -1) (void) close(s);
return ok;
}
Boolean
VLANPreferencesApplyChanges(VLANPreferencesRef prefs)
{
Boolean ok = FALSE;
VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
if (!isA_VLANPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
pthread_mutex_lock(&prefsPrivate->lock);
ok = SCPreferencesApplyChanges(prefsPrivate->prefs);
if (!ok) {
goto done;
}
ok = _VLANPreferencesUpdateConfiguration(prefs);
if (!ok) {
goto done;
}
done :
pthread_mutex_unlock(&prefsPrivate->lock);
return ok;
}