Pārlūkot izejas kodu

qcacld-3.0: Add support for rssi based assoc rejection during connect

Add support to handle rssi based assoc rejection from a bssid and
Try to connect to this bssid only after time interval indicated in
Assoc reject or when rssi has improved by margin indicated in Assoc
reject.

Change-Id: I6363bf5346ff8804611afbac3058819dc820092d
CRs-Fixed: 2070452
Abhishek Singh 8 gadi atpakaļ
vecāks
revīzija
f3756fcb5c

+ 18 - 0
core/mac/inc/sir_api.h

@@ -116,6 +116,7 @@ typedef uint8_t tSirVersionString[SIR_VERSION_STRING_LEN];
 	(QOS_MAP_LEN_MIN + 2 * QOS_MAP_MAX_EX)
 #define NUM_CHAINS_MAX  2
 
+#define MAX_RSSI_AVOID_BSSID_LIST    10
 /**
  * enum sir_conn_update_reason: Reason for conc connection update
  * @SIR_UPDATE_REASON_SET_OPER_CHAN: Set probable operating channel
@@ -7426,4 +7427,21 @@ struct sir_peer_set_rx_blocksize {
 	struct qdf_mac_addr peer_macaddr;
 	uint32_t rx_block_ack_win_limit;
 };
+
+/**
+ * struct sir_rssi_disallow_lst - Structure holding Rssi based avoid candidate
+ * list
+ * @node: Node pointer
+ * @bssid: BSSID of the AP
+ * @retry_delay: Retry delay received during last rejection in ms
+ * @ expected_rssi: RSSI at which STA can initate
+ * @time_during_rejection: Timestamp during last rejection in millisec
+ */
+struct sir_rssi_disallow_lst {
+	qdf_list_node_t node;
+	struct qdf_mac_addr bssid;
+	uint32_t retry_delay;
+	int8_t expected_rssi;
+	qdf_time_t time_during_rejection;
+};
 #endif /* __SIR_API_H */

+ 5 - 1
core/mac/inc/sir_mac_prot_def.h

@@ -672,7 +672,11 @@ typedef enum eSirMacStatusCodes {
 	eSIR_MAC_QOS_UNSPECIFIED_FAILURE_STATUS = 32,   /* Unspecified, QoS-related failure */
 	eSIR_MAC_QAP_NO_BANDWIDTH_STATUS = 33,  /* Association denied because QoS AP has insufficient bandwidth to handle another */
 	/* QoS STA */
-	eSIR_MAC_XS_FRAME_LOSS_STATUS = 34,     /* Association denied due to excessive frame loss rates and/or poor conditions on cur- */
+	/*
+	 * Association denied due to excessive frame loss rates
+	 * and/or poor conditions/RSSI on cur channel
+	 */
+	eSIR_MAC_XS_FRAME_LOSS_POOR_CHANNEL_RSSI_STATUS = 34,
 	/* rent operating channel */
 	eSIR_MAC_STA_QOS_NOT_SUPPORTED_STATUS = 35,     /* Association (with QoS BSS) denied because the requesting STA does not support the */
 	/* QoS facility */

+ 1 - 0
core/mac/src/include/parser_api.h

@@ -323,6 +323,7 @@ typedef struct sSirAssocRsp {
 #endif
 	tDot11fIEvendor_vht_ie vendor_vht_ie;
 	tDot11fIEOBSSScanParameters obss_scanparams;
+	tDot11fTLVrssi_assoc_rej rssi_assoc_rej;
 	tSirQCNIE QCN_IE;
 	tDot11fIEvendor_he_cap vendor_he_cap;
 	tDot11fIEvendor_he_op vendor_he_op;

+ 7 - 0
core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c

@@ -713,6 +713,13 @@ lim_process_assoc_rsp_frame(tpAniSirGlobal mac_ctx,
 	else
 		lim_stop_reassoc_retry_timer(mac_ctx);
 
+	if (eSIR_MAC_XS_FRAME_LOSS_POOR_CHANNEL_RSSI_STATUS ==
+	   assoc_rsp->statusCode &&
+	    assoc_rsp->rssi_assoc_rej.present)
+		lim_assoc_rej_add_to_rssi_based_reject_list(mac_ctx,
+			&assoc_rsp->rssi_assoc_rej, hdr->sa,
+			WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info));
+
 	if (assoc_rsp->statusCode != eSIR_MAC_SUCCESS_STATUS
 #ifdef WLAN_FEATURE_11W
 		&& (!session_entry->limRmfEnabled ||

+ 107 - 0
core/mac/src/pe/lim/lim_utils.c

@@ -7783,6 +7783,113 @@ error:
 }
 #endif
 
+/**
+ * lim_assoc_rej_get_remaining_delta() - Get remaining time delta for
+ * the rssi based disallowed list entry
+ * @node: rssi based disallowed list entry
+ *
+ * Return: remaining delta, can be -ve if time has already expired.
+ */
+static inline int
+lim_assoc_rej_get_remaining_delta(struct sir_rssi_disallow_lst *node)
+{
+	qdf_time_t cur_time;
+	uint32_t time_diff;
+
+	cur_time = qdf_do_div(qdf_get_monotonic_boottime(),
+				QDF_MC_TIMER_TO_MS_UNIT);
+	time_diff = cur_time - node->time_during_rejection;
+
+	return node->retry_delay - time_diff;
+}
+
+/**
+ * lim_assoc_rej_rem_entry_with_lowest_delta() - Remove the entry
+ * with lowest time delta
+ * @list: rssi based rejected BSSID list
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+lim_assoc_rej_rem_entry_with_lowest_delta(qdf_list_t *list)
+{
+	struct sir_rssi_disallow_lst *oldest_node = NULL;
+	struct sir_rssi_disallow_lst *cur_node;
+	qdf_list_node_t *cur_list = NULL;
+	qdf_list_node_t *next_list = NULL;
+
+	qdf_list_peek_front(list, &cur_list);
+	while (cur_list) {
+		cur_node = qdf_container_of(cur_list,
+			struct sir_rssi_disallow_lst, node);
+		if (!oldest_node ||
+		   (lim_assoc_rej_get_remaining_delta(oldest_node) >
+		    lim_assoc_rej_get_remaining_delta(cur_node)))
+			oldest_node = cur_node;
+
+		qdf_list_peek_next(list, cur_list, &next_list);
+		cur_list = next_list;
+		next_list = NULL;
+	}
+
+	if (oldest_node) {
+		pe_debug("remove node %pM with lowest delta %d",
+			oldest_node->bssid.bytes,
+			lim_assoc_rej_get_remaining_delta(oldest_node));
+		qdf_list_remove_node(list, &oldest_node->node);
+		qdf_mem_free(oldest_node);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	return QDF_STATUS_E_INVAL;
+}
+
+void lim_assoc_rej_add_to_rssi_based_reject_list(tpAniSirGlobal mac_ctx,
+	tDot11fTLVrssi_assoc_rej  *rssi_assoc_rej,
+	tSirMacAddr bssid, int8_t rssi)
+{
+	struct sir_rssi_disallow_lst *entry;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	entry = qdf_mem_malloc(sizeof(*entry));
+	if (!entry) {
+		pe_err("malloc failed for bssid entry");
+		return;
+	}
+
+	pe_debug("%pM: assoc resp rssi %d, delta rssi %d retry delay %d sec and list size %d",
+		bssid, rssi, rssi_assoc_rej->delta_rssi,
+		rssi_assoc_rej->retry_delay,
+		qdf_list_size(&mac_ctx->roam.rssi_disallow_bssid));
+
+	qdf_mem_copy(entry->bssid.bytes,
+		bssid, QDF_MAC_ADDR_SIZE);
+	entry->retry_delay = rssi_assoc_rej->retry_delay *
+		QDF_MC_TIMER_TO_MS_UNIT;
+	entry->expected_rssi = rssi + rssi_assoc_rej->delta_rssi;
+	entry->time_during_rejection =
+		qdf_do_div(qdf_get_monotonic_boottime(),
+		QDF_MC_TIMER_TO_MS_UNIT);
+
+	if (qdf_list_size(&mac_ctx->roam.rssi_disallow_bssid) >=
+		MAX_RSSI_AVOID_BSSID_LIST) {
+		status = lim_assoc_rej_rem_entry_with_lowest_delta(
+					&mac_ctx->roam.rssi_disallow_bssid);
+		if (QDF_IS_STATUS_ERROR(status))
+			pe_err("Failed to remove entry with lowest delta");
+	}
+
+	if (QDF_IS_STATUS_SUCCESS(status))
+		status = qdf_list_insert_back(
+				&mac_ctx->roam.rssi_disallow_bssid,
+				&entry->node);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Failed to enqueue bssid entry");
+		qdf_mem_free(entry);
+	}
+}
+
 void lim_decrement_pending_mgmt_count(tpAniSirGlobal mac_ctx)
 {
 	qdf_spin_lock(&mac_ctx->sys.bbt_mgmt_lock);

+ 18 - 0
core/mac/src/pe/lim/lim_utils.h

@@ -1078,6 +1078,24 @@ static inline QDF_STATUS lim_populate_he_mcs_set(tpAniSirGlobal mac_ctx,
 
 #endif
 
+/**
+ * lim_assoc_rej_add_to_rssi_based_reject_list() - Add BSSID to the rssi based
+ * rejection list
+ * @mac_ctx: mac ctx
+ * @rssi_assoc_rej: rssi assoc reject attribute
+ * @bssid : BSSID of the AP
+ * @rssi : RSSI of the assoc resp
+ *
+ * Add BSSID to the rssi based rejection list. Also if number
+ * of entries is greater than MAX_RSSI_AVOID_BSSID_LIST
+ * remove the entry with lowest time delta
+ *
+ * Return: void
+ */
+void lim_assoc_rej_add_to_rssi_based_reject_list(tpAniSirGlobal mac_ctx,
+	tDot11fTLVrssi_assoc_rej  *rssi_assoc_rej,
+	tSirMacAddr bssid, int8_t rssi);
+
 /**
  * lim_decrement_pending_mgmt_count: Decrement mgmt frame count
  * @mac_ctx: Pointer to global MAC structure

+ 7 - 0
core/mac/src/sys/legacy/src/utils/src/parser_api.c

@@ -2972,6 +2972,13 @@ sir_convert_assoc_resp_frame2_struct(tpAniSirGlobal pMac,
 			     sizeof(tDot11fIEvendor_he_op));
 	}
 
+	if (ar.MBO_IE.present && ar.MBO_IE.rssi_assoc_rej.present) {
+		qdf_mem_copy(&pAssocRsp->rssi_assoc_rej,
+				&ar.MBO_IE.rssi_assoc_rej,
+				sizeof(tDot11fTLVrssi_assoc_rej));
+		pe_debug("Received Assoc Response with rssi based assoc rej");
+	}
+
 	return eSIR_SUCCESS;
 
 } /* End sir_convert_assoc_resp_frame2_struct. */

+ 1 - 0
core/sme/inc/csr_internal.h

@@ -1009,6 +1009,7 @@ typedef struct tagCsrRoamStruct {
 	uint8_t *pReassocResp;          /* reassociation response from new AP */
 	uint16_t reassocRespLen;        /* length of reassociation response */
 	qdf_mc_timer_t packetdump_timer;
+	qdf_list_t rssi_disallow_bssid;
 } tCsrRoamStruct;
 
 #define GET_NEXT_ROAM_ID(pRoamStruct)  (((pRoamStruct)->nextRoamId + 1 == 0) ? \

+ 31 - 0
core/sme/src/csr/csr_api_roam.c

@@ -328,6 +328,8 @@ QDF_STATUS csr_open(tpAniSirGlobal pMac)
 			    (csr_ll_open(pMac->hHdd,
 					 &pMac->roam.peStatsReqList)))
 			break;
+		qdf_list_create(&pMac->roam.rssi_disallow_bssid,
+			MAX_RSSI_AVOID_BSSID_LIST);
 	} while (0);
 
 	return status;
@@ -379,12 +381,41 @@ QDF_STATUS csr_set_channels(tHalHandle hHal, tCsrConfigParam *pParam)
 	return status;
 }
 
+/**
+ * csr_assoc_rej_free_rssi_disallow_list() - Free the rssi diallowed
+ * BSSID entries and destroy the list
+ * @list: rssi based disallowed list entry
+ *
+ * Return: void
+ */
+static void csr_assoc_rej_free_rssi_disallow_list(qdf_list_t *list)
+{
+	QDF_STATUS status;
+	struct sir_rssi_disallow_lst *cur_node;
+	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
+
+	qdf_list_peek_front(list, &cur_lst);
+	while (cur_lst) {
+		qdf_list_peek_next(list, cur_lst, &next_lst);
+		cur_node = qdf_container_of(cur_lst,
+			struct sir_rssi_disallow_lst, node);
+		status = qdf_list_remove_node(list, cur_lst);
+		if (QDF_IS_STATUS_SUCCESS(status))
+			qdf_mem_free(cur_node);
+		cur_lst = next_lst;
+		next_lst = NULL;
+	}
+	qdf_list_destroy(list);
+}
+
 QDF_STATUS csr_close(tpAniSirGlobal pMac)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	tSmeCmd *saved_scan_cmd;
 
 	csr_roam_close(pMac);
+	csr_assoc_rej_free_rssi_disallow_list(
+		&pMac->roam.rssi_disallow_bssid);
 	csr_scan_close(pMac);
 	csr_ll_close(&pMac->roam.statsClientReqList);
 	csr_ll_close(&pMac->roam.peStatsReqList);

+ 127 - 0
core/sme/src/csr/csr_api_scan.c

@@ -5684,6 +5684,131 @@ static QDF_STATUS csr_parse_scan_list(tpAniSirGlobal mac_ctx,
 
 	return status;
 }
+
+/**
+ * csr_remove_ap_due_to_rssi() - check if bss is present in
+ * list of BSSID which rejected Assoc due to RSSI
+ * @list: rssi based rejected BSS list
+ * @bss_descr: pointer to bss description
+ *
+ * Check if the time interval indicated in last Assoc reject
+ * has expired OR rssi has improved by margin indicated
+ * in last Assoc reject. If any of the condition match remove
+ * the AP from the avoid list, else do not try to conenct
+ * to the AP
+ *
+ * Return: true if connection cannot be tried with AP else false
+ */
+static bool csr_remove_ap_due_to_rssi(qdf_list_t *list,
+	tSirBssDescription *bss_descr)
+{
+	QDF_STATUS status;
+	struct sir_rssi_disallow_lst *cur_node = NULL;
+	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
+	qdf_time_t cur_time;
+	uint32_t time_diff;
+
+	if (!qdf_list_size(list))
+		return false;
+
+	cur_time = qdf_do_div(qdf_get_monotonic_boottime(),
+		QDF_MC_TIMER_TO_MS_UNIT);
+
+	qdf_list_peek_front(list, &cur_lst);
+	while (cur_lst) {
+		cur_node = qdf_container_of(cur_lst,
+				struct sir_rssi_disallow_lst, node);
+
+		qdf_list_peek_next(list, cur_lst, &next_lst);
+
+		time_diff = cur_time - cur_node->time_during_rejection;
+		if ((time_diff > cur_node->retry_delay)) {
+			sme_debug("Remove %pM as time diff %d is greater retry delay %d",
+				cur_node->bssid.bytes, time_diff,
+				cur_node->retry_delay);
+			status = qdf_list_remove_node(list, cur_lst);
+			if (QDF_IS_STATUS_SUCCESS(status))
+				qdf_mem_free(cur_node);
+			cur_lst = next_lst;
+			next_lst = NULL;
+			cur_node = NULL;
+			continue;
+		}
+
+		if (!qdf_mem_cmp(cur_node->bssid.bytes,
+		    bss_descr->bssId, QDF_MAC_ADDR_SIZE))
+			break;
+		cur_lst = next_lst;
+		next_lst = NULL;
+		cur_node = NULL;
+	}
+
+	if (cur_node) {
+		time_diff = cur_time - cur_node->time_during_rejection;
+		if (!(time_diff > cur_node->retry_delay ||
+		   bss_descr->rssi_raw >= cur_node->expected_rssi)) {
+			sme_err("Don't Attempt to connect %pM (time diff %d retry delay %d rssi %d expected rssi %d)",
+				cur_node->bssid.bytes, time_diff,
+				cur_node->retry_delay, bss_descr->rssi_raw,
+				cur_node->expected_rssi);
+			return true;
+		}
+		sme_debug("Remove %pM as time diff %d is greater retry delay %d or RSSI %d is greater than expected %d",
+				cur_node->bssid.bytes, time_diff,
+				cur_node->retry_delay,
+				bss_descr->rssi_raw,
+				cur_node->expected_rssi);
+		status = qdf_list_remove_node(list, cur_lst);
+		if (QDF_IS_STATUS_SUCCESS(status))
+			qdf_mem_free(cur_node);
+	}
+
+	return false;
+}
+
+/**
+ * csr_filter_ap_due_to_rssi_reject() - filter the AP who has sent
+ * assoc reject due to RSSI if condition has not improved
+ * @mac_ctx: mac context
+ * @scan_list: candidate list for the connection
+ *
+ * Return: void
+ */
+static void csr_filter_ap_due_to_rssi_reject(tpAniSirGlobal mac_ctx,
+	tScanResultList *scan_list)
+{
+	tListElem *cur_entry;
+	tListElem *next_entry;
+	tCsrScanResult *scan_res;
+	bool remove;
+
+	if (!scan_list ||
+	   !qdf_list_size(&mac_ctx->roam.rssi_disallow_bssid))
+		return;
+
+	csr_ll_lock(&scan_list->List);
+
+	cur_entry = csr_ll_peek_head(&scan_list->List, LL_ACCESS_NOLOCK);
+	while (cur_entry) {
+		scan_res = GET_BASE_ADDR(cur_entry, tCsrScanResult,
+					Link);
+		next_entry = csr_ll_next(&scan_list->List,
+						cur_entry, LL_ACCESS_NOLOCK);
+		remove = csr_remove_ap_due_to_rssi(
+			&mac_ctx->roam.rssi_disallow_bssid,
+			&scan_res->Result.BssDescriptor);
+		if (remove) {
+			csr_ll_remove_entry(&scan_list->List,
+				cur_entry, LL_ACCESS_NOLOCK);
+			csr_free_scan_result_entry(mac_ctx, scan_res);
+		}
+		cur_entry = next_entry;
+		next_entry = NULL;
+	}
+	csr_ll_unlock(&scan_list->List);
+
+}
+
 QDF_STATUS csr_scan_get_result(tpAniSirGlobal mac_ctx,
 			       tCsrScanResultFilter *pFilter,
 			       tScanResultHandle *results)
@@ -5740,6 +5865,8 @@ QDF_STATUS csr_scan_get_result(tpAniSirGlobal mac_ctx,
 		/* Fail or No one wants the result. */
 		csr_scan_result_purge(mac_ctx, (tScanResultHandle) ret_list);
 	else {
+		if (pFilter)
+			csr_filter_ap_due_to_rssi_reject(mac_ctx, ret_list);
 		if (!csr_ll_count(&ret_list->List)) {
 			/* This mean that there is no match */
 			csr_ll_close(&ret_list->List);