[1/4] OCE: Add RSSI based association rejection support

Message ID 1503333835-15264-1-git-send-email-andrei.otcheretianski@intel.com
State New
Headers show

Commit Message

Otcheretianski, Andrei Aug. 21, 2017, 4:43 p.m.
From: Beni Lev <beni.lev@intel.com>

An AP might refuse to connect a STA if it has a low RSSI. In such case,
the AP informs the STA with the desired RSSI delta and a retry timeout.
Any association attempt should be avoided, unless the RSSI level improved
by the desired delta or the timeout has expired

Defined in WFA_OCE_TechSpec_v0.0.11, section 3.14

Signed-off-by: Beni Lev <beni.lev@intel.com>
---
 src/common/ieee802_11_common.c    | 16 ++++++++++++++++
 src/common/ieee802_11_common.h    |  2 ++
 wpa_supplicant/ctrl_iface.c       |  2 ++
 wpa_supplicant/events.c           | 24 +++++++++++++++++++++---
 wpa_supplicant/mbo.c              | 21 ++++++++++++++++++++-
 wpa_supplicant/wnm_sta.c          |  2 +-
 wpa_supplicant/wpa_supplicant.c   | 26 ++++++++++++++++----------
 wpa_supplicant/wpa_supplicant_i.h |  9 +++++++--
 8 files changed, 85 insertions(+), 17 deletions(-)

Patch

diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 4da10d2..074cac1 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1432,6 +1432,22 @@  const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
 	return NULL;
 }
 
+const u8 *get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
+{
+	const u8 *pos = ies, *end = ies + len;
+
+	while (end - pos > 1) {
+		if (2 + pos[1] > end - pos)
+			break;
+
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
 
 size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
 {
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index ff2f8e7..e3c0325 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -176,6 +176,8 @@  extern const struct oper_class_map global_op_class[];
 extern size_t global_op_class_size;
 
 const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
+const u8 *get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type);
+
 
 size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
 
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 6f91b83..138a35d 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -7797,6 +7797,8 @@  static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 
 	wpabuf_free(wpa_s->ric_ies);
 	wpa_s->ric_ies = NULL;
+
+	free_bss_tmp_disallowed(wpa_s);
 }
 
 
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index db7de89..b5f1737 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1201,10 +1201,10 @@  struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 			continue;
 		}
 
-		if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) {
+		if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
 			if (debug_print)
 				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - MBO retry delay has not passed yet");
+					"   skip - AP disallowed");
 			continue;
 		}
 #ifdef CONFIG_TESTING_OPTIONS
@@ -2856,7 +2856,7 @@  static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
 	    !disallowed_ssid(wpa_s, fast_reconnect->ssid,
 			     fast_reconnect->ssid_len) &&
 	    !wpas_temp_disabled(wpa_s, fast_reconnect_ssid) &&
-	    !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) {
+	    !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect)) {
 #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,
@@ -3903,6 +3903,24 @@  void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 				data->assoc_reject.timeout_reason : "");
 		wpa_s->assoc_status_code = data->assoc_reject.status_code;
 		wpas_notify_assoc_status_code(wpa_s);
+
+#ifdef CONFIG_MBO
+		if (data->assoc_reject.status_code ==
+		    WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS) {
+			const u8 *rssi_rej =
+			mbo_get_attr_from_ies(data->assoc_reject.resp_ies,
+				data->assoc_reject.resp_ies_len,
+				OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT);
+
+			if (rssi_rej && rssi_rej[1] == 2 &&
+			    wpa_s->current_bss)
+				wpa_bss_tmp_disallow(wpa_s,
+						     data->assoc_reject.bssid,
+						     rssi_rej[3],
+						     rssi_rej[2] +
+						     wpa_s->current_bss->level);
+		}
+#endif /* CONFIG_MBO */
 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
 			sme_event_assoc_reject(wpa_s, data);
 		else {
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 129d205..0535b88 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -37,6 +37,25 @@  static int wpas_mbo_validate_non_pref_chan(u8 oper_class, u8 chan, u8 reason)
 	return 0;
 }
 
+static const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie,
+				       enum mbo_attr_id attr)
+{
+	const u8 *mbo = mbo_ie + MBO_IE_HEADER, *end = mbo_ie + 2 + mbo_ie[1];
+
+	return get_ie(mbo, end - mbo, attr);
+}
+
+const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
+				 enum mbo_attr_id attr)
+{
+	const u8 *mbo_ie;
+
+	mbo_ie = get_vendor_ie(ies, ies_len, MBO_IE_VENDOR_TYPE);
+	if (!mbo_ie)
+		return NULL;
+
+	return mbo_attr_from_mbo_ie(mbo_ie, attr);
+}
 
 const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
 {
@@ -487,7 +506,7 @@  void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
 
 	if (disallowed_sec && wpa_s->current_bss)
 		wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
-				     disallowed_sec);
+				     disallowed_sec, 0);
 
 	return;
 fail:
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 7339ed2..d3a2b24 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -691,7 +691,7 @@  compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs,
 			continue;
 		}
 
-		if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
+		if (wpa_is_bss_tmp_disallowed(wpa_s, target)) {
 			wpa_printf(MSG_DEBUG,
 				   "MBO: Candidate BSS " MACSTR
 				   " retry delay is not over yet",
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index be44787..4932fa8 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -414,7 +414,7 @@  void free_hw_features(struct wpa_supplicant *wpa_s)
 }
 
 
-static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
+void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_bss_tmp_disallowed *bss, *prev;
 
@@ -6760,16 +6760,14 @@  static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx)
 
 
 void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
-			  unsigned int sec)
+			  unsigned int sec, int rssi_threshold)
 {
 	struct wpa_bss_tmp_disallowed *bss;
 
 	bss = wpas_get_disallowed_bss(wpa_s, bssid);
 	if (bss) {
 		eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
-		eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
-				       wpa_s, bss);
-		return;
+		goto finish;
 	}
 
 	bss = os_malloc(sizeof(*bss));
@@ -6782,23 +6780,31 @@  void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
 	os_memcpy(bss->bssid, bssid, ETH_ALEN);
 	dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
 	wpa_set_driver_tmp_disallow_list(wpa_s);
+
+finish:
+	bss->rssi_threshold = rssi_threshold;
 	eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
 			       wpa_s, bss);
 }
 
 
-int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *bss)
 {
-	struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev;
+	struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev;
 
 	dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
 			 struct wpa_bss_tmp_disallowed, list) {
-		if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
-			bss = tmp;
+		if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) {
+			disallowed = tmp;
 			break;
 		}
 	}
-	if (!bss)
+	if (!disallowed)
+		return 0;
+
+	if (disallowed->rssi_threshold != 0 &&
+	    bss->level > disallowed->rssi_threshold)
 		return 0;
 
 	return 1;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 8b7d2f5..2be4998 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -450,6 +450,7 @@  struct icon_entry {
 struct wpa_bss_tmp_disallowed {
 	struct dl_list list;
 	u8 bssid[ETH_ALEN];
+	int rssi_threshold;
 };
 
 struct beacon_rep_data {
@@ -1328,6 +1329,8 @@  void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s);
 /* MBO functions */
 int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len);
 const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
+const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
+				 enum mbo_attr_id attr);
 int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
 				  const char *non_pref_chan);
 void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
@@ -1436,8 +1439,10 @@  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, const u8 *bssid,
-			  unsigned int sec);
-int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+			  unsigned int sec, int rssi_threshold);
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *bss);
+void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s);
 
 struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 				     int i, struct wpa_bss *bss,