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:
Jouni Malinen 2012-12-16 19:16:17 +02:00
parent ad3872a372
commit c79938a584
7 changed files with 78 additions and 37 deletions

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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,

View file

@ -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 */

View file

@ -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;
} }

View file

@ -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 */