Эх сурвалжийг харах

qcacmn: Update candidate list before try next

Some IOT APs only allow to connect if last 3 bytes of
BSSID and self MAC is same. They create a new bssid on
receiving unicast probe/auth req from STA and allow STA to
connect to this matching BSSID only. So boost the matching BSSID
to try to connect to this BSSID.
And add logic to refresh the candidate list before next
candidate try when the last candidate connect fail.

Change-Id: I482e122c8c9febbab42f64013fbb78c266f49655
CRs-Fixed: 3432618
Liangwei Dong 2 жил өмнө
parent
commit
3a759ca431

+ 11 - 0
qdf/inc/qdf_util.h

@@ -127,6 +127,17 @@ typedef __qdf_wait_queue_head_t qdf_wait_queue_head_t;
 	 (_a)[4] == 0xff &&        \
 	 (_a)[4] == 0xff &&        \
 	 (_a)[5] == 0xff)
 	 (_a)[5] == 0xff)
 
 
+/**
+ * QDF_IS_LAST_3_BYTES_OF_MAC_SAME - check the last 3 bytes
+ * same or not for two mac addresses
+ * @mac1: mac address 1
+ * @mac2: mac address 2
+ */
+#define QDF_IS_LAST_3_BYTES_OF_MAC_SAME(mac1, mac2) \
+	((mac1)->bytes[3] == (mac2)->bytes[3] && \
+	 (mac1)->bytes[4] == (mac2)->bytes[4] && \
+	 (mac1)->bytes[5] == (mac2)->bytes[5])
+
 /* Get number of bits from the index bit */
 /* Get number of bits from the index bit */
 #define QDF_GET_BITS(_val, _index, _num_bits) \
 #define QDF_GET_BITS(_val, _index, _num_bits) \
 		(((_val) >> (_index)) & ((1 << (_num_bits)) - 1))
 		(((_val) >> (_index)) & ((1 << (_num_bits)) - 1))

+ 48 - 1
umac/mlme/connection_mgr/core/src/wlan_cm_bss_scoring.c

@@ -2299,6 +2299,40 @@ bool cm_is_bad_rssi_entry(struct scan_cache_entry *scan_entry,
 
 
 	return false;
 	return false;
 }
 }
+
+/**
+ * cm_update_bss_score_for_mac_addr_matching() - boost score based on mac
+ * address matching
+ * @scan_entry: pointer to scan cache entry
+ * @self_mac: pointer to bssid to be matched
+ *
+ * Some IOT APs only allow to connect if last 3 bytes of BSSID
+ * and self MAC is same. They create a new bssid on receiving
+ * unicast probe/auth req from STA and allow STA to connect to
+ * this matching BSSID only. So boost the matching BSSID to try
+ * to connect to this BSSID.
+ *
+ * Return: void
+ */
+static void
+cm_update_bss_score_for_mac_addr_matching(struct scan_cache_node *scan_entry,
+					  struct qdf_mac_addr *self_mac)
+{
+	struct qdf_mac_addr *scan_entry_bssid;
+
+	if (!self_mac)
+		return;
+	scan_entry_bssid = &scan_entry->entry->bssid;
+	if (QDF_IS_LAST_3_BYTES_OF_MAC_SAME(
+		self_mac, scan_entry_bssid)) {
+		mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): boost bss score due to same last 3 byte match",
+				QDF_MAC_ADDR_REF(
+				scan_entry_bssid->bytes),
+				scan_entry->entry->channel.chan_freq);
+		scan_entry->entry->bss_score =
+			CM_BEST_CANDIDATE_MAX_BSS_SCORE;
+	}
+}
 #else
 #else
 static inline
 static inline
 bool cm_is_bad_rssi_entry(struct scan_cache_entry *scan_entry,
 bool cm_is_bad_rssi_entry(struct scan_cache_entry *scan_entry,
@@ -2308,12 +2342,19 @@ bool cm_is_bad_rssi_entry(struct scan_cache_entry *scan_entry,
 {
 {
 	return false;
 	return false;
 }
 }
+
+static void
+cm_update_bss_score_for_mac_addr_matching(struct scan_cache_node *scan_entry,
+					  struct qdf_mac_addr *self_mac)
+{
+}
 #endif
 #endif
 
 
 void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev,
 void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev,
 				 struct pcl_freq_weight_list *pcl_lst,
 				 struct pcl_freq_weight_list *pcl_lst,
 				 qdf_list_t *scan_list,
 				 qdf_list_t *scan_list,
-				 struct qdf_mac_addr *bssid_hint)
+				 struct qdf_mac_addr *bssid_hint,
+				 struct qdf_mac_addr *self_mac)
 {
 {
 	struct scan_cache_node *scan_entry;
 	struct scan_cache_node *scan_entry;
 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
@@ -2410,8 +2451,14 @@ void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev,
 					scan_entry->entry->channel.chan_freq,
 					scan_entry->entry->channel.chan_freq,
 					scan_entry->entry->rssi_raw,
 					scan_entry->entry->rssi_raw,
 					scan_entry->entry->bss_score);
 					scan_entry->entry->bss_score);
+		} else {
+			mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): denylist_action %d",
+					QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes),
+					scan_entry->entry->channel.chan_freq,
+					denylist_action);
 		}
 		}
 
 
+		cm_update_bss_score_for_mac_addr_matching(scan_entry, self_mac);
 		/*
 		/*
 		 * The below logic is added to select the best candidate
 		 * The below logic is added to select the best candidate
 		 * amongst the denylisted candidates. This is done to
 		 * amongst the denylisted candidates. This is done to

+ 131 - 12
umac/mlme/connection_mgr/core/src/wlan_cm_connect.c

@@ -1319,9 +1319,12 @@ static QDF_STATUS cm_update_mlo_filter(struct wlan_objmgr_pdev *pdev,
 }
 }
 #endif
 #endif
 
 
-static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev,
-					    struct cnx_mgr *cm_ctx,
-					    struct cm_connect_req *cm_req)
+static QDF_STATUS
+cm_connect_fetch_candidates(struct wlan_objmgr_pdev *pdev,
+			    struct cnx_mgr *cm_ctx,
+			    struct cm_connect_req *cm_req,
+			    qdf_list_t **fetched_candidate_list,
+			    uint32_t *num_bss_found)
 {
 {
 	struct scan_filter *filter;
 	struct scan_filter *filter;
 	uint32_t num_bss = 0;
 	uint32_t num_bss = 0;
@@ -1331,10 +1334,6 @@ static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev,
 	bool security_valid_for_6ghz;
 	bool security_valid_for_6ghz;
 	const uint8_t *rsnxe;
 	const uint8_t *rsnxe;
 
 
-	filter = qdf_mem_malloc(sizeof(*filter));
-	if (!filter)
-		return QDF_STATUS_E_NOMEM;
-
 	rsnxe = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSNXE,
 	rsnxe = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSNXE,
 					 cm_req->req.assoc_ie.ptr,
 					 cm_req->req.assoc_ie.ptr,
 					 cm_req->req.assoc_ie.len);
 					 cm_req->req.assoc_ie.len);
@@ -1356,6 +1355,10 @@ static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev,
 			  cm_req->req.chan_freq);
 			  cm_req->req.chan_freq);
 		return QDF_STATUS_E_INVAL;
 		return QDF_STATUS_E_INVAL;
 	}
 	}
+	filter = qdf_mem_malloc(sizeof(*filter));
+	if (!filter)
+		return QDF_STATUS_E_NOMEM;
+
 	cm_connect_prepare_scan_filter(pdev, cm_ctx, cm_req, filter,
 	cm_connect_prepare_scan_filter(pdev, cm_ctx, cm_req, filter,
 				       security_valid_for_6ghz);
 				       security_valid_for_6ghz);
 
 
@@ -1367,7 +1370,7 @@ static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev,
 		mlme_debug(CM_PREFIX_FMT "num_entries found %d",
 		mlme_debug(CM_PREFIX_FMT "num_entries found %d",
 			   CM_PREFIX_REF(vdev_id, cm_req->cm_id), num_bss);
 			   CM_PREFIX_REF(vdev_id, cm_req->cm_id), num_bss);
 	}
 	}
-
+	*num_bss_found = num_bss;
 	op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev);
 	op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev);
 	if (num_bss && op_mode == QDF_STA_MODE &&
 	if (num_bss && op_mode == QDF_STA_MODE &&
 	    !cm_req->req.is_non_assoc_link)
 	    !cm_req->req.is_non_assoc_link)
@@ -1375,8 +1378,27 @@ static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev,
 	qdf_mem_free(filter);
 	qdf_mem_free(filter);
 
 
 	if (!candidate_list || !qdf_list_size(candidate_list)) {
 	if (!candidate_list || !qdf_list_size(candidate_list)) {
-		QDF_STATUS status;
+		if (candidate_list)
+			wlan_scan_purge_results(candidate_list);
+		return QDF_STATUS_E_EMPTY;
+	}
+	*fetched_candidate_list = candidate_list;
+
+	return QDF_STATUS_SUCCESS;
+}
 
 
+static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev,
+					    struct cnx_mgr *cm_ctx,
+					    struct cm_connect_req *cm_req)
+{
+	uint32_t num_bss = 0;
+	qdf_list_t *candidate_list = NULL;
+	uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
+	QDF_STATUS status;
+
+	status = cm_connect_fetch_candidates(pdev, cm_ctx, cm_req,
+					     &candidate_list, &num_bss);
+	if (QDF_IS_STATUS_ERROR(status)) {
 		if (candidate_list)
 		if (candidate_list)
 			wlan_scan_purge_results(candidate_list);
 			wlan_scan_purge_results(candidate_list);
 		mlme_info(CM_PREFIX_FMT "no valid candidate found, num_bss %d scan_id %d",
 		mlme_info(CM_PREFIX_FMT "no valid candidate found, num_bss %d scan_id %d",
@@ -1406,8 +1428,99 @@ static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev,
 	}
 	}
 	cm_req->candidate_list = candidate_list;
 	cm_req->candidate_list = candidate_list;
 
 
-	return QDF_STATUS_SUCCESS;
+	return status;
+}
+
+#ifdef CONN_MGR_ADV_FEATURE
+static void cm_update_candidate_list(struct cnx_mgr *cm_ctx,
+				     struct cm_connect_req *cm_req,
+				     struct scan_cache_node *prev_candidate)
+{
+	struct wlan_objmgr_pdev *pdev;
+	uint32_t num_bss = 0;
+	qdf_list_t *candidate_list = NULL;
+	uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
+	QDF_STATUS status;
+	struct scan_cache_node *scan_entry;
+	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
+	struct qdf_mac_addr *bssid;
+	bool found;
+
+	pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
+	if (!pdev) {
+		mlme_err(CM_PREFIX_FMT "Failed to find pdev",
+			 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
+		return;
+	}
+
+	status = cm_connect_fetch_candidates(pdev, cm_ctx, cm_req,
+					     &candidate_list, &num_bss);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_debug(CM_PREFIX_FMT "failed to fetch bss: %d",
+			   CM_PREFIX_REF(vdev_id, cm_req->cm_id), num_bss);
+		goto free_list;
+	}
+
+	if (qdf_list_peek_front(candidate_list, &cur_node) !=
+					QDF_STATUS_SUCCESS) {
+		mlme_err(CM_PREFIX_FMT"failed to peer front of candidate_list",
+			 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
+		goto free_list;
+	}
+
+	while (cur_node) {
+		qdf_list_peek_next(candidate_list, cur_node, &next_node);
+
+		scan_entry = qdf_container_of(cur_node, struct scan_cache_node,
+					      node);
+		bssid = &scan_entry->entry->bssid;
+		if (qdf_is_macaddr_zero(bssid) ||
+		    qdf_is_macaddr_broadcast(bssid))
+			goto next;
+		found = cm_find_bss_from_candidate_list(cm_req->candidate_list,
+							bssid, NULL);
+		if (found)
+			goto next;
+		status = qdf_list_remove_node(candidate_list, cur_node);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			mlme_err(CM_PREFIX_FMT"failed to remove node for BSS "QDF_MAC_ADDR_FMT" from candidate list",
+				 CM_PREFIX_REF(vdev_id, cm_req->cm_id),
+				 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes));
+			goto free_list;
+		}
+
+		status = qdf_list_insert_after(cm_req->candidate_list,
+					       &scan_entry->node,
+					       &prev_candidate->node);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			mlme_err(CM_PREFIX_FMT"failed to insert node for BSS "QDF_MAC_ADDR_FMT" from candidate list",
+				 CM_PREFIX_REF(vdev_id, cm_req->cm_id),
+				 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes));
+			util_scan_free_cache_entry(scan_entry->entry);
+			qdf_mem_free(scan_entry);
+			goto free_list;
+		}
+		prev_candidate = scan_entry;
+		mlme_debug(CM_PREFIX_FMT"insert new node BSS "QDF_MAC_ADDR_FMT" to existing candidate list",
+			   CM_PREFIX_REF(vdev_id, cm_req->cm_id),
+			   QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes));
+next:
+		cur_node = next_node;
+		next_node = NULL;
+	}
+
+free_list:
+	if (candidate_list)
+		wlan_scan_purge_results(candidate_list);
 }
 }
+#else
+static inline void
+cm_update_candidate_list(struct cnx_mgr *cm_ctx,
+			 struct cm_connect_req *cm_req,
+			 struct scan_cache_node *prev_candidate)
+{
+}
+#endif
 
 
 QDF_STATUS cm_if_mgr_inform_connect_complete(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS cm_if_mgr_inform_connect_complete(struct wlan_objmgr_vdev *vdev,
 					     QDF_STATUS connect_status)
 					     QDF_STATUS connect_status)
@@ -1683,12 +1796,18 @@ static QDF_STATUS cm_get_valid_candidate(struct cnx_mgr *cm_ctx,
 	 * Get next candidate if prev_candidate is not NULL, else get
 	 * Get next candidate if prev_candidate is not NULL, else get
 	 * the first candidate
 	 * the first candidate
 	 */
 	 */
-	if (prev_candidate)
+	if (prev_candidate) {
+		/* Fetch new candidate list and append new entries to the
+		 * current candidate list.
+		 */
+		cm_update_candidate_list(cm_ctx, &cm_req->connect_req,
+					 prev_candidate);
 		qdf_list_peek_next(cm_req->connect_req.candidate_list,
 		qdf_list_peek_next(cm_req->connect_req.candidate_list,
 				   &prev_candidate->node, &cur_node);
 				   &prev_candidate->node, &cur_node);
-	else
+	} else {
 		qdf_list_peek_front(cm_req->connect_req.candidate_list,
 		qdf_list_peek_front(cm_req->connect_req.candidate_list,
 				    &cur_node);
 				    &cur_node);
+	}
 
 
 	while (cur_node) {
 	while (cur_node) {
 		qdf_list_peek_next(cm_req->connect_req.candidate_list,
 		qdf_list_peek_next(cm_req->connect_req.candidate_list,

+ 1 - 1
umac/mlme/connection_mgr/core/src/wlan_cm_main.h

@@ -29,7 +29,7 @@
 #include <wlan_cm_public_struct.h>
 #include <wlan_cm_public_struct.h>
 
 
 /* Max candidate/attempts to be tried to connect */
 /* Max candidate/attempts to be tried to connect */
-#define CM_MAX_CONNECT_ATTEMPTS 5
+#define CM_MAX_CONNECT_ATTEMPTS 10
 /*
 /*
  * Default connect timeout to consider 3 sec join timeout + 5 sec auth timeout +
  * Default connect timeout to consider 3 sec join timeout + 5 sec auth timeout +
  * 2 sec assoc timeout + 5 sec buffer for vdev related timeouts.
  * 2 sec assoc timeout + 5 sec buffer for vdev related timeouts.

+ 12 - 0
umac/mlme/connection_mgr/core/src/wlan_cm_main_api.h

@@ -305,6 +305,18 @@ cm_send_connect_start_fail(struct cnx_mgr *cm_ctx,
 			   struct cm_connect_req *req,
 			   struct cm_connect_req *req,
 			   enum wlan_cm_connect_fail_reason reason);
 			   enum wlan_cm_connect_fail_reason reason);
 
 
+/**
+ * cm_find_bss_from_candidate_list() - get bss entry by bssid value
+ * @candidate_list: candidate list
+ * @bssid: bssid to find
+ * @entry_found: found bss entry
+ *
+ * Return: true if find bss entry with bssid
+ */
+bool cm_find_bss_from_candidate_list(qdf_list_t *candidate_list,
+				     struct qdf_mac_addr *bssid,
+				     struct scan_cache_node **entry_found);
+
 #ifdef WLAN_POLICY_MGR_ENABLE
 #ifdef WLAN_POLICY_MGR_ENABLE
 /**
 /**
  * cm_hw_mode_change_resp() - HW mode change response
  * cm_hw_mode_change_resp() - HW mode change response

+ 45 - 2
umac/mlme/connection_mgr/core/src/wlan_cm_util.c

@@ -1373,6 +1373,46 @@ void cm_fill_ml_partner_info(struct wlan_cm_connect_req *req,
 }
 }
 #endif
 #endif
 
 
+bool cm_find_bss_from_candidate_list(qdf_list_t *candidate_list,
+				     struct qdf_mac_addr *bssid,
+				     struct scan_cache_node **entry_found)
+{
+	struct scan_cache_node *scan_entry;
+	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
+	struct qdf_mac_addr *bssid2;
+
+	if (qdf_is_macaddr_zero(bssid) ||
+	    qdf_is_macaddr_broadcast(bssid))
+		return false;
+
+	if (qdf_list_peek_front(candidate_list, &cur_node) !=
+					QDF_STATUS_SUCCESS) {
+		mlme_err("failed to peer front of candidate_list");
+		return false;
+	}
+
+	while (cur_node) {
+		qdf_list_peek_next(candidate_list, cur_node, &next_node);
+
+		scan_entry = qdf_container_of(cur_node, struct scan_cache_node,
+					      node);
+		bssid2 = &scan_entry->entry->bssid;
+		if (qdf_is_macaddr_zero(bssid2))
+			goto next;
+
+		if (qdf_is_macaddr_equal(bssid, bssid2)) {
+			if (entry_found)
+				*entry_found = scan_entry;
+			return true;
+		}
+next:
+		cur_node = next_node;
+		next_node = NULL;
+	}
+
+	return false;
+}
+
 bool cm_is_connect_req_reassoc(struct wlan_cm_connect_req *req)
 bool cm_is_connect_req_reassoc(struct wlan_cm_connect_req *req)
 {
 {
 	if (!qdf_is_macaddr_zero(&req->prev_bssid) &&
 	if (!qdf_is_macaddr_zero(&req->prev_bssid) &&
@@ -1566,7 +1606,9 @@ void cm_calculate_scores(struct cnx_mgr *cm_ctx,
 			pcl_lst = NULL;
 			pcl_lst = NULL;
 		}
 		}
 	}
 	}
-	wlan_cm_calculate_bss_score(pdev, pcl_lst, list, &filter->bssid_hint);
+	wlan_cm_calculate_bss_score(pdev, pcl_lst, list, &filter->bssid_hint,
+				    (struct qdf_mac_addr *)
+				    wlan_vdev_mlme_get_macaddr(cm_ctx->vdev));
 	if (pcl_lst)
 	if (pcl_lst)
 		qdf_mem_free(pcl_lst);
 		qdf_mem_free(pcl_lst);
 }
 }
@@ -1576,7 +1618,8 @@ void cm_calculate_scores(struct cnx_mgr *cm_ctx,
 			 struct wlan_objmgr_pdev *pdev,
 			 struct wlan_objmgr_pdev *pdev,
 			 struct scan_filter *filter, qdf_list_t *list)
 			 struct scan_filter *filter, qdf_list_t *list)
 {
 {
-	wlan_cm_calculate_bss_score(pdev, NULL, list, &filter->bssid_hint);
+	wlan_cm_calculate_bss_score(pdev, NULL, list, &filter->bssid_hint,
+				    NULL);
 
 
 	/*
 	/*
 	 * Custom sorting if enabled
 	 * Custom sorting if enabled

+ 3 - 1
umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_bss_score_param.h

@@ -329,13 +329,15 @@ wlan_denylist_action_on_bssid(struct wlan_objmgr_pdev *pdev,
  * @scan_list: scan list, contains the input list and after the
  * @scan_list: scan list, contains the input list and after the
  *             func it will have sorted list
  *             func it will have sorted list
  * @bssid_hint: bssid hint
  * @bssid_hint: bssid hint
+ * @self_mac: connecting vdev self mac address
  *
  *
  * Return: void
  * Return: void
  */
  */
 void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev,
 void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev,
 				 struct pcl_freq_weight_list *pcl_lst,
 				 struct pcl_freq_weight_list *pcl_lst,
 				 qdf_list_t *scan_list,
 				 qdf_list_t *scan_list,
-				 struct qdf_mac_addr *bssid_hint);
+				 struct qdf_mac_addr *bssid_hint,
+				 struct qdf_mac_addr *self_mac);
 
 
 /**
 /**
  * wlan_cm_init_score_config() - Init score INI and config
  * wlan_cm_init_score_config() - Init score INI and config