Prechádzať zdrojové kódy

qcacld-3.0: Add support for TWT Terminate vendor command

Add support for TWT Terminate command request and response.

CRs-Fixed: 2736287
Change-Id: I710a600c53ad2b0f805ade70f254ea6aedcd4216
Rajasekaran Kalidoss 4 rokov pred
rodič
commit
188bf78da8

+ 2 - 0
core/hdd/inc/wlan_hdd_twt.h

@@ -35,6 +35,8 @@ struct hdd_context;
 struct hdd_adapter;
 struct wma_tgt_cfg;
 struct wmi_twt_add_dialog_param;
+struct wmi_twt_del_dialog_param;
+
 extern const struct nla_policy qca_wlan_vendor_twt_add_dialog_policy[
 		QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
 

+ 273 - 0
core/hdd/src/wlan_hdd_twt.c

@@ -36,6 +36,7 @@
 
 #define TWT_SETUP_COMPLETE_TIMEOUT 1000
 #define TWT_DISABLE_COMPLETE_TIMEOUT 1000
+#define TWT_TERMINATE_COMPLETE_TIMEOUT 1000
 
 /**
  * struct twt_add_dialog_complete_event - TWT add dialog complete event
@@ -61,6 +62,17 @@ struct twt_add_dialog_comp_ev_priv {
 	struct twt_add_dialog_complete_event add_dialog_comp_ev_buf;
 };
 
+/**
+ * struct twt_del_dialog_comp_ev_priv - private struct for twt del dialog
+ * @del_dialog_comp_ev_buf: buffer from TWT del dialog complete_event
+ *
+ * This TWT del dialog private structure is registered with os_if to
+ * retrieve the TWT del dialog response event buffer.
+ */
+struct twt_del_dialog_comp_ev_priv {
+	struct wmi_twt_del_dialog_complete_event_param del_dialog_comp_ev_buf;
+};
+
 const struct nla_policy
 wlan_hdd_wifi_twt_config_policy[
 	QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1] = {
@@ -130,6 +142,37 @@ int wmi_twt_add_cmd_to_vendor_twt_resp_type(enum WMI_HOST_TWT_COMMAND type)
 	}
 }
 
+/**
+ * wmi_twt_del_status_to_vendor_twt_status() - convert from
+ * WMI_HOST_DEL_TWT_STATUS to qca_wlan_vendor_twt_status
+ * @status: WMI_HOST_DEL_TWT_STATUS value from firmare
+ *
+ * Return: qca_wlan_vendor_twt_status values corresponsing
+ * to the firmware failure status
+ */
+static
+int wmi_twt_del_status_to_vendor_twt_status(enum WMI_HOST_DEL_TWT_STATUS status)
+{
+	switch (status) {
+	case WMI_HOST_DEL_TWT_STATUS_OK:
+		return QCA_WLAN_VENDOR_TWT_STATUS_OK;
+	case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_NOT_EXIST:
+		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
+	case WMI_HOST_DEL_TWT_STATUS_INVALID_PARAM:
+		return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
+	case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_BUSY:
+		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY;
+	case WMI_HOST_DEL_TWT_STATUS_NO_RESOURCE:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
+	case WMI_HOST_DEL_TWT_STATUS_NO_ACK:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
+	case WMI_HOST_DEL_TWT_STATUS_UNKNOWN_ERROR:
+		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
+	default:
+		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
+	}
+}
+
 /**
  * wmi_twt_add_status_to_vendor_twt_status() - convert from
  * WMI_HOST_ADD_TWT_STATUS to qca_wlan_vendor_twt_status
@@ -461,6 +504,235 @@ static int hdd_twt_setup_session(struct hdd_adapter *adapter,
 	return ret;
 }
 
+/**
+ * hdd_get_twt_terminate_event_len() - calculate length of skb
+ * required for sending twt terminate response.
+ *
+ * Return: length of skb
+ */
+static uint32_t hdd_get_twt_terminate_event_len(void)
+{
+	uint32_t len = 0;
+
+	len += NLMSG_HDRLEN;
+	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
+	len += nla_total_size(sizeof(u8));
+	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */
+	len += nla_total_size(sizeof(u8));
+
+	return len;
+}
+
+/**
+ * hdd_twt_terminate_pack_resp_nlmsg() - pack the skb with
+ * firmware response for twt terminate command
+ * @reply_skb: skb to store the response
+ * @params: Pointer to del dialog complete event buffer
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+hdd_twt_terminate_pack_resp_nlmsg(struct sk_buff *reply_skb,
+				  struct wmi_twt_del_dialog_complete_event_param *params)
+{
+	int vendor_status;
+
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID,
+		       params->dialog_id)) {
+		hdd_debug("TWT: Failed to put dialog_id");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	vendor_status = wmi_twt_del_status_to_vendor_twt_status(params->status);
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS,
+		       vendor_status)) {
+		hdd_err("TWT: Failed to put QCA_WLAN_TWT_TERMINATE");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * hdd_twt_del_dialog_comp_cb() - callback function
+ * to get twt terminate command complete event
+ * @context: private context
+ * @params: Pointer to del dialog complete event buffer
+ *
+ * Return: None
+ */
+static void
+hdd_twt_del_dialog_comp_cb(void *context,
+			   struct wmi_twt_del_dialog_complete_event_param *params)
+{
+	struct osif_request *request;
+	struct twt_del_dialog_comp_ev_priv *priv;
+
+	hdd_enter();
+
+	request = osif_request_get(context);
+	if (!request) {
+		hdd_err("Obsolete request");
+		return;
+	}
+
+	priv = osif_request_priv(request);
+	qdf_mem_copy(&priv->del_dialog_comp_ev_buf, params,
+		     sizeof(*params));
+	osif_request_complete(request);
+	osif_request_put(request);
+
+	hdd_debug("TWT: del dialog_id:%d, status:%d vdev_id %d peer mac_addr "
+		  QDF_MAC_ADDR_FMT, params->dialog_id,
+		  params->status, params->vdev_id,
+		  QDF_MAC_ADDR_REF(params->peer_macaddr));
+
+	hdd_exit();
+}
+
+/**
+ * hdd_send_twt_del_dialog_cmd() - Send TWT del dialog command to target
+ * @hdd_ctx: HDD Context
+ * @twt_params: Pointer to del dialog cmd params structure
+ *
+ * Return: QDF_STATUS
+ */
+static
+int hdd_send_twt_del_dialog_cmd(struct hdd_context *hdd_ctx,
+				struct wmi_twt_del_dialog_param *twt_params)
+{
+	struct wmi_twt_del_dialog_complete_event_param *del_dialog_comp_ev_params;
+	struct twt_del_dialog_comp_ev_priv *priv;
+	static const struct osif_request_params osif_req_params = {
+		.priv_size = sizeof(*priv),
+		.timeout_ms = TWT_TERMINATE_COMPLETE_TIMEOUT,
+		.dealloc = NULL,
+	};
+	struct osif_request *request;
+	struct sk_buff *reply_skb = NULL;
+	QDF_STATUS status;
+	void *cookie;
+	int skb_len;
+	int ret = 0;
+
+	request = osif_request_alloc(&osif_req_params);
+	if (!request) {
+		hdd_err("twt osif request allocation failure");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	cookie = osif_request_cookie(request);
+
+	status = sme_del_dialog_cmd(hdd_ctx->mac_handle,
+				    hdd_twt_del_dialog_comp_cb,
+				    twt_params,
+				    cookie);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("Failed to send del dialog command");
+		ret = qdf_status_to_os_return(status);
+		goto err;
+	}
+
+	ret = osif_request_wait_for_response(request);
+	if (ret) {
+		hdd_err("twt: del dialog req timedout");
+		ret = -ETIMEDOUT;
+		goto err;
+	}
+
+	priv = osif_request_priv(request);
+	del_dialog_comp_ev_params = &priv->del_dialog_comp_ev_buf;
+
+	skb_len = hdd_get_twt_terminate_event_len();
+	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
+							     skb_len);
+	if (!reply_skb) {
+		hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	status = hdd_twt_terminate_pack_resp_nlmsg(reply_skb,
+						   del_dialog_comp_ev_params);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("Failed to pack nl del dialog response");
+		ret = qdf_status_to_os_return(status);
+		goto err;
+	}
+
+	ret = wlan_cfg80211_vendor_cmd_reply(reply_skb);
+
+err:
+	if (request)
+		osif_request_put(request);
+	if (ret && reply_skb)
+		kfree_skb(reply_skb);
+	return ret;
+}
+
+/**
+ * hdd_twt_terminate_session - Process TWT terminate
+ * operation in the recevied vendor command and
+ * send it to firmare
+ * @adapter: adapter pointer
+ * @twt_param_attr: nl attributes
+ *
+ * Handles QCA_WLAN_TWT_TERMINATE
+ *
+ * Return: 0 on success, negative value on failure
+ */
+static int hdd_twt_terminate_session(struct hdd_adapter *adapter,
+				     struct nlattr *twt_param_attr)
+{
+	struct hdd_station_ctx *hdd_sta_ctx = NULL;
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
+	struct wmi_twt_del_dialog_param params = {0};
+	int id;
+	int ret;
+
+	if (adapter->device_mode != QDF_STA_MODE &&
+	    adapter->device_mode != QDF_P2P_CLIENT_MODE) {
+		return -EOPNOTSUPP;
+	}
+
+	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+	if (hdd_sta_ctx->conn_info.conn_state != eConnectionState_Associated) {
+		hdd_err_rl("Invalid state, vdev %d mode %d state %d",
+			   adapter->vdev_id, adapter->device_mode,
+			   hdd_sta_ctx->conn_info.conn_state);
+		return -EINVAL;
+	}
+
+	qdf_mem_copy(params.peer_macaddr,
+		     hdd_sta_ctx->conn_info.bssid.bytes,
+		     QDF_MAC_ADDR_SIZE);
+	params.vdev_id = adapter->vdev_id;
+
+	ret = wlan_cfg80211_nla_parse_nested(tb,
+					     QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
+					     twt_param_attr,
+					     qca_wlan_vendor_twt_add_dialog_policy);
+	if (ret)
+		return ret;
+
+	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
+	if (tb[id]) {
+		params.dialog_id = nla_get_u8(tb[id]);
+	} else {
+		params.dialog_id = 0;
+		hdd_debug("TWT_TERMINATE_FLOW_ID not specified. set to zero");
+	}
+
+	hdd_debug("twt_terminate: vdev_id %d dialog_id %d peer mac_addr "
+		  QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id,
+		  QDF_MAC_ADDR_REF(params.peer_macaddr));
+
+	ret = hdd_send_twt_del_dialog_cmd(adapter->hdd_ctx, &params);
+
+	return ret;
+}
+
 /**
  * hdd_twt_configure - Process the TWT
  * operation in the recevied vendor command
@@ -506,6 +778,7 @@ static int hdd_twt_configure(struct hdd_adapter *adapter,
 	case QCA_WLAN_TWT_GET:
 		break;
 	case QCA_WLAN_TWT_TERMINATE:
+		ret = hdd_twt_terminate_session(adapter, twt_param_attr);
 		break;
 	case QCA_WLAN_TWT_SUSPEND:
 		break;

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

@@ -3647,6 +3647,21 @@ QDF_STATUS sme_add_dialog_cmd(mac_handle_t mac_handle,
 			      struct wmi_twt_add_dialog_param *twt_params,
 			      void *context);
 
+/**
+ * sme_del_dialog_cmd() - Register callback and send TWT del dialog
+ * command to firmware
+ * @mac_handle: MAC handle
+ * @twt_del_dialog_cb: Function callback to handle del_dialog event
+ * @twt_params: TWT del dialog parameters
+ * @context: os_if_request cookie
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS sme_del_dialog_cmd(mac_handle_t mac_handle,
+			      twt_del_dialog_cb del_dialog_cb,
+			      struct wmi_twt_del_dialog_param *twt_params,
+			      void *context);
+
 /**
  * sme_deregister_twt_enable_complete_cb() - TWT enable deregistrar
  * @mac_handle: Opaque handle to the global MAC context

+ 10 - 0
core/sme/inc/sme_internal.h

@@ -169,6 +169,15 @@ typedef void (*twt_disable_cb)(hdd_handle_t hdd_handle);
 typedef void (*twt_add_dialog_cb)(void *context,
 				  struct wmi_twt_add_dialog_complete_event_param *params,
 				  struct wmi_twt_add_dialog_additional_params *additional_params);
+
+/**
+ * typedef twt_del_dialog_cb - TWT delete dialog callback signature.
+ * @context: Opaque context that the client can use to associate the
+ *           callback with the request.
+ * @params: TWT delete dialog complete event parameters.
+ */
+typedef void (*twt_del_dialog_cb)(void *context,
+				  struct wmi_twt_del_dialog_complete_event_param *params);
 #endif
 
 #ifdef FEATURE_WLAN_APF
@@ -379,6 +388,7 @@ struct sme_context {
 	twt_enable_cb twt_enable_cb;
 	twt_disable_cb twt_disable_cb;
 	twt_add_dialog_cb twt_add_dialog_cb;
+	twt_del_dialog_cb twt_del_dialog_cb;
 	void *twt_context;
 #endif
 #ifdef FEATURE_WLAN_APF

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

@@ -14486,6 +14486,42 @@ QDF_STATUS sme_add_dialog_cmd(mac_handle_t mac_handle,
 	return status;
 }
 
+QDF_STATUS sme_del_dialog_cmd(mac_handle_t mac_handle,
+			      twt_del_dialog_cb del_dialog_cb,
+			      struct wmi_twt_del_dialog_param *twt_params,
+			      void *context)
+{
+	struct mac_context *mac = MAC_CONTEXT(mac_handle);
+	QDF_STATUS status;
+	void *wma_handle;
+
+	SME_ENTER();
+	wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
+	if (!wma_handle) {
+		sme_err("wma_handle is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		mac->sme.twt_del_dialog_cb = del_dialog_cb;
+		mac->sme.twt_context = context;
+		sme_release_global_lock(&mac->sme);
+	}
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		sme_err("failed to register del dlg callback");
+		return status;
+	}
+
+	status = wma_twt_process_del_dialog(twt_params);
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		sme_err("failed to call wma_twt_process_del_dialog");
+
+	SME_EXIT();
+	return status;
+}
+
 #endif
 
 QDF_STATUS sme_set_smps_cfg(uint32_t vdev_id, uint32_t param_id,

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

@@ -1738,6 +1738,17 @@ int wma_twt_disable_comp_event_handler(void *handle, uint8_t *event,
  */
 int wma_twt_add_dialog_complete_event_handler(void *handle,
 					      uint8_t *event, uint32_t len);
+
+/**
+ * wma_twt_del_dialog_complete_event_handler - TWT del dlg complete evt handler
+ * @handle: wma handle
+ * @event: buffer with event
+ * @len: buffer length
+ *
+ * Return: 0 on success
+ */
+int wma_twt_del_dialog_complete_event_handler(void *handle,
+					      uint8_t *event, uint32_t len);
 #endif
 
 /**

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

@@ -3369,6 +3369,11 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc,
 				 wmi_twt_add_dialog_complete_event_id,
 				 wma_twt_add_dialog_complete_event_handler,
 				 WMA_RX_SERIALIZER_CTX);
+	wmi_unified_register_event_handler
+				(wma_handle->wmi_handle,
+				 wmi_twt_del_dialog_complete_event_id,
+				 wma_twt_del_dialog_complete_event_handler,
+				 WMA_RX_SERIALIZER_CTX);
 #endif
 
 	wma_register_apf_events(wma_handle);

+ 34 - 0
core/wma/src/wma_twt.c

@@ -214,3 +214,37 @@ QDF_STATUS wma_twt_process_del_dialog(
 
 	return wmi_unified_twt_del_dialog_cmd(wmi_handle, params);
 }
+
+int wma_twt_del_dialog_complete_event_handler(void *handle,
+					      uint8_t *event, uint32_t len)
+{
+	struct wmi_twt_del_dialog_complete_event_param param;
+	tp_wma_handle wma_handle = handle;
+	wmi_unified_t wmi_handle;
+	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
+	int status = -EINVAL;
+
+	if (!wma_handle) {
+		wma_err("Invalid wma handle for TWT del dialog complete");
+		return status;
+	}
+	wmi_handle = (wmi_unified_t)wma_handle->wmi_handle;
+	if (!wmi_handle) {
+		wma_err("Invalid wma handle for TWT del dialog complete");
+		return status;
+	}
+	if (!mac) {
+		wma_err("Invalid MAC context");
+		return status;
+	}
+	status = wmi_extract_twt_del_dialog_comp_event(wmi_handle, event,
+						       &param);
+	wma_debug("TWT: Extract TWT del dlg comp event, status:%d", status);
+
+	if (mac->sme.twt_del_dialog_cb)
+		mac->sme.twt_del_dialog_cb(mac->sme.twt_context, &param);
+
+	mac->sme.twt_del_dialog_cb = NULL;
+
+	return status;
+}