Преглед на файлове

qcacld-3.0: Add support to get roam scan channels from fw

Firmware advertises WMI_SERVICE_ROAM_SCAN_CHANNEL_LIST_TO_HOST_SUPPORT
at the time of initialization. When user requests for roam scan channels
to driver using GETROAMSCANCHANNELS command, driver queries firmware for
roam scan channel list by sending wmi command with command id
WMI_ROAM_GET_SCAN_CHANNEL_LIST_CMDID and vdev id.
Firmware response to WMI_ROAM_GET_SCAN_CHANNEL_LIST_CMDID commmad is
WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID. This event has roam scan channel
list, vdev id, connected BSSID, command_response.

Firmware issues WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID event for two reasons,
one for GETROAMSCANCHANNELS command where firmware sets command_response=1
in wmi event and asynchronous event upon disconnection where firmware sets
command_response=0 in wmi event.

Change-Id: I690aca6c3f1e3aa7ae1fe54aadc839ea19446079
CRs-Fixed: 2621535
Abhishek Ambure преди 5 години
родител
ревизия
4bb3519a42

+ 1 - 1
core/hdd/inc/wlan_hdd_cfg.h

@@ -242,7 +242,7 @@ struct hdd_config {
 	bool enable_sar_safety;
 	bool config_sar_safety_sleep_index;
 #endif
-
+	bool get_roam_chan_from_fw;
 	uint32_t fisa_enable;
 };
 

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

@@ -1900,6 +1900,7 @@ struct hdd_context {
 	/* value for packet capturte mode */
 	uint8_t val_pkt_capture_mode;
 #endif
+	bool roam_ch_from_fw_supported;
 };
 
 /**

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

@@ -1585,7 +1585,10 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
 		.vendor_id = QCA_NL80211_VENDOR_ID,
 		.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS_EVENT,
 	},
-
+	[QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO_INDEX] = {
+		.vendor_id = QCA_NL80211_VENDOR_ID,
+		.subcmd = QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO,
+	}
 };
 
 /**
@@ -6207,6 +6210,41 @@ wlan_hdd_add_fils_params_roam_auth_event(struct sk_buff *skb,
 #endif
 
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
+void hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx,
+				      uint16_t buf_len, uint8_t *buf)
+{
+	struct sk_buff *vendor_event;
+	uint32_t len, ret;
+
+	if (!hdd_ctx) {
+		hdd_err_rl("hdd context is null");
+		return;
+	}
+
+	len = nla_total_size(buf_len) + NLMSG_HDRLEN;
+	vendor_event =
+		cfg80211_vendor_event_alloc(
+			hdd_ctx->wiphy, NULL, len,
+			QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO_INDEX,
+			GFP_KERNEL);
+
+	if (!vendor_event) {
+		hdd_err("cfg80211_vendor_event_alloc failed");
+		return;
+	}
+
+	ret = nla_put(vendor_event,
+		      QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS,
+		      buf_len, buf);
+	if (ret) {
+		hdd_err("OEM event put fails status %d", ret);
+		kfree_skb(vendor_event);
+		return;
+	}
+
+	cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+}
+
 /**
  * wlan_hdd_send_roam_auth_event() - Send the roamed and authorized event
  * @adapter: Pointer to adapter struct

+ 17 - 0
core/hdd/src/wlan_hdd_cfg80211.h

@@ -397,6 +397,17 @@ void wlan_hdd_cfg80211_unlink_bss(struct hdd_adapter *adapter,
 void wlan_hdd_cfg80211_acs_ch_select_evt(struct hdd_adapter *adapter);
 
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * hdd_send_roam_scan_ch_list_event() - roam scan ch list event to user space
+ * @hdd_ctx: HDD context
+ * @buf_len: length of frequency list
+ * @buf: pointer to buffer of frequency list
+ *
+ * Return: None
+ */
+void hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx,
+				      uint16_t buf_len, uint8_t *buf);
+
 int wlan_hdd_send_roam_auth_event(struct hdd_adapter *adapter, uint8_t *bssid,
 		uint8_t *req_rsn_ie, uint32_t req_rsn_length, uint8_t
 		*rsp_rsn_ie, uint32_t rsp_rsn_length, struct csr_roam_info
@@ -409,6 +420,12 @@ static inline int wlan_hdd_send_roam_auth_event(struct hdd_adapter *adapter,
 {
 	return 0;
 }
+
+static inline void
+hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx,
+				 uint16_t buf_len, uint8_t *buf)
+{
+}
 #endif
 
 int wlan_hdd_cfg80211_update_apies(struct hdd_adapter *adapter);

+ 144 - 0
core/hdd/src/wlan_hdd_ioctl.c

@@ -3996,6 +3996,137 @@ static int drv_cmd_set_roam_scan_channels(struct hdd_adapter *adapter,
 	return hdd_parse_set_roam_scan_channels(adapter, command);
 }
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+static bool is_roam_ch_from_fw_supported(struct hdd_context *hdd_ctx)
+{
+	return hdd_ctx->roam_ch_from_fw_supported;
+}
+
+struct roam_ch_priv {
+	struct roam_scan_ch_resp roam_ch;
+};
+
+void hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle,
+			     struct roam_scan_ch_resp *roam_ch,
+			     void *context)
+{
+	struct osif_request *request;
+	struct roam_ch_priv *priv;
+	uint8_t *event = NULL, i = 0;
+	uint32_t  *freq = NULL, len;
+	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
+
+	hdd_debug("roam scan ch list event received : vdev_id:%d command resp: %d",
+		  roam_ch->vdev_id, roam_ch->command_resp);
+	/**
+	 * If command response is set in the response message, then it is
+	 * getroamscanchannels command response else this event is asyncronous
+	 * event raised by firmware.
+	 */
+	if (!roam_ch->command_resp) {
+		len = roam_ch->num_channels * sizeof(roam_ch->chan_list[0]);
+		event = (uint8_t *)qdf_mem_malloc(len);
+		if (!event) {
+			hdd_err("Failed to alloc event response buf vdev_id: %d",
+				roam_ch->vdev_id);
+			return;
+		}
+		freq = (uint32_t *)event;
+		for (i = 0; i < roam_ch->num_channels &&
+		     i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) {
+			freq[i] = roam_ch->chan_list[i];
+		}
+
+		hdd_send_roam_scan_ch_list_event(hdd_ctx, len, event);
+		qdf_mem_free(event);
+		return;
+	}
+
+	request = osif_request_get(context);
+	if (!request) {
+		hdd_err("Obsolete request");
+		return;
+	}
+	priv = osif_request_priv(request);
+
+	priv->roam_ch.num_channels = roam_ch->num_channels;
+	for (i = 0; i < priv->roam_ch.num_channels &&
+	     i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++)
+		priv->roam_ch.chan_list[i] = roam_ch->chan_list[i];
+
+	osif_request_complete(request);
+	osif_request_put(request);
+}
+
+static uint32_t
+hdd_get_roam_chan_from_fw(struct hdd_adapter *adapter, uint32_t *chan_list,
+			  uint8_t *num_channels)
+{
+	QDF_STATUS status = QDF_STATUS_E_INVAL;
+	struct hdd_context *hdd_ctx;
+	int ret, i;
+	void *cookie;
+	struct osif_request *request;
+	struct roam_ch_priv *priv;
+	struct roam_scan_ch_resp *p_roam_ch;
+	static const struct osif_request_params params = {
+		.priv_size = sizeof(*priv) +
+			     sizeof(priv->roam_ch.chan_list[0]) *
+			     WNI_CFG_VALID_CHANNEL_LIST_LEN,
+		.timeout_ms = WLAN_WAIT_TIME_STATS,
+	};
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	request = osif_request_alloc(&params);
+	if (!request) {
+		hdd_err("Request allocation failure");
+		return -ENOMEM;
+	}
+
+	priv = osif_request_priv(request);
+	p_roam_ch = &priv->roam_ch;
+	/** channel list starts after response structure*/
+	priv->roam_ch.chan_list = (uint32_t *)(p_roam_ch + 1);
+	cookie = osif_request_cookie(request);
+	status = sme_get_roam_scan_ch(hdd_ctx->mac_handle,
+				      adapter->vdev_id, cookie);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Unable to retrieve roam channels");
+		ret = qdf_status_to_os_return(status);
+		goto cleanup;
+	}
+
+	ret = osif_request_wait_for_response(request);
+	if (ret) {
+		hdd_err("SME timed out while retrieving raom channels");
+		goto cleanup;
+	}
+
+	priv = osif_request_priv(request);
+	*num_channels = priv->roam_ch.num_channels;
+	for (i = 0; i < *num_channels; i++)
+		chan_list[i] = priv->roam_ch.chan_list[i];
+
+cleanup:
+	osif_request_put(request);
+
+	return ret;
+}
+#else
+static bool is_roam_ch_from_fw_supported(struct hdd_context *hdd_ctx)
+{
+	return false;
+}
+
+static uint32_t
+hdd_get_roam_chan_from_fw(struct hdd_adapter *adapter, uint32_t *chan_list,
+                          uint8_t *num_channels)
+{
+	return QDF_STATUS_E_INVAL;
+}
+#endif
+
 static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter,
 					  struct hdd_context *hdd_ctx,
 					  uint8_t *command,
@@ -4010,6 +4141,18 @@ static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter,
 	int len;
 	uint8_t chan;
 
+	if (is_roam_ch_from_fw_supported(hdd_ctx)) {
+		ret = hdd_get_roam_chan_from_fw(adapter, freq_list,
+						&num_channels);
+		if (ret == QDF_STATUS_SUCCESS) {
+			goto fill_ch_resp;
+		} else {
+			hdd_err("failed to get roam scan channel list from FW");
+			ret = -EFAULT;
+			goto exit;
+		}
+	}
+
 	if (QDF_STATUS_SUCCESS !=
 		sme_get_roam_scan_channel_list(hdd_ctx->mac_handle,
 					       freq_list,
@@ -4020,6 +4163,7 @@ static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter,
 		goto exit;
 	}
 
+fill_ch_resp:
 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
 		   TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL,
 		   adapter->vdev_id, num_channels);

+ 27 - 1
core/hdd/src/wlan_hdd_ioctl.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014, 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2017-2019, 2020 The Linux Foundation. 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
@@ -48,6 +48,32 @@ QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode);
 int hdd_set_antenna_mode(struct hdd_adapter *adapter,
 			  struct hdd_context *hdd_ctx, int mode);
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * hdd_get_roam_scan_ch_cb() - roam scan channel list callback handler
+ * @hdd_handle: Pointer to hdd context
+ * @roam_ch: pointer to roam scan ch event data
+ * @context: cookie
+ *
+ * Callback function to processes roam scan chaanel list event. If
+ * command response field in the response message is set that means
+ * event received as a response of GETROAMSCANCHANNELS command else
+ * event was rasied by firmware upon disconnection.
+ *
+ * Return: none
+ */
+void hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle,
+			     struct roam_scan_ch_resp *roam_ch,
+			     void *context);
+#else
+static inline void
+hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle,
+			void *roam_ch,
+			void *context)
+{
+}
+#endif
+
 #ifdef QCA_IBSS_SUPPORT
 /**
  * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback

+ 3 - 0
core/hdd/src/wlan_hdd_main.c

@@ -1626,6 +1626,7 @@ static void hdd_update_tgt_services(struct hdd_context *hdd_ctx,
 				   mawc_enabled & cfg->is_fw_mawc_capable);
 	hdd_update_tdls_config(hdd_ctx);
 	sme_update_tgt_services(hdd_ctx->mac_handle, cfg);
+	hdd_ctx->roam_ch_from_fw_supported = cfg->is_roam_scan_ch_to_host;
 }
 
 /**
@@ -13427,6 +13428,8 @@ int hdd_register_cb(struct hdd_context *hdd_ctx)
 					    hdd_common_roam_callback);
 
 	sme_set_oem_data_event_handler_cb(mac_handle, hdd_oem_event_handler_cb);
+	sme_set_roam_scan_ch_event_cb(mac_handle, hdd_get_roam_scan_ch_cb);
+
 	hdd_exit();
 
 	return ret;

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

@@ -191,6 +191,20 @@ struct rsn_caps {
 	uint16_t Reserved:8;
 };
 
+/**
+ * struct roam_scan_ch_resp - roam scan chan list response to userspace
+ * @vdev_id: vdev id
+ * @num_channels: number of roam scan channels
+ * @command_resp: command response or async event
+ * @chan_list: list of roam scan channels
+ */
+struct roam_scan_ch_resp {
+	uint16_t vdev_id;
+	uint16_t num_channels;
+	uint32_t command_resp;
+	uint32_t *chan_list;
+};
+
 /**
  * struct wlan_beacon_report - Beacon info to be send to userspace
  * @vdev_id: vdev id

+ 3 - 1
core/mac/inc/wni_api.h

@@ -243,7 +243,9 @@ enum eWniMsgTypes {
 	eWNI_SME_VDEV_DELETE_RSP = SIR_SME_MSG_TYPES_BEGIN + 158,
 	eWNI_SME_ROAM_INIT_PARAM = SIR_SME_MSG_TYPES_BEGIN + 159,
 	eWNI_SME_ROAM_SEND_PER_REQ = SIR_SME_MSG_TYPES_BEGIN + 160,
-	eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 161
+	eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT =
+				SIR_SME_MSG_TYPES_BEGIN + 161,
+	eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 162
 };
 
 typedef struct sAniCfgTxRateCtrs {

+ 2 - 0
core/mac/src/include/sir_params.h

@@ -652,6 +652,8 @@ struct sir_cfg_action_frm_tb_ppdu {
 
 #define SIR_HAL_SET_ROAM_TRIGGERS           (SIR_HAL_ITC_MSG_TYPES_BEGIN + 413)
 
+#define SIR_HAL_ROAM_SCAN_CH_REQ           (SIR_HAL_ITC_MSG_TYPES_BEGIN + 414)
+
 #define SIR_HAL_MSG_TYPES_END               (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 
 /* LIM message types */

+ 5 - 0
core/sme/inc/csr_api.h

@@ -1436,6 +1436,11 @@ static inline void csr_roam_fill_tdls_info(struct mac_context *mac_ctx,
 {}
 #endif
 
+typedef void (*sme_get_raom_scan_ch_callback)(
+				hdd_handle_t hdd_handle,
+				struct roam_scan_ch_resp *roam_ch,
+				void *context);
+
 /**
  * csr_packetdump_timer_stop() - stops packet dump timer
  *

+ 41 - 0
core/sme/inc/sme_api.h

@@ -560,6 +560,32 @@ QDF_STATUS sme_roam_get_connect_profile(mac_handle_t mac_handle,
 void sme_roam_free_connect_profile(tCsrRoamConnectedProfile *profile);
 
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * sme_set_roam_scan_ch_event_cb() - Register roam scan ch callback
+ * @mac_handle: Opaque handle to the MAC context
+ * @cb: callback to be registered
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+sme_set_roam_scan_ch_event_cb(mac_handle_t mac_handle,
+			      sme_get_raom_scan_ch_callback cb);
+
+/**
+ * sme_get_roam_scan_ch() -API to get roam scan channels
+ * @mac_handle: Pointer to mac handle
+ * @sta_id: vdev id
+ * @pcontext: pointer to the context
+ *
+ * Extract number of frequencies and frequency list from chan_info and print
+ * to the logs.
+ *
+ * Return: None
+ */
+QDF_STATUS
+sme_get_roam_scan_ch(mac_handle_t mac_handle,
+		     uint8_t vdev_id, void *pcontext);
+
 /**
  * sme_get_pmk_info(): A wrapper function to request CSR to save PMK
  * @mac_handle: Global structure
@@ -578,6 +604,20 @@ static inline
 void sme_get_pmk_info(mac_handle_t mac_handle, uint8_t session_id,
 		      tPmkidCacheInfo *pmk_cache)
 {}
+
+static inline QDF_STATUS
+sme_get_roam_scan_ch(mac_handle_t mac_handle,
+		     uint8_t vdev_id, void *pcontext)
+{
+	return QDF_STATUS_E_FAILURE;
+}
+
+static inline QDF_STATUS
+sme_set_roam_scan_ch_event_cb(mac_handle_t mac_handle,
+			      void *cb)
+{
+	return QDF_STATUS_E_FAILURE;
+}
 #endif
 
 /**
@@ -1106,6 +1146,7 @@ QDF_STATUS sme_get_roam_scan_channel_list(mac_handle_t mac_handle,
 					  uint32_t *freq_list,
 					  uint8_t *pNumChannels,
 					  uint8_t sessionId);
+
 /**
  * sme_dump_freq_list() - Dump the frequencies from given chan info
  * @chan_info: Contains the frequency list and number of frequencies

+ 3 - 1
core/sme/inc/sme_internal.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2020 The Linux Foundation. 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
@@ -392,6 +392,8 @@ struct sme_context {
 	void (*oem_data_event_handler_cb)
 			(const struct oem_data *oem_event_data);
 #endif
+	sme_get_raom_scan_ch_callback roam_scan_ch_callback;
+	void *roam_scan_ch_get_context;
 };
 
 #endif /* #if !defined( __SMEINTERNAL_H ) */

+ 85 - 0
core/sme/src/common/sme_api.c

@@ -1721,6 +1721,38 @@ QDF_STATUS sme_get_tsm_stats(mac_handle_t mac_handle,
 	return status;
 }
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+QDF_STATUS sme_get_roam_scan_ch(mac_handle_t mac_handle,
+				uint8_t vdev_id, void *pcontext)
+{
+	struct scheduler_msg msg = {0};
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct mac_context *mac = MAC_CONTEXT(mac_handle);
+
+	status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_ERROR(status))
+		return QDF_STATUS_E_FAILURE;
+
+	msg.type = WMA_ROAM_SCAN_CH_REQ;
+	msg.bodyval = vdev_id;
+	mac->sme.roam_scan_ch_get_context = pcontext;
+
+	if (scheduler_post_message(QDF_MODULE_ID_SME,
+				   QDF_MODULE_ID_WMA,
+				   QDF_MODULE_ID_WMA,
+				   &msg)) {
+		sme_err("Posting message %d failed",
+			WMA_ROAM_SCAN_CH_REQ);
+		mac->sme.roam_scan_ch_get_context = NULL;
+		sme_release_global_lock(&mac->sme);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	sme_release_global_lock(&mac->sme);
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * sme_set_ese_roam_scan_channel_list() - To set ese roam scan channel list
  * @mac_handle: Opaque handle to the global MAC context
@@ -1949,6 +1981,55 @@ static QDF_STATUS sme_process_dual_mac_config_resp(struct mac_context *mac,
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+QDF_STATUS sme_set_roam_scan_ch_event_cb(mac_handle_t mac_handle,
+					 sme_get_raom_scan_ch_callback cb)
+{
+	QDF_STATUS qdf_status;
+	struct mac_context *mac = MAC_CONTEXT(mac_handle);
+
+	qdf_status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_ERROR(qdf_status))
+		return qdf_status;
+
+	mac->sme.roam_scan_ch_callback = cb;
+	sme_release_global_lock(&mac->sme);
+
+	return qdf_status;
+}
+
+/**
+ * sme_process_roam_scan_ch_list_resp() - Process get roam scan ch list
+ * response
+ * @mac: Global MAC pointer
+ * @msgbuf: pointer to roam scan ch list response
+ *
+ * This function checks the roam scan chan list message is for command
+ * response or a async event and accordingly data is given to user space.
+ * callback to process further
+ */
+static void
+sme_process_roam_scan_ch_list_resp(struct mac_context *mac,
+				   struct roam_scan_ch_resp *roam_ch)
+{
+	sme_get_raom_scan_ch_callback callback =
+				mac->sme.roam_scan_ch_callback;
+
+	if (!roam_ch)
+		return;
+
+	if (callback)
+		callback(mac->hdd_handle, roam_ch,
+			 mac->sme.roam_scan_ch_get_context);
+}
+#else
+static void
+sme_process_roam_scan_ch_list_resp(tpAniSirGlobal mac,
+				   struct roam_scan_ch_resp *roam_ch)
+{
+}
+#endif
+
 /**
  * sme_process_antenna_mode_resp() - Process set antenna mode
  * response
@@ -2326,6 +2407,10 @@ QDF_STATUS sme_process_msg(struct mac_context *mac, struct scheduler_msg *pMsg)
 			sme_err("Empty message for: %d", pMsg->type);
 		}
 		break;
+	case eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT:
+		sme_process_roam_scan_ch_list_resp(mac, pMsg->bodyptr);
+		qdf_mem_free(pMsg->bodyptr);
+		break;
 	default:
 
 		if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN)

+ 19 - 0
core/wma/inc/wma_api.h

@@ -295,6 +295,25 @@ void wma_process_pdev_hw_mode_trans_ind(void *wma,
 QDF_STATUS wma_set_cts2self_for_p2p_go(void *wma_handle,
 		uint32_t cts2self_for_p2p_go);
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * wma_get_roam_scan_ch() - API to get roam scan channel list.
+ * @wma_handle: pointer to wma handle.
+ * @vdev_id: vdev id
+ *
+ * Return: QDF_STATUS.
+ */
+QDF_STATUS wma_get_roam_scan_ch(wmi_unified_t wma,
+				uint8_t vdev_id);
+#else
+static inline
+QDF_STATUS wma_get_roam_scan_ch(wmi_unified_t wma,
+				uint8_t vdev_id)
+{
+	return QDF_STATUS_E_FAILURE;
+}
+#endif
+
 /**
  * wma_set_tx_rx_aggr_size() - set tx rx aggregation size
  * @vdev_id: vdev id

+ 21 - 0
core/wma/inc/wma_internal.h

@@ -301,6 +301,27 @@ wma_roam_pmkid_request_event_handler(void *handle,
 }
 #endif
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * wma_roam_scan_chan_list_event_handler() - roam scan chan list event handler
+ * @handle: wma handle
+ * @event: pointer to fw event
+ * @len: length of event
+ *
+ * Return: Success or Failure status
+ */
+int wma_roam_scan_chan_list_event_handler(WMA_HANDLE handle,
+					  uint8_t *event,
+					  uint32_t len);
+#else
+static inline int
+wma_roam_scan_chan_list_event_handler(WMA_HANDLE handle, uint8_t *event,
+				      uint32_t len)
+{
+	return 0;
+}
+#endif
+
 /**
  * wma_update_per_roam_config() -per roam config parameter updation to FW
  * @handle: wma handle

+ 3 - 1
core/wma/inc/wma_tgt_cfg.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020 The Linux Foundation. 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
@@ -43,6 +43,7 @@
  * @twt_requestor: TWT requestor capability
  * @twt_responder: TWT responder capability
  * @bcn_reception_stats: Beacon Reception stats capability
+ * @is_roam_scan_ch_to_host: Get roam scan channels from fw supported
  */
 struct wma_tgt_services {
 	uint32_t sta_power_save;
@@ -75,6 +76,7 @@ struct wma_tgt_services {
 	bool twt_responder;
 	bool obss_scan_offload;
 	bool bcn_reception_stats;
+	bool is_roam_scan_ch_to_host;
 };
 
 /**

+ 2 - 0
core/wma/inc/wma_types.h

@@ -165,6 +165,8 @@
 #define WMA_TSM_STATS_RSP              SIR_HAL_TSM_STATS_RSP
 #endif
 
+#define WMA_ROAM_SCAN_CH_REQ              SIR_HAL_ROAM_SCAN_CH_REQ
+
 #define WMA_HT40_OBSS_SCAN_IND                  SIR_HAL_HT40_OBSS_SCAN_IND
 
 #define WMA_SET_MIMOPS_REQ                      SIR_HAL_SET_MIMOPS_REQ

+ 11 - 0
core/wma/src/wma_main.c

@@ -3281,6 +3281,11 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc,
 					   wma_roam_stats_event_handler,
 					   WMA_RX_SERIALIZER_CTX);
 
+	wmi_unified_register_event_handler(
+		wma_handle->wmi_handle, wmi_roam_scan_chan_list_id,
+		wma_roam_scan_chan_list_event_handler,
+		WMA_RX_SERIALIZER_CTX);
+
 	wma_register_pmkid_req_event_handler(wma_handle);
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
@@ -4683,6 +4688,9 @@ static inline void wma_update_target_services(struct wmi_unified *wmi_handle,
 
 	if (wmi_service_enabled(wmi_handle, wmi_service_vdev_latency_config))
 		g_fw_wlan_feat_caps |= (1 << VDEV_LATENCY_CONFIG);
+	if (wmi_service_enabled(wmi_handle,
+				wmi_roam_scan_chan_list_to_host_support))
+		cfg->is_roam_scan_ch_to_host = true;
 }
 
 /**
@@ -8961,6 +8969,9 @@ static QDF_STATUS wma_mc_process_msg(struct scheduler_msg *msg)
 		wma_update_roam_offload_flag(wma_handle, msg->bodyptr);
 		qdf_mem_free(msg->bodyptr);
 		break;
+	case WMA_ROAM_SCAN_CH_REQ:
+		wma_get_roam_scan_ch(wma_handle->wmi_handle, msg->bodyval);
+		break;
 	default:
 		WMA_LOGD("Unhandled WMA message of type %d", msg->type);
 		if (msg->bodyptr)

+ 63 - 0
core/wma/src/wma_scan_roam.c

@@ -3273,6 +3273,69 @@ int wma_roam_auth_offload_event_handler(WMA_HANDLE handle, uint8_t *event,
 	return 0;
 }
 
+int wma_roam_scan_chan_list_event_handler(WMA_HANDLE handle,
+					  uint8_t *event,
+					  uint32_t len)
+{
+	tp_wma_handle wma = (tp_wma_handle)handle;
+	WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID_param_tlvs *param_buf;
+	wmi_roam_scan_channel_list_event_fixed_param *fixed_param;
+	uint8_t vdev_id, i = 0, num_ch = 0;
+	struct roam_scan_ch_resp *resp;
+	struct scheduler_msg sme_msg = {0};
+
+	param_buf = (WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID_param_tlvs *)event;
+	if (!param_buf) {
+		wma_err_rl("NULL event received from target");
+		return -EINVAL;
+	}
+
+	fixed_param = param_buf->fixed_param;
+	if (!fixed_param) {
+		wma_err_rl(" NULL fixed param");
+		return -EINVAL;
+	}
+
+	vdev_id = fixed_param->vdev_id;
+	if (vdev_id >= wma->max_bssid) {
+		wma_err_rl("Invalid vdev_id %d", vdev_id);
+		return -EINVAL;
+	}
+
+	num_ch = (param_buf->num_channel_list <
+		WNI_CFG_VALID_CHANNEL_LIST_LEN) ?
+		param_buf->num_channel_list :
+		WNI_CFG_VALID_CHANNEL_LIST_LEN;
+
+	resp = qdf_mem_malloc(sizeof(struct roam_scan_ch_resp) +
+		num_ch * sizeof(param_buf->channel_list[0]));
+	if (!resp) {
+		wma_err_rl("Failed to alloc resp message");
+		return -EINVAL;
+	}
+
+	resp->chan_list = (uint32_t *)(resp + 1);
+	resp->vdev_id = vdev_id;
+	resp->command_resp = fixed_param->command_response;
+	resp->num_channels = param_buf->num_channel_list;
+
+	for (i = 0; i < num_ch; i++)
+		resp->chan_list[i] = param_buf->channel_list[i];
+
+	sme_msg.type = eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT;
+	sme_msg.bodyptr = resp;
+
+	if (scheduler_post_message(QDF_MODULE_ID_WMA,
+				   QDF_MODULE_ID_SME,
+				   QDF_MODULE_ID_SME, &sme_msg)) {
+		WMA_LOGE(FL("Failed to post msg to SME"));
+		qdf_mem_free(sme_msg.bodyptr);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
 /**
  * wma_get_trigger_detail_str  - Return roam trigger string from the

+ 41 - 0
core/wma/src/wma_utils.c

@@ -3777,6 +3777,47 @@ bool wma_is_p2p_lo_capable(void)
 }
 #endif
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+QDF_STATUS wma_get_roam_scan_ch(wmi_unified_t wmi_handle,
+				uint8_t vdev_id)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct roam_scan_ch_resp *roam_ch;
+	struct scheduler_msg sme_msg = {0};
+
+	if (!wma_is_vdev_valid(vdev_id)) {
+		wma_err("vdev_id: %d is not active", vdev_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = wmi_unified_get_roam_scan_ch_list(wmi_handle, vdev_id);
+	if (QDF_IS_STATUS_SUCCESS(status))
+		return status;
+	roam_ch = qdf_mem_malloc(sizeof(struct roam_scan_ch_resp));
+	if (!roam_ch) {
+		wma_err("Failed to alloc resp");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	roam_ch->command_resp = 1;
+	roam_ch->num_channels = 0;
+	roam_ch->chan_list = NULL;
+	roam_ch->vdev_id = vdev_id;
+	sme_msg.type = eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT;
+	sme_msg.bodyptr = roam_ch;
+
+	if (scheduler_post_message(QDF_MODULE_ID_WMA,
+				   QDF_MODULE_ID_SME,
+				   QDF_MODULE_ID_SME, &sme_msg)) {
+		wma_err("Failed to post msg to SME");
+		qdf_mem_free(roam_ch);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return status;
+}
+#endif
+
 bool wma_capability_enhanced_mcast_filter(void)
 {
 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);