浏览代码

qcacld-3.0: Handle STA + TDLS + P2P CLI concurrencies

When P2P CLI is connected first and then STA is connected,
disable TDLS on existing interface and enable TDLS on the STA
vdev.

When existing STA + TDLS exists, disable off channel when P2P
connection is started and re-enable off channel for TDLS once
connection is complete. Don't teardown TDLS peers once the
P2P client connection is successful.

Change-Id: I91d152a3a052706289c06cebc932c84a69fdbc00
CRs-Fixed: 3455639
Pragaspathi Thilagaraj 2 年之前
父节点
当前提交
9e24d820d4

+ 6 - 0
components/cmn_services/interface_mgr/src/wlan_if_mgr_sap.c

@@ -31,6 +31,7 @@
 #include "wlan_mlme_vdev_mgr_interface.h"
 #include "wlan_p2p_ucfg_api.h"
 #include "wlan_vdev_mgr_utils_api.h"
+#include "wlan_tdls_tgt_api.h"
 
 QDF_STATUS if_mgr_ap_start_bss(struct wlan_objmgr_vdev *vdev,
 			       struct if_mgr_event_data *event_data)
@@ -113,6 +114,11 @@ if_mgr_ap_start_bss_complete(struct wlan_objmgr_vdev *vdev,
 	ifmgr_debug("check for SAP restart");
 	policy_mgr_check_concurrent_intf_and_restart_sap(psoc,
 				wlan_util_vdev_mgr_get_acs_mode_for_vdev(vdev));
+	/*
+	 * Enable TDLS again on concurrent STA
+	 */
+	if (event_data && QDF_IS_STATUS_ERROR(event_data->status))
+		wlan_tdls_notify_start_bss_failure(psoc);
 
 	return QDF_STATUS_SUCCESS;
 }

+ 60 - 6
components/tdls/core/src/wlan_tdls_main.c

@@ -1656,18 +1656,40 @@ tdls_process_sta_disconnect(struct tdls_sta_notify_params *notify)
 QDF_STATUS tdls_notify_sta_disconnect(struct tdls_sta_notify_params *notify)
 {
 	QDF_STATUS status;
+	struct wlan_objmgr_vdev *vdev;
+	enum QDF_OPMODE opmode;
+	struct wlan_objmgr_psoc *psoc;
+	uint8_t sta_count;
 
 	if (!notify) {
 		tdls_err("invalid param");
 		return QDF_STATUS_E_INVAL;
 	}
 
-	if (!notify->vdev) {
+	vdev = notify->vdev;
+	if (!vdev) {
 		tdls_err("invalid param");
 		qdf_mem_free(notify);
 		return QDF_STATUS_E_INVAL;
 	}
 
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID);
+		qdf_mem_free(notify);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	opmode = wlan_vdev_mlme_get_opmode(vdev);
+	sta_count = policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE,
+							      NULL);
+	if (opmode == QDF_P2P_CLIENT_MODE && sta_count) {
+		tdls_debug("STA + P2P concurrency. No action on P2P vdev");
+		wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID);
+		qdf_mem_free(notify);
+		return QDF_STATUS_E_INVAL;
+	}
+
 	status = tdls_process_sta_disconnect(notify);
 
 	wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID);
@@ -1750,6 +1772,7 @@ QDF_STATUS tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+static
 QDF_STATUS tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc,
 					    uint8_t vdev_id)
 {
@@ -1762,13 +1785,10 @@ QDF_STATUS tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc,
 	if (!indication)
 		return QDF_STATUS_E_NULL_VALUE;
 
-	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
-						    vdev_id,
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
 						    WLAN_TDLS_SB_ID);
-
 	if (!vdev) {
-		tdls_err("vdev not exist for the session id %d",
-			 vdev_id);
+		tdls_err("vdev:%d does not exist", vdev_id);
 		qdf_mem_free(indication);
 		return QDF_STATUS_E_INVAL;
 	}
@@ -1793,6 +1813,40 @@ QDF_STATUS tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS
+tdls_check_and_indicate_delete_all_peers(struct wlan_objmgr_psoc *psoc,
+					 uint8_t vdev_id)
+{
+	struct wlan_objmgr_pdev *pdev;
+	uint32_t pdev_id;
+	enum QDF_OPMODE opmode;
+	uint8_t sta_count =
+		policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE,
+							  NULL);
+
+	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TDLS_SB_ID);
+	if (pdev_id == WLAN_INVALID_PDEV_ID) {
+		tdls_debug("Invalid pdev id");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TDLS_SB_ID);
+	if (!pdev) {
+		tdls_debug("pdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	opmode = wlan_get_opmode_from_vdev_id(pdev, vdev_id);
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_TDLS_SB_ID);
+
+	if (opmode == QDF_P2P_CLIENT_MODE && sta_count) {
+		tdls_debug("STA + P2P concurrency. No action on P2P vdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return tdls_delete_all_peers_indication(psoc, vdev_id);
+}
+
 /**
  * tdls_set_mode_in_vdev() - set TDLS mode
  * @tdls_vdev: tdls vdev object

+ 8 - 6
components/tdls/core/src/wlan_tdls_main.h

@@ -840,17 +840,19 @@ QDF_STATUS tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc,
 				     struct tdls_channel_switch_params *param);
 
 /**
- * tdls_delete_all_peers_indication() - update tdls status info
+ * tdls_check_and_indicate_delete_all_peers() - Check if delete all peers is
+ * allowed for the vdev based on current concurrency.
  * @psoc: soc object
  * @vdev_id: vdev id
  *
- * Notify tdls component to cleanup all peers
+ * Notify tdls component to cleanup all peers based on current concurrency
+ * combination.
  *
- * Return: QDF_STATUS.
+ * Return: QDF_STATUS
  */
-
-QDF_STATUS tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc,
-					    uint8_t vdev_id);
+QDF_STATUS
+tdls_check_and_indicate_delete_all_peers(struct wlan_objmgr_psoc *psoc,
+					 uint8_t vdev_id);
 
 /**
  * tdls_get_opclass_from_bandwidth() - Return opclass for corresponding BW and

+ 51 - 2
components/tdls/core/src/wlan_tdls_peer.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -29,6 +29,7 @@
 #include <wlan_policy_mgr_api.h>
 #include "wlan_reg_ucfg_api.h"
 #include <host_diag_core_event.h>
+#include "wlan_policy_mgr_api.h"
 
 static uint8_t calculate_hash_key(const uint8_t *macaddr)
 {
@@ -574,6 +575,46 @@ static void tdls_get_wifi_hal_state(struct tdls_peer *peer, uint32_t *state,
 	}
 }
 
+#ifdef WLAN_FEATURE_TDLS_CONCURRENCIES
+/**
+ * tdls_get_allowed_off_channel_for_concurrency() - Get allowed off-channel
+ * frequency based on current concurrency. Return 0 if all frequencies are
+ * allowed
+ * @pdev: Pointer to PDEV object
+ * @vdev: Pointer to vdev object
+ *
+ * Return: Frequency
+ */
+static inline qdf_freq_t
+tdls_get_allowed_off_channel_for_concurrency(struct wlan_objmgr_pdev *pdev,
+					     struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+	qdf_freq_t freq = 0;
+
+	if (!psoc)
+		return 0;
+
+	if (!wlan_psoc_nif_fw_ext2_cap_get(psoc,
+					   WLAN_TDLS_CONCURRENCIES_SUPPORT))
+		return 0;
+
+	if (!policy_mgr_get_allowed_tdls_offchannel_freq(psoc, vdev, &freq)) {
+		tdls_debug("off channel not allowed for current concurrency");
+		return 0;
+	}
+
+	return freq;
+}
+#else
+static inline qdf_freq_t
+tdls_get_allowed_off_channel_for_concurrency(struct wlan_objmgr_pdev *pdev,
+					     struct wlan_objmgr_vdev *vdev)
+{
+	return 0;
+}
+#endif
+
 /**
  * tdls_extract_peer_state_param() - extract peer update params from TDLS peer
  * @peer_param: output peer update params
@@ -592,7 +633,7 @@ void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param,
 	enum channel_state ch_state;
 	struct wlan_objmgr_pdev *pdev;
 	uint32_t cur_band;
-	qdf_freq_t ch_freq;
+	qdf_freq_t ch_freq, allowed_freq;
 	uint32_t tx_power = 0;
 
 	vdev_obj = peer->vdev_priv;
@@ -654,8 +695,16 @@ void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param,
 	}
 
 	num = 0;
+	allowed_freq =
+		tdls_get_allowed_off_channel_for_concurrency(pdev,
+							     vdev_obj->vdev);
+	tdls_debug("allowed freq:%u", allowed_freq);
+
 	for (i = 0; i < peer->supported_channels_len; i++) {
 		ch_freq = peer->supported_chan_freq[i];
+		if (allowed_freq && allowed_freq != ch_freq)
+			continue;
+
 		ch_state = wlan_reg_get_channel_state_for_pwrmode(
 							pdev, ch_freq,
 							REG_CURRENT_PWR_MODE);

+ 12 - 0
components/tdls/dispatcher/inc/wlan_tdls_api.h

@@ -125,6 +125,14 @@ void wlan_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
 void wlan_tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
 				 struct qdf_mac_addr *mac_addr,
 				 struct qdf_mac_addr *dest_mac_addr);
+/**
+ * wlan_tdls_notify_start_bss_failure() - Notify TDLS module on start bss
+ * failure
+ * @psoc: Pointer to PSOC object
+ *
+ * Return: None
+ */
+void wlan_tdls_notify_start_bss_failure(struct wlan_objmgr_psoc *psoc);
 
 /**
  * wlan_tdls_notify_start_bss() - Notify TDLS module on start bss
@@ -255,5 +263,9 @@ static inline
 void wlan_tdls_handle_p2p_client_connect(struct wlan_objmgr_psoc *psoc,
 					 struct wlan_objmgr_vdev *vdev)
 {}
+
+static inline
+void wlan_tdls_notify_start_bss_failure(struct wlan_objmgr_psoc *psoc)
+{}
 #endif
 #endif

+ 6 - 1
components/tdls/dispatcher/src/wlan_tdls_api.c

@@ -269,7 +269,7 @@ void wlan_tdls_notify_channel_switch_start(struct wlan_objmgr_psoc *psoc,
 void wlan_tdls_handle_p2p_client_connect(struct wlan_objmgr_psoc *psoc,
 					 struct wlan_objmgr_vdev *vdev)
 {
-	if (policy_mgr_get_connection_count(psoc) < 2)
+	if (!policy_mgr_get_connection_count(psoc))
 		return;
 
 	/*
@@ -296,6 +296,11 @@ void wlan_tdls_notify_start_bss(struct wlan_objmgr_psoc *psoc,
 	wlan_tdls_check_and_teardown_links_sync(psoc, vdev);
 }
 
+void wlan_tdls_notify_start_bss_failure(struct wlan_objmgr_psoc *psoc)
+{
+	tdls_notify_decrement_session(psoc);
+}
+
 static QDF_STATUS tdls_notify_flush_cb(struct scheduler_msg *msg)
 {
 	struct tdls_sta_notify_params *notify = msg->bodyptr;

+ 2 - 2
components/tdls/dispatcher/src/wlan_tdls_tgt_api.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -362,6 +363,5 @@ void tgt_tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc,
 void tgt_tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc,
 					  uint32_t session_id)
 {
-
-	tdls_delete_all_peers_indication(psoc, session_id);
+	tdls_check_and_indicate_delete_all_peers(psoc, session_id);
 }

+ 1 - 15
components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c

@@ -1272,23 +1272,9 @@ QDF_STATUS ucfg_tdls_set_rssi(struct wlan_objmgr_vdev *vdev,
 	return tdls_set_rssi(vdev, mac, rssi);
 }
 
-/**
- * wlan_tdls_notify_connect_failure() - This api is called if STA/P2P
- * connection fails on one iface and to enable/disable TDLS on the other
- * STA/P2P iface which is already connected.
- * @psoc: psoc object
- *
- * Return: void
- */
-static inline
-void  wlan_tdls_notify_connect_failure(struct wlan_objmgr_psoc *psoc)
-{
-	return tdls_notify_decrement_session(psoc);
-}
-
 void ucfg_tdls_notify_connect_failure(struct wlan_objmgr_psoc *psoc)
 {
-	return wlan_tdls_notify_connect_failure(psoc);
+	return tdls_notify_decrement_session(psoc);
 }
 
 uint16_t ucfg_get_tdls_conn_peer_count(struct wlan_objmgr_vdev *vdev)

+ 8 - 3
core/hdd/src/wlan_hdd_hostapd.c

@@ -6813,10 +6813,15 @@ error:
 free:
 	wlan_twt_concurrency_update(hdd_ctx);
 	if (deliver_start_evt) {
+		struct if_mgr_event_data evt_data;
+
+		evt_data.status = QDF_STATUS_SUCCESS;
+		if (ret < 0)
+			evt_data.status = QDF_STATUS_E_FAILURE;
+
 		status = ucfg_if_mgr_deliver_event(
-					vdev,
-					WLAN_IF_MGR_EV_AP_START_BSS_COMPLETE,
-					NULL);
+				vdev, WLAN_IF_MGR_EV_AP_START_BSS_COMPLETE,
+				&evt_data);
 		if (!QDF_IS_STATUS_SUCCESS(status)) {
 			hdd_err("start bss complete failed!!");
 			ret = -EINVAL;