BondConfiguration.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 <SystemConfiguration/BondConfiguration.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_bond_var.h>
#include <net/if_types.h>
#include <net/if_media.h>
#include <net/route.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;
}
static int
siocgifmedia(int s, const char * ifname, int * status, int * active)
{
struct ifmediareq ifmr;
*status = 0;
*active = 0;
bzero(&ifmr, sizeof(ifmr));
strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
return (-1);
}
if (ifmr.ifm_count != 0) {
*status = ifmr.ifm_status;
*active = ifmr.ifm_active;
}
return (0);
}
static struct if_bond_status_req *
if_bond_status_req_copy(int s, const char * ifname)
{
void * buf = NULL;
struct if_bond_req ibr;
struct if_bond_status_req * ibsr_p;
struct ifreq ifr;
bzero(&ifr, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
bzero((char *)&ibr, sizeof(ibr));
ibr.ibr_op = IF_BOND_OP_GET_STATUS;
ibsr_p = &ibr.ibr_ibru.ibru_status;
ibsr_p->ibsr_version = IF_BOND_STATUS_REQ_VERSION;
ifr.ifr_data = (caddr_t)&ibr;
if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) == -1) {
goto failed;
}
buf = malloc(sizeof(struct if_bond_status) * ibsr_p->ibsr_total + sizeof(*ibsr_p));
if (buf == NULL) {
goto failed;
}
if (ibsr_p->ibsr_total == 0) {
goto done;
}
ibsr_p->ibsr_count = ibsr_p->ibsr_total;
ibsr_p->ibsr_buffer = buf + sizeof(*ibsr_p);
if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) == -1) {
goto failed;
}
done:
(*(struct if_bond_status_req *)buf) = *ibsr_p;
return ((struct if_bond_status_req *)buf);
failed:
if (buf != NULL) {
free(buf);
}
return (NULL);
}
static void
add_interface(CFMutableArrayRef *interfaces, CFStringRef if_name)
{
SCNetworkInterfaceRef interface;
if (*interfaces == NULL) {
*interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
interface = _SCNetworkInterfaceCreateWithBSDName(NULL, if_name,
kIncludeNoVirtualInterfaces);
CFArrayAppendValue(*interfaces, interface);
CFRelease(interface);
}
static Boolean
_SCBondInterfaceSetMemberInterfaces(SCBondInterfaceRef bond, CFArrayRef members);
static Boolean
_SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode);
typedef struct {
CFMutableArrayRef bonds;
SCPreferencesRef prefs;
} addContext, *addContextRef;
static void
add_configured_interface(const void *key, const void *value, void *context)
{
SCBondInterfaceRef bond;
CFStringRef bond_if = (CFStringRef)key;
CFDictionaryRef bond_info = (CFDictionaryRef)value;
CFDictionaryRef bond_options;
CFIndex i;
CFArrayRef interfaces;
SCNetworkInterfacePrivateRef interfacePrivate;
CFMutableArrayRef members = NULL;
CFNumberRef mode;
addContextRef myContext = (addContextRef)context;
CFStringRef name;
CFIndex n;
bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(NULL, bond_if);
interfaces = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondInterfaces);
n = isA_CFArray(interfaces) ? CFArrayGetCount(interfaces) : 0;
for (i = 0; i < n; i++) {
CFStringRef member;
member = CFArrayGetValueAtIndex(interfaces, i);
if (isA_CFString(member)) {
add_interface(&members, member);
}
}
if (members != NULL) {
_SCBondInterfaceSetMemberInterfaces(bond, members);
CFRelease(members);
}
name = CFDictionaryGetValue(bond_info, kSCPropUserDefinedName);
if (isA_CFString(name)) {
SCBondInterfaceSetLocalizedDisplayName(bond, name);
}
bond_options = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondOptions);
if (isA_CFDictionary(bond_options)) {
SCBondInterfaceSetOptions(bond, bond_options);
}
mode = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondMode);
_SCBondInterfaceSetMode(bond, isA_CFNumber(mode));
interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
interfacePrivate->prefs = CFRetain(myContext->prefs);
CFArrayAppendValue(myContext->bonds, bond);
CFRelease(bond);
return;
}
static void
add_legacy_configuration(addContextRef myContext)
{
CFArrayRef bonds;
CFIndex i;
CFIndex n_bonds;
SCPreferencesRef prefs;
#define BOND_PREFERENCES_ID CFSTR("VirtualNetworkInterfaces.plist")
#define BOND_PREFERENCES_BONDS CFSTR("Bonds")
#define __kBondInterface_interface CFSTR("interface") // e.g. bond0, bond1, ...
#define __kBondInterface_devices CFSTR("devices") // e.g. en0, en1, ...
#define __kBondInterface_options CFSTR("options") // e.g. UserDefinedName
prefs = SCPreferencesCreate(NULL, CFSTR("SCBondInterfaceCopyAll"), BOND_PREFERENCES_ID);
if (prefs == NULL) {
return;
}
bonds = SCPreferencesGetValue(prefs, BOND_PREFERENCES_BONDS);
if ((bonds != NULL) && !isA_CFArray(bonds)) {
CFRelease(prefs); return;
}
n_bonds = (bonds != NULL) ? CFArrayGetCount(bonds) : 0;
for (i = 0; i < n_bonds; i++) {
SCBondInterfaceRef bond;
CFDictionaryRef bond_dict;
CFStringRef bond_if;
CFDictionaryRef dict;
CFArrayRef interfaces;
SCNetworkInterfacePrivateRef interfacePrivate;
CFIndex j;
CFMutableArrayRef members = NULL;
CFMutableDictionaryRef newDict;
CFArrayRef newInterfaces;
CFIndex n_interfaces;
Boolean ok;
CFDictionaryRef options;
CFStringRef path;
bond_dict = CFArrayGetValueAtIndex(bonds, i);
if (!isA_CFDictionary(bond_dict)) {
continue; }
bond_if = CFDictionaryGetValue(bond_dict, __kBondInterface_interface);
if (!isA_CFString(bond_if)) {
continue; }
path = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("/%@/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeBond,
bond_if);
dict = SCPreferencesPathGetValue(myContext->prefs, path);
if (dict != NULL) {
CFRelease(path);
continue;
}
newDict = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
newInterfaces = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
CFDictionaryAddValue(newDict, kSCPropVirtualNetworkInterfacesBondInterfaces, newInterfaces);
CFRelease(newInterfaces);
ok = SCPreferencesPathSetValue(myContext->prefs, path, newDict);
CFRelease(newDict);
CFRelease(path);
if (!ok) {
continue;
}
bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(NULL, bond_if);
interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
interfacePrivate->prefs = CFRetain(myContext->prefs);
interfaces = CFDictionaryGetValue(bond_dict, __kBondInterface_devices);
n_interfaces = isA_CFArray(interfaces) ? CFArrayGetCount(interfaces) : 0;
for (j = 0; j < n_interfaces; j++) {
CFStringRef member;
member = CFArrayGetValueAtIndex(interfaces, j);
if (isA_CFString(member)) {
add_interface(&members, member);
}
}
if (members != NULL) {
_SCBondInterfaceSetMemberInterfaces(bond, members);
CFRelease(members);
}
options = CFDictionaryGetValue(bond_dict, __kBondInterface_options);
if (isA_CFDictionary(options)) {
CFStringRef name;
name = CFDictionaryGetValue(options, kSCPropUserDefinedName);
if (isA_CFString(name)) {
SCBondInterfaceSetLocalizedDisplayName(bond, name);
}
}
CFArrayAppendValue(myContext->bonds, bond);
CFRelease(bond);
}
CFRelease(prefs);
return;
}
#pragma mark -
#pragma mark SCBondInterface APIs
CFArrayRef
SCBondInterfaceCopyAll(SCPreferencesRef prefs)
{
addContext context;
CFDictionaryRef dict;
CFStringRef path;
context.bonds = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
context.prefs = prefs;
path = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeBond);
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.bonds;
}
__private_extern__ void
__SCBondInterfaceListCopyMembers(CFArrayRef interfaces, CFMutableSetRef set)
{
CFIndex i;
CFIndex n;
n = CFArrayGetCount(interfaces);
for (i = 0; i < n; i++) {
SCBondInterfaceRef bondInterface;
CFArrayRef members;
bondInterface = CFArrayGetValueAtIndex(interfaces, i);
members = SCBondInterfaceGetMemberInterfaces(bondInterface);
if (members != NULL) {
CFIndex j;
CFIndex n_members;
n_members = CFArrayGetCount(members);
for (j = 0; j < n_members; j++) {
SCNetworkInterfaceRef member;
member = CFArrayGetValueAtIndex(members, j);
CFSetAddValue(set, member);
}
}
}
return;
}
CFArrayRef
SCBondInterfaceCopyAvailableMemberInterfaces(SCPreferencesRef prefs)
{
CFMutableArrayRef available;
CFMutableSetRef exclude;
CFArrayRef interfaces;
available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
exclude = CFSetCreateMutable (NULL, 0, &kCFTypeSetCallBacks);
interfaces = SCBondInterfaceCopyAll(prefs);
if (interfaces != NULL) {
__SCBondInterfaceListCopyMembers(interfaces, exclude);
CFRelease(interfaces);
}
interfaces = SCVLANInterfaceCopyAll(prefs);
if (interfaces != NULL) {
CFIndex i;
CFIndex n;
n = CFArrayGetCount(interfaces);
for (i = 0; i < n; i++) {
SCVLANInterfaceRef vlanInterface;
SCNetworkInterfaceRef physical;
vlanInterface = CFArrayGetValueAtIndex(interfaces, i);
physical = SCVLANInterfaceGetPhysicalInterface(vlanInterface);
CFSetAddValue(exclude, physical);
}
CFRelease(interfaces);
}
interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface();
if (interfaces != NULL) {
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 (!interfacePrivate->supportsBond) {
continue;
}
if (CFSetContainsValue(exclude, interface)) {
continue;
}
CFArrayAppendValue(available, interface);
}
CFRelease(interfaces);
}
CFRelease(exclude);
return available;
}
CFArrayRef
_SCBondInterfaceCopyActive(void)
{
struct ifaddrs *ifap;
struct ifaddrs *ifp;
int s;
CFMutableArrayRef bonds = NULL;
if (getifaddrs(&ifap) == -1) {
_SCErrorSet(errno);
SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
return NULL;
}
s = inet_dgram_socket();
if (s == -1) {
_SCErrorSet(errno);
goto done;
}
bonds = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
SCBondInterfaceRef bond;
CFStringRef bond_if;
struct if_bond_status_req *ibsr_p;
struct if_data *if_data;
int int_val;
CFNumberRef mode;
CFMutableArrayRef members = NULL;
if_data = (struct if_data *)ifp->ifa_data;
if (if_data == NULL
|| ifp->ifa_addr->sa_family != AF_LINK
|| if_data->ifi_type != IFT_IEEE8023ADLAG) {
continue;
}
ibsr_p = if_bond_status_req_copy(s, ifp->ifa_name);
if (ibsr_p == NULL) {
if (errno == EBUSY) {
continue;
}
_SCErrorSet(errno);
SCLog(TRUE, LOG_ERR,
CFSTR("if_bond_status_req_copy(%s) failed: %s"),
ifp->ifa_name,
strerror(errno));
CFRelease(bonds);
bonds = NULL;
goto done;
}
bond_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(NULL, bond_if);
CFRelease(bond_if);
int_val = ibsr_p->ibsr_mode;
mode = CFNumberCreate(NULL, kCFNumberIntType, &int_val);
_SCBondInterfaceSetMode(bond, mode);
CFRelease(mode);
if (ibsr_p->ibsr_total > 0) {
int i;
struct if_bond_status * ibs_p;
ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer;
for (i = 0; i < ibsr_p->ibsr_total; i++) {
char if_name[IFNAMSIZ + 1];
CFStringRef member;
bzero(&if_name, sizeof(if_name));
bcopy(ibs_p[i].ibs_if_name, if_name, IFNAMSIZ);
member = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
add_interface(&members, member);
CFRelease(member);
}
}
free(ibsr_p);
if (members != NULL) {
_SCBondInterfaceSetMemberInterfaces(bond, members);
CFRelease(members);
}
CFArrayAppendValue(bonds, bond);
CFRelease(bond);
}
done :
(void) close(s);
freeifaddrs(ifap);
return bonds;
}
SCBondInterfaceRef
SCBondInterfaceCreate(SCPreferencesRef prefs)
{
CFAllocatorRef allocator;
SCBondInterfaceRef bond = NULL;
CFIndex i;
if (prefs == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
allocator = CFGetAllocator(prefs);
for (i = 0; bond == NULL; i++) {
CFDictionaryRef dict;
CFStringRef bond_if;
SCNetworkInterfacePrivateRef interfacePrivate;
CFMutableDictionaryRef newDict;
CFArrayRef newInterfaces;
Boolean ok;
CFStringRef path;
bond_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("bond%d"), i);
path = CFStringCreateWithFormat(allocator,
NULL,
CFSTR("/%@/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeBond,
bond_if);
dict = SCPreferencesPathGetValue(prefs, path);
if (dict != NULL) {
CFRelease(path);
CFRelease(bond_if);
continue;
}
newDict = CFDictionaryCreateMutable(allocator,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
newInterfaces = CFArrayCreate(allocator, NULL, 0, &kCFTypeArrayCallBacks);
CFDictionaryAddValue(newDict, kSCPropVirtualNetworkInterfacesBondInterfaces, newInterfaces);
CFRelease(newInterfaces);
ok = SCPreferencesPathSetValue(prefs, path, newDict);
CFRelease(newDict);
CFRelease(path);
if (!ok) {
CFRelease(bond_if);
break;
}
bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(allocator, bond_if);
CFRelease(bond_if);
interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
interfacePrivate->prefs = CFRetain(prefs);
}
return bond;
}
Boolean
SCBondInterfaceRemove(SCBondInterfaceRef bond)
{
CFStringRef bond_if;
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
Boolean ok;
CFStringRef path;
if (!isA_SCBondInterface(bond)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (interfacePrivate->prefs == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
bond_if = SCNetworkInterfaceGetBSDName(bond);
path = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("/%@/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeBond,
bond_if);
ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path);
CFRelease(path);
return ok;
}
CFArrayRef
SCBondInterfaceGetMemberInterfaces(SCBondInterfaceRef bond)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
if (!isA_SCBondInterface(bond)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
return interfacePrivate->bond.interfaces;
}
CFDictionaryRef
SCBondInterfaceGetOptions(SCBondInterfaceRef bond)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
if (!isA_SCBondInterface(bond)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
return interfacePrivate->bond.options;
}
static Boolean
_SCBondInterfaceSetMemberInterfaces(SCBondInterfaceRef bond, CFArrayRef members)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
Boolean ok = TRUE;
if (interfacePrivate->prefs != NULL) {
CFDictionaryRef dict;
CFIndex i;
CFIndex n;
CFMutableDictionaryRef newDict;
CFMutableArrayRef newMembers;
CFStringRef path;
path = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("/%@/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeBond,
interfacePrivate->entity_device);
dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
if (!isA_CFDictionary(dict)) {
CFRelease(path);
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
n = (members != NULL) ? CFArrayGetCount(members) : 0;
for (i = 0; i < n; i++) {
SCNetworkInterfaceRef interface;
CFStringRef memberName;
interface = CFArrayGetValueAtIndex(members, i);
memberName = SCNetworkInterfaceGetBSDName(interface);
CFArrayAppendValue(newMembers, memberName);
}
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBondInterfaces, newMembers);
CFRelease(newMembers);
ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
CFRelease(newDict);
CFRelease(path);
}
if (ok) {
CFRelease(interfacePrivate->bond.interfaces);
if (members == NULL) {
interfacePrivate->bond.interfaces = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
} else {
interfacePrivate->bond.interfaces = CFArrayCreateCopy(NULL, members);
}
}
return ok;
}
Boolean
SCBondInterfaceSetMemberInterfaces(SCBondInterfaceRef bond, CFArrayRef members)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
Boolean ok = TRUE;
if (!isA_SCBondInterface(bond)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if ((members != NULL) && !isA_CFArray(members)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (interfacePrivate->prefs != NULL) {
CFArrayRef available;
CFArrayRef current;
CFIndex i;
CFIndex n_available;
CFIndex n_current;
CFIndex n_members;
current = SCBondInterfaceGetMemberInterfaces(bond);
n_current = (current != NULL) ? CFArrayGetCount(current) : 0;
available = SCBondInterfaceCopyAvailableMemberInterfaces(interfacePrivate->prefs);
n_available = (available != NULL) ? CFArrayGetCount(available) : 0;
n_members = (members != NULL) ? CFArrayGetCount(members) : 0;
for (i = 0; i < n_members; i++) {
SCNetworkInterfaceRef member;
member = CFArrayGetValueAtIndex(members, i);
if ((current != NULL) &&
CFArrayContainsValue(current, CFRangeMake(0, n_current), member)) {
continue;
}
if ((available != NULL) &&
CFArrayContainsValue(available, CFRangeMake(0, n_available), member)) {
continue;
}
ok = FALSE;
break;
}
CFRelease(available);
if (!ok) {
_SCErrorSet(kSCStatusInvalidArgument);
}
}
if (ok) {
ok = _SCBondInterfaceSetMemberInterfaces(bond, members);
}
return ok;
}
Boolean
SCBondInterfaceSetLocalizedDisplayName(SCBondInterfaceRef bond, CFStringRef newName)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
Boolean ok = TRUE;
if (!isA_SCBondInterface(bond)) {
_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,
kSCNetworkInterfaceTypeBond,
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
SCBondInterfaceSetOptions(SCBondInterfaceRef bond, CFDictionaryRef newOptions)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
Boolean ok = TRUE;
if (!isA_SCBondInterface(bond)) {
_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,
kSCNetworkInterfaceTypeBond,
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, kSCPropVirtualNetworkInterfacesBondOptions, newOptions);
} else {
CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesBondOptions);
}
ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
CFRelease(newDict);
CFRelease(path);
}
if (ok) {
if (interfacePrivate->bond.options != NULL) {
CFRelease(interfacePrivate->bond.options);
interfacePrivate->bond.options = NULL;
}
if (newOptions != NULL) {
interfacePrivate->bond.options = CFDictionaryCreateCopy(NULL, newOptions);
}
}
return ok;
}
static Boolean
_SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
Boolean needs_release = FALSE;
Boolean ok = TRUE;
if (mode == NULL) {
int mode_num = IF_BOND_MODE_LACP;
mode = CFNumberCreate(NULL, kCFNumberIntType, &mode_num);
needs_release = TRUE;
}
if (interfacePrivate->prefs != NULL) {
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
CFStringRef path;
path = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("/%@/%@/%@"),
kSCPrefVirtualNetworkInterfaces,
kSCNetworkInterfaceTypeBond,
interfacePrivate->entity_device);
dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
if (!isA_CFDictionary(dict)) {
CFRelease(path);
_SCErrorSet(kSCStatusFailed);
ok = FALSE;
goto done;
}
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBondMode, mode);
ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
CFRelease(newDict);
CFRelease(path);
}
if (ok) {
CFRetain(mode);
if (interfacePrivate->bond.mode != NULL) {
CFRelease(interfacePrivate->bond.mode);
}
interfacePrivate->bond.mode = mode;
}
done :
if (needs_release) CFRelease(mode);
return ok;
}
Boolean
SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode)
{
int mode_num;
if (!isA_SCBondInterface(bond) || !isA_CFNumber(mode)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (CFNumberGetValue(mode, kCFNumberIntType, &mode_num) == FALSE) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
switch (mode_num) {
case IF_BOND_MODE_LACP:
case IF_BOND_MODE_STATIC:
break;
default:
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
return (_SCBondInterfaceSetMode(bond, mode));
}
CFNumberRef
SCBondInterfaceGetMode(SCBondInterfaceRef bond)
{
SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
if (!isA_SCBondInterface(bond)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
return (interfacePrivate->bond.mode);
}
#pragma mark -
#pragma mark SCBondStatus APIs
typedef struct {
CFRuntimeBase cfBase;
SCBondInterfaceRef bond;
CFDictionaryRef status_bond;
CFArrayRef interfaces; CFDictionaryRef status_interfaces;
} SCBondStatusPrivate, * SCBondStatusPrivateRef;
const CFStringRef kSCBondStatusDeviceAggregationStatus = CFSTR("AggregationStatus");
const CFStringRef kSCBondStatusDeviceCollecting = CFSTR("Collecting");
const CFStringRef kSCBondStatusDeviceDistributing = CFSTR("Distributing");
static CFStringRef __SCBondStatusCopyDescription (CFTypeRef cf);
static void __SCBondStatusDeallocate (CFTypeRef cf);
static Boolean __SCBondStatusEqual (CFTypeRef cf1, CFTypeRef cf2);
static const CFRuntimeClass __SCBondStatusClass = {
0, "BondStatus", NULL, NULL, __SCBondStatusDeallocate, __SCBondStatusEqual, NULL, NULL, __SCBondStatusCopyDescription };
static CFTypeID __kSCBondStatusTypeID = _kCFRuntimeNotATypeID;
static pthread_once_t bondStatus_init = PTHREAD_ONCE_INIT;
static CFStringRef
__SCBondStatusCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)cf;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<SCBondStatus %p [%p]> {"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR(" bond = %@"), statusPrivate->bond);
CFStringAppendFormat(result, NULL, CFSTR(", interface = %@"), statusPrivate->status_bond);
CFStringAppendFormat(result, NULL, CFSTR(", members = %@"), statusPrivate->status_interfaces);
CFStringAppendFormat(result, NULL, CFSTR(" }"));
return result;
}
static void
__SCBondStatusDeallocate(CFTypeRef cf)
{
SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)cf;
CFRelease(statusPrivate->bond);
CFRelease(statusPrivate->status_bond);
if (statusPrivate->interfaces != NULL) CFRelease(statusPrivate->interfaces);
CFRelease(statusPrivate->status_interfaces);
return;
}
static Boolean
__SCBondStatusEqual(CFTypeRef cf1, CFTypeRef cf2)
{
SCBondStatusPrivateRef status1 = (SCBondStatusPrivateRef)cf1;
SCBondStatusPrivateRef status2 = (SCBondStatusPrivateRef)cf2;
if (status1 == status2)
return TRUE;
if (!CFEqual(status1->bond, status2->bond))
return FALSE;
if (!CFEqual(status1->status_bond, status2->status_bond))
return FALSE;
if (!CFEqual(status1->status_interfaces, status2->status_interfaces))
return FALSE;
return TRUE;
}
static void
__SCBondStatusInitialize(void)
{
__kSCBondStatusTypeID = _CFRuntimeRegisterClass(&__SCBondStatusClass);
return;
}
static SCBondStatusRef
__SCBondStatusCreatePrivate(CFAllocatorRef allocator,
SCBondInterfaceRef bond,
CFDictionaryRef status_bond,
CFDictionaryRef status_interfaces)
{
SCBondStatusPrivateRef statusPrivate;
uint32_t size;
pthread_once(&bondStatus_init, __SCBondStatusInitialize);
size = sizeof(SCBondStatusPrivate) - sizeof(CFRuntimeBase);
statusPrivate = (SCBondStatusPrivateRef)_CFRuntimeCreateInstance(allocator,
__kSCBondStatusTypeID,
size,
NULL);
if (statusPrivate == NULL) {
return NULL;
}
statusPrivate->bond = CFRetain(bond);
statusPrivate->status_bond = CFDictionaryCreateCopy(NULL, status_bond);
statusPrivate->interfaces = NULL;
statusPrivate->status_interfaces = CFDictionaryCreateCopy(NULL, status_interfaces);
return (SCBondStatusRef)statusPrivate;
}
static __inline__ CFTypeRef
isA_SCBondStatus(CFTypeRef obj)
{
return (isA_CFType(obj, SCBondStatusGetTypeID()));
}
CFTypeID
SCBondStatusGetTypeID()
{
pthread_once(&bondStatus_init, __SCBondStatusInitialize);
return __kSCBondStatusTypeID;
}
#define N_QUICK 16
CFArrayRef
SCBondStatusGetMemberInterfaces(SCBondStatusRef bondStatus)
{
SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)bondStatus;
if (!isA_SCBondStatus(bondStatus)) {
return NULL;
}
if (statusPrivate->interfaces == NULL) {
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
CFIndex n;
n = CFDictionaryGetCount(statusPrivate->status_interfaces);
if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
}
CFDictionaryGetKeysAndValues(statusPrivate->status_interfaces, keys, NULL);
statusPrivate->interfaces = CFArrayCreate(NULL, keys, n, &kCFTypeArrayCallBacks);
if (keys != keys_q) {
CFAllocatorDeallocate(NULL, keys);
}
}
return statusPrivate->interfaces;
}
CFDictionaryRef
SCBondStatusGetInterfaceStatus(SCBondStatusRef bondStatus, SCNetworkInterfaceRef interface)
{
CFDictionaryRef status = NULL;
SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)bondStatus;
if (!isA_SCBondStatus(bondStatus)) {
return NULL;
}
if (interface == NULL) {
status = statusPrivate->status_bond;
} else {
status = CFDictionaryGetValue(statusPrivate->status_interfaces, interface);
}
return status;
}
SCBondStatusRef
SCBondInterfaceCopyStatus(SCBondInterfaceRef bond)
{
int bond_if_active;
int bond_if_status;
CFIndex i;
struct if_bond_status_req *ibsr_p = NULL;
char if_name[IFNAMSIZ + 1];
CFIndex n;
CFNumberRef num;
int s;
struct if_bond_status *scan_p;
SCBondStatusRef status = NULL;
CFMutableDictionaryRef status_bond;
CFMutableDictionaryRef status_interfaces;
if (!isA_SCBondInterface(bond)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
s = inet_dgram_socket();
if (s == -1) {
_SCErrorSet(errno);
goto done;
}
_SC_cfstring_to_cstring(SCNetworkInterfaceGetBSDName(bond),
if_name,
sizeof(if_name),
kCFStringEncodingASCII);
if (siocgifmedia(s, if_name, &bond_if_status, &bond_if_active) == -1) {
_SCErrorSet(errno);
switch (errno) {
case EBUSY :
case ENXIO :
break;
default :
SCLog(TRUE, LOG_ERR,
CFSTR("siocgifmedia(%s) failed: %s"),
if_name,
strerror(errno));
}
goto done;
}
ibsr_p = if_bond_status_req_copy(s, if_name);
if (ibsr_p == NULL) {
_SCErrorSet(errno);
goto done;
}
status_bond = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
status_interfaces = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
n = ibsr_p->ibsr_total;
for (i = 0, scan_p = (struct if_bond_status *)ibsr_p->ibsr_buffer; i < n; i++, scan_p++) {
int collecting = 0;
int distributing = 0;
SCNetworkInterfaceRef interface;
CFStringRef interface_name;
struct if_bond_partner_state * ps;
CFMutableDictionaryRef status_interface;
int status_val;
ps = &scan_p->ibs_partner_state;
if (lacp_actor_partner_state_in_sync(scan_p->ibs_state)) {
status_val = kSCBondStatusOK;
if (lacp_actor_partner_state_in_sync(ps->ibps_state)) {
if (lacp_actor_partner_state_collecting(scan_p->ibs_state)
&& lacp_actor_partner_state_distributing(ps->ibps_state)) {
collecting = 1;
}
if (lacp_actor_partner_state_distributing(scan_p->ibs_state)
&& lacp_actor_partner_state_collecting(ps->ibps_state)) {
distributing = 1;
}
}
} else {
int active = 0;
int status = 0;
static lacp_system zeroes = { {0, 0, 0, 0, 0, 0}};
if (siocgifmedia(s, scan_p->ibs_if_name, &status, &active) == -1) {
switch (errno) {
case EBUSY :
case ENXIO :
break;
default :
SCLog(TRUE, LOG_ERR,
CFSTR("siocgifmedia(%s) failed: %s"),
if_name,
strerror(errno));
break;
}
}
if (((status & IFM_AVALID) == 0) ||
((status & IFM_ACTIVE) == 0) ||
((active & IFM_FDX ) == 0)) {
status_val = kSCBondStatusLinkInvalid;
} else if ((ps->ibps_system_priority == 0) &&
(bcmp(&zeroes, &ps->ibps_system, sizeof(zeroes)) == 0)) {
status_val = kSCBondStatusNoPartner;
} else if (active != bond_if_active) {
status_val = kSCBondStatusLinkInvalid;
} else {
status_val = kSCBondStatusNotInActiveGroup;
}
}
bzero(&if_name, sizeof(if_name));
bcopy(scan_p->ibs_if_name, if_name, IFNAMSIZ);
interface_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
interface = _SCNetworkInterfaceCreateWithBSDName(NULL, interface_name,
kIncludeNoVirtualInterfaces);
CFRelease(interface_name);
status_interface = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
num = CFNumberCreate(NULL, kCFNumberIntType, &status_val);
CFDictionarySetValue(status_interface, kSCBondStatusDeviceAggregationStatus, num);
CFRelease(num);
num = CFNumberCreate(NULL, kCFNumberIntType, &collecting);
CFDictionarySetValue(status_interface, kSCBondStatusDeviceCollecting, num);
CFRelease(num);
num = CFNumberCreate(NULL, kCFNumberIntType, &distributing);
CFDictionarySetValue(status_interface, kSCBondStatusDeviceDistributing, num);
CFRelease(num);
CFDictionarySetValue(status_interfaces, interface, status_interface);
CFRelease(interface);
CFRelease(status_interface);
}
status = __SCBondStatusCreatePrivate(NULL, bond, status_bond, status_interfaces);
CFRelease(status_bond);
CFRelease(status_interfaces);
done:
if (s != -1) {
close(s);
}
if (ibsr_p != NULL) {
free(ibsr_p);
}
return (SCBondStatusRef)status;
}
#pragma mark -
#pragma mark SCBondInterface management
static Boolean
__bond_set_mode(int s, CFStringRef bond_if, CFNumberRef mode)
{
struct if_bond_req breq;
struct ifreq ifr;
int mode_num;
mode_num = IF_BOND_MODE_LACP;
if (mode != NULL) {
CFNumberGetValue(mode, kCFNumberIntType, &mode_num);
}
bzero(&ifr, sizeof(ifr));
(void) _SC_cfstring_to_cstring(bond_if,
ifr.ifr_name,
sizeof(ifr.ifr_name),
kCFStringEncodingASCII);
ifr.ifr_data = (caddr_t)&breq;
bzero(&breq, sizeof(breq));
breq.ibr_op = IF_BOND_OP_SET_MODE;
breq.ibr_ibru.ibru_int_val = mode_num;
if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
_SCErrorSet(errno);
SCLog(TRUE, LOG_ERR,
CFSTR("could not set mode to %d on bond \"%@\": %s"),
mode,
bond_if,
strerror(errno));
return FALSE;
}
return TRUE;
}
static Boolean
__bond_add_interface(int s, CFStringRef bond_if, CFStringRef interface_if)
{
struct if_bond_req breq;
struct ifreq ifr;
bzero(&ifr, sizeof(ifr));
(void) _SC_cfstring_to_cstring(bond_if,
ifr.ifr_name,
sizeof(ifr.ifr_name),
kCFStringEncodingASCII);
ifr.ifr_data = (caddr_t)&breq;
bzero(&breq, sizeof(breq));
breq.ibr_op = IF_BOND_OP_ADD_INTERFACE;
(void) _SC_cfstring_to_cstring(interface_if,
breq.ibr_ibru.ibru_if_name,
sizeof(breq.ibr_ibru.ibru_if_name),
kCFStringEncodingASCII);
if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
_SCErrorSet(errno);
SCLog(TRUE, LOG_ERR,
CFSTR("could not add interface \"%@\" to bond \"%@\": %s"),
interface_if,
bond_if,
strerror(errno));
return FALSE;
}
return TRUE;
}
static Boolean
__bond_remove_interface(int s, CFStringRef bond_if, CFStringRef interface_if)
{
struct if_bond_req breq;
struct ifreq ifr;
bzero(&ifr, sizeof(ifr));
(void) _SC_cfstring_to_cstring(bond_if,
ifr.ifr_name,
sizeof(ifr.ifr_name),
kCFStringEncodingASCII);
ifr.ifr_data = (caddr_t)&breq;
bzero(&breq, sizeof(breq));
breq.ibr_op = IF_BOND_OP_REMOVE_INTERFACE;
(void) _SC_cfstring_to_cstring(interface_if,
breq.ibr_ibru.ibru_if_name,
sizeof(breq.ibr_ibru.ibru_if_name),
kCFStringEncodingASCII);
if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
_SCErrorSet(errno);
SCLog(TRUE, LOG_ERR,
CFSTR("could not remove interface \"%@\" from bond \"%@\": %s"),
interface_if,
bond_if,
strerror(errno));
return FALSE;
}
return TRUE;
}
Boolean
_SCBondInterfaceUpdateConfiguration(SCPreferencesRef prefs)
{
CFArrayRef active = NULL;
CFArrayRef config = NULL;
CFIndex i;
CFIndex nActive;
CFIndex nConfig;
Boolean ok = TRUE;
int s = -1;
if (prefs == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
config = SCBondInterfaceCopyAll(prefs);
nConfig = CFArrayGetCount(config);
active = _SCBondInterfaceCopyActive();
nActive = CFArrayGetCount(active);
for (i = 0; i < nActive; i++) {
SCBondInterfaceRef a_bond;
CFStringRef a_bond_if;
CFIndex j;
Boolean found = FALSE;
a_bond = CFArrayGetValueAtIndex(active, i);
a_bond_if = SCNetworkInterfaceGetBSDName(a_bond);
for (j = 0; j < nConfig; j++) {
SCBondInterfaceRef c_bond;
CFStringRef c_bond_if;
c_bond = CFArrayGetValueAtIndex(config, j);
c_bond_if = SCNetworkInterfaceGetBSDName(c_bond);
if (CFEqual(a_bond_if, c_bond_if)) {
CFIndex a;
CFArrayRef a_bond_interfaces;
CFIndex a_count;
CFArrayRef c_bond_interfaces;
CFIndex c_count;
c_bond_interfaces = SCBondInterfaceGetMemberInterfaces(c_bond);
c_count = (c_bond_interfaces != NULL) ? CFArrayGetCount(c_bond_interfaces) : 0;
a_bond_interfaces = SCBondInterfaceGetMemberInterfaces(a_bond);
a_count = (a_bond_interfaces != NULL) ? CFArrayGetCount(a_bond_interfaces) : 0;
for (a = 0; a < a_count; a++) {
SCNetworkInterfaceRef a_interface;
CFStringRef a_interface_if;
a_interface = CFArrayGetValueAtIndex(a_bond_interfaces, a);
if ((c_count == 0) ||
!CFArrayContainsValue(c_bond_interfaces,
CFRangeMake(0, c_count),
a_interface)) {
if (s == -1) {
s = inet_dgram_socket();
if (s == -1) {
_SCErrorSet(errno);
ok = FALSE;
goto done;
}
}
a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
if (!__bond_remove_interface(s, a_bond_if, a_interface_if)) {
ok = FALSE;
}
}
}
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_bond_if)) {
_SCErrorSet(errno);
ok = FALSE;
}
}
}
for (i = 0; i < nConfig; i++) {
CFNumberRef c_bond_mode;
SCBondInterfaceRef c_bond;
CFArrayRef c_bond_interfaces;
CFStringRef c_bond_if;
CFIndex c_count;
Boolean found = FALSE;
CFIndex j;
c_bond = CFArrayGetValueAtIndex(config, i);
c_bond_if = SCNetworkInterfaceGetBSDName(c_bond);
c_bond_interfaces = SCBondInterfaceGetMemberInterfaces(c_bond);
c_bond_mode = SCBondInterfaceGetMode(c_bond);
c_count = (c_bond_interfaces != NULL) ? CFArrayGetCount(c_bond_interfaces) : 0;
for (j = 0; j < nActive; j++) {
SCBondInterfaceRef a_bond;
CFArrayRef a_bond_interfaces;
CFNumberRef a_bond_mode;
CFStringRef a_bond_if;
CFIndex a_count;
a_bond = CFArrayGetValueAtIndex(active, j);
a_bond_if = SCNetworkInterfaceGetBSDName(a_bond);
a_bond_interfaces = SCBondInterfaceGetMemberInterfaces(a_bond);
a_bond_mode = SCBondInterfaceGetMode(a_bond);
a_count = (a_bond_interfaces != NULL) ? CFArrayGetCount(a_bond_interfaces) : 0;
if (CFEqual(c_bond_if, a_bond_if)) {
CFIndex c;
Boolean if_list_change = FALSE;
Boolean mode_change = FALSE;
found = TRUE;
if (!_SC_CFEqual(a_bond_mode, c_bond_mode)) {
mode_change = TRUE;
}
if (!_SC_CFEqual(c_bond_interfaces, a_bond_interfaces)) {
if_list_change = TRUE;
}
if (!mode_change && !if_list_change) {
break; }
if (s == -1) {
s = inet_dgram_socket();
if (s == -1) {
_SCErrorSet(errno);
ok = FALSE;
goto done;
}
}
if (mode_change) {
__bond_set_mode(s, a_bond_if, c_bond_mode);
}
if (!if_list_change) {
break; }
if ((c_count > 0) &&
(a_count > 0) &&
!CFEqual(CFArrayGetValueAtIndex(c_bond_interfaces, 0),
CFArrayGetValueAtIndex(a_bond_interfaces, 0))) {
CFIndex a;
for (a = 0; a < a_count; a++) {
SCNetworkInterfaceRef a_interface;
CFStringRef a_interface_if;
a_interface = CFArrayGetValueAtIndex(a_bond_interfaces, a);
if (!CFArrayContainsValue(c_bond_interfaces,
CFRangeMake(0, c_count),
a_interface)) {
continue; }
a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
if (!__bond_remove_interface(s, a_bond_if, a_interface_if)) {
ok = FALSE;
}
}
a_count = 0; }
for (c = 0; c < c_count; c++) {
SCNetworkInterfaceRef c_interface;
SCNetworkInterfacePrivateRef c_interfacePrivate;
CFStringRef c_interface_if;
c_interface = CFArrayGetValueAtIndex(c_bond_interfaces, c);
if ((a_count == 0) ||
!CFArrayContainsValue(a_bond_interfaces,
CFRangeMake(0, a_count),
c_interface)) {
c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
if (!c_interfacePrivate->supportsBond) {
continue;
}
c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
if (!__bond_add_interface(s, c_bond_if, c_interface_if)) {
ok = FALSE;
}
}
}
break;
}
}
if (!found) {
CFIndex c;
if (s == -1) {
s = inet_dgram_socket();
if (s == -1) {
_SCErrorSet(errno);
ok = FALSE;
goto done;
}
}
if (!__createInterface(s, c_bond_if)) {
_SCErrorSet(errno);
ok = FALSE;
continue;
}
__bond_set_mode(s, c_bond_if, c_bond_mode);
for (c = 0; c < c_count; c++) {
SCNetworkInterfaceRef c_interface;
SCNetworkInterfacePrivateRef c_interfacePrivate;
CFStringRef c_interface_if;
c_interface = CFArrayGetValueAtIndex(c_bond_interfaces, c);
c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
if (!c_interfacePrivate->supportsBond) {
continue;
}
c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
if (!__bond_add_interface(s, c_bond_if, c_interface_if)) {
ok = FALSE;
}
}
}
}
done :
if (active != NULL) CFRelease(active);
if (config != NULL) CFRelease(config);
if (s != -1) (void) close(s);
return ok;
}
#pragma mark -
#pragma mark Deprecated SPIs (remove when no longer referenced)
Boolean
IsBondSupported(CFStringRef device)
{
SCNetworkInterfaceRef interface;
SCNetworkInterfacePrivateRef interfacePrivate;
Boolean isBond = FALSE;
interface = _SCNetworkInterfaceCreateWithBSDName(NULL, device,
kIncludeNoVirtualInterfaces);
interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
isBond = interfacePrivate->supportsBond;
CFRelease(interface);
return isBond;
}
typedef struct {
CFRuntimeBase cfBase;
CFStringRef ifname; CFArrayRef devices; CFDictionaryRef options;
} BondInterfacePrivate, * BondInterfacePrivateRef;
static CFStringRef __BondInterfaceCopyDescription (CFTypeRef cf);
static void __BondInterfaceDeallocate (CFTypeRef cf);
static Boolean __BondInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2);
static const CFRuntimeClass __BondInterfaceClass = {
0, "BondInterface", NULL, NULL, __BondInterfaceDeallocate, __BondInterfaceEqual, NULL, NULL, __BondInterfaceCopyDescription };
static CFTypeID __kBondInterfaceTypeID = _kCFRuntimeNotATypeID;
static pthread_once_t bondInterface_init = PTHREAD_ONCE_INIT;
static CFStringRef
__BondInterfaceCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)cf;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<BondInterface %p [%p]> {"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR("if = %@"), bondPrivate->ifname);
if (bondPrivate->devices != NULL) {
CFIndex i;
CFIndex n;
CFStringAppendFormat(result, NULL, CFSTR(", devices ="));
n = CFArrayGetCount(bondPrivate->devices);
for (i = 0; i < n; i++) {
CFStringAppendFormat(result,
NULL,
CFSTR(" %@"),
CFArrayGetValueAtIndex(bondPrivate->devices, i));
}
}
if (bondPrivate->options != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", options = %@"), bondPrivate->options);
}
CFStringAppendFormat(result, NULL, CFSTR("}"));
return result;
}
static void
__BondInterfaceDeallocate(CFTypeRef cf)
{
BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)cf;
CFRelease(bondPrivate->ifname);
if (bondPrivate->devices) CFRelease(bondPrivate->devices);
if (bondPrivate->options) CFRelease(bondPrivate->options);
return;
}
static Boolean
__BondInterfaceEquiv(CFTypeRef cf1, CFTypeRef cf2)
{
BondInterfacePrivateRef bond1 = (BondInterfacePrivateRef)cf1;
BondInterfacePrivateRef bond2 = (BondInterfacePrivateRef)cf2;
if (bond1 == bond2)
return TRUE;
if (!CFEqual(bond1->ifname, bond2->ifname))
return FALSE;
if (!CFEqual(bond1->devices, bond2->devices))
return FALSE;
return TRUE;
}
static Boolean
__BondInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2)
{
BondInterfacePrivateRef bond1 = (BondInterfacePrivateRef)cf1;
BondInterfacePrivateRef bond2 = (BondInterfacePrivateRef)cf2;
if (!__BondInterfaceEquiv(bond1, bond2))
return FALSE;
if (bond1->options != bond2->options) {
if ((bond1->options != NULL) && (bond2->options != NULL)) {
if (!CFEqual(bond1->options, bond2->options)) {
return FALSE;
}
} else {
return FALSE;
}
}
return TRUE;
}
static void
__BondInterfaceInitialize(void)
{
__kBondInterfaceTypeID = _CFRuntimeRegisterClass(&__BondInterfaceClass);
return;
}
static __inline__ CFTypeRef
isA_BondInterface(CFTypeRef obj)
{
return (isA_CFType(obj, BondInterfaceGetTypeID()));
}
CFTypeID
BondInterfaceGetTypeID(void)
{
pthread_once(&bondInterface_init, __BondInterfaceInitialize);
return __kBondInterfaceTypeID;
}
static BondInterfaceRef
__BondInterfaceCreatePrivate(CFAllocatorRef allocator,
CFStringRef ifname)
{
BondInterfacePrivateRef bondPrivate;
uint32_t size;
pthread_once(&bondInterface_init, __BondInterfaceInitialize);
size = sizeof(BondInterfacePrivate) - sizeof(CFRuntimeBase);
bondPrivate = (BondInterfacePrivateRef)_CFRuntimeCreateInstance(allocator,
__kBondInterfaceTypeID,
size,
NULL);
if (bondPrivate == NULL) {
return NULL;
}
bondPrivate->ifname = CFStringCreateCopy(allocator, ifname);
bondPrivate->devices = NULL;
bondPrivate->options = NULL;
return (BondInterfaceRef)bondPrivate;
}
CFStringRef
BondInterfaceGetInterface(BondInterfaceRef bond)
{
BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
CFStringRef bond_if = NULL;
if (isA_BondInterface(bond)) {
bond_if = bondPrivate->ifname;
}
return bond_if;
}
CFArrayRef
BondInterfaceGetDevices(BondInterfaceRef bond)
{
BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
CFArrayRef bond_devices = NULL;
if (isA_BondInterface(bond)) {
bond_devices = bondPrivate->devices;
}
return bond_devices;
}
CFDictionaryRef
BondInterfaceGetOptions(BondInterfaceRef bond)
{
BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
CFDictionaryRef bond_options = NULL;
if (isA_BondInterface(bond)) {
bond_options = bondPrivate->options;
}
return bond_options;
}
static void
BondInterfaceSetDevices(BondInterfaceRef bond, CFArrayRef newDevices)
{
BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
if (isA_BondInterface(bond)) {
CFAllocatorRef allocator = CFGetAllocator(bond);
if (bondPrivate->devices != NULL) CFRelease(bondPrivate->devices);
if ((newDevices != NULL) && (CFArrayGetCount(newDevices) > 0)) {
bondPrivate->devices = CFArrayCreateCopy(allocator, newDevices);
} else {
bondPrivate->devices = NULL;
}
}
return;
}
static void
BondInterfaceSetOptions(BondInterfaceRef bond, CFDictionaryRef newOptions)
{
BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
if (isA_BondInterface(bond)) {
CFAllocatorRef allocator = CFGetAllocator(bond);
if (bondPrivate->options) CFRelease(bondPrivate->options);
if (newOptions != NULL) {
bondPrivate->options = CFDictionaryCreateCopy(allocator, newOptions);
} else {
bondPrivate->options = NULL;
}
}
return;
}
typedef struct {
CFRuntimeBase cfBase;
pthread_mutex_t lock;
SCPreferencesRef prefs;
CFArrayRef bBase;
} BondPreferencesPrivate, * BondPreferencesPrivateRef;
static CFStringRef __BondPreferencesCopyDescription (CFTypeRef cf);
static void __BondPreferencesDeallocate (CFTypeRef cf);
static const CFRuntimeClass __BondPreferencesClass = {
0, "BondPreferences", NULL, NULL, __BondPreferencesDeallocate, NULL, NULL, NULL, __BondPreferencesCopyDescription };
static CFTypeID __kBondPreferencesTypeID = _kCFRuntimeNotATypeID;
static pthread_once_t bondPreferences_init = PTHREAD_ONCE_INIT;
static CFStringRef
__BondPreferencesCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFIndex i;
CFArrayRef keys;
CFIndex n;
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)cf;
CFMutableStringRef result;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<BondPreferences %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;
}
static void
__BondPreferencesDeallocate(CFTypeRef cf)
{
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)cf;
pthread_mutex_destroy(&prefsPrivate->lock);
if (prefsPrivate->prefs) CFRelease(prefsPrivate->prefs);
if (prefsPrivate->bBase) CFRelease(prefsPrivate->bBase);
return;
}
static void
__BondPreferencesInitialize(void)
{
__kBondPreferencesTypeID = _CFRuntimeRegisterClass(&__BondPreferencesClass);
return;
}
static __inline__ CFTypeRef
isA_BondPreferences(CFTypeRef obj)
{
return (isA_CFType(obj, BondPreferencesGetTypeID()));
}
CFArrayRef
_BondPreferencesCopyActiveInterfaces()
{
CFArrayCallBacks callbacks;
struct ifaddrs *ifap;
struct ifaddrs *ifp;
int s;
CFMutableArrayRef bonds = NULL;
if (getifaddrs(&ifap) == -1) {
_SCErrorSet(errno);
SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
return NULL;
}
s = inet_dgram_socket();
if (s == -1) {
_SCErrorSet(errno);
goto done;
}
callbacks = kCFTypeArrayCallBacks;
callbacks.equal = __BondInterfaceEquiv;
bonds = CFArrayCreateMutable(NULL, 0, &callbacks);
for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
BondInterfaceRef bond;
CFStringRef bond_if;
CFMutableArrayRef devices = NULL;
struct if_bond_status_req *ibsr_p;
struct if_data *if_data;
if_data = (struct if_data *)ifp->ifa_data;
if (if_data == NULL
|| ifp->ifa_addr->sa_family != AF_LINK
|| if_data->ifi_type != IFT_IEEE8023ADLAG) {
continue;
}
ibsr_p = if_bond_status_req_copy(s, ifp->ifa_name);
if (ibsr_p == NULL) {
if (errno == EBUSY) {
continue;
}
_SCErrorSet(errno);
SCLog(TRUE, LOG_ERR,
CFSTR("if_bond_status_req_copy(%s) failed: %s"),
ifp->ifa_name,
strerror(errno));
CFRelease(bonds);
bonds = NULL;
goto done;
}
if (ibsr_p->ibsr_total > 0) {
int i;
struct if_bond_status * ibs_p;
devices = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer;
for (i = 0; i < ibsr_p->ibsr_total; i++) {
CFStringRef device;
char if_name[IFNAMSIZ + 1];
bzero(&if_name, sizeof(if_name));
bcopy(ibs_p[i].ibs_if_name, if_name, IFNAMSIZ);
device = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
CFArrayAppendValue(devices, device);
CFRelease(device);
}
}
free(ibsr_p);
bond_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
bond = __BondInterfaceCreatePrivate(NULL, bond_if);
CFRelease(bond_if);
if (devices != NULL) {
BondInterfaceSetDevices(bond, devices);
CFRelease(devices);
}
CFArrayAppendValue(bonds, bond);
CFRelease(bond);
}
done :
(void) close(s);
freeifaddrs(ifap);
return bonds;
}
static CFIndex
findBond(CFArrayRef bonds, CFStringRef interface)
{
CFIndex found = kCFNotFound;
CFIndex i;
CFIndex n;
n = isA_CFArray(bonds) ? CFArrayGetCount(bonds) : 0;
for (i = 0; i < n; i++) {
CFDictionaryRef bond_dict;
CFStringRef bond_if;
bond_dict = CFArrayGetValueAtIndex(bonds, i);
if (!isA_CFDictionary(bond_dict)) {
break; }
bond_if = CFDictionaryGetValue(bond_dict, __kBondInterface_interface);
if (!isA_CFString(bond_if)) {
break; }
if (!CFEqual(bond_if, interface)) {
continue; }
found = i;
break;
}
return found;
}
static void
setConfigurationChanged(BondPreferencesRef prefs)
{
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
if (prefsPrivate->bBase == NULL) {
prefsPrivate->bBase = BondPreferencesCopyInterfaces(prefs);
}
return;
}
CFTypeID
BondPreferencesGetTypeID(void)
{
pthread_once(&bondPreferences_init, __BondPreferencesInitialize);
return __kBondPreferencesTypeID;
}
BondPreferencesRef
BondPreferencesCreate(CFAllocatorRef allocator)
{
CFBundleRef bundle;
CFStringRef bundleID = NULL;
CFStringRef name = CFSTR("BondConfiguration");
BondPreferencesPrivateRef prefsPrivate;
uint32_t size;
pthread_once(&bondPreferences_init, __BondPreferencesInitialize);
size = sizeof(BondPreferencesPrivate) - sizeof(CFRuntimeBase);
prefsPrivate = (BondPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
__kBondPreferencesTypeID,
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, BOND_PREFERENCES_ID);
CFRelease(name);
prefsPrivate->bBase = NULL;
return (BondPreferencesRef)prefsPrivate;
}
CFArrayRef
BondPreferencesCopyInterfaces(BondPreferencesRef prefs)
{
CFAllocatorRef allocator;
CFArrayCallBacks callbacks;
CFIndex i;
CFIndex n;
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
CFMutableArrayRef result;
CFArrayRef bonds;
if (!isA_BondPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
allocator = CFGetAllocator(prefs);
callbacks = kCFTypeArrayCallBacks;
callbacks.equal = __BondInterfaceEquiv;
result = CFArrayCreateMutable(allocator, 0, &callbacks);
bonds = SCPreferencesGetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
if ((bonds != NULL) && !isA_CFArray(bonds)) {
goto error; }
n = (bonds != NULL) ? CFArrayGetCount(bonds) : 0;
for (i = 0; i < n; i++) {
BondInterfaceRef bond;
CFDictionaryRef bond_dict;
CFStringRef bond_if;
CFArrayRef devices;
CFDictionaryRef options;
bond_dict = CFArrayGetValueAtIndex(bonds, i);
if (!isA_CFDictionary(bond_dict)) {
goto error; }
bond_if = CFDictionaryGetValue(bond_dict, __kBondInterface_interface);
if (!isA_CFString(bond_if)) {
goto error; }
devices = CFDictionaryGetValue(bond_dict, __kBondInterface_devices);
if ((devices != NULL) && !isA_CFArray(devices)) {
goto error; }
options = CFDictionaryGetValue(bond_dict, __kBondInterface_options);
if ((options != NULL) && !isA_CFDictionary(options)) {
goto error; }
bond = __BondInterfaceCreatePrivate(allocator, bond_if);
BondInterfaceSetDevices(bond, devices);
BondInterfaceSetOptions(bond, options);
CFArrayAppendValue(result, bond);
CFRelease(bond);
}
return result;
error :
_SCErrorSet(kSCStatusFailed);
CFRelease(result);
return NULL;
}
BondInterfaceRef
BondPreferencesCreateInterface(BondPreferencesRef prefs)
{
CFArrayRef active_bonds = NULL;
CFAllocatorRef allocator;
CFArrayRef config_bonds;
CFIndex i;
CFIndex nActive;
CFIndex nConfig;
BondInterfaceRef newBond = NULL;
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
if (!isA_BondPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
pthread_mutex_lock(&prefsPrivate->lock);
config_bonds = SCPreferencesGetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
if ((config_bonds != NULL) && !isA_CFArray(config_bonds)) {
_SCErrorSet(kSCStatusFailed);
goto done;
}
nConfig = (config_bonds != NULL) ? CFArrayGetCount(config_bonds) : 0;
active_bonds = _BondPreferencesCopyActiveInterfaces();
nActive = isA_CFArray(active_bonds) ? CFArrayGetCount(active_bonds) : 0;
allocator = CFGetAllocator(prefs);
for (i = 0; newBond == NULL; i++) {
CFIndex j;
CFMutableDictionaryRef newDict;
CFMutableArrayRef newBonds;
CFStringRef bond_if;
bond_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("bond%d"), i);
for (j = 0; j < nActive; j++) {
CFStringRef active_if;
BondInterfaceRef active_bond;
active_bond = CFArrayGetValueAtIndex(active_bonds, j);
active_if = BondInterfaceGetInterface(active_bond);
if (CFEqual(bond_if, active_if)) {
goto next_if; }
}
for (j = 0; j < nConfig; j++) {
CFDictionaryRef config;
CFStringRef config_if;
config = CFArrayGetValueAtIndex(config_bonds, j);
if (!isA_CFDictionary(config)) {
_SCErrorSet(kSCStatusFailed);
CFRelease(bond_if);
goto done;
}
config_if = CFDictionaryGetValue(config, __kBondInterface_interface);
if (!isA_CFString(config_if)) {
_SCErrorSet(kSCStatusFailed);
CFRelease(bond_if);
goto done;
}
if (CFEqual(bond_if, config_if)) {
goto next_if; }
}
newDict = CFDictionaryCreateMutable(allocator,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(newDict, __kBondInterface_interface, bond_if);
newBond = __BondInterfaceCreatePrivate(allocator, bond_if);
if (nConfig > 0) {
newBonds = CFArrayCreateMutableCopy(allocator, 0, config_bonds);
} else {
newBonds = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
}
CFArrayAppendValue(newBonds, newDict);
CFRelease(newDict);
setConfigurationChanged(prefs);
(void) SCPreferencesSetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS, newBonds);
CFRelease(newBonds);
next_if :
CFRelease(bond_if);
}
done :
if (active_bonds != NULL) CFRelease(active_bonds);
pthread_mutex_unlock(&prefsPrivate->lock);
return (BondInterfaceRef) newBond;
}
static Boolean
_BondPreferencesUpdate(BondPreferencesRef prefs, BondInterfaceRef bond)
{
CFAllocatorRef allocator;
CFIndex bond_index;
CFArrayRef devices;
CFStringRef interface;
CFMutableDictionaryRef newDict;
CFMutableArrayRef newBonds;
CFDictionaryRef options;
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
CFArrayRef bonds;
bonds = SCPreferencesGetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
if ((bonds != NULL) && !isA_CFArray(bonds)) {
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
interface = BondInterfaceGetInterface(bond);
bond_index = findBond(bonds, interface);
if (bond_index == kCFNotFound) {
_SCErrorSet(kSCStatusNoKey);
return FALSE;
}
allocator = CFGetAllocator(prefs);
newDict = CFDictionaryCreateMutable(allocator,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(newDict, __kBondInterface_interface, interface);
devices = BondInterfaceGetDevices(bond);
if (devices != NULL) {
CFDictionaryAddValue(newDict, __kBondInterface_devices, devices);
}
options = BondInterfaceGetOptions(bond);
if (options != NULL) {
CFDictionaryAddValue(newDict, __kBondInterface_options, options);
}
setConfigurationChanged(prefs);
newBonds = CFArrayCreateMutableCopy(allocator, 0, bonds);
CFArraySetValueAtIndex(newBonds, bond_index, newDict);
CFRelease(newDict);
(void) SCPreferencesSetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS, newBonds);
CFRelease(newBonds);
return TRUE;
}
Boolean
BondPreferencesAddDevice(BondPreferencesRef prefs,
BondInterfaceRef bond,
CFStringRef device)
{
CFArrayRef config_bonds;
CFIndex i;
CFIndex nConfig;
Boolean ok = TRUE;
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
if (!isA_BondPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_BondInterface(bond)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_CFString(device)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!IsBondSupported(device)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
pthread_mutex_lock(&prefsPrivate->lock);
config_bonds = SCPreferencesGetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
if ((config_bonds != NULL) && !isA_CFArray(config_bonds)) {
_SCErrorSet(kSCStatusFailed);
ok = FALSE;
goto done;
}
nConfig = (config_bonds != NULL) ? CFArrayGetCount(config_bonds) : 0;
for (i = 0; ok && (i < nConfig); i++) {
CFDictionaryRef config_bond;
CFArrayRef devices;
config_bond = CFArrayGetValueAtIndex(config_bonds, i);
if (!isA_CFDictionary(config_bond)) {
ok = FALSE; break;
}
devices = CFDictionaryGetValue(config_bond, __kBondInterface_devices);
if ((devices != NULL) && !isA_CFArray(devices)) {
ok = FALSE; break;
}
if (devices == NULL) {
continue; }
ok = !CFArrayContainsValue(devices,
CFRangeMake(0, CFArrayGetCount(devices)),
device);
}
if (ok) {
CFArrayRef devices;
CFMutableArrayRef newDevices;
devices = BondInterfaceGetDevices(bond);
if (devices != NULL) {
devices = CFArrayCreateCopy(NULL, devices);
newDevices = CFArrayCreateMutableCopy(NULL, 0, devices);
} else {
newDevices = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
CFArrayAppendValue(newDevices, device);
BondInterfaceSetDevices(bond, newDevices);
CFRelease(newDevices);
ok = _BondPreferencesUpdate(prefs, bond);
if (!ok) {
BondInterfaceSetDevices(bond, devices);
}
if (devices != NULL) {
CFRelease(devices);
}
} else {
_SCErrorSet(kSCStatusKeyExists);
}
done :
pthread_mutex_unlock(&prefsPrivate->lock);
return ok;
}
Boolean
BondPreferencesRemoveDevice(BondPreferencesRef prefs,
BondInterfaceRef bond,
CFStringRef device)
{
CFIndex bond_index;
CFArrayRef devices;
Boolean ok = FALSE;
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
if (!isA_BondPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_BondInterface(bond)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_CFString(device)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
pthread_mutex_lock(&prefsPrivate->lock);
devices = BondInterfaceGetDevices(bond);
if (devices != NULL) {
bond_index = CFArrayGetFirstIndexOfValue(devices,
CFRangeMake(0, CFArrayGetCount(devices)),
device);
if (bond_index != kCFNotFound) {
CFMutableArrayRef newDevices;
devices = CFArrayCreateCopy(NULL, devices);
newDevices = CFArrayCreateMutableCopy(NULL, 0, devices);
CFArrayRemoveValueAtIndex(newDevices, bond_index);
BondInterfaceSetDevices(bond, newDevices);
CFRelease(newDevices);
ok = _BondPreferencesUpdate(prefs, bond);
if (!ok) {
BondInterfaceSetDevices(bond, devices);
}
CFRelease(devices);
} else {
_SCErrorSet(kSCStatusNoKey);
}
}
pthread_mutex_unlock(&prefsPrivate->lock);
return ok;
}
Boolean
BondPreferencesSetOptions(BondPreferencesRef prefs, BondInterfaceRef bond, CFDictionaryRef newOptions)
{
Boolean ok = FALSE;
CFDictionaryRef options;
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
if (!isA_BondPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_BondInterface(bond)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
pthread_mutex_lock(&prefsPrivate->lock);
options = BondInterfaceGetOptions(bond);
if (options != NULL) {
options = CFDictionaryCreateCopy(NULL, options);
}
BondInterfaceSetOptions(bond, newOptions);
ok = _BondPreferencesUpdate(prefs, bond);
if (!ok) {
BondInterfaceSetOptions(bond, options);
}
if (options != NULL) {
CFRelease(options);
}
pthread_mutex_unlock(&prefsPrivate->lock);
return ok;
}
Boolean
BondPreferencesRemoveInterface(BondPreferencesRef prefs,
BondInterfaceRef bond)
{
CFIndex bond_index;
Boolean ok = FALSE;
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
CFArrayRef bonds;
if (!isA_BondPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_BondInterface(bond)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
pthread_mutex_lock(&prefsPrivate->lock);
bonds = SCPreferencesGetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
if (!isA_CFArray(bonds)) {
_SCErrorSet(kSCStatusFailed);
goto done;
}
bond_index = findBond(bonds, BondInterfaceGetInterface(bond));
if (bond_index == kCFNotFound) {
_SCErrorSet(kSCStatusNoKey);
goto done;
}
setConfigurationChanged(prefs);
if (CFArrayGetCount(bonds) > 1) {
CFAllocatorRef allocator;
CFMutableArrayRef newBonds;
allocator = CFGetAllocator(prefs);
newBonds = CFArrayCreateMutableCopy(allocator, 0, bonds);
CFArrayRemoveValueAtIndex(newBonds, bond_index);
(void) SCPreferencesSetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS, newBonds);
CFRelease(newBonds);
} else {
(void) SCPreferencesRemoveValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
}
ok = TRUE;
done :
pthread_mutex_unlock(&prefsPrivate->lock);
return ok;
}
Boolean
BondPreferencesCommitChanges(BondPreferencesRef prefs)
{
Boolean ok = FALSE;
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
if (!isA_BondPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
ok = SCPreferencesCommitChanges(prefsPrivate->prefs);
if (!ok) {
return ok;
}
if (prefsPrivate->bBase != NULL) {
CFRelease(prefsPrivate->bBase);
prefsPrivate->bBase = NULL;
}
return TRUE;
}
Boolean
_BondPreferencesUpdateConfiguration(BondPreferencesRef prefs)
{
return TRUE;
}
Boolean
BondPreferencesApplyChanges(BondPreferencesRef prefs)
{
SCPreferencesRef defaultPrefs;
Boolean ok = FALSE;
BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
if (!isA_BondPreferences(prefs)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
pthread_mutex_lock(&prefsPrivate->lock);
ok = SCPreferencesApplyChanges(prefsPrivate->prefs);
if (!ok) {
goto done;
}
defaultPrefs = SCPreferencesCreate(NULL, CFSTR("BondPreferencesApplyChanges"), 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;
}
typedef struct {
CFRuntimeBase cfBase;
BondInterfaceRef bond;
CFDictionaryRef status_interface; CFArrayRef devices; CFDictionaryRef status_devices;
} BondStatusPrivate, * BondStatusPrivateRef;
static CFStringRef __BondStatusCopyDescription (CFTypeRef cf);
static void __BondStatusDeallocate (CFTypeRef cf);
static Boolean __BondStatusEqual (CFTypeRef cf1, CFTypeRef cf2);
static const CFRuntimeClass __BondStatusClass = {
0, "BondStatus", NULL, NULL, __BondStatusDeallocate, __BondStatusEqual, NULL, NULL, __BondStatusCopyDescription };
static CFTypeID __kBondStatusTypeID = _kCFRuntimeNotATypeID;
static pthread_once_t bondStatus_init_X = PTHREAD_ONCE_INIT;
static CFStringRef
__BondStatusCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
BondStatusPrivateRef statusPrivate = (BondStatusPrivateRef)cf;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<BondStatus %p [%p]> {"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR(" bond = %@"), statusPrivate->bond);
CFStringAppendFormat(result, NULL, CFSTR(" interface = %@"), statusPrivate->status_interface);
CFStringAppendFormat(result, NULL, CFSTR(" devices = %@"), statusPrivate->status_devices);
CFStringAppendFormat(result, NULL, CFSTR(" }"));
return result;
}
static void
__BondStatusDeallocate(CFTypeRef cf)
{
BondStatusPrivateRef statusPrivate = (BondStatusPrivateRef)cf;
CFRelease(statusPrivate->bond);
CFRelease(statusPrivate->status_interface);
if (statusPrivate->devices != NULL) CFRelease(statusPrivate->devices);
CFRelease(statusPrivate->status_devices);
return;
}
static Boolean
__BondStatusEqual(CFTypeRef cf1, CFTypeRef cf2)
{
BondStatusPrivateRef status1 = (BondStatusPrivateRef)cf1;
BondStatusPrivateRef status2 = (BondStatusPrivateRef)cf2;
if (status1 == status2)
return TRUE;
if (!CFEqual(status1->bond, status2->bond))
return FALSE;
if (!CFEqual(status1->status_interface, status2->status_interface))
return FALSE;
if (!CFEqual(status1->status_devices, status2->status_devices))
return FALSE;
return TRUE;
}
static void
__BondStatusInitialize(void)
{
__kBondStatusTypeID = _CFRuntimeRegisterClass(&__BondStatusClass);
return;
}
static __inline__ CFTypeRef
isA_BondStatus(CFTypeRef obj)
{
return (isA_CFType(obj, BondStatusGetTypeID()));
}
CFTypeID
BondStatusGetTypeID(void)
{
pthread_once(&bondStatus_init_X, __BondStatusInitialize);
return __kBondStatusTypeID;
}
static BondStatusRef
__BondStatusCreatePrivate(CFAllocatorRef allocator,
BondInterfaceRef bond,
CFDictionaryRef status_interface,
CFDictionaryRef status_devices)
{
BondStatusPrivateRef statusPrivate;
uint32_t size;
pthread_once(&bondStatus_init_X, __BondStatusInitialize);
size = sizeof(BondStatusPrivate) - sizeof(CFRuntimeBase);
statusPrivate = (BondStatusPrivateRef)_CFRuntimeCreateInstance(allocator,
__kBondStatusTypeID,
size,
NULL);
if (statusPrivate == NULL) {
return NULL;
}
statusPrivate->bond = CFRetain(bond);
statusPrivate->status_interface = CFDictionaryCreateCopy(allocator, status_interface);
statusPrivate->devices = NULL;
statusPrivate->status_devices = CFDictionaryCreateCopy(allocator, status_devices);
return (BondStatusRef)statusPrivate;
}
BondStatusRef
BondInterfaceCopyStatus(BondInterfaceRef bond)
{
BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
int bond_if_active;
int bond_if_status;
CFIndex i;
struct if_bond_status_req *ibsr_p = NULL;
char if_name[IFNAMSIZ + 1];
CFIndex n;
CFNumberRef num;
int s;
struct if_bond_status * scan_p;
BondStatusRef status = NULL;
CFMutableDictionaryRef status_devices;
CFMutableDictionaryRef status_interface;
if (!isA_BondInterface(bond)) {
return NULL;
}
s = inet_dgram_socket();
if (s == -1) {
_SCErrorSet(errno);
goto done;
}
_SC_cfstring_to_cstring(bondPrivate->ifname, if_name,
sizeof(if_name), kCFStringEncodingASCII);
(void)siocgifmedia(s, if_name, &bond_if_status, &bond_if_active);
ibsr_p = if_bond_status_req_copy(s, if_name);
if (ibsr_p == NULL) {
_SCErrorSet(errno);
goto done;
}
status_interface = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
status_devices = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
n = ibsr_p->ibsr_total;
for (i = 0, scan_p = (struct if_bond_status *)ibsr_p->ibsr_buffer; i < n; i++, scan_p++) {
CFStringRef bond_if;
int collecting = 0;
int distributing = 0;
struct if_bond_partner_state * ps;
CFMutableDictionaryRef status_device;
int status_val;
ps = &scan_p->ibs_partner_state;
status_device = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (lacp_actor_partner_state_in_sync(scan_p->ibs_state)) {
status_val = kSCBondStatusOK;
if (lacp_actor_partner_state_in_sync(ps->ibps_state)) {
if (lacp_actor_partner_state_collecting(scan_p->ibs_state)
&& lacp_actor_partner_state_distributing(ps->ibps_state)) {
collecting = 1;
}
if (lacp_actor_partner_state_distributing(scan_p->ibs_state)
&& lacp_actor_partner_state_collecting(ps->ibps_state)) {
distributing = 1;
}
}
}
else {
int active = 0;
int status = 0;
static lacp_system zeroes = {{0,0,0,0,0,0}};
(void)siocgifmedia(s, scan_p->ibs_if_name, &status, &active);
if ((status & IFM_AVALID) == 0 || (status & IFM_ACTIVE) == 0
|| (active & IFM_FDX) == 0) {
status_val = kSCBondStatusLinkInvalid;
}
else if (ps->ibps_system_priority == 0
&& bcmp(&zeroes, &ps->ibps_system, sizeof(zeroes)) == 0) {
status_val = kSCBondStatusNoPartner;
}
else if (active != bond_if_active) {
status_val = kSCBondStatusLinkInvalid;
}
else {
status_val = kSCBondStatusNotInActiveGroup;
}
}
num = CFNumberCreate(NULL, kCFNumberIntType, &status_val);
CFDictionarySetValue(status_device, kSCBondStatusDeviceAggregationStatus, num);
CFRelease(num);
num = CFNumberCreate(NULL, kCFNumberIntType, &collecting);
CFDictionarySetValue(status_device, kSCBondStatusDeviceCollecting, num);
CFRelease(num);
num = CFNumberCreate(NULL, kCFNumberIntType, &distributing);
CFDictionarySetValue(status_device, kSCBondStatusDeviceDistributing, num);
CFRelease(num);
bond_if = CFArrayGetValueAtIndex(bondPrivate->devices, i);
CFDictionarySetValue(status_devices, bond_if, status_device);
CFRelease(status_device);
}
status = __BondStatusCreatePrivate(NULL, bond, status_interface, status_devices);
CFRelease(status_interface);
CFRelease(status_devices);
done:
if (s != -1) {
close(s);
}
if (ibsr_p != NULL) {
free(ibsr_p);
}
return status;
}
CFArrayRef
BondStatusGetDevices(BondStatusRef bondStatus)
{
BondStatusPrivateRef statusPrivate = (BondStatusPrivateRef)bondStatus;
if (!isA_BondStatus(bondStatus)) {
return NULL;
}
if (statusPrivate->devices == NULL) {
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
CFIndex n;
n = CFDictionaryGetCount(statusPrivate->status_devices);
if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
}
CFDictionaryGetKeysAndValues(statusPrivate->status_devices, keys, NULL);
statusPrivate->devices = CFArrayCreate(NULL, keys, n, &kCFTypeArrayCallBacks);
if (keys != keys_q) {
CFAllocatorDeallocate(NULL, keys);
}
}
return statusPrivate->devices;
}
CFDictionaryRef
BondStatusGetInterfaceStatus(BondStatusRef bondStatus)
{
BondStatusPrivateRef statusPrivate = (BondStatusPrivateRef)bondStatus;
if (!isA_BondStatus(bondStatus)) {
return NULL;
}
return statusPrivate->status_interface;
}
CFDictionaryRef
BondStatusGetDeviceStatus(BondStatusRef bondStatus, CFStringRef device)
{
BondStatusPrivateRef statusPrivate = (BondStatusPrivateRef)bondStatus;
if (!isA_BondStatus(bondStatus)) {
return NULL;
}
return CFDictionaryGetValue(statusPrivate->status_devices, device);
}