switch timeout processing to libev

Rework the timeout and network code to use libev.
This commit is contained in:
Andreas Schultz 2016-03-30 10:39:04 +02:00
parent a4cb96da7c
commit 9572de350a
27 changed files with 654 additions and 816 deletions

View File

@ -6,6 +6,8 @@ This fork is currently focusing on the WTP side only.
## STATUS ## STATUS
NOTE: The WTP has been ported to libev, the AC has not been adjusted and is therefor broken for the moment.
### WTP tested and working features: ### WTP tested and working features:
* 802.11b * 802.11b
@ -37,6 +39,7 @@ NOTE: To run WTP you must have a wireless card that has Linux driver based on th
* libconfig-dev * libconfig-dev
* libjson0-dev * libjson0-dev
* libnl-dev * libnl-dev
* libev-dev
* libtool * libtool
* libxml2-dev * libxml2-dev
* wolfssl 3.8 or newer * wolfssl 3.8 or newer

View File

@ -23,6 +23,7 @@ bin_PROGRAMS = wtp
AM_CFLAGS = -D_REENTRANT \ AM_CFLAGS = -D_REENTRANT \
-D_GNU_SOURCE \ -D_GNU_SOURCE \
-fno-strict-aliasing \
${LIBNL_CFLAGS} ${LIBNL_CFLAGS}
if DTLS_ENABLED if DTLS_ENABLED

View File

@ -174,6 +174,7 @@ AC_DEFINE_UNQUOTED([LIBCONFIG_LOOKUP_INT_ARG], [$LIBCONFIG_LOOKUP_INT_ARG], [con
# Check PTHREAD library # Check PTHREAD library
AC_CHECK_HEADER([pthread.h], [], [AC_MSG_ERROR(You need the pthread headers)]) AC_CHECK_HEADER([pthread.h], [], [AC_MSG_ERROR(You need the pthread headers)])
AC_CHECK_LIB([pthread], [pthread_create], [PTHREAD_LIBS="-lpthread"], [AC_MSG_ERROR(You need the pthread library)]) AC_CHECK_LIB([pthread], [pthread_create], [PTHREAD_LIBS="-lpthread"], [AC_MSG_ERROR(You need the pthread library)])
AC_CHECK_LIB([ev], [ev_run],, [AC_MSG_ERROR(Required library ev missing)])
# Check SSL library # Check SSL library
PKG_CHECK_MODULES([WOLFSSL], [wolfssl >= 3.8.0], [have_wolfssl_ssl="yes"], [have_wolfssl_ssl="no"]) PKG_CHECK_MODULES([WOLFSSL], [wolfssl >= 3.8.0], [have_wolfssl_ssl="yes"], [have_wolfssl_ssl="no"])

View File

@ -235,83 +235,42 @@ int capwap_compare_ip(union sockaddr_capwap* addr1, union sockaddr_capwap* addr2
return -1; return -1;
} }
/* Wait receive packet with timeout */
int capwap_wait_recvready(struct pollfd* fds, int fdscount, struct capwap_timeout* timeout) {
int i;
int readysocket;
int polltimeout = CAPWAP_TIMEOUT_INFINITE;
ASSERT(fds);
ASSERT(fdscount > 0);
/* Check timeout */
if (timeout) {
polltimeout = capwap_timeout_getcoming(timeout);
if (!polltimeout) {
capwap_timeout_hasexpired(timeout);
return CAPWAP_RECV_ERROR_TIMEOUT;
}
}
for (i = 0; i < fdscount; i++) {
fds[i].revents = 0;
}
/* Wait event */
readysocket = poll(fds, fdscount, polltimeout);
if (readysocket > 0) {
/* Get packet from only one socket */
for (i = 0; i < fdscount; i++) {
if (fds[i].revents & POLLIN) {
return i;
} else if ((fds[i].revents & (POLLHUP | POLLERR | POLLNVAL))) {
return CAPWAP_RECV_ERROR_SOCKET;
}
}
} else if (!readysocket && timeout) {
capwap_timeout_hasexpired(timeout);
return CAPWAP_RECV_ERROR_TIMEOUT;
} else if (errno == EINTR) {
return CAPWAP_RECV_ERROR_INTR;
}
return CAPWAP_RECV_ERROR_SOCKET;
}
/* Receive packet from fd */ /* Receive packet from fd */
int capwap_recvfrom(int sock, void* buffer, int* size, union sockaddr_capwap* fromaddr, union sockaddr_capwap* toaddr) { ssize_t capwap_recvfrom(int sock, void* buffer, size_t len,
int result = 0; union sockaddr_capwap* fromaddr,
struct iovec iov; union sockaddr_capwap* toaddr)
struct msghdr msgh; {
struct cmsghdr* cmsg; ssize_t r = 0;
char cbuf[256]; char cbuf[256];
struct iovec iov = {
.iov_base = buffer,
.iov_len = len
};
struct msghdr msgh = {
.msg_control = cbuf,
.msg_controllen = sizeof(cbuf),
.msg_name = &fromaddr->ss,
.msg_namelen = sizeof(struct sockaddr_storage),
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_flags = 0
};
struct cmsghdr* cmsg;
ASSERT(sock >= 0); ASSERT(sock >= 0);
ASSERT(buffer != NULL); ASSERT(buffer != NULL);
ASSERT(size != NULL); ASSERT(len > 0);
ASSERT(*size > 0);
ASSERT(fromaddr != NULL); ASSERT(fromaddr != NULL);
/* */
iov.iov_base = buffer;
iov.iov_len = *size;
memset(&msgh, 0, sizeof(struct msghdr));
msgh.msg_control = cbuf;
msgh.msg_controllen = sizeof(cbuf);
msgh.msg_name = &fromaddr->ss;
msgh.msg_namelen = sizeof(struct sockaddr_storage);
msgh.msg_iov = &iov;
msgh.msg_iovlen = 1;
msgh.msg_flags = 0;
/* Receive packet with recvmsg */ /* Receive packet with recvmsg */
while (result <= 0) { do {
result = recvmsg(sock, &msgh, 0); r = recvmsg(sock, &msgh, MSG_DONTWAIT);
if ((result <= 0) && (errno != EAGAIN) && (errno != EINTR)) { } while (r < 0 && errno == EINTR);
capwap_logging_warning("Unable to recv packet, recvmsg return %d with error %d", result, errno);
return -1; if (r < 0) {
} if (errno != EAGAIN)
capwap_logging_warning("Unable to recv packet, recvmsg return %d with error %d", r, errno);
return r;
} }
/* Check if IPv4 is mapped into IPv6 */ /* Check if IPv4 is mapped into IPv6 */
@ -357,18 +316,18 @@ int capwap_recvfrom(int sock, void* buffer, int* size, union sockaddr_capwap* fr
} }
} }
/* Packet receive */
*size = result;
#ifdef DEBUG #ifdef DEBUG
{ {
char strfromaddr[INET6_ADDRSTRLEN]; char strfromaddr[INET6_ADDRSTRLEN];
char strtoaddr[INET6_ADDRSTRLEN]; char strtoaddr[INET6_ADDRSTRLEN];
capwap_logging_debug("Receive packet from %s:%d to %s with size %d", capwap_address_to_string(fromaddr, strfromaddr, INET6_ADDRSTRLEN), (int)CAPWAP_GET_NETWORK_PORT(fromaddr), capwap_address_to_string(toaddr, strtoaddr, INET6_ADDRSTRLEN), result); capwap_logging_debug("Receive packet from %s:%d to %s with size %d",
capwap_address_to_string(fromaddr, strfromaddr, INET6_ADDRSTRLEN),
(int)CAPWAP_GET_NETWORK_PORT(fromaddr),
capwap_address_to_string(toaddr, strtoaddr, INET6_ADDRSTRLEN), r);
} }
#endif #endif
return 0; return r;
} }
/* */ /* */

View File

@ -74,8 +74,9 @@ int capwap_compare_ip(union sockaddr_capwap* addr1, union sockaddr_capwap* addr2
int capwap_sendto(int sock, void* buffer, int size, union sockaddr_capwap* toaddr); int capwap_sendto(int sock, void* buffer, int size, union sockaddr_capwap* toaddr);
int capwap_sendto_fragmentpacket(int sock, struct capwap_list* fragmentlist, union sockaddr_capwap* toaddr); int capwap_sendto_fragmentpacket(int sock, struct capwap_list* fragmentlist, union sockaddr_capwap* toaddr);
int capwap_wait_recvready(struct pollfd* fds, int fdscount, struct capwap_timeout* timeout); ssize_t capwap_recvfrom(int sock, void *buffer, size_t len,
int capwap_recvfrom(int sock, void* buffer, int* size, union sockaddr_capwap* fromaddr, union sockaddr_capwap* toaddr); union sockaddr_capwap* fromaddr,
union sockaddr_capwap* toaddr);
int capwap_address_from_string(const char* ip, union sockaddr_capwap* sockaddr); int capwap_address_from_string(const char* ip, union sockaddr_capwap* sockaddr);
const char* capwap_address_to_string(union sockaddr_capwap* sockaddr, char* ip, int len); const char* capwap_address_to_string(union sockaddr_capwap* sockaddr, char* ip, int len);

View File

@ -4,6 +4,8 @@
#include "wifi_drivers.h" #include "wifi_drivers.h"
#include "netlink_link.h" #include "netlink_link.h"
static void netlink_event_receive_cb(EV_P_ ev_io *w, int revents);
/* */ /* */
struct netlink_request { struct netlink_request {
struct nlmsghdr hdr; struct nlmsghdr hdr;
@ -12,7 +14,8 @@ struct netlink_request {
}; };
/* */ /* */
struct netlink* netlink_init(void) { struct netlink *netlink_init(wifi_global_handle handle)
{
int sock; int sock;
struct sockaddr_nl local; struct sockaddr_nl local;
struct netlink* netlinkhandle; struct netlink* netlinkhandle;
@ -34,43 +37,61 @@ struct netlink* netlink_init(void) {
/* Netlink reference */ /* Netlink reference */
netlinkhandle = (struct netlink*)capwap_alloc(sizeof(struct netlink)); netlinkhandle = (struct netlink*)capwap_alloc(sizeof(struct netlink));
netlinkhandle->handle = handle;
netlinkhandle->sock = sock; netlinkhandle->sock = sock;
netlinkhandle->nl_sequence = 1; netlinkhandle->nl_sequence = 1;
ev_io_init(&netlinkhandle->io_ev, netlink_event_receive_cb, sock, EV_READ);
ev_io_start(EV_DEFAULT_UC_ &netlinkhandle->io_ev);
return netlinkhandle; return netlinkhandle;
} }
/* */ /* */
void netlink_free(struct netlink* netlinkhandle) { void netlink_free(struct netlink* netlinkhandle)
{
ASSERT(netlinkhandle != NULL); ASSERT(netlinkhandle != NULL);
ASSERT(netlinkhandle->sock >= 0); ASSERT(netlinkhandle->sock >= 0);
if (ev_is_active(&netlinkhandle->io_ev))
ev_io_stop(EV_DEFAULT_UC_ &netlinkhandle->io_ev);
/* */ /* */
close(netlinkhandle->sock); close(netlinkhandle->sock);
capwap_free(netlinkhandle); capwap_free(netlinkhandle);
} }
static void invoke_event_fn(netlink_event_fn event_fn, struct netlink *netlinkhandle, struct nlmsghdr* message)
{
if (!event_fn)
return;
if (NLMSG_PAYLOAD(message, 0) < sizeof(struct ifinfomsg))
return;
event_fn(netlinkhandle->handle,
NLMSG_DATA(message),
(uint8_t*)(NLMSG_DATA(message) + NLMSG_ALIGN(sizeof(struct ifinfomsg))),
NLMSG_PAYLOAD(message, sizeof(struct ifinfomsg)));
}
/* */ /* */
void netlink_event_receive(int fd, void** params, int paramscount) { static void netlink_event_receive_cb(EV_P_ ev_io *w, int revents)
{
struct netlink *netlinkhandle = (struct netlink *)
(((char *)w) - offsetof(struct netlink, io_ev));
int result; int result;
struct netlink* netlinkhandle;
struct sockaddr_nl from; struct sockaddr_nl from;
socklen_t fromlen; socklen_t fromlen;
char buffer[8192]; char buffer[8192];
struct nlmsghdr* message; struct nlmsghdr* message;
ASSERT(fd >= 0);
ASSERT(params != NULL);
ASSERT(paramscount == 2);
/* */
netlinkhandle = (struct netlink*)params[0];
/* Retrieve all netlink message */ /* Retrieve all netlink message */
for (;;) { for (;;) {
/* Get message */ /* Get message */
fromlen = sizeof(struct sockaddr_nl); fromlen = sizeof(struct sockaddr_nl);
result = recvfrom(netlinkhandle->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&from, &fromlen); result = recvfrom(w->fd, buffer, sizeof(buffer), MSG_DONTWAIT,
(struct sockaddr *)&from, &fromlen);
if (result <= 0) { if (result <= 0) {
if (errno == EINTR) { if (errno == EINTR) {
continue; continue;
@ -84,21 +105,18 @@ void netlink_event_receive(int fd, void** params, int paramscount) {
message = (struct nlmsghdr*)buffer; message = (struct nlmsghdr*)buffer;
while (NLMSG_OK(message, result)) { while (NLMSG_OK(message, result)) {
switch (message->nlmsg_type) { switch (message->nlmsg_type) {
case RTM_NEWLINK: { case RTM_NEWLINK:
if (netlinkhandle->newlink_event && NLMSG_PAYLOAD(message, 0) >= sizeof(struct ifinfomsg)) { invoke_event_fn(netlinkhandle->newlink_event,
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))); netlinkhandle, message);
} break;
break; case RTM_DELLINK:
} invoke_event_fn(netlinkhandle->dellink_event,
netlinkhandle, message);
break;
case RTM_DELLINK: { default:
if (netlinkhandle->dellink_event && NLMSG_PAYLOAD(message, 0) >= sizeof(struct ifinfomsg)) { break;
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;
}
} }
/* */ /* */

View File

@ -4,6 +4,8 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <ev.h>
/* */ /* */
#ifndef IFLA_IFNAME #ifndef IFLA_IFNAME
#define IFLA_IFNAME 3 #define IFLA_IFNAME 3
@ -37,17 +39,23 @@
#define IFF_DORMANT 0x20000 #define IFF_DORMANT 0x20000
#endif #endif
typedef void (*netlink_event_fn)(wifi_global_handle handle, struct ifinfomsg* infomsg,
uint8_t* data, int length);
/* */ /* */
struct netlink { struct netlink {
wifi_global_handle handle;
int sock; int sock;
void (*newlink_event)(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length); ev_io io_ev;
void (*dellink_event)(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length);
netlink_event_fn newlink_event;
netlink_event_fn dellink_event;
int nl_sequence; int nl_sequence;
}; };
/* */ /* */
struct netlink* netlink_init(void); struct netlink* netlink_init(wifi_global_handle handle);
void netlink_free(struct netlink* netlinkhandle); void netlink_free(struct netlink* netlinkhandle);
/* */ /* */

View File

@ -25,11 +25,18 @@ static struct wifi_global g_wifiglobal;
static uint8_t g_bufferIEEE80211[IEEE80211_MTU]; static uint8_t g_bufferIEEE80211[IEEE80211_MTU];
/* */ /* */
static void wifi_station_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); static void wifi_station_timeout_delete(EV_P_ ev_timer *w, int revents);
static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode, int reusestation); static void wifi_station_timeout_deauth(EV_P_ ev_timer *w, int revents);
static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan,
struct wifi_station* station,
uint16_t reasoncode,
int reusestation);
/* */ /* */
static void wifi_wlan_getrates(struct wifi_device* device, uint8_t* rates, int ratescount, 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 i, j, w;
int radiotype; int radiotype;
uint32_t mode = 0; uint32_t mode = 0;
@ -262,10 +269,7 @@ static void wifi_station_clean(struct wifi_station* station) {
} }
/* Remove timers */ /* Remove timers */
if (station->idtimeout != CAPWAP_TIMEOUT_INDEX_NO_SET) { ev_timer_stop(EV_DEFAULT_UC_ &station->timeout);
capwap_timeout_deletetimer(g_wifiglobal.timeout, station->idtimeout);
station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET;
}
/* */ /* */
station->flags = 0; station->flags = 0;
@ -273,7 +277,8 @@ static void wifi_station_clean(struct wifi_station* station) {
} }
/* */ /* */
static void wifi_station_delete(struct wifi_station* station) { static void wifi_station_delete(struct wifi_station* station)
{
ASSERT(station != NULL); ASSERT(station != NULL);
/* */ /* */
@ -283,8 +288,10 @@ static void wifi_station_delete(struct wifi_station* station) {
wifi_station_clean(station); wifi_station_clean(station);
/* Delay delete station */ /* Delay delete station */
station->timeoutaction = WIFI_STATION_TIMEOUT_ACTION_DELETE; ev_timer_stop(EV_DEFAULT_UC_ &station->timeout);
station->idtimeout = capwap_timeout_set(g_wifiglobal.timeout, station->idtimeout, WIFI_STATION_TIMEOUT_AFTER_DEAUTHENTICATED, wifi_station_timeout, station, NULL); ev_timer_init(&station->timeout, wifi_station_timeout_delete,
WIFI_STATION_TIMEOUT_AFTER_DEAUTHENTICATED / 1000.0, 0.);
ev_timer_start(EV_DEFAULT_UC_ &station->timeout);
} }
/* */ /* */
@ -327,7 +334,6 @@ static struct wifi_station* wifi_station_create(struct wifi_wlan* wlan, const ui
/* Initialize station */ /* Initialize station */
memcpy(station->address, address, MACADDRESS_EUI48_LENGTH); memcpy(station->address, address, MACADDRESS_EUI48_LENGTH);
capwap_printf_macaddress(station->addrtext, address, MACADDRESS_EUI48_LENGTH); capwap_printf_macaddress(station->addrtext, address, MACADDRESS_EUI48_LENGTH);
station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET;
/* Add to pool */ /* Add to pool */
capwap_hash_add(g_wifiglobal.stations, station); capwap_hash_add(g_wifiglobal.stations, station);
@ -371,7 +377,11 @@ static void wifi_wlan_send_mgmt_deauthentication(struct wifi_wlan* wlan, const u
} }
/* */ /* */
static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode, int reusestation) { static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan,
struct wifi_station* station,
uint16_t reasoncode,
int reusestation)
{
ASSERT(wlan != NULL); ASSERT(wlan != NULL);
ASSERT(station != NULL); ASSERT(station != NULL);
@ -389,31 +399,33 @@ static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan, struct wi
} }
/* */ /* */
static void wifi_station_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { static void wifi_station_timeout_delete(EV_P_ ev_timer *w, int revents)
struct wifi_station* station = (struct wifi_station*)context; {
struct wifi_station *station = (struct wifi_station *)
(((char *)w) - offsetof(struct wifi_station, timeout));
ASSERT(station != NULL); /* Free station into hash callback function */
wifi_station_clean(station);
capwap_hash_delete(g_wifiglobal.stations, station->address);
}
if (station->idtimeout == index) { static void wifi_station_timeout_deauth(EV_P_ ev_timer *w, int revents)
switch (station->timeoutaction) { {
case WIFI_STATION_TIMEOUT_ACTION_DELETE: { struct wifi_station *station = (struct wifi_station *)
/* Free station into hash callback function */ (((char *)w) - offsetof(struct wifi_station, timeout));
wifi_station_clean(station); struct wifi_wlan* wlan = (struct wifi_wlan *)w->data;
capwap_hash_delete(g_wifiglobal.stations, station->address);
break;
}
case WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE: { capwap_logging_warning("The %s station has not completed the association in time",
capwap_logging_warning("The %s station has not completed the association in time", station->addrtext); station->addrtext);
wifi_wlan_deauthentication_station((struct wifi_wlan*)param, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0);
break;
}
}
}
} }
/* */ /* */
static void wifi_wlan_receive_station_mgmt_probe_request(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { static void wifi_wlan_receive_station_mgmt_probe_request(struct wifi_wlan* wlan,
const struct ieee80211_header_mgmt* frame,
int length, uint8_t rssi,
uint8_t snr, uint16_t rate)
{
int ielength; int ielength;
int ssidcheck; int ssidcheck;
int nowaitack; int nowaitack;
@ -590,8 +602,11 @@ static void wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan
station = wifi_station_create(wlan, frame->sa); station = wifi_station_create(wlan, frame->sa);
if (station) { if (station) {
/* A station is removed if the association does not complete within a given period of time */ /* A station is removed if the association does not complete within a given period of time */
station->timeoutaction = WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE; ev_timer_stop(EV_DEFAULT_UC_ &station->timeout);
station->idtimeout = capwap_timeout_set(g_wifiglobal.timeout, station->idtimeout, WIFI_STATION_TIMEOUT_ASSOCIATION_COMPLETE, wifi_station_timeout, station, wlan); ev_timer_init(&station->timeout, wifi_station_timeout_deauth,
WIFI_STATION_TIMEOUT_ASSOCIATION_COMPLETE / 1000.0, 0.);
station->timeout.data = wlan;
ev_timer_start(EV_DEFAULT_UC_ &station->timeout);
responsestatuscode = IEEE80211_STATUS_SUCCESS; responsestatuscode = IEEE80211_STATUS_SUCCESS;
} else { } else {
responsestatuscode = IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; responsestatuscode = IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
@ -1134,11 +1149,10 @@ static int wifi_wlan_receive_ac_mgmt_frame(struct wifi_wlan* wlan, struct ieee80
} }
/* */ /* */
int wifi_driver_init(struct capwap_timeout* timeout) { int wifi_driver_init()
{
int i; int i;
ASSERT(timeout != NULL);
/* Socket utils */ /* Socket utils */
memset(&g_wifiglobal, 0, sizeof(struct wifi_global)); memset(&g_wifiglobal, 0, sizeof(struct wifi_global));
g_wifiglobal.sock_util = socket(AF_PACKET, SOCK_RAW, 0); g_wifiglobal.sock_util = socket(AF_PACKET, SOCK_RAW, 0);
@ -1156,7 +1170,6 @@ int wifi_driver_init(struct capwap_timeout* timeout) {
} }
/* */ /* */
g_wifiglobal.timeout = timeout;
g_wifiglobal.devices = capwap_list_create(); g_wifiglobal.devices = capwap_list_create();
g_wifiglobal.stations = capwap_hash_create(WIFI_STATIONS_HASH_SIZE); g_wifiglobal.stations = capwap_hash_create(WIFI_STATIONS_HASH_SIZE);
g_wifiglobal.stations->item_gethash = wifi_hash_station_gethash; g_wifiglobal.stations->item_gethash = wifi_hash_station_gethash;
@ -1234,44 +1247,6 @@ void wifi_driver_free(void) {
close(g_wifiglobal.sock_util); close(g_wifiglobal.sock_util);
} }
/* */
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;
if ((count > 0) && (!fds || !events)) {
return -1;
}
/* Get from driver */
for (i = 0; wifi_driver[i].ops != NULL; i++) {
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_wifiglobal.devices->first; itemdevice != NULL; itemdevice = itemdevice->next) {
struct wifi_device* device = (struct wifi_device*)itemdevice->item;
if (device->handle) {
result += device->instance->ops->device_getfdevent(device, (count ? &fds[result] : NULL), (count ? &events[result] : NULL));
/* Get from wlan */
if (device->wlans) {
for (itemwlan = device->wlans->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, (count ? &fds[result] : NULL), (count ? &events[result] : NULL));
}
}
}
}
}
return result;
}
/* */ /* */
struct wifi_wlan* wifi_get_wlan(uint32_t ifindex) { struct wifi_wlan* wifi_get_wlan(uint32_t ifindex) {
struct capwap_list_item* itemdevice; struct capwap_list_item* itemdevice;
@ -1318,39 +1293,40 @@ struct wifi_device* wifi_device_connect(const char* ifname, const char* driver)
/* Search driver */ /* Search driver */
for (i = 0; wifi_driver[i].ops != NULL; i++) { for (i = 0; wifi_driver[i].ops != NULL; i++) {
if (!strcmp(driver, wifi_driver[i].ops->name)) { if (strcmp(driver, wifi_driver[i].ops->name) != 0)
itemdevice = capwap_itemlist_create(sizeof(struct wifi_device)); continue;
device = (struct wifi_device*)itemdevice->item;
memset(device, 0, sizeof(struct wifi_device));
/* */ itemdevice = capwap_itemlist_create(sizeof(struct wifi_device));
device->global = &g_wifiglobal; device = (struct wifi_device*)itemdevice->item;
device->instance = &wifi_driver[i]; memset(device, 0, sizeof(struct wifi_device));
strcpy(device->phyname, ifname);
/* Device init */ /* */
if (!wifi_driver[i].ops->device_init(wifi_driver[i].handle, device)) { device->global = &g_wifiglobal;
/* Registered new device */ device->instance = &wifi_driver[i];
device->wlans = capwap_list_create(); strcpy(device->phyname, ifname);
/* Device capability */ /* Device init */
device->capability = (struct wifi_capability*)capwap_alloc(sizeof(struct wifi_capability)); if (wifi_driver[i].ops->device_init(wifi_driver[i].handle, device)) {
memset(device->capability, 0, sizeof(struct wifi_capability)); capwap_itemlist_free(itemdevice);
device->capability->bands = capwap_array_create(sizeof(struct wifi_band_capability), 0, 1); return NULL;
device->capability->ciphers = capwap_array_create(sizeof(struct wifi_cipher_capability), 0, 1);
/* Retrieve device capability */
device->instance->ops->device_getcapability(device, device->capability);
/* Appent to device list */
capwap_itemlist_insert_after(g_wifiglobal.devices, NULL, itemdevice);
} else {
capwap_itemlist_free(itemdevice);
device = NULL;
}
break;
} }
/* Registered new device */
device->wlans = capwap_list_create();
/* Device capability */
device->capability = (struct wifi_capability*)capwap_alloc(sizeof(struct wifi_capability));
memset(device->capability, 0, sizeof(struct wifi_capability));
device->capability->bands = capwap_array_create(sizeof(struct wifi_band_capability), 0, 1);
device->capability->ciphers = capwap_array_create(sizeof(struct wifi_cipher_capability), 0, 1);
/* Retrieve device capability */
device->instance->ops->device_getcapability(device, device->capability);
/* Appent to device list */
capwap_itemlist_insert_after(g_wifiglobal.devices, NULL, itemdevice);
break;
} }
return device; return device;
@ -1886,10 +1862,6 @@ int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* pa
return 0; return 0;
} }
/* */
capwap_timeout_deletetimer(g_wifiglobal.timeout, station->idtimeout);
station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET;
/* Station is authorized only after Authentication and Association */ /* Station is authorized only after Authentication and Association */
station->flags |= WIFI_STATION_FLAGS_AUTHORIZED; station->flags |= WIFI_STATION_FLAGS_AUTHORIZED;
if (!(station->flags & WIFI_STATION_FLAGS_AUTHENTICATED) || if (!(station->flags & WIFI_STATION_FLAGS_AUTHENTICATED) ||

View File

@ -5,6 +5,8 @@
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include "ieee80211.h" #include "ieee80211.h"
#include <ev.h>
/* */ /* */
#define WIFI_DRIVER_NAME_SIZE 16 #define WIFI_DRIVER_NAME_SIZE 16
@ -227,9 +229,6 @@ struct wifi_global {
int sock_util; int sock_util;
struct capwap_list* devices; struct capwap_list* devices;
/* Timeout */
struct capwap_timeout* timeout;
/* Stations */ /* Stations */
struct capwap_hash* stations; struct capwap_hash* stations;
}; };
@ -353,8 +352,7 @@ struct wifi_station {
unsigned long flags; unsigned long flags;
/* Timers */ /* Timers */
int timeoutaction; struct ev_timer timeout;
unsigned long idtimeout;
/* */ /* */
uint16_t capability; uint16_t capability;
@ -380,12 +378,10 @@ struct wifi_driver_ops {
/* Global initialize driver */ /* Global initialize driver */
wifi_global_handle (*global_init)(void); wifi_global_handle (*global_init)(void);
int (*global_getfdevent)(wifi_global_handle handle, struct pollfd* fds, struct wifi_event* events);
void (*global_deinit)(wifi_global_handle handle); void (*global_deinit)(wifi_global_handle handle);
/* Device functions */ /* Device functions */
int (*device_init)(wifi_global_handle handle, struct wifi_device* device); int (*device_init)(wifi_global_handle handle, struct wifi_device* device);
int (*device_getfdevent)(struct wifi_device* device, struct pollfd* fds, struct wifi_event* events);
int (*device_getcapability)(struct wifi_device* device, struct wifi_capability* capability); int (*device_getcapability)(struct wifi_device* device, struct wifi_capability* capability);
void (*device_updatebeacons)(struct wifi_device* device); void (*device_updatebeacons)(struct wifi_device* device);
int (*device_setfrequency)(struct wifi_device* device); int (*device_setfrequency)(struct wifi_device* device);
@ -395,7 +391,6 @@ struct wifi_driver_ops {
/* WLAN functions */ /* WLAN functions */
wifi_wlan_handle (*wlan_create)(struct wifi_device* device, struct wifi_wlan* wlan); wifi_wlan_handle (*wlan_create)(struct wifi_device* device, struct wifi_wlan* wlan);
int (*wlan_getfdevent)(struct wifi_wlan* wlan, struct pollfd* fds, struct wifi_event* events);
int (*wlan_startap)(struct wifi_wlan* wlan); int (*wlan_startap)(struct wifi_wlan* wlan);
void (*wlan_stopap)(struct wifi_wlan* wlan); void (*wlan_stopap)(struct wifi_wlan* wlan);
int (*wlan_sendframe)(struct wifi_wlan* wlan, uint8_t* frame, int length, uint32_t frequency, uint32_t duration, int offchannel_tx_ok, int no_cck_rate, int no_wait_ack); int (*wlan_sendframe)(struct wifi_wlan* wlan, uint8_t* frame, int length, uint32_t frequency, uint32_t duration, int offchannel_tx_ok, int no_cck_rate, int no_wait_ack);
@ -407,12 +402,9 @@ struct wifi_driver_ops {
}; };
/* Initialize wifi driver engine */ /* Initialize wifi driver engine */
int wifi_driver_init(struct capwap_timeout* timeout); int wifi_driver_init(void);
void wifi_driver_free(void); void wifi_driver_free(void);
/* Get File Descriptor Event */
int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count);
/* */ /* */
struct wifi_wlan* wifi_get_wlan(uint32_t ifindex); struct wifi_wlan* wifi_get_wlan(uint32_t ifindex);

View File

@ -120,7 +120,12 @@ static int nl80211_ack_handler(struct nl_msg* msg, void* arg) {
} }
/* */ /* */
static int nl80211_send_and_recv(struct nl_sock* nl, struct nl_cb* nl_cb, struct nl_msg* msg, nl_valid_cb valid_cb, void* data) { static int nl80211_send_and_recv(struct nl_sock *nl,
struct nl_cb *nl_cb,
struct nl_msg *msg,
nl_valid_cb valid_cb,
void *data)
{
int result; int result;
struct nl_cb* cb; struct nl_cb* cb;
@ -156,12 +161,17 @@ static int nl80211_send_and_recv(struct nl_sock* nl, struct nl_cb* nl_cb, struct
} }
/* */ /* */
static int nl80211_send_and_recv_msg(struct nl80211_global_handle* globalhandle, struct nl_msg* msg, nl_valid_cb valid_cb, void* data) { static int nl80211_send_and_recv_msg(struct nl80211_global_handle* globalhandle,
struct nl_msg* msg,
nl_valid_cb valid_cb,
void* data)
{
return nl80211_send_and_recv(globalhandle->nl, globalhandle->nl_cb, msg, valid_cb, data); return nl80211_send_and_recv(globalhandle->nl, globalhandle->nl_cb, msg, valid_cb, data);
} }
/* */ /* */
static int cb_family_handler(struct nl_msg* msg, void* data) { static int cb_family_handler(struct nl_msg* msg, void* data)
{
int i; int i;
struct nlattr* mcast_group; struct nlattr* mcast_group;
struct nlattr* tb_msg[CTRL_ATTR_MAX + 1]; struct nlattr* tb_msg[CTRL_ATTR_MAX + 1];
@ -591,52 +601,37 @@ static wifi_wlan_handle nl80211_wlan_create(struct wifi_device* device, struct w
memset(wlanhandle, 0, sizeof(struct nl80211_wlan_handle)); memset(wlanhandle, 0, sizeof(struct nl80211_wlan_handle));
wlanhandle->devicehandle = devicehandle; wlanhandle->devicehandle = devicehandle;
wlanhandle->nl_fd = -1;
return (wifi_wlan_handle)wlanhandle; return (wifi_wlan_handle)wlanhandle;
} }
/* */ /* */
static void nl80211_event_receive(int fd, void** params, int paramscount) { static void nl80211_global_event_receive_cb(EV_P_ ev_io *w, int revents)
{
struct nl80211_global_handle *globalhandle = (struct nl80211_global_handle *)
(((char *)w) - offsetof(struct nl80211_global_handle, nl_event_ev));
int res; int res;
ASSERT(fd >= 0); capwap_logging_warning("nl80211_global_event_receive_cb on fd %d", w->fd);
ASSERT(params != NULL);
ASSERT(paramscount == 2);
/* */ /* */
res = nl_recvmsgs((struct nl_sock*)params[0], (struct nl_cb*)params[1]); res = nl_recvmsgs(globalhandle->nl_event, globalhandle->nl_cb);
if (res) { if (res) {
capwap_logging_warning("Receive nl80211 message failed: %d", res); capwap_logging_warning("Receive nl80211 message failed: %d", res);
} }
} }
/* */ static void nl80211_wlan_event_receive_cb(EV_P_ ev_io *w, int revents)
static int nl80211_wlan_getfdevent(struct wifi_wlan* wlan, struct pollfd* fds, struct wifi_event* events) { {
struct nl80211_wlan_handle* wlanhandle; struct nl80211_wlan_handle *wlanhandle = (struct nl80211_wlan_handle *)
(((char *)w) - offsetof(struct nl80211_wlan_handle, nl_ev));
ASSERT(wlan != NULL); int res;
ASSERT(wlan->handle != NULL);
capwap_logging_warning("nl80211_wlan_event_receive_cb on fd %d", w->fd);
/* */ /* */
wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; res = nl_recvmsgs(wlanhandle->nl, wlanhandle->nl_cb);
if (!(wlan->flags & WIFI_WLAN_RUNNING) || (wlanhandle->nl_fd < 0)) { if (res) {
return 0; capwap_logging_warning("Receive nl80211 message failed: %d", res);
} }
if (fds) {
fds[0].fd = wlanhandle->nl_fd;
fds[0].events = POLLIN | POLLERR | POLLHUP;
}
if (events) {
events[0].event_handler = nl80211_event_receive;
events[0].params[0] = (void*)wlanhandle->nl;
events[0].params[1] = (void*)wlanhandle->nl_cb;
events[0].paramscount = 2;
}
return 1;
} }
/* */ /* */
@ -807,11 +802,8 @@ static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_wlan_valid_handler, (void*)wlan); nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_wlan_valid_handler, (void*)wlan);
wlanhandle->nl = nl_create_handle(wlanhandle->nl_cb); wlanhandle->nl = nl_create_handle(wlanhandle->nl_cb);
if (wlanhandle->nl) { if (!wlanhandle->nl)
wlanhandle->nl_fd = nl_socket_get_fd(wlanhandle->nl);
} else {
return -1; return -1;
}
/* Register frames */ /* Register frames */
for (i = 0; i < sizeof(g_stypes) / sizeof(g_stypes[0]); i++) { for (i = 0; i < sizeof(g_stypes) / sizeof(g_stypes[0]); i++) {
@ -837,6 +829,12 @@ static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
/* Enable interface */ /* Enable interface */
wlan->flags |= WIFI_WLAN_RUNNING; wlan->flags |= WIFI_WLAN_RUNNING;
/* hook into I/O loop */
ev_io_init(&wlanhandle->nl_ev, nl80211_wlan_event_receive_cb,
nl_socket_get_fd(wlanhandle->nl), EV_READ);
ev_io_start(EV_DEFAULT_UC_ &wlanhandle->nl_ev);
if (wifi_iface_up(wlanhandle->devicehandle->globalhandle->sock_util, wlan->virtname)) { if (wifi_iface_up(wlanhandle->devicehandle->globalhandle->sock_util, wlan->virtname)) {
return -1; return -1;
} }
@ -897,10 +895,12 @@ static void nl80211_wlan_stopap(struct wifi_wlan* wlan) {
nl80211_wlan_set_profile(wlan, NL80211_IFTYPE_STATION); nl80211_wlan_set_profile(wlan, NL80211_IFTYPE_STATION);
/* */ /* */
if (ev_is_active(&wlanhandle->nl_ev))
ev_io_stop(EV_DEFAULT_UC_ &wlanhandle->nl_ev);
if (wlanhandle->nl) { if (wlanhandle->nl) {
nl_socket_free(wlanhandle->nl); nl_socket_free(wlanhandle->nl);
wlanhandle->nl = NULL; wlanhandle->nl = NULL;
wlanhandle->nl_fd = -1;
} }
if (wlanhandle->nl_cb) { if (wlanhandle->nl_cb) {
@ -1229,14 +1229,6 @@ int nl80211_device_init(wifi_global_handle handle, struct wifi_device* device) {
return 0; return 0;
} }
/* */
static int nl80211_device_getfdevent(struct wifi_device* device, struct pollfd* fds, struct wifi_event* events) {
ASSERT(device != NULL);
ASSERT(device->handle != NULL);
return 0;
}
/* */ /* */
static unsigned long nl80211_get_cipher(uint32_t chiper) { static unsigned long nl80211_get_cipher(uint32_t chiper) {
switch (chiper) { switch (chiper) {
@ -1676,7 +1668,8 @@ static int nl80211_device_setfrequency(struct wifi_device* device) {
} }
/* */ /* */
static void nl80211_device_deinit(struct wifi_device* device) { static void nl80211_device_deinit(struct wifi_device* device)
{
struct nl80211_device_handle* devicehandle; struct nl80211_device_handle* devicehandle;
ASSERT(device != NULL); ASSERT(device != NULL);
@ -1689,36 +1682,38 @@ static void nl80211_device_deinit(struct wifi_device* device) {
} }
/* */ /* */
static void nl80211_global_deinit(wifi_global_handle handle) { static void nl80211_global_deinit(wifi_global_handle handle)
{
struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle;
if (globalhandle) { if (!globalhandle)
if (globalhandle->netlinkhandle) { return;
netlink_free(globalhandle->netlinkhandle);
}
if (globalhandle->nl) { if (globalhandle->netlinkhandle)
nl_socket_free(globalhandle->nl); netlink_free(globalhandle->netlinkhandle);
}
if (globalhandle->nl_event) { if (globalhandle->nl)
nl_socket_free(globalhandle->nl_event); nl_socket_free(globalhandle->nl);
}
if (globalhandle->nl_cb) { if (globalhandle->nl_event)
nl_cb_put(globalhandle->nl_cb); nl_socket_free(globalhandle->nl_event);
}
if (globalhandle->sock_util >= 0) { if (ev_is_active(&globalhandle->nl_event_ev))
close(globalhandle->sock_util); ev_io_stop(EV_DEFAULT_UC_ &globalhandle->nl_event_ev);
}
capwap_free(globalhandle); if (globalhandle->nl_cb)
} nl_cb_put(globalhandle->nl_cb);
if (globalhandle->sock_util >= 0)
close(globalhandle->sock_util);
capwap_free(globalhandle);
} }
/* */ /* */
static void nl80211_global_newlink_event(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length) { static void nl80211_global_newlink_event(wifi_global_handle handle, struct ifinfomsg* infomsg,
uint8_t* data, int length)
{
struct wifi_wlan* wlan; struct wifi_wlan* wlan;
struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle;
@ -1727,22 +1722,29 @@ static void nl80211_global_newlink_event(wifi_global_handle handle, struct ifinf
/* Search device */ /* Search device */
wlan = wifi_get_wlan(infomsg->ifi_index); wlan = wifi_get_wlan(infomsg->ifi_index);
if (wlan) { if (!wlan)
if (!(wlan->flags & WIFI_WLAN_RUNNING)) { return;
if ((infomsg->ifi_flags & IFF_UP) && (wifi_iface_getstatus(globalhandle->sock_util, wlan->virtname) > 0)) {
wifi_iface_down(globalhandle->sock_util, wlan->virtname); if (!(wlan->flags & WIFI_WLAN_RUNNING)) {
} if ((infomsg->ifi_flags & IFF_UP) &&
} else if (wlan->flags & WIFI_WLAN_SET_BEACON) { (wifi_iface_getstatus(globalhandle->sock_util, wlan->virtname) > 0)) {
if ((wlan->flags & WIFI_WLAN_OPERSTATE_RUNNING) && (infomsg->ifi_flags & IFF_LOWER_UP) && !(infomsg->ifi_flags & (IFF_RUNNING | IFF_DORMANT))) { wifi_iface_down(globalhandle->sock_util, wlan->virtname);
struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; }
netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle, wlan->virtindex, -1, IF_OPER_UP); } else if (wlan->flags & WIFI_WLAN_SET_BEACON) {
} if ((wlan->flags & WIFI_WLAN_OPERSTATE_RUNNING) &&
(infomsg->ifi_flags & IFF_LOWER_UP) &&
!(infomsg->ifi_flags & (IFF_RUNNING | IFF_DORMANT))) {
struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle;
netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle,
wlan->virtindex, -1, IF_OPER_UP);
} }
} }
} }
/* */ /* */
static void nl80211_global_dellink_event(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length) { static void nl80211_global_dellink_event(wifi_global_handle handle, struct ifinfomsg* infomsg,
uint8_t* data, int length)
{
} }
/* */ /* */
@ -1768,7 +1770,8 @@ static int nl80211_global_valid_handler(struct nl_msg* msg, void* data) {
} }
/* */ /* */
static wifi_global_handle nl80211_global_init(void) { static wifi_global_handle nl80211_global_init()
{
int result; int result;
struct nl80211_global_handle* globalhandle; struct nl80211_global_handle* globalhandle;
@ -1793,13 +1796,16 @@ static wifi_global_handle nl80211_global_init(void) {
/* Create netlink socket for event */ /* Create netlink socket for event */
globalhandle->nl_event = nl_create_handle(globalhandle->nl_cb); globalhandle->nl_event = nl_create_handle(globalhandle->nl_cb);
if (globalhandle->nl_event) { if (!globalhandle->nl_event) {
globalhandle->nl_event_fd = nl_socket_get_fd(globalhandle->nl_event);
} else {
nl80211_global_deinit((wifi_global_handle)globalhandle); nl80211_global_deinit((wifi_global_handle)globalhandle);
return NULL; return NULL;
} }
/* hook into I/O loop */
ev_io_init(&globalhandle->nl_event_ev, nl80211_global_event_receive_cb,
nl_socket_get_fd(globalhandle->nl_event), EV_READ);
ev_io_start(EV_DEFAULT_UC_ &globalhandle->nl_event_ev);
/* Add membership scan events */ /* Add membership scan events */
result = nl80211_get_multicast_id(globalhandle, "nl80211", "scan"); result = nl80211_get_multicast_id(globalhandle, "nl80211", "scan");
if (result >= 0) { if (result >= 0) {
@ -1841,7 +1847,7 @@ static wifi_global_handle nl80211_global_init(void) {
nl_cb_set(globalhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_global_valid_handler, NULL); nl_cb_set(globalhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_global_valid_handler, NULL);
/* Netlink lisk status */ /* Netlink lisk status */
globalhandle->netlinkhandle = netlink_init(); globalhandle->netlinkhandle = netlink_init((wifi_global_handle)globalhandle);
if (!globalhandle->netlinkhandle) { if (!globalhandle->netlinkhandle) {
nl80211_global_deinit((wifi_global_handle)globalhandle); nl80211_global_deinit((wifi_global_handle)globalhandle);
return NULL; return NULL;
@ -1860,46 +1866,14 @@ static wifi_global_handle nl80211_global_init(void) {
return (wifi_global_handle)globalhandle; return (wifi_global_handle)globalhandle;
} }
/* */
static int nl80211_global_getfdevent(wifi_global_handle handle, struct pollfd* fds, struct wifi_event* events) {
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].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 2;
}
/* Driver function */ /* Driver function */
const struct wifi_driver_ops wifi_driver_nl80211_ops = { const struct wifi_driver_ops wifi_driver_nl80211_ops = {
.name = "nl80211", .name = "nl80211",
.description = "Linux nl80211/cfg80211", .description = "Linux nl80211/cfg80211",
.global_init = nl80211_global_init, .global_init = nl80211_global_init,
.global_getfdevent = nl80211_global_getfdevent,
.global_deinit = nl80211_global_deinit, .global_deinit = nl80211_global_deinit,
.device_init = nl80211_device_init, .device_init = nl80211_device_init,
.device_getfdevent = nl80211_device_getfdevent,
.device_getcapability = nl80211_device_getcapability, .device_getcapability = nl80211_device_getcapability,
.device_updatebeacons = nl80211_device_updatebeacons, .device_updatebeacons = nl80211_device_updatebeacons,
.device_settxqueue = nl80211_device_settxqueue, .device_settxqueue = nl80211_device_settxqueue,
@ -1907,7 +1881,6 @@ const struct wifi_driver_ops wifi_driver_nl80211_ops = {
.device_deinit = nl80211_device_deinit, .device_deinit = nl80211_device_deinit,
.wlan_create = nl80211_wlan_create, .wlan_create = nl80211_wlan_create,
.wlan_getfdevent = nl80211_wlan_getfdevent,
.wlan_startap = nl80211_wlan_startap, .wlan_startap = nl80211_wlan_startap,
.wlan_stopap = nl80211_wlan_stopap, .wlan_stopap = nl80211_wlan_stopap,
.wlan_sendframe = nl80211_wlan_sendframe, .wlan_sendframe = nl80211_wlan_sendframe,

View File

@ -1,6 +1,8 @@
#ifndef __WIFI_NL80211_HEADER__ #ifndef __WIFI_NL80211_HEADER__
#define __WIFI_NL80211_HEADER__ #define __WIFI_NL80211_HEADER__
#include <ev.h>
#include "capwap_hash.h" #include "capwap_hash.h"
#include "netlink_link.h" #include "netlink_link.h"
@ -18,12 +20,13 @@ typedef int (*nl_valid_cb)(struct nl_msg* msg, void* data);
/* Global handle */ /* Global handle */
struct nl80211_global_handle { struct nl80211_global_handle {
struct nl_sock* nl;
struct nl_cb* nl_cb;
int nl80211_id; int nl80211_id;
struct nl_sock* nl_event; struct nl_sock* nl;
int nl_event_fd; struct nl_cb* nl_cb;
struct nl_sock *nl_event;
ev_io nl_event_ev;
struct netlink* netlinkhandle; struct netlink* netlinkhandle;
@ -39,9 +42,9 @@ struct nl80211_device_handle {
struct nl80211_wlan_handle { struct nl80211_wlan_handle {
struct nl80211_device_handle* devicehandle; struct nl80211_device_handle* devicehandle;
struct nl_sock* nl; struct nl_sock *nl;
int nl_fd; ev_io nl_ev;
struct nl_cb* nl_cb; struct nl_cb *nl_cb;
uint64_t last_cookie; uint64_t last_cookie;
}; };

View File

@ -10,6 +10,7 @@
#include "wtp_radio.h" #include "wtp_radio.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#include <ev.h>
#include <libconfig.h> #include <libconfig.h>
struct wtp_t g_wtp; struct wtp_t g_wtp;
@ -22,7 +23,8 @@ struct wtp_t g_wtp;
static char g_configurationfile[260] = WTP_STANDARD_CONFIGURATION_FILE; static char g_configurationfile[260] = WTP_STANDARD_CONFIGURATION_FILE;
/* Alloc WTP */ /* Alloc WTP */
static int wtp_init(void) { static int wtp_init(void)
{
/* Init WTP with default value */ /* Init WTP with default value */
memset(&g_wtp, 0, sizeof(struct wtp_t)); memset(&g_wtp, 0, sizeof(struct wtp_t));
@ -39,13 +41,6 @@ static int wtp_init(void) {
g_wtp.discoveryinterval = WTP_DISCOVERY_INTERVAL; g_wtp.discoveryinterval = WTP_DISCOVERY_INTERVAL;
g_wtp.echointerval = WTP_ECHO_INTERVAL; g_wtp.echointerval = WTP_ECHO_INTERVAL;
/* */
g_wtp.timeout = capwap_timeout_init();
g_wtp.idtimercontrol = capwap_timeout_createtimer(g_wtp.timeout);
g_wtp.idtimerecho = capwap_timeout_createtimer(g_wtp.timeout);
g_wtp.idtimerkeepalive = capwap_timeout_createtimer(g_wtp.timeout);
g_wtp.idtimerkeepalivedead = capwap_timeout_createtimer(g_wtp.timeout);
/* Socket */ /* Socket */
capwap_network_init(&g_wtp.net); capwap_network_init(&g_wtp.net);
@ -127,7 +122,6 @@ static void wtp_destroy(void) {
wtp_free_discovery_response_array(); wtp_free_discovery_response_array();
capwap_array_free(g_wtp.acdiscoveryresponse); capwap_array_free(g_wtp.acdiscoveryresponse);
capwap_timeout_free(g_wtp.timeout);
/* Free local message elements */ /* Free local message elements */
capwap_free(g_wtp.name.name); capwap_free(g_wtp.name.name);
@ -914,7 +908,7 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
case CAPWAP_WIRELESS_BINDING_IEEE80211: { case CAPWAP_WIRELESS_BINDING_IEEE80211: {
/* Initialize wifi binding driver */ /* Initialize wifi binding driver */
capwap_logging_info("Initializing wifi binding engine"); capwap_logging_info("Initializing wifi binding engine");
if (wifi_driver_init(g_wtp.timeout)) { if (wifi_driver_init()) {
capwap_logging_fatal("Unable initialize wifi binding engine"); capwap_logging_fatal("Unable initialize wifi binding engine");
return 0; return 0;
} }
@ -1346,40 +1340,26 @@ static int wtp_configure(void) {
capwap_logging_fatal("Cannot bind control address"); capwap_logging_fatal("Cannot bind control address");
return WTP_ERROR_NETWORK; return WTP_ERROR_NETWORK;
} }
wtp_socket_io_start();
return CAPWAP_SUCCESSFUL; return CAPWAP_SUCCESSFUL;
} }
static void wtp_wait_radio_ready_timeout_cb(EV_P_ ev_timer *w, int revents)
{
ev_break (EV_A_ EVBREAK_ONE);
}
/* */ /* */
static void wtp_wait_radio_ready(void) { static void wtp_wait_radio_ready(void)
int index; {
struct wtp_fds fds; ev_timer timeout;
/* Get only radio file descriptor */ ev_timer_init(&timeout, wtp_wait_radio_ready_timeout_cb,
memset(&fds, 0, sizeof(struct wtp_fds)); WTP_RADIO_INITIALIZATION_INTERVAL / 1000, 0.);
wtp_dfa_update_fdspool(&fds); ev_timer_start(EV_DEFAULT_UC_ &timeout);
if (fds.wifieventscount > 0) {
ASSERT(fds.fdsnetworkcount == 0);
ASSERT(fds.kmodeventscount == 0);
for (;;) { ev_run(EV_DEFAULT_UC_ 0);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RADIO_INITIALIZATION_INTERVAL, NULL, NULL, NULL);
/* Wait packet */
index = capwap_wait_recvready(fds.fdspoll, fds.fdstotalcount, g_wtp.timeout);
if (index < 0) {
break;
} else if (!fds.wifievents[index].event_handler) {
break;
}
fds.wifievents[index].event_handler(fds.fdspoll[index].fd, fds.wifievents[index].params, fds.wifievents[index].paramscount);
}
}
/* */
wtp_dfa_free_fdspool(&fds);
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
} }
/* */ /* */
@ -1393,6 +1373,8 @@ int main(int argc, char** argv) {
int value; int value;
int result = CAPWAP_SUCCESSFUL; int result = CAPWAP_SUCCESSFUL;
ev_default_loop(0);
/* Init logging */ /* Init logging */
capwap_logging_init(); capwap_logging_init();
capwap_logging_verboselevel(CAPWAP_LOGGING_ERROR); capwap_logging_verboselevel(CAPWAP_LOGGING_ERROR);
@ -1445,7 +1427,7 @@ int main(int argc, char** argv) {
} }
/* Wait the initialization of radio interfaces */ /* Wait the initialization of radio interfaces */
capwap_logging_info("Wait the initialization of radio interfaces"); capwap_logging_info("Wait for the initialization of radio interfaces");
wtp_wait_radio_ready(); wtp_wait_radio_ready();
/* Connect WTP with kernel module */ /* Connect WTP with kernel module */
@ -1463,9 +1445,11 @@ int main(int argc, char** argv) {
result = wtp_configure(); result = wtp_configure();
if (result == CAPWAP_SUCCESSFUL) { if (result == CAPWAP_SUCCESSFUL) {
/* Running WTP */ /* Running WTP */
result = wtp_dfa_running(); result = wtp_dfa_running();
/* Close sockets */ /* Close sockets */
wtp_socket_io_stop();
capwap_close_sockets(&g_wtp.net); capwap_close_sockets(&g_wtp.net);
} }

View File

@ -2,6 +2,8 @@
#define __CAPWAP_WTP_HEADER__ #define __CAPWAP_WTP_HEADER__
/* standard include */ /* standard include */
#include <ev.h>
#include "capwap.h" #include "capwap.h"
#include "capwap_dtls.h" #include "capwap_dtls.h"
#include "capwap_network.h" #include "capwap_network.h"
@ -76,7 +78,11 @@ struct wtp_t {
/* */ /* */
unsigned short mtu; unsigned short mtu;
struct capwap_network net; struct capwap_network net;
struct wtp_fds fds;
/* libev watchers */
ev_io socket_ev;
ev_signal sigint_ev;
ev_signal sigterm_ev;
/* */ /* */
unsigned long state; unsigned long state;
@ -88,11 +94,10 @@ struct wtp_t {
int echointerval; int echointerval;
/* Timer */ /* Timer */
struct capwap_timeout* timeout; struct ev_timer timercontrol;
unsigned long idtimercontrol; struct ev_timer timerecho;
unsigned long idtimerecho; struct ev_timer timerkeepalive;
unsigned long idtimerkeepalive; struct ev_timer timerkeepalivedead;
unsigned long idtimerkeepalivedead;
struct capwap_wtpname_element name; struct capwap_wtpname_element name;
struct capwap_acname_element acname; struct capwap_acname_element acname;

View File

@ -6,14 +6,74 @@
#include "wtp_radio.h" #include "wtp_radio.h"
#include <signal.h> #include <signal.h>
#include <ev.h>
#define WTP_RECV_NOERROR_RADIO -1001 #define WTP_RECV_NOERROR_RADIO -1001
/* Handler signal */ static const struct dfa_states {
static void wtp_signal_handler(int signum) { void (*state_enter)(void);
if ((signum == SIGINT) || (signum == SIGTERM)) { void (*state_execute)(struct capwap_parsed_packet *packet);
g_wtp.running = 0; } dfa_states[] = {
[CAPWAP_IDLE_STATE] = {
.state_enter = wtp_dfa_state_idle_enter,
},
[CAPWAP_DISCOVERY_STATE] = {
.state_enter = wtp_dfa_state_discovery_enter,
.state_execute = wtp_dfa_state_discovery,
},
[CAPWAP_SULKING_STATE] = {
.state_enter = wtp_dfa_state_sulking_enter,
.state_execute = wtp_dfa_state_sulking,
},
[CAPWAP_DTLS_CONNECT_STATE] = {
.state_enter = wtp_dfa_state_dtlsconnect_enter,
},
[CAPWAP_DTLS_TEARDOWN_STATE] = {
.state_enter = wtp_dfa_state_dtlsteardown_enter,
.state_execute = wtp_dfa_state_dtlsteardown,
},
[CAPWAP_JOIN_STATE] = {
.state_enter = wtp_dfa_state_join_enter,
.state_execute = wtp_dfa_state_join,
},
[CAPWAP_IMAGE_DATA_STATE] = {
},
[CAPWAP_CONFIGURE_STATE] = {
.state_enter = wtp_dfa_state_configure_enter,
.state_execute = wtp_dfa_state_configure,
},
[CAPWAP_RESET_STATE] = {
.state_enter = wtp_dfa_state_reset_enter,
},
[CAPWAP_DATA_CHECK_STATE] = {
.state_enter = wtp_dfa_state_datacheck_enter,
.state_execute = wtp_dfa_state_datacheck,
},
[CAPWAP_RUN_STATE] = {
.state_enter = wtp_dfa_state_run_enter,
.state_execute = wtp_dfa_state_run,
},
[CAPWAP_DEAD_STATE] = {
.state_enter = wtp_dfa_state_dead_enter,
} }
};
static inline int is_valid_state(int state)
{
return (state >= 0) && (state < (sizeof(dfa_states) / sizeof(dfa_states[0])));
}
/* libev handler */
static void signal_cb (EV_P_ ev_signal *w, int revents);
static void capwap_control_cb(EV_P_ ev_io *w, int revents);
/* Handler signal */
static void signal_cb (EV_P_ ev_signal *w, int revents)
{
g_wtp.running = 0;
/* Teardown */
wtp_teardown_connection();
} }
/* */ /* */
@ -77,228 +137,12 @@ static void wtp_dfa_execute(struct capwap_parsed_packet* packet)
{ {
ASSERT(packet != NULL); ASSERT(packet != NULL);
switch (g_wtp.state) { if (!is_valid_state(g_wtp.state) ||
case CAPWAP_DISCOVERY_STATE: !dfa_states[g_wtp.state].state_execute) {
wtp_dfa_state_discovery(packet); capwap_logging_debug("Got packet in invalid WTP state: %lu", g_wtp.state);
break;
case CAPWAP_SULKING_STATE:
wtp_dfa_state_sulking(packet);
break;
case CAPWAP_DTLS_CONNECT_STATE:
wtp_teardown_connection(); wtp_teardown_connection();
break; } else
dfa_states[g_wtp.state].state_execute(packet);
case CAPWAP_DTLS_TEARDOWN_STATE:
wtp_dfa_state_dtlsteardown(packet);
break;
case CAPWAP_JOIN_STATE:
wtp_dfa_state_join(packet);
break;
case CAPWAP_CONFIGURE_STATE:
wtp_dfa_state_configure(packet);
break;
case CAPWAP_DATA_CHECK_STATE:
wtp_dfa_state_datacheck(packet);
break;
case CAPWAP_RUN_STATE:
wtp_dfa_state_run(packet);
break;
default:
capwap_logging_debug("Unknown WTP action event: %lu", g_wtp.state);
wtp_teardown_connection();
break;
}
}
/* */
static int wtp_recvfrom(struct wtp_fds* fds, void* buffer, int* size, union sockaddr_capwap* recvfromaddr, union sockaddr_capwap* recvtoaddr) {
int index;
ASSERT(fds != NULL);
ASSERT(fds->fdspoll != NULL);
ASSERT(fds->fdstotalcount > 0);
ASSERT(buffer != NULL);
ASSERT(size != NULL);
ASSERT(*size > 0);
ASSERT(recvfromaddr != NULL);
ASSERT(recvtoaddr != NULL);
/* Wait packet */
index = capwap_wait_recvready(fds->fdspoll, fds->fdstotalcount, g_wtp.timeout);
if (index < 0) {
return index;
} else if ((fds->wifieventsstartpos >= 0) && (index >= fds->wifieventsstartpos)) {
int pos = index - fds->wifieventsstartpos;
if (pos < fds->wifieventscount) {
if (!fds->wifievents[pos].event_handler) {
return CAPWAP_RECV_ERROR_SOCKET;
}
fds->wifievents[pos].event_handler(fds->fdspoll[index].fd, fds->wifievents[pos].params, fds->wifievents[pos].paramscount);
}
return WTP_RECV_NOERROR_RADIO;
} else if ((fds->kmodeventsstartpos >= 0) && (index >= fds->kmodeventsstartpos)) {
int pos = index - fds->kmodeventsstartpos;
if (pos < fds->kmodeventscount) {
if (!fds->kmodevents[pos].event_handler) {
return CAPWAP_RECV_ERROR_SOCKET;
}
fds->kmodevents[pos].event_handler(fds->fdspoll[index].fd, fds->kmodevents[pos].params, fds->kmodevents[pos].paramscount);
}
return WTP_RECV_NOERROR_RADIO;
}
/* Receive packet */
if (capwap_recvfrom(fds->fdspoll[index].fd, buffer, size, recvfromaddr, recvtoaddr)) {
return CAPWAP_RECV_ERROR_SOCKET;
}
return index;
}
/* */
static int 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->fdsnetworkcount = capwap_network_set_pollfd(net, NULL, 0);
fds->fdspoll = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * fds->fdsnetworkcount);
/* Retrive all socket for polling */
fds->fdstotalcount = capwap_network_set_pollfd(net, fds->fdspoll, fds->fdsnetworkcount);
if (fds->fdsnetworkcount != fds->fdstotalcount) {
capwap_free(fds->fdspoll);
return -1;
}
/* Update Event File Descriptor */
wtp_dfa_update_fdspool(fds);
return 0;
}
/* */
int wtp_dfa_update_fdspool(struct wtp_fds* fds) {
int totalcount;
int kmodcount;
int wificount;
struct pollfd* fdsbuffer;
ASSERT(fds != NULL);
/* Retrieve number of Dynamic File Descriptor Event */
kmodcount = wtp_kmod_getfd(NULL, NULL, 0);
wificount = wifi_event_getfd(NULL, NULL, 0);
if ((kmodcount < 0) || (wificount < 0)) {
return -1;
}
/* Kernel Module Events Callback */
fds->kmodeventsstartpos = -1;
if (kmodcount != fds->kmodeventscount) {
if (fds->kmodevents) {
capwap_free(fds->kmodevents);
}
/* */
fds->kmodeventscount = kmodcount;
fds->kmodevents = (struct wtp_kmod_event*)((kmodcount > 0) ? capwap_alloc(sizeof(struct wtp_kmod_event) * kmodcount) : NULL);
}
/* Wifi Events Callback */
fds->wifieventsstartpos = -1;
if (wificount != fds->wifieventscount) {
if (fds->wifievents) {
capwap_free(fds->wifievents);
}
/* */
fds->wifieventscount = wificount;
fds->wifievents = (struct wifi_event*)((wificount > 0) ? capwap_alloc(sizeof(struct wifi_event) * wificount) : NULL);
}
/* Resize poll */
totalcount = fds->fdsnetworkcount + fds->kmodeventscount + fds->wifieventscount;
if (fds->fdstotalcount != totalcount) {
fdsbuffer = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * totalcount);
if (fds->fdspoll) {
if (fds->fdsnetworkcount > 0) {
memcpy(fdsbuffer, fds->fdspoll, sizeof(struct pollfd) * fds->fdsnetworkcount);
}
capwap_free(fds->fdspoll);
}
/* */
fds->fdspoll = fdsbuffer;
fds->fdstotalcount = totalcount;
}
/* Retrieve File Descriptor Kernel Module Event */
if (fds->kmodeventscount > 0) {
fds->kmodeventsstartpos = fds->fdsnetworkcount;
wtp_kmod_getfd(&fds->fdspoll[fds->kmodeventsstartpos], fds->kmodevents, fds->kmodeventscount);
}
/* Retrieve File Descriptor Wifi Event */
if (fds->wifieventscount > 0) {
fds->wifieventsstartpos = fds->fdsnetworkcount + fds->kmodeventscount;
wifi_event_getfd(&fds->fdspoll[fds->wifieventsstartpos], fds->wifievents, fds->wifieventscount);
}
return fds->fdstotalcount;
}
/* */
void wtp_dfa_free_fdspool(struct wtp_fds* fds) {
ASSERT(fds != NULL);
if (fds->fdspoll) {
capwap_free(fds->fdspoll);
}
if (fds->kmodevents) {
capwap_free(fds->kmodevents);
}
if (fds->wifievents) {
capwap_free(fds->wifievents);
}
}
/* */
static void wtp_dfa_closeapp(void) {
g_wtp.running = 0;
/* Teardown */
wtp_teardown_connection();
/* Wait RFC teardown timeout */
for (;;) {
if (capwap_timeout_wait(capwap_timeout_getcoming(g_wtp.timeout)) < 0) {
break;
}
if (capwap_timeout_hasexpired(g_wtp.timeout) == g_wtp.idtimercontrol) {
break;
}
}
/* */
ASSERT(g_wtp.state == CAPWAP_DEAD_STATE);
} }
static void wtp_dfa_process_packet(void *buffer, int buffersize, static void wtp_dfa_process_packet(void *buffer, int buffersize,
@ -338,10 +182,9 @@ static void wtp_dfa_process_packet(void *buffer, int buffersize,
if (oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE && if (oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE &&
g_wtp.dtls.action == CAPWAP_DTLS_ACTION_DATA) { g_wtp.dtls.action == CAPWAP_DTLS_ACTION_DATA) {
if (g_wtp.state == CAPWAP_DTLS_CONNECT_STATE) { if (g_wtp.state == CAPWAP_DTLS_CONNECT_STATE) {
wtp_send_join(); wtp_dfa_change_state(CAPWAP_JOIN_STATE);
} else { } else
wtp_teardown_connection(); wtp_teardown_connection();
}
} }
} else if (oldaction == CAPWAP_DTLS_ACTION_DATA && } else if (oldaction == CAPWAP_DTLS_ACTION_DATA &&
g_wtp.dtls.action == CAPWAP_DTLS_ACTION_SHUTDOWN) { g_wtp.dtls.action == CAPWAP_DTLS_ACTION_SHUTDOWN) {
@ -450,56 +293,71 @@ static void wtp_dfa_process_packet(void *buffer, int buffersize,
} }
/* WTP state machine */ /* WTP state machine */
int wtp_dfa_running(void) int wtp_dfa_running()
{ {
int result = CAPWAP_SUCCESSFUL; int result = CAPWAP_SUCCESSFUL;
char buffer[CAPWAP_MAX_PACKET_SIZE];
int buffersize;
int index;
union sockaddr_capwap fromaddr;
union sockaddr_capwap toaddr;
/* Configure poll struct */
if (wtp_dfa_init_fdspool(&g_wtp.fds, &g_wtp.net)) {
return CAPWAP_GENERIC_ERROR;
}
/* Handler signal */ /* Handler signal */
g_wtp.running = 1; g_wtp.running = 1;
signal(SIGPIPE, SIG_IGN); ev_signal_init(&g_wtp.sigint_ev, signal_cb, SIGINT);
signal(SIGINT, wtp_signal_handler); ev_signal_init(&g_wtp.sigterm_ev, signal_cb, SIGTERM);
signal(SIGTERM, wtp_signal_handler); ev_signal_start(EV_DEFAULT_UC_ &g_wtp.sigint_ev);
ev_signal_start(EV_DEFAULT_UC_ &g_wtp.sigterm_ev);
/* Init complete, start DFA */ /* Init complete, start DFA */
wtp_dfa_change_state(CAPWAP_IDLE_STATE); wtp_dfa_change_state(CAPWAP_IDLE_STATE);
wtp_dfa_state_idle();
/* */ ev_run(EV_DEFAULT_UC_ 0);
while (g_wtp.state != CAPWAP_DEAD_STATE) {
return result;
}
void wtp_socket_io_start()
{
capwap_logging_debug("Start EV_IO on socket %d", g_wtp.net.socket);
/* Configure libev struct */
ev_io_init (&g_wtp.socket_ev, capwap_control_cb, g_wtp.net.socket, EV_READ);
ev_io_start(EV_DEFAULT_UC_ &g_wtp.socket_ev);
}
void wtp_socket_io_stop()
{
capwap_logging_debug("Stop EV_IO on socket %d", g_wtp.socket_ev.fd);
ev_io_stop(EV_DEFAULT_UC_ &g_wtp.socket_ev);
}
static void capwap_control_cb(EV_P_ ev_io *w, int revents)
{
char buffer[CAPWAP_MAX_PACKET_SIZE];
ssize_t r;
union sockaddr_capwap fromaddr;
union sockaddr_capwap toaddr;
while (42) {
/* If request wait packet from AC */ /* If request wait packet from AC */
buffersize = sizeof(buffer); do {
index = wtp_recvfrom(&g_wtp.fds, &buffer, &buffersize, &fromaddr, &toaddr); capwap_logging_debug("Receive CAPWAP Control Channel message");
capwap_logging_debug("WTP got data: idx: %d, size: %d", index, buffersize); r = capwap_recvfrom(w->fd, &buffer, sizeof(buffer),
&fromaddr, &toaddr);
} while (r < 0 && errno == EINTR);
capwap_logging_debug("WTP got data: r: %zd", r);
if (!g_wtp.running) { if (!g_wtp.running) {
capwap_logging_debug("Closing WTP, Teardown connection"); capwap_logging_debug("Closing WTP, Teardown connection");
wtp_dfa_closeapp();
ev_io_stop (EV_A_ w);
break; break;
} }
if (index == CAPWAP_RECV_ERROR_INTR || if (r < 0) {
index == WTP_RECV_NOERROR_RADIO) { if (errno != EAGAIN) {
/* Ignore recv */ capwap_logging_debug("capwap_control_cb I/O error %m, exiting loop");
continue; ev_io_stop (EV_A_ w);
} else if (index == CAPWAP_RECV_ERROR_SOCKET) { ev_break (EV_A_ EVBREAK_ONE);
/* Socket close */ }
break; break;
} else if (index < 0) {
continue;
/* TODO: Really? Previosly, this was hidden in the
* overly deep indention, check if that is correct */
} }
if (g_wtp.teardown) { if (g_wtp.teardown) {
@ -507,24 +365,29 @@ int wtp_dfa_running(void)
continue; /* Drop packet */ continue; /* Drop packet */
} }
wtp_dfa_process_packet(&buffer, buffersize, &fromaddr, &toaddr); wtp_dfa_process_packet(&buffer, r, &fromaddr, &toaddr);
} }
/* Free memory */
wtp_dfa_free_fdspool(&g_wtp.fds);
return result;
} }
/* Change WTP state machine */ /* Change WTP state machine */
void wtp_dfa_change_state(int state) { void wtp_dfa_change_state(int state) {
if (state != g_wtp.state) { if (state != g_wtp.state) {
capwap_logging_debug("WTP change state from %s to %s", capwap_dfa_getname(g_wtp.state), capwap_dfa_getname(state)); capwap_logging_debug("WTP change state from %s to %s",
capwap_dfa_getname(g_wtp.state),
capwap_dfa_getname(state));
g_wtp.state = state; g_wtp.state = state;
ev_timer_stop(EV_DEFAULT_UC_ &g_wtp.timercontrol);
if (is_valid_state(g_wtp.state) &&
dfa_states[g_wtp.state].state_enter)
dfa_states[g_wtp.state].state_enter();
} }
} }
/* */ /* */
void wtp_free_reference_last_request(void) { void wtp_free_reference_last_request(void)
{
capwap_list_flush(g_wtp.requestfragmentpacket); capwap_list_flush(g_wtp.requestfragmentpacket);
} }
@ -536,8 +399,7 @@ void wtp_free_reference_last_response(void) {
} }
/* */ /* */
void wtp_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long index, static void wtp_dfa_retransmition_timeout_cb(EV_P_ ev_timer *w, int revents)
void* context, void* param)
{ {
if (!g_wtp.requestfragmentpacket->count) { if (!g_wtp.requestfragmentpacket->count) {
capwap_logging_warning("Invalid retransmition request packet"); capwap_logging_warning("Invalid retransmition request packet");
@ -564,8 +426,31 @@ void wtp_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long
} }
/* Update timeout */ /* Update timeout */
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, ev_timer_again(EV_A_ w);
wtp_dfa_retransmition_timeout, NULL, NULL); }
/* */
void wtp_dfa_start_retransmition_timer()
{
ev_timer_stop(EV_DEFAULT_UC_ &g_wtp.timercontrol);
ev_timer_init(&g_wtp.timercontrol, wtp_dfa_retransmition_timeout_cb,
0., WTP_RETRANSMIT_INTERVAL / 1000.0);
ev_timer_again(EV_DEFAULT_UC_ &g_wtp.timercontrol);
}
/* */
void wtp_dfa_stop_retransmition_timer()
{
ev_timer_stop(EV_DEFAULT_UC_ &g_wtp.timercontrol);
}
/* */
void wtp_timeout_stop_all()
{
ev_timer_stop(EV_DEFAULT_UC_ &g_wtp.timercontrol);
ev_timer_stop(EV_DEFAULT_UC_ &g_wtp.timerecho);
ev_timer_stop(EV_DEFAULT_UC_ &g_wtp.timerkeepalive);
ev_timer_stop(EV_DEFAULT_UC_ &g_wtp.timerkeepalivedead);
} }
void wtp_reset_state(void) void wtp_reset_state(void)

View File

@ -1,6 +1,8 @@
#ifndef __WTP_DFA_HEADER__ #ifndef __WTP_DFA_HEADER__
#define __WTP_DFA_HEADER__ #define __WTP_DFA_HEADER__
#include <ev.h>
#include "capwap_network.h" #include "capwap_network.h"
#include "capwap_protocol.h" #include "capwap_protocol.h"
#include "capwap_element.h" #include "capwap_element.h"
@ -16,13 +18,17 @@ void wtp_free_discovery_response_array(void);
/* */ /* */
void wtp_teardown_connection(void); void wtp_teardown_connection(void);
/* */
void wtp_socket_io_start(void);
void wtp_socket_io_stop(void);
/* */ /* */
void wtp_free_packet_rxmng(void); void wtp_free_packet_rxmng(void);
void wtp_free_reference_last_request(void); void wtp_free_reference_last_request(void);
void wtp_free_reference_last_response(void); void wtp_free_reference_last_response(void);
/* State machine */ /* State machine */
int wtp_dfa_running(void); int wtp_dfa_running();
void wtp_dfa_change_state(int state); void wtp_dfa_change_state(int state);
/* */ /* */
@ -30,39 +36,32 @@ void wtp_start_dtlssetup(void);
void wtp_start_datachannel(void); void wtp_start_datachannel(void);
/* */ /* */
void wtp_send_join(void);
void wtp_send_configure(void);
void wtp_send_datacheck(void); void wtp_send_datacheck(void);
/* */ /* */
void wtp_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); void wtp_dfa_start_retransmition_timer(void);
void wtp_dfa_stop_retransmition_timer(void);
int wtp_dfa_update_fdspool(struct wtp_fds* fds);
void wtp_dfa_free_fdspool(struct wtp_fds* fds);
/* */ /* */
void wtp_dfa_state_idle(void); void wtp_dfa_state_idle_enter(void);
void wtp_dfa_state_discovery_enter(void);
void wtp_dfa_state_sulking_enter(void);
void wtp_dfa_state_dtlsconnect_enter(void);
void wtp_dfa_state_dtlsteardown_enter(void);
void wtp_dfa_state_join_enter(void);
void wtp_dfa_state_configure_enter(void);
void wtp_dfa_state_reset_enter(void);
void wtp_dfa_state_datacheck_enter(void);
void wtp_dfa_state_run_enter(void);
void wtp_dfa_state_dead_enter(void);
void wtp_dfa_state_discovery(struct capwap_parsed_packet* packet); void wtp_dfa_state_discovery(struct capwap_parsed_packet* packet);
void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
void wtp_dfa_state_dtlsteardown(struct capwap_parsed_packet* packet);
void wtp_dfa_state_sulking(struct capwap_parsed_packet* packet); void wtp_dfa_state_sulking(struct capwap_parsed_packet* packet);
void wtp_dfa_state_sulking_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); void wtp_dfa_state_dtlsteardown(struct capwap_parsed_packet* packet);
void wtp_dfa_state_join(struct capwap_parsed_packet* packet); void wtp_dfa_state_join(struct capwap_parsed_packet* packet);
void wtp_dfa_state_configure(struct capwap_parsed_packet* packet); void wtp_dfa_state_configure(struct capwap_parsed_packet* packet);
void wtp_dfa_state_datacheck(struct capwap_parsed_packet* packet); void wtp_dfa_state_datacheck(struct capwap_parsed_packet* packet);
void wtp_dfa_state_run(struct capwap_parsed_packet* packet); void wtp_dfa_state_run(struct capwap_parsed_packet* packet);
void wtp_dfa_state_run_echo_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
void wtp_dfa_state_run_keepalive_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
void wtp_dfa_state_run_keepalivedead_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
void wtp_dfa_state_reset(void);
/* */ /* */
void wtp_ieee80211_packet(uint8_t radioid, const struct ieee80211_header* header, int length); void wtp_ieee80211_packet(uint8_t radioid, const struct ieee80211_header* header, int length);
@ -70,6 +69,7 @@ void wtp_ieee80211_packet(uint8_t radioid, const struct ieee80211_header* header
void wtp_recv_data_keepalive(void); void wtp_recv_data_keepalive(void);
void wtp_recv_data(uint8_t* buffer, int length); void wtp_recv_data(uint8_t* buffer, int length);
void wtp_timeout_stop_all(void);
void wtp_reset_state(void); void wtp_reset_state(void);
#endif /* __WTP_DFA_HEADER__ */ #endif /* __WTP_DFA_HEADER__ */

View File

@ -81,7 +81,7 @@ static void cfg_binding_add_ieee80211(struct capwap_packet_txmng* txmngpacket)
} }
/* */ /* */
void wtp_send_configure(void) void wtp_dfa_state_configure_enter(void)
{ {
struct capwap_header_data capwapheader; struct capwap_header_data capwapheader;
struct capwap_acnamepriority_element acnamepriority; struct capwap_acnamepriority_element acnamepriority;
@ -129,9 +129,7 @@ void wtp_send_configure(void)
} }
g_wtp.retransmitcount = 0; g_wtp.retransmitcount = 0;
wtp_dfa_change_state(CAPWAP_CONFIGURE_STATE); wtp_dfa_start_retransmition_timer();
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL,
wtp_dfa_retransmition_timeout, NULL, NULL);
} }
/* */ /* */
@ -160,6 +158,8 @@ void wtp_dfa_state_configure(struct capwap_parsed_packet* packet)
return; return;
} }
wtp_dfa_stop_retransmition_timer();
g_wtp.localseqnumber++; g_wtp.localseqnumber++;
/* Valid packet, free request packet */ /* Valid packet, free request packet */
@ -187,5 +187,5 @@ void wtp_dfa_state_configure(struct capwap_parsed_packet* packet)
return; return;
} }
wtp_send_datacheck(); /* Send change state event packet */ wtp_dfa_change_state(CAPWAP_DATA_CHECK_STATE); /* Send change state event packet */
} }

View File

@ -4,7 +4,7 @@
#include "wtp_dfa.h" #include "wtp_dfa.h"
/* */ /* */
void wtp_send_datacheck(void) void wtp_dfa_state_datacheck_enter(void)
{ {
struct capwap_header_data capwapheader; struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket; struct capwap_packet_txmng* txmngpacket;
@ -44,9 +44,7 @@ void wtp_send_datacheck(void)
} }
g_wtp.retransmitcount = 0; g_wtp.retransmitcount = 0;
wtp_dfa_change_state(CAPWAP_DATA_CHECK_STATE); wtp_dfa_start_retransmition_timer();
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL,
wtp_dfa_retransmition_timeout, NULL, NULL);
} }
/* */ /* */
@ -74,15 +72,19 @@ void wtp_dfa_state_datacheck(struct capwap_parsed_packet* packet)
return; return;
} }
wtp_dfa_stop_retransmition_timer();
g_wtp.localseqnumber++; g_wtp.localseqnumber++;
/* Valid packet, free request packet */ /* Valid packet, free request packet */
wtp_free_reference_last_request(); wtp_free_reference_last_request();
/* Check the success of the Request */ /* Check the success of the Request */
resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE); resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet,
CAPWAP_ELEMENT_RESULTCODE);
if (resultcode && !CAPWAP_RESULTCODE_OK(resultcode->code)) { if (resultcode && !CAPWAP_RESULTCODE_OK(resultcode->code)) {
capwap_logging_warning("Receive Data Check Response with error: %d", (int)resultcode->code); capwap_logging_warning("Receive Data Check Response with error: %d",
(int)resultcode->code);
wtp_teardown_connection(); wtp_teardown_connection();
return; return;

View File

@ -91,8 +91,7 @@ static void wtp_send_discovery_request()
} }
/* */ /* */
void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned long index, static void wtp_dfa_state_discovery_timeout(EV_P_ ev_timer *w, int revents)
void* context, void* param)
{ {
long discoveryinterval; long discoveryinterval;
@ -198,6 +197,7 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
if (capwap_connect_socket(&g_wtp.net, &peeraddr) < 0) { if (capwap_connect_socket(&g_wtp.net, &peeraddr) < 0) {
capwap_logging_fatal("Cannot bind control address"); capwap_logging_fatal("Cannot bind control address");
wtp_socket_io_stop();
capwap_close_sockets(&g_wtp.net); capwap_close_sockets(&g_wtp.net);
return; return;
} }
@ -205,6 +205,7 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
/* Retrieve local address */ /* Retrieve local address */
if (capwap_getsockname(&g_wtp.net, &localaddr) < 0) { if (capwap_getsockname(&g_wtp.net, &localaddr) < 0) {
capwap_logging_fatal("Cannot get local endpoint address"); capwap_logging_fatal("Cannot get local endpoint address");
wtp_socket_io_stop();
capwap_close_sockets(&g_wtp.net); capwap_close_sockets(&g_wtp.net);
return; return;
} }
@ -214,7 +215,7 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
/* */ /* */
if (!g_wtp.enabledtls) { if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */ wtp_dfa_change_state(CAPWAP_JOIN_STATE); /* Bypass DTLS connection */
} else { } else {
wtp_start_dtlssetup(); /* Create DTLS connection */ wtp_start_dtlssetup(); /* Create DTLS connection */
} }
@ -228,17 +229,30 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
if (g_wtp.discoverycount >= WTP_MAX_DISCOVERY_COUNT) { if (g_wtp.discoverycount >= WTP_MAX_DISCOVERY_COUNT) {
/* Timeout discovery state */ /* Timeout discovery state */
wtp_dfa_change_state(CAPWAP_SULKING_STATE); wtp_dfa_change_state(CAPWAP_SULKING_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL,
wtp_dfa_state_sulking_timeout, NULL, NULL);
return; return;
} }
wtp_send_discovery_request(); wtp_send_discovery_request();
/* Wait before send another Discovery Request */ /* Wait before send another Discovery Request */
discoveryinterval = (capwap_get_rand(g_wtp.discoveryinterval - WTP_MIN_DISCOVERY_INTERVAL) + WTP_MIN_DISCOVERY_INTERVAL); discoveryinterval = capwap_get_rand(g_wtp.discoveryinterval - WTP_MIN_DISCOVERY_INTERVAL) +
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, discoveryinterval, wtp_dfa_state_discovery_timeout, NULL, NULL); WTP_MIN_DISCOVERY_INTERVAL;
w->repeat = discoveryinterval / 1000.0;
ev_timer_again(EV_A_ w);
}
/* */
void wtp_dfa_state_discovery_enter(void)
{
long discoveryinterval;
discoveryinterval = capwap_get_rand(g_wtp.discoveryinterval - WTP_MIN_DISCOVERY_INTERVAL) +
WTP_MIN_DISCOVERY_INTERVAL;
/* Wait before send Discovery Request */
ev_timer_init(&g_wtp.timercontrol, wtp_dfa_state_discovery_timeout,
0., discoveryinterval / 1000.0);
ev_timer_again(EV_DEFAULT_UC_ &g_wtp.timercontrol);
} }
/* */ /* */

View File

@ -1,35 +1,46 @@
#include "wtp.h" #include "wtp.h"
#include "capwap_dfa.h" #include "capwap_dfa.h"
#include "wtp_dfa.h" #include "wtp_dfa.h"
#include "wtp_radio.h"
/* */ /* */
static void wtp_dfa_state_dtlsconnect_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { static void wtp_dfa_state_dtlsconnect_timeout(EV_P_ ev_timer *w, int revents)
{
wtp_teardown_connection(); wtp_teardown_connection();
} }
/* */ /* */
void wtp_start_dtlssetup(void) { void wtp_dfa_state_dead_enter(void)
{
ev_break(EV_DEFAULT_UC_ EVBREAK_ALL);
}
/* */
void wtp_dfa_state_dtlsconnect_enter(void)
{
ev_timer_init(&g_wtp.timercontrol, wtp_dfa_state_dtlsconnect_timeout,
WTP_DTLS_INTERVAL / 1000.0, 0.);
ev_timer_start(EV_DEFAULT_UC_ &g_wtp.timercontrol);
}
/* */
void wtp_start_dtlssetup(void)
{
/* Create DTLS session */ /* Create DTLS session */
if (!capwap_crypt_createsession(&g_wtp.dtls, &g_wtp.dtlscontext)) { if (!capwap_crypt_createsession(&g_wtp.dtls, &g_wtp.dtlscontext)) {
wtp_dfa_change_state(CAPWAP_SULKING_STATE); wtp_dfa_change_state(CAPWAP_SULKING_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL,
wtp_dfa_state_sulking_timeout, NULL, NULL);
return; return;
} }
if (capwap_crypt_open(&g_wtp.dtls) == CAPWAP_HANDSHAKE_ERROR) { if (capwap_crypt_open(&g_wtp.dtls) == CAPWAP_HANDSHAKE_ERROR) {
wtp_dfa_change_state(CAPWAP_SULKING_STATE); wtp_dfa_change_state(CAPWAP_SULKING_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL, } else
wtp_dfa_state_sulking_timeout, NULL, NULL);
} else {
wtp_dfa_change_state(CAPWAP_DTLS_CONNECT_STATE); wtp_dfa_change_state(CAPWAP_DTLS_CONNECT_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_DTLS_INTERVAL,
wtp_dfa_state_dtlsconnect_timeout, NULL, NULL);
}
} }
/* */ /* */
void wtp_start_datachannel(void) { void wtp_start_datachannel(void)
{
union sockaddr_capwap dataaddr; union sockaddr_capwap dataaddr;
/* Set AC data address */ /* Set AC data address */
@ -39,7 +50,9 @@ void wtp_start_datachannel(void) {
#ifdef DEBUG #ifdef DEBUG
{ {
char addr[INET6_ADDRSTRLEN]; char addr[INET6_ADDRSTRLEN];
capwap_logging_debug("Create data channel with peer %s:%d", capwap_address_to_string(&dataaddr, addr, INET6_ADDRSTRLEN), (int)CAPWAP_GET_NETWORK_PORT(&dataaddr)); capwap_logging_debug("Create data channel with peer %s:%d",
capwap_address_to_string(&dataaddr, addr, INET6_ADDRSTRLEN),
(int)CAPWAP_GET_NETWORK_PORT(&dataaddr));
} }
#endif #endif
@ -57,14 +70,10 @@ void wtp_start_datachannel(void) {
/* Set timer */ /* Set timer */
wtp_dfa_change_state(CAPWAP_RUN_STATE); wtp_dfa_change_state(CAPWAP_RUN_STATE);
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerecho, g_wtp.echointerval, wtp_dfa_state_run_echo_timeout, NULL, NULL);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalivedead, WTP_DATACHANNEL_KEEPALIVEDEAD, wtp_dfa_state_run_keepalivedead_timeout, NULL, NULL);
} }
/* */ /* */
static void wtp_dfa_state_dtlsteardown_timeout(struct capwap_timeout* timeout, static void wtp_dfa_state_dtlsteardown_timeout(EV_P_ ev_timer *w, int revents)
unsigned long index, void* context, void* param)
{ {
/* Free and reset resource */ /* Free and reset resource */
if (g_wtp.dtls.enable) if (g_wtp.dtls.enable)
@ -76,6 +85,9 @@ static void wtp_dfa_state_dtlsteardown_timeout(struct capwap_timeout* timeout,
g_wtp.acname.name = NULL; g_wtp.acname.name = NULL;
} }
wtp_socket_io_stop();
capwap_close_sockets(&g_wtp.net);
/* */ /* */
wtp_reset_state(); wtp_reset_state();
@ -85,12 +97,17 @@ static void wtp_dfa_state_dtlsteardown_timeout(struct capwap_timeout* timeout,
} else if ((g_wtp.faileddtlssessioncount >= WTP_FAILED_DTLS_SESSION_RETRY) || } else if ((g_wtp.faileddtlssessioncount >= WTP_FAILED_DTLS_SESSION_RETRY) ||
(g_wtp.faileddtlsauthfailcount >= WTP_FAILED_DTLS_SESSION_RETRY)) { (g_wtp.faileddtlsauthfailcount >= WTP_FAILED_DTLS_SESSION_RETRY)) {
wtp_dfa_change_state(CAPWAP_SULKING_STATE); wtp_dfa_change_state(CAPWAP_SULKING_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL, } else
wtp_dfa_state_sulking_timeout, NULL, NULL);
} else {
wtp_dfa_change_state(CAPWAP_IDLE_STATE); wtp_dfa_change_state(CAPWAP_IDLE_STATE);
wtp_dfa_state_idle(); }
}
/* */
void wtp_dfa_state_dtlsteardown_enter(void)
{
wtp_timeout_stop_all();
ev_timer_init(&g_wtp.timercontrol, wtp_dfa_state_dtlsteardown_timeout,
WTP_DTLS_SESSION_DELETE / 1000.0, 0.);
ev_timer_start(EV_DEFAULT_UC_ &g_wtp.timercontrol);
} }
/* */ /* */
@ -102,18 +119,16 @@ void wtp_teardown_connection(void)
{ {
g_wtp.teardown = 1; g_wtp.teardown = 1;
/* TODO: close SSID ? */ wtp_radio_reset();
/* DTSL Control */ ev_io_stop(EV_DEFAULT_UC_ &g_wtp.socket_ev);
/* DTLS Control */
if (g_wtp.dtls.enable) if (g_wtp.dtls.enable)
capwap_crypt_close(&g_wtp.dtls); capwap_crypt_close(&g_wtp.dtls);
/* Close data channel session */ /* Close data channel session */
wtp_kmod_resetsession(); wtp_kmod_resetsession();
/* */
wtp_dfa_change_state(CAPWAP_DTLS_TEARDOWN_STATE); wtp_dfa_change_state(CAPWAP_DTLS_TEARDOWN_STATE);
capwap_timeout_unsetall(g_wtp.timeout);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_DTLS_SESSION_DELETE,
wtp_dfa_state_dtlsteardown_timeout, NULL, NULL);
} }

View File

@ -23,11 +23,13 @@ static int wtp_join_prefered_ac()
g_wtp.acpreferedselected++; g_wtp.acpreferedselected++;
/* restart and connect the control Socket */ /* restart and connect the control Socket */
wtp_socket_io_stop();
capwap_close_sockets(&g_wtp.net); capwap_close_sockets(&g_wtp.net);
if (capwap_bind_sockets(&g_wtp.net) < 0) { if (capwap_bind_sockets(&g_wtp.net) < 0) {
capwap_logging_fatal("Cannot bind control address"); capwap_logging_fatal("Cannot bind control address");
return -1; return -1;
} }
wtp_socket_io_start();
if(!peeraddr->resolved) { if(!peeraddr->resolved) {
if (capwap_address_from_string(peeraddr->fqdn, &peeraddr->sockaddr)) { if (capwap_address_from_string(peeraddr->fqdn, &peeraddr->sockaddr)) {
@ -42,6 +44,7 @@ static int wtp_join_prefered_ac()
if (capwap_connect_socket(&g_wtp.net, &peeraddr->sockaddr) < 0) { if (capwap_connect_socket(&g_wtp.net, &peeraddr->sockaddr) < 0) {
capwap_logging_fatal("Cannot bind control address"); capwap_logging_fatal("Cannot bind control address");
wtp_socket_io_stop();
capwap_close_sockets(&g_wtp.net); capwap_close_sockets(&g_wtp.net);
return -1; return -1;
} }
@ -49,6 +52,7 @@ static int wtp_join_prefered_ac()
/* Retrieve local address */ /* Retrieve local address */
if (capwap_getsockname(&g_wtp.net, &localaddr) < 0) { if (capwap_getsockname(&g_wtp.net, &localaddr) < 0) {
capwap_logging_fatal("Cannot get local endpoint address"); capwap_logging_fatal("Cannot get local endpoint address");
wtp_socket_io_stop();
capwap_close_sockets(&g_wtp.net); capwap_close_sockets(&g_wtp.net);
return -1; return -1;
} }
@ -58,10 +62,9 @@ static int wtp_join_prefered_ac()
/* */ /* */
if (!g_wtp.enabledtls) { if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */ wtp_dfa_change_state(CAPWAP_JOIN_STATE); /* Bypass DTLS connection */
} else { } else
wtp_start_dtlssetup(); /* Create DTLS connection */ wtp_start_dtlssetup(); /* Create DTLS connection */
}
return 0; return 0;
} }
@ -70,32 +73,29 @@ static int wtp_join_prefered_ac()
} }
/* */ /* */
void wtp_dfa_state_idle(void) { void wtp_dfa_state_idle_enter(void)
long discoveryinterval; {
/* Remove teardown */ /* Remove teardown */
g_wtp.teardown = 0; g_wtp.teardown = 0;
capwap_timeout_unsetall(g_wtp.timeout); wtp_timeout_stop_all();
if (wtp_join_prefered_ac() == 0) if (wtp_join_prefered_ac() == 0)
return; return;
if (g_wtp.net.socket < 0) if (g_wtp.net.socket < 0) {
if (capwap_bind_sockets(&g_wtp.net) < 0) { if (capwap_bind_sockets(&g_wtp.net) < 0) {
capwap_logging_fatal("Cannot bind control address"); capwap_logging_fatal("Cannot bind control address");
exit(-1); exit(-1);
} }
wtp_socket_io_start();
}
/* Discovery AC */ /* Discovery AC */
g_wtp.acpreferedselected = 0; g_wtp.acpreferedselected = 0;
/* Set discovery interval */ /* Set discovery interval */
g_wtp.discoverycount = 0; g_wtp.discoverycount = 0;
discoveryinterval = capwap_get_rand(g_wtp.discoveryinterval - WTP_MIN_DISCOVERY_INTERVAL) + WTP_MIN_DISCOVERY_INTERVAL;
/* Change state */ /* Change state */
wtp_dfa_change_state(CAPWAP_DISCOVERY_STATE); wtp_dfa_change_state(CAPWAP_DISCOVERY_STATE);
/* Wait before send Discovery Request */
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, discoveryinterval, wtp_dfa_state_discovery_timeout, NULL, NULL);
} }

View File

@ -7,7 +7,7 @@
#include "wtp_radio.h" #include "wtp_radio.h"
/* */ /* */
void wtp_send_join(void) void wtp_dfa_state_join_enter(void)
{ {
struct capwap_header_data capwapheader; struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket; struct capwap_packet_txmng* txmngpacket;
@ -87,9 +87,7 @@ void wtp_send_join(void)
} }
g_wtp.retransmitcount = 0; g_wtp.retransmitcount = 0;
wtp_dfa_change_state(CAPWAP_JOIN_STATE); wtp_dfa_start_retransmition_timer();
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL,
wtp_dfa_retransmition_timeout, NULL, NULL);
} }
/* */ /* */
@ -119,6 +117,8 @@ void wtp_dfa_state_join(struct capwap_parsed_packet* packet)
return; return;
} }
wtp_dfa_stop_retransmition_timer();
g_wtp.localseqnumber++; g_wtp.localseqnumber++;
/* Valid packet, free request packet */ /* Valid packet, free request packet */
@ -160,5 +160,5 @@ void wtp_dfa_state_join(struct capwap_parsed_packet* packet)
return; return;
} }
wtp_send_configure(); /* Send configuration packet */ wtp_dfa_change_state(CAPWAP_CONFIGURE_STATE);
} }

View File

@ -3,7 +3,8 @@
#include "wtp_dfa.h" #include "wtp_dfa.h"
/* */ /* */
void wtp_dfa_state_reset(void) { void wtp_dfa_state_reset_enter(void)
{
/* Teardown connection and close application */ /* Teardown connection and close application */
g_wtp.running = 0; g_wtp.running = 0;
wtp_teardown_connection(); wtp_teardown_connection();

View File

@ -5,6 +5,11 @@
#include "wtp_radio.h" #include "wtp_radio.h"
#include "ieee80211.h" #include "ieee80211.h"
/* ev timer callbacks */
static void wtp_dfa_state_run_echo_timeout(EV_P_ ev_timer *w, int revents);
static void wtp_dfa_state_run_keepalive_timeout(EV_P_ ev_timer *w, int revents);
static void wtp_dfa_state_run_keepalivedead_timeout(EV_P_ ev_timer *w, int revents);
/* */ /* */
static int send_echo_request(void) static int send_echo_request(void)
{ {
@ -241,8 +246,7 @@ static void receive_ieee80211_wlan_configuration_request(struct capwap_parsed_pa
} }
/* */ /* */
void wtp_dfa_state_run_echo_timeout(struct capwap_timeout* timeout, unsigned long index, static void wtp_dfa_state_run_echo_timeout(EV_P_ ev_timer *w, int revents)
void* context, void* param)
{ {
capwap_logging_debug("Send Echo Request"); capwap_logging_debug("Send Echo Request");
if (send_echo_request()) { if (send_echo_request()) {
@ -252,18 +256,15 @@ void wtp_dfa_state_run_echo_timeout(struct capwap_timeout* timeout, unsigned lon
} }
g_wtp.retransmitcount = 0; g_wtp.retransmitcount = 0;
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_start_retransmition_timer();
wtp_dfa_retransmition_timeout, NULL, NULL);
} }
/* */ /* */
void wtp_dfa_state_run_keepalive_timeout(struct capwap_timeout* timeout, unsigned long index, static void wtp_dfa_state_run_keepalive_timeout(EV_P_ ev_timer *w, int revents)
void* context, void* param)
{ {
capwap_logging_debug("Send Keep-Alive"); capwap_logging_debug("Send Keep-Alive");
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimerkeepalive);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalivedead, WTP_DATACHANNEL_KEEPALIVEDEAD, ev_timer_again(EV_A_ &g_wtp.timerkeepalivedead);
wtp_dfa_state_run_keepalivedead_timeout, NULL, NULL);
if (wtp_kmod_send_keepalive()) { if (wtp_kmod_send_keepalive()) {
capwap_logging_error("Unable to send Keep-Alive"); capwap_logging_error("Unable to send Keep-Alive");
@ -272,8 +273,7 @@ void wtp_dfa_state_run_keepalive_timeout(struct capwap_timeout* timeout, unsigne
} }
/* */ /* */
void wtp_dfa_state_run_keepalivedead_timeout(struct capwap_timeout* timeout, unsigned long index, static void wtp_dfa_state_run_keepalivedead_timeout(EV_P_ ev_timer *w, int revents)
void* context, void* param)
{ {
capwap_logging_info("Keep-Alive timeout, teardown"); capwap_logging_info("Keep-Alive timeout, teardown");
wtp_teardown_connection(); wtp_teardown_connection();
@ -284,9 +284,10 @@ void wtp_recv_data_keepalive(void) {
capwap_logging_debug("Receive Keep-Alive"); capwap_logging_debug("Receive Keep-Alive");
/* Receive Data Keep-Alive, wait for next packet */ /* Receive Data Keep-Alive, wait for next packet */
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimerkeepalivedead); if (ev_is_active(&g_wtp.timerkeepalivedead))
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalive, WTP_DATACHANNEL_KEEPALIVE_INTERVAL, ev_timer_stop(EV_DEFAULT_UC_ &g_wtp.timerkeepalivedead);
wtp_dfa_state_run_keepalive_timeout, NULL, NULL);
ev_timer_again(EV_DEFAULT_UC_ &g_wtp.timerkeepalive);
} }
/* */ /* */
@ -307,6 +308,23 @@ void wtp_recv_data(uint8_t* buffer, int length) {
} }
} }
/* */
void wtp_dfa_state_run_enter()
{
ev_timer_init(&g_wtp.timerecho,
wtp_dfa_state_run_echo_timeout,
0., g_wtp.echointerval / 1000.0);
ev_timer_init(&g_wtp.timerkeepalivedead,
wtp_dfa_state_run_keepalivedead_timeout,
0., WTP_DATACHANNEL_KEEPALIVEDEAD / 1000.0);
ev_timer_init(&g_wtp.timerkeepalive,
wtp_dfa_state_run_keepalive_timeout,
0., WTP_DATACHANNEL_KEEPALIVE_INTERVAL / 1000.0);
ev_timer_again(EV_DEFAULT_UC_ &g_wtp.timerecho);
ev_timer_again(EV_DEFAULT_UC_ &g_wtp.timerkeepalivedead);
}
/* */ /* */
void wtp_dfa_state_run(struct capwap_parsed_packet* packet) void wtp_dfa_state_run(struct capwap_parsed_packet* packet)
{ {
@ -316,9 +334,12 @@ void wtp_dfa_state_run(struct capwap_parsed_packet* packet)
g_wtp.localseqnumber != packet->rxmngpacket->ctrlmsg.seq) g_wtp.localseqnumber != packet->rxmngpacket->ctrlmsg.seq)
return; return;
/* Update sequence */ if (!capwap_is_request_type(packet->rxmngpacket->ctrlmsg.type)) {
if (!capwap_is_request_type(packet->rxmngpacket->ctrlmsg.type)) wtp_dfa_stop_retransmition_timer();
/* Update sequence */
g_wtp.localseqnumber++; g_wtp.localseqnumber++;
}
/* Parsing message */ /* Parsing message */
switch (packet->rxmngpacket->ctrlmsg.type) { switch (packet->rxmngpacket->ctrlmsg.type) {
@ -333,9 +354,9 @@ void wtp_dfa_state_run(struct capwap_parsed_packet* packet)
case CAPWAP_ECHO_RESPONSE: case CAPWAP_ECHO_RESPONSE:
if (!receive_echo_response(packet)) { if (!receive_echo_response(packet)) {
capwap_logging_debug("Receive Echo Response"); capwap_logging_debug("Receive Echo Response");
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerecho, g_wtp.echointerval, g_wtp.timerecho.repeat = g_wtp.echointerval / 1000.0;
wtp_dfa_state_run_echo_timeout, NULL, NULL); ev_timer_again(EV_DEFAULT_UC_ &g_wtp.timerecho);
} }
break; break;
@ -363,7 +384,6 @@ void wtp_dfa_state_run(struct capwap_parsed_packet* packet)
case CAPWAP_RESET_REQUEST: case CAPWAP_RESET_REQUEST:
receive_reset_request(packet); receive_reset_request(packet);
wtp_dfa_change_state(CAPWAP_RESET_STATE); wtp_dfa_change_state(CAPWAP_RESET_STATE);
wtp_dfa_state_reset();
break; break;
case CAPWAP_IEEE80211_WLAN_CONFIGURATION_REQUEST: case CAPWAP_IEEE80211_WLAN_CONFIGURATION_REQUEST:

View File

@ -3,14 +3,22 @@
#include "wtp_dfa.h" #include "wtp_dfa.h"
/* */ /* */
void wtp_dfa_state_sulking_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { static void wtp_dfa_state_sulking_timeout(EV_P_ ev_timer *w, int revents)
{
g_wtp.discoverycount = 0; g_wtp.discoverycount = 0;
g_wtp.faileddtlssessioncount = 0; g_wtp.faileddtlssessioncount = 0;
g_wtp.faileddtlsauthfailcount = 0; g_wtp.faileddtlsauthfailcount = 0;
/* */ /* */
wtp_dfa_change_state(CAPWAP_IDLE_STATE); wtp_dfa_change_state(CAPWAP_IDLE_STATE);
wtp_dfa_state_idle(); }
/* */
void wtp_dfa_state_sulking_enter()
{
ev_timer_init(&g_wtp.timercontrol, wtp_dfa_state_sulking_timeout,
WTP_SILENT_INTERVAL / 1000.0, 0.);
ev_timer_start(EV_DEFAULT_UC_ &g_wtp.timercontrol);
} }
/* */ /* */

View File

@ -5,6 +5,9 @@
#include <netlink/genl/ctrl.h> #include <netlink/genl/ctrl.h>
#include "nlsmartcapwap.h" #include "nlsmartcapwap.h"
/* libev handler */
static void wtp_kmod_event_receive(EV_P_ ev_io *w, int revents);
/* Compatibility functions */ /* Compatibility functions */
#ifdef HAVE_LIBNL_10 #ifdef HAVE_LIBNL_10
static uint32_t g_portbitmap[32] = { 0 }; static uint32_t g_portbitmap[32] = { 0 };
@ -183,15 +186,15 @@ static int wtp_kmod_link(void) {
} }
/* */ /* */
static void wtp_kmod_event_receive(int fd, void** params, int paramscount) { static void wtp_kmod_event_receive(EV_P_ ev_io *w, int revents)
{
struct wtp_kmod_handle *kmodhandle = (struct wtp_kmod_handle *)
(((char *)w) - offsetof(struct wtp_kmod_handle, nl_ev));
int res; int res;
ASSERT(fd >= 0);
ASSERT(params != NULL);
ASSERT(paramscount == 2);
/* */ /* */
res = nl_recvmsgs((struct nl_sock*)params[0], (struct nl_cb*)params[1]); res = nl_recvmsgs(kmodhandle->nl, kmodhandle->nl_cb);
if (res) { if (res) {
capwap_logging_warning("Receive kernel module message failed: %d", res); capwap_logging_warning("Receive kernel module message failed: %d", res);
} }
@ -496,34 +499,6 @@ int wtp_kmod_isconnected(void) {
return (g_wtp.kmodhandle.nlsmartcapwap_id ? 1 : 0); return (g_wtp.kmodhandle.nlsmartcapwap_id ? 1 : 0);
} }
/* */
int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count) {
int kmodcount = (wtp_kmod_isconnected() ? 1 : 0);
/* */
if (!kmodcount) {
return 0;
} else if (!fds && !events && !count) {
return kmodcount;
} else if ((count > 0) && (!fds || !events)) {
return -1;
} else if (count < kmodcount) {
return -1;
}
/* */
fds[0].fd = g_wtp.kmodhandle.nl_fd;
fds[0].events = POLLIN | POLLERR | POLLHUP;
/* */
events[0].event_handler = wtp_kmod_event_receive;
events[0].params[0] = (void*)g_wtp.kmodhandle.nl;
events[0].params[1] = (void*)g_wtp.kmodhandle.nl_cb;
events[0].paramscount = 2;
return kmodcount;
}
/* */ /* */
int wtp_kmod_init(void) { int wtp_kmod_init(void) {
int result; int result;
@ -542,8 +517,6 @@ int wtp_kmod_init(void) {
return -1; return -1;
} }
g_wtp.kmodhandle.nl_fd = nl_socket_get_fd(g_wtp.kmodhandle.nl);
/* Get nlsmartcapwap netlink family */ /* Get nlsmartcapwap netlink family */
g_wtp.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_wtp.kmodhandle.nl, NLSMARTCAPWAP_GENL_NAME); g_wtp.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_wtp.kmodhandle.nl, NLSMARTCAPWAP_GENL_NAME);
if (g_wtp.kmodhandle.nlsmartcapwap_id < 0) { if (g_wtp.kmodhandle.nlsmartcapwap_id < 0) {
@ -579,6 +552,12 @@ int wtp_kmod_init(void) {
/* */ /* */
g_wtp.kmodhandle.interfaces = capwap_list_create(); g_wtp.kmodhandle.interfaces = capwap_list_create();
/* Configure libev struct */
ev_io_init(&g_wtp.kmodhandle.nl_ev, wtp_kmod_event_receive,
nl_socket_get_fd(g_wtp.kmodhandle.nl), EV_READ);
ev_io_start(EV_DEFAULT_UC_ &g_wtp.kmodhandle.nl_ev);
return 0; return 0;
} }

View File

@ -21,9 +21,9 @@ struct wtp_kmod_iface_handle {
/* */ /* */
struct wtp_kmod_handle { struct wtp_kmod_handle {
struct nl_sock* nl; struct nl_sock* nl;
int nl_fd;
struct nl_cb* nl_cb; struct nl_cb* nl_cb;
int nlsmartcapwap_id; int nlsmartcapwap_id;
ev_io nl_ev;
/* */ /* */
struct nl_sock* nlmsg; struct nl_sock* nlmsg;

View File

@ -165,9 +165,6 @@ void wtp_radio_reset()
radio->initialized = 0; radio->initialized = 0;
} }
/* Update Event File Descriptor */
wtp_dfa_update_fdspool(&g_wtp.fds);
} }
static void push_wtp_update_configuration_item(struct capwap_array *updateitems, static void push_wtp_update_configuration_item(struct capwap_array *updateitems,
@ -709,9 +706,6 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet,
/* Mark interface as used */ /* Mark interface as used */
wlan->in_use = 1; wlan->in_use = 1;
/* Update Event File Descriptor */
wtp_dfa_update_fdspool(&g_wtp.fds);
/* Retrieve macaddress of new device */ /* Retrieve macaddress of new device */
bssid->radioid = addwlan->radioid; bssid->radioid = addwlan->radioid;
bssid->wlanid = addwlan->wlanid; bssid->wlanid = addwlan->wlanid;