[PATCH 1/5] WNM: Use a dynamically allocated buffer for BTM query and response

Andrei Otcheretianski andrei.otcheretianski at intel.com
Wed Mar 8 04:37:38 PST 2017


From: Avraham Stern <avraham.stern at intel.com>

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 wpa_drv_send_action() adds the MAC header anyway.

Signed-off-by: Avraham Stern <avraham.stern at intel.com>
---
 wpa_supplicant/wnm_sta.c | 157 ++++++++++++++++++++++++-----------------------
 1 file changed, 80 insertions(+), 77 deletions(-)

diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index f7200bf..3ac568e 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 (wpabuf_len(*buf) + 18 >
+	    IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: No room in frame for Neighbor report element");
+		return -1;
+	}
 
-	if (len < 18) {
+	if (wpabuf_resize(buf, 18) < 0) {
 		wpa_printf(MSG_DEBUG,
-			   "WNM: Not enough room for Neighbor Report element");
+			   "WNM: Failed to allocate memory for Neighbor Report element");
 		return -1;
 	}
 
-	*pos++ = WLAN_EID_NEIGHBOR_REPORT;
+	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;
+		    wpabuf_head_u8(*buf), wpabuf_len(*buf));
 }
 
 
+#define BTM_RESP_MIN_SIZE	11
+
 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;
 
-	if (cand_list)
-		pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
+	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);
 
-	len = pos - (u8 *) &mgmt->u.action.category;
+	if (cand_list)
+		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;
 }
 
-- 
1.9.1




More information about the Hostap mailing list