VLANConfiguration.c [plain text]
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFRuntime.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include "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 <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 <SystemConfiguration/VLANConfiguration.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));
}
return s;
}
typedef struct {
CFMutableArrayRef vlans;
SCPreferencesRef prefs;
} addContext, *addContextRef;
static void
add_configured_interface(const void *key, const void *value, void *context)
{
SCNetworkInterfacePrivateRef interfacePrivate;
addContextRef myContext = (addContextRef)context;
SCVLANInterfaceRef vlan;
CFStringRef vlan_if = (CFStringRef)key;
CFDictionaryRef vlan_info = (CFDictionaryRef)value;
CFStringRef vlan_name;
CFDictionaryRef vlan_options;
SCNetworkInterfaceRef vlan_physical;
CFStringRef vlan_physical_if;
CFNumberRef vlan_tag;
vlan_physical_if = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANInterface);
if (!isA_CFString(vlan_physical_if)) {
return;
}
vlan_tag = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANTag);
if (!isA_CFNumber(vlan_tag)) {
return;
}
vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
kIncludeBondInterfaces);
SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
CFRelease(vlan_physical);
vlan_name = CFDictionaryGetValue(vlan_info, kSCPropUserDefinedName);
if (isA_CFString(vlan_name)) {
SCVLANInterfaceSetLocalizedDisplayName(vlan, vlan_name);
}
vlan_options = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANOptions);
if (isA_CFDictionary(vlan_options)) {
SCVLANInterfaceSetOptions(vlan, vlan_options);
}
interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
interfacePrivate->prefs = CFRetain(myContext->prefs);
CFArrayAppendValue(myContext->vlans, vlan);
CFRelease(vlan);
return;
}
static void
add_legacy_configuration(addContextRef myContext)
{
CFIndex i;
CFIndex n;
SCPreferencesRef prefs;
CFArrayRef vlans;
#define VLAN_PREFERENCES_ID CFSTR("VirtualNetworkInterfaces.plist")
#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
prefs = SCPreferencesCreate(NULL, CFSTR("SCVLANInterfaceCopyAll"), VLAN_PREFERENCES_ID);
if (prefs == NULL) {
return;
}
vlans = SCPreferencesGetValue(prefs, VLAN_PREFERENCES_VLANS);
if ((vlans != NULL) && !isA_CFArray(vlans)) {
CFRelease(prefs); return;
}
n = (vlans != NULL) ? CFArrayGetCount(vlans) : 0;
for (i = 0; i < n; i++) {
CFDictionaryRef dict;
SCNetworkInterfacePrivateRef interfacePrivate;
Boolean ok;
CFDictionaryRef options;
CFStringRef path;
SCVLANInterfaceRef vlan;
CFStringRef vlan_if;
CFDictionaryRef vlan_dict;
SCNetworkInterfaceRef vlan_physical;
CFStringRef vlan_physical_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_physical_if = CFDictionaryGetValue(vlan_dict, __kVLANInterface_device);
if (!isA_CFString(vlan_physical_if)) {
continue; }
vlan_tag = CFDictionaryGetValue(vlan_dict, __kVLANInterface_tag);
if (!isA_CFNumber(vlan_tag)) {
continue; }
path = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("/%@/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeVLAN,
vlan_if);
dict = SCPreferencesPathGetValue(myContext->prefs, path);
if (dict != NULL) {
CFRelease(path);
continue;
}
dict = CFDictionaryCreate(NULL,
NULL, NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
ok = SCPreferencesPathSetValue(myContext->prefs, path, dict);
CFRelease(dict);
CFRelease(path);
if (!ok) {
continue;
}
vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
interfacePrivate->prefs = CFRetain(myContext->prefs);
vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
kIncludeBondInterfaces);
SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
CFRelease(vlan_physical);
options = CFDictionaryGetValue(vlan_dict, __kVLANInterface_options);
if (isA_CFDictionary(options)) {
CFStringRef vlan_name;
vlan_name = CFDictionaryGetValue(options, CFSTR("VLAN Name"));
if (isA_CFString(vlan_name)) {
SCVLANInterfaceSetLocalizedDisplayName(vlan, vlan_name);
}
}
CFArrayAppendValue(myContext->vlans, vlan);
CFRelease(vlan);
}
CFRelease(prefs);
return;
}
static SCVLANInterfaceRef
findVLANInterfaceAndTag(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag)
{
CFIndex i;
CFIndex n;
SCVLANInterfaceRef vlan = NULL;
CFArrayRef vlans;
vlans = SCVLANInterfaceCopyAll(prefs);
n = CFArrayGetCount(vlans);
for (i = 0; i < n; i++) {
SCVLANInterfaceRef config_vlan;
SCNetworkInterfaceRef config_physical;
CFNumberRef config_tag;
config_vlan = CFArrayGetValueAtIndex(vlans, i);
config_physical = SCVLANInterfaceGetPhysicalInterface(config_vlan);
config_tag = SCVLANInterfaceGetTag(config_vlan);
if ((config_physical != NULL) && (config_tag != NULL)) {
if (!CFEqual(physical, config_physical)) {
continue;
}
if (!CFEqual(tag, config_tag)) {
continue;
}
vlan = CFRetain(config_vlan);
break;
}
}
CFRelease(vlans);
return vlan;
}
#pragma mark -
#pragma mark SCVLANInterface APIs
CFArrayRef
SCVLANInterfaceCopyAll(SCPreferencesRef prefs)
{
addContext context;
CFDictionaryRef dict;
CFStringRef path;
context.vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
context.prefs = prefs;
path = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeVLAN);
dict = SCPreferencesPathGetValue(prefs, path);
if (isA_CFDictionary(dict)) {
CFDictionaryApplyFunction(dict, add_configured_interface, &context);
} else {
dict = CFDictionaryCreate(NULL,
NULL, NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
(void) SCPreferencesPathSetValue(prefs, path, dict);
CFRelease(dict);
add_legacy_configuration(&context);
}
CFRelease(path);
return context.vlans;
}
static void
addAvailableInterfaces(CFMutableArrayRef available, CFArrayRef interfaces,
CFSetRef exclude)
{
CFIndex i;
CFIndex n;
n = CFArrayGetCount(interfaces);
for (i = 0; i < n; i++) {
SCNetworkInterfaceRef interface;
SCNetworkInterfacePrivateRef interfacePrivate;
interface = CFArrayGetValueAtIndex(interfaces, i);
interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
if (exclude != NULL
&& CFSetContainsValue(exclude, interface)) {
continue;
}
if (interfacePrivate->supportsVLAN) {
CFArrayAppendValue(available, interface);
}
}
return;
}
CFArrayRef
SCVLANInterfaceCopyAvailablePhysicalInterfaces()
{
CFMutableArrayRef available;
CFArrayRef bond_interfaces = NULL;
CFMutableSetRef exclude = NULL;
CFArrayRef interfaces;
SCPreferencesRef prefs;
available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
prefs = SCPreferencesCreate(NULL, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL);
if (prefs != NULL) {
bond_interfaces = SCBondInterfaceCopyAll(prefs);
CFRelease(prefs);
if (bond_interfaces != NULL) {
exclude = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
__SCBondInterfaceListCopyMembers(bond_interfaces, exclude);
}
}
interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface();
if (interfaces != NULL) {
addAvailableInterfaces(available, interfaces, exclude);
CFRelease(interfaces);
}
if (bond_interfaces != NULL) {
addAvailableInterfaces(available, bond_interfaces, NULL);
CFRelease(bond_interfaces);
}
if (exclude != NULL) {
CFRelease(exclude);
}
return available;
}
CFArrayRef
_SCVLANInterfaceCopyActive(void)
{
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) {
_SCErrorSet(errno);
goto done;
}
vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
struct if_data *if_data;
struct ifreq ifr;
SCVLANInterfaceRef vlan;
CFStringRef vlan_if;
SCNetworkInterfaceRef vlan_physical;
CFStringRef vlan_physical_if;
CFNumberRef vlan_tag;
char vlr_parent[IFNAMSIZ + 1];
int vlr_tag;
struct vlanreq vreq;
if_data = (struct if_data *)ifp->ifa_data;
if (if_data == NULL
|| ifp->ifa_addr->sa_family != AF_LINK
|| if_data->ifi_type != IFT_L2VLAN) {
continue;
}
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));
CFRelease(vlans);
vlans = NULL;
_SCErrorSet(kSCStatusFailed);
goto done;
}
vlan_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
CFRelease(vlan_if);
bzero(&vlr_parent, sizeof(vlr_parent));
bcopy(vreq.vlr_parent, vlr_parent, IFNAMSIZ);
vlan_physical_if = CFStringCreateWithCString(NULL, vlr_parent, kCFStringEncodingASCII);
vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
kIncludeBondInterfaces);
CFRelease(vlan_physical_if);
vlr_tag = vreq.vlr_tag;
vlan_tag = CFNumberCreate(NULL, kCFNumberIntType, &vlr_tag);
SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
CFRelease(vlan_physical);
CFRelease(vlan_tag);
CFArrayAppendValue(vlans, vlan);
CFRelease(vlan);
}
done :
(void) close(s);
freeifaddrs(ifap);
return vlans;
}
SCVLANInterfaceRef
SCVLANInterfaceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag)
{
CFAllocatorRef allocator;
CFIndex i;
SCNetworkInterfacePrivateRef interfacePrivate;
SCVLANInterfaceRef vlan;
if (prefs == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (!isA_SCNetworkInterface(physical)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
interfacePrivate = (SCNetworkInterfacePrivateRef)physical;
if (!interfacePrivate->supportsVLAN) {
_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;
}
vlan = findVLANInterfaceAndTag(prefs, physical, tag);
if (vlan != NULL) {
CFRelease(vlan);
_SCErrorSet(kSCStatusKeyExists);
return NULL;
}
allocator = CFGetAllocator(prefs);
for (i = 0; vlan == NULL; i++) {
CFDictionaryRef dict;
CFStringRef vlan_if;
Boolean ok;
CFStringRef path;
vlan_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("vlan%d"), i);
path = CFStringCreateWithFormat(allocator,
NULL,
CFSTR("/%@/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeVLAN,
vlan_if);
dict = SCPreferencesPathGetValue(prefs, path);
if (dict != NULL) {
CFRelease(path);
CFRelease(vlan_if);
continue;
}
dict = CFDictionaryCreate(allocator,
NULL, NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
ok = SCPreferencesPathSetValue(prefs, path, dict);
CFRelease(dict);
CFRelease(path);
if (!ok) {
CFRelease(vlan_if);
_SCErrorSet(kSCStatusFailed);
break;
}
vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(allocator, vlan_if);
CFRelease(vlan_if);
interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
interfacePrivate->prefs = CFRetain(prefs);
SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, physical, tag);
}
return vlan;
}
Boolean
SCVLANInterfaceRemove(SCVLANInterfaceRef vlan)
{
CFStringRef vlan_if;
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
Boolean ok;
CFStringRef path;
if (!isA_SCVLANInterface(vlan)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (interfacePrivate->prefs == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
vlan_if = SCNetworkInterfaceGetBSDName(vlan);
path = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("/%@/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeVLAN,
vlan_if);
ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path);
CFRelease(path);
return ok;
}
SCNetworkInterfaceRef
SCVLANInterfaceGetPhysicalInterface(SCVLANInterfaceRef vlan)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
if (!isA_SCVLANInterface(vlan)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
return interfacePrivate->vlan.interface;
}
CFNumberRef
SCVLANInterfaceGetTag(SCVLANInterfaceRef vlan)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
if (!isA_SCVLANInterface(vlan)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
return interfacePrivate->vlan.tag;
}
CFDictionaryRef
SCVLANInterfaceGetOptions(SCVLANInterfaceRef vlan)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
if (!isA_SCVLANInterface(vlan)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
return interfacePrivate->vlan.options;
}
Boolean
SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan, SCNetworkInterfaceRef physical, CFNumberRef tag)
{
SCNetworkInterfacePrivateRef interfacePrivate;
Boolean ok = TRUE;
if (!isA_SCVLANInterface(vlan)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_SCNetworkInterface(physical)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
interfacePrivate = (SCNetworkInterfacePrivateRef)physical;
if (!interfacePrivate->supportsVLAN) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (isA_CFNumber(tag)) {
int tag_val;
CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
if ((tag_val < 1) || (tag_val > 4094)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
} else {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
if (interfacePrivate->prefs != NULL) {
SCVLANInterfaceRef config_vlan;
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
CFStringRef path;
config_vlan = findVLANInterfaceAndTag(interfacePrivate->prefs, physical, tag);
if (config_vlan != NULL) {
if (!CFEqual(vlan, config_vlan)) {
CFRelease(config_vlan);
_SCErrorSet(kSCStatusKeyExists);
return FALSE;
}
CFRelease(config_vlan);
}
path = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("/%@/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeVLAN,
interfacePrivate->entity_device);
dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
if (!isA_CFDictionary(dict)) {
CFRelease(path);
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
CFDictionarySetValue(newDict,
kSCPropVirtualNetworkInterfacesVLANInterface,
SCNetworkInterfaceGetBSDName(physical));
CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANTag, tag);
ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
CFRelease(newDict);
CFRelease(path);
}
if (ok) {
if (interfacePrivate->vlan.interface != NULL)
CFRelease(interfacePrivate->vlan.interface);
interfacePrivate->vlan.interface = CFRetain(physical);
if (interfacePrivate->vlan.tag != NULL)
CFRelease(interfacePrivate->vlan.tag);
interfacePrivate->vlan.tag = CFRetain(tag);
}
return ok;
}
Boolean
SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan, CFStringRef newName)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
Boolean ok = TRUE;
if (!isA_SCVLANInterface(vlan)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if ((newName != NULL) && !isA_CFString(newName)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (interfacePrivate->prefs != NULL) {
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
CFStringRef path;
path = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("/%@/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeVLAN,
interfacePrivate->entity_device);
dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
if (!isA_CFDictionary(dict)) {
CFRelease(path);
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
if (newName != NULL) {
CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
} else {
CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
}
ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
CFRelease(newDict);
CFRelease(path);
}
if (ok) {
if (interfacePrivate->localized_name != NULL) {
CFRelease(interfacePrivate->localized_name);
interfacePrivate->localized_name = NULL;
}
if (newName != NULL) {
interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName);
}
}
return ok;
}
Boolean
SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan, CFDictionaryRef newOptions)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
Boolean ok = TRUE;
if (!isA_SCVLANInterface(vlan)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (interfacePrivate->prefs != NULL) {
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
CFStringRef path;
path = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("/%@/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeVLAN,
interfacePrivate->entity_device);
dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
if (!isA_CFDictionary(dict)) {
CFRelease(path);
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
if (newOptions != NULL) {
CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions, newOptions);
} else {
CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions);
}
ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
CFRelease(newDict);
CFRelease(path);
}
if (ok) {
if (interfacePrivate->vlan.options != NULL) {
CFRelease(interfacePrivate->vlan.options);
interfacePrivate->vlan.options = NULL;
}
if (newOptions != NULL) {
interfacePrivate->vlan.options = CFDictionaryCreateCopy(NULL, newOptions);
}
}
return ok;
}
#pragma mark -
#pragma mark SCVLANInterface management
static Boolean
__vlan_set(int s, CFStringRef interface_if, CFStringRef physical_if, 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_if,
ifr.ifr_name,
sizeof(ifr.ifr_name),
kCFStringEncodingASCII);
ifr.ifr_data = (caddr_t)&vreq;
(void) _SC_cfstring_to_cstring(physical_if,
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;
}
return TRUE;
}
static Boolean
__vlan_clear(int s, CFStringRef interface_if)
{
struct ifreq ifr;
struct vlanreq vreq;
bzero(&ifr, sizeof(ifr));
bzero(&vreq, sizeof(vreq));
(void) _SC_cfstring_to_cstring(interface_if,
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
_SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs)
{
CFArrayRef active = NULL;
CFArrayRef config = NULL;
CFMutableDictionaryRef devices = NULL;
CFIndex i;
CFIndex nActive;
CFIndex nConfig;
Boolean ok = TRUE;
int s = -1;
if (prefs == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
config = SCVLANInterfaceCopyAll(prefs);
nConfig = CFArrayGetCount(config);
devices = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
active = _SCVLANInterfaceCopyActive();
nActive = CFArrayGetCount(active);
for (i = 0; i < nActive; i++) {
SCVLANInterfaceRef a_vlan;
CFStringRef a_vlan_if;
CFIndex j;
Boolean found = FALSE;
a_vlan = CFArrayGetValueAtIndex(active, i);
a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
for (j = 0; j < nConfig; j++) {
SCVLANInterfaceRef c_vlan;
CFStringRef c_vlan_if;
c_vlan = CFArrayGetValueAtIndex(config, j);
c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
if (CFEqual(a_vlan_if, c_vlan_if)) {
found = TRUE;
break;
}
}
if (!found) {
if (s == -1) {
s = inet_dgram_socket();
if (s == -1) {
_SCErrorSet(errno);
ok = FALSE;
goto done;
}
}
if (!__destroyInterface(s, a_vlan_if)) {
ok = FALSE;
_SCErrorSet(errno);
}
}
}
for (i = 0; i < nConfig; i++) {
SCVLANInterfaceRef c_vlan;
CFStringRef c_vlan_if;
SCNetworkInterfaceRef c_vlan_physical;
Boolean found = FALSE;
CFIndex j;
CFBooleanRef supported;
c_vlan = CFArrayGetValueAtIndex(config, i);
c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
c_vlan_physical = SCVLANInterfaceGetPhysicalInterface(c_vlan);
if (c_vlan_physical == NULL) {
continue;
}
supported = CFDictionaryGetValue(devices, c_vlan_physical);
if (supported == NULL) {
SCNetworkInterfacePrivateRef c_vlan_physicalPrivate = (SCNetworkInterfacePrivateRef)c_vlan_physical;
supported = c_vlan_physicalPrivate->supportsVLAN ? kCFBooleanTrue
: kCFBooleanFalse;
CFDictionaryAddValue(devices, c_vlan_physical, supported);
}
for (j = 0; j < nActive; j++) {
SCVLANInterfaceRef a_vlan;
CFStringRef a_vlan_if;
a_vlan = CFArrayGetValueAtIndex(active, j);
a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
if (CFEqual(c_vlan_if, a_vlan_if)) {
if (!CFEqual(c_vlan, a_vlan)) {
if (s == -1) {
s = inet_dgram_socket();
if (s == -1) {
_SCErrorSet(errno);
ok = FALSE;
goto done;
}
}
if (!CFBooleanGetValue(supported)
|| !__vlan_clear(s, c_vlan_if)
|| !__vlan_set(s, c_vlan_if,
SCNetworkInterfaceGetBSDName(c_vlan_physical),
SCVLANInterfaceGetTag(c_vlan))) {
if (!CFBooleanGetValue(supported)) {
_SCErrorSet(kSCStatusFailed);
}
(void)__destroyInterface(s, c_vlan_if);
ok = FALSE;
}
}
found = TRUE;
break;
}
}
if (!found && CFBooleanGetValue(supported)) {
Boolean created;
if (s == -1) {
s = inet_dgram_socket();
if (s == -1) {
_SCErrorSet(errno);
ok = FALSE;
goto done;
}
}
created = __createInterface(s, c_vlan_if);
if (!created
|| !__vlan_set(s,
c_vlan_if,
SCNetworkInterfaceGetBSDName(c_vlan_physical),
SCVLANInterfaceGetTag(c_vlan))) {
if (created) {
(void)__destroyInterface(s, c_vlan_if);
} else {
_SCErrorSet(errno);
}
ok = FALSE;
}
}
}
done :
if (active) CFRelease(active);
if (config) CFRelease(config);
if (devices) CFRelease(devices);
if (s != -1) (void) close(s);
return ok;
}
#pragma mark -
#pragma mark Deprecated SPIs (remove when no longer referenced)
Boolean
IsVLANSupported(CFStringRef device)
{
return __SCNetworkInterfaceSupportsVLAN(device);
}
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;
}
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) {
_SCErrorSet(errno);
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));
CFRelease(vlans);
vlans = NULL;
_SCErrorSet(kSCStatusFailed);
goto done;
}
vlr_tag = vreq.vlr_tag;
bzero(&vlr_parent, sizeof(vlr_parent));
bcopy(vreq.vlr_parent, vlr_parent, IFNAMSIZ);
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)
{
return TRUE;
}
Boolean
VLANPreferencesApplyChanges(VLANPreferencesRef prefs)
{
SCPreferencesRef defaultPrefs;
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;
}
defaultPrefs = SCPreferencesCreate(NULL, CFSTR("VLANPreferencesApplyChanges"), NULL);
{
#include "SCPreferencesInternal.h"
SCPreferencesPrivateRef defaultPrefsPrivate;
defaultPrefsPrivate = (SCPreferencesPrivateRef)defaultPrefs;
pthread_mutex_lock(&defaultPrefsPrivate->lock);
if (defaultPrefsPrivate->session == NULL) {
__SCPreferencesAddSession(defaultPrefs);
}
pthread_mutex_unlock(&defaultPrefsPrivate->lock);
ok = SCDynamicStoreNotifyValue(defaultPrefsPrivate->session, defaultPrefsPrivate->sessionKeyApply);
}
CFRelease(defaultPrefs);
if (!ok) {
goto done;
}
done :
pthread_mutex_unlock(&prefsPrivate->lock);
return ok;
}