Parcourir la source

qcacld-3.0: Handle attribute OEM_DATA_RESPONSE_EXPECTED

Add support for OEM_DATA_RESPONSE_EXPECTED. Driver waits for the
response from FW when this attribute is set and forward the blob of
data to supplicant.

Change-Id: I3e51809e4f5736b521c26e37afb02396f9c5ed23
CRs-Fixed: 2694556
sheenam monga il y a 4 ans
Parent
commit
0ec49a71f7

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

@@ -1374,6 +1374,11 @@ struct hdd_adapter {
 	qdf_mutex_t sta_periodic_stats_lock;
 #endif /* WLAN_FEATURE_PERIODIC_STA_STATS */
 	qdf_event_t peer_cleanup_done;
+#ifdef FEATURE_OEM_DATA
+	bool oem_data_in_progress;
+	void *cookie;
+	bool response_expected;
+#endif
 };
 
 #define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station)

+ 8 - 2
core/hdd/inc/wlan_hdd_oemdata.h

@@ -29,6 +29,9 @@
 
 struct hdd_context;
 
+#ifdef FEATURE_OEM_DATA
+#define WLAN_WAIT_TIME_GET_OEM_DATA 1000
+#endif
 #ifdef FEATURE_OEM_DATA_SUPPORT
 
 #ifndef OEM_DATA_REQ_SIZE
@@ -284,12 +287,15 @@ extern const struct nla_policy
 /**
  * hdd_oem_event_handler_cb() - callback for oem data event
  * @oem_event_data: oem data received in the event from the FW
+ * @vdev_id: vdev id
  *
  * Return: None
  */
-void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data);
+void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data,
+			      uint8_t vdev_id);
 #else
-static inline void hdd_oem_event_handler_cb(void *oem_event_data)
+static inline void hdd_oem_event_handler_cb(void *oem_event_data,
+					    uint8_t vdev_id)
 {
 }
 #endif

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

@@ -13971,7 +13971,6 @@ int hdd_register_cb(struct hdd_context *hdd_ctx)
 					    hdd_sme_close_session_callback,
 					    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);
 	status = sme_set_monitor_mode_cb(mac_handle,
 					 hdd_sme_monitor_mode_callback);
@@ -14005,8 +14004,6 @@ void hdd_deregister_cb(struct hdd_context *hdd_ctx)
 
 	mac_handle = hdd_ctx->mac_handle;
 
-	sme_reset_oem_data_event_handler_cb(mac_handle);
-
 	sme_deregister_tx_queue_cb(mac_handle);
 
 	sme_reset_link_layer_stats_ind_cb(mac_handle);

+ 164 - 23
core/hdd/src/wlan_hdd_oemdata.c

@@ -38,7 +38,8 @@
 #include "sme_api.h"
 #include "wlan_nlink_srv.h"
 #include "wlan_hdd_oemdata.h"
-
+#include "wlan_osif_request_manager.h"
+#include "wlan_hdd_main.h"
 #ifdef FEATURE_OEM_DATA_SUPPORT
 #ifdef CNSS_GENL
 #include <net/cnss_nl.h>
@@ -1124,46 +1125,100 @@ oem_data_attr_policy[QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1] = {
 						    .type = NLA_BINARY,
 						    .len = OEM_DATA_MAX_SIZE
 	},
+
+	[QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED] = {.type = NLA_FLAG},
 };
 
-void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data)
+void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data,
+			      uint8_t vdev_id)
 {
 	struct sk_buff *vendor_event;
+	struct osif_request *request;
 	uint32_t len;
 	int ret;
+	struct oem_data *oem_data;
 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
-
+	struct hdd_adapter *hdd_adapter = hdd_get_adapter_by_vdev(hdd_ctx,
+								  vdev_id);
 	hdd_enter();
 
 	ret = wlan_hdd_validate_context(hdd_ctx);
 	if (ret)
 		return;
 
-	len = nla_total_size(oem_event_data->data_len) + NLMSG_HDRLEN;
-	vendor_event =
-		cfg80211_vendor_event_alloc(
+	if (hdd_validate_adapter(hdd_adapter))
+		return;
+
+	if (!oem_event_data || !(oem_event_data->data)) {
+		hdd_err("Invalid oem event data");
+		return;
+	}
+
+	if (hdd_adapter->response_expected) {
+		request = osif_request_get(hdd_adapter->cookie);
+		if (!request) {
+			hdd_err("Invalid request");
+			return;
+		}
+
+		oem_data = osif_request_priv(request);
+		oem_data->data_len = oem_event_data->data_len;
+		oem_data->data = qdf_mem_malloc(oem_data->data_len);
+		if (!oem_data->data) {
+			hdd_err("Memory allocation failure");
+			return;
+		}
+		qdf_mem_copy(oem_data->data, oem_event_data->data,
+			     oem_data->data_len);
+		oem_data->vdev_id = hdd_adapter->vdev_id;
+		osif_request_complete(request);
+		osif_request_put(request);
+	} else {
+		len = nla_total_size(oem_event_data->data_len) + NLMSG_HDRLEN;
+		vendor_event =
+			cfg80211_vendor_event_alloc(
 				hdd_ctx->wiphy, NULL, len,
 				QCA_NL80211_VENDOR_SUBCMD_OEM_DATA_INDEX,
 				GFP_KERNEL);
 
-	if (!vendor_event) {
-		hdd_err("cfg80211_vendor_event_alloc failed");
-		return;
-	}
+		if (!vendor_event) {
+			hdd_err("cfg80211_vendor_event_alloc failed");
+			return;
+		}
 
-	ret = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA,
-		      oem_event_data->data_len, oem_event_data->data);
-	if (ret) {
-		hdd_err("OEM event put fails status %d", ret);
-		kfree_skb(vendor_event);
-		return;
+		ret = nla_put(vendor_event,
+			      QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA,
+			      oem_event_data->data_len, oem_event_data->data);
+		if (ret) {
+			hdd_err("OEM event put fails status %d", ret);
+			kfree_skb(vendor_event);
+			return;
+		}
+		cfg80211_vendor_event(vendor_event, GFP_KERNEL);
 	}
 
-	cfg80211_vendor_event(vendor_event, GFP_KERNEL);
-
 	hdd_exit();
 }
 
+/**
+ *wlan_hdd_free_oem_data: delete data of priv data
+ *@priv: osif request private data
+ *
+ *Return: void
+ */
+static void wlan_hdd_free_oem_data(void *priv)
+{
+	struct oem_data *local_priv = priv;
+
+	if (!local_priv)
+		return;
+
+	if (local_priv->data) {
+		qdf_mem_free(local_priv->data);
+		local_priv->data = NULL;
+	}
+}
+
 /**
  * __wlan_hdd_cfg80211_oem_data_handler() - the handler for oem data
  * @wiphy: wiphy structure pointer
@@ -1179,17 +1234,34 @@ __wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy,
 				     const void *data, int data_len)
 {
 	struct net_device *dev = wdev->netdev;
-	QDF_STATUS status;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	int ret;
+	struct sk_buff *skb = NULL;
 	struct oem_data oem_data = {0};
+	struct oem_data *get_oem_data = NULL;
 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1];
+	struct osif_request *request = NULL;
+	struct oem_data *priv;
+	static const struct osif_request_params params = {
+		.priv_size = sizeof(*priv),
+		.timeout_ms = WLAN_WAIT_TIME_GET_OEM_DATA,
+		.dealloc = wlan_hdd_free_oem_data,
+	};
 
 	ret = wlan_hdd_validate_context(hdd_ctx);
 	if (ret)
 		return ret;
 
+	if (hdd_validate_adapter(adapter))
+		return -EINVAL;
+
+	if (adapter->oem_data_in_progress) {
+		hdd_err("oem request already in progress");
+		return -EBUSY;
+	}
+
 	if (wlan_cfg80211_nla_parse(tb,
 				    QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX,
 				    data, data_len, oem_data_attr_policy)) {
@@ -1203,18 +1275,87 @@ __wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy,
 	}
 
 	oem_data.data_len =
-			nla_len(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]);
+		nla_len(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]);
 	if (!oem_data.data_len) {
 		hdd_err("oem data len is 0!");
 		return -EINVAL;
 	}
-
 	oem_data.vdev_id = adapter->vdev_id;
 	oem_data.data = nla_data(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]);
 
-	status = sme_oem_data_cmd(hdd_ctx->mac_handle, &oem_data);
+	if (tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED])
+		adapter->response_expected = nla_get_flag(
+			   tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED]);
+
+	if (adapter->response_expected) {
+		int skb_len = 0;
+
+		adapter->oem_data_in_progress = true;
+
+		request = osif_request_alloc(&params);
+		if (!request) {
+			hdd_err("request allocation failure");
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		adapter->cookie = osif_request_cookie(request);
+
+		status = sme_oem_data_cmd(hdd_ctx->mac_handle,
+					  hdd_oem_event_handler_cb,
+					  &oem_data, adapter->vdev_id);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_err("Failure while sending command to fw");
+			ret = -EAGAIN;
+			goto err;
+		}
+		ret = osif_request_wait_for_response(request);
+		if (ret) {
+			hdd_err("Timedout while retrieving oem get data");
+			goto err;
+		}
+
+		get_oem_data = osif_request_priv(request);
+		if (!get_oem_data || !(get_oem_data->data)) {
+			hdd_err("invalid get_oem_data");
+			ret = -EINVAL;
+			goto err;
+		}
+
+		skb_len = NLMSG_HDRLEN + NLA_HDRLEN + get_oem_data->data_len;
+
+		skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
+							       skb_len);
+		if (!skb) {
+			hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA,
+			    get_oem_data->data_len, get_oem_data->data)) {
+			hdd_err("nla put failure");
+			kfree_skb(skb);
+			ret =  -EINVAL;
+			goto err;
+		}
+		wlan_cfg80211_vendor_cmd_reply(skb);
+
+	} else {
+		status = sme_oem_data_cmd(hdd_ctx->mac_handle,
+					  hdd_oem_event_handler_cb,
+					  &oem_data, adapter->vdev_id);
+		return qdf_status_to_os_return(status);
+	}
+
+err:
+	if (request)
+		osif_request_put(request);
+	adapter->oem_data_in_progress = false;
+	adapter->response_expected = false;
+
+	return ret;
 
-	return qdf_status_to_os_return(status);
 }
 
 int wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy,

+ 7 - 38
core/sme/inc/sme_api.h

@@ -768,12 +768,18 @@ QDF_STATUS sme_neighbor_report_request(mac_handle_t mac_handle,
 /**
  * sme_oem_data_cmd() - the wrapper to send oem data cmd to wma
  * @mac_handle: Opaque handle to the global MAC context.
+ * @@oem_data_event_handler_cb: callback to be registered
  * @oem_data: the pointer of oem data
+ * @vdev id: vdev id to fetch adapter
  *
  * Return: QDF_STATUS
  */
 QDF_STATUS sme_oem_data_cmd(mac_handle_t mac_handle,
-			    struct oem_data *oem_data);
+			    void (*oem_data_event_handler_cb)
+			    (const struct oem_data *oem_event_data,
+			     uint8_t vdev_id),
+			     struct oem_data *oem_data,
+			     uint8_t vdev_id);
 #endif
 
 #ifdef FEATURE_OEM_DATA_SUPPORT
@@ -4069,43 +4075,6 @@ QDF_STATUS sme_get_ani_level(mac_handle_t mac_handle, uint32_t *freqs,
 			     void *context), void *context);
 #endif /* FEATURE_ANI_LEVEL_REQUEST */
 
-#ifdef FEATURE_OEM_DATA
-/**
- * sme_set_oem_data_event_handler_cb() - Register oem data event handler
- * callback
- * @mac_handle: Opaque handle to the MAC context
- * @oem_data_event_handler_cb: callback to be registered
- *
- * Return: QDF_STATUS
- */
-QDF_STATUS sme_set_oem_data_event_handler_cb(
-			mac_handle_t mac_handle,
-			void (*oem_data_event_handler_cb)
-				(const struct oem_data *oem_event_data));
-
-/**
- * sme_reset_oem_data_event_handler_cb() - De-register oem data event handler
- * @mac_handle: Handler return by mac_open
- *
- * This function De-registers the OEM data event handler callback to SME
- *
- * Return: None
- */
-void sme_reset_oem_data_event_handler_cb(mac_handle_t  mac_handle);
-#else
-static inline QDF_STATUS sme_set_oem_data_event_handler_cb(
-			mac_handle_t mac_handle,
-			void (*oem_data_event_handler_cb)
-				(void *oem_event_data))
-{
-	return QDF_STATUS_SUCCESS;
-}
-
-static inline void sme_reset_oem_data_event_handler_cb(mac_handle_t  mac_handle)
-{
-}
-#endif
-
 /**
  * sme_get_prev_connected_bss_ies() - Get the previous connected AP IEs
  * @mac_handle: The handle returned by mac_open.

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

@@ -380,7 +380,9 @@ struct sme_context {
 #endif
 #ifdef FEATURE_OEM_DATA
 	void (*oem_data_event_handler_cb)
-			(const struct oem_data *oem_event_data);
+			(const struct oem_data *oem_event_data,
+			 uint8_t vdev_id);
+	uint8_t oem_data_vdev_id;
 #endif
 	sme_get_raom_scan_ch_callback roam_scan_ch_callback;
 	void *roam_scan_ch_get_context;

+ 12 - 37
core/sme/src/common/sme_api.c

@@ -3700,10 +3700,15 @@ QDF_STATUS sme_oem_req_cmd(mac_handle_t mac_handle,
 
 #ifdef FEATURE_OEM_DATA
 QDF_STATUS sme_oem_data_cmd(mac_handle_t mac_handle,
-			    struct oem_data *oem_data)
+			    void (*oem_data_event_handler_cb)
+			    (const struct oem_data *oem_event_data,
+			     uint8_t vdev_id),
+			     struct oem_data *oem_data,
+			     uint8_t vdev_id)
 {
 	QDF_STATUS status;
 	void *wma_handle;
+	struct mac_context *mac = MAC_CONTEXT(mac_handle);
 
 	SME_ENTER();
 	wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
@@ -3712,6 +3717,12 @@ QDF_STATUS sme_oem_data_cmd(mac_handle_t mac_handle,
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		mac->sme.oem_data_event_handler_cb = oem_data_event_handler_cb;
+		mac->sme.oem_data_vdev_id = vdev_id;
+		sme_release_global_lock(&mac->sme);
+	}
 	status = wma_start_oem_data_cmd(wma_handle, oem_data);
 	if (!QDF_IS_STATUS_SUCCESS(status))
 		sme_err("fail to call wma_start_oem_data_cmd.");
@@ -16062,42 +16073,6 @@ QDF_STATUS sme_get_ani_level(mac_handle_t mac_handle, uint32_t *freqs,
 }
 #endif /* FEATURE_ANI_LEVEL_REQUEST */
 
-#ifdef FEATURE_OEM_DATA
-QDF_STATUS sme_set_oem_data_event_handler_cb(
-			mac_handle_t mac_handle,
-			void (*oem_data_event_handler_cb)
-					(const struct oem_data *oem_event_data))
-{
-	struct mac_context *mac = MAC_CONTEXT(mac_handle);
-	QDF_STATUS qdf_status;
-
-	qdf_status = sme_acquire_global_lock(&mac->sme);
-	if (QDF_IS_STATUS_SUCCESS(qdf_status)) {
-		mac->sme.oem_data_event_handler_cb = oem_data_event_handler_cb;
-		sme_release_global_lock(&mac->sme);
-	}
-	return qdf_status;
-}
-
-void sme_reset_oem_data_event_handler_cb(mac_handle_t  mac_handle)
-{
-	struct mac_context *pmac;
-	QDF_STATUS qdf_status;
-
-	if (!mac_handle) {
-		sme_err("mac_handle is not valid");
-		return;
-	}
-	pmac = MAC_CONTEXT(mac_handle);
-
-	qdf_status = sme_acquire_global_lock(&pmac->sme);
-	if (QDF_IS_STATUS_SUCCESS(qdf_status)) {
-		pmac->sme.oem_data_event_handler_cb = NULL;
-		sme_release_global_lock(&pmac->sme);
-	}
-}
-#endif
-
 QDF_STATUS sme_get_prev_connected_bss_ies(mac_handle_t mac_handle,
 					  uint8_t vdev_id,
 					  uint8_t **ies, uint32_t *ie_len)

+ 3 - 2
core/wma/src/wma_utils.c

@@ -4950,8 +4950,9 @@ int wma_oem_event_handler(void *wma_ctx, uint8_t *event_buff, uint32_t len)
 
 	oem_event_data.data_len = event->data_len;
 	oem_event_data.data = param_buf->data;
-
-	pmac->sme.oem_data_event_handler_cb(&oem_event_data);
+	pmac->sme.oem_data_event_handler_cb(&oem_event_data,
+					    pmac->sme.oem_data_vdev_id);
+	pmac->sme.oem_data_event_handler_cb = NULL;
 
 	return QDF_STATUS_SUCCESS;
 }