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);
|
||||
if (bss->time_zone == NULL)
|
||||
errors++;
|
||||
} else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
|
||||
bss->wnm_sleep_mode = atoi(pos);
|
||||
#ifdef CONFIG_INTERWORKING
|
||||
} else if (os_strcmp(buf, "interworking") == 0) {
|
||||
bss->interworking = atoi(pos);
|
||||
|
|
|
@ -1300,6 +1300,11 @@ own_ip_addr=127.0.0.1
|
|||
# stdoffset[dst[offset][,start[/time],end[/time]]]
|
||||
#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 #######################################################
|
||||
|
||||
# Enable Interworking service
|
||||
|
|
|
@ -390,6 +390,7 @@ struct hostapd_bss_config {
|
|||
/* IEEE 802.11v */
|
||||
int time_advertisement;
|
||||
char *time_zone;
|
||||
int wnm_sleep_mode;
|
||||
|
||||
/* IEEE 802.11u - Interworking */
|
||||
int interworking;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "ap_mlme.h"
|
||||
#include "p2p_hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "wnm_ap.h"
|
||||
#include "ieee802_11.h"
|
||||
|
||||
|
||||
|
@ -1434,13 +1435,32 @@ static int robust_action_frame(u8 category)
|
|||
#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,
|
||||
const struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
|
||||
struct sta_info *sta;
|
||||
sta = ap_get_sta(hapd, mgmt->sa);
|
||||
#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
|
||||
|
||||
if (len < IEEE80211_HDRLEN + 1) {
|
||||
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
|
||||
|
@ -1450,6 +1470,14 @@ static void handle_action(struct hostapd_data *hapd,
|
|||
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
|
||||
if (sta && (sta->flags & WLAN_STA_MFP) &&
|
||||
!(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) {
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
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,
|
||||
len - IEEE80211_HDRLEN))
|
||||
break;
|
||||
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
case WLAN_ACTION_WMM:
|
||||
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);
|
||||
return;
|
||||
#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:
|
||||
if (hapd->public_action_cb) {
|
||||
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;
|
||||
if (len < 4 && hapd->conf->interworking)
|
||||
len = 4;
|
||||
if (len < 3 && hapd->conf->wnm_sleep_mode)
|
||||
len = 3;
|
||||
if (len == 0)
|
||||
return eid;
|
||||
|
||||
|
@ -180,8 +182,14 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
|||
*pos++ = len;
|
||||
*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;
|
||||
if (hapd->conf->time_advertisement == 2)
|
||||
*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,
|
||||
const u8 *addr, const u8 *frm, int len)
|
||||
{
|
||||
/*
|
||||
* Action [1] | Dialog Token [1] | WNM-Sleep Mode IE |
|
||||
* TFS Response IE
|
||||
*/
|
||||
u8 *pos = (u8 *) frm; /* point to action field */
|
||||
u8 dialog_token = pos[1];
|
||||
/* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
|
||||
const u8 *pos = frm;
|
||||
u8 dialog_token;
|
||||
struct wnm_sleep_element *wnmsleep_ie = NULL;
|
||||
/* multiple TFS Req IE (assuming consecutive) */
|
||||
u8 *tfsreq_ie_start = NULL;
|
||||
u8 *tfsreq_ie_end = NULL;
|
||||
u16 tfsreq_ie_len = 0;
|
||||
|
||||
pos += 1 + 1;
|
||||
while (pos - frm < len - 1) {
|
||||
u8 ie_len = *(pos+1);
|
||||
dialog_token = *pos++;
|
||||
while (pos + 1 < frm + len) {
|
||||
u8 ie_len = pos[1];
|
||||
if (pos + 2 + ie_len > frm + len)
|
||||
break;
|
||||
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) {
|
||||
if (!tfsreq_ie_start)
|
||||
tfsreq_ie_start = pos;
|
||||
tfsreq_ie_end = pos;
|
||||
tfsreq_ie_start = (u8 *) pos;
|
||||
tfsreq_ie_end = (u8 *) pos;
|
||||
} else
|
||||
wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
|
||||
wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
|
||||
*pos);
|
||||
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,
|
||||
struct rx_action *action)
|
||||
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
||||
struct rx_action *action)
|
||||
{
|
||||
u8 *pos = (u8 *) action->data + 1; /* point to the action field */
|
||||
u8 act = *pos;
|
||||
if (action->len < 1 || action->data == NULL)
|
||||
return -1;
|
||||
|
||||
switch (act) {
|
||||
switch (action->data[0]) {
|
||||
case WNM_SLEEP_MODE_REQ:
|
||||
ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
|
||||
action->len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
action->len - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
void ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
||||
struct rx_action *action);
|
||||
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
||||
struct rx_action *action);
|
||||
|
||||
#endif /* WNM_AP_H */
|
||||
|
|
Loading…
Reference in a new issue