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.
This commit is contained in:
Andreas Schultz 2016-04-07 15:15:50 +02:00
parent bca5c91ae1
commit 813f24b8ac
9 changed files with 432 additions and 38 deletions

View File

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

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

@ -25,14 +25,18 @@ static struct wifi_global g_wifiglobal;
static uint8_t g_bufferIEEE80211[IEEE80211_MTU];
/* */
static void wifi_station_timeout_delete(EV_P_ ev_timer *w, int revents);
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);
static void wifi_wlan_send_mgmt_deauthentication(struct wifi_wlan* wlan,
const uint8_t* station,
uint16_t reasoncode);
static void wifi_wlan_disassociate_station(struct wifi_wlan* wlan,
struct wifi_station* station,
uint16_t reasoncode);
static void wifi_wlan_send_mgmt_disassociation(struct wifi_wlan* wlan,
const uint8_t* station,
uint16_t reasoncode);
/* device operations */
static int device_init(struct wifi_driver_instance *instance, struct wifi_device* device)
@ -96,6 +100,11 @@ static int wlan_sendframe(struct wifi_wlan* wlan,
no_wait_ack);
}
static void wlan_poll_station(struct wifi_wlan* wlan, const uint8_t* address, int qos)
{
wlan->device->instance->ops->wlan_poll_station(wlan, address, qos);
}
static void wlan_delete(struct wifi_wlan* wlan)
{
wlan->device->instance->ops->wlan_delete(wlan);
@ -379,10 +388,9 @@ static void wifi_station_delete(struct wifi_station* station)
wifi_station_clean(station);
/* Delay delete station */
ev_timer_stop(EV_DEFAULT_UC_ &station->timeout);
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);
station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_DELETE;
station->timeout.repeat = WIFI_STATION_TIMEOUT_AFTER_DEAUTHENTICATED / 1000.0;
ev_timer_again(EV_DEFAULT_UC_ &station->timeout);
}
/* */
@ -493,25 +501,214 @@ static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan,
}
/* */
static void wifi_station_timeout_delete(EV_P_ ev_timer *w, int revents)
static void wifi_wlan_send_mgmt_disassociation(struct wifi_wlan* wlan,
const uint8_t* station,
uint16_t reasoncode)
{
struct wifi_station *station = (struct wifi_station *)
(((char *)w) - offsetof(struct wifi_station, timeout));
int responselength;
struct ieee80211_disassociation_params ieee80211_params;
/* Free station into hash callback function */
wifi_station_clean(station);
capwap_hash_delete(g_wifiglobal.stations, station->address);
/* Create disassociation packet */
memset(&ieee80211_params, 0, sizeof(struct ieee80211_disassociation_params));
memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN);
memcpy(ieee80211_params.station, station, ETH_ALEN);
ieee80211_params.reasoncode = reasoncode;
responselength = ieee80211_create_disassociation(g_bufferIEEE80211,
sizeof(g_bufferIEEE80211),
&ieee80211_params);
if (responselength < 0) {
log_printf(LOG_WARNING, "Unable to create IEEE802.11 Disassociation "
"to " MACSTR " station", MAC2STR(station));
return;
}
if (wlan_sendframe(wlan, g_bufferIEEE80211, responselength,
wlan->device->currentfrequency.frequency,
0, 0, 0, 0)) {
log_printf(LOG_WARNING, "Unable to send IEEE802.11 Disassociation "
"to " MACSTR " station", MAC2STR(station));
return;
}
log_printf(LOG_INFO, "Sent IEEE802.11 Disassociation to " MACSTR " station",
MAC2STR(station));
/* Forward the station disassociation also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0);
}
static void wifi_station_timeout_deauth(EV_P_ ev_timer *w, int revents)
/* */
static void wifi_wlan_disassociate_station(struct wifi_wlan* wlan,
struct wifi_station* station,
uint16_t reasoncode)
{
ASSERT(wlan != NULL);
ASSERT(station != NULL);
/* Send deauthentication message */
if (station->flags & WIFI_STATION_FLAGS_ASSOCIATE)
wifi_wlan_send_mgmt_disassociation(wlan, station->address, reasoncode);
}
/* */
static void wifi_wlan_poll_station(struct wifi_wlan* wlan,
struct wifi_station* station)
{
ASSERT(wlan != NULL);
ASSERT(station != NULL);
wlan_poll_station(wlan, station->address, station->flags & WIFI_STATION_FLAGS_WMM);
}
/* */
static void wifi_station_timeout(EV_P_ ev_timer *w, int revents)
{
struct wifi_station *station = (struct wifi_station *)
(((char *)w) - offsetof(struct wifi_station, timeout));
struct wifi_wlan* wlan = (struct wifi_wlan *)w->data;
unsigned long repeat = 0;
log_printf(LOG_WARNING, "The " MACSTR " station has not completed the association in time",
MAC2STR(station->address));
wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID);
log_printf(LOG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_action=%d",
wlan->virtname, __func__, MAC2STR(station->address), station->flags,
station->timeout_action);
if (station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_DELETE) {
/* Free station into hash callback function */
wifi_station_clean(station);
capwap_hash_delete(g_wifiglobal.stations, station->address);
return;
}
if ((station->flags & WIFI_STATION_FLAGS_ASSOCIATE) &&
station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC) {
int inactive_sec;
inactive_sec = station_get_inact_sec(wlan, station->address);
log_printf(LOG_WARNING, "Station " MACSTR ", inactive for %d seconds",
MAC2STR(station->address), inactive_sec);
if (inactive_sec == -1) {
log_printf(LOG_DEBUG, "Check inactivity: Could not get station info "
"from kernel driver for " MACSTR, MAC2STR(station->address));
repeat = station->max_inactivity;
} else if (inactive_sec == -ENOENT) {
log_printf(LOG_DEBUG, "Station " MACSTR " has lost its driver entry",
MAC2STR(station->address));
/* Avoid sending client probe on removed client */
station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE;
goto skip_poll;
} else if (inactive_sec < station->max_inactivity) {
/* station activity detected; reset timeout state */
log_printf(LOG_DEBUG, "Station " MACSTR " has been active %is ago",
MAC2STR(station->address), inactive_sec);
station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC;
repeat = station->max_inactivity - inactive_sec;
log_printf(LOG_DEBUG, "Station " MACSTR " has been inactive for: %d sec, max allowed: %d",
MAC2STR(station->address), inactive_sec, station->max_inactivity);
} else {
log_printf(LOG_DEBUG, "Station " MACSTR " has been inactive too "
"long: %d sec, max allowed: %d",
MAC2STR(station->address), inactive_sec, station->max_inactivity);
}
}
if ((station->flags & WIFI_STATION_FLAGS_ASSOCIATE) &&
station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE &&
!(station->flags & WIFI_STATION_FLAGS_POLL_PENDING)) {
log_printf(LOG_DEBUG, "Station " MACSTR " has ACKed data poll",
MAC2STR(station->address));
/* data nullfunc frame poll did not produce TX errors; assume
* station ACKed it */
station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC;
repeat = station->max_inactivity;
}
skip_poll:
if (repeat) {
log_printf(LOG_DEBUG, "%s: register wifi_station_timeout for " MACSTR " (%lu seconds)",
__func__, MAC2STR(station->address), repeat);
w->repeat = repeat;
ev_timer_again(EV_A_ w);
return;
}
if ((station->flags & WIFI_STATION_FLAGS_ASSOCIATE) &&
station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC) {
log_printf(LOG_DEBUG, " Polling STA");
station->flags |= WIFI_STATION_FLAGS_POLL_PENDING;
wifi_wlan_poll_station(wlan, station);
} else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) {
/* everything else means we go to remove the Station */
int deauth = station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE;
log_printf(LOG_DEBUG, "Timeout, sending %s info to STA " MACSTR,
deauth ? "deauthentication" : "disassociation", MAC2STR(station->address));
if (deauth) {
wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID);
} else {
uint16_t reason =
(station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE) ?
IEEE80211_REASON_DISASSOC_DUE_TO_INACTIVITY :
IEEE80211_REASON_PREV_AUTH_NOT_VALID;
wifi_wlan_disassociate_station(wlan, station, reason);
}
} else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT &&
station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE) {
/*
* TODO: tell the AC about the STA timeout with a WTP Event
*/
}
switch (station->timeout_action) {
case WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC:
station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE;
w->repeat = WIFI_STATION_TIMEOUT_BEFORE_DISASSOCIATE / 1000.0;
log_printf(LOG_DEBUG, "%s: register ap_handle_timer timeout for " MACSTR
" (%f seconds - TIMEOUT_BEFORE_DISASSOCIATE)",
__func__, MAC2STR(station->address), w->repeat);
ev_timer_again(EV_A_ w);
break;
case WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE:
station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE;
w->repeat = WIFI_STATION_TIMEOUT_BEFORE_DEAUTHENTICATE / 1000.0;
log_printf(LOG_DEBUG, "%s: register ap_handle_timer timeout for " MACSTR
" (%f seconds - TIMEOUT_BEFORE_DEAUTHENTICATE)",
__func__, MAC2STR(station->address), w->repeat);
ev_timer_again(EV_A_ w);
break;
case WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE:
log_printf(LOG_DEBUG, MACSTR " deauthenticated due to inactivity (timer DEAUTH/REMOVE)",
MAC2STR(station->address));
break;
default:
break;
}
}
/* */
void wifi_wlan_client_probe_event(struct wifi_wlan *wlan, const uint8_t *address)
{
struct wifi_station* station;
station = wifi_station_get(wlan, address);
if (!station)
return;
if (!(station->flags & WIFI_STATION_FLAGS_POLL_PENDING))
return;
log_printf(LOG_DEBUG, "STA " MACSTR " ACKed pending "
"activity poll", MAC2STR(station->address));
station->flags &= ~WIFI_STATION_FLAGS_POLL_PENDING;
}
/* */
@ -738,9 +935,10 @@ wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan,
if (station) {
/* A station is removed if the association does not complete within a given period of time */
ev_timer_stop(EV_DEFAULT_UC_ &station->timeout);
ev_timer_init(&station->timeout, wifi_station_timeout_deauth,
ev_timer_init(&station->timeout, wifi_station_timeout,
WIFI_STATION_TIMEOUT_ASSOCIATION_COMPLETE / 1000.0, 0.);
station->timeout.data = wlan;
station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE;
ev_timer_start(EV_DEFAULT_UC_ &station->timeout);
responsestatuscode = IEEE80211_STATUS_SUCCESS;
} else {
@ -2150,16 +2348,19 @@ int wifi_station_authorize(struct wifi_wlan* wlan,
station->flags |= WIFI_STATION_FLAGS_HT_CAP;
}
/* Stop authorization timeout */
ev_timer_stop(EV_DEFAULT_UC_ &station->timeout);
station->max_inactivity = params->max_inactivity;
/* Station authorized */
result = station_authorize(wlan, station);
if (result)
if (result) {
wifi_wlan_deauthentication_station(wlan, station,
IEEE80211_REASON_PREV_AUTH_NOT_VALID);
return result;
}
return result;
/* let the timer expire, but set the action to SEND NULLFUNC */
station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC;
return 0;
}
/* */

View File

@ -128,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 */
@ -162,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;
@ -187,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;
@ -325,22 +333,21 @@ struct wifi_wlan {
};
/* Station handle */
#define WIFI_STATION_FLAGS_AUTHENTICATED 0x00000001
#define WIFI_STATION_FLAGS_ASSOCIATE 0x00000002
#define WIFI_STATION_FLAGS_NON_ERP 0x00000004
#define WIFI_STATION_FLAGS_NO_SHORT_SLOT_TIME 0x00000008
#define WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE 0x00000010
#define WIFI_STATION_FLAGS_WMM 0x00000020
#define WIFI_STATION_FLAGS_AUTHORIZED 0x00000040
#define WIFI_STATION_FLAGS_HT_CAP 0x00000080
#define WIFI_STATION_FLAGS_AUTHENTICATED 0x00000001
#define WIFI_STATION_FLAGS_ASSOCIATE 0x00000002
#define WIFI_STATION_FLAGS_NON_ERP 0x00000004
#define WIFI_STATION_FLAGS_NO_SHORT_SLOT_TIME 0x00000008
#define WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE 0x00000010
#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_ASSOCIATION_COMPLETE 30000
#define WIFI_STATION_TIMEOUT_AFTER_DEAUTHENTICATED 5000
#define WIFI_STATION_TIMEOUT_BEFORE_DISASSOCIATE 3000
#define WIFI_STATION_TIMEOUT_BEFORE_DEAUTHENTICATE 1000
struct wifi_station {
uint8_t address[MACADDRESS_EUI48_LENGTH];
@ -349,9 +356,16 @@ struct wifi_station {
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,6 +408,7 @@ 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 */
@ -430,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);

View File

@ -520,6 +520,16 @@ static int nl80211_device_changefrequency(struct wifi_device* device, struct wif
return result;
}
/* */
static void nl80211_wlan_client_probe_event(struct wifi_wlan* wlan,
struct nlattr** tb_msg)
{
if (!tb_msg[NL80211_ATTR_MAC] || !tb_msg[NL80211_ATTR_ACK])
return;
wifi_wlan_client_probe_event(wlan, nla_data(tb_msg[NL80211_ATTR_MAC]));
}
/* */
static int nl80211_wlan_event(struct wifi_wlan* wlan,
struct genlmsghdr* gnlh,
@ -574,6 +584,10 @@ static int nl80211_wlan_event(struct wifi_wlan* wlan,
case NL80211_CMD_DEL_STATION:
break;
case NL80211_CMD_PROBE_CLIENT:
nl80211_wlan_client_probe_event(wlan, tb_msg);
break;
default:
log_printf(LOG_DEBUG, "*** nl80211_wlan_event: %s (%d)",
nl80211_command_to_string((int)gnlh->cmd), (int)gnlh->cmd);
@ -709,6 +723,12 @@ static wifi_wlan_handle nl80211_wlan_create(struct wifi_device* device, struct w
ASSERT(device->handle != NULL);
ASSERT(wlan != NULL);
if (!wlan->device->capability->supp_cmds.poll_command_supported) {
log_printf(LOG_CRIT, "unable to run nl80211 WTP on device %s without "
"probe_client command support", wlan->device->phyname);
return NULL;
}
/* */
msg = nlmsg_alloc();
if (!msg ||
@ -1054,7 +1074,13 @@ static int cb_wlan_send_frame(struct nl_msg* msg, void* arg) {
}
/* */
static int nl80211_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) {
static int
nl80211_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 result;
uint64_t cookie;
struct nl_msg* msg;
@ -1066,6 +1092,11 @@ static int nl80211_wlan_sendframe(struct wifi_wlan* wlan, uint8_t* frame, int le
ASSERT(frame != NULL);
ASSERT(length > 0);
log_printf(LOG_DEBUG, "nl80211: CMD_FRAME frequency=%u duration=%u no_cck=%d "
"no_ack=%d offchanok=%d",
frequency, duration, no_cck_rate, no_wait_ack, offchannel_tx_ok);
log_hexdump(LOG_DEBUG, "CMD_FRAME", frame, length);
/* */
msg = nl80211_wlan_msg(wlan, 0, NL80211_CMD_FRAME);
if (!msg)
@ -1106,6 +1137,79 @@ out_err:
return -1;
}
#if 0
/* Sending non-Mgmt Frames via nl80211_wlan_sendframe does not work,
disable this till the WTP kernel mode supports frame injection from userspace */
/* Send data frame to poll STA and check whether this frame is ACKed */
static void nl80211_wlan_send_null_frame(struct wifi_wlan* wlan, const uint8_t* address, int qos)
{
struct {
struct ieee80211_header hdr;
uint16_t qos_ctl;
} STRUCT_PACKED nulldata;
size_t size;
memset(&nulldata, 0, sizeof(nulldata));
if (qos) {
nulldata.hdr.framecontrol =
IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_DATA,
IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSNULL);
size = sizeof(nulldata);
} else {
nulldata.hdr.framecontrol =
IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_DATA,
IEEE80211_FRAMECONTROL_DATA_SUBTYPE_NULL);
size = sizeof(struct ieee80211_header);
}
nulldata.hdr.framecontrol |= __cpu_to_le16(IEEE80211_FRAME_CONTROL_MASK_FROMDS);
memcpy(nulldata.hdr.address1, address, ETH_ALEN);
memcpy(nulldata.hdr.address2, wlan->address, ETH_ALEN);
memcpy(nulldata.hdr.address3, wlan->address, ETH_ALEN);
if (nl80211_wlan_sendframe(wlan, (uint8_t *)&nulldata, size,
wlan->device->currentfrequency.frequency,
0, 0, 0, 0))
log_printf(LOG_DEBUG, "nl80211_send_null_frame: Failed to send poll frame");
}
#endif
/* */
static void nl80211_wlan_poll_station(struct wifi_wlan* wlan, const uint8_t* address, int qos)
{
int result;
struct nl_msg* msg;
ASSERT(wlan != NULL);
ASSERT(wlan->handle != NULL);
ASSERT(address != NULL);
#if 0 /* see nl80211_wlan_send_null_frame for explanation */
if (!wlan->device->capability->supp_cmds.poll_command_supported) {
nl80211_wlan_send_null_frame(wlan, address, qos);
return;
}
#endif
/* */
msg = nl80211_wlan_msg(wlan, 0, NL80211_CMD_PROBE_CLIENT);
if (!msg ||
nla_put(msg, NL80211_ATTR_MAC, MACADDRESS_EUI48_LENGTH, address)) {
nlmsg_free(msg);
return;
}
/* */
result = nl80211_wlan_send_and_recv_msg(wlan, msg, NULL, NULL);
if (result < 0)
log_printf(LOG_DEBUG, "nl80211: Client probe request for "
MACSTR " failed: ret=%d (%s)",
MAC2STR(address), result, strerror(-result));
}
/* */
static void nl80211_wlan_delete(struct wifi_wlan* wlan) {
struct nl80211_wlan_handle* wlanhandle;
@ -1486,6 +1590,24 @@ static void phydevice_capability_feature_flags(struct wifi_capability *capabilit
}
}
static void phydevice_capability_supp_cmds(struct wifi_commands_capability *cmd_cap,
struct nlattr *tb)
{
int i;
struct nlattr *nl_cmd;
if (tb == NULL)
return;
nla_for_each_nested(nl_cmd, tb, i) {
switch (nla_get_u32(nl_cmd)) {
case NL80211_CMD_PROBE_CLIENT:
cmd_cap->poll_command_supported = 1;
break;
}
}
}
static void phydevice_capability_cipher_suites(struct wifi_capability *capability,
struct nlattr *tb)
{
@ -1775,6 +1897,9 @@ static int cb_get_phydevice_capability(struct nl_msg* msg, void* data)
phydevice_capability_feature_flags(capability, tb_msg[NL80211_ATTR_FEATURE_FLAGS]);
/* Commands supported */
phydevice_capability_supp_cmds(&capability->supp_cmds, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]);
/* Cipher supported */
phydevice_capability_cipher_suites(capability, tb_msg[NL80211_ATTR_CIPHER_SUITES]);
@ -2155,6 +2280,7 @@ const struct wifi_driver_ops wifi_driver_nl80211_ops = {
.wlan_startap = nl80211_wlan_startap,
.wlan_stopap = nl80211_wlan_stopap,
.wlan_sendframe = nl80211_wlan_sendframe,
.wlan_poll_station = nl80211_wlan_poll_station,
.wlan_delete = nl80211_wlan_delete,
.station_authorize = nl80211_station_authorize,

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,8 @@ struct wtp_t {
struct capwap_statisticstimer_element statisticstimer;
struct capwap_wtprebootstat_element rebootstat;
int sta_max_inactivity;
/* */
unsigned short fragmentid;
struct capwap_packet_rxmng* rxmngpacket;

View File

@ -805,6 +805,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);