19 Commits

Author SHA1 Message Date
9ded0bb87b release 1.2.1 2016-05-06 17:58:27 +02:00
b0aaaa4436 replace memcmp on message id struct with direct compare
cset 3761122c fixed one place, but a few others remained.
This should take care of them all and fix a missing
IE in Add WLAN responses.
2016-05-06 17:52:39 +02:00
6024cc15cf fix interpretation of Add WLAN's capability field
RFC 5416 copies the order of the capability flags from the
IEEE 802.11 capability IE. However, the bit ordering assumtions
in RFC 5416 differ from IEEE 802.11 (in the RFC the MSB is
numbered 0, in IEEE 802.11 the MSB is numbere 15).

RFC 5416 therefore specifies the capability flags bit reversed
compared to IEEE 802.11.
2016-05-03 10:28:38 +02:00
d51873dd4b adjust OpenWRT package for v1.2.0 and OpenWRT HEAD 2016-04-29 09:04:52 +02:00
480f5d8782 update README and NEWS for 1.2.0 release 2016-04-29 08:58:26 +02:00
651ccc0d33 rework debug output to be more helpful for radio config failures 2016-04-29 08:32:49 +02:00
baf1ccbc73 add Vendor TP WTP Timestamp to Echo Request 2016-04-08 15:18:53 +02:00
4f3fe0c339 fix error-condition for invalid WLAN ID 2016-04-08 13:16:19 +02:00
813f24b8ac implement station inactivity timeout
After the max station inactivity has expired, a probe request
(a data null frame) is sent to the station. It the station does
not ACK this frame, it is removed from the WTP.

Note: inactivity timeout is not the same as the CAPWAP Idle Timeout.
The CAPWAP Idle Timeout would remove a station due to inactivity
even when it is still reachable from the WTP. In contrast, the
inactivity timeout probes whether the station is still present
and only removes it when not.
2016-04-07 15:15:50 +02:00
bca5c91ae1 fix spelling of Deauthentication 2016-04-07 14:41:39 +02:00
619c40d5be move nlmsg_free into nl send_and_recv
Simplify resource cleanup and return handling for all
callers of nl send_and_recv.
2016-04-07 11:54:07 +02:00
7b4e386057 add nl80211_wlan_send_and_recv_msg helper 2016-04-07 11:31:11 +02:00
5195ea9e37 rework nl80211_wlan_event in preparation of more events to handle 2016-04-07 11:31:11 +02:00
8f03ecca9b add support functions to handle station inactivity
Detect support for AP side inactivity timer and reading
to the inactivity time for a station.
2016-04-07 11:31:11 +02:00
4b1caad54b consolidate nl msg generation into helper and add more error handling to it 2016-04-07 11:31:04 +02:00
c19da7ffb8 move access to device ops into wrappers 2016-04-06 14:39:20 +02:00
9096bff7a5 coding style updates in wifi_drivers 2016-04-06 14:13:33 +02:00
c132036914 use MACSTR and MAC2STR where appropriate
Replace capwap_printf_macaddress with MACSTR and MAC2STR
macro for all EUI48 MAC addresses. Save a text buffer in
the station structure and some buffers in functions.
2016-04-06 12:57:56 +02:00
f3fb11ac81 rework wifi device capability detection
get rid of deep indention, split into functions, no
functional changes.
2016-04-05 16:22:15 +02:00
29 changed files with 2340 additions and 1218 deletions

18
NEWS.md Normal file
View File

@ -0,0 +1,18 @@
SmartCAPWAP
===========
CAPWAP WTP and AC implementation
Version 1.2.1 - 06 May 2016
---------------------------
* fix Add WLAN's capability field
* fix mssing IEEE 802.11 Assigned WTP BSSID IE in Add WLAN response
Version 1.2.0 - 29 Apr 2016
---------------------------
* 802.11n support
* WMM/WME support
* ported to libev
* ported to Linux 4.4

View File

@ -12,14 +12,17 @@ NOTE: The WTP has been ported to libev, the AC has not been adjusted and is ther
* 802.11b
* 802.11g
* 802.11a
* WMM/WME (mostly)
* Local MAC
* single radio, single WLAN mode
* 802.11n ([draft-ietf-opsawg-capwap-extension-06](https://tools.ietf.org/html/draft-ietf-opsawg-capwap-extension-06))
Only cards with cfg80211 netlink API are supported and only
ath9k cards (in particular Qualcomm Atheros AR5418) have
been tested.
Only cards with cfg80211 netlink API are supported. The following devices
have been tested:
* Atheros AR9280 (Compex WLE200NX)
* Mediatek MT7602E, MT7612E (ZBT WG2626, ALL-WR1200AC_WRT)
### Planned WTP features:

View File

@ -102,7 +102,8 @@ capwap_SOURCES = $(top_srcdir)/src/common/capwap.c \
$(top_srcdir)/src/common/capwap_element_80211_wtpradiofailalarm.c \
$(top_srcdir)/src/common/capwap_element_80211_wtpradioinformation.c \
$(top_srcdir)/src/common/capwap_element_80211n_radioconf.c \
$(top_srcdir)/src/common/capwap_element_80211n_station_information.c
$(top_srcdir)/src/common/capwap_element_80211n_station_information.c \
$(top_srcdir)/src/common/capwap_element_vendor_travelping_wtp_timestamp.c
if DEBUG_BUILD
capwap_SOURCES += $(top_srcdir)/src/common/capwap_debug.c

View File

@ -49,6 +49,7 @@ application: {
timer: {
statistics = 120;
inactivity = 300;
};
dtls: {

View File

@ -19,7 +19,7 @@
AC_PREREQ(2.63)
AC_INIT([SmartCAPWAP], [1.2], [https://github.com/travelping/smartcapwap], [smartcapwap])
AC_INIT([SmartCAPWAP], [1.2.1], [https://github.com/travelping/smartcapwap], [smartcapwap])
AC_CONFIG_AUX_DIR([build])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([1.11 -Wall])

View File

@ -9,10 +9,21 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=smartcapwap
PKG_VERSION:=1.0
PKG_VERSION:=1.2.1
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
SRC_SMARTCAPWAP := /usr/src/tplino/components/smartcapwap
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=git://github.com/travelping/smartcapwap.git
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE_VERSION:=v1.2.1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_MAINTAINER:=Travelping GmbH <info@travelping.com>
PKG_LICENSE:=GPL-v2
PKG_LICENSE_FILES:=LICENSE
PKG_FIXUP:=autoreconf
@ -29,18 +40,25 @@ define Package/smartcapwap
CATEGORY:=Network
TITLE:=SmartCAPWAP WTP
MAINTAINER:=Massimo Vellucci <vemax78@gmail.com>
DEPENDS:=+libnl-tiny +libconfig +libwolfssl +kmod-smartcapwap
DEPENDS:=+libnl +libev +libconfig +libcyassl +kmod-smartcapwap
endef
define Package/smartcapwap/description
This package contains the SmartCAPWAP WTP daemon.
endef
define Package/smartcapwap/conffiles
/etc/capwap/wtp.conf
/etc/capwap/ca.crt
/etc/capwap/wtp.crt
/etc/capwap/wtp.key
endef
define KernelPackage/smartcapwap
SUBMENU:=Network Support
TITLE:=SmartCAPWAP Data Channel Module
MAINTAINER:=Massimo Vellucci <vemax78@gmail.com>
DEPENDS:=+kmod-mac80211 +kmod-ipv6
DEPENDS:=+kmod-mac80211 +kmod-udptunnel4 +IPV6:kmod-udptunnel6
FILES:=$(PKG_BUILD_DIR)/src/wtp/kmod/smartcapwap.ko
AUTOLOAD:=$(call AutoLoad,70,smartcapwap)
endef
@ -49,8 +67,7 @@ define KernelPackage/smartcapwap/description
This package contains the SmartCAPWAP Data Transport kernel module.
endef
TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny
SRC_SMARTCAPWAP := /mnt/hgfs/shared/smartcapwap
TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl3
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)

View File

@ -170,7 +170,8 @@ static void execute_ieee80211_station_configuration_response_addstation(struct a
station = ac_stations_get_station(session, station80211->radioid, wlan->address, addstation->address);
if (station) {
if (CAPWAP_RESULTCODE_OK(resultcode->code)) {
log_printf(LOG_INFO, "Authorized station: %s", station->addrtext);
log_printf(LOG_INFO, "Authorized station: " MACSTR,
MAC2STR(station->address));
/* */
station->flags |= AC_STATION_FLAGS_AUTHORIZED;
@ -198,7 +199,8 @@ static void execute_ieee80211_station_configuration_response_deletestation(struc
/* */
station = ac_stations_get_station(session, deletestation->radioid, NULL, deletestation->address);
if (station) {
log_printf(LOG_INFO, "Deauthorized station: %s with %d result code", station->addrtext, (int)resultcode->code);
log_printf(LOG_INFO, "Deauthorized station: " MACSTR " with %d result code",
MAC2STR(station->address), (int)resultcode->code);
/* */
ac_stations_delete_station(session, station);

View File

@ -42,7 +42,8 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_t* session
}
/* */
log_printf(LOG_INFO, "Receive IEEE802.11 Authentication Request from %s station", station->addrtext);
log_printf(LOG_INFO, "Receive IEEE802.11 Authentication Request "
"from " MACSTR " station", MAC2STR(station->address));
/* A station is removed if the association does not complete within a given period of time */
station->timeoutaction = AC_STATION_TIMEOUT_ACTION_DEAUTHENTICATE;
@ -62,7 +63,8 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_t* session
/* Parsing Information Elements */
if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->authetication.ie[0], ielength)) {
log_printf(LOG_INFO, "Invalid IEEE802.11 Authentication Request from %s station", station->addrtext);
log_printf(LOG_INFO, "Invalid IEEE802.11 Authentication Request "
"from " MACSTR " station", MAC2STR(station->address));
return;
}
@ -95,14 +97,18 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_t* session
if (responselength > 0) {
/* Send authentication response */
if (!ac_kmod_send_data(&session->sessionid, wlan->device->radioid, session->binding, buffer, responselength)) {
log_printf(LOG_INFO, "Sent IEEE802.11 Authentication Response to %s station with %d status code", station->addrtext, (int)responsestatuscode);
log_printf(LOG_INFO, "Sent IEEE802.11 Authentication Response "
"to " MACSTR " station with %d status code",
MAC2STR(station->address), (int)responsestatuscode);
station->flags |= AC_STATION_FLAGS_AUTHENTICATED;
} else {
log_printf(LOG_WARNING, "Unable to send IEEE802.11 Authentication Response to %s station", station->addrtext);
log_printf(LOG_WARNING, "Unable to send IEEE802.11 Authentication Response "
"to " MACSTR " station", MAC2STR(station->address));
ac_stations_delete_station(session, station);
}
} else {
log_printf(LOG_WARNING, "Unable to create IEEE802.11 Authentication Response to %s station", station->addrtext);
log_printf(LOG_WARNING, "Unable to create IEEE802.11 Authentication Response "
"to " MACSTR " station", MAC2STR(station->address));
ac_stations_delete_station(session, station);
}
}
@ -117,7 +123,9 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_t* session
statuscode = __le16_to_cpu(mgmt->authetication.statuscode);
/* */
log_printf(LOG_INFO, "Receive IEEE802.11 Authentication Response to %s station with %d status code", station->addrtext, (int)statuscode);
log_printf(LOG_INFO, "Receive IEEE802.11 Authentication Response "
"to " MACSTR " station with %d status code",
MAC2STR(station->address), (int)statuscode);
if (statuscode == IEEE80211_STATUS_SUCCESS) {
algorithm = __le16_to_cpu(mgmt->authetication.algorithm);
@ -155,13 +163,15 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_t* se
}
/* */
log_printf(LOG_INFO, "Receive IEEE802.11 Association Request from %s station", station->addrtext);
log_printf(LOG_INFO, "Receive IEEE802.11 Association Request "
"from " MACSTR " station", MAC2STR(station->address));
/* */
wlan = station->wlan;
if (!(station->flags & AC_STATION_FLAGS_AUTHENTICATED)) {
/* Invalid station, delete station */
log_printf(LOG_INFO, "Receive IEEE802.11 Association Request from %s unauthorized station", station->addrtext);
log_printf(LOG_INFO, "Receive IEEE802.11 Association Request "
"from " MACSTR " unauthorized station", MAC2STR(station->address));
ac_stations_delete_station(session, station);
return;
}
@ -191,7 +201,8 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_t* se
/* Parsing Information Elements */
if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationrequest.ie[0], ielength)) {
log_printf(LOG_INFO, "Invalid IEEE802.11 Association Request from %s station", station->addrtext);
log_printf(LOG_INFO, "Invalid IEEE802.11 Association Request "
"from " MACSTR " station", MAC2STR(station->address));
ac_stations_delete_station(session, station);
return;
}
@ -237,17 +248,21 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_t* se
if (responselength > 0) {
/* Send association response */
if (!ac_kmod_send_data(&session->sessionid, wlan->device->radioid, session->binding, buffer, responselength)) {
log_printf(LOG_INFO, "Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode);
log_printf(LOG_INFO, "Sent IEEE802.11 Association Response "
"to " MACSTR " station with %d status code",
MAC2STR(station->address), (int)resultstatuscode);
/* Active Station */
station->flags |= AC_STATION_FLAGS_ASSOCIATE;
ac_stations_authorize_station(session, station);
} else {
log_printf(LOG_WARNING, "Unable to send IEEE802.11 Association Response to %s station", station->addrtext);
log_printf(LOG_WARNING, "Unable to send IEEE802.11 Association Response "
"to " MACSTR " station", MAC2STR(station->address));
ac_stations_delete_station(session, station);
}
} else {
log_printf(LOG_WARNING, "Unable to create IEEE802.11 Association Response to %s station", station->addrtext);
log_printf(LOG_WARNING, "Unable to create IEEE802.11 Association Response "
"to " MACSTR " station", MAC2STR(station->address));
ac_stations_delete_station(session, station);
}
}
@ -271,7 +286,9 @@ static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_t* s
if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) {
station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->da);
if (station && station->wlan && (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) {
log_printf(LOG_INFO, "Receive IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)mgmt->associationresponse.statuscode);
log_printf(LOG_INFO, "Receive IEEE802.11 Association Response "
"to " MACSTR " station with %d status code",
MAC2STR(station->address), (int)mgmt->associationresponse.statuscode);
if (mgmt->associationresponse.statuscode == IEEE80211_STATUS_SUCCESS) {
/* Get Station Info */

View File

@ -45,7 +45,7 @@ static void ac_stations_destroy_station(struct ac_session_t* session, struct ac_
ASSERT(station != NULL);
/* */
log_printf(LOG_INFO, "Destroy station: %s", station->addrtext);
log_printf(LOG_INFO, "Destroy station: " MACSTR, MAC2STR(station->address));
/* Remove reference from Authoritative Stations List */
capwap_rwlock_wrlock(&g_ac.authstationslock);
@ -139,9 +139,8 @@ void ac_wlans_destroy(struct ac_session_t* session) {
}
/* */
int ac_wlans_assign_bssid(struct ac_session_t* session, struct ac_wlan* wlan) {
char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER];
int ac_wlans_assign_bssid(struct ac_session_t* session, struct ac_wlan* wlan)
{
ASSERT(session != NULL);
ASSERT(session->wlans != NULL);
ASSERT(wlan != NULL);
@ -166,7 +165,8 @@ int ac_wlans_assign_bssid(struct ac_session_t* session, struct ac_wlan* wlan) {
capwap_itemlist_insert_after(session->wlans->devices[wlan->device->radioid - 1].wlans, NULL, wlan->wlanitem);
/* */
log_printf(LOG_INFO, "Added new wlan with radioid: %d, wlanid: %d, bssid: %s", (int)wlan->device->radioid, (int)wlan->wlanid, capwap_printf_macaddress(buffer, wlan->address, MACADDRESS_EUI48_LENGTH));
log_printf(LOG_INFO, "Added new wlan with radioid: %d, wlanid: %d, bssid: " MACSTR,
(int)wlan->device->radioid, (int)wlan->wlanid, MAC2STR(wlan->address));
return 0;
}
@ -325,9 +325,8 @@ struct ac_station* ac_stations_get_station(struct ac_session_t* session, uint8_t
}
/* */
struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address) {
char buffer1[CAPWAP_MACADDRESS_EUI48_BUFFER];
char buffer2[CAPWAP_MACADDRESS_EUI48_BUFFER];
struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address)
{
struct ac_wlan* wlan;
struct ac_station* authoritativestation;
struct ac_station* station = NULL;
@ -340,9 +339,8 @@ struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint
ASSERT(address != NULL);
/* */
capwap_printf_macaddress(buffer1, bssid, MACADDRESS_EUI48_LENGTH);
capwap_printf_macaddress(buffer2, address, MACADDRESS_EUI48_LENGTH);
log_printf(LOG_INFO, "Create station to radioid: %d, bssid: %s, station address: %s", (int)radioid, buffer1, buffer2);
log_printf(LOG_INFO, "Create station to radioid: %d, bssid: " MACSTR ", station address: " MACSTR,
(int)radioid, MAC2STR(bssid), MAC2STR(address));
/* */
wlan = ac_wlans_get_bssid(session, radioid, bssid);
@ -357,7 +355,6 @@ struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint
/* */
station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET;
memcpy(station->address, address, MACADDRESS_EUI48_LENGTH);
capwap_printf_macaddress(station->addrtext, address, MACADDRESS_EUI48_LENGTH);
station->wlanitem = stationitem;
station->session = session;
@ -392,7 +389,8 @@ struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint
}
}
} else {
log_printf(LOG_WARNING, "Unable to find radioid: %d, bssid: %s", (int)radioid, buffer1);
log_printf(LOG_WARNING, "Unable to find radioid: %d, bssid: " MACSTR,
(int)radioid, MAC2STR(bssid));
}
return station;
@ -479,7 +477,8 @@ void ac_stations_timeout(struct capwap_timeout* timeout, unsigned long index, vo
if (station->idtimeout == index) {
switch (station->timeoutaction) {
case AC_STATION_TIMEOUT_ACTION_DEAUTHENTICATE: {
log_printf(LOG_WARNING, "The %s station has not completed the association in time", station->addrtext);
log_printf(LOG_WARNING, "The " MACSTR " station has not completed "
"the association in time", MAC2STR(station->address));
ac_stations_delete_station((struct ac_session_t*)param, station);
break;
}

View File

@ -74,7 +74,6 @@ struct ac_wlans {
/* AC Station */
struct ac_station {
uint8_t address[MACADDRESS_EUI48_LENGTH];
char addrtext[CAPWAP_MACADDRESS_EUI48_BUFFER];
/* */
unsigned long flags;

View File

@ -764,3 +764,27 @@ int ieee80211_create_deauthentication(uint8_t* buffer, int length, struct ieee80
return (int)((uint8_t*)&header->deauthetication.ie[0] - (uint8_t*)header);
}
/* */
int ieee80211_create_disassociation(uint8_t* buffer, int length,
struct ieee80211_disassociation_params* params)
{
struct ieee80211_header_mgmt* header;
ASSERT(buffer != NULL);
/* */
header = (struct ieee80211_header_mgmt*)buffer;
/* Management header frame */
header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT,
IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION);
header->durationid = __cpu_to_le16(0);
memcpy(header->da, params->station, ETH_ALEN);
memcpy(header->sa, params->bssid, ETH_ALEN);
memcpy(header->bssid, params->bssid, ETH_ALEN);
header->sequencecontrol = __cpu_to_le16(0);
header->disassociation.reasoncode = __cpu_to_le16(params->reasoncode);
return (int)((uint8_t*)&header->disassociation.ie[0] - (uint8_t*)header);
}

View File

@ -697,6 +697,16 @@ struct ieee80211_deauthentication_params {
int ieee80211_create_deauthentication(uint8_t* buffer, int length, struct ieee80211_deauthentication_params* params);
/* Management Disassociation */
struct ieee80211_disassociation_params {
uint8_t bssid[ETH_ALEN];
uint8_t station[ETH_ALEN];
uint16_t reasoncode;
};
int ieee80211_create_disassociation(uint8_t* buffer, int length, struct ieee80211_disassociation_params* params);
/* Utils */
int ieee80211_retrieve_information_elements_position(struct ieee80211_ie_items* items, const uint8_t* data, int length);
unsigned long ieee80211_frequency_to_channel(uint32_t freq);

View File

@ -1,9 +1,6 @@
#ifndef __CAPWAP_DEBUG_HEADER__
#define __CAPWAP_DEBUG_HEADER__
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#ifdef DEBUG
#define ASSERT(expr) if (!(expr)) { log_printf(LOG_EMERG, "Assertion failed \'%s\': %s(%d)", #expr, __FILE__, __LINE__); capwap_exit(CAPWAP_ASSERT_CONDITION); }

View File

@ -91,6 +91,7 @@ static const struct capwap_message_elements_ops * capwap_80211_message_elements[
/* */
#define element_ops(Id, Ops) [(Id) - 1] = &(Ops)
static const struct capwap_message_elements_ops * capwap_vendor_travelping_message_elements[] = {
element_ops(CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP_TYPE, capwap_element_vendor_travelping_wtp_timestamp_ops),
element_ops(CAPWAP_ELEMENT_80211N_RADIO_CONF_TYPE, capwap_element_80211n_radioconf_ops),
element_ops(CAPWAP_ELEMENT_80211N_STATION_INFO_TYPE, capwap_element_80211n_station_info_ops)
};
@ -138,7 +139,7 @@ struct capwap_list_item* capwap_get_message_element(struct capwap_parsed_packet*
while (search) {
struct capwap_message_element_itemlist* messageelement =
(struct capwap_message_element_itemlist*)search->item;
if ((id.vendor == messageelement->id.vendor) && (id.type == messageelement->id.type))
if (message_element_id_eq(id, messageelement->id))
return search;
/* */

View File

@ -10,6 +10,9 @@ struct capwap_message_element_id
uint16_t type;
};
#define message_element_id_eq(a, b) \
(((a).vendor == (b).vendor) && ((a).type == (b).type))
/* */
typedef void* capwap_message_elements_handle;
struct capwap_write_message_elements_ops {

View File

@ -0,0 +1,109 @@
#include "capwap.h"
#include "capwap_element.h"
/*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Second |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Fraction |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* WTP Timestamp
*
* Vendor Id: 18681 (Travelping GmbH)
* Type: 2
*
*/
struct ntp_time_t {
uint32_t second;
uint32_t fraction;
};
static inline void convert_ntp_time_into_unix_time(struct ntp_time_t *ntp, struct timeval *tv)
{
tv->tv_sec = ntp->second - 0x83AA7E80; // the seconds from Jan 1, 1900 to Jan 1, 1970
tv->tv_usec = (uint32_t)( (double)ntp->fraction * 1.0e6 / (double)(1LL<<32) );
}
static inline void convert_unix_time_into_ntp_time(struct timeval *tv, struct ntp_time_t *ntp)
{
ntp->second = tv->tv_sec + 0x83AA7E80;
ntp->fraction = (uint32_t)( (double)(tv->tv_usec+1) * (double)(1LL<<32) * 1.0e-6 );
}
/* */
static void
capwap_vendor_travelping_wtp_timestamp_element_create(void *data,
capwap_message_elements_handle handle,
struct capwap_write_message_elements_ops *func)
{
struct capwap_vendor_travelping_wtp_timestamp_element *element =
(struct capwap_vendor_travelping_wtp_timestamp_element *)data;
struct ntp_time_t ntp;
ASSERT(data != NULL);
convert_unix_time_into_ntp_time(&element->tv, &ntp);
func->write_u32(handle, ntp.second);
func->write_u32(handle, ntp.fraction);
}
/* */
static void *
capwap_vendor_travelping_wtp_timestamp_element_parsing(capwap_message_elements_handle handle,
struct capwap_read_message_elements_ops *func)
{
struct capwap_vendor_travelping_wtp_timestamp_element *data;
struct ntp_time_t ntp;
ASSERT(handle != NULL);
ASSERT(func != NULL);
if (func->read_ready(handle) != 8) {
log_printf(LOG_DEBUG, "Invalid Vendor Travelping WTP Timestamp element");
return NULL;
}
/* */
data = (struct capwap_vendor_travelping_wtp_timestamp_element *)
capwap_alloc(sizeof(struct capwap_vendor_travelping_wtp_timestamp_element));
/* Retrieve data */
func->read_u32(handle, &ntp.second);
func->read_u32(handle, &ntp.fraction);
convert_ntp_time_into_unix_time(&ntp, &data->tv);
return data;
}
/* */
static void *
capwap_vendor_travelping_wtp_timestamp_element_clone(void *data)
{
ASSERT(data != NULL);
return capwap_clone(data, sizeof(struct capwap_vendor_travelping_wtp_timestamp_element));
}
/* */
static void
capwap_vendor_travelping_wtp_timestamp_element_free(void* data)
{
ASSERT(data != NULL);
capwap_free(data);
}
/* */
const struct capwap_message_elements_ops capwap_element_vendor_travelping_wtp_timestamp_ops = {
.category = CAPWAP_MESSAGE_ELEMENT_SINGLE,
.create = capwap_vendor_travelping_wtp_timestamp_element_create,
.parse = capwap_vendor_travelping_wtp_timestamp_element_parsing,
.clone = capwap_vendor_travelping_wtp_timestamp_element_clone,
.free = capwap_vendor_travelping_wtp_timestamp_element_free
};

View File

@ -0,0 +1,19 @@
#ifndef __CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP_HEADER__
#define __CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP_HEADER__
#define CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP_VENDOR CAPWAP_VENDOR_TRAVELPING_ID
#define CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP_TYPE 2
#define CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP \
(struct capwap_message_element_id){ \
.vendor = CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP_VENDOR, \
.type = CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP_TYPE \
}
struct capwap_vendor_travelping_wtp_timestamp_element {
struct timeval tv;
};
extern const struct capwap_message_elements_ops capwap_element_vendor_travelping_wtp_timestamp_ops;
#endif /* __CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP_HEADER__ */

View File

@ -1,6 +1,9 @@
#ifndef __CAPWAP_LOGGING_HEADER__
#define __CAPWAP_LOGGING_HEADER__
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#include <syslog.h>
#define LOG_TO_SYSLOG

View File

@ -384,7 +384,9 @@ int capwap_sendto(int sock, void* buffer, int size, union sockaddr_capwap* toadd
#ifdef DEBUG
{
char strtoaddr[INET6_ADDRSTRLEN];
log_printf(LOG_DEBUG, "Sent packet to %s:%d with result %d", capwap_address_to_string(toaddr, strtoaddr, INET6_ADDRSTRLEN), (int)CAPWAP_GET_NETWORK_PORT(toaddr), result);
log_printf(LOG_DEBUG, "Sent packet to %s:%d with result %d",
capwap_address_to_string(toaddr, strtoaddr, INET6_ADDRSTRLEN),
(int)CAPWAP_GET_NETWORK_PORT(toaddr), result);
}
#endif

View File

@ -3,6 +3,8 @@
#define CAPWAP_VENDOR_TRAVELPING_ID 18681
#include "capwap_element_vendor_travelping_wtp_timestamp.h"
/* draft-ietf-opsawg-capwap-extension-06 */
#include "capwap_element_80211n_radioconf.h"
#include "capwap_element_80211n_station_information.h"

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@
#define WIFI_CAPABILITY_FLAGS_SUPPORT_AP_UAPSD 0x00000004
#define WIFI_CAPABILITY_FLAGS_DEVICE_AP_SME 0x00000008
#define WIFI_CAPABILITY_FLAGS_PROBE_RESPONSE_OFFLOAD 0x00000010
#define WIFI_CAPABILITY_FLAGS_INACTIVITY_TIMER 0x00000020
/* */
#define WIFI_CAPABILITY_AP_SUPPORTED 0x00000001
@ -127,6 +128,7 @@ struct wlan_send_frame_params {
struct station_add_params {
uint8_t* address;
struct ieee80211_ht_cap *ht_cap;
int max_inactivity;
};
/* Interface capability */
@ -161,6 +163,11 @@ struct wifi_band_capability {
struct capwap_array* rate;
};
/* */
struct wifi_commands_capability {
unsigned int poll_command_supported:1;
};
/* */
struct wifi_cipher_capability {
unsigned long cipher;
@ -186,6 +193,8 @@ struct wifi_capability {
/* WIFI_CAPABILITY_BANDS */
struct capwap_array* bands;
struct wifi_commands_capability supp_cmds;
/* WIFI_CAPABILITY_CIPHERS */
struct capwap_array* ciphers;
@ -332,26 +341,31 @@ struct wifi_wlan {
#define WIFI_STATION_FLAGS_WMM 0x00000020
#define WIFI_STATION_FLAGS_AUTHORIZED 0x00000040
#define WIFI_STATION_FLAGS_HT_CAP 0x00000080
#define WIFI_STATION_FLAGS_POLL_PENDING 0x00000100
/* */
#define WIFI_STATION_TIMEOUT_ASSOCIATION_COMPLETE 30000
#define WIFI_STATION_TIMEOUT_AFTER_DEAUTHENTICATED 5000
/* */
#define WIFI_STATION_TIMEOUT_ACTION_DELETE 0x00000001
#define WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE 0x00000002
#define WIFI_STATION_TIMEOUT_BEFORE_DISASSOCIATE 3000
#define WIFI_STATION_TIMEOUT_BEFORE_DEAUTHENTICATE 1000
struct wifi_station {
uint8_t address[MACADDRESS_EUI48_LENGTH];
char addrtext[CAPWAP_MACADDRESS_EUI48_BUFFER];
/* */
struct wifi_wlan* wlan;
/* */
unsigned long flags;
uint32_t flags;
/* Timers */
/* Timer */
int max_inactivity;
enum {
WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC = 0,
WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE,
WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE,
WIFI_STATION_TIMEOUT_ACTION_DELETE
} timeout_action;
struct ev_timer timeout;
/* */
@ -394,11 +408,13 @@ struct wifi_driver_ops {
int (*wlan_startap)(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);
void (*wlan_poll_station)(struct wifi_wlan* wlan, const uint8_t* address, int qos);
void (*wlan_delete)(struct wifi_wlan* wlan);
/* Stations functions */
int (*station_authorize)(struct wifi_wlan* wlan, struct wifi_station* station);
int (*station_deauthorize)(struct wifi_wlan* wlan, const uint8_t* address);
int (*station_get_inact_sec)(struct wifi_wlan* wlan, const uint8_t* address);
};
/* Initialize wifi driver engine */
@ -429,6 +445,7 @@ void wifi_wlan_destroy(struct wifi_wlan* wlan);
void wifi_wlan_receive_station_frame(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, uint32_t frequency, uint8_t rssi, uint8_t snr, uint16_t rate);
void wifi_wlan_receive_station_ackframe(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, int ack);
void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header* frame, int length);
void wifi_wlan_client_probe_event(struct wifi_wlan *wlan, const uint8_t *address);
/* Station management */
int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params);
@ -436,9 +453,6 @@ void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address
/* Util functions */
uint32_t wifi_iface_index(const char* ifname);
int wifi_iface_hwaddr(int sock, const char* ifname, uint8_t* hwaddr);
int wifi_frequency_to_radiotype(uint32_t freq);
/* */
int wifi_iface_getstatus(int sock, const char* ifname);

File diff suppressed because it is too large Load Diff

View File

@ -49,4 +49,13 @@ struct nl80211_wlan_handle {
uint64_t last_cookie;
};
/* NL80211 Station statistics */
struct nl80211_station_data {
unsigned long rx_packets, tx_packets;
unsigned long long rx_bytes, tx_bytes;
int bytes_64bit;
unsigned long inactive_msec;
unsigned long tx_retry_failed;
};
#endif /* __WIFI_NL80211_HEADER__ */

View File

@ -57,6 +57,7 @@ static int wtp_init(void)
g_wtp.ecn.flag = CAPWAP_LIMITED_ECN_SUPPORT;
g_wtp.transport.type = CAPWAP_UDP_TRANSPORT;
g_wtp.statisticstimer.timer = WTP_STATISTICSTIMER_INTERVAL / 1000;
g_wtp.sta_max_inactivity = WIFI_STATIONS_DEFAULT_STA_MAX_INACTIVITY;
g_wtp.mactype.type = CAPWAP_LOCALMAC;
g_wtp.mactunnel.mode = CAPWAP_WTP_LOCAL_BRIDGING;
@ -1041,6 +1042,16 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
}
}
if (config_lookup_int(config, "application.timer.inactivity", &configInt) == CONFIG_TRUE) {
if ((configInt < 0) || (configInt > 3600)) {
log_printf(LOG_ERR, "Invalid configuration file, "
"invalid application.timer.inactivity value");
return 0;
}
g_wtp.sta_max_inactivity = (unsigned short)configInt;
}
/* Set DTLS of WTP */
if (config_lookup_bool(config, "application.dtls.enable", &configBool) == CONFIG_TRUE) {
if (configBool != 0) {

View File

@ -48,6 +48,8 @@
#define WTP_TUNNEL_DATA_FRAME_KERNELMODE 0x00000001
#define WTP_TUNNEL_DATA_FRAME_USERMODE 0x00000002
#define WIFI_STATIONS_DEFAULT_STA_MAX_INACTIVITY 300
/* */
struct wtp_fds {
int fdstotalcount;
@ -118,6 +120,11 @@ struct wtp_t {
struct capwap_statisticstimer_element statisticstimer;
struct capwap_wtprebootstat_element rebootstat;
int sta_max_inactivity;
/* Echo statistics */
struct timeval echo_latency;
/* */
unsigned short fragmentid;
struct capwap_packet_rxmng* rxmngpacket;

View File

@ -6,6 +6,7 @@
/* */
static void wtp_dfa_state_dtlsconnect_timeout(EV_P_ ev_timer *w, int revents)
{
log_printf(LOG_DEBUG, "DTLS Connect Timeout");
wtp_teardown_connection();
}

View File

@ -16,6 +16,9 @@ static int send_echo_request(void)
int result = -1;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
struct capwap_vendor_travelping_wtp_timestamp_element timestamp;
gettimeofday(&timestamp.tv, NULL);
/* Build packet */
capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, g_wtp.binding);
@ -23,7 +26,9 @@ static int send_echo_request(void)
g_wtp.localseqnumber, g_wtp.mtu);
/* Add message element */
/* CAPWAP_ELEMENT_VENDORPAYLOAD */ /* TODO */
capwap_packet_txmng_add_message_element(txmngpacket,
CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP,
&timestamp);
/* Echo request complete, get fragment packets */
wtp_free_reference_last_request();
@ -47,18 +52,34 @@ static int send_echo_request(void)
}
/* */
static int receive_echo_response(struct capwap_parsed_packet* packet) {
static int receive_echo_response(struct capwap_parsed_packet* packet)
{
struct capwap_resultcode_element* resultcode;
struct capwap_vendor_travelping_wtp_timestamp_element *timestamp;
ASSERT(packet != NULL);
/* 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)) {
log_printf(LOG_WARNING, "Receive Echo Response with error: %d", (int)resultcode->code);
return 1;
}
timestamp = (struct capwap_vendor_travelping_wtp_timestamp_element *)
capwap_get_message_element_data(packet, CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP);
if (timestamp) {
struct timeval now;
gettimeofday(&now, NULL);
timersub(&now, &timestamp->tv, &g_wtp.echo_latency);
log_printf(LOG_DEBUG, "Echo Latency: %ld.%03ld ms",
g_wtp.echo_latency.tv_sec * 1000 + g_wtp.echo_latency.tv_usec / 1000,
g_wtp.echo_latency.tv_usec % 1000);
}
/* Valid packet, free request packet */
wtp_free_reference_last_request();
return 0;
@ -221,7 +242,7 @@ static void receive_ieee80211_wlan_configuration_request(struct capwap_parsed_pa
/* Add message element */
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_RESULTCODE, &resultcode);
if (resultcode.code == CAPWAP_RESULTCODE_SUCCESS &&
memcmp(&action, &CAPWAP_ELEMENT_80211_ADD_WLAN, sizeof(CAPWAP_ELEMENT_80211_ADD_WLAN)) == 0)
message_element_id_eq(action, CAPWAP_ELEMENT_80211_ADD_WLAN))
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_ASSIGN_BSSID, &bssid);
/* CAPWAP_ELEMENT_VENDORPAYLOAD */ /* TODO */

View File

@ -195,7 +195,7 @@ static void wtp_radio_setconfiguration_80211(struct capwap_parsed_packet *packet
/* Parsing only IEEE 802.11 message element */
if (!IS_80211_MESSAGE_ELEMENTS(messageelement->id) &&
memcmp(&messageelement->id, &CAPWAP_ELEMENT_80211N_RADIO_CONF, sizeof(messageelement->id)) != 0)
!message_element_id_eq(messageelement->id, CAPWAP_ELEMENT_80211N_RADIO_CONF))
continue;
ASSERT(messageelements != NULL);
@ -255,7 +255,7 @@ static void wtp_radio_setconfiguration_80211(struct capwap_parsed_packet *packet
/* Parsing only IEEE 802.11 message element */
if (!IS_80211_MESSAGE_ELEMENTS(messageelement->id) &&
memcmp(&messageelement->id, &CAPWAP_ELEMENT_80211N_RADIO_CONF, sizeof(messageelement->id)) != 0)
!message_element_id_eq(messageelement->id, CAPWAP_ELEMENT_80211N_RADIO_CONF))
continue;
ASSERT(messageelements != NULL);
@ -464,18 +464,22 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet)
result = wifi_device_setfrequency(item->radio->devicehandle, WIFI_BAND_2GHZ,
item->radio->radioinformation.radiotype,
item->radio->directsequencecontrol.currentchannel);
log_printf(LOG_DEBUG, "wtp_radio %d, set 2GHz frequency to %d, result: %d",
item->radio->radioid, item->radio->directsequencecontrol.currentchannel,
result);
break;
case WTP_UPDATE_FREQUENCY_OFDM:
result = wifi_device_setfrequency(item->radio->devicehandle, WIFI_BAND_5GHZ,
item->radio->radioinformation.radiotype,
item->radio->ofdmcontrol.currentchannel);
log_printf(LOG_DEBUG, "wtp_radio %d, set 5GHz frequency to %d, result: %d",
item->radio->radioid, item->radio->ofdmcontrol.currentchannel,
result);
break;
}
}
log_printf(LOG_DEBUG, "wtp_radio_setconfiguration result #2: %d", result);
/* Update radio configuration */
for (i = 0; (i < updateitems->count) && !result; i++) {
struct wtp_update_configuration_item* item =
@ -486,6 +490,8 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet)
result = wifi_device_updaterates(item->radio->devicehandle,
item->radio->rateset.rateset,
item->radio->rateset.ratesetcount);
log_printf(LOG_DEBUG, "wtp_radio %d, update rates result: %d",
item->radio->radioid, result);
break;
case WTP_UPDATE_CONFIGURATION: {
@ -499,17 +505,21 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet)
params.beaconperiod = item->radio->radioconfig.beaconperiod;
memcpy(params.country, item->radio->radioconfig.country, WIFI_COUNTRY_LENGTH);
result = wifi_device_setconfiguration(item->radio->devicehandle, &params);
log_printf(LOG_DEBUG, "wtp_radio %d, set configuration result: %d",
item->radio->radioid, result);
break;
}
case WTP_UPDATE_TX_QUEUE:
result = wifi_device_settxqueue(item->radio->devicehandle, &item->radio->qos);
log_printf(LOG_DEBUG, "wtp_radio %d, set Tx queue result: %d",
item->radio->radioid, result);
break;
}
}
log_printf(LOG_DEBUG, "wtp_radio_setconfiguration result #3: %d", result);
/* */
capwap_array_free(updateitems);
return result;
@ -642,6 +652,16 @@ void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, cons
}
}
/* source http://stackoverflow.com/a/16994674 */
static uint16_t reverse(register uint16_t x)
{
x = (((x & 0xaaaa) >> 1) | ((x & 0x5555) << 1));
x = (((x & 0xcccc) >> 2) | ((x & 0x3333) << 2));
x = (((x & 0xf0f0) >> 4) | ((x & 0x0f0f) << 4));
x = (((x & 0xff00) >> 8) | ((x & 0x00ff) << 8));
return x;
}
/* */
uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet,
struct capwap_80211_assignbssid_element* bssid)
@ -669,7 +689,7 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet,
/* Check if virtual interface is already exist */
wlan = wtp_radio_get_wlan(radio, addwlan->wlanid);
if (!wlan && !wlan->wlanhandle) {
if (!wlan || !wlan->wlanhandle) {
log_printf(LOG_DEBUG, "Create WLAN: invalid WLAN ID");
return CAPWAP_RESULTCODE_FAILURE;
}
@ -690,7 +710,7 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet,
params.wlanid = addwlan->wlanid;
params.ssid = (const char*)addwlan->ssid;
params.ssid_hidden = addwlan->suppressssid;
params.capability = addwlan->capability;
params.capability = reverse(addwlan->capability);
params.qos = addwlan->qos;
params.authmode = addwlan->authmode;
params.macmode = addwlan->macmode;
@ -805,6 +825,7 @@ uint32_t wtp_radio_add_station(struct capwap_parsed_packet* packet) {
memcpy(&ht_cap.mcs.rx_mask, station80211n->mcsset, sizeof(ht_cap.mcs.rx_mask));
stationparams.ht_cap = &ht_cap;
stationparams.max_inactivity = g_wtp.sta_max_inactivity;
}
err = wtp_kmod_add_station(addstation->radioid, station80211->address, station80211->wlanid);