[2/4] hostapd: add RSSI based association rejection support

Message ID 1503333835-15264-2-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 reject a STA association request due to low RSSI.
In such case, the AP informs the STA the desired RSSI improvement and a retry
timeout. The STA might retry to associate even if the RSSI hasn't improved
if the retry timeout expired.

Signed-off-by: Beni Lev <beni.lev@intel.com>
---
 hostapd/config_file.c      |  4 ++++
 hostapd/hostapd.conf       |  9 +++++++++
 src/ap/ap_config.c         |  3 +++
 src/ap/ap_config.h         |  3 +++
 src/ap/ieee802_11.c        | 25 +++++++++++++++++++------
 src/ap/ieee802_11.h        |  3 +++
 src/ap/ieee802_11_shared.c | 14 ++++++++++++++
 7 files changed, 55 insertions(+), 6 deletions(-)

Comments

Jouni Malinen Sept. 21, 2017, 12:58 p.m. | #1
On Mon, Aug 21, 2017 at 07:43:53PM +0300, Andrei Otcheretianski wrote:
> An AP might reject a STA association request due to low RSSI.
> In such case, the AP informs the STA the desired RSSI improvement and a retry
> timeout. The STA might retry to associate even if the RSSI hasn't improved
> if the retry timeout expired.

> diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c

> @@ -2931,6 +2938,12 @@ static void handle_assoc(struct hostapd_data *hapd,
>  	}
>  
>  	sta = ap_get_sta(hapd, mgmt->sa);
> +
> +	if (hapd->iconf->rssi_reject_assoc_rssi &&
> +	    rssi < hapd->iconf->rssi_reject_assoc_rssi) {
> +		resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
> +		goto fail;
> +	}

Making a decision to reject an association based on the RSSI of a single
frame sounds like a bad idea to me. That value can vary a lot from frame
to frame.. At minimum, I'd expect the AP to include the RSSI of the
Authentication frame received just before this (Re)Association Request
frame and reject the association only if both those frames show too low
RSSI.
Otcheretianski, Andrei Sept. 24, 2017, 7:25 a.m. | #2
> -----Original Message-----
> From: Jouni Malinen [mailto:j@w1.fi]
> Sent: Thursday, September 21, 2017 15:58
> To: Otcheretianski, Andrei <andrei.otcheretianski@intel.com>
> Cc: hostap@lists.infradead.org; Lev, Beni <beni.lev@intel.com>
> Subject: Re: [PATCH 2/4] hostapd: add RSSI based association rejection support
> 
> On Mon, Aug 21, 2017 at 07:43:53PM +0300, Andrei Otcheretianski wrote:
>

Hi Jouni,

> Making a decision to reject an association based on the RSSI of a single frame
> sounds like a bad idea to me. That value can vary a lot from frame to frame.. At

I totally agree with you :)
We mainly wanted to add the STA part to comply with the OCE spec,
the AP part is needed basically to support hwsim testing.

> minimum, I'd expect the AP to include the RSSI of the Authentication frame
> received just before this (Re)Association Request frame and reject the
> association only if both those frames show too low RSSI.

Sure, we will add this.
Though I'm not sure whether using 2 frames will improve this much - may be you want us to put this entire feature  under CONFIG_TESTING_OPTIONS for AP side?

Thanks,
Andrei
> 
> --
> Jouni Malinen                                            PGP id EFC895FA
Jouni Malinen Sept. 25, 2017, 9:11 a.m. | #3
On Sun, Sep 24, 2017 at 07:25:18AM +0000, Otcheretianski, Andrei wrote:
> > From: Jouni Malinen [mailto:j@w1.fi]
> > minimum, I'd expect the AP to include the RSSI of the Authentication frame
> > received just before this (Re)Association Request frame and reject the
> > association only if both those frames show too low RSSI.
> 
> Sure, we will add this.
> Though I'm not sure whether using 2 frames will improve this much - may be you want us to put this entire feature  under CONFIG_TESTING_OPTIONS for AP side?

I don't think we'll need CONFIG_TESTING_OPTIONS need here. I would not
recommend this capability to be used, but as long as there is AP mode
configuration parameter that practically prevents this from causing
issues by default, that should be fine to include in normal builds.

Patch

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index cc799d4..4062569 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3740,6 +3740,10 @@  static int hostapd_config_fill(struct hostapd_config *conf,
 	} else if (os_strcmp(buf, "dpp_csign_expiry") == 0) {
 		bss->dpp_csign_expiry = strtol(pos, NULL, 0);
 #endif /* CONFIG_DPP */
+	} else if (os_strcmp(buf, "rssi_reject_assoc_rssi") == 0) {
+		conf->rssi_reject_assoc_rssi = atoi(pos);
+	} else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
+		conf->rssi_reject_assoc_timeout = atoi(pos);
 	} else {
 		wpa_printf(MSG_ERROR,
 			   "Line %d: unknown configuration item '%s'",
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 7ad3206..63a47f3 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -2225,3 +2225,12 @@  own_ip_addr=127.0.0.1
 #bss=wlan0_1
 #bssid=00:13:10:95:fe:0b
 # ...
+
+# RSSI based assocition rejection settings
+#
+# Reject STA association if RSSI is below given threshold(in dBm)
+#rssi_reject_assoc_rssi=-75
+#
+# Assoc retry delay in seconds allowed by the STA if RSSI has not met the
+# threshold. (default=30)
+#rssi_reject_assoc_timeout=60
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 07a13f8..eb4e293 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -219,6 +219,9 @@  struct hostapd_config * hostapd_config_defaults(void)
 	 * environments for the current frequency band in the country. */
 	conf->country[2] = ' ';
 
+	conf->rssi_reject_assoc_rssi = 0;
+	conf->rssi_reject_assoc_timeout = 30;
+
 	return conf;
 }
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 8e5ff52..514aaf5 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -785,6 +785,9 @@  struct hostapd_config {
 	struct he_phy_capabilities_info he_phy_capab;
 	struct he_operation he_op;
 #endif /* CONFIG_IEEE80211AX */
+
+	int rssi_reject_assoc_rssi;
+	int rssi_reject_assoc_timeout;
 };
 
 
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 7999611..6f51214 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2576,7 +2576,7 @@  static int add_associated_sta(struct hostapd_data *hapd,
 
 static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 			   const u8 *addr, u16 status_code, int reassoc,
-			   const u8 *ies, size_t ies_len)
+			   const u8 *ies, size_t ies_len, int rssi)
 {
 	int send_len;
 	u8 *buf;
@@ -2621,6 +2621,13 @@  static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 	/* Extended supported rates */
 	p = hostapd_eid_ext_supp_rates(hapd, p);
 
+	if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS) {
+		int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
+
+		p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
+						   delta);
+	}
+
 #ifdef CONFIG_IEEE80211R_AP
 	if (sta && status_code == WLAN_STATUS_SUCCESS) {
 		/* IEEE 802.11r: Mobility Domain Information, Fast BSS
@@ -2820,7 +2827,7 @@  void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
 	reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
 				    sta->fils_pending_assoc_is_reassoc,
 				    sta->fils_pending_assoc_req,
-				    sta->fils_pending_assoc_req_len);
+				    sta->fils_pending_assoc_req_len, 0);
 	os_free(sta->fils_pending_assoc_req);
 	sta->fils_pending_assoc_req = NULL;
 	sta->fils_pending_assoc_req_len = 0;
@@ -2860,7 +2867,7 @@  void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
 
 static void handle_assoc(struct hostapd_data *hapd,
 			 const struct ieee80211_mgmt *mgmt, size_t len,
-			 int reassoc)
+			 int reassoc, int rssi)
 {
 	u16 capab_info, listen_interval, seq_ctrl, fc;
 	u16 resp = WLAN_STATUS_SUCCESS, reply_res;
@@ -2931,6 +2938,12 @@  static void handle_assoc(struct hostapd_data *hapd,
 	}
 
 	sta = ap_get_sta(hapd, mgmt->sa);
+
+	if (hapd->iconf->rssi_reject_assoc_rssi &&
+	    rssi < hapd->iconf->rssi_reject_assoc_rssi) {
+		resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
+		goto fail;
+	}
 #ifdef CONFIG_IEEE80211R_AP
 	if (sta && sta->auth_alg == WLAN_AUTH_FT &&
 	    (sta->flags & WLAN_STA_AUTH) == 0) {
@@ -3218,7 +3231,7 @@  static void handle_assoc(struct hostapd_data *hapd,
 #endif /* CONFIG_FILS */
 
 	reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
-				    left);
+				    left, rssi);
 	os_free(tmp);
 
 	/*
@@ -3652,12 +3665,12 @@  int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
 		break;
 	case WLAN_FC_STYPE_ASSOC_REQ:
 		wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
-		handle_assoc(hapd, mgmt, len, 0);
+		handle_assoc(hapd, mgmt, len, 0, fi->ssi_signal);
 		ret = 1;
 		break;
 	case WLAN_FC_STYPE_REASSOC_REQ:
 		wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
-		handle_assoc(hapd, mgmt, len, 1);
+		handle_assoc(hapd, mgmt, len, 1, fi->ssi_signal);
 		ret = 1;
 		break;
 	case WLAN_FC_STYPE_DISASSOC:
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 0653fb2..97cfdaf 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -112,6 +112,9 @@  static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
 }
 #endif /* CONFIG_SAE */
 
+u8 * hostapd_eid_mbo_rssi_assoc_rej(struct hostapd_data *hapd, u8 *eid,
+				    size_t len, int delta);
+
 #ifdef CONFIG_MBO
 
 u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len);
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 902f64f..66fb4ef 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -539,6 +539,20 @@  u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
 	return pos;
 }
 
+u8 * hostapd_eid_mbo_rssi_assoc_rej(struct hostapd_data *hapd, u8 *eid,
+				    size_t len, int delta)
+{
+	u8 mbo[4];
+
+	mbo[0] = OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT;
+	mbo[1] = 2;
+	/* Delta RSSI */
+	mbo[2] = delta;
+	/* Retry delay */
+	mbo[3] = hapd->iconf->rssi_reject_assoc_timeout;
+
+	return eid + mbo_add_ie(eid, len, mbo, 4);
+}
 
 #ifdef CONFIG_MBO