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);
# 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
/* IEEE 802.11v */
int time_advertisement;
char *time_zone;
+ int wnm_sleep_mode;
/* IEEE 802.11u - Interworking */
int interworking;
#include "ap_mlme.h"
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
+#include "wnm_ap.h"
#include "ieee802_11.h"
#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,
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) &&
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);
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,
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;
*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 */
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;
}
}
-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;
}
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 */