diff --git a/build/wtp/Makefile.am b/build/wtp/Makefile.am index 065e572..5af0af1 100755 --- a/build/wtp/Makefile.am +++ b/build/wtp/Makefile.am @@ -55,6 +55,7 @@ wtp_SOURCES = \ $(top_srcdir)/src/wtp/wtp_dfa_imagedata.c \ $(top_srcdir)/src/wtp/wtp_radio.c \ $(top_srcdir)/src/binding/ieee80211/ieee80211.c \ + $(top_srcdir)/src/binding/ieee80211/netlink_link.c \ $(top_srcdir)/src/binding/ieee80211/wifi_drivers.c wtp_LDADD = \ diff --git a/conf/wtp.conf b/conf/wtp.conf index 2b9c754..3409b7d 100755 --- a/conf/wtp.conf +++ b/conf/wtp.conf @@ -80,7 +80,7 @@ application: { radio = ( { - device = "phy0"; + device = "phy0"; enabled = true; driver = "nl80211"; mode = "g"; @@ -93,7 +93,8 @@ application: { fragmentationthreshold = 2346; txmsdulifetime = 512; rxmsdulifetime = 512; - maxbssid = 4; + maxbssid = 1; + bssprefixname = "ap"; dtimperiod = 1; beaconperiod = 100; antenna = { diff --git a/configure.ac b/configure.ac index 59bc2f6..ec0c88d 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,7 @@ AC_INIT([PRODUCT_NAME], [PRODUCT_VERSION], [PRODUCT_BUGREPORT], [PRODUCT_TARNAME AC_CONFIG_AUX_DIR([.]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE +AC_USE_SYSTEM_EXTENSIONS # cross-compile macros AC_CANONICAL_BUILD @@ -113,6 +114,11 @@ CFLAGS="${old_CFLAGS}" AM_CONDITIONAL([DEBUG_BUILD], [test "$enable_debug" = yes]) if test "${enable_debug}" = "yes"; then CFLAGS="${CFLAGS} -DDEBUG -Wall -Werror -g -O0" + + AC_CHECK_HEADERS([execinfo.h], [have_backtrace="yes"],[]) + if test "x${have_backtrace}" = "xyes"; then + AC_DEFINE([USE_DEBUG_BACKTRACE], [1], [Use debug backtrace]) + fi else CFLAGS="${CFLAGS} -O2" AC_DEFINE([DISABLE_LOGGING_DEBUG], [1], [Disable logging debug]) @@ -120,7 +126,6 @@ fi # AC_PROG_INSTALL -AC_USE_SYSTEM_EXTENSIONS AC_LANG(C) @@ -211,25 +216,19 @@ if test "${enable_ac}" = "yes"; then fi # Check nl80211 -has_libnl_ver=0 -PKG_CHECK_MODULES( - [LIBNL], - [libnl-3.0 >= 3.0 libnl-genl-3.0 >= 3.0], - [AC_DEFINE([HAVE_LIBNL30], [1], [Use libnl-3.0 library])], - [PKG_CHECK_MODULES( +if test "${enable_wifi_drivers_nl80211}" = "yes"; then + PKG_CHECK_MODULES( [LIBNL], - [libnl-2.0 >= 2.0], - [AC_DEFINE([HAVE_LIBNL20], [1], [Use libnl-2.0 library])], + [libnl-1], + [AC_DEFINE([HAVE_LIBNL_10], [1], [Use libnl-1.0 library])], [PKG_CHECK_MODULES( [LIBNL], - [libnl-1], - [AC_DEFINE([HAVE_LIBNL10], [1], [Use libnl-1.0 library])], - [AC_MSG_ERROR(You need the libnl and libnl-genl)] + [libnl-tiny], + [AC_DEFINE([HAVE_LIBNL_TINY], [1], [Use libnl-tiny library])], + [AC_MSG_ERROR(You need the libnl or libnl-tiny)] )] - )] -) + ) -if test "${enable_wifi_drivers_nl80211}" = "yes"; then AC_CHECK_HEADERS([netlink/genl/genl.h netlink/genl/family.h netlink/genl/ctrl.h], [], [AC_MSG_ERROR(You need the netlink header)]) AC_CHECK_HEADER([linux/nl80211.h], [], [AC_MSG_ERROR(You need the nl80211 header)]) AC_DEFINE([ENABLE_WIFI_DRIVERS_NL80211], [1], [Enable WTP support for nl80211 wifi binding]) @@ -266,7 +265,7 @@ if test "${with_ssl_library}" = "openssl"; then )] ) - if test "${have_openssl_ssl}" = "yes"; then + if test "x${have_openssl_ssl}" = "xyes"; then have_openssl_engine="yes" OPENSSL_SSL_LIBS="${OPENSSL_SSL_LIBS} -ldl" #saved_CFLAGS="${CFLAGS}" @@ -293,7 +292,7 @@ case "${with_ssl_library}" in have_crypto_ssl="${have_openssl_ssl}" SSL_CFLAGS="${OPENSSL_CRYPTO_CFLAGS} ${OPENSSL_SSL_CFLAGS}" SSL_LIBS="${OPENSSL_SSL_LIBS}" - test "${have_crypto_engine}" = "yes" && AC_DEFINE([HAVE_OPENSSL_ENGINE], [1], [Use ssl library]) + test "x${have_crypto_engine}" = "xyes" && AC_DEFINE([HAVE_OPENSSL_ENGINE], [1], [Use ssl library]) ;; cyassl) have_crypto_engine="${have_cyassl_engine}" @@ -301,14 +300,14 @@ case "${with_ssl_library}" in have_crypto_ssl="${have_cyassl_ssl}" SSL_CFLAGS="" SSL_LIBS="-lcyassl" - test "${have_crypto_engine}" = "yes" && AC_DEFINE([HAVE_CYASSL_ENGINE], [1], [Use ssl library]) + test "x${have_crypto_engine}" = "xyes" && AC_DEFINE([HAVE_CYASSL_ENGINE], [1], [Use ssl library]) ;; esac if test "${enable_dtls}" = "yes"; then - test "${have_crypto_engine}" != "yes" && AC_MSG_ERROR([${with_ssl_library} engine is required but missing]) - test "${have_crypto_ssl}" != "yes" && AC_MSG_ERROR([${with_ssl_library} ssl is required but missing]) - test "${have_crypto_crypto}" != "yes" && AC_MSG_ERROR([${with_ssl_library} crypto is required but missing]) + test "x${have_crypto_engine}" != "xyes" && AC_MSG_ERROR([${with_ssl_library} engine is required but missing]) + test "x${have_crypto_ssl}" != "xyes" && AC_MSG_ERROR([${with_ssl_library} ssl is required but missing]) + test "x${have_crypto_crypto}" != "xyes" && AC_MSG_ERROR([${with_ssl_library} crypto is required but missing]) AC_DEFINE([ENABLE_DTLS], [1], [Enable DTLS]) fi diff --git a/src/binding/ieee80211/ieee80211.h b/src/binding/ieee80211/ieee80211.h index ba37c33..ad0edc6 100644 --- a/src/binding/ieee80211/ieee80211.h +++ b/src/binding/ieee80211/ieee80211.h @@ -12,6 +12,7 @@ /* Global values */ #define IEEE80211_MTU 2304 #define IEEE80211_SUPPORTEDRATE_MAX_COUNT 16 +#define IEEE80211_MAX_STATIONS 2007 /* Radio type with value same of IEEE802.11 Radio Information Message Element */ #define IEEE80211_RADIO_TYPE_80211B 0x00000001 diff --git a/src/binding/ieee80211/netlink_link.c b/src/binding/ieee80211/netlink_link.c new file mode 100644 index 0000000..535bb2f --- /dev/null +++ b/src/binding/ieee80211/netlink_link.c @@ -0,0 +1,156 @@ +#include "capwap.h" +#include +#include "wifi_drivers.h" +#include "netlink_link.h" + +/* */ +struct netlink_request { + struct nlmsghdr hdr; + struct ifinfomsg ifinfo; + char opts[16]; +}; + +/* */ +struct netlink* netlink_init(void) { + int sock; + struct sockaddr_nl local; + struct netlink* netlinkhandle; + + /* Create netlink socket */ + sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sock < 0) { + return NULL; + } + + /* Bind to kernel */ + memset(&local, 0, sizeof(struct sockaddr_nl)); + local.nl_family = AF_NETLINK; + local.nl_groups = RTMGRP_LINK; + if (bind(sock, (struct sockaddr*)&local, sizeof(struct sockaddr_nl)) < 0) { + close(sock); + return NULL; + } + + /* Netlink reference */ + netlinkhandle = (struct netlink*)capwap_alloc(sizeof(struct netlink)); + netlinkhandle->sock = sock; + netlinkhandle->nl_sequence = 1; + + return netlinkhandle; +} + +/* */ +void netlink_free(struct netlink* netlinkhandle) { + ASSERT(netlinkhandle != NULL); + ASSERT(netlinkhandle->sock >= 0); + + /* */ + close(netlinkhandle->sock); + capwap_free(netlinkhandle); +} + +/* */ +void netlink_event_receive(int fd, void** params, int paramscount) { + int result; + struct netlink* netlinkhandle; + struct sockaddr_nl from; + socklen_t fromlen; + char buffer[8192]; + struct nlmsghdr* message; + + ASSERT(fd >= 0); + ASSERT(params != NULL); + ASSERT(paramscount == 2); + + /* */ + netlinkhandle = (struct netlink*)params[0]; + + /* Retrieve all netlink message */ + for (;;) { + /* Get message */ + fromlen = sizeof(struct sockaddr_nl); + result = recvfrom(netlinkhandle->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&from, &fromlen); + if (result <= 0) { + if (errno == EINTR) { + continue; + } + + /* */ + break; + } + + /* Parsing message */ + message = (struct nlmsghdr*)buffer; + while (NLMSG_OK(message, result)) { + switch (message->nlmsg_type) { + case RTM_NEWLINK: { + if (netlinkhandle->newlink_event && NLMSG_PAYLOAD(message, 0) >= sizeof(struct ifinfomsg)) { + netlinkhandle->newlink_event((wifi_global_handle)params[1], NLMSG_DATA(message), (uint8_t*)(NLMSG_DATA(message) + NLMSG_ALIGN(sizeof(struct ifinfomsg))), NLMSG_PAYLOAD(message, sizeof(struct ifinfomsg))); + } + + break; + } + + case RTM_DELLINK: { + if (netlinkhandle->dellink_event && NLMSG_PAYLOAD(message, 0) >= sizeof(struct ifinfomsg)) { + netlinkhandle->dellink_event((wifi_global_handle)params[1], NLMSG_DATA(message), (uint8_t*)(NLMSG_DATA(message) + NLMSG_ALIGN(sizeof(struct ifinfomsg))), NLMSG_PAYLOAD(message, sizeof(struct ifinfomsg))); + } + + break; + } + } + + /* */ + message = NLMSG_NEXT(message, result); + } + } +} + +int netlink_set_link_status(struct netlink* netlinkhandle, int ifindex, int linkmode, int operstate) { + char* data; + struct rtattr* rta; + struct netlink_request request; + + ASSERT(netlinkhandle != NULL); + ASSERT(ifindex >= 0); + + /* */ + memset(&request, 0, sizeof(struct netlink_request)); + request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + request.hdr.nlmsg_type = RTM_SETLINK; + request.hdr.nlmsg_flags = NLM_F_REQUEST; + request.hdr.nlmsg_seq = netlinkhandle->nl_sequence++; + request.hdr.nlmsg_pid = 0; + request.ifinfo.ifi_family = AF_UNSPEC; + request.ifinfo.ifi_type = 0; + request.ifinfo.ifi_index = ifindex; + request.ifinfo.ifi_flags = 0; + request.ifinfo.ifi_change = 0; + + if (linkmode != -1) { + rta = (struct rtattr*)((char*)&request + NLMSG_ALIGN(request.hdr.nlmsg_len)); + rta->rta_type = IFLA_LINKMODE; + rta->rta_len = RTA_LENGTH(sizeof(char)); + data = (char*)RTA_DATA(rta); + *data = (char)linkmode; + request.hdr.nlmsg_len = NLMSG_ALIGN(request.hdr.nlmsg_len) + RTA_LENGTH(sizeof(char)); + } + + if (operstate != -1) { + rta = (struct rtattr*)((char*)&request + NLMSG_ALIGN(request.hdr.nlmsg_len)); + rta->rta_type = IFLA_OPERSTATE; + rta->rta_len = RTA_LENGTH(sizeof(char)); + data = (char*)RTA_DATA(rta); + *data = (char)operstate; + request.hdr.nlmsg_len = NLMSG_ALIGN(request.hdr.nlmsg_len) + RTA_LENGTH(sizeof(char)); + } + + /* Send new interface operation state */ + if (send(netlinkhandle->sock, &request, request.hdr.nlmsg_len, 0) < 0) { + capwap_logging_debug("*** netlink_set_link_status error"); + return -1; + } + + capwap_logging_debug("*** netlink_set_link_status complete"); + return 0; +} diff --git a/src/binding/ieee80211/netlink_link.h b/src/binding/ieee80211/netlink_link.h new file mode 100644 index 0000000..e388ae8 --- /dev/null +++ b/src/binding/ieee80211/netlink_link.h @@ -0,0 +1,59 @@ +#ifndef __NETLINK_LINK_HEADER__ +#define __NETLINK_LINK_HEADER__ + +#include +#include + +/* */ +#ifndef IFLA_IFNAME +#define IFLA_IFNAME 3 +#endif + +#ifndef IFLA_WIRELESS +#define IFLA_WIRELESS 11 +#endif + +#ifndef IFLA_OPERSTATE +#define IFLA_OPERSTATE 16 +#endif + +#ifndef IFLA_LINKMODE +#define IFLA_LINKMODE 17 +#endif + +#ifndef IF_OPER_DORMANT +#define IF_OPER_DORMANT 5 +#endif + +#ifndef IF_OPER_UP +#define IF_OPER_UP 6 +#endif + +#ifndef IFF_LOWER_UP +#define IFF_LOWER_UP 0x10000 +#endif + +#ifndef IFF_DORMANT +#define IFF_DORMANT 0x20000 +#endif + +/* */ +struct netlink { + int sock; + void (*newlink_event)(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length); + void (*dellink_event)(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length); + + int nl_sequence; +}; + +/* */ +struct netlink* netlink_init(void); +void netlink_free(struct netlink* netlinkhandle); + +/* */ +int netlink_set_link_status(struct netlink* netlinkhandle, int ifindex, int linkmode, int operstate); + +/* */ +void netlink_event_receive(int fd, void** params, int paramscount); + +#endif /* __NETLINK_LINK_HEADER__ */ diff --git a/src/binding/ieee80211/wifi_drivers.c b/src/binding/ieee80211/wifi_drivers.c index ff1ffba..987055f 100644 --- a/src/binding/ieee80211/wifi_drivers.c +++ b/src/binding/ieee80211/wifi_drivers.c @@ -1,7 +1,6 @@ #include "capwap.h" -#include "capwap_array.h" +#include "capwap_list.h" #include "capwap_element.h" -#include "wtp_radio.h" #include "wifi_drivers.h" /* Declare enable wifi driver */ @@ -17,276 +16,25 @@ static struct wifi_driver_instance wifi_driver[] = { }; /* Radio instance */ -static struct capwap_array* g_wifidevice = NULL; +static struct capwap_list* g_wifidevice = NULL; /* */ -int wifi_driver_init(void) { - int i; - - for (i = 0; wifi_driver[i].ops != NULL; i++) { - /* Initialize driver */ - ASSERT(wifi_driver[i].ops->global_init != NULL); - wifi_driver[i].handle = wifi_driver[i].ops->global_init(); - if (!wifi_driver[i].handle) { - return -1; - } - } - - /* Device handler */ - g_wifidevice = capwap_array_create(sizeof(struct wifi_device), 0, 1); - - return 0; -} - -/* */ -void wifi_driver_free(void) { - unsigned long i; - unsigned long j; - - /* Free device */ - if (g_wifidevice) { - for (i = 0; i < g_wifidevice->count; i++) { - struct wifi_device* device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, i); - - if (device->wlan) { - if (device->instance->ops->wlan_delete != NULL) { - for (j = 0; j < device->wlan->count; j++) { - struct wifi_wlan* wlan = (struct wifi_wlan*)capwap_array_get_item_pointer(device->wlan, j); - - if (wlan->handle) { - device->instance->ops->wlan_delete(wlan->handle); - } - } - } - - capwap_array_free(device->wlan); - } - - if (device->handle && device->instance->ops->device_deinit) { - device->instance->ops->device_deinit(device->handle); - } - } - - capwap_array_free(g_wifidevice); - } - - /* Free driver */ - for (i = 0; wifi_driver[i].ops != NULL; i++) { - if (wifi_driver[i].ops->global_deinit) { - wifi_driver[i].ops->global_deinit(wifi_driver[i].handle); - } - } -} - -/* */ -int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count) { - int i, j; - int result = 0; - - if ((count > 0) && (!fds || !events)) { - return -1; - } - - /* Get from driver */ - for (i = 0; wifi_driver[i].ops != NULL; i++) { - if (wifi_driver[i].ops->global_getfdevent) { - result += wifi_driver[i].ops->global_getfdevent(wifi_driver[i].handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); - } - } - - /* Get from device */ - for (i = 0; i < g_wifidevice->count; i++) { - struct wifi_device* device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, i); - if (device->handle) { - if (device->instance->ops->device_getfdevent) { - result += device->instance->ops->device_getfdevent(device->handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); - } - - /* Get from wlan */ - if (device->instance->ops->wlan_getfdevent) { - for (j = 0; j < device->wlan->count; j++) { - struct wifi_wlan* wlan = (struct wifi_wlan*)capwap_array_get_item_pointer(device->wlan, j); - - if (wlan->handle) { - result += device->instance->ops->wlan_getfdevent(wlan->handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); - } - } - } - } - } - - return result; -} - -/* */ -int wifi_device_connect(int radioid, const char* ifname, const 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 (g_wifidevice->count >= radioid) { - struct wifi_device* device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, radioid); - - if (device->handle) { - 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, ¶ms); - if (devicehandle) { - /* Register new device */ - struct wifi_device* device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, radioid); - device->handle = devicehandle; - device->instance = &wifi_driver[i]; - device->wlan = capwap_array_create(sizeof(struct wifi_wlan), 0, 1); - - result = 0; - } - - break; - } - } - - return result; -} - -/* */ -static struct wifi_device* wifi_device_getdevice(int radioid) { - struct wifi_device* device; - - ASSERT(radioid > 0); - - if (g_wifidevice->count < radioid) { - return NULL; - } - - /* Get radio connection */ - device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, radioid); - if (!device->handle) { - return NULL; - } - - return device; -} - -/* */ -static struct wifi_wlan* wifi_wlan_getdevice(int radioid, int wlanid) { - struct wifi_device* device; - - ASSERT(radioid > 0); - ASSERT(wlanid > 0); - - if (g_wifidevice->count < radioid) { - return NULL; - } - - /* Get radio connection */ - device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, radioid); - if (!device->handle || (device->wlan->count < wlanid)) { - return NULL; - } - - /* */ - if (device->wlan->count < wlanid) { - return NULL; - } - - /* Return wlan connection */ - return (struct wifi_wlan*)capwap_array_get_item_pointer(device->wlan, wlanid); -} - -/* */ -int wifi_wlan_create(int radioid, int wlanid, const char* ifname, uint8_t* bssid) { - int length; - struct wifi_device* device; - struct wifi_wlan* wlan; - wifi_wlan_handle wlanhandle; - struct wlan_init_params params; - - ASSERT(radioid > 0); - ASSERT(wlanid > 0); - ASSERT(ifname != NULL); - //ASSERT(bssid != NULL); - - /* Check */ - length = strlen(ifname); - if ((length <= 0) || (length >= IFNAMSIZ)) { - capwap_logging_warning("Wifi device name error: %s", ifname); - return -1; - } else if (g_wifidevice->count < radioid) { - capwap_logging_warning("Wifi device RadioID %d is not connected", radioid); - return -1; - } - - /* Get radio connection */ - device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, radioid); - if (!device->handle) { - capwap_logging_warning("Wifi device RadioID %d is not connected", radioid); - return -1; - } else if (device->wlan->count >= wlanid) { - wlan = (struct wifi_wlan*)capwap_array_get_item_pointer(device->wlan, wlanid); - if (wlan->handle) { - capwap_logging_warning("WLAN interface already used: %d", wlanid); - return -1; - } - } else if (!device->instance->ops->wlan_create) { - capwap_logging_warning("%s library don't support wlan_create", device->instance->ops->name); - return -1; - } - - /* Create interface */ - params.ifname = ifname; - params.type = WLAN_INTERFACE_AP; - wlanhandle = device->instance->ops->wlan_create(device->handle, ¶ms); - if (!wlanhandle) { - capwap_logging_warning("Unable to create virtual interface: %s", ifname); - return -1; - } - - /* */ - wlan = (struct wifi_wlan*)capwap_array_get_item_pointer(device->wlan, wlanid); - wlan->handle = wlanhandle; - wlan->device = device; - - return 0; -} - -/* */ -static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* radio, struct device_setrates_params* device_params) { +static void wifi_wlan_getrates(struct wifi_device* device, uint8_t* rates, int ratescount, struct device_setrates_params* device_params) { int i, j, w; int radiotype; uint32_t mode = 0; const struct wifi_capability* capability; ASSERT(device != NULL); - ASSERT(radio != NULL); - ASSERT(radio->rateset.ratesetcount > 0); + ASSERT(rates != NULL); + ASSERT(ratescount > 0); + ASSERT(device_params != NULL); /* */ memset(device_params, 0, sizeof(struct device_setrates_params)); /* Retrieve capability */ - capability = wifi_device_getcapability(radio->radioid); + capability = wifi_device_getcapability(device); if (!capability) { return; } @@ -298,19 +46,19 @@ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* rad } /* Check type of rate mode */ - for (i = 0; i < radio->rateset.ratesetcount; i++) { + for (i = 0; i < ratescount; i++) { if (device->currentfreq.band == WIFI_BAND_2GHZ) { - if (IS_IEEE80211_RATE_B(radio->rateset.rateset[i])) { + if (IS_IEEE80211_RATE_B(rates[i])) { mode |= CAPWAP_RADIO_TYPE_80211B; - } else if (IS_IEEE80211_RATE_G(radio->rateset.rateset[i])) { + } else if (IS_IEEE80211_RATE_G(rates[i])) { mode |= CAPWAP_RADIO_TYPE_80211G; - } else if (IS_IEEE80211_RATE_N(radio->rateset.rateset[i])) { + } else if (IS_IEEE80211_RATE_N(rates[i])) { mode |= CAPWAP_RADIO_TYPE_80211N; } } else if (device->currentfreq.band == WIFI_BAND_5GHZ) { - if (IS_IEEE80211_RATE_A(radio->rateset.rateset[i])) { + if (IS_IEEE80211_RATE_A(rates[i])) { mode |= CAPWAP_RADIO_TYPE_80211A; - } else if (IS_IEEE80211_RATE_N(radio->rateset.rateset[i])) { + } else if (IS_IEEE80211_RATE_N(rates[i])) { mode |= CAPWAP_RADIO_TYPE_80211N; } } @@ -330,12 +78,12 @@ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* rad if (bandcap->band == device->currentfreq.band) { for (j = 0; j < bandcap->rate->count; j++) { - struct wifi_rate_capability* rate = (struct wifi_rate_capability*)capwap_array_get_item_pointer(bandcap->rate, j); + struct wifi_rate_capability* ratecapability = (struct wifi_rate_capability*)capwap_array_get_item_pointer(bandcap->rate, j); /* Validate rate */ - for (w = 0; w < radio->rateset.ratesetcount; w++) { - if (radio->rateset.rateset[w] == rate->bitrate) { - device_params->supportedrates[device_params->supportedratescount++] = rate->bitrate; + for (w = 0; w < ratescount; w++) { + if (rates[w] == ratecapability->bitrate) { + device_params->supportedrates[device_params->supportedratescount++] = ratecapability->bitrate; break; } } @@ -372,85 +120,162 @@ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* rad } /* */ -int wifi_wlan_startap(int radioid, int wlanid, struct wifi_wlan_startap_params* params) { - struct wifi_wlan* wlan; - struct wlan_startap_params wlan_params; +int wifi_driver_init(void) { + int i; - ASSERT(radioid > 0); - ASSERT(wlanid > 0); - - /* */ - wlan = wifi_wlan_getdevice(radioid, wlanid); - if (!wlan || !wlan->device->instance->ops->wlan_startap) { - return -1; + for (i = 0; wifi_driver[i].ops != NULL; i++) { + /* Initialize driver */ + ASSERT(wifi_driver[i].ops->global_init != NULL); + wifi_driver[i].handle = wifi_driver[i].ops->global_init(); + if (!wifi_driver[i].handle) { + return -1; + } } - /* Start AP */ - memset(&wlan_params, 0, sizeof(struct wlan_startap_params)); - wlan_params.ssid = params->ssid; - wlan_params.ssid_hidden = params->ssid_hidden; - wlan_params.capability = params->capability; - wlan_params.authenticationtype = params->authmode; + /* Device handler */ + g_wifidevice = capwap_list_create(); - return wlan->device->instance->ops->wlan_startap(wlan->handle, &wlan_params); + return 0; } /* */ -int wifi_wlan_stopap(int radioid, int wlanid) { - struct wifi_wlan* wlan; +void wifi_driver_free(void) { + unsigned long i; + struct capwap_list_item* itemdevice; + struct capwap_list_item* itemwlan; - /* */ - wlan = wifi_wlan_getdevice(radioid, wlanid); - if (!wlan->device->instance->ops->wlan_stopap) { - return -1; - } + /* Free device */ + if (g_wifidevice) { + for (itemdevice = g_wifidevice->first; itemdevice != NULL; itemdevice = itemdevice->next) { + struct wifi_device* device = (struct wifi_device*)itemdevice->item; - return wlan->device->instance->ops->wlan_stopap(wlan->handle); -} + if (device->wlan) { + if (device->instance->ops->wlan_delete != NULL) { + for (itemwlan = device->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { + struct wifi_wlan* wlan = (struct wifi_wlan*)itemwlan->item; -/* */ -int wifi_wlan_getbssid(int radioid, int wlanid, uint8_t* bssid) { - struct wifi_wlan* wlan; + if (wlan->handle) { + device->instance->ops->wlan_delete(wlan->handle); + } + } + } - /* */ - wlan = wifi_wlan_getdevice(radioid, wlanid); - if (!wlan->device->instance->ops->wlan_getmacaddress) { - return -1; - } + capwap_list_free(device->wlan); + } - return wlan->device->instance->ops->wlan_getmacaddress(wlan->handle, bssid); -} - -/* */ -void wifi_wlan_destroy(int radioid, int wlanid) { - struct wifi_wlan* wlan; - - ASSERT(radioid > 0); - ASSERT(wlanid > 0); - - wlan = wifi_wlan_getdevice(radioid, wlanid); - if (wlan && wlan->handle) { - if (wlan->device->instance->ops->wlan_delete) { - wlan->device->instance->ops->wlan_delete(wlan->handle); + if (device->handle && device->instance->ops->device_deinit) { + device->instance->ops->device_deinit(device->handle); + } } - memset(wlan, 0, sizeof(struct wifi_wlan)); + capwap_list_free(g_wifidevice); + } + + /* Free driver */ + for (i = 0; wifi_driver[i].ops != NULL; i++) { + if (wifi_driver[i].ops->global_deinit) { + wifi_driver[i].ops->global_deinit(wifi_driver[i].handle); + } } } /* */ -const struct wifi_capability* wifi_device_getcapability(int radioid) { - struct wifi_device* device; +int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count) { + int i; + int result = 0; + struct capwap_list_item* itemdevice; + struct capwap_list_item* itemwlan; - ASSERT(radioid > 0); + if ((count > 0) && (!fds || !events)) { + return -1; + } - if (g_wifidevice->count <= radioid) { + /* Get from driver */ + for (i = 0; wifi_driver[i].ops != NULL; i++) { + if (wifi_driver[i].ops->global_getfdevent) { + result += wifi_driver[i].ops->global_getfdevent(wifi_driver[i].handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); + } + } + + /* Get from device */ + for (itemdevice = g_wifidevice->first; itemdevice != NULL; itemdevice = itemdevice->next) { + struct wifi_device* device = (struct wifi_device*)itemdevice->item; + if (device->handle) { + if (device->instance->ops->device_getfdevent) { + result += device->instance->ops->device_getfdevent(device->handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); + } + + /* Get from wlan */ + if (device->wlan && device->instance->ops->wlan_getfdevent) { + for (itemwlan = device->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { + struct wifi_wlan* wlan = (struct wifi_wlan*)itemwlan->item; + + if (wlan->handle) { + result += device->instance->ops->wlan_getfdevent(wlan->handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); + } + } + } + } + } + + return result; +} + +/* */ +struct wifi_device* wifi_device_connect(const char* ifname, const char* driver) { + int i; + int length; + struct wifi_device* device = NULL; + + 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 NULL; } + /* 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, ¶ms); + if (devicehandle) { + struct capwap_list_item* itemdevice; + + /* Register new device */ + itemdevice = capwap_itemlist_create(sizeof(struct wifi_device)); + device = (struct wifi_device*)itemdevice->item; + device->handle = devicehandle; + device->instance = &wifi_driver[i]; + device->wlan = capwap_list_create(); + + /* Appent to device list */ + capwap_itemlist_insert_after(g_wifidevice, NULL, itemdevice); + } + + break; + } + } + + return device; +} + +/* */ +const struct wifi_capability* wifi_device_getcapability(struct wifi_device* device) { + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + /* Retrieve cached capability */ - device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, radioid); - if (!device->handle || !device->instance->ops->device_getcapability) { + if (!device->instance->ops->device_getcapability) { return NULL; } @@ -458,12 +283,13 @@ const struct wifi_capability* wifi_device_getcapability(int radioid) { } /* */ -int wifi_device_setconfiguration(int radioid, struct device_setconfiguration_params* params) { - struct wifi_device* device; +int wifi_device_setconfiguration(struct wifi_device* device, struct device_setconfiguration_params* params) { + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + ASSERT(params != NULL); /* Get radio device */ - device = wifi_device_getdevice(radioid); - if (!device || !device->handle || !device->instance->ops->device_setconfiguration) { + if (!device->instance->ops->device_setconfiguration) { return -1; } @@ -472,20 +298,22 @@ int wifi_device_setconfiguration(int radioid, struct device_setconfiguration_par } /* */ -int wifi_device_setfrequency(int radioid, uint32_t band, uint32_t mode, uint8_t channel) { +int wifi_device_setfrequency(struct wifi_device* device, uint32_t band, uint32_t mode, uint8_t channel) { int i, j; int result = -1; const struct wifi_capability* capability; uint32_t frequency = 0; - ASSERT(radioid > 0); + ASSERT(device != NULL); + ASSERT(device->handle != NULL); - if (g_wifidevice->count <= radioid) { + /* Check device */ + if (!device->instance->ops->device_setfrequency) { return -1; } /* Capability device */ - capability = wifi_device_getcapability(radioid); + capability = wifi_device_getcapability(device); if (!capability || !(capability->flags & WIFI_CAPABILITY_RADIOTYPE) || !(capability->flags & WIFI_CAPABILITY_BANDS)) { return -1; } @@ -507,9 +335,6 @@ int wifi_device_setfrequency(int radioid, uint32_t band, uint32_t mode, uint8_t /* Configure frequency */ if (frequency) { - struct wifi_device* device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, radioid); - - memset(&device->currentfreq, 0, sizeof(struct wifi_frequency)); device->currentfreq.band = band; device->currentfreq.mode = mode; device->currentfreq.channel = channel; @@ -523,10 +348,7 @@ int wifi_device_setfrequency(int radioid, uint32_t band, uint32_t mode, uint8_t } /* Set frequency */ - device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, radioid); - if (device->handle && device->instance->ops->device_setfrequency) { - result = device->instance->ops->device_setfrequency(device->handle, &device->currentfreq); - } + result = device->instance->ops->device_setfrequency(device->handle, &device->currentfreq); } /* */ @@ -534,23 +356,124 @@ int wifi_device_setfrequency(int radioid, uint32_t band, uint32_t mode, uint8_t } /* */ -int wifi_device_updaterates(int radioid) { - struct wtp_radio* radio; - struct wifi_device* device; +int wifi_device_updaterates(struct wifi_device* device, uint8_t* rates, int ratescount) { struct device_setrates_params params; + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + ASSERT(rates != NULL); + ASSERT(ratescount > 0); + /* Get radio device */ - device = wifi_device_getdevice(radioid); - radio = wtp_radio_get_phy(radioid); - if (!device || !radio || !device->handle || !device->instance->ops->device_setrates) { + if (!device->instance->ops->device_setrates) { return -1; } /* Set rates */ - wifi_wlan_getrates(device, radio, ¶ms); + wifi_wlan_getrates(device, rates, ratescount, ¶ms); return device->instance->ops->device_setrates(device->handle, ¶ms); } +/* */ +struct wifi_wlan* wifi_wlan_create(struct wifi_device* device, const char* ifname) { + int length; + struct wifi_wlan* wlan; + wifi_wlan_handle wlanhandle; + struct capwap_list_item* itemwlan; + + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + ASSERT(ifname != NULL); + + /* Check */ + length = strlen(ifname); + if ((length <= 0) || (length >= IFNAMSIZ)) { + capwap_logging_warning("Wifi device name error: %s", ifname); + return NULL; + } else if (!device->instance->ops->wlan_create) { + capwap_logging_warning("%s library don't support wlan_create", device->instance->ops->name); + return NULL; + } + + /* Create interface */ + wlanhandle = device->instance->ops->wlan_create(device->handle, ifname); + if (!wlanhandle) { + capwap_logging_warning("Unable to create BSS: %s", ifname); + return NULL; + } + + /* Create new BSS */ + itemwlan = capwap_itemlist_create(sizeof(struct wifi_wlan)); + wlan = (struct wifi_wlan*)itemwlan->item; + wlan->handle = wlanhandle; + wlan->device = device; + + /* Appent to wlan list */ + capwap_itemlist_insert_after(device->wlan, NULL, itemwlan); + return wlan; +} + +/* */ +int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params) { + ASSERT(wlan != NULL); + ASSERT(wlan->device != NULL); + ASSERT(params != NULL); + + /* Check */ + if (!wlan->device->instance->ops->wlan_startap) { + return -1; + } + + /* Start AP */ + return wlan->device->instance->ops->wlan_startap(wlan->handle, params); +} + +/* */ +void wifi_wlan_stopap(struct wifi_wlan* wlan) { + ASSERT(wlan != NULL); + ASSERT(wlan->device != NULL); + + /* Stop AP */ + if (wlan->device->instance->ops->wlan_stopap) { + wlan->device->instance->ops->wlan_stopap(wlan->handle); + } +} + +/* */ +int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid) { + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + ASSERT(bssid != NULL); + + /* */ + if (!wlan->device->instance->ops->wlan_getmacaddress) { + return -1; + } + + return wlan->device->instance->ops->wlan_getmacaddress(wlan->handle, bssid); +} + +/* */ +void wifi_wlan_destroy(struct wifi_wlan* wlan) { + struct capwap_list_item* itemwlan; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + + /* */ + if (wlan->device->instance->ops->wlan_delete) { + wlan->device->instance->ops->wlan_delete(wlan->handle); + } + + /* Remove from wlan list of device */ + for (itemwlan = wlan->device->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { + if (wlan == (struct wifi_wlan*)itemwlan->item) { + capwap_itemlist_free(capwap_itemlist_remove(wlan->device->wlan, itemwlan)); + break; + } + } +} + /* */ uint32_t wifi_iface_index(const char* ifname) { if (!ifname || !*ifname) { @@ -560,6 +483,24 @@ uint32_t wifi_iface_index(const char* ifname) { return if_nametoindex(ifname); } +/* */ +int wifi_iface_getstatus(int sock, const char* ifname) { + struct ifreq ifreq; + + ASSERT(sock > 0); + ASSERT(ifname != NULL); + ASSERT(*ifname != 0); + + /* Change link state of interface */ + memset(&ifreq, 0, sizeof(ifreq)); + strcpy(ifreq.ifr_name, ifname); + if (!ioctl(sock, SIOCGIFFLAGS, &ifreq)) { + return ((ifreq.ifr_flags & IFF_UP) ? 1: 0); + } + + return -1; +} + /* */ int wifi_iface_updown(int sock, const char* ifname, int up) { struct ifreq ifreq; @@ -572,9 +513,18 @@ int wifi_iface_updown(int sock, const char* ifname, int up) { memset(&ifreq, 0, sizeof(ifreq)); strcpy(ifreq.ifr_name, ifname); if (!ioctl(sock, SIOCGIFFLAGS, &ifreq)) { + /* Set flag */ if (up) { + if (ifreq.ifr_flags & IFF_UP) { + return 0; /* Flag is already set */ + } + ifreq.ifr_flags |= IFF_UP; } else { + if (!(ifreq.ifr_flags & IFF_UP)) { + return 0; /* Flag is already unset */ + } + ifreq.ifr_flags &= ~IFF_UP; } diff --git a/src/binding/ieee80211/wifi_drivers.h b/src/binding/ieee80211/wifi_drivers.h index 0cb1c29..19527bc 100644 --- a/src/binding/ieee80211/wifi_drivers.h +++ b/src/binding/ieee80211/wifi_drivers.h @@ -94,22 +94,18 @@ struct device_setconfiguration_params { uint8_t country[WIFI_COUNTRY_LENGTH]; }; -/* */ -struct wlan_init_params { - const char* ifname; - int type; -}; - /* */ struct wlan_startap_params { const char* ssid; uint8_t ssid_hidden; - uint16_t capability; - - uint8_t authenticationtype; + uint8_t qos; + uint8_t authmode; + uint8_t macmode; + uint8_t tunnelmode; }; + /* */ struct wlan_send_frame_params { char* packet; @@ -204,10 +200,11 @@ struct wifi_frequency { }; /* */ +#define WIFI_EVENT_MAX_ITEMS 2 struct wifi_event { - void (*event_handler)(int fd, void* param1, void* param2); - void* param1; - void* param2; + void (*event_handler)(int fd, void** params, int paramscount); + int paramscount; + void* params[WIFI_EVENT_MAX_ITEMS]; }; /* */ @@ -230,10 +227,10 @@ struct wifi_driver_ops { void (*device_deinit)(wifi_device_handle handle); /* WLAN functions */ - wifi_wlan_handle (*wlan_create)(wifi_device_handle handle, struct wlan_init_params* params); + wifi_wlan_handle (*wlan_create)(wifi_device_handle handle, const char* ifname); int (*wlan_getfdevent)(wifi_wlan_handle handle, struct pollfd* fds, struct wifi_event* events); int (*wlan_startap)(wifi_wlan_handle handle, struct wlan_startap_params* params); - int (*wlan_stopap)(wifi_wlan_handle handle); + void (*wlan_stopap)(wifi_wlan_handle handle); int (*wlan_getmacaddress)(wifi_wlan_handle handle, uint8_t* address); void (*wlan_delete)(wifi_wlan_handle handle); }; @@ -249,7 +246,7 @@ struct wifi_device { wifi_device_handle handle; /* Device handle */ struct wifi_driver_instance* instance; /* Driver instance */ - struct capwap_array* wlan; /* Virtual AP */ + struct capwap_list* wlan; /* BSS */ /* Current frequency */ struct wifi_frequency currentfreq; @@ -261,17 +258,6 @@ struct wifi_wlan { struct wifi_device* device; }; -/* */ -struct wifi_wlan_startap_params { - uint16_t capability; - uint8_t qos; - uint8_t authmode; - uint8_t macmode; - uint8_t tunnelmode; - uint8_t ssid_hidden; - char ssid[IEEE80211_IE_SSID_MAX_LENGTH + 1]; -}; - /* Initialize wifi driver engine */ int wifi_driver_init(void); void wifi_driver_free(void); @@ -280,18 +266,18 @@ void wifi_driver_free(void); int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count); /* */ -int wifi_device_connect(int radioid, const char* ifname, const char* driver); -const struct wifi_capability* wifi_device_getcapability(int radioid); -int wifi_device_setconfiguration(int radioid, struct device_setconfiguration_params* params); -int wifi_device_setfrequency(int radioid, uint32_t band, uint32_t mode, uint8_t channel); -int wifi_device_updaterates(int radioid); +struct wifi_device* wifi_device_connect(const char* ifname, const char* driver); +const struct wifi_capability* wifi_device_getcapability(struct wifi_device* device); +int wifi_device_setconfiguration(struct wifi_device* device, struct device_setconfiguration_params* params); +int wifi_device_setfrequency(struct wifi_device* device, uint32_t band, uint32_t mode, uint8_t channel); +int wifi_device_updaterates(struct wifi_device* device, uint8_t* rates, int ratescount); /* */ -int wifi_wlan_create(int radioid, int wlanid, const char* ifname, uint8_t* bssid); -int wifi_wlan_startap(int radioid, int wlanid, struct wifi_wlan_startap_params* params); -int wifi_wlan_stopap(int radioid, int wlanid); -int wifi_wlan_getbssid(int radioid, int wlanid, uint8_t* bssid); -void wifi_wlan_destroy(int radioid, int wlanid); +struct wifi_wlan* wifi_wlan_create(struct wifi_device* device, const char* ifname); +int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params); +void wifi_wlan_stopap(struct wifi_wlan* wlan); +int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid); +void wifi_wlan_destroy(struct wifi_wlan* wlan); /* Util functions */ uint32_t wifi_iface_index(const char* ifname); @@ -314,6 +300,7 @@ void wifi_aid_free(uint32_t* aidbitfield, uint16_t aid); /* */ int wifi_retrieve_information_elements_position(struct ieee80211_ie_items* items, const uint8_t* data, int length); +int wifi_iface_getstatus(int sock, const char* ifname); int wifi_iface_updown(int sock, const char* ifname, int up); #define wifi_iface_up(sock, ifname) wifi_iface_updown(sock, ifname, 1) #define wifi_iface_down(sock, ifname) wifi_iface_updown(sock, ifname, 0) diff --git a/src/binding/ieee80211/wifi_nl80211.c b/src/binding/ieee80211/wifi_nl80211.c index 6aeced6..36a3530 100644 --- a/src/binding/ieee80211/wifi_nl80211.c +++ b/src/binding/ieee80211/wifi_nl80211.c @@ -2,6 +2,7 @@ #include "capwap_array.h" #include "capwap_list.h" #include "capwap_element.h" +#include "wtp.h" #include "wtp_radio.h" #include #include @@ -13,6 +14,20 @@ #include "wifi_drivers.h" #include "wifi_nl80211.h" +/* */ +static void nl80211_wlan_stopap(wifi_wlan_handle handle); + +/* */ +static const int g_stypes[] = { + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST +}; + /* */ struct family_data { int id; @@ -20,7 +35,7 @@ struct family_data { }; /* Compatibility functions */ -#if !defined(HAVE_LIBNL20) && !defined(HAVE_LIBNL30) +#ifdef HAVE_LIBNL_10 static uint32_t port_bitmap[32] = { 0 }; static struct nl_sock* nl_socket_alloc_cb(void* cb) { @@ -199,6 +214,8 @@ static int nl80211_get_multicast_id(struct nl80211_global_handle* globalhandle, result = nl80211_send_and_recv_msg(globalhandle, msg, cb_family_handler, &resource); if (!result) { result = resource.id; + } else { + capwap_logging_error("Unable get multicast id, error code: %d", result); } /* */ @@ -206,6 +223,80 @@ static int nl80211_get_multicast_id(struct nl80211_global_handle* globalhandle, return result; } +/* */ +static int nl80211_wlan_set_type(struct nl80211_wlan_handle* wlanhandle, uint32_t type) { + int result; + struct nl_msg* msg; + + ASSERT(wlanhandle != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_SET_INTERFACE, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlanhandle->virtindex); + nla_put_u32(msg, NL80211_ATTR_IFTYPE, type); + + /* */ + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable set type, error code: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static int cb_get_type(struct nl_msg* msg, void* data) { + struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + uint32_t* type = (uint32_t*)data; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[NL80211_ATTR_IFTYPE]) { + *type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]); + } + + return NL_SKIP; +} + +/* */ +static uint32_t nl80211_wlan_get_type(struct nl80211_wlan_handle* wlanhandle) { + int result; + struct nl_msg* msg; + uint32_t type = NL80211_IFTYPE_UNSPECIFIED; + + ASSERT(wlanhandle != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return NL80211_IFTYPE_UNSPECIFIED; + } + + /* */ + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_GET_INTERFACE, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlanhandle->virtindex); + + /* */ + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, cb_get_type, &type); + if (result) { + capwap_logging_error("Unable get type, error code: %d", result); + type = NL80211_IFTYPE_UNSPECIFIED; + } + + /* */ + nlmsg_free(msg); + return type; +} + /* */ static int nl80211_wlan_send_frame(wifi_wlan_handle handle, struct wlan_send_frame_params* params) { int result; @@ -248,6 +339,10 @@ static int nl80211_wlan_send_frame(wifi_wlan_handle handle, struct wlan_send_fra /* Send frame */ cookie = 0; result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, nl80211_cookie_handler, &cookie); + if (result) { + capwap_logging_error("Unable send frame, error code: %d", result); + } + nlmsg_free(msg); params->cookie = (result || params->no_wait_ack ? 0 : cookie); @@ -323,6 +418,10 @@ static int nl80211_wlan_setbss(struct nl80211_wlan_handle* wlanhandle, int cts, /* */ result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable set BSS, error code: %d", result); + } + nlmsg_free(msg); return result; @@ -373,6 +472,10 @@ static int nl80211_wlan_setbeacon(struct nl80211_wlan_handle* wlanhandle) { /* Start AP */ result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable set beacon, error code: %d", result); + } + nlmsg_free(msg); /* Configure AP */ @@ -395,96 +498,120 @@ static int nl80211_wlan_setbeacon(struct nl80211_wlan_handle* wlanhandle) { /* */ static void nl80211_device_updatebeacons(struct nl80211_device_handle* devicehandle) { struct capwap_list_item* wlansearch; + struct nl80211_wlan_handle* wlanhandle; ASSERT(devicehandle != NULL); /* Update all wlan beacon */ wlansearch = devicehandle->wlanlist->first; while (wlansearch) { - nl80211_wlan_setbeacon((struct nl80211_wlan_handle*)wlansearch->item); + wlanhandle = (struct nl80211_wlan_handle*)wlansearch->item; + if (wlanhandle->flags & NL80211_WLAN_SET_BEACON) { + nl80211_wlan_setbeacon(wlanhandle); + } + + /* */ wlansearch = wlansearch->next; } } /* */ -static void nl80211_station_delete(struct nl80211_wlan_handle* wlanhandle, const uint8_t* macaddress) { +static void nl80211_station_clean(struct nl80211_wlan_handle* wlanhandle, struct nl80211_station* station) { int updatebeacons = 0; + + ASSERT(wlanhandle != NULL); + ASSERT(station != NULL); + + if (station->aid) { + wifi_aid_free(wlanhandle->aidbitfield, station->aid); + } + + if (station->flags & NL80211_STATION_FLAGS_NON_ERP) { + wlanhandle->devicehandle->stationsnonerpcount--; + if (!wlanhandle->devicehandle->stationsnonerpcount) { + updatebeacons = 1; + } + } + + if (station->flags & NL80211_STATION_FLAGS_NO_SHORT_SLOT_TIME) { + wlanhandle->devicehandle->stationsnoshortslottimecount--; + if (!wlanhandle->devicehandle->stationsnoshortslottimecount && (wlanhandle->devicehandle->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { + updatebeacons = 1; + } + } + + if (station->flags & NL80211_STATION_FLAGS_NO_SHORT_PREAMBLE) { + wlanhandle->devicehandle->stationsnoshortpreamblecount--; + if (!wlanhandle->devicehandle->stationsnoshortpreamblecount && (wlanhandle->devicehandle->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { + updatebeacons = 1; + } + } + + /* Reset state */ + station->flags = 0; + station->supportedratescount = 0; + + /* Update beacons */ + if (updatebeacons) { + nl80211_device_updatebeacons(wlanhandle->devicehandle); + } +} + +/* */ +static void nl80211_station_delete(struct nl80211_wlan_handle* wlanhandle, const uint8_t* macaddress) { struct nl80211_station* station; + ASSERT(wlanhandle != NULL); ASSERT(macaddress != NULL); station = (struct nl80211_station*)capwap_hash_search(wlanhandle->stations, macaddress); if (station) { - if (station->aid) { - wifi_aid_free(wlanhandle->aidbitfield, station->aid); - } - - if (station->flags & NL80211_STATION_FLAGS_NON_ERP) { - wlanhandle->devicehandle->stationsnonerpcount--; - if (!wlanhandle->devicehandle->stationsnonerpcount) { - updatebeacons = 1; - } - } - - if (station->flags & NL80211_STATION_FLAGS_NO_SHORT_SLOT_TIME) { - wlanhandle->devicehandle->stationsnoshortslottimecount--; - if (!wlanhandle->devicehandle->stationsnoshortslottimecount && (wlanhandle->devicehandle->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { - updatebeacons = 1; - } - } - - if (station->flags & NL80211_STATION_FLAGS_NO_SHORT_PREAMBLE) { - wlanhandle->devicehandle->stationsnoshortpreamblecount--; - if (!wlanhandle->devicehandle->stationsnoshortpreamblecount && (wlanhandle->devicehandle->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { - updatebeacons = 1; - } - } + nl80211_station_clean(wlanhandle, station); /* Free station into hash callback */ wlanhandle->stationscount--; capwap_hash_delete(wlanhandle->stations, macaddress); - - /* Update beacons */ - if (updatebeacons) { - nl80211_device_updatebeacons(wlanhandle->devicehandle); - } } } +/* */ +static struct nl80211_station* nl80211_station_get(struct nl80211_wlan_handle* wlanhandle, const uint8_t* macaddress) { + ASSERT(macaddress != NULL); + + return (struct nl80211_station*)capwap_hash_search(wlanhandle->stations, macaddress); +} + /* */ static struct nl80211_station* nl80211_station_create(struct nl80211_wlan_handle* wlanhandle, const uint8_t* macaddress) { struct nl80211_station* station; ASSERT(macaddress != NULL); - /* If exist free old station */ - nl80211_station_delete(wlanhandle, macaddress); - - /* Checks if it has reached the maximum number of stations */ - /* TODO */ - /* Disconnect from another WLAN */ /* TODO */ - /* Create new station */ - station = (struct nl80211_station*)capwap_alloc(sizeof(struct nl80211_station)); - memset(station, 0, sizeof(struct nl80211_station)); - - /* TODO */ - /* */ - wlanhandle->stationscount++; - capwap_hash_add(wlanhandle->stations, macaddress, station); + station = nl80211_station_get(wlanhandle, macaddress); + if (station) { + nl80211_station_clean(wlanhandle, station); /* Reuse station */ + } else { + /* Checks if it has reached the maximum number of stations */ + if (wlanhandle->stationscount >= wlanhandle->maxstationscount) { + return NULL; + } + + /* Create new station */ + station = (struct nl80211_station*)capwap_alloc(sizeof(struct nl80211_station)); + memset(station, 0, sizeof(struct nl80211_station)); + + /* */ + wlanhandle->stationscount++; + capwap_hash_add(wlanhandle->stations, macaddress, station); + } + return station; } -/* */ -static struct nl80211_station* nl80211_station_get(struct nl80211_wlan_handle* wlanhandle, const uint8_t* macaddress) { - ASSERT(macaddress != NULL); - - return (struct nl80211_station*)capwap_hash_search(wlanhandle->stations, macaddress); -} - /* */ static void nl80211_wlan_send_deauthentication(struct nl80211_wlan_handle* wlanhandle, const uint8_t* stationaddress, uint16_t reasoncode) { int responselength; @@ -800,6 +927,20 @@ static void nl80211_do_mgmt_association_request_event(struct nl80211_wlan_handle } } +/* */ +static void nl80211_do_mgmt_deauthentication_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + struct nl80211_station* station; + + /* Get station reference */ + station = nl80211_station_get(wlanhandle, mgmt->sa); + if (!station) { + return; + } + + /* Free station */ + nl80211_station_delete(wlanhandle, mgmt->sa); +} + /* */ static void nl80211_do_mgmt_frame_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint16_t framecontrol_subtype, uint32_t frequency) { int broadcast; @@ -841,7 +982,7 @@ static void nl80211_do_mgmt_frame_event(struct nl80211_wlan_handle* wlanhandle, } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { - /* TODO */ + nl80211_do_mgmt_deauthentication_event(wlanhandle, mgmt, mgmtlength); break; } @@ -1021,6 +1162,14 @@ static int nl80211_execute_bss_event(struct nl80211_wlan_handle* wlanhandle, str break; } + case NL80211_CMD_TRIGGER_SCAN: { + break; + } + + case NL80211_CMD_NEW_SCAN_RESULTS: { + break; + } + default: { capwap_logging_debug("*** nl80211_execute_bss_event: %d", (int)gnlh->cmd); break; @@ -1042,13 +1191,15 @@ static int nl80211_process_bss_event(struct nl_msg* msg, void* arg) { } /* */ -static void nl80211_event_receive(int fd, void* param1, void* param2) { +static void nl80211_event_receive(int fd, void** params, int paramscount) { int res; - struct nl_sock* nl = (struct nl_sock*)param1; - struct nl_cb* nl_cb = (struct nl_cb*)param2; + + ASSERT(fd >= 0); + ASSERT(params != NULL); + ASSERT(paramscount == 2); /* */ - res = nl_recvmsgs(nl, nl_cb); + res = nl_recvmsgs((struct nl_sock*)params[0], (struct nl_cb*)params[1]); if (res) { capwap_logging_warning("Receive nl80211 message failed: %d", res); } @@ -1073,12 +1224,42 @@ static void nl80211_hash_station_free(const void* key, unsigned long keysize, vo } /* */ -static int nl80211_global_valid_handler(struct nl_msg* msg, void* data) { - uint32_t ifindex; +static struct nl80211_wlan_handle* nl80211_global_search_wlan(struct nl80211_global_handle* globalhandle, uint32_t ifindex) { struct nl80211_device_handle* devicehandle; struct nl80211_wlan_handle* wlanhandle; struct capwap_list_item* devicesearch; struct capwap_list_item* wlansearch; + + ASSERT(globalhandle != NULL); + + /* Search device */ + devicesearch = globalhandle->devicelist->first; + while (devicesearch) { + devicehandle = (struct nl80211_device_handle*)devicesearch->item; + + /* Search wlan */ + wlansearch = devicehandle->wlanlist->first; + while (wlansearch) { + wlanhandle = (struct nl80211_wlan_handle*)wlansearch->item; + if (wlanhandle->virtindex == ifindex) { + return wlanhandle; + } + + /* */ + wlansearch = wlansearch->next; + } + + /* */ + devicesearch = devicesearch->next; + } + + return NULL; +} + +/* */ +static int nl80211_global_valid_handler(struct nl_msg* msg, void* data) { + uint32_t ifindex; + struct nl80211_wlan_handle* wlanhandle; struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)data; @@ -1088,23 +1269,12 @@ static int nl80211_global_valid_handler(struct nl_msg* msg, void* data) { if (tb_msg[NL80211_ATTR_IFINDEX]) { ifindex = (int)nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX]); - /* Search device */ - devicesearch = globalhandle->devicelist->first; - while (devicesearch) { - devicehandle = (struct nl80211_device_handle*)devicesearch->item; - - /* Search wlan */ - wlansearch = devicehandle->wlanlist->first; - while (wlansearch) { - wlanhandle = (struct nl80211_wlan_handle*)wlansearch->item; - if (wlanhandle->virtindex == ifindex) { - return nl80211_execute_bss_event(wlanhandle, gnlh, tb_msg); - } - - wlansearch = wlansearch->next; - } - - devicesearch = devicesearch->next; + /* Search interface */ + wlanhandle = nl80211_global_search_wlan(globalhandle, ifindex); + if (wlanhandle) { + return nl80211_execute_bss_event(wlanhandle, gnlh, tb_msg); + } else { + capwap_logging_debug("*** Receive nl80211_global_valid_handler without found interface: %d", (int)ifindex); } } else { capwap_logging_debug("*** Receive nl80211_global_valid_handler without interface index"); @@ -1113,6 +1283,88 @@ static int nl80211_global_valid_handler(struct nl_msg* msg, void* data) { return NL_SKIP; } +/* */ +static void nl80211_global_newlink_event(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length) { + char ifname[IFNAMSIZ + 1]; + char buffer[100]; + char* pos = buffer; + char* end = buffer + sizeof(buffer); + int attrlen = length; + struct rtattr* attr = (struct rtattr*)data; + struct nl80211_wlan_handle* wlanhandle; + struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; + + ASSERT(handle != NULL); + ASSERT(infomsg != NULL); + + /* */ + memset(ifname, 0, sizeof(ifname)); + memset(buffer, 0, sizeof(buffer)); + + while (RTA_OK(attr, attrlen)) { + switch (attr->rta_type) { + case IFLA_IFNAME: { + if (RTA_PAYLOAD(attr) < IFNAMSIZ) { + memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr)); + } + + break; + } + + case IFLA_MASTER: { + pos += snprintf(pos, end - pos, " master=%u", nla_get_u32((struct nlattr*)attr)); + break; + } + + case IFLA_WIRELESS: { + int length = (int)RTA_PAYLOAD(attr); + uint16_t* data = (uint16_t*)RTA_DATA(attr); + + pos += snprintf(pos, end - pos, " wext"); + + if ((length > 0) && (data != NULL)) { + pos += snprintf(pos, end - pos, " (%d:%d [%d])", (unsigned int)data[0], (unsigned int)data[1], length); + } + + break; + } + + case IFLA_OPERSTATE: { + pos += snprintf(pos, end - pos, " operstate=%u", nla_get_u32((struct nlattr*)attr)); + break; + } + + case IFLA_LINKMODE: { + pos += snprintf(pos, end - pos, " linkmode=%u", nla_get_u32((struct nlattr*)attr)); + break; + } + } + + attr = RTA_NEXT(attr, attrlen); + } + + capwap_logging_debug("Link status change: ifi_index=%d ifname=%s%s ifi_flags=0x%x (%s%s%s%s)", infomsg->ifi_index, ifname, buffer, infomsg->ifi_flags, (infomsg->ifi_flags & IFF_UP) ? "[UP]" : "", (infomsg->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", (infomsg->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", (infomsg->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); + + /* Search device */ + wlanhandle = nl80211_global_search_wlan(globalhandle, infomsg->ifi_index); + if (wlanhandle) { + if (!(wlanhandle->flags & NL80211_WLAN_RUNNING)) { + if ((infomsg->ifi_flags & IFF_UP) && (wifi_iface_getstatus(globalhandle->sock_util, wlanhandle->virtname) > 0)) { + wifi_iface_down(globalhandle->sock_util, wlanhandle->virtname); + } + } else if (wlanhandle->flags & NL80211_WLAN_SET_BEACON) { + if ((wlanhandle->flags & NL80211_WLAN_OPERSTATE_RUNNING) && (infomsg->ifi_flags & IFF_LOWER_UP) && !(infomsg->ifi_flags & (IFF_RUNNING | IFF_DORMANT))) { + netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle, wlanhandle->virtindex, -1, IF_OPER_UP); + } + } + } +} + +/* */ +static void nl80211_global_dellink_event(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length) { + capwap_logging_debug("*** Del link"); +} + /* */ static unsigned long nl80211_get_cipher(uint32_t chiper) { switch (chiper) { @@ -1171,7 +1423,7 @@ static int cb_get_virtdevice_list(struct nl_msg* msg, void* data) { } /* */ -static int nl80211_get_virtdevice_list(struct nl80211_global_handle* globalhandle, struct capwap_list* list) { +static int nl80211_get_virtdevice_list(struct nl80211_global_handle* globalhandle, uint32_t phyindex, struct capwap_list* list) { int result; struct nl_msg* msg; @@ -1185,9 +1437,13 @@ static int nl80211_get_virtdevice_list(struct nl80211_global_handle* globalhandl } genlmsg_put(msg, 0, 0, globalhandle->nl80211_id, 0, NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0); + nla_put_u32(msg, NL80211_ATTR_WIPHY, phyindex); /* Retrieve all virtual interface */ result = nl80211_send_and_recv_msg(globalhandle, msg, cb_get_virtdevice_list, list); + if (result) { + capwap_logging_error("Unable get interfaces, error code: %d", result); + } /* */ nlmsg_free(msg); @@ -1233,6 +1489,9 @@ static int nl80211_get_phydevice_list(struct nl80211_global_handle* globalhandle /* Retrieve all physical interface */ result = nl80211_send_and_recv_msg(globalhandle, msg, cb_get_phydevice_list, list); + if (result) { + capwap_logging_error("Unable get physical interfaces, error code: %d", result); + } /* */ nlmsg_free(msg); @@ -1501,6 +1760,9 @@ static int nl80211_destroy_virtdevice(struct nl80211_global_handle* globalhandle /* Destroy virtual device */ result = nl80211_send_and_recv_msg(globalhandle, msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable destroy interface, error code: %d", result); + } /* */ nlmsg_free(msg); @@ -1514,7 +1776,7 @@ static void nl80211_destroy_all_virtdevice(struct nl80211_global_handle* globalh /* Retrieve all virtual device */ list = capwap_list_create(); - result = nl80211_get_virtdevice_list(globalhandle, list); + result = nl80211_get_virtdevice_list(globalhandle, phyindex, list); if (!result) { struct capwap_list_item* item = list->first; @@ -1688,38 +1950,67 @@ static int nl80211_device_setconfiguration(wifi_device_handle handle, struct dev ASSERT(handle != NULL); /* */ + devicehandle->flags |= NL80211_DEVICE_SET_CONFIGURATION; devicehandle->beaconperiod = params->beaconperiod; devicehandle->dtimperiod = params->dtimperiod; devicehandle->shortpreamble = (params->shortpreamble ? 1 : 0); /* Update beacons */ - nl80211_device_updatebeacons(devicehandle); + if (devicehandle->wlanlist->count) { + nl80211_device_updatebeacons(devicehandle); + } + return 0; } /* */ -static int nl80211_device_setfrequency(wifi_device_handle handle, struct wifi_frequency* freq) { +static int nl80211_device_changefrequency(struct nl80211_device_handle* devicehandle, struct wifi_frequency* freq) { int result; struct nl_msg* msg; - struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle; + struct capwap_list_item* wlansearch; + struct nl80211_wlan_handle* wlanhandle = NULL; - ASSERT(handle != NULL); + ASSERT(devicehandle != NULL); ASSERT(freq != NULL); + /* Delay request if not found BSS interface */ + if (!devicehandle->wlanactive) { + return 0; + } + + /* Search a valid interface */ + wlansearch = devicehandle->wlanlist->first; + while (wlansearch) { + struct nl80211_wlan_handle* element = (struct nl80211_wlan_handle*)wlansearch->item; + + if (element->flags & NL80211_WLAN_RUNNING) { + wlanhandle = element; + break; + } + + /* */ + wlansearch = wlansearch->next; + } + + /* */ + if (!wlanhandle) { + return -1; + } + + /* */ msg = nlmsg_alloc(); if (!msg) { return -1; } + /* Set frequecy using device index of first BSS */ genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_SET_WIPHY, 0); - nla_put_u32(msg, NL80211_ATTR_WIPHY, devicehandle->phyindex); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlanhandle->virtindex); nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->frequency); /* Set wifi frequency */ result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, NULL, NULL); - if (!result) { - memcpy(&devicehandle->currentfrequency, freq, sizeof(struct wifi_frequency)); - } else { + if (result) { capwap_logging_error("Unable set frequency %d, error code: %d", (int)freq->frequency, result); } @@ -1728,6 +2019,19 @@ static int nl80211_device_setfrequency(wifi_device_handle handle, struct wifi_fr return result; } +/* */ +static int nl80211_device_setfrequency(wifi_device_handle handle, struct wifi_frequency* freq) { + struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle; + + ASSERT(handle != NULL); + ASSERT(freq != NULL); + + /* Save frequency before change */ + devicehandle->flags |= NL80211_DEVICE_SET_FREQUENCY; + memcpy(&devicehandle->currentfrequency, freq, sizeof(struct wifi_frequency)); + return nl80211_device_changefrequency(devicehandle, &devicehandle->currentfrequency); +} + /* */ static int nl80211_device_setrates(wifi_device_handle handle, struct device_setrates_params* params) { struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle; @@ -1743,13 +2047,17 @@ static int nl80211_device_setrates(wifi_device_handle handle, struct device_setr } /* Set new rates */ + devicehandle->flags |= NL80211_DEVICE_SET_RATES; memcpy(devicehandle->supportedrates, params->supportedrates, params->supportedratescount); devicehandle->supportedratescount = params->supportedratescount; memcpy(devicehandle->basicrates, params->basicrates, params->basicratescount); devicehandle->basicratescount = params->basicratescount; /* Update beacons */ - nl80211_device_updatebeacons(devicehandle); + if (devicehandle->wlanlist->count) { + nl80211_device_updatebeacons(devicehandle); + } + return 0; } @@ -1758,6 +2066,10 @@ static void nl80211_wlan_delete(wifi_wlan_handle handle) { struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; if (wlanhandle) { + /* Terminate service */ + nl80211_wlan_stopap(handle); + + /* Release resource */ if (wlanhandle->devicehandle) { struct capwap_list_item* search; @@ -1778,14 +2090,6 @@ static void nl80211_wlan_delete(wifi_wlan_handle handle) { nl80211_destroy_virtdevice(wlanhandle->devicehandle->globalhandle, wlanhandle->virtindex); } - if (wlanhandle->nl) { - nl_socket_free(wlanhandle->nl); - } - - if (wlanhandle->nl_cb) { - nl_cb_put(wlanhandle->nl_cb); - } - if (wlanhandle->stations) { capwap_hash_free(wlanhandle->stations); } @@ -1855,28 +2159,46 @@ static void nl80211_device_deinit(wifi_device_handle handle) { } /* */ -static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wlan_init_params* params) { - int i; +static int nl80211_wlan_set_profile(struct nl80211_wlan_handle* wlanhandle, uint32_t type) { + int result; + + ASSERT(wlanhandle != NULL); + + /* Check current type */ + /*if (type == nl80211_wlan_get_type(wlanhandle)) { + return 0; + }*/ + + /* Change interface type */ + result = nl80211_wlan_set_type(wlanhandle, type); + if (result && (type == nl80211_wlan_get_type(wlanhandle))) { + result = 0; /* No error */ + } + + /* */ + if (result) { + if (result == -ENODEV) { + return -1; + } + + /* TODO */ + } + + return result; +} + +/* */ +static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, const char* ifname) { int result; uint32_t ifindex; struct nl_msg* msg; struct capwap_list_item* item; - struct nl80211_wlan_handle* wlanhandle = NULL; + struct nl80211_wlan_handle* wlanhandle; struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle; - static const int stypes[] = { - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION - }; ASSERT(handle != NULL); - ASSERT(params != NULL); - ASSERT(params->ifname != NULL); - ASSERT(params->type == WLAN_INTERFACE_AP); + ASSERT(ifname != NULL); + ASSERT(*ifname != 0); if (!devicehandle) { return NULL; @@ -1891,8 +2213,8 @@ static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wl /* Create wlan interface */ genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_NEW_INTERFACE, 0); nla_put_u32(msg, NL80211_ATTR_WIPHY, devicehandle->phyindex); - nla_put_u32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP); - nla_put_string(msg, NL80211_ATTR_IFNAME, params->ifname); + nla_put_u32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION); + nla_put_string(msg, NL80211_ATTR_IFNAME, ifname); /* */ result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, NULL, NULL); @@ -1900,10 +2222,11 @@ static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wl /* Check interface */ if (result) { + capwap_logging_error("Unable create interface %s, error code: %d", ifname, result); return NULL; } - ifindex = wifi_iface_index(params->ifname); + ifindex = wifi_iface_index(ifname); if (!ifindex) { return NULL; } @@ -1915,7 +2238,8 @@ static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wl /* */ wlanhandle->devicehandle = devicehandle; wlanhandle->virtindex = ifindex; - strcpy(wlanhandle->virtname, params->ifname); + strcpy(wlanhandle->virtname, ifname); + wlanhandle->nl_fd = -1; /* Save AP handle into device handle */ item = capwap_itemlist_create_with_item(wlanhandle, sizeof(struct nl80211_wlan_handle)); @@ -1928,34 +2252,9 @@ static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wl return NULL; } - /* BSS management */ - wlanhandle->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!wlanhandle->nl_cb) { - nl80211_wlan_delete((wifi_wlan_handle)wlanhandle); - return NULL; - } - - nl_cb_set(wlanhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL); - nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_process_bss_event, (void*)wlanhandle); - - wlanhandle->nl = nl_create_handle(wlanhandle->nl_cb); - if (wlanhandle->nl) { - wlanhandle->nl_fd = nl_socket_get_fd(wlanhandle->nl); - } else { - nl80211_wlan_delete((wifi_wlan_handle)wlanhandle); - return NULL; - } - - /* Register frames */ - for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) { - if (nl80211_registerframe(wlanhandle, (IEEE80211_FRAMECONTROL_TYPE_MGMT << 2) | (stypes[i] << 4), NULL, 0)) { - nl80211_wlan_delete((wifi_wlan_handle)wlanhandle); - return NULL; - } - } - /* Stations */ wlanhandle->stations = capwap_hash_create(WIFI_NL80211_STATIONS_HASH_SIZE, WIFI_NL80211_STATIONS_KEY_SIZE, nl80211_hash_station_gethash, NULL, nl80211_hash_station_free); + wlanhandle->maxstationscount = IEEE80211_MAX_STATIONS; return wlanhandle; } @@ -1966,6 +2265,10 @@ static int nl80211_wlan_getfdevent(wifi_wlan_handle handle, struct pollfd* fds, ASSERT(handle != NULL); + if (!(wlanhandle->flags & NL80211_WLAN_RUNNING) || (wlanhandle->nl_fd < 0)) { + return 0; + } + if (fds) { fds[0].fd = wlanhandle->nl_fd; fds[0].events = POLLIN | POLLERR | POLLHUP; @@ -1973,8 +2276,9 @@ static int nl80211_wlan_getfdevent(wifi_wlan_handle handle, struct pollfd* fds, if (events) { events[0].event_handler = nl80211_event_receive; - events[0].param1 = (void*)wlanhandle->nl; - events[0].param2 = (void*)wlanhandle->nl_cb; + events[0].params[0] = (void*)wlanhandle->nl; + events[0].params[1] = (void*)wlanhandle->nl_cb; + events[0].paramscount = 2; } return 1; @@ -1982,49 +2286,129 @@ static int nl80211_wlan_getfdevent(wifi_wlan_handle handle, struct pollfd* fds, /* */ static int nl80211_wlan_startap(wifi_wlan_handle handle, struct wlan_startap_params* params) { + int i; + int result; struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; - /* Enable interface */ - if (wifi_iface_up(wlanhandle->devicehandle->globalhandle->sock_util, wlanhandle->virtname)) { + ASSERT(handle != NULL); + ASSERT(params != NULL); + + /* Check device */ + if ((wlanhandle->flags & NL80211_WLAN_RUNNING) || ((wlanhandle->devicehandle->flags & NL80211_DEVICE_REQUIRED_FOR_BSS) != NL80211_DEVICE_REQUIRED_FOR_BSS)) { return -1; } + /* Configure interface with AP profile */ + if (nl80211_wlan_set_profile(wlanhandle, NL80211_IFTYPE_AP)) { + return -1; + } + + /* Socket management */ + wlanhandle->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!wlanhandle->nl_cb) { + return -1; + } + + nl_cb_set(wlanhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL); + nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_process_bss_event, (void*)wlanhandle); + + wlanhandle->nl = nl_create_handle(wlanhandle->nl_cb); + if (wlanhandle->nl) { + wlanhandle->nl_fd = nl_socket_get_fd(wlanhandle->nl); + } else { + nl80211_wlan_stopap(handle); + return -1; + } + + /* Register frames */ + for (i = 0; i < sizeof(g_stypes) / sizeof(g_stypes[0]); i++) { + result = nl80211_registerframe(wlanhandle, (IEEE80211_FRAMECONTROL_TYPE_MGMT << 2) | (g_stypes[i] << 4), NULL, 0); + if (result) { + capwap_logging_error("Unable to register frame %d, error code: %d", g_stypes[i], result); + nl80211_wlan_stopap(handle); + return -1; + } + } + + /* Enable interface */ + wlanhandle->flags |= NL80211_WLAN_RUNNING; + if (wifi_iface_up(wlanhandle->devicehandle->globalhandle->sock_util, wlanhandle->virtname)) { + nl80211_wlan_stopap(handle); + return -1; + } + + /* Configure device if first BSS device */ + if (!wlanhandle->devicehandle->wlanactive) { + /* Set device frequency */ + nl80211_device_changefrequency(wlanhandle->devicehandle, &wlanhandle->devicehandle->currentfrequency); + /* TODO Get current frequency */ + } + /* Save configuration */ strcpy(wlanhandle->ssid, params->ssid); wlanhandle->ssid_hidden = params->ssid_hidden; wlanhandle->capability = params->capability; - wlanhandle->authenticationtype = ((params->authenticationtype == CAPWAP_ADD_WLAN_AUTHTYPE_WEP) ? NL80211_AUTHTYPE_SHARED_KEY : NL80211_AUTHTYPE_OPEN_SYSTEM); + wlanhandle->authenticationtype = ((params->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_WEP) ? NL80211_AUTHTYPE_SHARED_KEY : NL80211_AUTHTYPE_OPEN_SYSTEM); /* Set beacon */ - return nl80211_wlan_setbeacon(wlanhandle); + if (nl80211_wlan_setbeacon(wlanhandle)) { + nl80211_wlan_stopap(handle); + return -1; + } + + /* Enable operation status */ + wlanhandle->flags |= NL80211_WLAN_OPERSTATE_RUNNING; + netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle, wlanhandle->virtindex, -1, IF_OPER_UP); + + /* Configuration complete */ + wlanhandle->devicehandle->wlanactive++; + return 0; } /* */ -static int nl80211_wlan_stopap(wifi_wlan_handle handle) { - int result; +static void nl80211_wlan_stopap(wifi_wlan_handle handle) { struct nl_msg* msg; struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; + ASSERT(handle); + /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; + if (wlanhandle->flags & NL80211_WLAN_SET_BEACON) { + msg = nlmsg_alloc(); + if (msg) { + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_STOP_AP, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlanhandle->virtindex); + + /* Stop AP */ + nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + nlmsg_free(msg); + } } - /* */ - genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_STOP_AP, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlanhandle->virtindex); - - /* Stop AP */ - result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); - nlmsg_free(msg); - /* Disable interface */ - if (wifi_iface_down(wlanhandle->devicehandle->globalhandle->sock_util, wlanhandle->virtname)) { - return -1; + wifi_iface_down(wlanhandle->devicehandle->globalhandle->sock_util, wlanhandle->virtname); + + /* Configure interface with station profile */ + nl80211_wlan_set_profile(wlanhandle, NL80211_IFTYPE_STATION); + + /* */ + if (wlanhandle->nl) { + nl_socket_free(wlanhandle->nl); + wlanhandle->nl = NULL; + wlanhandle->nl_fd = -1; } - return result; + if (wlanhandle->nl_cb) { + nl_cb_put(wlanhandle->nl_cb); + wlanhandle->nl_cb = NULL; + } + + if (wlanhandle->flags & NL80211_WLAN_RUNNING) { + wlanhandle->devicehandle->wlanactive--; + } + + /* */ + wlanhandle->flags = 0; } /* */ @@ -2044,6 +2428,10 @@ static void nl80211_global_deinit(wifi_global_handle handle) { struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; if (globalhandle) { + if (globalhandle->netlinkhandle) { + netlink_free(globalhandle->netlinkhandle); + } + if (globalhandle->nl) { nl_socket_free(globalhandle->nl); } @@ -2142,6 +2530,16 @@ static wifi_global_handle nl80211_global_init(void) { nl_cb_set(globalhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL); nl_cb_set(globalhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_global_valid_handler, globalhandle); + /* Netlink lisk status */ + globalhandle->netlinkhandle = netlink_init(); + if (!globalhandle->netlinkhandle) { + nl80211_global_deinit((wifi_global_handle)globalhandle); + return NULL; + } + + globalhandle->netlinkhandle->newlink_event = nl80211_global_newlink_event; + globalhandle->netlinkhandle->dellink_event = nl80211_global_dellink_event; + /* Device list */ globalhandle->devicelist = capwap_list_create(); @@ -2160,19 +2558,29 @@ static int nl80211_global_getfdevent(wifi_global_handle handle, struct pollfd* f struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; ASSERT(handle != NULL); + ASSERT(globalhandle->nl_event_fd >= 0); + ASSERT(globalhandle->netlinkhandle != NULL); + ASSERT(globalhandle->netlinkhandle->sock >= 0); if (fds) { fds[0].fd = globalhandle->nl_event_fd; fds[0].events = POLLIN | POLLERR | POLLHUP; + fds[1].fd = globalhandle->netlinkhandle->sock; + fds[1].events = POLLIN | POLLERR | POLLHUP; } if (events) { events[0].event_handler = nl80211_event_receive; - events[0].param1 = (void*)globalhandle->nl_event; - events[0].param2 = (void*)globalhandle->nl_cb; + events[0].params[0] = (void*)globalhandle->nl_event; + events[0].params[1] = (void*)globalhandle->nl_cb; + events[0].paramscount = 2; + events[1].event_handler = netlink_event_receive; + events[1].params[0] = (void*)globalhandle->netlinkhandle; + events[1].params[1] = (void*)globalhandle; + events[1].paramscount = 2; } - return 1; + return 2; } /* Driver function */ diff --git a/src/binding/ieee80211/wifi_nl80211.h b/src/binding/ieee80211/wifi_nl80211.h index 426136c..1507678 100644 --- a/src/binding/ieee80211/wifi_nl80211.h +++ b/src/binding/ieee80211/wifi_nl80211.h @@ -2,9 +2,10 @@ #define __WIFI_NL80211_HEADER__ #include "capwap_hash.h" +#include "netlink_link.h" /* Compatibility functions */ -#if !defined(HAVE_LIBNL20) && !defined(HAVE_LIBNL30) +#ifdef HAVE_LIBNL_10 #define nl_sock nl_handle #endif @@ -24,19 +25,31 @@ struct nl80211_global_handle { struct nl_sock* nl_event; int nl_event_fd; + struct netlink* netlinkhandle; + int sock_util; struct capwap_list* devicelist; }; /* Device handle */ +#define NL80211_DEVICE_SET_FREQUENCY 0x00000001 +#define NL80211_DEVICE_SET_RATES 0x00000002 +#define NL80211_DEVICE_SET_CONFIGURATION 0x00000004 + +#define NL80211_DEVICE_REQUIRED_FOR_BSS (NL80211_DEVICE_SET_FREQUENCY | NL80211_DEVICE_SET_RATES | NL80211_DEVICE_SET_CONFIGURATION) + struct nl80211_device_handle { struct nl80211_global_handle* globalhandle; uint32_t phyindex; char phyname[IFNAMSIZ]; + unsigned long flags; + + /* */ struct capwap_list* wlanlist; + unsigned long wlanactive; /* */ uint16_t beaconperiod; @@ -63,7 +76,9 @@ struct nl80211_device_handle { }; /* WLAN handle */ -#define NL80211_WLAN_SET_BEACON 0x00000001 +#define NL80211_WLAN_RUNNING 0x00000001 +#define NL80211_WLAN_SET_BEACON 0x00000002 +#define NL80211_WLAN_OPERSTATE_RUNNING 0x00000004 struct nl80211_wlan_handle { struct nl80211_device_handle* devicehandle; @@ -91,9 +106,13 @@ struct nl80211_wlan_handle { /* Station information */ unsigned long stationscount; + unsigned long maxstationscount; struct capwap_hash* stations; uint32_t aidbitfield[WIFI_AID_BITFIELD_SIZE]; + + /* Scan */ + unsigned long scancomplete; }; /* Physical device info */ diff --git a/src/common/capwap_debug.c b/src/common/capwap_debug.c index 3bd24bd..e0dcb98 100644 --- a/src/common/capwap_debug.c +++ b/src/common/capwap_debug.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -7,6 +6,10 @@ #include "config.h" #endif +#ifdef USE_DEBUG_BACKTRACE +#include +#endif + #include "capwap_logging.h" #include "capwap_error.h" @@ -23,8 +26,10 @@ struct capwap_memory_block { size_t size; const char* file; int line; +#ifdef USE_DEBUG_BACKTRACE void* backtrace[BACKTRACE_BUFFER]; int backtrace_count; +#endif struct capwap_memory_block* next; }; @@ -54,7 +59,9 @@ void* capwap_alloc_debug(size_t size, const char* file, const int line) { block->size = size; block->file = file; block->line = line; +#ifdef USE_DEBUG_BACKTRACE block->backtrace_count = backtrace(block->backtrace, BACKTRACE_BUFFER); +#endif block->next = g_memoryblocks; /* Canary */ @@ -125,13 +132,16 @@ void capwap_free_debug(void* p, const char* file, const int line) { /* Dump memory alloced */ void capwap_dump_memory(void) { +#ifdef USE_DEBUG_BACKTRACE char** backtrace_functions; +#endif struct capwap_memory_block* findblock; findblock = g_memoryblocks; while (findblock != NULL) { capwap_logging_debug("%s(%d): block at %p, %d bytes long", findblock->file, findblock->line, findblock->item, findblock->size); +#ifdef USE_DEBUG_BACKTRACE backtrace_functions = backtrace_symbols(findblock->backtrace, findblock->backtrace_count); if (backtrace_functions) { int j; @@ -143,7 +153,7 @@ void capwap_dump_memory(void) { free(backtrace_functions); } - +#endif /* Next */ findblock = findblock->next; @@ -162,6 +172,7 @@ int capwap_check_memory_leak(int verbose) { } /* Backtrace call stack */ +#ifdef USE_DEBUG_BACKTRACE void capwap_backtrace_callstack(void) { int i; int count; @@ -183,3 +194,4 @@ void capwap_backtrace_callstack(void) { } } } +#endif diff --git a/src/common/capwap_debug.h b/src/common/capwap_debug.h index ef59284..5124072 100644 --- a/src/common/capwap_debug.h +++ b/src/common/capwap_debug.h @@ -19,7 +19,11 @@ void capwap_free_debug(void* p, const char* file, const int line); int capwap_check_memory_leak(int verbose); void capwap_dump_memory(void); +#ifdef USE_DEBUG_BACKTRACE void capwap_backtrace_callstack(void); +#else +#define capwap_backtrace_callstack() (0) +#endif #else diff --git a/src/wtp/wtp.c b/src/wtp/wtp.c index 2f6ec83..e6a020e 100644 --- a/src/wtp/wtp.c +++ b/src/wtp/wtp.c @@ -7,6 +7,7 @@ #include "capwap_element.h" #include "capwap_dtls.h" #include "wtp_dfa.h" +#include "wtp_radio.h" #include #include @@ -14,8 +15,9 @@ struct wtp_t g_wtp; /* Local param */ -#define WTP_STANDARD_NAME "Unknown WTP" -#define WTP_STANDARD_LOCATION "Unknown Location" +#define WTP_STANDARD_NAME "Unknown WTP" +#define WTP_STANDARD_LOCATION "Unknown Location" +#define WTP_WAIT_RADIO_INITIALIZATION 1 static char g_configurationfile[260] = WTP_STANDARD_CONFIGURATION_FILE; @@ -186,7 +188,7 @@ static void wtp_print_usage(void) { static int wtp_parsing_radio_configuration(config_setting_t* configElement, struct wtp_radio* radio) { int i; int configBool; - long int configInt; + LIBCONFIG_LOOKUP_INT_ARG configInt; const char* configString; config_setting_t* configItems; config_setting_t* configSection; @@ -458,6 +460,16 @@ static int wtp_parsing_radio_configuration(config_setting_t* configElement, stru return 0; } + if (config_setting_lookup_string(configElement, "bssprefixname", &configString) == CONFIG_TRUE) { + if (strlen(configString) < IFNAMSIZ) { + strcpy(radio->wlanprefix, configString); + } else { + return 0; + } + } else { + return 0; + } + if (config_setting_lookup_int(configElement, "dtimperiod", &configInt) == CONFIG_TRUE) { if ((configInt > 0) && (configInt < 256)) { radio->radioconfig.dtimperiod = (uint8_t)configInt; @@ -501,17 +513,16 @@ static int wtp_parsing_radio_configuration(config_setting_t* configElement, stru /* Parsing configuration */ static int wtp_parsing_configuration_1_0(config_t* config) { int i; - int result; - int configInt; + int configBool; int configIPv4; int configIPv6; - long int configLongInt; + LIBCONFIG_LOOKUP_INT_ARG configInt; const char* configString; config_setting_t* configSetting; /* Logging configuration */ - if (config_lookup_bool(config, "logging.enable", &configInt) == CONFIG_TRUE) { - if (!configInt) { + if (config_lookup_bool(config, "logging.enable", &configBool) == CONFIG_TRUE) { + if (!configBool) { capwap_logging_verboselevel(CAPWAP_LOGGING_NONE); capwap_logging_disable_allinterface(); } else { @@ -559,8 +570,8 @@ static int wtp_parsing_configuration_1_0(config_t* config) { } /* Set running mode */ - if (config_lookup_bool(config, "application.standalone", &configInt) == CONFIG_TRUE) { - g_wtp.standalone = ((configInt != 0) ? 1 : 0); + if (config_lookup_bool(config, "application.standalone", &configBool) == CONFIG_TRUE) { + g_wtp.standalone = ((configBool != 0) ? 1 : 0); } /* Set name of WTP */ @@ -623,20 +634,20 @@ static int wtp_parsing_configuration_1_0(config_t* config) { /* Set tunnelmode of WTP */ if (config_lookup(config, "application.tunnelmode") != NULL) { g_wtp.mactunnel.mode = 0; - if (config_lookup_bool(config, "application.tunnelmode.nativeframe", &configInt) == CONFIG_TRUE) { - if (configInt != 0) { + if (config_lookup_bool(config, "application.tunnelmode.nativeframe", &configBool) == CONFIG_TRUE) { + if (configBool != 0) { g_wtp.mactunnel.mode |= CAPWAP_WTP_NATIVE_FRAME_TUNNEL; } } - if (config_lookup_bool(config, "application.tunnelmode.ethframe", &configInt) == CONFIG_TRUE) { - if (configInt != 0) { + if (config_lookup_bool(config, "application.tunnelmode.ethframe", &configBool) == CONFIG_TRUE) { + if (configBool != 0) { g_wtp.mactunnel.mode |= CAPWAP_WTP_8023_FRAME_TUNNEL; } } - if (config_lookup_bool(config, "application.tunnelmode.localbridging", &configInt) == CONFIG_TRUE) { - if (configInt != 0) { + if (config_lookup_bool(config, "application.tunnelmode.localbridging", &configBool) == CONFIG_TRUE) { + if (configBool != 0) { g_wtp.mactunnel.mode |= CAPWAP_WTP_LOCAL_BRIDGING; } } @@ -655,8 +666,8 @@ static int wtp_parsing_configuration_1_0(config_t* config) { } /* Set VendorID Boardinfo of WTP */ - if (config_lookup_int(config, "application.boardinfo.idvendor", &configLongInt) == CONFIG_TRUE) { - g_wtp.boarddata.vendor = (unsigned long)configLongInt; + if (config_lookup_int(config, "application.boardinfo.idvendor", &configInt) == CONFIG_TRUE) { + g_wtp.boarddata.vendor = (unsigned long)configInt; } /* Set Element Boardinfo of WTP */ @@ -769,22 +780,48 @@ static int wtp_parsing_configuration_1_0(config_t* config) { radio = wtp_radio_create_phy(); strcpy(radio->device, configString); - if (config_setting_lookup_bool(configElement, "enabled", &configInt) == CONFIG_TRUE) { - if (configInt) { + if (config_setting_lookup_bool(configElement, "enabled", &configBool) == CONFIG_TRUE) { + if (configBool) { /* Retrieve radio capability */ if (wtp_parsing_radio_configuration(configElement, radio)) { /* Initialize radio device */ if (config_setting_lookup_string(configElement, "driver", &configString) == CONFIG_TRUE) { if (*configString && (strlen(configString) < WIFI_DRIVER_NAME_SIZE)) { - result = wifi_device_connect(radio->radioid, radio->device, configString); - if (!result) { + radio->devicehandle = wifi_device_connect(radio->device, configString); + if (radio->devicehandle) { radio->status = WTP_RADIO_ENABLED; capwap_logging_info("Register radioid %d with radio device: %s - %s", radio->radioid, radio->device, configString); /* Update radio capability with device query */ - capability = wifi_device_getcapability(radio->radioid); + capability = wifi_device_getcapability(radio->devicehandle); if (capability) { - /* TODO */ + uint8_t bssid; + char wlanname[IFNAMSIZ]; + struct capwap_list_item* itemwlan; + struct wtp_radio_wlanpool* wlanpool; + + /* Create interface */ + for (bssid = 0; bssid < radio->radioconfig.maxbssid; bssid++) { + sprintf(wlanname, "%s%02d.%02d", radio->wlanprefix, (int)radio->radioid, (int)bssid + 1); + if (wifi_iface_index(wlanname)) { + capwap_logging_error("interface %s already exists", wlanname); + return 0; + } + + /* */ + itemwlan = capwap_itemlist_create(sizeof(struct wtp_radio_wlanpool)); + wlanpool = (struct wtp_radio_wlanpool*)itemwlan->item; + wlanpool->radio = radio; + wlanpool->wlanhandle = wifi_wlan_create(radio->devicehandle, wlanname); + if (!wlanpool->wlanhandle) { + capwap_logging_error("Unable to create interface: %s", wlanname); + return 0; + } + + /* Appent to wlan pool */ + capwap_logging_debug("Created wlan interface: %s", wlanname); + capwap_itemlist_insert_after(radio->wlanpool, NULL, itemwlan); + } } } else { radio->status = WTP_RADIO_HWFAILURE; @@ -855,7 +892,7 @@ static int wtp_parsing_configuration_1_0(config_t* config) { for (i = 0; i < count; i++) { config_setting_t* configElement = config_setting_get_elem(configSetting, i); if (configElement != NULL) { - long int configVendor; + LIBCONFIG_LOOKUP_INT_ARG configVendor; if (config_setting_lookup_int(configElement, "idvendor", &configVendor) == CONFIG_TRUE) { const char* configType; if (config_setting_lookup_string(configElement, "type", &configType) == CONFIG_TRUE) { @@ -916,9 +953,9 @@ static int wtp_parsing_configuration_1_0(config_t* config) { } /* Set Timer of WTP */ - if (config_lookup_int(config, "application.timer.statistics", &configLongInt) == CONFIG_TRUE) { - if ((configLongInt > 0) && (configLongInt < 65536)) { - g_wtp.statisticstimer.timer = (unsigned short)configLongInt; + if (config_lookup_int(config, "application.timer.statistics", &configInt) == CONFIG_TRUE) { + if ((configInt > 0) && (configInt < 65536)) { + g_wtp.statisticstimer.timer = (unsigned short)configInt; } else { capwap_logging_error("Invalid configuration file, invalid application.timer.statistics value"); return 0; @@ -926,8 +963,8 @@ static int wtp_parsing_configuration_1_0(config_t* config) { } /* Set DTLS of WTP */ - if (config_lookup_bool(config, "application.dtls.enable", &configInt) == CONFIG_TRUE) { - if (configInt != 0) { + if (config_lookup_bool(config, "application.dtls.enable", &configBool) == CONFIG_TRUE) { + if (configBool != 0) { struct capwap_dtls_param dtlsparam; /* Init dtls param */ @@ -937,14 +974,14 @@ static int wtp_parsing_configuration_1_0(config_t* config) { /* Set DTLS Policy of WTP */ if (config_lookup(config, "application.dtls.dtlspolicy") != NULL) { g_wtp.validdtlsdatapolicy = 0; - if (config_lookup_bool(config, "application.dtls.dtlspolicy.cleardatachannel", &configInt) == CONFIG_TRUE) { - if (configInt != 0) { + if (config_lookup_bool(config, "application.dtls.dtlspolicy.cleardatachannel", &configBool) == CONFIG_TRUE) { + if (configBool != 0) { g_wtp.validdtlsdatapolicy |= CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED; } } - if (config_lookup_bool(config, "application.dtls.dtlspolicy.dtlsdatachannel", &configInt) == CONFIG_TRUE) { - if (configInt != 0) { + if (config_lookup_bool(config, "application.dtls.dtlspolicy.dtlsdatachannel", &configBool) == CONFIG_TRUE) { + if (configBool != 0) { g_wtp.validdtlsdatapolicy |= CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED; } } @@ -1058,9 +1095,9 @@ static int wtp_parsing_configuration_1_0(config_t* config) { } /* Set mtu of WTP */ - if (config_lookup_int(config, "application.network.mtu", &configLongInt) == CONFIG_TRUE) { - if ((configLongInt > 0) && (configLongInt < 65536)) { - g_wtp.mtu = (unsigned short)configLongInt; + if (config_lookup_int(config, "application.network.mtu", &configInt) == CONFIG_TRUE) { + if ((configInt > 0) && (configInt < 65536)) { + g_wtp.mtu = (unsigned short)configInt; } else { capwap_logging_error("Invalid configuration file, invalid application.network.mtu value"); return 0; @@ -1068,9 +1105,9 @@ static int wtp_parsing_configuration_1_0(config_t* config) { } /* Set network port of WTP */ - if (config_lookup_int(config, "application.network.port", &configLongInt) == CONFIG_TRUE) { - if ((configLongInt > 0) && (configLongInt < 65535)) { - g_wtp.net.bind_sock_ctrl_port = (unsigned short)configLongInt; + if (config_lookup_int(config, "application.network.port", &configInt) == CONFIG_TRUE) { + if ((configInt > 0) && (configInt < 65535)) { + g_wtp.net.bind_sock_ctrl_port = (unsigned short)configInt; } else { capwap_logging_error("Invalid configuration file, invalid application.network.port value"); return 0; @@ -1108,8 +1145,8 @@ static int wtp_parsing_configuration_1_0(config_t* config) { } /* Set ip dual stack of WTP */ - if (config_lookup_bool(config, "application.network.ipdualstack", &configInt) == CONFIG_TRUE) { - if (!configInt) { + if (config_lookup_bool(config, "application.network.ipdualstack", &configBool) == CONFIG_TRUE) { + if (!configBool) { g_wtp.net.bind_ctrl_flags |= CAPWAP_IPV6ONLY_FLAG; g_wtp.net.bind_data_flags |= CAPWAP_IPV6ONLY_FLAG; } else { @@ -1119,8 +1156,8 @@ static int wtp_parsing_configuration_1_0(config_t* config) { } /* Set search discovery of WTP */ - if (config_lookup_bool(config, "application.acdiscovery.search", &configInt) == CONFIG_TRUE) { - g_wtp.acdiscoveryrequest = (configInt ? 1 : 0); + if (config_lookup_bool(config, "application.acdiscovery.search", &configBool) == CONFIG_TRUE) { + g_wtp.acdiscoveryrequest = (configBool ? 1 : 0); } /* Set discovery host of WTP */ @@ -1271,12 +1308,54 @@ static int wtp_configure(void) { return CAPWAP_SUCCESSFUL; } +/* */ +static void wtp_wait_radio_ready(void) { + int index; + struct wtp_fds fds; + struct timeout_control timeout; + + /* Get only radio file descriptor */ + memset(&fds, 0, sizeof(struct wtp_fds)); + wtp_radio_update_fdevent(&fds); + capwap_init_timeout(&timeout); + + for (;;) { + capwap_set_timeout(WTP_WAIT_RADIO_INITIALIZATION, &timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + + /* Wait packet */ + index = capwap_wait_recvready(fds.fdspoll, fds.fdstotalcount, &timeout); + if (index < 0) { + break; + } else if (!fds.events[index].event_handler) { + break; + } + + fds.events[index].event_handler(fds.fdspoll[index].fd, fds.events[index].params, fds.events[index].paramscount); + } + + /* */ + wtp_free_fds(&fds); +} + /* */ int wtp_update_radio_in_use() { /* TODO */ return g_wtp.radios->count; } +/* */ +void wtp_free_fds(struct wtp_fds* fds) { + ASSERT(fds != NULL); + + if (fds->fdspoll) { + capwap_free(fds->fdspoll); + } + + if (fds->events) { + capwap_free(fds->events); + } +} + /* Main*/ int main(int argc, char** argv) { int value; @@ -1319,6 +1398,11 @@ int main(int argc, char** argv) { capwap_logging_info("Running WTP in daemon mode"); } + /* Wait the initialization of radio interfaces */ + capwap_logging_info("Wait the initialization of radio interfaces"); + wtp_wait_radio_ready(); + + /* */ capwap_logging_info("Startup WTP"); /* Complete configuration WTP */ diff --git a/src/wtp/wtp.h b/src/wtp/wtp.h index 0afea97..db004ed 100644 --- a/src/wtp/wtp.h +++ b/src/wtp/wtp.h @@ -7,7 +7,6 @@ #include "capwap_network.h" #include "capwap_protocol.h" #include "wifi_drivers.h" -#include "wtp_radio.h" /* WTP Configuration */ #define WTP_STANDARD_CONFIGURATION_FILE "/etc/capwap/wtp.conf" @@ -74,6 +73,16 @@ struct wtp_state { int rfcDTLSSessionDelete; }; +/* */ +struct wtp_fds { + struct pollfd* fdspoll; + int fdstotalcount; + int fdsnetworkcount; + + struct wifi_event* events; + int eventscount; +}; + /* WTP */ struct wtp_t { int standalone; @@ -83,9 +92,7 @@ struct wtp_t { /* */ struct capwap_network net; - struct pollfd* fds; - int fdstotalcount; - int fdsnetworkcount; + struct wtp_fds fds; /* */ struct wtp_state dfa; @@ -137,8 +144,6 @@ struct wtp_t { /* */ struct capwap_array* radios; - struct wifi_event* events; - int eventscount; /* Radio ACL */ int defaultaclstations; @@ -158,6 +163,7 @@ extern struct wtp_t g_wtp; /* */ int wtp_update_radio_in_use(); +void wtp_free_fds(struct wtp_fds* fds); /* Build capwap element helper */ void wtp_create_radioadmstate_element(struct capwap_packet_txmng* txmngpacket); diff --git a/src/wtp/wtp_dfa.c b/src/wtp/wtp_dfa.c index d132216..268dede 100644 --- a/src/wtp/wtp_dfa.c +++ b/src/wtp/wtp_dfa.c @@ -150,11 +150,12 @@ static void wtp_dfa_execute(struct capwap_parsed_packet* packet, struct timeout_ } /* */ -static int wtp_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, struct timeout_control* timeout) { +static int wtp_recvfrom(struct wtp_fds* fds, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, struct timeout_control* timeout) { int index; - ASSERT(fds); - ASSERT(fdscount > 0); + ASSERT(fds != NULL); + ASSERT(fds->fdspoll != NULL); + ASSERT(fds->fdstotalcount > 0); ASSERT(buffer != NULL); ASSERT(size != NULL); ASSERT(*size > 0); @@ -162,31 +163,49 @@ static int wtp_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* siz ASSERT(recvtoaddr != NULL); /* Wait packet */ - index = capwap_wait_recvready(fds, fdscount, timeout); + index = capwap_wait_recvready(fds->fdspoll, fds->fdstotalcount, timeout); if (index < 0) { return index; - } else if (index >= g_wtp.fdsnetworkcount) { - int pos = index - g_wtp.fdsnetworkcount; + } else if (index >= fds->fdsnetworkcount) { + int pos = index - fds->fdsnetworkcount; - if (pos < g_wtp.eventscount) { - if (!g_wtp.events[pos].event_handler) { + if (pos < fds->eventscount) { + if (!fds->events[pos].event_handler) { return CAPWAP_RECV_ERROR_SOCKET; } - g_wtp.events[pos].event_handler(fds[index].fd, g_wtp.events[pos].param1, g_wtp.events[pos].param2); + fds->events[pos].event_handler(fds->fdspoll[index].fd, fds->events[pos].params, fds->events[pos].paramscount); } return WTP_RECV_NOERROR_RADIO; } /* Receive packet */ - if (!capwap_recvfrom_fd(fds[index].fd, buffer, size, recvfromaddr, recvtoaddr)) { + if (!capwap_recvfrom_fd(fds->fdspoll[index].fd, buffer, size, recvfromaddr, recvtoaddr)) { return CAPWAP_RECV_ERROR_SOCKET; } return index; } +/* */ +static void wtp_dfa_init_fdspool(struct wtp_fds* fds, struct capwap_network* net) { + ASSERT(fds != NULL); + ASSERT(net != NULL); + + /* */ + memset(fds, 0, sizeof(struct wtp_fds)); + fds->fdstotalcount = CAPWAP_MAX_SOCKETS * 2; + fds->fdspoll = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * fds->fdstotalcount); + + /* Retrive all socket for polling */ + fds->fdsnetworkcount = capwap_network_set_pollfd(net, fds->fdspoll, fds->fdstotalcount); + fds->fdstotalcount = fds->fdsnetworkcount; + + /* Update Event File Descriptor */ + wtp_radio_update_fdevent(fds); +} + /* WTP state machine */ int wtp_dfa_running(void) { int res; @@ -209,21 +228,13 @@ int wtp_dfa_running(void) { /* Init */ capwap_init_timeout(&timeout); - capwap_set_timeout(0, &timeout, CAPWAP_TIMER_CONTROL_CONNECTION); /* Start DFA with timeout */ - memset(&packet, 0, sizeof(struct capwap_parsed_packet)); + /* Start DFA with timeout */ + capwap_set_timeout(0, &timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + /* Configure poll struct */ - g_wtp.fdstotalcount = CAPWAP_MAX_SOCKETS * 2; - g_wtp.fds = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * g_wtp.fdstotalcount); - - /* Retrive all socket for polling */ - g_wtp.fdsnetworkcount = capwap_network_set_pollfd(&g_wtp.net, g_wtp.fds, g_wtp.fdstotalcount); - g_wtp.fdstotalcount = g_wtp.fdsnetworkcount; - ASSERT(g_wtp.fdstotalcount > 0); - - /* Update Event File Descriptor */ - wtp_radio_update_fdevent(); + wtp_dfa_init_fdspool(&g_wtp.fds, &g_wtp.net); /* Handler signal */ g_wtp.running = 1; @@ -241,7 +252,7 @@ int wtp_dfa_running(void) { isrecvpacket = 0; buffer = bufferencrypt; buffersize = CAPWAP_MAX_PACKET_SIZE; - index = wtp_recvfrom(g_wtp.fds, g_wtp.fdstotalcount, buffer, &buffersize, &recvfromaddr, &recvtoaddr, &timeout); + index = wtp_recvfrom(&g_wtp.fds, buffer, &buffersize, &recvfromaddr, &recvtoaddr, &timeout); if (!g_wtp.running) { capwap_logging_debug("Closing WTP, Teardown connection"); @@ -261,7 +272,7 @@ int wtp_dfa_running(void) { int check; /* Retrieve network information */ - capwap_get_network_socket(&g_wtp.net, &socket, g_wtp.fds[index].fd); + capwap_get_network_socket(&g_wtp.net, &socket, g_wtp.fds.fdspoll[index].fd); /* Check source */ if (socket.isctrlsocket && (g_wtp.acctrladdress.ss_family != AF_UNSPEC)) { @@ -339,7 +350,7 @@ int wtp_dfa_running(void) { socklen_t sockinfolen = sizeof(struct sockaddr_storage); memset(&sockinfo, 0, sizeof(struct sockaddr_storage)); - if (getsockname(g_wtp.fds[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) { + if (getsockname(g_wtp.fds.fdspoll[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) { break; } @@ -447,7 +458,7 @@ int wtp_dfa_running(void) { } /* Free memory */ - capwap_free(g_wtp.fds); + wtp_free_fds(&g_wtp.fds); return result; } diff --git a/src/wtp/wtp_dfa_configure.c b/src/wtp/wtp_dfa_configure.c index 19652bc..2cfc834 100644 --- a/src/wtp/wtp_dfa_configure.c +++ b/src/wtp/wtp_dfa_configure.c @@ -4,6 +4,7 @@ #include "capwap_array.h" #include "capwap_list.h" #include "wtp_dfa.h" +#include "wtp_radio.h" /* */ void wtp_send_configure(struct timeout_control* timeout) { diff --git a/src/wtp/wtp_dfa_join.c b/src/wtp/wtp_dfa_join.c index 12314cc..4090ab5 100644 --- a/src/wtp/wtp_dfa_join.c +++ b/src/wtp/wtp_dfa_join.c @@ -4,6 +4,7 @@ #include "capwap_array.h" #include "capwap_list.h" #include "wtp_dfa.h" +#include "wtp_radio.h" /* */ void wtp_send_join(struct timeout_control* timeout) { diff --git a/src/wtp/wtp_dfa_run.c b/src/wtp/wtp_dfa_run.c index 33a0ed6..39fa665 100644 --- a/src/wtp/wtp_dfa_run.c +++ b/src/wtp/wtp_dfa_run.c @@ -2,6 +2,7 @@ #include "capwap_dfa.h" #include "capwap_element.h" #include "wtp_dfa.h" +#include "wtp_radio.h" /* */ static int send_echo_request() { diff --git a/src/wtp/wtp_element_helper.c b/src/wtp/wtp_element_helper.c index 1a5d705..9b02b36 100644 --- a/src/wtp/wtp_element_helper.c +++ b/src/wtp/wtp_element_helper.c @@ -1,4 +1,5 @@ #include "wtp.h" +#include "wtp_radio.h" /* */ void wtp_create_radioopsstate_element(struct capwap_packet_txmng* txmngpacket) { diff --git a/src/wtp/wtp_radio.c b/src/wtp/wtp_radio.c index 0ccd68e..d4fc4d7 100644 --- a/src/wtp/wtp_radio.c +++ b/src/wtp/wtp_radio.c @@ -1,5 +1,6 @@ #include "wtp.h" #include "capwap_hash.h" +#include "capwap_list.h" #include "wtp_radio.h" /* */ @@ -27,7 +28,7 @@ static int wtp_radio_configure_phy(struct wtp_radio* radio) { memcpy(radio->rateset.rateset, radio->supportedrates.supportedrates, CAPWAP_RATESET_MAXLENGTH); /* Update rates */ - if (wifi_device_updaterates(radio->radioid)) { + if (wifi_device_updaterates(radio->devicehandle, radio->rateset.rateset, radio->rateset.ratesetcount)) { return -1; } } @@ -48,23 +49,6 @@ static int wtp_radio_configure_phy(struct wtp_radio* radio) { return 0; } -/* */ -static void wtp_radio_destroy_wlan(struct wtp_radio_wlan* wlan) { - if (wlan->wlanid && wlan->radio) { - if (wlan->state != WTP_RADIO_WLAN_STATE_IDLE) { - if (wlan->state == WTP_RADIO_WLAN_STATE_AP) { - wifi_wlan_stopap(wlan->radio->radioid, wlan->wlanid); - } - - /* Destroy interface */ - wifi_wlan_destroy(wlan->radio->radioid, wlan->wlanid); - } - } - - /* Release item */ - memset(wlan, 0, sizeof(struct wtp_radio_wlan)); -} - /* */ unsigned long wtp_radio_acl_item_gethash(const void* key, unsigned long keysize, unsigned long hashsize) { uint8_t* macaddress = (uint8_t*)key; @@ -84,7 +68,8 @@ void wtp_radio_init(void) { /* */ void wtp_radio_close(void) { - int i, j; + int i; + struct capwap_list_item* itemwlan; ASSERT(g_wtp.radios != NULL); @@ -96,11 +81,29 @@ void wtp_radio_close(void) { } if (radio->wlan) { - for (j = 0; j < radio->wlan->count; j++) { - wtp_radio_destroy_wlan((struct wtp_radio_wlan*)capwap_array_get_item_pointer(radio->wlan, j)); + for (itemwlan = radio->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { + struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)itemwlan->item; + + /* Destroy BSS interface */ + if (wlan->wlanhandle) { + wifi_wlan_destroy(wlan->wlanhandle); + } } - capwap_array_free(radio->wlan); + capwap_list_free(radio->wlan); + } + + if (radio->wlanpool) { + for (itemwlan = radio->wlanpool->first; itemwlan != NULL; itemwlan = itemwlan->next) { + struct wtp_radio_wlanpool* wlanpool = (struct wtp_radio_wlanpool*)itemwlan->item; + + /* Destroy BSS interface */ + if (wlanpool->wlanhandle) { + wifi_wlan_destroy(wlanpool->wlanhandle); + } + } + + capwap_list_free(radio->wlanpool); } } @@ -110,10 +113,9 @@ void wtp_radio_close(void) { /* */ void wtp_radio_free(void) { ASSERT(g_wtp.radios != NULL); - ASSERT(g_wtp.radios->count == 0); - if (g_wtp.events) { - capwap_free(g_wtp.events); + if (g_wtp.radios->count > 0) { + wtp_radio_close(); } capwap_array_free(g_wtp.radios); @@ -125,7 +127,6 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { int i; int result = 0; unsigned short binding; - struct wtp_radio* radio; struct capwap_array* messageelements; struct capwap_array* updateitems; struct wtp_update_configuration_item* item; @@ -138,6 +139,7 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { /* */ binding = GET_WBID_HEADER(packet->rxmngpacket->header); if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) { + struct wtp_radio* radio; struct capwap_list_item* search; /* Set radio configuration and invalidate the old values */ @@ -422,12 +424,12 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { switch (item->type) { case WTP_UPDATE_FREQUENCY_DSSS: { - result = wifi_device_setfrequency(item->radio->radioid, WIFI_BAND_2GHZ, item->radio->radioinformation.radiotype, item->radio->directsequencecontrol.currentchannel); + result = wifi_device_setfrequency(item->radio->devicehandle, WIFI_BAND_2GHZ, item->radio->radioinformation.radiotype, item->radio->directsequencecontrol.currentchannel); break; } case WTP_UPDATE_FREQUENCY_OFDM: { - result = wifi_device_setfrequency(item->radio->radioid, WIFI_BAND_5GHZ, item->radio->radioinformation.radiotype, item->radio->ofdmcontrol.currentchannel); + result = wifi_device_setfrequency(item->radio->devicehandle, WIFI_BAND_5GHZ, item->radio->radioinformation.radiotype, item->radio->ofdmcontrol.currentchannel); break; } } @@ -439,7 +441,7 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { switch (item->type) { case WTP_UPDATE_RATES: { - result = wifi_device_updaterates(radio->radioid); + result = wifi_device_updaterates(item->radio->devicehandle, item->radio->rateset.rateset, item->radio->rateset.ratesetcount); break; } @@ -453,7 +455,7 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { memcpy(params.bssid, item->radio->radioconfig.bssid, ETH_ALEN); params.beaconperiod = item->radio->radioconfig.beaconperiod; memcpy(params.country, item->radio->radioconfig.country, WIFI_COUNTRY_LENGTH); - result = wifi_device_setconfiguration(item->radio->radioid, ¶ms); + result = wifi_device_setconfiguration(item->radio->devicehandle, ¶ms); break; } } @@ -474,7 +476,8 @@ struct wtp_radio* wtp_radio_create_phy(void) { radio->status = WTP_RADIO_DISABLED; /* Init configuration radio */ - radio->wlan = capwap_array_create(sizeof(struct wtp_radio_wlan), 0, 1); + radio->wlan = capwap_list_create(); + radio->wlanpool = capwap_list_create(); radio->antenna.selections = capwap_array_create(sizeof(uint8_t), 0, 1); return radio; } @@ -483,8 +486,12 @@ struct wtp_radio* wtp_radio_create_phy(void) { struct wtp_radio* wtp_radio_get_phy(uint8_t radioid) { int i; - ASSERT(IS_VALID_RADIOID(radioid)); + /* Check */ + if (!IS_VALID_RADIOID(radioid)) { + return NULL; + } + /* Retrieve radio */ 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); if (radioid == radio->radioid) { @@ -497,13 +504,19 @@ struct wtp_radio* wtp_radio_get_phy(uint8_t radioid) { /* */ struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlanid) { - int i; + struct capwap_list_item* itemwlan; - ASSERT(IS_VALID_WLANID(wlanid)); + ASSERT(radio != NULL); - for (i = 0; i < radio->wlan->count; i++) { - struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)capwap_array_get_item_pointer(radio->wlan, i); - if ((wlanid == wlan->wlanid) && (radio == wlan->radio)) { + /* Check */ + if (!IS_VALID_WLANID(wlanid)) { + return NULL; + } + + /* Retrieve BSS */ + for (itemwlan = radio->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { + struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)itemwlan->item; + if (wlanid == wlan->wlanid) { return wlan; } } @@ -512,8 +525,11 @@ struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlani } /* */ -void wtp_radio_update_fdevent(void) { +void wtp_radio_update_fdevent(struct wtp_fds* fds) { int count; + struct pollfd* fdsbuffer; + + ASSERT(fds != NULL); /* Retrieve number of File Descriptor Event */ count = wifi_event_getfd(NULL, NULL, 0); @@ -521,41 +537,43 @@ void wtp_radio_update_fdevent(void) { return; } - /* */ - if (g_wtp.eventscount != count) { - struct pollfd* fds; - - /* Resize poll */ - fds = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * (g_wtp.fdsnetworkcount + count)); - memcpy(fds, g_wtp.fds, sizeof(struct pollfd) * g_wtp.fdsnetworkcount); - capwap_free(g_wtp.fds); - g_wtp.fds = fds; - - /* Events Callback */ - if (g_wtp.events) { - capwap_free(g_wtp.events); + /* Resize poll */ + if (fds->eventscount != count) { + fdsbuffer = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * (fds->fdsnetworkcount + count)); + if (fds->fdspoll && (fds->fdsnetworkcount > 0)) { + memcpy(fdsbuffer, fds->fdspoll, sizeof(struct pollfd) * fds->fdsnetworkcount); + capwap_free(fds->fdspoll); } - g_wtp.events = (struct wifi_event*)((count > 0) ? capwap_alloc(sizeof(struct wifi_event) * count) : NULL); + fds->fdspoll = fdsbuffer; + + /* Events Callback */ + if (fds->events) { + capwap_free(fds->events); + } + + fds->events = (struct wifi_event*)((count > 0) ? capwap_alloc(sizeof(struct wifi_event) * count) : NULL); /* */ - g_wtp.eventscount = count; - g_wtp.fdstotalcount = g_wtp.fdsnetworkcount + g_wtp.eventscount; + fds->eventscount = count; + fds->fdstotalcount = fds->fdsnetworkcount + count; } /* Retrieve File Descriptor Event */ if (count > 0) { - count = wifi_event_getfd(&g_wtp.fds[g_wtp.fdsnetworkcount], g_wtp.events, g_wtp.eventscount); - ASSERT(g_wtp.eventscount == count); + ASSERT(fds->fdspoll != NULL); + wifi_event_getfd(&fds->fdspoll[fds->fdsnetworkcount], fds->events, fds->eventscount); } } /* */ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwap_80211_assignbssid_element* bssid) { - char wlanname[IFNAMSIZ]; struct wtp_radio* radio; struct wtp_radio_wlan* wlan; - struct wifi_wlan_startap_params params; + struct wtp_radio_wlanpool* wlanpool; + struct capwap_list_item* itemwlan; + struct capwap_list_item* itemwlanpool; + struct wlan_startap_params params; struct capwap_80211_addwlan_element* addwlan; /* Get message elements */ @@ -576,6 +594,11 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwa return CAPWAP_RESULTCODE_FAILURE; } + /* Verify exist interface into pool */ + if (!radio->wlanpool->first) { + return CAPWAP_RESULTCODE_FAILURE; + } + /* Prepare physical interface for create wlan */ if (!radio->wlan->count) { if (wtp_radio_configure_phy(radio)) { @@ -583,51 +606,45 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwa } } - /* Set virtual interface information */ - wlan = (struct wtp_radio_wlan*)capwap_array_get_item_pointer(radio->wlan, radio->wlan->count); - wlan->radio = radio; - wlan->wlanid = addwlan->wlanid; - sprintf(wlanname, "%s%02d.%02d", g_wtp.wlanprefix, (int)addwlan->radioid, (int)addwlan->wlanid); - if (wifi_iface_index(wlanname)) { - memset(wlan, 0, sizeof(struct wtp_radio_wlan)); - return CAPWAP_RESULTCODE_FAILURE; - } - - /* Create virtual interface */ - if (!wifi_wlan_create(addwlan->radioid, addwlan->wlanid, wlanname, NULL)) { - wlan->state = WTP_RADIO_WLAN_STATE_CREATED; - } else { - wtp_radio_destroy_wlan(wlan); - return CAPWAP_RESULTCODE_FAILURE; - } + /* Get interface from pool */ + itemwlanpool = capwap_itemlist_remove_head(radio->wlanpool); + wlanpool = (struct wtp_radio_wlanpool*)itemwlanpool->item; /* Wlan configuration */ - memset(¶ms, 0, sizeof(struct wifi_wlan_startap_params)); + memset(¶ms, 0, sizeof(struct wlan_startap_params)); + params.ssid = (const char*)addwlan->ssid; + params.ssid_hidden = addwlan->suppressssid; params.capability = addwlan->capability; params.qos = addwlan->qos; params.authmode = addwlan->authmode; params.macmode = addwlan->macmode; params.tunnelmode = addwlan->tunnelmode; - params.ssid_hidden = addwlan->suppressssid; - strcpy(params.ssid, (const char*)addwlan->ssid); - /* TODO (struct capwap_array*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE) */ /* Start AP */ - if (!wifi_wlan_startap(addwlan->radioid, addwlan->wlanid, ¶ms)) { - wlan->state = WTP_RADIO_WLAN_STATE_AP; - } else { - wtp_radio_destroy_wlan(wlan); + if (wifi_wlan_startap(wlanpool->wlanhandle, ¶ms)) { + capwap_itemlist_insert_before(radio->wlanpool, NULL, itemwlanpool); return CAPWAP_RESULTCODE_FAILURE; } + /* Move interface from pool to used */ + itemwlan = capwap_itemlist_create(sizeof(struct wtp_radio_wlan)); + wlan = (struct wtp_radio_wlan*)itemwlan->item; + wlan->wlanid = addwlan->wlanid; + wlan->wlanhandle = wlanpool->wlanhandle; + wlan->radio = wlanpool->radio; + + /* */ + capwap_itemlist_free(itemwlanpool); + capwap_itemlist_insert_after(radio->wlan, NULL, itemwlan); + /* Update Event File Descriptor */ - wtp_radio_update_fdevent(); + wtp_radio_update_fdevent(&g_wtp.fds); /* Retrieve macaddress of new device */ bssid->radioid = addwlan->radioid; bssid->wlanid = addwlan->wlanid; - wifi_wlan_getbssid(addwlan->radioid, addwlan->wlanid, bssid->bssid); + wifi_wlan_getbssid(wlan->wlanhandle, bssid->bssid); return CAPWAP_RESULTCODE_SUCCESS; } diff --git a/src/wtp/wtp_radio.h b/src/wtp/wtp_radio.h index 03bc8f6..2e07f48 100644 --- a/src/wtp/wtp_radio.h +++ b/src/wtp/wtp_radio.h @@ -20,22 +20,27 @@ #define WTP_PREFIX_NAME_MAX_LENGTH (IFNAMSIZ - 6) #define WTP_PREFIX_DEFAULT_NAME "ap" -#define WTP_RADIO_WLAN_STATE_IDLE 0 -#define WTP_RADIO_WLAN_STATE_CREATED 1 -#define WTP_RADIO_WLAN_STATE_AP 2 - struct wtp_radio_wlan { - struct wtp_radio* radio; - int state; uint8_t wlanid; + struct wifi_wlan* wlanhandle; + struct wtp_radio* radio; +}; + +/* */ +struct wtp_radio_wlanpool { + struct wifi_wlan* wlanhandle; + struct wtp_radio* radio; }; /* */ struct wtp_radio { uint8_t radioid; char device[IFNAMSIZ]; + struct wifi_device* devicehandle; - struct capwap_array* wlan; + char wlanprefix[IFNAMSIZ]; + struct capwap_list* wlan; + struct capwap_list* wlanpool; int status; struct capwap_80211_antenna_element antenna; @@ -64,7 +69,7 @@ struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlani /* */ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet); -void wtp_radio_update_fdevent(void); +void wtp_radio_update_fdevent(struct wtp_fds* fds); /* */ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwap_80211_assignbssid_element* bssid);