@@ -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,41 @@ 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 &&
+ sta != NULL && 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 == NULL) {
+ wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
+ "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);
+ mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_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");
@@ -136,9 +168,15 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
pos += wnmsleep_ie_len;
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 +223,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;
}
@@ -193,6 +232,7 @@ fail:
static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *frm, int len)
{
+ struct sta_info *sta;
/* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
const u8 *pos = frm;
u8 dialog_token;
@@ -201,6 +241,8 @@ 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;
+ const u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
if (!hapd->conf->wnm_sleep_mode) {
wpa_printf(MSG_DEBUG, "Ignore WNM-Sleep Mode Request from "
@@ -221,6 +263,10 @@ 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;
+ } 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;
} else
wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
*pos);
@@ -232,6 +278,28 @@ 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 != NULL && 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, 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"
@@ -54,12 +55,13 @@ static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
u8 action, u16 intval, struct wpabuf *tfs_req)
{
+ struct wpa_sm *sm = wpa_s->wpa;
struct ieee80211_mgmt *mgmt;
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 +108,40 @@ 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(sm)) {
+ 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 == NULL) {
+ 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");
@@ -130,9 +165,15 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
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 +186,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 +298,8 @@ 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;
+ const u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
size_t left;
if (!wpa_s->wnmsleep_used) {
@@ -289,6 +333,10 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
if (!tfsresp_ie_start)
tfsresp_ie_start = pos;
tfsresp_ie_end = pos;
+ } 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;
} else
wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
pos += ie_len + 2;
@@ -299,6 +347,27 @@ 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, ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
wpa_s->wnmsleep_used = 0;
if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
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 | 78 ++++++++++++++++++++++++++++++++++++--- wpa_supplicant/wnm_sta.c | 79 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 147 insertions(+), 10 deletions(-)