OCV: Include and verify OCI in WNM-Sleep Exit frames
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>
This commit is contained in:
parent
0059625b77
commit
fa97981265
2 changed files with 156 additions and 9 deletions
|
@ -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) {
|
||||
|
|
|
@ -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 ||
|
||||
|
|
Loading…
Reference in a new issue