diff --git a/build/wtp/Makefile.am b/build/wtp/Makefile.am index 3918aee..3419468 100755 --- a/build/wtp/Makefile.am +++ b/build/wtp/Makefile.am @@ -43,6 +43,7 @@ include $(top_srcdir)/build/Makefile_common.am wtp_SOURCES = \ $(capwap_SOURCES) \ $(top_srcdir)/src/wtp/wtp.c \ + $(top_srcdir)/src/wtp/wtp_element_helper.c \ $(top_srcdir)/src/wtp/wtp_dfa.c \ $(top_srcdir)/src/wtp/wtp_dfa_idle.c \ $(top_srcdir)/src/wtp/wtp_dfa_discovery.c \ diff --git a/src/binding/wifi/drivers/wifi_drivers.c b/src/binding/wifi/drivers/wifi_drivers.c index 966e10e..aea397c 100644 --- a/src/binding/wifi/drivers/wifi_drivers.c +++ b/src/binding/wifi/drivers/wifi_drivers.c @@ -1,4 +1,7 @@ #include "wifi_drivers.h" +#include +#include + #include "capwap_array.h" /* Declare enable wifi driver */ @@ -41,7 +44,7 @@ void wifi_free_driver(void) { 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) { + if (device->handle && device->instance->ops->device_deinit) { device->instance->ops->device_deinit(device->handle); } } @@ -103,3 +106,40 @@ int wifi_create_device(int radioid, char* ifname, char* driver) { return result; } + +/* */ +void wifi_iface_updown(int sock, const char* ifname, int up) { + int localsock = -1; + struct ifreq ifreq; + + ASSERT(ifname != NULL); + ASSERT(*ifname != 0); + + /* Check if build local socket */ + if (sock < 0) { + localsock = socket(AF_PACKET, SOCK_RAW, 0); + if (localsock < 0) { + return; + } else { + sock = localsock; + } + } + + /* Change link state of interface */ + memset(&ifreq, 0, sizeof(ifreq)); + strcpy(ifreq.ifr_name, ifname); + if (!ioctl(sock, SIOCGIFFLAGS, &ifreq)) { + if (up) { + ifreq.ifr_flags |= IFF_UP; + } else { + ifreq.ifr_flags &= ~IFF_UP; + } + + ioctl(sock, SIOCSIFFLAGS, &ifreq); + } + + /* Free local socket */ + if (localsock >= 0) { + close(localsock); + } +} diff --git a/src/binding/wifi/drivers/wifi_drivers.h b/src/binding/wifi/drivers/wifi_drivers.h index 67281b3..7181821 100644 --- a/src/binding/wifi/drivers/wifi_drivers.h +++ b/src/binding/wifi/drivers/wifi_drivers.h @@ -16,6 +16,13 @@ /* */ #define WIFI_DRIVER_NAME_SIZE 16 +/* */ +#define WIFI_CAPABILITY_AP_SUPPORTED 0x00000001 +#define WIFI_CAPABILITY_AP_VLAN_SUPPORTED 0x00000002 +#define WIFI_CAPABILITY_ADHOC_SUPPORTED 0x00000004 +#define WIFI_CAPABILITY_MONITOR_SUPPORTED 0x00000008 +#define WIFI_CAPABILITY_WDS_SUPPORTED 0x00000010 + /* */ typedef void* wifi_global_handle; typedef void* wifi_device_handle; @@ -58,4 +65,7 @@ void wifi_free_driver(void); /* */ int wifi_create_device(int radioid, char* ifname, char* driver); +/* Util functions */ +void wifi_iface_updown(int sock, const char* ifname, int up); + #endif /* __WIFI_DRIVERS_HEADER__ */ diff --git a/src/binding/wifi/drivers/wifi_nl80211.c b/src/binding/wifi/drivers/wifi_nl80211.c index 9b8950b..e91e13f 100644 --- a/src/binding/wifi/drivers/wifi_nl80211.c +++ b/src/binding/wifi/drivers/wifi_nl80211.c @@ -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 */ diff --git a/src/binding/wifi/drivers/wifi_nl80211.h b/src/binding/wifi/drivers/wifi_nl80211.h index 33a940d..ef9c0f5 100644 --- a/src/binding/wifi/drivers/wifi_nl80211.h +++ b/src/binding/wifi/drivers/wifi_nl80211.h @@ -15,6 +15,8 @@ struct nl80211_global_handle { struct nl_cb* nl_cb; int nl80211_id; + int sock_util; + struct capwap_list* devicelist; }; @@ -24,6 +26,9 @@ struct nl80211_device_handle { uint32_t phyindex; char phyname[IFNAMSIZ]; + + /* Capability */ + unsigned long physupported; }; /* Physical device info */ @@ -32,4 +37,11 @@ struct nl80211_phydevice_item { char name[IFNAMSIZ]; }; +/* Virtual device info */ +struct nl80211_virtdevice_item { + uint32_t phyindex; + uint32_t virtindex; + char virtname[IFNAMSIZ]; +}; + #endif /* __WIFI_NL80211_HEADER__ */ diff --git a/src/wtp/wtp_dfa_discovery.c b/src/wtp/wtp_dfa_discovery.c index 2c9625d..6b8a407 100644 --- a/src/wtp/wtp_dfa_discovery.c +++ b/src/wtp/wtp_dfa_discovery.c @@ -155,7 +155,6 @@ int wtp_dfa_state_discovery(struct capwap_packet* packet, struct timeout_control status = WTP_DFA_NO_PACKET; } else { - int i; int result; struct capwap_build_packet* buildpacket; @@ -168,11 +167,11 @@ int wtp_dfa_state_discovery(struct capwap_packet* packet, struct timeout_control } else { /* Update status radio */ g_wtp.descriptor.radiosinuse = wtp_update_radio_in_use(); - + /* Build packet */ buildpacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, g_wtp.binding); buildpacket->isctrlmsg = 1; - + /* Prepare discovery request */ capwap_build_packet_set_control_message_type(buildpacket, CAPWAP_DISCOVERY_REQUEST, g_wtp.localseqnumber++); capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_DISCOVERYTYPE_ELEMENT(&g_wtp.discoverytype)); @@ -180,19 +179,16 @@ int wtp_dfa_state_discovery(struct capwap_packet* packet, struct timeout_control capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPDESCRIPTOR_ELEMENT(&g_wtp.descriptor)); capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPFRAMETUNNELMODE_ELEMENT(&g_wtp.mactunnel)); capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPMACTYPE_ELEMENT(&g_wtp.mactype)); - + if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) { - for (i = 0; i < g_wtp.radios->count; i++) { - struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); - capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_80211_WTPRADIOINFORMATION_ELEMENT(&radio->radioinformation)); - } + wtp_create_80211_wtpradioinformation_element(buildpacket); } else { capwap_logging_debug("Unknown capwap binding"); } - + /* CAPWAP_CREATE_MTUDISCOVERYPADDING_ELEMENT */ /* TODO */ /* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */ - + /* Create discovery request packet */ if (!capwap_build_packet_validate(buildpacket, NULL)) { wtp_free_reference_last_request(); @@ -206,7 +202,7 @@ int wtp_dfa_state_discovery(struct capwap_packet* packet, struct timeout_control } capwap_build_packet_free(buildpacket); - + /* Send discovery request to AC */ if (result >= 0) { int i; diff --git a/src/wtp/wtp_dfa_join.c b/src/wtp/wtp_dfa_join.c index e25aae1..5c91246 100644 --- a/src/wtp/wtp_dfa_join.c +++ b/src/wtp/wtp_dfa_join.c @@ -68,14 +68,11 @@ int wtp_dfa_state_dtlsconnect_to_join(struct capwap_packet* packet, struct timeo capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPMACTYPE_ELEMENT(&g_wtp.mactype)); if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) { - for (i = 0; i < g_wtp.radios->count; i++) { - struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); - capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_80211_WTPRADIOINFORMATION_ELEMENT(&radio->radioinformation)); - } + wtp_create_80211_wtpradioinformation_element(buildpacket); } else { capwap_logging_debug("Unknown capwap binding"); } - + capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_ECNSUPPORT_ELEMENT(&g_wtp.ecn)); if (g_wtp.wtpctrladdress.ss_family == AF_INET) { @@ -245,6 +242,12 @@ int wtp_dfa_state_join_to_configure(struct capwap_packet* packet, struct timeout /* CAPWAP_CREATE_WTPSTATICIPADDRESS_ELEMENT */ /* TODO */ /* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */ + if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) { + wtp_create_80211_wtpradioinformation_element(buildpacket); + } else { + capwap_logging_debug("Unknown capwap binding"); + } + /* Create Configuration Status request packet */ if (!capwap_build_packet_validate(buildpacket, NULL)) { wtp_free_reference_last_request(); diff --git a/src/wtp/wtp_element_helper.c b/src/wtp/wtp_element_helper.c new file mode 100644 index 0000000..7e1c6f2 --- /dev/null +++ b/src/wtp/wtp_element_helper.c @@ -0,0 +1,10 @@ +#include "wtp.h" + +void wtp_create_80211_wtpradioinformation_element(struct capwap_build_packet* buildpacket) { + int i; + + for (i = 0; i < g_wtp.radios->count; i++) { + struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); + capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_80211_WTPRADIOINFORMATION_ELEMENT(&radio->radioinformation)); + } +}