first features of mac80211 driver

This commit is contained in:
vemax78
2013-05-11 15:08:28 +02:00
parent bb449e7ec6
commit 0a2ae76acc
8 changed files with 320 additions and 46 deletions

View File

@ -125,6 +125,52 @@ static int nl80211_send_and_recv_msg(struct nl80211_global_handle* globalhandle,
return nl80211_send_and_recv(globalhandle->nl, globalhandle->nl_cb, msg, valid_cb, data);
}
/* */
static int cb_get_virtdevice_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] && tb_msg[NL80211_ATTR_IFNAME] && tb_msg[NL80211_ATTR_IFINDEX]) {
struct capwap_list_item* item = capwap_itemlist_create(sizeof(struct nl80211_virtdevice_item));
struct nl80211_virtdevice_item* virtitem = (struct nl80211_virtdevice_item*)item->item;
/* Add virtual device info */
virtitem->phyindex = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
virtitem->virtindex = nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX]);
strcpy(virtitem->virtname, nla_get_string(tb_msg[NL80211_ATTR_IFNAME]));
capwap_itemlist_insert_after(list, NULL, item);
}
return NL_SKIP;
}
/* */
static int nl80211_get_virtdevice_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;
}
genlmsg_put(msg, 0, 0, globalhandle->nl80211_id, 0, NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0);
/* Retrieve all virtual interface */
result = nl80211_send_and_recv_msg(globalhandle, msg, cb_get_virtdevice_list, list);
/* */
nlmsg_free(msg);
return result;
}
/* */
static int cb_get_phydevice_list(struct nl_msg* msg, void* data) {
struct nlattr* tb_msg[NL80211_ATTR_MAX + 1];
@ -160,7 +206,6 @@ static int nl80211_get_phydevice_list(struct nl80211_global_handle* globalhandle
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 */
@ -171,6 +216,139 @@ static int nl80211_get_phydevice_list(struct nl80211_global_handle* globalhandle
return result;
}
/* */
static int cb_get_phydevice_capability(struct nl_msg* msg, void* data) {
struct nlattr* tb_msg[NL80211_ATTR_MAX + 1];
struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg));
struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)data;
nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
if (tb_msg[NL80211_ATTR_WIPHY] && (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]) == devicehandle->phyindex)) {
/* Interface supported */
if (tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) {
int i;
struct nlattr* nl_mode;
devicehandle->physupported = 0;
nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
switch (nla_type(nl_mode)) {
case NL80211_IFTYPE_AP: {
devicehandle->physupported |= WIFI_CAPABILITY_AP_SUPPORTED;
break;
}
case NL80211_IFTYPE_AP_VLAN: {
devicehandle->physupported |= WIFI_CAPABILITY_AP_VLAN_SUPPORTED;
break;
}
case NL80211_IFTYPE_ADHOC: {
devicehandle->physupported |= WIFI_CAPABILITY_ADHOC_SUPPORTED;
break;
}
case NL80211_IFTYPE_WDS: {
devicehandle->physupported |= WIFI_CAPABILITY_WDS_SUPPORTED;
break;
}
case NL80211_IFTYPE_MONITOR: {
devicehandle->physupported |= WIFI_CAPABILITY_MONITOR_SUPPORTED;
break;
}
}
}
}
}
return NL_SKIP;
}
/* */
static int nl80211_get_phydevice_capability(struct nl80211_device_handle* devicehandle) {
int result;
struct nl_msg* msg;
ASSERT(devicehandle != NULL);
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_GET_WIPHY, 0);
nla_put_u32(msg, NL80211_ATTR_WIPHY, devicehandle->phyindex);
/* Retrieve physical device capability */
result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, cb_get_phydevice_capability, devicehandle);
/* */
nlmsg_free(msg);
return result;
}
/* */
static int nl80211_destroy_virtdevice(struct nl80211_global_handle* globalhandle, uint32_t virtindex) {
int result;
struct nl_msg* msg;
ASSERT(globalhandle != NULL);
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
genlmsg_put(msg, 0, 0, globalhandle->nl80211_id, 0, 0, NL80211_CMD_DEL_INTERFACE, 0);
nla_put_u32(msg, NL80211_ATTR_IFINDEX, virtindex);
/* Destroy virtual device */
result = nl80211_send_and_recv_msg(globalhandle, msg, NULL, NULL);
/* */
nlmsg_free(msg);
return result;
}
/* */
static void nl80211_destroy_all_virtdevice(struct nl80211_global_handle* globalhandle, uint32_t phyindex) {
int result;
struct capwap_list* list;
/* Retrieve all virtual device */
list = capwap_list_create();
result = nl80211_get_virtdevice_list(globalhandle, list);
if (!result) {
struct capwap_list_item* item = list->first;
/* Search virtual device by physical device */
while (item) {
struct nl80211_virtdevice_item* virtitem = (struct nl80211_virtdevice_item*)item->item;
/* Destroy virtual device */
if (virtitem->phyindex == phyindex) {
wifi_iface_updown(globalhandle->sock_util, virtitem->virtname, 0);
result = nl80211_destroy_virtdevice(globalhandle, virtitem->virtindex);
if (result) {
capwap_logging_error("Unable to destroy virtual device, error code: %d", result);
}
}
/* Next */
item = item->next;
}
} else {
/* Error get virtual devices */
capwap_logging_error("Unable retrieve virtual device info, error code: %d", result);
}
/* */
capwap_list_free(list);
}
/* */
static wifi_device_handle nl80211_device_init(wifi_global_handle handle, struct device_init_params* params) {
int result;
@ -222,8 +400,18 @@ static wifi_device_handle nl80211_device_init(wifi_global_handle handle, struct
/* */
devicehandle->globalhandle = globalhandle;
/* Remove all virtual adapter from wifi device */
nl80211_destroy_all_virtdevice(globalhandle, devicehandle->phyindex);
/* Retrieve wifi device capability */
result = nl80211_get_phydevice_capability(devicehandle);
if (result) {
capwap_logging_error("Unable retrieve physical device capability, error code: %d", result);
}
/* Save device handle into global handle */
item = capwap_itemlist_create_with_item(devicehandle, sizeof(struct nl80211_device_handle));
item->autodelete = 0;
capwap_itemlist_insert_after(globalhandle->devicelist, NULL, item);
return devicehandle;
@ -239,9 +427,12 @@ static void nl80211_device_deinit(wifi_device_handle handle) {
/* 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);
/* Remove all virtual adapter from wifi device */
nl80211_destroy_all_virtdevice(devicehandle->globalhandle, devicehandle->phyindex);
/* Remove item from list */
capwap_itemlist_free(capwap_itemlist_remove(devicehandle->globalhandle->devicelist, search));
break;
}
@ -253,6 +444,32 @@ static void nl80211_device_deinit(wifi_device_handle handle) {
}
}
/* */
static void nl80211_global_deinit(wifi_global_handle handle) {
struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle;
if (globalhandle) {
if (globalhandle->nl) {
nl_socket_free(globalhandle->nl);
}
if (globalhandle->nl_cb) {
nl_cb_put(globalhandle->nl_cb);
}
if (globalhandle->devicelist) {
ASSERT(globalhandle->devicelist->count == 0);
capwap_list_free(globalhandle->devicelist);
}
if (globalhandle->sock_util >= 0) {
close(globalhandle->sock_util);
}
capwap_free(globalhandle);
}
}
/* */
static wifi_global_handle nl80211_global_init(void) {
struct nl80211_global_handle* globalhandle;
@ -260,19 +477,19 @@ static wifi_global_handle nl80211_global_init(void) {
/* */
globalhandle = (struct nl80211_global_handle*)capwap_alloc(sizeof(struct nl80211_global_handle));
memset(globalhandle, 0, sizeof(struct nl80211_global_handle));
globalhandle->sock_util = -1;
/* Configure global netlink callback */
globalhandle->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!globalhandle->nl_cb) {
capwap_free(globalhandle);
nl80211_global_deinit((wifi_global_handle)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);
nl80211_global_deinit((wifi_global_handle)globalhandle);
return NULL;
}
@ -280,9 +497,7 @@ static wifi_global_handle nl80211_global_init(void) {
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);
nl80211_global_deinit((wifi_global_handle)globalhandle);
return NULL;
}
@ -293,27 +508,14 @@ static wifi_global_handle nl80211_global_init(void) {
/* Device list */
globalhandle->devicelist = capwap_list_create();
return (wifi_global_handle)globalhandle;
}
/* */
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);
/* Socket utils */
globalhandle->sock_util = socket(AF_PACKET, SOCK_RAW, 0);
if (globalhandle->sock_util < 0) {
nl80211_global_deinit((wifi_global_handle)globalhandle);
return NULL;
}
return (wifi_global_handle)globalhandle;
}
/* Driver function */