multiple update

This commit is contained in:
vemax78
2013-05-03 22:28:06 +02:00
parent f2dda6e115
commit 9082a7855c
10 changed files with 635 additions and 233 deletions

View File

@ -1,11 +1,5 @@
#include "wifi_drivers.h"
/* */
struct wifi_driver_instance {
struct wifi_driver_ops* ops; /* Driver functions */
wifi_global_handle handle; /* Global instance handle */
};
#include "capwap_array.h"
/* Declare enable wifi driver */
#ifdef ENABLE_WIFI_DRIVERS_NL80211
@ -19,30 +13,93 @@ static struct wifi_driver_instance wifi_driver[] = {
{ NULL }
};
/* Radio instance */
static struct capwap_array* wifi_device = NULL;
/* */
int wifi_init_driver(void) {
int i;
for (i = 0; wifi_driver[i].ops != NULL; i++) {
if (!wifi_driver[i].ops->global_init) {
return -1;
}
/* Initialize driver */
ASSERT(wifi_driver[i].ops->global_init != NULL);
wifi_driver[i].handle = wifi_driver[i].ops->global_init();
}
/* Device handler */
wifi_device = capwap_array_create(sizeof(struct wifi_device), 0);
wifi_device->zeroed = 1;
return 0;
}
/* */
void wifi_free_driver(void) {
int i;
unsigned long i;
/* Free device */
if (wifi_device) {
for (i = 0; i < wifi_device->count; i++) {
struct wifi_device* device = (struct wifi_device*)capwap_array_get_item_pointer(wifi_device, i);
if (device->instance->ops->device_deinit) {
device->instance->ops->device_deinit(device->handle);
}
}
capwap_array_free(wifi_device);
}
/* Free driver */
for (i = 0; wifi_driver[i].ops != NULL; i++) {
/* Free driver */
if (wifi_driver[i].ops->global_deinit) {
wifi_driver[i].ops->global_deinit(wifi_driver[i].handle);
}
}
}
/* */
int wifi_create_device(int radioid, char* ifname, char* driver) {
int i;
int length;
int result = -1;
ASSERT(radioid > 0);
ASSERT(ifname != NULL);
ASSERT(driver != NULL);
/* Check */
length = strlen(ifname);
if ((length <= 0) || (length >= IFNAMSIZ)) {
capwap_logging_warning("Wifi device name error: %s", ifname);
return -1;
} else if (wifi_device->count >= radioid) {
capwap_logging_warning("Wifi device RadioID already used: %d", radioid);
return -1;
}
/* Search driver */
for (i = 0; wifi_driver[i].ops != NULL; i++) {
if (!strcmp(driver, wifi_driver[i].ops->name)) {
wifi_device_handle devicehandle;
struct device_init_params params = {
.ifname = ifname
};
/* Device init */
ASSERT(wifi_driver[i].ops->device_init);
devicehandle = wifi_driver[i].ops->device_init(wifi_driver[i].handle, &params);
if (devicehandle) {
/* Register new device */
struct wifi_device* device = (struct wifi_device*)capwap_array_get_item_pointer(wifi_device, radioid);
device->handle = devicehandle;
device->instance = &wifi_driver[i];
result = 0;
}
break;
}
}
return result;
}

View File

@ -8,10 +8,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include "capwap_debug.h"
#include "capwap_logging.h"
/* */
#define WIFI_DRIVER_NAME_SIZE 16
/* */
typedef void* wifi_global_handle;
typedef void* wifi_device_handle;
@ -35,8 +39,23 @@ struct wifi_driver_ops {
void (*device_deinit)(wifi_device_handle handle);
};
/* */
struct wifi_driver_instance {
struct wifi_driver_ops* ops; /* Driver functions */
wifi_global_handle handle; /* Global instance handle */
};
/* */
struct wifi_device {
wifi_device_handle handle; /* Device handle */
struct wifi_driver_instance* instance; /* Driver instance */
};
/* Initialize wifi driver engine */
int wifi_init_driver(void);
void wifi_free_driver(void);
/* */
int wifi_create_device(int radioid, char* ifname, char* driver);
#endif /* __WIFI_DRIVERS_HEADER__ */

View File

@ -1,14 +1,17 @@
#include "wifi_drivers.h"
#include <sys/types.h>
#include <unistd.h>
#include <net/if.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/nl80211.h>
#include "capwap_list.h"
#include "wifi_nl80211.h"
/* Compatibility functions */
#if !defined(HAVE_LIBNL20) && !defined(HAVE_LIBNL30)
#define nl_sock nl_handle
static uint32_t port_bitmap[32] = { 0 };
static struct nl_sock* nl_socket_alloc_cb(void* cb) {
@ -42,21 +45,275 @@ static void nl_socket_free(struct nl_sock* handle) {
#endif
/* */
wifi_device_handle nl80211_device_init(wifi_global_handle handle, struct device_init_params* params) {
return NULL;
static struct nl_sock* nl_create_handle(struct nl_cb* cb) {
struct nl_sock* handle;
handle = nl_socket_alloc_cb(cb);
if (!handle) {
return NULL;
}
if (genl_connect(handle)) {
nl_socket_free(handle);
return NULL;
}
return handle;
}
/* */
void nl80211_device_deinit(wifi_device_handle handle) {
static int nl80211_no_seq_check(struct nl_msg* msg, void* arg) {
return NL_OK;
}
/* */
static int nl80211_error_handler(struct sockaddr_nl* nla, struct nlmsgerr* err, void* arg) {
*((int*)arg) = err->error;
return NL_STOP;
}
/* */
static int nl80211_finish_handler(struct nl_msg* msg, void* arg) {
*((int*)arg) = 0;
return NL_SKIP;
}
/* */
static int nl80211_ack_handler(struct nl_msg* msg, void* arg) {
*((int*)arg) = 0;
return NL_STOP;
}
/* */
static int nl80211_send_and_recv(struct nl_sock* nl, struct nl_cb* nl_cb, struct nl_msg* msg, nl_valid_cb valid_cb, void* data) {
int result;
struct nl_cb* cb;
/* Clone netlink callback */
cb = nl_cb_clone(nl_cb);
if (!cb) {
return -1;
}
/* Complete send message */
result = nl_send_auto_complete(nl, msg);
if (result < 0) {
nl_cb_put(cb);
return -1;
}
/* Customize message callback */
nl_cb_err(cb, NL_CB_CUSTOM, nl80211_error_handler, &result);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl80211_finish_handler, &result);
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl80211_ack_handler, &result);
if (valid_cb) {
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_cb, data);
}
result = 1;
while (result > 0) {
nl_recvmsgs(nl, cb);
}
nl_cb_put(cb);
return result;
}
/* */
static int nl80211_send_and_recv_msg(struct nl80211_global_handle* globalhandle, struct nl_msg* msg, nl_valid_cb valid_cb, void* data) {
return nl80211_send_and_recv(globalhandle->nl, globalhandle->nl_cb, msg, valid_cb, data);
}
/* */
static int cb_get_phydevice_list(struct nl_msg* msg, void* data) {
struct nlattr* tb_msg[NL80211_ATTR_MAX + 1];
struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg));
struct capwap_list* list = (struct capwap_list*)data;
nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
if (tb_msg[NL80211_ATTR_WIPHY_NAME] && tb_msg[NL80211_ATTR_WIPHY]) {
struct capwap_list_item* item = capwap_itemlist_create(sizeof(struct nl80211_phydevice_item));
struct nl80211_phydevice_item* phyitem = (struct nl80211_phydevice_item*)item->item;
/* Add physical device info */
phyitem->index = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
strcpy(phyitem->name, nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
capwap_itemlist_insert_after(list, NULL, item);
}
return NL_SKIP;
}
/* */
static int nl80211_get_phydevice_list(struct nl80211_global_handle* globalhandle, struct capwap_list* list) {
int result;
struct nl_msg* msg;
ASSERT(globalhandle != NULL);
ASSERT(list != NULL);
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* Retrieve list of physical device */
genlmsg_put(msg, 0, 0, globalhandle->nl80211_id, 0, NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
/* Retrieve all physical interface */
result = nl80211_send_and_recv_msg(globalhandle, msg, cb_get_phydevice_list, list);
/* */
nlmsg_free(msg);
return result;
}
/* */
static wifi_device_handle nl80211_device_init(wifi_global_handle handle, struct device_init_params* params) {
int result;
struct capwap_list* list;
struct capwap_list_item* item;
struct nl80211_device_handle* devicehandle = NULL;
struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle;
ASSERT(params != NULL);
if (!handle) {
return NULL;
}
/* Retrieve physical device info */
list = capwap_list_create();
result = nl80211_get_phydevice_list(globalhandle, list);
if (!result) {
item = list->first;
while (item) {
struct nl80211_phydevice_item* phyitem = (struct nl80211_phydevice_item*)item->item;
if (!strcmp(phyitem->name, params->ifname)) {
/* Create device */
devicehandle = (struct nl80211_device_handle*)capwap_alloc(sizeof(struct nl80211_device_handle));
memset(devicehandle, 0, sizeof(struct nl80211_device_handle));
/* */
strcpy(devicehandle->phyname, phyitem->name);
devicehandle->phyindex = phyitem->index;
break;
}
/* Next */
item = item->next;
}
} else {
/* Error get physical devices */
capwap_logging_error("Unable retrieve physical device info, error code: %d", result);
}
/* */
capwap_list_free(list);
if (!devicehandle) {
return NULL;
}
/* */
devicehandle->globalhandle = globalhandle;
/* Save device handle into global handle */
item = capwap_itemlist_create_with_item(devicehandle, sizeof(struct nl80211_device_handle));
capwap_itemlist_insert_after(globalhandle->devicelist, NULL, item);
return devicehandle;
}
/* */
static void nl80211_device_deinit(wifi_device_handle handle) {
struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle;
if (devicehandle) {
struct capwap_list_item* search;
/* Remove device handle from global handle*/
search = devicehandle->globalhandle->devicelist->first;
while (search) {
/* Remove item from list without destroy */
if ((struct nl80211_device_handle*)search->item == devicehandle) {
capwap_itemlist_remove(devicehandle->globalhandle->devicelist, search);
break;
}
search = search->next;
}
/* */
capwap_free(devicehandle);
}
}
/* */
static wifi_global_handle nl80211_global_init(void) {
return NULL;
struct nl80211_global_handle* globalhandle;
/* */
globalhandle = (struct nl80211_global_handle*)capwap_alloc(sizeof(struct nl80211_global_handle));
memset(globalhandle, 0, sizeof(struct nl80211_global_handle));
/* Configure global netlink callback */
globalhandle->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!globalhandle->nl_cb) {
capwap_free(globalhandle);
return NULL;
}
/* Create netlink socket */
globalhandle->nl = nl_create_handle(globalhandle->nl_cb);
if (!globalhandle->nl) {
nl_cb_put(globalhandle->nl_cb);
capwap_free(globalhandle);
return NULL;
}
/* Get nl80211 netlink family */
globalhandle->nl80211_id = genl_ctrl_resolve(globalhandle->nl, "nl80211");
if (globalhandle->nl80211_id < 0) {
capwap_logging_warning("Unable to found mac80211 kernel module");
nl_socket_free(globalhandle->nl);
nl_cb_put(globalhandle->nl_cb);
capwap_free(globalhandle);
return NULL;
}
/* Configure global callback function */
nl_cb_set(globalhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL);
/* TODO */
/* Device list */
globalhandle->devicelist = capwap_list_create();
return (wifi_global_handle)globalhandle;
}
/* */
void nl80211_global_deinit(wifi_global_handle handle) {
static void nl80211_global_deinit(wifi_global_handle handle) {
struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle;
if (globalhandle) {
ASSERT(globalhandle->devicelist->count == 0);
if (globalhandle->nl) {
nl_socket_free(globalhandle->nl);
}
if (globalhandle->nl_cb) {
nl_cb_put(globalhandle->nl_cb);
}
capwap_list_free(globalhandle->devicelist);
capwap_free(globalhandle);
}
}
/* Driver function */

View File

@ -0,0 +1,35 @@
#ifndef __WIFI_NL80211_HEADER__
#define __WIFI_NL80211_HEADER__
/* Compatibility functions */
#if !defined(HAVE_LIBNL20) && !defined(HAVE_LIBNL30)
#define nl_sock nl_handle
#endif
/* */
typedef int (*nl_valid_cb)(struct nl_msg* msg, void* data);
/* Global handle */
struct nl80211_global_handle {
struct nl_sock* nl;
struct nl_cb* nl_cb;
int nl80211_id;
struct capwap_list* devicelist;
};
/* Device handle */
struct nl80211_device_handle {
struct nl80211_global_handle* globalhandle;
uint32_t phyindex;
char phyname[IFNAMSIZ];
};
/* Physical device info */
struct nl80211_phydevice_item {
uint32_t index;
char name[IFNAMSIZ];
};
#endif /* __WIFI_NL80211_HEADER__ */