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
This commit is contained in:
Rajasekaran Kalidoss 2020-07-19 22:23:25 +05:30 • committed by snandini
commit 188bf78da8
8 changed files with 386 additions and 0 deletions

View file

@ -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];

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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
/**

View file

@ -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);

View file

@ -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;
}