]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
OCV: Include and verify OCI in WNM-Sleep Exit frames
authorMathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
Mon, 6 Aug 2018 19:46:33 +0000 (15:46 -0400)
committerJouni Malinen <j@w1.fi>
Mon, 17 Dec 2018 13:50:12 +0000 (15:50 +0200)
Include and verify the OCI element in WNM-Sleep Exit Request and
Response frames. In case verification fails, the frame is silently
ignored.

Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
src/ap/wnm_ap.c
wpa_supplicant/wnm_sta.c

index 1e8f58b4d07eeae068e014c0264e89d10f6662bb..d9c1690eef8f98206e8799f8828d2c979805502b 100644 (file)
@@ -12,6 +12,7 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
+#include "common/ocv.h"
 #include "ap/hostapd.h"
 #include "ap/sta_info.h"
 #include "ap/ap_config.h"
@@ -54,8 +55,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
        size_t gtk_elem_len = 0;
        size_t igtk_elem_len = 0;
        struct wnm_sleep_element wnmsleep_ie;
-       u8 *wnmtfs_ie;
-       u8 wnmsleep_ie_len;
+       u8 *wnmtfs_ie, *oci_ie;
+       u8 wnmsleep_ie_len, oci_ie_len;
        u16 wnmtfs_ie_len;
        u8 *pos;
        struct sta_info *sta;
@@ -88,10 +89,42 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
                wnmtfs_ie = NULL;
        }
 
+       oci_ie = NULL;
+       oci_ie_len = 0;
+#ifdef CONFIG_OCV
+       if (action_type == WNM_SLEEP_MODE_EXIT &&
+           wpa_auth_uses_ocv(sta->wpa_sm)) {
+               struct wpa_channel_info ci;
+
+               if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+                       wpa_printf(MSG_WARNING,
+                                  "Failed to get channel info for OCI element in WNM-Sleep Mode frame");
+                       os_free(wnmtfs_ie);
+                       return -1;
+               }
+
+               oci_ie_len = OCV_OCI_EXTENDED_LEN;
+               oci_ie = os_zalloc(oci_ie_len);
+               if (!oci_ie) {
+                       wpa_printf(MSG_WARNING,
+                                  "Failed to allocate buffer for OCI element in WNM-Sleep Mode frame");
+                       os_free(wnmtfs_ie);
+                       return -1;
+               }
+
+               if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+                       os_free(wnmtfs_ie);
+                       os_free(oci_ie);
+                       return -1;
+               }
+       }
+#endif /* CONFIG_OCV */
+
 #define MAX_GTK_SUBELEM_LEN 45
 #define MAX_IGTK_SUBELEM_LEN 26
        mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
-                        MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN);
+                        MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
+                        oci_ie_len);
        if (mgmt == NULL) {
                wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
                           "WNM-Sleep Response action frame");
@@ -134,11 +167,18 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
        os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
        /* copy TFS IE here */
        pos += wnmsleep_ie_len;
-       if (wnmtfs_ie)
+       if (wnmtfs_ie) {
                os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
+               pos += wnmtfs_ie_len;
+       }
+#ifdef CONFIG_OCV
+       /* copy OCV OCI here */
+       if (oci_ie_len > 0)
+               os_memcpy(pos, oci_ie, oci_ie_len);
+#endif /* CONFIG_OCV */
 
        len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
-               igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
+               igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
 
        /* In driver, response frame should be forced to sent when STA is in
         * PS mode */
@@ -185,6 +225,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
 #undef MAX_IGTK_SUBELEM_LEN
 fail:
        os_free(wnmtfs_ie);
+       os_free(oci_ie);
        os_free(mgmt);
        return res;
 }
@@ -201,6 +242,11 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
        u8 *tfsreq_ie_start = NULL;
        u8 *tfsreq_ie_end = NULL;
        u16 tfsreq_ie_len = 0;
+#ifdef CONFIG_OCV
+       struct sta_info *sta;
+       const u8 *oci_ie = NULL;
+       u8 oci_ie_len = 0;
+#endif /* CONFIG_OCV */
 
        if (!hapd->conf->wnm_sleep_mode) {
                wpa_printf(MSG_DEBUG, "Ignore WNM-Sleep Mode Request from "
@@ -221,6 +267,12 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
                        if (!tfsreq_ie_start)
                                tfsreq_ie_start = (u8 *) pos;
                        tfsreq_ie_end = (u8 *) pos;
+#ifdef CONFIG_OCV
+               } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 &&
+                          pos[2] == WLAN_EID_EXT_OCV_OCI) {
+                       oci_ie = pos + 3;
+                       oci_ie_len = ie_len - 1;
+#endif /* CONFIG_OCV */
                } else
                        wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
                                   *pos);
@@ -232,6 +284,27 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
                return;
        }
 
+#ifdef CONFIG_OCV
+       sta = ap_get_sta(hapd, addr);
+       if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT &&
+           sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
+               struct wpa_channel_info ci;
+
+               if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+                       wpa_printf(MSG_WARNING,
+                                  "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame");
+                       return;
+               }
+
+               if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
+                                        channel_width_to_int(ci.chanwidth),
+                                        ci.seg1_idx) != 0) {
+                       wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr);
+                       return;
+               }
+       }
+#endif /* CONFIG_OCV */
+
        if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER &&
            tfsreq_ie_start && tfsreq_ie_end &&
            tfsreq_ie_end - tfsreq_ie_start >= 0) {
index 6b68fc9e3772a0251c8968c94834f6ab57afbcc0..a6ccd842b90bc2a82041e8667a2db96a6d70dfbf 100644 (file)
@@ -12,6 +12,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
+#include "common/ocv.h"
 #include "rsn_supp/wpa.h"
 #include "config.h"
 #include "wpa_supplicant_i.h"
@@ -58,8 +59,8 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
        int res;
        size_t len;
        struct wnm_sleep_element *wnmsleep_ie;
-       u8 *wnmtfs_ie;
-       u8 wnmsleep_ie_len;
+       u8 *wnmtfs_ie, *oci_ie;
+       u8 wnmsleep_ie_len, oci_ie_len;
        u16 wnmtfs_ie_len;  /* possibly multiple IE(s) */
        enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
                WNM_SLEEP_TFS_REQ_IE_NONE;
@@ -106,7 +107,41 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
        wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
                    (u8 *) wnmtfs_ie, wnmtfs_ie_len);
 
-       mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
+       oci_ie = NULL;
+       oci_ie_len = 0;
+#ifdef CONFIG_OCV
+       if (action == WNM_SLEEP_MODE_EXIT && wpa_sm_ocv_enabled(wpa_s->wpa)) {
+               struct wpa_channel_info ci;
+
+               if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+                       wpa_printf(MSG_WARNING,
+                                  "Failed to get channel info for OCI element in WNM-Sleep Mode frame");
+                       os_free(wnmsleep_ie);
+                       os_free(wnmtfs_ie);
+                       return -1;
+               }
+
+               oci_ie_len = OCV_OCI_EXTENDED_LEN;
+               oci_ie = os_zalloc(oci_ie_len);
+               if (!oci_ie) {
+                       wpa_printf(MSG_WARNING,
+                                  "Failed to allocate buffer for for OCI element in WNM-Sleep Mode frame");
+                       os_free(wnmsleep_ie);
+                       os_free(wnmtfs_ie);
+                       return -1;
+               }
+
+               if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+                       os_free(wnmsleep_ie);
+                       os_free(wnmtfs_ie);
+                       os_free(oci_ie);
+                       return -1;
+               }
+       }
+#endif /* CONFIG_OCV */
+
+       mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len +
+                        oci_ie_len);
        if (mgmt == NULL) {
                wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
                           "WNM-Sleep Request action frame");
@@ -131,8 +166,16 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
                          wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
        }
 
+#ifdef CONFIG_OCV
+       /* copy OCV OCI here */
+       if (oci_ie_len > 0) {
+               os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
+                         wnmsleep_ie_len + wnmtfs_ie_len, oci_ie, oci_ie_len);
+       }
+#endif /* CONFIG_OCV */
+
        len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
-               wnmtfs_ie_len;
+               wnmtfs_ie_len + oci_ie_len;
 
        res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
                                  wpa_s->own_addr, wpa_s->bssid,
@@ -145,6 +188,7 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
 
        os_free(wnmsleep_ie);
        os_free(wnmtfs_ie);
+       os_free(oci_ie);
        os_free(mgmt);
 
        return res;
@@ -256,6 +300,10 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
        /* multiple TFS Resp IE (assuming consecutive) */
        const u8 *tfsresp_ie_start = NULL;
        const u8 *tfsresp_ie_end = NULL;
+#ifdef CONFIG_OCV
+       const u8 *oci_ie = NULL;
+       u8 oci_ie_len = 0;
+#endif /* CONFIG_OCV */
        size_t left;
 
        if (!wpa_s->wnmsleep_used) {
@@ -289,6 +337,12 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
                        if (!tfsresp_ie_start)
                                tfsresp_ie_start = pos;
                        tfsresp_ie_end = pos;
+#ifdef CONFIG_OCV
+               } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 &&
+                          pos[2] == WLAN_EID_EXT_OCV_OCI) {
+                       oci_ie = pos + 3;
+                       oci_ie_len = ie_len - 1;
+#endif /* CONFIG_OCV */
                } else
                        wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
                pos += ie_len + 2;
@@ -299,6 +353,26 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
                return;
        }
 
+#ifdef CONFIG_OCV
+       if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT &&
+           wpa_sm_ocv_enabled(wpa_s->wpa)) {
+               struct wpa_channel_info ci;
+
+               if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+                       wpa_msg(wpa_s, MSG_WARNING,
+                               "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame");
+                       return;
+               }
+
+               if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
+                                        channel_width_to_int(ci.chanwidth),
+                                        ci.seg1_idx) != 0) {
+                       wpa_msg(wpa_s, MSG_WARNING, "WNM: %s", ocv_errorstr);
+                       return;
+               }
+       }
+#endif /* CONFIG_OCV */
+
        wpa_s->wnmsleep_used = 0;
 
        if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||