Browse Source

qcacld-3.0: Multi link to single link connection

if probe response does not have ml ie element,
compare join request partner link info with scan db.
If join request info does not match scan db partner info
clear the partner link info in join request.

Change-Id: I0c63c543744c926502af5238f38d41460857ea98
CRs-Fixed: 3376313
sandhu 2 years ago
parent
commit
23a74529b0
1 changed files with 189 additions and 16 deletions
  1. 189 16
      core/mac/src/pe/lim/lim_api.c

+ 189 - 16
core/mac/src/pe/lim/lim_api.c

@@ -3684,7 +3684,7 @@ lim_match_link_info(uint8_t req_link_id,
 	return false;
 }
 
-static void
+static QDF_STATUS
 lim_add_bcn_probe(struct wlan_objmgr_vdev *vdev, uint8_t *bcn_probe,
 		  uint32_t len, qdf_freq_t freq, int32_t rssi)
 {
@@ -3694,18 +3694,19 @@ lim_add_bcn_probe(struct wlan_objmgr_vdev *vdev, uint8_t *bcn_probe,
 	struct mgmt_rx_event_params rx_param = {0};
 	struct wlan_frame_hdr *hdr;
 	enum mgmt_frame_type frm_type = MGMT_BEACON;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
 	vdev_id = wlan_vdev_get_id(vdev);
 	if (!bcn_probe || !len || (len < sizeof(*hdr))) {
 		pe_err("bcn_probe is null or invalid len %d",
 		       len);
-		return;
+		return QDF_STATUS_E_FAILURE;
 	}
 
 	pdev = wlan_vdev_get_pdev(vdev);
 	if (!pdev) {
 		pe_err("Failed to find pdev");
-		return;
+		return QDF_STATUS_E_FAILURE;
 	}
 
 	hdr = (struct wlan_frame_hdr *)bcn_probe;
@@ -3723,7 +3724,7 @@ lim_add_bcn_probe(struct wlan_objmgr_vdev *vdev, uint8_t *bcn_probe,
 
 	buf = qdf_nbuf_alloc(NULL, qdf_roundup(len, 4), 0, 4, false);
 	if (!buf)
-		return;
+		return QDF_STATUS_E_FAILURE;
 
 	qdf_nbuf_put_tail(buf, len);
 	qdf_nbuf_set_protocol(buf, ETH_P_CONTROL);
@@ -3733,8 +3734,10 @@ lim_add_bcn_probe(struct wlan_objmgr_vdev *vdev, uint8_t *bcn_probe,
 
 	pe_debug("MLO: add prb rsp to scan db");
 	/* buf will be freed by scan module in error or success case */
-	wlan_scan_process_bcn_probe_rx_sync(wlan_pdev_get_psoc(pdev), buf,
-					    &rx_param, frm_type);
+	status = wlan_scan_process_bcn_probe_rx_sync(wlan_pdev_get_psoc(pdev), buf,
+			&rx_param, frm_type);
+
+	return status;
 }
 
 #ifdef WLAN_FEATURE_11BE_MLO
@@ -3819,11 +3822,139 @@ lim_clear_ml_partner_info(struct pe_session *session_entry)
 	}
 	partner_info->num_partner_links = 0;
 }
+
+static QDF_STATUS
+lim_compare_scan_entry_partner_info_with_join_req(struct mlo_partner_info
+						  *partner_info,
+						  struct partner_link_info
+						  *partner_link)
+{
+	int i;
+	int j;
+	struct mlo_link_info *partner_link_info;
+	struct partner_link_info *scan_info;
+	int num_matching_links = 0;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		partner_link_info = &partner_info->partner_link_info[i];
+		for (j = 0; j < MLD_MAX_LINKS - 1; j++) {
+			scan_info = &partner_link[j];
+			if (!scan_info)
+				continue;
+			/*
+			 * do not compare if both have freq as zero
+			 */
+			if (scan_info->freq == 0)
+				continue;
+
+			if (scan_info->freq == partner_link_info->chan_freq) {
+				qdf_mem_cmp(partner_link_info->link_addr.bytes,
+					    scan_info->link_addr.bytes,
+					    QDF_MAC_ADDR_SIZE);
+				num_matching_links += 1;
+			}
+		}
+	}
+
+	if (partner_info->num_partner_links == num_matching_links) {
+		pe_debug("num of matching partner links %d",
+			 num_matching_links);
+		status = QDF_STATUS_SUCCESS;
+	}
+
+	return status;
+}
+
+static QDF_STATUS
+lim_check_scan_db_for_join_req_partner_info(struct pe_session *session_entry,
+					    struct mac_context *mac_ctx)
+{
+	struct join_req *lim_join_req;
+	struct wlan_objmgr_pdev *pdev;
+	struct partner_link_info *partner_link = NULL;
+	struct qdf_mac_addr qdf_bssid;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct mlo_partner_info *partner_info;
+	uint16_t join_req_freq = 0;
+	struct scan_cache_entry cache_entry;
+
+	if (!session_entry) {
+		pe_err("session entry is NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	if (!mac_ctx) {
+		pe_err("mac context is NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	lim_join_req = session_entry->lim_join_req;
+	if (!lim_join_req) {
+		pe_err("join req is NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	pdev = mac_ctx->pdev;
+	if (!pdev) {
+		pe_err("pdev is NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	partner_link = qdf_mem_malloc(sizeof(struct partner_link_info) *
+			(MLD_MAX_LINKS - 1));
+
+	if (!partner_link)
+		return QDF_STATUS_E_FAILURE;
+
+	qdf_mem_copy(&qdf_bssid,
+		     &(lim_join_req->bssDescription.bssId),
+		     QDF_MAC_ADDR_SIZE);
+
+	join_req_freq = lim_join_req->bssDescription.chan_freq;
+
+	status = wlan_scan_get_scan_entry_by_mac_freq(pdev,
+						      &qdf_bssid,
+						      join_req_freq,
+						      &cache_entry);
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		pe_err("failed to get partner link info by mac addr");
+		status = QDF_STATUS_E_FAILURE;
+		goto free_mem;
+	}
+
+	qdf_mem_copy(partner_link, cache_entry.ml_info.link_info,
+		     sizeof(struct partner_link_info) * (MLD_MAX_LINKS - 1));
+
+	partner_info = &lim_join_req->partner_info;
+
+	status = lim_compare_scan_entry_partner_info_with_join_req(
+			partner_info, partner_link);
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		pe_err("failed to match num of partner links in scan entry");
+		status = QDF_STATUS_E_FAILURE;
+		goto free_mem;
+	}
+
+free_mem:
+	qdf_mem_free(partner_link);
+	return status;
+}
 #else
 static inline void
 lim_clear_ml_partner_info(struct pe_session *session_entry)
 {
 }
+
+static QDF_STATUS
+lim_check_db_for_join_req_partner_info(struct pe_session *session_entry,
+				       struct mac_context *mac_ctx)
+{
+
+	return QDF_STATUS_E_FAILURE;
+}
 #endif
 
 QDF_STATUS lim_check_for_ml_probe_req(struct pe_session *session)
@@ -3847,7 +3978,7 @@ lim_gen_link_specific_probe_rsp(struct mac_context *mac_ctx,
 {
 	struct element_info link_probe_rsp = {0};
 	struct qdf_mac_addr sta_link_addr;
-	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	struct mlo_link_info *link_info = NULL;
 	struct mlo_partner_info *partner_info;
 	uint8_t chan;
@@ -3876,8 +4007,12 @@ lim_gen_link_specific_probe_rsp(struct mac_context *mac_ctx,
 							  probe_rsp_len);
 
 		if (QDF_IS_STATUS_ERROR(status)) {
-			lim_clear_ml_partner_info(session_entry);
-			goto end;
+			if(QDF_IS_STATUS_ERROR(
+				lim_check_scan_db_for_join_req_partner_info(
+						session_entry,
+						mac_ctx)))
+				lim_clear_ml_partner_info(session_entry);
+			return status;
 		}
 
 		/*
@@ -3896,8 +4031,14 @@ lim_gen_link_specific_probe_rsp(struct mac_context *mac_ctx,
 		gen_frame_len = MAX_MGMT_MPDU_LEN;
 
 		link_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len);
-		if (!link_probe_rsp.ptr)
+		if (!link_probe_rsp.ptr) {
+			if(QDF_IS_STATUS_ERROR(
+				lim_check_scan_db_for_join_req_partner_info(
+					session_entry,
+					mac_ctx)))
+				lim_clear_ml_partner_info(session_entry);
 			return QDF_STATUS_E_NOMEM;
+		}
 
 		qdf_mem_copy(&sta_link_addr, session_entry->self_mac_addr,
 			     QDF_MAC_ADDR_SIZE);
@@ -3909,11 +4050,17 @@ lim_gen_link_specific_probe_rsp(struct mac_context *mac_ctx,
 				(qdf_size_t *)&link_probe_rsp.len);
 
 		if (QDF_IS_STATUS_ERROR(status)) {
-			pe_err("MLO: Link probe response generation failed %d", status);
-			lim_clear_ml_partner_info(session_entry);
-			status = QDF_STATUS_E_FAILURE;
+			pe_err("MLO: Link probe response generation failed %d",
+					status);
+			if(QDF_IS_STATUS_ERROR(
+				lim_check_scan_db_for_join_req_partner_info(
+					session_entry,
+					mac_ctx)))
+				lim_clear_ml_partner_info(session_entry);
+
 			goto end;
 		}
+
 		pe_debug("MLO: link probe rsp size:%u original probe rsp :%u",
 			 link_probe_rsp.len, probe_rsp_len);
 
@@ -3932,15 +4079,41 @@ lim_gen_link_specific_probe_rsp(struct mac_context *mac_ctx,
 			pe_err("Invalid link id %d link mac: " QDF_MAC_ADDR_FMT,
 			       link_info->link_id,
 			       QDF_MAC_ADDR_REF(link_info->link_addr.bytes));
+			if(QDF_IS_STATUS_ERROR(
+				lim_check_scan_db_for_join_req_partner_info(
+					session_entry,
+					mac_ctx)))
+				lim_clear_ml_partner_info(session_entry);
+
 			status = QDF_STATUS_E_FAILURE;
 			goto end;
 		}
 		chan_freq = wlan_reg_chan_opclass_to_freq(chan, op_class,
 							  true);
 
-		lim_add_bcn_probe(session_entry->vdev, link_probe_rsp.ptr,
-				  link_probe_rsp.len,
-				  chan_freq, rssi);
+		status = lim_add_bcn_probe(session_entry->vdev,
+				link_probe_rsp.ptr,
+				link_probe_rsp.len,
+				chan_freq, rssi);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pe_err("failed to add bcn probe %d", status);
+			if(QDF_IS_STATUS_ERROR(
+				lim_check_scan_db_for_join_req_partner_info(
+					session_entry,
+					mac_ctx)))
+				lim_clear_ml_partner_info(session_entry);
+
+			goto end;
+		}
+	} else if (session_entry->lim_join_req->is_ml_probe_req_sent &&
+			!rcvd_probe_resp->mlo_ie.mlo_ie_present) {
+		if(QDF_IS_STATUS_ERROR(lim_check_scan_db_for_join_req_partner_info(
+						session_entry,
+						mac_ctx)))
+				lim_clear_ml_partner_info(session_entry);
+
+		status = QDF_STATUS_E_FAILURE;
+		return status;
 	} else {
 		return status;
 	}