WNM: Additional BSS Transition Management capability
Add some more functionality for BSS Transition Management: - advertise support for BSS Transition Management in extended capabilities element - add hostapd.conf parameter bss_transition=1 for enabling support for BSS Transition Management - add "hostapd_cli disassoc_imminent <STA> <num TBTTs>" for sending disassociation imminent notifications for testing purposes - wpa_supplicant: trigger a new scan to find another BSS if the current AP indicates disassociation imminent (TODO: the old AP needs to be marked to use lower priority to avoid re-selecting it) Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
03e47c9c3a
commit
2049a875bc
10 changed files with 207 additions and 24 deletions
|
@ -2721,8 +2721,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
|||
bss->time_zone = os_strdup(pos);
|
||||
if (bss->time_zone == NULL)
|
||||
errors++;
|
||||
#ifdef CONFIG_WNM
|
||||
} else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
|
||||
bss->wnm_sleep_mode = atoi(pos);
|
||||
} else if (os_strcmp(buf, "bss_transition") == 0) {
|
||||
bss->bss_transition = atoi(pos);
|
||||
#endif /* CONFIG_WNM */
|
||||
#ifdef CONFIG_INTERWORKING
|
||||
} else if (os_strcmp(buf, "interworking") == 0) {
|
||||
bss->interworking = atoi(pos);
|
||||
|
|
|
@ -436,6 +436,50 @@ static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
|
|||
#endif /* CONFIG_WPS */
|
||||
|
||||
|
||||
#ifdef CONFIG_WNM
|
||||
|
||||
static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
|
||||
const char *cmd)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 buf[1000], *pos;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
int disassoc_timer;
|
||||
|
||||
if (hwaddr_aton(cmd, addr))
|
||||
return -1;
|
||||
if (cmd[17] != ' ')
|
||||
return -1;
|
||||
disassoc_timer = atoi(cmd + 17);
|
||||
|
||||
os_memset(buf, 0, sizeof(buf));
|
||||
mgmt = (struct ieee80211_mgmt *) buf;
|
||||
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(mgmt->da, addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
|
||||
mgmt->u.action.category = WLAN_ACTION_WNM;
|
||||
mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
|
||||
mgmt->u.action.u.bss_tm_req.dialog_token = 1;
|
||||
mgmt->u.action.u.bss_tm_req.req_mode =
|
||||
WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
|
||||
mgmt->u.action.u.bss_tm_req.disassoc_timer =
|
||||
host_to_le16(disassoc_timer);
|
||||
mgmt->u.action.u.bss_tm_req.validity_interval = 0;
|
||||
|
||||
pos = mgmt->u.action.u.bss_tm_req.variable;
|
||||
|
||||
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
|
||||
"Management Request frame");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
|
||||
const char *cmd)
|
||||
{
|
||||
|
@ -486,6 +530,8 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_WNM */
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
|
||||
char *buf, size_t buflen)
|
||||
|
@ -906,9 +952,14 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
|
|||
hapd, buf + 14, reply, reply_size);
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
#endif /* CONFIG_WPS */
|
||||
#ifdef CONFIG_WNM
|
||||
} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
|
||||
if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
|
||||
reply_len = -1;
|
||||
} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
|
||||
if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
|
||||
reply_len = -1;
|
||||
#endif /* CONFIG_WNM */
|
||||
} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
|
||||
reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
|
||||
reply_size);
|
||||
|
|
|
@ -1310,6 +1310,11 @@ own_ip_addr=127.0.0.1
|
|||
# 1 = enabled (allow stations to use WNM-Sleep Mode)
|
||||
#wnm_sleep_mode=1
|
||||
|
||||
# BSS Transition Management
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#bss_transition=1
|
||||
|
||||
##### IEEE 802.11u-2011 #######################################################
|
||||
|
||||
# Enable Interworking service
|
||||
|
|
|
@ -539,6 +539,26 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
|
|||
#endif /* CONFIG_WPS */
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char buf[300];
|
||||
int res;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Invalid 'disassoc_imminent' command - two arguments "
|
||||
"(STA addr and Disassociation Timer) are needed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
|
||||
argv[0], argv[1]);
|
||||
if (res < 0 || res >= (int) sizeof(buf))
|
||||
return -1;
|
||||
return wpa_ctrl_command(ctrl, buf);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
|
@ -775,6 +795,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
|||
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
|
||||
{ "wps_config", hostapd_cli_cmd_wps_config },
|
||||
#endif /* CONFIG_WPS */
|
||||
{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
|
||||
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
|
||||
{ "get_config", hostapd_cli_cmd_get_config },
|
||||
{ "help", hostapd_cli_cmd_help },
|
||||
|
|
|
@ -392,6 +392,7 @@ struct hostapd_bss_config {
|
|||
int time_advertisement;
|
||||
char *time_zone;
|
||||
int wnm_sleep_mode;
|
||||
int bss_transition;
|
||||
|
||||
/* IEEE 802.11u - Interworking */
|
||||
int interworking;
|
||||
|
|
|
@ -192,6 +192,8 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
|||
*pos = 0x00;
|
||||
if (hapd->conf->wnm_sleep_mode)
|
||||
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
|
||||
if (hapd->conf->bss_transition)
|
||||
*pos |= 0x08; /* Bit 19 - BSS Transition */
|
||||
pos++;
|
||||
|
||||
if (len < 4)
|
||||
|
|
|
@ -250,6 +250,15 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
|||
return -1;
|
||||
|
||||
switch (action->data[0]) {
|
||||
case WNM_BSS_TRANS_MGMT_QUERY:
|
||||
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query");
|
||||
/* TODO */
|
||||
return -1;
|
||||
case WNM_BSS_TRANS_MGMT_RESP:
|
||||
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
|
||||
"Response");
|
||||
/* TODO */
|
||||
return -1;
|
||||
case WNM_SLEEP_MODE_REQ:
|
||||
ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
|
||||
action->len - 1);
|
||||
|
|
|
@ -538,6 +538,16 @@ struct ieee80211_mgmt {
|
|||
* Entries */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED bss_tm_req;
|
||||
struct {
|
||||
u8 action; /* 8 */
|
||||
u8 dialog_token;
|
||||
u8 status_code;
|
||||
u8 bss_termination_delay;
|
||||
/* Target BSSID (optional),
|
||||
* BSS Transition Candidate List
|
||||
* Entries (optional) */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED bss_tm_resp;
|
||||
} u;
|
||||
} STRUCT_PACKED action;
|
||||
} u;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "rsn_supp/wpa.h"
|
||||
#include "wpa_supplicant_i.h"
|
||||
#include "driver_i.h"
|
||||
#include "scan.h"
|
||||
|
||||
#define MAX_TFS_IE_LEN 1024
|
||||
|
||||
|
@ -293,11 +294,104 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
|
|||
}
|
||||
|
||||
|
||||
static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
|
||||
u8 dialog_token, u8 status,
|
||||
u8 delay, const u8 *target_bssid)
|
||||
{
|
||||
u8 buf[1000], *pos;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
size_t len;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response "
|
||||
"to " MACSTR " dialog_token=%u status=%u delay=%d",
|
||||
MAC2STR(wpa_s->bssid), dialog_token, status, delay);
|
||||
|
||||
mgmt = (struct ieee80211_mgmt *) buf;
|
||||
os_memset(&buf, 0, sizeof(buf));
|
||||
os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
|
||||
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
mgmt->u.action.category = WLAN_ACTION_WNM;
|
||||
mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP;
|
||||
mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token;
|
||||
mgmt->u.action.u.bss_tm_resp.status_code = status;
|
||||
mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay;
|
||||
pos = mgmt->u.action.u.bss_tm_resp.variable;
|
||||
if (target_bssid) {
|
||||
os_memcpy(pos, target_bssid, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
}
|
||||
|
||||
len = pos - (u8 *) &mgmt->u.action.category;
|
||||
|
||||
wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
|
||||
wpa_s->own_addr, wpa_s->bssid,
|
||||
&mgmt->u.action.category, len, 0);
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
|
||||
const u8 *pos, const u8 *end,
|
||||
int reply)
|
||||
{
|
||||
u8 dialog_token;
|
||||
u8 mode;
|
||||
u16 disassoc_timer;
|
||||
|
||||
if (pos + 5 > end)
|
||||
return;
|
||||
|
||||
dialog_token = pos[0];
|
||||
mode = pos[1];
|
||||
disassoc_timer = WPA_GET_LE16(pos + 2);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
|
||||
"dialog_token=%u request_mode=0x%x "
|
||||
"disassoc_timer=%u validity_interval=%u",
|
||||
dialog_token, mode, disassoc_timer, pos[4]);
|
||||
pos += 5;
|
||||
if (mode & 0x08)
|
||||
pos += 12; /* BSS Termination Duration */
|
||||
if (mode & 0x10) {
|
||||
char url[256];
|
||||
if (pos + 1 > end || pos + 1 + pos[0] > end) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
|
||||
"Management Request (URL)");
|
||||
return;
|
||||
}
|
||||
os_memcpy(url, pos + 1, pos[0]);
|
||||
url[pos[0]] = '\0';
|
||||
wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation Imminent - "
|
||||
"session_info_url=%s", url);
|
||||
}
|
||||
|
||||
if (mode & 0x04) {
|
||||
wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
|
||||
"Disassociation Timer %u", disassoc_timer);
|
||||
if (disassoc_timer && !wpa_s->scanning) {
|
||||
/* TODO: mark current BSS less preferred for
|
||||
* selection */
|
||||
wpa_printf(MSG_DEBUG, "Trying to find another BSS");
|
||||
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (reply) {
|
||||
/* TODO: add support for reporting Accept */
|
||||
wnm_send_bss_transition_mgmt_resp(wpa_s, dialog_token,
|
||||
1 /* Reject - unspecified */,
|
||||
0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
|
||||
struct rx_action *action)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
u8 act, mode;
|
||||
u8 act;
|
||||
|
||||
if (action->data == NULL || action->len == 0)
|
||||
return;
|
||||
|
@ -308,32 +402,17 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
|
|||
|
||||
wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
|
||||
act, MAC2STR(action->sa));
|
||||
if (wpa_s->wpa_state < WPA_ASSOCIATED ||
|
||||
os_memcmp(action->sa, wpa_s->bssid, ETH_ALEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
|
||||
"frame");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (act) {
|
||||
case WNM_BSS_TRANS_MGMT_REQ:
|
||||
if (pos + 5 > end)
|
||||
break;
|
||||
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
|
||||
"Request: dialog_token=%u request_mode=0x%x "
|
||||
"disassoc_timer=%u validity_interval=%u",
|
||||
pos[0], pos[1], WPA_GET_LE16(pos + 2), pos[4]);
|
||||
mode = pos[1];
|
||||
pos += 5;
|
||||
if (mode & 0x08)
|
||||
pos += 12; /* BSS Termination Duration */
|
||||
if (mode & 0x10) {
|
||||
char url[256];
|
||||
if (pos + 1 > end || pos + 1 + pos[0] > end) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS "
|
||||
"Transition Management Request "
|
||||
"(URL)");
|
||||
break;
|
||||
}
|
||||
os_memcpy(url, pos + 1, pos[0]);
|
||||
url[pos[0]] = '\0';
|
||||
wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation "
|
||||
"Imminent - session_info_url=%s", url);
|
||||
}
|
||||
ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
|
||||
!(action->da[0] & 0x01));
|
||||
break;
|
||||
case WNM_SLEEP_MODE_RESP:
|
||||
ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len);
|
||||
|
|
|
@ -1242,6 +1242,7 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
|
|||
|
||||
#ifdef CONFIG_WNM
|
||||
ext_capab |= BIT(17); /* WNM-Sleep Mode */
|
||||
ext_capab |= BIT(19); /* BSS Transition */
|
||||
#endif /* CONFIG_WNM */
|
||||
|
||||
if (!ext_capab)
|
||||
|
|
Loading…
Reference in a new issue