]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WNM: Enable WNM-Sleep Mode configuration with hostapd SME/MLME
authorJouni Malinen <j@w1.fi>
Sun, 16 Dec 2012 17:16:17 +0000 (19:16 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 16 Dec 2012 17:16:17 +0000 (19:16 +0200)
This allows hostapd to process WNM-Sleep Mode Request when using the
internal SME/MLME.

Signed-hostap: Jouni Malinen <j@w1.fi>

hostapd/config_file.c
hostapd/hostapd.conf
src/ap/ap_config.h
src/ap/ieee802_11.c
src/ap/ieee802_11_shared.c
src/ap/wnm_ap.c
src/ap/wnm_ap.h

index 8af8157a762a45f9bb1446066d7e027a10d9390e..70a114db6c7716d3fca03e1dae71e5092accc790 100644 (file)
@@ -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);
index c839ad0ca5d64f6bb34effe59564be87e620c579..ad81f06e38601883c2b608c74c0067f00ea271be 100644 (file)
@@ -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
index 71313c02379a203aeecc7dfd7b9e8cba5003b5e8..ec6db3a6e8ff55a30bfdddb0a1241ec8450c2e04 100644 (file)
@@ -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;
index a13a135e0f2639f1349fd299dc9af72093062896..51c8d286d86875e4938dea6e0e849a32d537e058 100644 (file)
@@ -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,
index b3fdf3d6e5fa9efc4a9c3ea4020bd2cdb2827e94..9d07d651601032c6aeab8b9df29eb76fc5d1653c 100644 (file)
@@ -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 */
index 01fe135543c6772f562cc2a20184187c29ce628d..9fa31bb2144ccda856165b4791562d3739beb2a0 100644 (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,
                                       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;
 }
index ab7c4f1c202a83b0a771e4c03acbd786e445964b..f05726ee74d172a1d8f34ef218443dbeb642f9ed 100644 (file)
@@ -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 */