diff --git a/src/binding/ieee80211/wifi_drivers.c b/src/binding/ieee80211/wifi_drivers.c index 551b3a8..5c389ee 100644 --- a/src/binding/ieee80211/wifi_drivers.c +++ b/src/binding/ieee80211/wifi_drivers.c @@ -113,6 +113,46 @@ void wifi_driver_free(void) { } } +/* */ +int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count) { + int i, j; + int result = 0; + + if ((count > 0) && (!fds || !events)) { + return -1; + } + + /* Get from driver */ + for (i = 0; wifi_driver[i].ops != NULL; i++) { + if (wifi_driver[i].ops->global_getfdevent) { + result += wifi_driver[i].ops->global_getfdevent(wifi_driver[i].handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); + } + } + + /* Get from device */ + for (i = 0; i < g_wifidevice->count; i++) { + struct wifi_device* device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, i); + if (device->handle) { + if (device->instance->ops->device_getfdevent) { + result += device->instance->ops->device_getfdevent(device->handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); + } + + /* Get from wlan */ + if (device->instance->ops->wlan_getfdevent) { + for (j = 0; j < device->wlan->count; j++) { + struct wifi_wlan* wlan = (struct wifi_wlan*)capwap_array_get_item_pointer(device->wlan, j); + + if (wlan->handle) { + result += device->instance->ops->wlan_getfdevent(wlan->handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); + } + } + } + } + } + + return result; +} + /* */ int wifi_device_connect(int radioid, const char* ifname, const char* driver) { int i; diff --git a/src/binding/ieee80211/wifi_drivers.h b/src/binding/ieee80211/wifi_drivers.h index 03361f8..3998016 100644 --- a/src/binding/ieee80211/wifi_drivers.h +++ b/src/binding/ieee80211/wifi_drivers.h @@ -152,6 +152,13 @@ struct wifi_frequency { uint32_t frequency; }; +/* */ +struct wifi_event { + void (*event_handler)(int fd, void* param1, void* param2); + void* param1; + void* param2; +}; + /* */ struct wifi_driver_ops { const char* name; /* Name of wifi driver */ @@ -159,16 +166,19 @@ struct wifi_driver_ops { /* Global initialize driver */ 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); /* Device functions */ wifi_device_handle (*device_init)(wifi_global_handle handle, struct device_init_params* params); + int (*device_getfdevent)(wifi_device_handle handle, struct pollfd* fds, struct wifi_event* events); int (*device_getcapability)(wifi_device_handle handle, struct wifi_capability* capability); int (*device_setfrequency)(wifi_device_handle handle, struct wifi_frequency* freq); void (*device_deinit)(wifi_device_handle handle); /* WLAN functions */ wifi_wlan_handle (*wlan_create)(wifi_device_handle handle, struct wlan_init_params* params); + int (*wlan_getfdevent)(wifi_wlan_handle handle, struct pollfd* fds, struct wifi_event* events); int (*wlan_setupap)(wifi_wlan_handle handle, struct wlan_setupap_params* params); int (*wlan_startap)(wifi_wlan_handle handle); int (*wlan_stopap)(wifi_wlan_handle handle); @@ -210,6 +220,9 @@ struct wifi_wlan { int wifi_driver_init(void); void wifi_driver_free(void); +/* Get File Descriptor Event */ +int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count); + /* */ int wifi_device_connect(int radioid, const char* ifname, const char* driver); struct wifi_capability* wifi_device_getcapability(int radioid); diff --git a/src/binding/ieee80211/wifi_nl80211.c b/src/binding/ieee80211/wifi_nl80211.c index 799cacd..6f50505 100644 --- a/src/binding/ieee80211/wifi_nl80211.c +++ b/src/binding/ieee80211/wifi_nl80211.c @@ -93,6 +93,19 @@ static int nl80211_process_bss_event(struct nl_msg* msg, void* arg) { return NL_SKIP; } +/* */ +static void nl80211_event_receive(int fd, void* param1, void* param2) { + int res; + struct nl_sock* nl = (struct nl_sock*)param1; + struct nl_cb* nl_cb = (struct nl_cb*)param2; + + /* */ + res = nl_recvmsgs(nl, nl_cb); + if (res) { + capwap_logging_warning("Receive nl80211 message failed: %d", res); + } +} + /* */ static int nl80211_global_valid_handler(struct nl_msg* msg, void* arg) { /* TODO */ @@ -622,6 +635,11 @@ static wifi_device_handle nl80211_device_init(wifi_global_handle handle, struct return devicehandle; } +/* */ +int nl80211_device_getfdevent(wifi_device_handle handle, struct pollfd* fds, struct wifi_event* events) { + return 0; +} + /* */ int nl80211_device_getcapability(wifi_device_handle handle, struct wifi_capability* capability) { int result; @@ -805,7 +823,9 @@ static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wl nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_process_bss_event, NULL); wlanhandle->nl = nl_create_handle(wlanhandle->nl_cb); - if (!wlanhandle->nl) { + if (wlanhandle->nl) { + wlanhandle->nl_fd = nl_socket_get_fd(wlanhandle->nl); + } else { nl80211_wlan_delete((wifi_wlan_handle)wlanhandle); return NULL; } @@ -813,6 +833,26 @@ static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wl return wlanhandle; } +/* */ +static int nl80211_wlan_getfdevent(wifi_wlan_handle handle, struct pollfd* fds, struct wifi_event* events) { + struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; + + ASSERT(handle != NULL); + + 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].param1 = (void*)wlanhandle->nl; + events[0].param2 = (void*)wlanhandle->nl_cb; + } + + return 1; +} + /* */ static int nl80211_wlan_setupap(wifi_wlan_handle handle, struct wlan_setupap_params* params) { int i; @@ -1005,17 +1045,25 @@ static wifi_global_handle nl80211_global_init(void) { return (wifi_global_handle)globalhandle; } +/* */ +static int nl80211_global_getfdevent(wifi_global_handle handle, struct pollfd* fds, struct wifi_event* events) { + return 0; +} + /* Driver function */ const struct wifi_driver_ops wifi_driver_nl80211_ops = { .name = "nl80211", .description = "Linux nl80211/cfg80211", .global_init = nl80211_global_init, + .global_getfdevent = nl80211_global_getfdevent, .global_deinit = nl80211_global_deinit, .device_init = nl80211_device_init, + .device_getfdevent = nl80211_device_getfdevent, .device_getcapability = nl80211_device_getcapability, .device_setfrequency = nl80211_device_setfrequency, .device_deinit = nl80211_device_deinit, .wlan_create = nl80211_wlan_create, + .wlan_getfdevent = nl80211_wlan_getfdevent, .wlan_setupap = nl80211_wlan_setupap, .wlan_startap = nl80211_wlan_startap, .wlan_stopap = nl80211_wlan_stopap, diff --git a/src/binding/ieee80211/wifi_nl80211.h b/src/binding/ieee80211/wifi_nl80211.h index 3eef38b..d4d7c13 100644 --- a/src/binding/ieee80211/wifi_nl80211.h +++ b/src/binding/ieee80211/wifi_nl80211.h @@ -33,6 +33,7 @@ struct nl80211_wlan_handle { struct nl80211_device_handle* devicehandle; struct nl_sock* nl; + int nl_fd; struct nl_cb* nl_cb; uint32_t virtindex; diff --git a/src/wtp/wtp.h b/src/wtp/wtp.h index a8ac8ff..3c9808e 100644 --- a/src/wtp/wtp.h +++ b/src/wtp/wtp.h @@ -81,8 +81,14 @@ struct wtp_t { char wlanprefix[IFNAMSIZ]; - struct wtp_state dfa; + /* */ struct capwap_network net; + struct pollfd* fds; + int fdstotalcount; + int fdsnetworkcount; + + /* */ + struct wtp_state dfa; struct capwap_wtpname_element name; struct capwap_acname_element acname; @@ -106,6 +112,7 @@ struct wtp_t { struct capwap_packet_rxmng* rxmngctrlpacket; struct capwap_packet_rxmng* rxmngdatapacket; + /* */ unsigned char localseqnumber; unsigned char remoteseqnumber; unsigned short mtu; @@ -128,7 +135,10 @@ struct wtp_t { struct capwap_socket acctrlsock; struct capwap_socket acdatasock; + /* */ struct capwap_array* radios; + struct wifi_event* events; + int eventscount; /* Dtls */ int enabledtls; diff --git a/src/wtp/wtp_dfa.c b/src/wtp/wtp_dfa.c index 2fc133d..69088c4 100644 --- a/src/wtp/wtp_dfa.c +++ b/src/wtp/wtp_dfa.c @@ -6,6 +6,8 @@ #include +#define WTP_RECV_NOERROR_RADIO -1001 + /* Handler signal */ static void wtp_signal_handler(int signum) { if ((signum == SIGINT) || (signum == SIGTERM)) { @@ -146,6 +148,44 @@ static void wtp_dfa_execute(struct capwap_parsed_packet* packet, struct timeout_ } } +/* */ +static int wtp_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, struct timeout_control* timeout) { + int index; + + ASSERT(fds); + ASSERT(fdscount > 0); + ASSERT(buffer != NULL); + ASSERT(size != NULL); + ASSERT(*size > 0); + ASSERT(recvfromaddr != NULL); + ASSERT(recvtoaddr != NULL); + + /* Wait packet */ + index = capwap_wait_recvready(fds, fdscount, timeout); + if (index < 0) { + return index; + } else if (index >= g_wtp.fdsnetworkcount) { + int pos = index - g_wtp.fdsnetworkcount; + + if (pos < g_wtp.eventscount) { + if (!g_wtp.events[pos].event_handler) { + return CAPWAP_RECV_ERROR_SOCKET; + } + + g_wtp.events[pos].event_handler(fds[index].fd, g_wtp.events[pos].param1, g_wtp.events[pos].param2); + } + + return WTP_RECV_NOERROR_RADIO; + } + + /* Receive packet */ + if (!capwap_recvfrom_fd(fds[index].fd, buffer, size, recvfromaddr, recvtoaddr)) { + return CAPWAP_RECV_ERROR_SOCKET; + } + + return index; +} + /* WTP state machine */ int wtp_dfa_running(void) { int res; @@ -165,23 +205,21 @@ int wtp_dfa_running(void) { struct sockaddr_storage recvfromaddr; struct sockaddr_storage recvtoaddr; int isrecvpacket = 0; - - struct pollfd* fds; - int fdscount; - + /* Init */ capwap_init_timeout(&timeout); capwap_set_timeout(0, &timeout, CAPWAP_TIMER_CONTROL_CONNECTION); /* Start DFA with timeout */ - + memset(&packet, 0, sizeof(struct capwap_parsed_packet)); - + /* Configure poll struct */ - fdscount = CAPWAP_MAX_SOCKETS * 2; - fds = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * fdscount); - + g_wtp.fdstotalcount = CAPWAP_MAX_SOCKETS * 2; + g_wtp.fds = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * g_wtp.fdstotalcount); + /* Retrive all socket for polling */ - fdscount = capwap_network_set_pollfd(&g_wtp.net, fds, fdscount); - ASSERT(fdscount > 0); + g_wtp.fdsnetworkcount = capwap_network_set_pollfd(&g_wtp.net, g_wtp.fds, g_wtp.fdstotalcount); + g_wtp.fdstotalcount = g_wtp.fdsnetworkcount; + ASSERT(g_wtp.fdstotalcount > 0); /* Handler signal */ g_wtp.running = 1; @@ -199,7 +237,7 @@ int wtp_dfa_running(void) { isrecvpacket = 0; buffer = bufferencrypt; buffersize = CAPWAP_MAX_PACKET_SIZE; - index = capwap_recvfrom(fds, fdscount, buffer, &buffersize, &recvfromaddr, &recvtoaddr, &timeout); + index = wtp_recvfrom(g_wtp.fds, g_wtp.fdstotalcount, buffer, &buffersize, &recvfromaddr, &recvtoaddr, &timeout); if (!g_wtp.running) { capwap_logging_debug("Closing WTP, Teardown connection"); @@ -219,7 +257,7 @@ int wtp_dfa_running(void) { int check; /* Retrieve network information */ - capwap_get_network_socket(&g_wtp.net, &socket, fds[index].fd); + capwap_get_network_socket(&g_wtp.net, &socket, g_wtp.fds[index].fd); /* Check source */ if (socket.isctrlsocket && (g_wtp.acctrladdress.ss_family != AF_UNSPEC)) { @@ -297,7 +335,7 @@ int wtp_dfa_running(void) { socklen_t sockinfolen = sizeof(struct sockaddr_storage); memset(&sockinfo, 0, sizeof(struct sockaddr_storage)); - if (getsockname(fds[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) { + if (getsockname(g_wtp.fds[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) { break; } @@ -386,7 +424,7 @@ int wtp_dfa_running(void) { isrecvpacket = 1; } } - } else if (index == CAPWAP_RECV_ERROR_INTR) { + } else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == WTP_RECV_NOERROR_RADIO)) { /* Ignore recv */ continue; } else if (index == CAPWAP_RECV_ERROR_SOCKET) { @@ -405,7 +443,7 @@ int wtp_dfa_running(void) { } /* Free memory */ - capwap_free(fds); + capwap_free(g_wtp.fds); return result; } diff --git a/src/wtp/wtp_radio.c b/src/wtp/wtp_radio.c index 7c139d1..cc9a0b5 100644 --- a/src/wtp/wtp_radio.c +++ b/src/wtp/wtp_radio.c @@ -83,6 +83,10 @@ void wtp_radio_free(void) { ASSERT(g_wtp.radios != NULL); ASSERT(g_wtp.radios->count == 0); + if (g_wtp.events) { + capwap_free(g_wtp.events); + } + capwap_array_free(g_wtp.radios); } @@ -350,6 +354,45 @@ struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlani return NULL; } +/* */ +static void wtp_radio_update_fdevent(void) { + int count; + + /* Retrieve number of File Descriptor Event */ + count = wifi_event_getfd(NULL, NULL, 0); + if (count < 0) { + return; + } + + /* */ + if (g_wtp.eventscount != count) { + struct pollfd* fds; + + /* Resize poll */ + fds = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * (g_wtp.fdsnetworkcount + count)); + memcpy(fds, g_wtp.fds, sizeof(struct pollfd) * g_wtp.fdsnetworkcount); + capwap_free(g_wtp.fds); + g_wtp.fds = fds; + + /* Events Callback */ + if (g_wtp.events) { + capwap_free(g_wtp.events); + } + + g_wtp.events = (struct wifi_event*)((count > 0) ? capwap_alloc(sizeof(struct wifi_event) * count) : NULL); + + /* */ + g_wtp.eventscount = count; + g_wtp.fdstotalcount = g_wtp.fdsnetworkcount + g_wtp.eventscount; + } + + /* Retrieve File Descriptor Event */ + if (count > 0) { + count = wifi_event_getfd(&g_wtp.fds[g_wtp.fdsnetworkcount], g_wtp.events, g_wtp.eventscount); + ASSERT(g_wtp.eventscount == count); + } +} + /* */ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwap_80211_assignbssid_element* bssid) { uint32_t band; @@ -426,7 +469,10 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwa return CAPWAP_RESULTCODE_FAILURE; } - /* */ + /* Update Event File Descriptor */ + wtp_radio_update_fdevent(); + + /* Retrieve macaddress of new device */ bssid->radioid = addwlan->radioid; bssid->wlanid = addwlan->wlanid; wifi_wlan_getbssid(addwlan->radioid, addwlan->wlanid, bssid->bssid);