[PATCH 12/25] MBO: Parse MBO IE in BSS transition management request frames

Ilan Peer ilan.peer at intel.com
Mon Feb 15 06:53:36 PST 2016


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

Add parsing of MBO IE in BSS transition management request.

If the MBO IE includes the association retry delay attribute, do
not try to reconnect to the current BSS until the delay time is over.

If the MBO IE includes the cellular data connection preference
attribute or the transition rejection reason attribute, send a message
to upper layers with the data.

Signed-off-by: David Spinadel <david.spinadel at intel.com>
Signed-off-by: Avraham Stern <avraham.stern at intel.com>
---
 src/common/wpa_ctrl.h             |  6 +++
 wpa_supplicant/events.c           |  9 +++-
 wpa_supplicant/mbo.c              | 96 +++++++++++++++++++++++++++++++++++++++
 wpa_supplicant/wnm_sta.c          | 19 +++++++-
 wpa_supplicant/wpa_supplicant.c   | 85 ++++++++++++++++++++++++++++++++++
 wpa_supplicant/wpa_supplicant_i.h | 17 +++++++
 6 files changed, 230 insertions(+), 2 deletions(-)

diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 3e0a7ec..d9641bb 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -270,6 +270,12 @@ extern "C" {
 /* BSS Transition Management Response frame received */
 #define BSS_TM_RESP "BSS-TM-RESP "
 
+/* MBO IE with cellular data connection preference received */
+#define MBO_CELL_PREFERENCE "MBO-CELL-PREFERENCE "
+
+/* BSS Transition Management Request received with MBO transition reason */
+#define MBO_TRANSITION_REASON "MBO-TRANSITION-REASON "
+
 /* BSS command information masks */
 
 #define WPA_BSS_MASK_ALL		0xFFFDFFFF
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index cb44674..de4ef91 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1076,6 +1076,12 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 				assoc_disallow[2]);
 			continue;
 		}
+
+		if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - MBO Retry delay didn't pass yet");
+			continue;
+		}
 #endif /* CONFIG_MBO */
 
 		/* Matching configuration found */
@@ -2541,7 +2547,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
 	    !disallowed_bssid(wpa_s, fast_reconnect->bssid) &&
 	    !disallowed_ssid(wpa_s, fast_reconnect->ssid,
 			     fast_reconnect->ssid_len) &&
-	    !wpas_temp_disabled(wpa_s, fast_reconnect_ssid)) {
+	    !wpas_temp_disabled(wpa_s, fast_reconnect_ssid) &&
+	    !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) {
 #ifndef CONFIG_NO_SCAN_PROCESSING
 		wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
 		if (wpa_supplicant_connect(wpa_s, fast_reconnect,
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 43e7033..1e28545 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -618,3 +618,99 @@ int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
 	wpabuf_free(buf);
 	return res;
 }
+
+
+void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
+			   size_t len)
+{
+	const u8 *pos, *cell_pref = NULL, *reason = NULL;
+	u8 id, elen;
+	u16 disallowed_sec = 0;
+
+	if (len <= 4 || WPA_GET_BE24(mbo_ie) != OUI_WFA ||
+	    mbo_ie[3] != MBO_OUI_TYPE)
+		return;
+
+	pos = mbo_ie + 4;
+	len -= 4;
+
+	while (len >= 2) {
+		id = *pos++;
+		elen = *pos++;
+		len -= 2;
+
+		if (elen > len)
+			goto fail;
+
+		switch (id) {
+		case MBO_ATTR_ID_CELL_DATA_PREF:
+			if (elen != 1)
+				goto fail;
+
+			if (wpa_s->conf->mbo_cell_capa ==
+			    MBO_CELL_CAPA_AVAILABLE)
+				cell_pref = pos;
+			else
+				wpa_printf(MSG_DEBUG,
+					   "MBO: Station does not support Cellular data connection");
+
+			break;
+		case MBO_ATTR_ID_TRANSITION_REASON:
+			if (elen != 1)
+				goto fail;
+
+			reason = pos;
+			break;
+		case MBO_ATTR_ID_ASSOC_RETRY_DELAY:
+			if (elen != 2)
+				goto fail;
+
+			if (wpa_s->wnm_mode &
+			    WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+				wpa_printf(MSG_DEBUG,
+					   "MBO: Unexpected assoc retry delay, BSS is terminating");
+				goto fail;
+			} else if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+				disallowed_sec = WPA_GET_LE16(pos);
+			} else {
+				wpa_printf(MSG_DEBUG,
+					   "MBO: Assoc retry delay attribute not in disassoc imminent mode");
+			}
+
+			break;
+		case MBO_ATTR_ID_CAPA_IND:
+		case MBO_ATTR_ID_NP_CHAN_REPORT:
+		case MBO_ATTR_ID_CELL_CAPA:
+		case MBO_ATTR_ID_ASSOC_DISALLOW:
+		case MBO_ATTR_ID_TRANSITION_REJECT_REASON:
+			wpa_printf(MSG_DEBUG,
+				   "MBO: Attribute %d should not be included in BTM request frame",
+				   id);
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "MBO: Unknown attribute id %u",
+				   id);
+			return;
+		}
+
+		pos += elen;
+		len -= elen;
+	}
+
+	if (cell_pref)
+		wpa_msg(wpa_s, MSG_INFO, MBO_CELL_PREFERENCE "preference=%u",
+			*cell_pref);
+
+	if (reason)
+		wpa_msg(wpa_s, MSG_INFO, MBO_TRANSITION_REASON "reason=%u",
+			*reason);
+
+	if (disallowed_sec)
+		wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
+				     disallowed_sec);
+
+	return;
+fail:
+	wpa_printf(MSG_DEBUG, "MBO IE parse failed (id=%u len=%u left=%zu)", id,
+		   elen, len);
+}
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index ffc9052..a3cf32d 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -546,6 +546,13 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
 			continue;
 		}
 
+		if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
+			wpa_printf(MSG_DEBUG,
+				   "MBO: Candidate BSS " MACSTR " retry delay isn't over yet",
+				   MAC2STR(nei->bssid));
+			continue;
+		}
+
 		if (target->level < bss->level && target->level < -80) {
 			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
 				   " (pref %d) does not have sufficient signal level (%d)",
@@ -821,6 +828,9 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
 {
 	unsigned int beacon_int;
 	u8 valid_int;
+#ifdef CONFIG_MBO
+	const u8 *vendor;
+#endif
 
 	if (end - pos < 5)
 		return;
@@ -881,6 +891,12 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
 		}
 	}
 
+#ifdef CONFIG_MBO
+	vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC);
+	if (vendor)
+		wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]);
+#endif /* CONFIG_MBO */
+
 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
 		unsigned int valid_ms;
 
@@ -945,7 +961,8 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
 	} else if (reply) {
 		enum bss_trans_mgmt_status_code status;
-		if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
+		if ((wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) ||
+		    (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))
 			status = WNM_BSS_TM_ACCEPT;
 		else {
 			wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates");
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index d1c5723..5f2f032 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -397,6 +397,18 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
 }
 
 
+static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss_tmp_disallowed *bss, *prev;
+
+	dl_list_for_each_safe(bss, prev,  &wpa_s->bss_tmp_disallowed,
+			      struct wpa_bss_tmp_disallowed, list) {
+		dl_list_del(&bss->list);
+		os_free(bss);
+	}
+}
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
 	int i;
@@ -554,6 +566,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 	wpa_s->np_chan_num = 0;
 	os_free(wpa_s->np_chan);
 #endif /* CONFIG_MBO */
+
+	free_bss_tmp_disallowed(wpa_s);
 }
 
 
@@ -3490,6 +3504,8 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
 	wpa_s->parent = parent ? parent : wpa_s;
 	wpa_s->sched_scanning = 0;
 
+	dl_list_init(&wpa_s->bss_tmp_disallowed);
+
 	return wpa_s;
 }
 
@@ -6302,3 +6318,72 @@ struct hostapd_hw_modes *get_mode(struct hostapd_hw_modes *modes,
 
 	return NULL;
 }
+
+
+static struct
+wpa_bss_tmp_disallowed *wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
+						u8 *bssid)
+{
+	struct wpa_bss_tmp_disallowed *bss;
+
+	dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed,
+			 struct wpa_bss_tmp_disallowed, list) {
+		if (!os_memcmp(bssid, bss->bssid, ETH_ALEN))
+			return bss;
+	}
+
+	return NULL;
+}
+
+
+void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, u8 *bssid, u16 sec)
+{
+	struct wpa_bss_tmp_disallowed *bss;
+	struct os_reltime until;
+
+	os_get_reltime(&until);
+	until.sec += sec;
+
+	bss = wpas_get_disallowed_bss(wpa_s, bssid);
+	if (bss) {
+		bss->disallowed_until = until;
+		return;
+	}
+
+	bss = os_malloc(sizeof(*bss));
+	if (!bss) {
+		wpa_printf(MSG_DEBUG,
+			   "Failed to allocate memory for temp disallow BSS");
+		return;
+	}
+
+	bss->disallowed_until = until;
+	os_memcpy(bss->bssid, bssid, ETH_ALEN);
+	dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
+}
+
+
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, u8 *bssid)
+{
+	struct wpa_bss_tmp_disallowed *bss;
+	struct os_reltime now;
+
+	os_get_reltime(&now);
+
+	bss = wpas_get_disallowed_bss(wpa_s, bssid);
+	if (!bss)
+		return 0;
+
+	if (os_reltime_before(&now, &bss->disallowed_until)) {
+		wpa_printf(MSG_DEBUG,
+			   "BSS " MACSTR " disabled until %ld.%ld, now=%ld.%ld",
+			   MAC2STR(bss->bssid), bss->disallowed_until.sec,
+			   bss->disallowed_until.usec, now.sec, now.usec);
+		return 1;
+	}
+
+	/* This BSS is not disallowed anymore */
+	dl_list_del(&bss->list);
+	os_free(bss);
+	return 0;
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index ec486a7..9c09fd7 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -434,6 +434,12 @@ struct icon_entry {
 	size_t image_len;
 };
 
+struct wpa_bss_tmp_disallowed {
+	struct dl_list list;
+	u8 bssid[ETH_ALEN];
+	struct os_reltime disallowed_until;
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -1029,6 +1035,12 @@ struct wpa_supplicant {
 	size_t np_chan_num;
 	u8 mbo_wnm_token;
 #endif /* CONFIG_MBO */
+
+	/*
+	 * This should be under CONFIG_MBO, but it is left out to allow using
+	 * the bss_temp_disallowed list for other purposes as well.
+	 */
+	struct dl_list bss_tmp_disallowed;
 };
 
 
@@ -1150,6 +1162,8 @@ int wpas_mbo_update_np_chan(struct wpa_supplicant *wpa_s, const char *np_chan);
 void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
 int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
 			      size_t len);
+void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie,
+			   size_t len);
 
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -1232,4 +1246,7 @@ int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd);
 struct hostapd_hw_modes *get_mode(struct hostapd_hw_modes *modes,
 				  u16 num_modes,
 				  enum hostapd_hw_mode mode);
+
+void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, u8 *bssid, u16 sec);
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, u8 *bssid);
 #endif /* WPA_SUPPLICANT_I_H */
-- 
1.9.1




More information about the Hostap mailing list