From 13bf18eda56fc64abfdb481caeeae9d9a7d18ba8 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Wed, 8 Mar 2017 14:37:38 +0200 Subject: [PATCH] WNM: Use a dynamically allocated buffer for BTM query and response BSS transition management query and response use a large static buffer for the frame because the candidate list may require a lot of space. However, in most cases the actually used space will be much less than the buffer (since the candidate list is short or completely missing). Use a dynamically allocated buffer instead and allocate it according to the actual space needed. While at it, remove unneeded filling of the MAC header in the Action frames, since this gets ignored and wpa_drv_send_action() adds the MAC header anyway. Signed-off-by: Avraham Stern --- wpa_supplicant/wnm_sta.c | 163 ++++++++++++++++++++------------------- 1 file changed, 83 insertions(+), 80 deletions(-) diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index f7200bf2b..c4f77e730 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -780,36 +780,40 @@ static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) } -static int wnm_add_nei_rep(u8 *buf, size_t len, const u8 *bssid, u32 bss_info, - u8 op_class, u8 chan, u8 phy_type, u8 pref) +static int wnm_add_nei_rep(struct wpabuf **buf, const u8 *bssid, + u32 bss_info, u8 op_class, u8 chan, u8 phy_type, + u8 pref) { - u8 *pos = buf; - - if (len < 18) { + if (wpabuf_len(*buf) + 18 > + IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN) { wpa_printf(MSG_DEBUG, - "WNM: Not enough room for Neighbor Report element"); + "WNM: No room in frame for Neighbor Report element"); return -1; } - *pos++ = WLAN_EID_NEIGHBOR_REPORT; + if (wpabuf_resize(buf, 18) < 0) { + wpa_printf(MSG_DEBUG, + "WNM: Failed to allocate memory for Neighbor Report element"); + return -1; + } + + wpabuf_put_u8(*buf, WLAN_EID_NEIGHBOR_REPORT); /* length: 13 for basic neighbor report + 3 for preference subelement */ - *pos++ = 16; - os_memcpy(pos, bssid, ETH_ALEN); - pos += ETH_ALEN; - WPA_PUT_LE32(pos, bss_info); - pos += 4; - *pos++ = op_class; - *pos++ = chan; - *pos++ = phy_type; - *pos++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE; - *pos++ = 1; - *pos++ = pref; - return pos - buf; + wpabuf_put_u8(*buf, 16); + wpabuf_put_data(*buf, bssid, ETH_ALEN); + wpabuf_put_le32(*buf, bss_info); + wpabuf_put_u8(*buf, op_class); + wpabuf_put_u8(*buf, chan); + wpabuf_put_u8(*buf, phy_type); + wpabuf_put_u8(*buf, WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE); + wpabuf_put_u8(*buf, 1); + wpabuf_put_u8(*buf, pref); + return 0; } static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, - struct wpa_bss *bss, u8 *buf, size_t len, + struct wpa_bss *bss, struct wpabuf **buf, u8 pref) { const u8 *ie; @@ -858,20 +862,19 @@ static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, info = wnm_get_bss_info(wpa_s, bss); - return wnm_add_nei_rep(buf, len, bss->bssid, info, op_class, chan, - phy_type, pref); + return wnm_add_nei_rep(buf, bss->bssid, info, op_class, chan, phy_type, + pref); } -static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) +static void wnm_add_cand_list(struct wpa_supplicant *wpa_s, struct wpabuf **buf) { - u8 *pos = buf; unsigned int i, pref = 255; struct os_reltime now; struct wpa_ssid *ssid = wpa_s->current_ssid; if (!ssid) - return 0; + return; /* * TODO: Define when scan results are no longer valid for the candidate @@ -879,7 +882,7 @@ static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) */ os_get_reltime(&now); if (os_reltime_expired(&now, &wpa_s->last_scan, 10)) - return 0; + return; wpa_printf(MSG_DEBUG, "WNM: Add candidate list to BSS Transition Management Response frame"); @@ -888,36 +891,31 @@ static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) int res; if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) { - res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--); + res = wnm_nei_rep_add_bss(wpa_s, bss, buf, pref--); if (res == -2) continue; /* could not build entry for BSS */ if (res < 0) break; /* no more room for candidates */ if (pref == 1) break; - - pos += res; - len -= res; } } - wpa_hexdump(MSG_DEBUG, - "WNM: BSS Transition Management Response candidate list", - buf, pos - buf); - - return pos - buf; + wpa_hexdump_buf(MSG_DEBUG, + "WNM: BSS Transition Management Response candidate list", + *buf); } +#define BTM_RESP_MIN_SIZE 5 + ETH_ALEN + static void wnm_send_bss_transition_mgmt_resp( struct wpa_supplicant *wpa_s, u8 dialog_token, enum bss_trans_mgmt_status_code status, enum mbo_transition_reject_reason reason, u8 delay, const u8 *target_bssid) { - u8 buf[2000], *pos; - struct ieee80211_mgmt *mgmt; - size_t len; + struct wpabuf *buf; int res; wpa_printf(MSG_DEBUG, @@ -930,52 +928,62 @@ static void wnm_send_bss_transition_mgmt_resp( return; } - mgmt = (struct ieee80211_mgmt *) buf; - os_memset(&buf, 0, sizeof(buf)); - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; - mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; - mgmt->u.action.u.bss_tm_resp.status_code = status; - mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; - pos = mgmt->u.action.u.bss_tm_resp.variable; + buf = wpabuf_alloc(BTM_RESP_MIN_SIZE); + if (!buf) { + wpa_printf(MSG_DEBUG, + "WNM: Failed to allocate memory for BTM response"); + return; + } + + wpabuf_put_u8(buf, WLAN_ACTION_WNM); + wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP); + wpabuf_put_u8(buf, dialog_token); + wpabuf_put_u8(buf, status); + wpabuf_put_u8(buf, delay); if (target_bssid) { - os_memcpy(pos, target_bssid, ETH_ALEN); - pos += ETH_ALEN; + wpabuf_put_data(buf, target_bssid, ETH_ALEN); } else if (status == WNM_BSS_TM_ACCEPT) { /* * P802.11-REVmc clarifies that the Target BSSID field is always * present when status code is zero, so use a fake value here if * no BSSID is yet known. */ - os_memset(pos, 0, ETH_ALEN); - pos += ETH_ALEN; + wpabuf_put_data(buf, "\0\0\0\0\0\0", ETH_ALEN); } if (status == WNM_BSS_TM_ACCEPT) - pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); + wnm_add_cand_list(wpa_s, &buf); #ifdef CONFIG_MBO if (status != WNM_BSS_TM_ACCEPT && wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) { - pos += wpas_mbo_ie_bss_trans_reject( - wpa_s, pos, buf + sizeof(buf) - pos, reason); + u8 mbo[10]; + size_t ret; + + ret = wpas_mbo_ie_bss_trans_reject(wpa_s, mbo, sizeof(mbo), + reason); + if (ret) { + if (wpabuf_resize(&buf, ret) < 0) { + wpabuf_free(buf); + wpa_printf(MSG_DEBUG, + "WNM: Failed to allocate memory for MBO IE"); + return; + } + + wpabuf_put_data(buf, mbo, ret); + } } #endif /* CONFIG_MBO */ - len = pos - (u8 *) &mgmt->u.action.category; - res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, - &mgmt->u.action.category, len, 0); + wpabuf_head_u8(buf), wpabuf_len(buf), 0); if (res < 0) { wpa_printf(MSG_DEBUG, "WNM: Failed to send BSS Transition Management Response"); } + + wpabuf_free(buf); } @@ -1475,12 +1483,12 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, } +#define BTM_QUERY_MIN_SIZE 4 + int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, u8 query_reason, int cand_list) { - u8 buf[2000], *pos; - struct ieee80211_mgmt *mgmt; - size_t len; + struct wpabuf *buf; int ret; wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " @@ -1488,28 +1496,23 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, MAC2STR(wpa_s->bssid), query_reason, cand_list ? " candidate list" : ""); - mgmt = (struct ieee80211_mgmt *) buf; - os_memset(&buf, 0, sizeof(buf)); - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; - mgmt->u.action.u.bss_tm_query.dialog_token = 1; - mgmt->u.action.u.bss_tm_query.query_reason = query_reason; - pos = mgmt->u.action.u.bss_tm_query.variable; + buf = wpabuf_alloc(BTM_QUERY_MIN_SIZE); + if (!buf) + return -1; + + wpabuf_put_u8(buf, WLAN_ACTION_WNM); + wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_QUERY); + wpabuf_put_u8(buf, 1); + wpabuf_put_u8(buf, query_reason); if (cand_list) - pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); - - len = pos - (u8 *) &mgmt->u.action.category; + wnm_add_cand_list(wpa_s, &buf); ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, - &mgmt->u.action.category, len, 0); + wpabuf_head_u8(buf), wpabuf_len(buf), 0); + wpabuf_free(buf); return ret; }