WNM: Enable WNM-Sleep Mode configuration with hostapd SME/MLME
This allows hostapd to process WNM-Sleep Mode Request when using the internal SME/MLME. Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
ad3872a372
commit
c79938a584
7 changed files with 78 additions and 37 deletions
|
@ -2717,6 +2717,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
bss->time_zone = os_strdup(pos);
|
bss->time_zone = os_strdup(pos);
|
||||||
if (bss->time_zone == NULL)
|
if (bss->time_zone == NULL)
|
||||||
errors++;
|
errors++;
|
||||||
|
} else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
|
||||||
|
bss->wnm_sleep_mode = atoi(pos);
|
||||||
#ifdef CONFIG_INTERWORKING
|
#ifdef CONFIG_INTERWORKING
|
||||||
} else if (os_strcmp(buf, "interworking") == 0) {
|
} else if (os_strcmp(buf, "interworking") == 0) {
|
||||||
bss->interworking = atoi(pos);
|
bss->interworking = atoi(pos);
|
||||||
|
|
|
@ -1300,6 +1300,11 @@ own_ip_addr=127.0.0.1
|
||||||
# stdoffset[dst[offset][,start[/time],end[/time]]]
|
# stdoffset[dst[offset][,start[/time],end[/time]]]
|
||||||
#time_zone=EST5
|
#time_zone=EST5
|
||||||
|
|
||||||
|
# WNM-Sleep Mode (extended sleep mode for stations)
|
||||||
|
# 0 = disabled (default)
|
||||||
|
# 1 = enabled (allow stations to use WNM-Sleep Mode)
|
||||||
|
#wnm_sleep_mode=1
|
||||||
|
|
||||||
##### IEEE 802.11u-2011 #######################################################
|
##### IEEE 802.11u-2011 #######################################################
|
||||||
|
|
||||||
# Enable Interworking service
|
# Enable Interworking service
|
||||||
|
|
|
@ -390,6 +390,7 @@ struct hostapd_bss_config {
|
||||||
/* IEEE 802.11v */
|
/* IEEE 802.11v */
|
||||||
int time_advertisement;
|
int time_advertisement;
|
||||||
char *time_zone;
|
char *time_zone;
|
||||||
|
int wnm_sleep_mode;
|
||||||
|
|
||||||
/* IEEE 802.11u - Interworking */
|
/* IEEE 802.11u - Interworking */
|
||||||
int interworking;
|
int interworking;
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "ap_mlme.h"
|
#include "ap_mlme.h"
|
||||||
#include "p2p_hostapd.h"
|
#include "p2p_hostapd.h"
|
||||||
#include "ap_drv_ops.h"
|
#include "ap_drv_ops.h"
|
||||||
|
#include "wnm_ap.h"
|
||||||
#include "ieee802_11.h"
|
#include "ieee802_11.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1434,13 +1435,32 @@ static int robust_action_frame(u8 category)
|
||||||
#endif /* CONFIG_IEEE80211W */
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_WNM
|
||||||
|
static void hostapd_wnm_action(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
const struct ieee80211_mgmt *mgmt,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct rx_action action;
|
||||||
|
if (len < IEEE80211_HDRLEN + 2)
|
||||||
|
return;
|
||||||
|
os_memset(&action, 0, sizeof(action));
|
||||||
|
action.da = mgmt->da;
|
||||||
|
action.sa = mgmt->sa;
|
||||||
|
action.bssid = mgmt->bssid;
|
||||||
|
action.category = mgmt->u.action.category;
|
||||||
|
action.data = (const u8 *) &mgmt->u.action.u.wnm_sleep_req.action;
|
||||||
|
action.len = len - IEEE80211_HDRLEN - 1;
|
||||||
|
action.freq = hapd->iface->freq;
|
||||||
|
ieee802_11_rx_wnm_action_ap(hapd, &action);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_WNM */
|
||||||
|
|
||||||
|
|
||||||
static void handle_action(struct hostapd_data *hapd,
|
static void handle_action(struct hostapd_data *hapd,
|
||||||
const struct ieee80211_mgmt *mgmt, size_t len)
|
const struct ieee80211_mgmt *mgmt, size_t len)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
|
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
sta = ap_get_sta(hapd, mgmt->sa);
|
sta = ap_get_sta(hapd, mgmt->sa);
|
||||||
#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
|
|
||||||
|
|
||||||
if (len < IEEE80211_HDRLEN + 1) {
|
if (len < IEEE80211_HDRLEN + 1) {
|
||||||
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
|
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
@ -1450,6 +1470,14 @@ static void handle_action(struct hostapd_data *hapd,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
|
||||||
|
(sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
|
||||||
|
wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
|
||||||
|
"frame (category=%u) from unassociated STA " MACSTR,
|
||||||
|
MAC2STR(mgmt->sa), mgmt->u.action.category);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_IEEE80211W
|
#ifdef CONFIG_IEEE80211W
|
||||||
if (sta && (sta->flags & WLAN_STA_MFP) &&
|
if (sta && (sta->flags & WLAN_STA_MFP) &&
|
||||||
!(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
|
!(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
|
||||||
|
@ -1465,20 +1493,10 @@ static void handle_action(struct hostapd_data *hapd,
|
||||||
switch (mgmt->u.action.category) {
|
switch (mgmt->u.action.category) {
|
||||||
#ifdef CONFIG_IEEE80211R
|
#ifdef CONFIG_IEEE80211R
|
||||||
case WLAN_ACTION_FT:
|
case WLAN_ACTION_FT:
|
||||||
{
|
|
||||||
if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
|
|
||||||
wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action "
|
|
||||||
"frame from unassociated STA " MACSTR,
|
|
||||||
MAC2STR(mgmt->sa));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
|
if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
|
||||||
len - IEEE80211_HDRLEN))
|
len - IEEE80211_HDRLEN))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#endif /* CONFIG_IEEE80211R */
|
||||||
case WLAN_ACTION_WMM:
|
case WLAN_ACTION_WMM:
|
||||||
hostapd_wmm_action(hapd, mgmt, len);
|
hostapd_wmm_action(hapd, mgmt, len);
|
||||||
|
@ -1488,6 +1506,11 @@ static void handle_action(struct hostapd_data *hapd,
|
||||||
hostapd_sa_query_action(hapd, mgmt, len);
|
hostapd_sa_query_action(hapd, mgmt, len);
|
||||||
return;
|
return;
|
||||||
#endif /* CONFIG_IEEE80211W */
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
#ifdef CONFIG_WNM
|
||||||
|
case WLAN_ACTION_WNM:
|
||||||
|
hostapd_wnm_action(hapd, sta, mgmt, len);
|
||||||
|
return;
|
||||||
|
#endif /* CONFIG_WNM */
|
||||||
case WLAN_ACTION_PUBLIC:
|
case WLAN_ACTION_PUBLIC:
|
||||||
if (hapd->public_action_cb) {
|
if (hapd->public_action_cb) {
|
||||||
hapd->public_action_cb(hapd->public_action_cb_ctx,
|
hapd->public_action_cb(hapd->public_action_cb_ctx,
|
||||||
|
|
|
@ -173,6 +173,8 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||||
len = 5;
|
len = 5;
|
||||||
if (len < 4 && hapd->conf->interworking)
|
if (len < 4 && hapd->conf->interworking)
|
||||||
len = 4;
|
len = 4;
|
||||||
|
if (len < 3 && hapd->conf->wnm_sleep_mode)
|
||||||
|
len = 3;
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return eid;
|
return eid;
|
||||||
|
|
||||||
|
@ -180,8 +182,14 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||||
*pos++ = len;
|
*pos++ = len;
|
||||||
*pos++ = 0x00;
|
*pos++ = 0x00;
|
||||||
*pos++ = 0x00;
|
*pos++ = 0x00;
|
||||||
*pos++ = 0x00;
|
|
||||||
|
|
||||||
|
*pos = 0x00;
|
||||||
|
if (hapd->conf->wnm_sleep_mode)
|
||||||
|
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
if (len < 4)
|
||||||
|
return pos;
|
||||||
*pos = 0x00;
|
*pos = 0x00;
|
||||||
if (hapd->conf->time_advertisement == 2)
|
if (hapd->conf->time_advertisement == 2)
|
||||||
*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
|
*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
|
||||||
|
|
|
@ -183,29 +183,29 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||||
static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
|
static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
|
||||||
const u8 *addr, const u8 *frm, int len)
|
const u8 *addr, const u8 *frm, int len)
|
||||||
{
|
{
|
||||||
/*
|
/* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
|
||||||
* Action [1] | Dialog Token [1] | WNM-Sleep Mode IE |
|
const u8 *pos = frm;
|
||||||
* TFS Response IE
|
u8 dialog_token;
|
||||||
*/
|
|
||||||
u8 *pos = (u8 *) frm; /* point to action field */
|
|
||||||
u8 dialog_token = pos[1];
|
|
||||||
struct wnm_sleep_element *wnmsleep_ie = NULL;
|
struct wnm_sleep_element *wnmsleep_ie = NULL;
|
||||||
/* multiple TFS Req IE (assuming consecutive) */
|
/* multiple TFS Req IE (assuming consecutive) */
|
||||||
u8 *tfsreq_ie_start = NULL;
|
u8 *tfsreq_ie_start = NULL;
|
||||||
u8 *tfsreq_ie_end = NULL;
|
u8 *tfsreq_ie_end = NULL;
|
||||||
u16 tfsreq_ie_len = 0;
|
u16 tfsreq_ie_len = 0;
|
||||||
|
|
||||||
pos += 1 + 1;
|
dialog_token = *pos++;
|
||||||
while (pos - frm < len - 1) {
|
while (pos + 1 < frm + len) {
|
||||||
u8 ie_len = *(pos+1);
|
u8 ie_len = pos[1];
|
||||||
|
if (pos + 2 + ie_len > frm + len)
|
||||||
|
break;
|
||||||
if (*pos == WLAN_EID_WNMSLEEP)
|
if (*pos == WLAN_EID_WNMSLEEP)
|
||||||
wnmsleep_ie = (struct wnm_sleep_element *)pos;
|
wnmsleep_ie = (struct wnm_sleep_element *) pos;
|
||||||
else if (*pos == WLAN_EID_TFS_REQ) {
|
else if (*pos == WLAN_EID_TFS_REQ) {
|
||||||
if (!tfsreq_ie_start)
|
if (!tfsreq_ie_start)
|
||||||
tfsreq_ie_start = pos;
|
tfsreq_ie_start = (u8 *) pos;
|
||||||
tfsreq_ie_end = pos;
|
tfsreq_ie_end = (u8 *) pos;
|
||||||
} else
|
} else
|
||||||
wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
|
wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
|
||||||
|
*pos);
|
||||||
pos += ie_len + 2;
|
pos += ie_len + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,18 +238,20 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
||||||
struct rx_action *action)
|
struct rx_action *action)
|
||||||
{
|
{
|
||||||
u8 *pos = (u8 *) action->data + 1; /* point to the action field */
|
if (action->len < 1 || action->data == NULL)
|
||||||
u8 act = *pos;
|
return -1;
|
||||||
|
|
||||||
switch (act) {
|
switch (action->data[0]) {
|
||||||
case WNM_SLEEP_MODE_REQ:
|
case WNM_SLEEP_MODE_REQ:
|
||||||
ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
|
ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
|
||||||
action->len);
|
action->len - 1);
|
||||||
break;
|
return 0;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
|
||||||
|
action->data[0], MAC2STR(action->sa));
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
struct rx_action;
|
struct rx_action;
|
||||||
|
|
||||||
void ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
||||||
struct rx_action *action);
|
struct rx_action *action);
|
||||||
|
|
||||||
#endif /* WNM_AP_H */
|
#endif /* WNM_AP_H */
|
||||||
|
|
Loading…
Reference in a new issue