diff options
Diffstat (limited to 'src/ap/wnm_ap.c')
| -rw-r--r-- | src/ap/wnm_ap.c | 90 |
1 files changed, 85 insertions, 5 deletions
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c index 1e8f58b4d07ee..27c69d34a7caa 100644 --- a/src/ap/wnm_ap.c +++ b/src/ap/wnm_ap.c @@ -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 " @@ -209,6 +255,13 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd, return; } + if (len < 1) { + wpa_printf(MSG_DEBUG, + "WNM: Ignore too short WNM-Sleep Mode Request from " + MACSTR, MAC2STR(addr)); + return; + } + dialog_token = *pos++; while (pos + 1 < frm + len) { u8 ie_len = pos[1]; @@ -221,6 +274,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 +291,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) { |
