Parcourir la source

qcacld-3.0: Handle concurrency scenarios in connected monitor mode

If the monitor_mode_concurrency ini is set to 1 and SAP/P2P/NAN is trying
to come up when STA + connected monitor is running, then because of
this ini setting, SAP/P2P/NAN bring up is terminated.

Fix this issue by allowing the SAP/P2P/NAN to come up by terminating the
monitor interface if connected monitor is running.

Change-Id: Ic37d97522c1a1e72a8a1614d6eab2c411ab46f3e
CRs-Fixed: 3610132
Srinivas Girigowda il y a 1 an
Parent
commit
a04c94da27

+ 54 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1803,6 +1803,18 @@ static inline bool hdd_get_wlan_driver_status(void)
 }
 #endif
 
+/**
+ * struct hdd_lpc_info - Local packet capture information
+ * @lpc_wk: local packet capture work
+ * @lpc_wk_scheduled: flag to indicate if lpc work is scheduled or not
+ * @mon_adapter: monitor adapter
+ */
+struct hdd_lpc_info {
+	qdf_work_t lpc_wk;
+	bool lpc_wk_scheduled;
+	struct hdd_adapter *mon_adapter;
+};
+
 /**
  * enum wlan_state_ctrl_str_id - state control param string id
  * @WLAN_OFF_STR: Turn OFF WiFi
@@ -2015,6 +2027,7 @@ enum wlan_state_ctrl_str_id {
  * @is_mlo_per_link_stats_supported: Per link mlo stats is supported or not
  * @num_mlo_peers: Total number of MLO peers
  * @more_peer_data: more mlo peer data in peer stats
+ * @lpc_info: Local packet capture info
  */
 struct hdd_context {
 	struct wlan_objmgr_psoc *psoc;
@@ -2296,6 +2309,9 @@ struct hdd_context {
 	uint8_t num_mlo_peers;
 	uint32_t more_peer_data;
 #endif
+#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE
+	struct hdd_lpc_info lpc_info;
+#endif
 };
 
 /**
@@ -5450,4 +5466,42 @@ static inline void hdd_set_sar_init_index(struct hdd_context *hdd_ctx)
 {}
 #endif
 
+#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE
+/**
+ * wlan_hdd_lpc_handle_concurrency() - Handle local packet capture
+ * concurrency scenario
+ * @hdd_ctx: hdd_ctx
+ * @is_virtual_iface: is virtual interface
+ *
+ * This function takes care of handling concurrency scenario
+ * If STA+Mon present and SAP is coming up, terminate Mon and let SAP come up
+ * If STA+Mon present and P2P is coming up, terminate Mon and let P2P come up
+ * If STA+Mon present and NAN is coming up, terminate Mon and let NAN come up
+ *
+ * Return: none
+ */
+void wlan_hdd_lpc_handle_concurrency(struct hdd_context *hdd_ctx,
+				     bool is_virtual_iface);
+
+/**
+ * hdd_lpc_is_work_scheduled() - function to return if lpc wq scheduled
+ * @hdd_ctx: hdd_ctx
+ *
+ * Return: true if scheduled; false otherwise
+ */
+bool hdd_lpc_is_work_scheduled(struct hdd_context *hdd_ctx);
+
+#else
+static inline void
+wlan_hdd_lpc_handle_concurrency(struct hdd_context *hdd_ctx,
+				bool is_virtual_iface)
+{}
+
+static inline bool
+hdd_lpc_is_work_scheduled(struct hdd_context *hdd_ctx)
+{
+	return false;
+}
+#endif
+
 #endif /* end #if !defined(WLAN_HDD_MAIN_H) */

+ 4 - 1
core/hdd/src/wlan_hdd_cfg80211.c

@@ -22285,7 +22285,10 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy,
 	if (wlan_hdd_is_mon_concurrency())
 		return -EINVAL;
 
-	if (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc))
+	wlan_hdd_lpc_handle_concurrency(hdd_ctx, false);
+
+	if (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc) &&
+	    !hdd_lpc_is_work_scheduled(hdd_ctx))
 		return -EINVAL;
 
 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,

+ 83 - 13
core/hdd/src/wlan_hdd_main.c

@@ -541,16 +541,17 @@ void hdd_start_complete(int ret)
 /**
  * wlan_hdd_lpc_del_monitor_interface() - Delete monitor interface
  * @hdd_ctx: hdd_ctx
+ * @is_virtual_iface: Is virtual interface
  *
  * This function takes care of deleting monitor interface
  *
  * Return: none
  */
 static void
-wlan_hdd_lpc_del_monitor_interface(struct hdd_context *hdd_ctx)
+wlan_hdd_lpc_del_monitor_interface(struct hdd_context *hdd_ctx,
+				   bool is_virtual_iface)
 {
 	struct hdd_adapter *adapter;
-	struct osif_vdev_sync *vdev_sync;
 	void *soc;
 	bool running;
 
@@ -575,21 +576,90 @@ wlan_hdd_lpc_del_monitor_interface(struct hdd_context *hdd_ctx)
 	}
 
 	hdd_debug("lpc: Delete monitor interface");
-	vdev_sync = osif_vdev_sync_unregister(adapter->dev);
-	if (vdev_sync)
-		osif_vdev_sync_wait_for_ops(vdev_sync);
 
 	wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes);
+	qdf_zero_macaddr(&adapter->mac_addr);
 	hdd_stop_adapter(hdd_ctx, adapter);
 	hdd_deinit_adapter(hdd_ctx, adapter, true);
+	adapter->is_virtual_iface = is_virtual_iface;
+	hdd_ctx->lpc_info.mon_adapter = adapter;
+
+	hdd_ctx->lpc_info.lpc_wk_scheduled = true;
+	qdf_sched_work(0, &hdd_ctx->lpc_info.lpc_wk);
+}
+
+void wlan_hdd_lpc_handle_concurrency(struct hdd_context *hdd_ctx,
+				     bool is_virtual_iface)
+{
+	if (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc))
+		wlan_hdd_lpc_del_monitor_interface(hdd_ctx, is_virtual_iface);
+}
+
+bool hdd_lpc_is_work_scheduled(struct hdd_context *hdd_ctx)
+{
+	return hdd_ctx->lpc_info.lpc_wk_scheduled;
+}
+
+static void hdd_lpc_work_handler(void *arg)
+{
+	struct hdd_context *hdd_ctx = (struct hdd_context *)arg;
+	struct hdd_adapter *adapter;
+	struct osif_vdev_sync *vdev_sync;
+	int errno;
+
+	if (!hdd_ctx)
+		return;
+
+	adapter = hdd_ctx->lpc_info.mon_adapter;
+	if (!adapter) {
+		hdd_err("There is no monitor adapter");
+		return;
+	}
+
+	errno = osif_vdev_sync_trans_start_wait(adapter->dev, &vdev_sync);
+	if (errno)
+		return;
+
+	osif_vdev_sync_unregister(adapter->dev);
+	osif_vdev_sync_wait_for_ops(vdev_sync);
+
 	hdd_close_adapter(hdd_ctx, adapter, true);
+	hdd_ctx->lpc_info.lpc_wk_scheduled = false;
+
+	osif_vdev_sync_trans_stop(vdev_sync);
+	osif_vdev_sync_destroy(vdev_sync);
+}
 
-	if (vdev_sync)
-		osif_vdev_sync_destroy(vdev_sync);
+static inline
+void hdd_lp_create_work(struct hdd_context *hdd_ctx)
+{
+	hdd_ctx->lpc_info.lpc_wk_scheduled = false;
+	qdf_create_work(0, &hdd_ctx->lpc_info.lpc_wk, hdd_lpc_work_handler,
+			hdd_ctx);
+}
+
+static inline
+void hdd_lpc_delete_work(struct hdd_context *hdd_ctx)
+{
+	qdf_flush_work(&hdd_ctx->lpc_info.lpc_wk);
+	hdd_ctx->lpc_info.lpc_wk_scheduled = false;
+	qdf_destroy_work(NULL, &hdd_ctx->lpc_info.lpc_wk);
 }
+
 #else
 static inline
-void wlan_hdd_lpc_del_monitor_interface(struct hdd_context *hdd_ctx)
+void hdd_lp_create_work(struct hdd_context *hdd_ctx)
+{
+}
+
+static inline
+void hdd_lpc_delete_work(struct hdd_context *hdd_ctx)
+{
+}
+
+static inline
+void wlan_hdd_lpc_del_monitor_interface(struct hdd_context *hdd_ctx,
+					bool is_virtual_iface)
 {
 }
 #endif
@@ -8789,7 +8859,6 @@ static void __hdd_close_adapter(struct hdd_context *hdd_ctx,
 	struct qdf_mac_addr adapter_mac;
 	struct wlan_hdd_link_info *link_info;
 
-
 	qdf_copy_macaddr(&adapter_mac, &adapter->mac_addr);
 	if (adapter->device_mode == QDF_STA_MODE) {
 		hdd_adapter_for_each_link_info(adapter, link_info)
@@ -10943,6 +11012,8 @@ static inline void hdd_pm_notifier_deinit(struct hdd_context *hdd_ctx)
  */
 static int hdd_context_deinit(struct hdd_context *hdd_ctx)
 {
+	hdd_lpc_delete_work(hdd_ctx);
+
 	qdf_wake_lock_destroy(&hdd_ctx->monitor_mode_wakelock);
 
 	wlan_hdd_cfg80211_deinit(hdd_ctx->wiphy);
@@ -13611,6 +13682,7 @@ static int hdd_context_init(struct hdd_context *hdd_ctx)
 
 	qdf_wake_lock_create(&hdd_ctx->monitor_mode_wakelock,
 			     "monitor_mode_wakelock");
+	hdd_lp_create_work(hdd_ctx);
 
 	return 0;
 
@@ -14560,7 +14632,7 @@ int hdd_start_station_adapter(struct hdd_adapter *adapter)
 
 	if ((adapter->device_mode == QDF_P2P_DEVICE_MODE) ||
 	    (adapter->device_mode == QDF_NAN_DISC_MODE))
-		wlan_hdd_lpc_del_monitor_interface(adapter->hdd_ctx);
+		wlan_hdd_lpc_del_monitor_interface(adapter->hdd_ctx, false);
 
 	status = hdd_adapter_fill_link_address(adapter);
 	if (QDF_IS_STATUS_ERROR(status)) {
@@ -14636,8 +14708,6 @@ int hdd_start_ap_adapter(struct hdd_adapter *adapter, bool rtnl_held)
 		return qdf_status_to_os_return(QDF_STATUS_SUCCESS);
 	}
 
-	wlan_hdd_lpc_del_monitor_interface(hdd_ctx);
-
 	status = hdd_adapter_fill_link_address(adapter);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_debug("Link address derive failed");
@@ -18329,7 +18399,7 @@ static void __hdd_inform_wifi_off(void)
 	ucfg_dlm_wifi_off(hdd_ctx->pdev);
 
 	if (rtnl_trylock()) {
-		wlan_hdd_lpc_del_monitor_interface(hdd_ctx);
+		wlan_hdd_lpc_del_monitor_interface(hdd_ctx, false);
 		rtnl_unlock();
 	}
 }

+ 7 - 2
core/hdd/src/wlan_hdd_p2p.c

@@ -111,7 +111,9 @@ static int __wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy,
 		return -EINVAL;
 	}
 
-	if (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc))
+	wlan_hdd_lpc_handle_concurrency(hdd_ctx, false);
+	if (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc) &&
+	    !hdd_lpc_is_work_scheduled(hdd_ctx))
 		return -EINVAL;
 
 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
@@ -679,7 +681,10 @@ struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
 	if (ret)
 		return ERR_PTR(ret);
 
-	if (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc))
+	wlan_hdd_lpc_handle_concurrency(hdd_ctx, true);
+
+	if (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc) &&
+	    !hdd_lpc_is_work_scheduled(hdd_ctx))
 		return ERR_PTR(-EINVAL);
 
 	if (wlan_hdd_is_mon_concurrency())