From c79938a5840091179a9d893a9b0362a34abdad55 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 16 Dec 2012 19:16:17 +0200 Subject: [PATCH] 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 --- hostapd/config_file.c | 2 ++ hostapd/hostapd.conf | 5 ++++ src/ap/ap_config.h | 1 + src/ap/ieee802_11.c | 47 ++++++++++++++++++++++++++++---------- src/ap/ieee802_11_shared.c | 10 +++++++- src/ap/wnm_ap.c | 46 +++++++++++++++++++------------------ src/ap/wnm_ap.h | 4 ++-- 7 files changed, 78 insertions(+), 37 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 8af8157a7..70a114db6 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -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); diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index c839ad0ca..ad81f06e3 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -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 diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 71313c023..ec6db3a6e 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -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; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index a13a135e0..51c8d286d 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -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, diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c index b3fdf3d6e..9d07d6516 100644 --- a/src/ap/ieee802_11_shared.c +++ b/src/ap/ieee802_11_shared.c @@ -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 */ diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c index 01fe13554..9fa31bb21 100644 --- a/src/ap/wnm_ap.c +++ b/src/ap/wnm_ap.c @@ -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; } diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h index ab7c4f1c2..f05726ee7 100644 --- a/src/ap/wnm_ap.h +++ b/src/ap/wnm_ap.h @@ -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 */