qcacld-3.0: Refine the extscan start BSSID hotlist logic

Make the following updates to the extscan start BSSID hotlist logic:
1) Exclusively use the Unified WMI data structures.
2) Use the new wmi_unified_extscan_start_hotlist_monitor_cmd() API.
3) Update the HDD<=>SME interface to enforce the contract that SME
   must not make any assumptions about the buffers provided by HDD.

Change-Id: I4d9f982177bc61a751ba0e7437fe55482dfd2723
CRs-Fixed: 2291946
diff --git a/core/hdd/src/wlan_hdd_ext_scan.c b/core/hdd/src/wlan_hdd_ext_scan.c
index cb7b170..066a35d 100644
--- a/core/hdd/src/wlan_hdd_ext_scan.c
+++ b/core/hdd/src/wlan_hdd_ext_scan.c
@@ -31,6 +31,8 @@
 #include "cds_sched.h"
 #include <qca_vendor.h>
 
+#define EXTSCAN_PARAM_MAX QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
+
 /* amount of time to wait for a synchronous request/response operation */
 #define WLAN_WAIT_TIME_EXTSCAN  1000
 
@@ -1888,6 +1890,60 @@
 }
 
 /**
+ * hdd_parse_ap_rssi_threshold() - parse AP RSSI threshold parameters
+ * @attr: netlink attribute containing the AP RSSI threshold parameters
+ * @ap: destination buffer for the parsed parameters
+ *
+ * This function parses the BSSID, low RSSI and high RSSI values from
+ * the @attr netlink attribute, storing the parsed values in @ap.
+ *
+ * Return: 0 if @attr is parsed and all required attributes are
+ * present, otherwise a negative errno.
+ */
+static int hdd_parse_ap_rssi_threshold(struct nlattr *attr,
+				       struct ap_threshold_params *ap)
+{
+	struct nlattr *tb[EXTSCAN_PARAM_MAX + 1];
+	int id;
+
+	if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX,
+				    nla_data(attr), nla_len(attr),
+				    wlan_hdd_extscan_config_policy)) {
+		hdd_err("nla_parse failed");
+		return -EINVAL;
+	}
+
+	/* Parse and fetch MAC address */
+	id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID;
+	if (!tb[id]) {
+		hdd_err("attr mac address failed");
+		return -EINVAL;
+	}
+	nla_memcpy(ap->bssid.bytes, tb[id], QDF_MAC_ADDR_SIZE);
+	hdd_debug("BSSID: " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(ap->bssid.bytes));
+
+	/* Parse and fetch low RSSI */
+	id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW;
+	if (!tb[id]) {
+		hdd_err("attr low RSSI failed");
+		return -EINVAL;
+	}
+	ap->low = nla_get_s32(tb[id]);
+	hdd_debug("RSSI low %d", ap->low);
+
+	/* Parse and fetch high RSSI */
+	id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH;
+	if (!tb[id]) {
+		hdd_err("attr high RSSI failed");
+		return -EINVAL;
+	}
+	ap->high = nla_get_s32(tb[id]);
+	hdd_debug("RSSI High %d", ap->high);
+
+	return 0;
+}
+
+/**
  * __wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set bssid hot list
  * @wiphy: Pointer to wireless phy
  * @wdev: Pointer to wireless device
@@ -1898,24 +1954,20 @@
  */
 static int
 __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy,
-						struct wireless_dev
-						*wdev, const void *data,
-						int data_len)
+					      struct wireless_dev *wdev,
+					      const void *data,
+					      int data_len)
 {
-	tpSirExtScanSetBssidHotListReqParams pReqMsg = NULL;
+	struct extscan_bssid_hotlist_set_params *params;
 	struct net_device *dev = wdev->netdev;
 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
-	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
-			  1];
-	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
-			   + 1];
-	struct nlattr *apTh;
+	struct nlattr *tb[EXTSCAN_PARAM_MAX + 1];
+	struct nlattr *apth;
 	struct hdd_ext_scan_context *context;
-	uint32_t request_id;
 	QDF_STATUS status;
 	uint8_t i;
-	int rem, retval;
+	int id, rem, retval;
 	unsigned long rc;
 
 	hdd_enter_dev(dev);
@@ -1933,131 +1985,98 @@
 		hdd_err("extscan not supported");
 		return -ENOTSUPP;
 	}
-	if (wlan_cfg80211_nla_parse(tb,
-			   QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
-			   data, data_len, wlan_hdd_extscan_config_policy)) {
+
+	if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX,
+				    data, data_len,
+				    wlan_hdd_extscan_config_policy)) {
 		hdd_err("Invalid ATTR");
 		return -EINVAL;
 	}
 
-	pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg));
-	if (!pReqMsg) {
+	params = qdf_mem_malloc(sizeof(*params));
+	if (!params) {
 		hdd_err("qdf_mem_malloc failed");
 		return -ENOMEM;
 	}
 
+	/* assume the worst until proven otherwise */
+	retval = -EINVAL;
+
 	/* Parse and fetch request Id */
-	if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
+	id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID;
+	if (!tb[id]) {
 		hdd_err("attr request id failed");
 		goto fail;
 	}
 
-	pReqMsg->requestId =
-		nla_get_u32(tb
-		 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
-	hdd_debug("Req Id %d", pReqMsg->requestId);
+	params->request_id = nla_get_u32(tb[id]);
+	hdd_debug("Req Id %d", params->request_id);
 
 	/* Parse and fetch number of APs */
-	if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]) {
+	id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP;
+	if (!tb[id]) {
 		hdd_err("attr number of AP failed");
 		goto fail;
 	}
-	pReqMsg->numAp =
-		nla_get_u32(tb
-		    [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]);
-	if (pReqMsg->numAp > WLAN_EXTSCAN_MAX_HOTLIST_APS) {
+
+	params->num_ap = nla_get_u32(tb[id]);
+	if (params->num_ap > WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS) {
 		hdd_err("Number of AP: %u exceeds max: %u",
-			pReqMsg->numAp, WLAN_EXTSCAN_MAX_HOTLIST_APS);
+			params->num_ap, WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS);
 		goto fail;
 	}
-	pReqMsg->sessionId = adapter->session_id;
-	hdd_debug("Number of AP %d Session Id %d",
-		pReqMsg->numAp, pReqMsg->sessionId);
+	params->vdev_id = adapter->session_id;
+	hdd_debug("Number of AP %d vdev Id %d",
+		  params->num_ap, params->vdev_id);
 
 	/* Parse and fetch lost ap sample size */
-	if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]) {
+	id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE;
+	if (!tb[id]) {
 		hdd_err("attr lost ap sample size failed");
 		goto fail;
 	}
 
-	pReqMsg->lost_ap_sample_size = nla_get_u32(
-		tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]);
+	params->lost_ap_sample_size = nla_get_u32(tb[id]);
 	hdd_debug("Lost ap sample size %d",
-			pReqMsg->lost_ap_sample_size);
+		  params->lost_ap_sample_size);
 
-	if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM]) {
+	/* Parse the AP Threshold array */
+	id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM;
+	if (!tb[id]) {
 		hdd_err("attr ap threshold failed");
 		goto fail;
 	}
+
 	i = 0;
-	nla_for_each_nested(apTh,
-			    tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM],
-			    rem) {
-		if (i == pReqMsg->numAp) {
+	nla_for_each_nested(apth, tb[id], rem) {
+		if (i == params->num_ap) {
 			hdd_warn("Ignoring excess AP");
 			break;
 		}
 
-		if (wlan_cfg80211_nla_parse(tb2,
-			   QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
-			   nla_data(apTh), nla_len(apTh),
-			   wlan_hdd_extscan_config_policy)) {
-			hdd_err("nla_parse failed");
+		retval = hdd_parse_ap_rssi_threshold(apth, &params->ap[i]);
+		if (retval)
 			goto fail;
-		}
-
-		/* Parse and fetch MAC address */
-		if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID]) {
-			hdd_err("attr mac address failed");
-			goto fail;
-		}
-		nla_memcpy(pReqMsg->ap[i].bssid.bytes,
-			tb2
-			[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID],
-			   QDF_MAC_ADDR_SIZE);
-		hdd_debug(MAC_ADDRESS_STR,
-		       MAC_ADDR_ARRAY(pReqMsg->ap[i].bssid.bytes));
-
-		/* Parse and fetch low RSSI */
-		if (!tb2
-		    [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]) {
-			hdd_err("attr low RSSI failed");
-			goto fail;
-		}
-		pReqMsg->ap[i].low =
-			nla_get_s32(tb2
-			    [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]);
-		hdd_debug("RSSI low %d", pReqMsg->ap[i].low);
-
-		/* Parse and fetch high RSSI */
-		if (!tb2
-		    [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]) {
-			hdd_err("attr high RSSI failed");
-			goto fail;
-		}
-		pReqMsg->ap[i].high =
-			nla_get_s32(tb2
-			    [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]);
-		hdd_debug("RSSI High %d", pReqMsg->ap[i].high);
 
 		i++;
 	}
 
-	if (i < pReqMsg->numAp) {
+	if (i < params->num_ap) {
 		hdd_warn("Number of AP %u less than expected %u",
-			 i, pReqMsg->numAp);
-		pReqMsg->numAp = i;
+			 i, params->num_ap);
+		params->num_ap = i;
 	}
 
 	context = &ext_scan_context;
 	spin_lock(&context->context_lock);
 	INIT_COMPLETION(context->response_event);
-	context->request_id = request_id = pReqMsg->requestId;
+	context->request_id = params->request_id;
 	spin_unlock(&context->context_lock);
 
-	status = sme_set_bss_hotlist(hdd_ctx->mac_handle, pReqMsg);
+	status = sme_set_bss_hotlist(hdd_ctx->mac_handle, params);
 	if (!QDF_IS_STATUS_SUCCESS(status)) {
 		hdd_err("sme_set_bss_hotlist failed(err=%d)", status);
+		retval = qdf_status_to_os_return(status);
 		goto fail;
 	}
 
@@ -2071,18 +2090,17 @@
 		retval = -ETIMEDOUT;
 	} else {
 		spin_lock(&context->context_lock);
-		if (context->request_id == request_id)
+		if (context->request_id == params->request_id)
 			retval = context->response_status;
 		else
 			retval = -EINVAL;
 		spin_unlock(&context->context_lock);
 	}
 	hdd_exit();
-	return retval;
 
 fail:
-	qdf_mem_free(pReqMsg);
-	return -EINVAL;
+	qdf_mem_free(params);
+	return retval;
 }
 
 /**
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index a13b17b..9a83acf 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -3905,7 +3905,6 @@
 
 #define WLAN_EXTSCAN_MAX_CHANNELS                 36
 #define WLAN_EXTSCAN_MAX_BUCKETS                  16
-#define WLAN_EXTSCAN_MAX_HOTLIST_APS              128
 #define WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS   64
 
 typedef enum {
@@ -4321,23 +4320,6 @@
 	uint8_t sessionId;
 } tSirExtScanStopReqParams, *tpSirExtScanStopReqParams;
 
-/**
- * struct tSirExtScanSetBssidHotListReqParams - set hotlist request
- * @requestId: request identifier
- * @sessionId: session identifier
- * @lost_ap_sample_size: number of samples to confirm AP loss
- * @numAp: Number of hotlist APs
- * @ap: hotlist APs
- */
-typedef struct {
-	uint32_t  requestId;
-	uint8_t   sessionId;
-
-	uint32_t  lost_ap_sample_size;
-	uint32_t  numAp;
-	tSirAPThresholdParam ap[WLAN_EXTSCAN_MAX_HOTLIST_APS];
-} tSirExtScanSetBssidHotListReqParams, *tpSirExtScanSetBssidHotListReqParams;
-
 typedef struct {
 	uint32_t requestId;
 	uint8_t sessionId;
diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h
index 041c8e5..d72b73b 100644
--- a/core/sme/inc/sme_api.h
+++ b/core/sme/inc/sme_api.h
@@ -983,9 +983,20 @@
 		tSirWifiScanCmdReqParams *pStartCmd);
 QDF_STATUS sme_ext_scan_stop(tHalHandle hHal,
 		tSirExtScanStopReqParams *pStopReq);
-QDF_STATUS sme_set_bss_hotlist(tHalHandle hHal,
-		tSirExtScanSetBssidHotListReqParams *
-		pSetHotListReq);
+
+/**
+ * sme_set_bss_hotlist() - SME API to set BSSID hotlist
+ * @mac_handle: Opaque handle to the MAC context
+ * @params: extscan set hotlist structure
+ *
+ * Handles the request to set the BSSID hotlist in firmware.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+sme_set_bss_hotlist(mac_handle_t mac_handle,
+		    struct extscan_bssid_hotlist_set_params *params);
+
 QDF_STATUS sme_reset_bss_hotlist(tHalHandle hHal,
 		tSirExtScanResetBssidHotlistReqParams *
 		pResetReq);
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index 61efac0..7facf77 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -11178,36 +11178,37 @@
 	return status;
 }
 
-/*
- * sme_set_bss_hotlist() -
- * SME API to set BSSID hotlist
- *
- * hHal
- * pSetHotListReq: extscan set hotlist structure
- * Return QDF_STATUS
- */
-QDF_STATUS sme_set_bss_hotlist(tHalHandle hHal,
-			       tSirExtScanSetBssidHotListReqParams *
-			       pSetHotListReq)
+QDF_STATUS
+sme_set_bss_hotlist(mac_handle_t mac_handle,
+		    struct extscan_bssid_hotlist_set_params *params)
 {
-	QDF_STATUS status = QDF_STATUS_SUCCESS;
-	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
-	tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+	QDF_STATUS status;
+	tpAniSirGlobal mac = MAC_CONTEXT(mac_handle);
 	struct scheduler_msg message = {0};
+	struct extscan_bssid_hotlist_set_params *bodyptr;
 
-	status = sme_acquire_global_lock(&pMac->sme);
+	/* per contract must make a copy of the params when messaging */
+	bodyptr = qdf_mem_malloc(sizeof(*bodyptr));
+	if (!bodyptr) {
+		sme_err("buffer allocation failure");
+		return QDF_STATUS_E_NOMEM;
+	}
+	*bodyptr = *params;
+
+	status = sme_acquire_global_lock(&mac->sme);
 	if (QDF_IS_STATUS_SUCCESS(status)) {
 		/* Serialize the req through MC thread */
-		message.bodyptr = pSetHotListReq;
+		message.bodyptr = bodyptr;
 		message.type = WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ;
-		MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG,
-				 NO_SESSION, message.type));
-		qdf_status = scheduler_post_msg(QDF_MODULE_ID_WMA,
-						 &message);
-		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
-			status = QDF_STATUS_E_FAILURE;
+		qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG,
+			  NO_SESSION, message.type);
+		status = scheduler_post_msg(QDF_MODULE_ID_WMA, &message);
+		sme_release_global_lock(&mac->sme);
+	}
 
-		sme_release_global_lock(&pMac->sme);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		sme_err("failure: %d", status);
+		qdf_mem_free(bodyptr);
 	}
 	return status;
 }
diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h
index 2b5eaf4..59124c2 100644
--- a/core/wma/inc/wma_internal.h
+++ b/core/wma/inc/wma_internal.h
@@ -362,13 +362,17 @@
 QDF_STATUS wma_stop_extscan(tp_wma_handle wma,
 			    tSirExtScanStopReqParams *pstopcmd);
 
-QDF_STATUS wma_get_buf_extscan_hotlist_cmd(tp_wma_handle wma_handle,
-					   tSirExtScanSetBssidHotListReqParams *
-					   photlist, int *buf_len);
-
+/**
+ * wma_extscan_start_hotlist_monitor() - start hotlist monitor
+ * @wma: wma handle
+ * @params: hotlist request params
+ *
+ * This function configures hotlist monitor in fw.
+ *
+ * Return: QDF status
+ */
 QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma,
-					     tSirExtScanSetBssidHotListReqParams
-					     *photlist);
+			struct extscan_bssid_hotlist_set_params *params);
 
 QDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma,
 			tSirExtScanResetBssidHotlistReqParams *photlist_reset);
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index 21decf7..0c1b4f7 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -8149,8 +8149,7 @@
 		qdf_mem_free(msg->bodyptr);
 		break;
 	case WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ:
-		wma_extscan_start_hotlist_monitor(wma_handle,
-			(tSirExtScanSetBssidHotListReqParams *) msg->bodyptr);
+		wma_extscan_start_hotlist_monitor(wma_handle, msg->bodyptr);
 		qdf_mem_free(msg->bodyptr);
 		break;
 	case WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ:
diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c
index 99dab76..f988230 100644
--- a/core/wma/src/wma_scan_roam.c
+++ b/core/wma/src/wma_scan_roam.c
@@ -4628,56 +4628,22 @@
 	return num_entries;
 }
 
-/**
- * wma_get_buf_extscan_hotlist_cmd() - prepare hotlist command
- * @handle: wma handle
- * @photlist: hotlist command params
- * @buf_len: buffer length
- *
- * This function fills individual elements for  hotlist request and
- * TLV for bssid entries
- *
- * Return: QDF Status.
- */
-QDF_STATUS wma_get_buf_extscan_hotlist_cmd(tp_wma_handle wma_handle,
-				tSirExtScanSetBssidHotListReqParams *photlist,
-				int *buf_len)
-{
-	return wmi_unified_get_buf_extscan_hotlist_cmd(wma_handle->wmi_handle,
-			(struct ext_scan_setbssid_hotlist_params *)photlist,
-			buf_len);
-}
-
-/**
- * wma_extscan_start_hotlist_monitor() - start hotlist monitor
- * @wma: wma handle
- * @photlist: hotlist request params
- *
- * This function configures hotlist monitor in fw.
- *
- * Return: QDF status
- */
 QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma,
-			     tSirExtScanSetBssidHotListReqParams *photlist)
+			struct extscan_bssid_hotlist_set_params *params)
 {
-	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
-	int len;
-
 	if (!wma || !wma->wmi_handle) {
 		WMA_LOGE("%s: WMA is closed, can not issue hotlist cmd",
 			 __func__);
 		return QDF_STATUS_E_INVAL;
 	}
-	/* Fill individual elements for  hotlist request and
-	 * TLV for bssid entries
-	 */
-	qdf_status = wma_get_buf_extscan_hotlist_cmd(wma, photlist, &len);
-	if (qdf_status != QDF_STATUS_SUCCESS) {
-		WMA_LOGE("%s: Failed to get buffer for hotlist scan cmd",
-			__func__);
-		return QDF_STATUS_E_FAILURE;
+
+	if (!params) {
+		WMA_LOGE("%s: Invalid params", __func__);
+		return QDF_STATUS_E_INVAL;
 	}
-	return QDF_STATUS_SUCCESS;
+
+	return wmi_unified_extscan_start_hotlist_monitor_cmd(wma->wmi_handle,
+							     params);
 }
 
 /**