qcacld-3.0: Add support for TWT get capabilities vendor command

Add support to get the TWT self and peer capabilities via the
QCA_WLAN_TWT_GET_CAPABILTIES vendor command.
High 16 bits - self capabilities,
Low 16 bits : peer device’s capabilities

The meaning of each bit is below:
Bit 0: Requester Support
Bit 1: Responder Support
Bit 2: Broadcast TWT Support
Bit 3: Flexible TWT Support
Bit 4: TWT Required

Change-Id: I78b0c5902c89fe3a8eec1697fa513aac3c2b7a36
CRs-Fixed: 2847177
Cette révision appartient à :
Pragaspathi Thilagaraj
2020-12-06 00:04:37 +05:30
révisé par snandini
Parent fccdc9cc8a
révision f7735c8ba3

Voir le fichier

@@ -885,6 +885,10 @@ int wmi_twt_del_status_to_vendor_twt_status(enum WMI_HOST_DEL_TWT_STATUS status)
return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
case WMI_HOST_DEL_TWT_STATUS_UNKNOWN_ERROR:
return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
case WMI_DEL_TWT_STATUS_PEER_INIT_TEARDOWN:
return QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE;
case WMI_DEL_TWT_STATUS_ROAMING:
return QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE;
default:
return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
}
@@ -1193,6 +1197,7 @@ int hdd_send_twt_add_dialog_cmd(struct hdd_context *hdd_ctx,
static int hdd_twt_setup_session(struct hdd_adapter *adapter,
struct nlattr *twt_param_attr)
{
struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
struct hdd_station_ctx *hdd_sta_ctx = NULL;
struct wmi_twt_add_dialog_param params = {0};
struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
@@ -1212,6 +1217,9 @@ static int hdd_twt_setup_session(struct hdd_adapter *adapter,
return -EINVAL;
}
if (hdd_is_roaming_in_progress(hdd_ctx))
return -EBUSY;
qdf_mem_copy(params.peer_macaddr,
hdd_sta_ctx->conn_info.bssid.bytes,
QDF_MAC_ADDR_SIZE);
@@ -2014,6 +2022,125 @@ hdd_send_twt_resume_dialog_cmd(struct hdd_context *hdd_ctx,
return ret;
}
/**
* hdd_twt_pack_get_capabilities_resp - TWT pack and send response to
* userspace for get capabilities command
* @adapter: Pointer to hdd adapter
*
* Return: QDF_STATUS
*/
static QDF_STATUS
hdd_twt_pack_get_capabilities_resp(struct hdd_adapter *adapter)
{
struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
struct nlattr *config_attr;
struct sk_buff *reply_skb;
size_t skb_len = NLMSG_HDRLEN;
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
uint8_t peer_cap = 0, self_cap = 0;
bool twt_req = false, twt_bcast_req = false;
/*
* Length of attribute QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF &
* QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER
*/
skb_len += 2 * nla_total_size(sizeof(u16)) + NLA_HDRLEN;
reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
skb_len);
if (!reply_skb) {
hdd_err("TWT: get_caps alloc reply skb failed");
return QDF_STATUS_E_NOMEM;
}
config_attr = nla_nest_start(reply_skb,
QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
if (!config_attr) {
hdd_err("TWT: nla_nest_start error");
qdf_status = QDF_STATUS_E_FAILURE;
goto free_skb;
}
ucfg_mlme_get_twt_requestor(hdd_ctx->psoc, &twt_req);
if (twt_req)
self_cap |= QCA_WLAN_TWT_CAPA_REQUESTOR;
ucfg_mlme_get_twt_bcast_requestor(hdd_ctx->psoc,
&twt_bcast_req);
if (twt_bcast_req)
self_cap |= QCA_WLAN_TWT_CAPA_BROADCAST;
if (nla_put_u16(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF,
self_cap)) {
hdd_err("TWT: Failed to fill capabilities");
qdf_status = QDF_STATUS_E_FAILURE;
goto free_skb;
}
if (nla_put_u16(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER,
peer_cap)) {
hdd_err("TWT: Failed to fill capabilities");
qdf_status = QDF_STATUS_E_FAILURE;
goto free_skb;
}
nla_nest_end(reply_skb, config_attr);
if (cfg80211_vendor_cmd_reply(reply_skb))
qdf_status = QDF_STATUS_E_INVAL;
free_skb:
if (QDF_IS_STATUS_ERROR(qdf_status) && reply_skb)
kfree_skb(reply_skb);
return qdf_status;
}
/**
* hdd_twt_get_capabilities() - Process TWT resume operation
* in the received vendor command and send it to firmware
* @adapter: adapter pointer
* @twt_param_attr: nl attributes
*
* Handles QCA_WLAN_TWT_RESUME
*
* Return: 0 on success, negative value on failure
*/
static int hdd_twt_get_capabilities(struct hdd_adapter *adapter,
struct nlattr *twt_param_attr)
{
struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
struct hdd_station_ctx *hdd_sta_ctx;
QDF_STATUS status;
int ret = 0;
ret = wlan_hdd_validate_context(hdd_ctx);
if (ret < 0)
return -EINVAL;
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;
}
if (hdd_is_roaming_in_progress(hdd_ctx))
return -EBUSY;
status = hdd_twt_pack_get_capabilities_resp(adapter);
if (QDF_IS_STATUS_ERROR(status))
hdd_err_rl("TWT: Get capabilities failed");
return qdf_status_to_os_return(status);
}
/**
* hdd_twt_resume_session - Process TWT resume operation
* in the received vendor command and send it to firmware
@@ -2114,22 +2241,23 @@ static int hdd_twt_configure(struct hdd_adapter *adapter,
id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION;
twt_oper_attr = tb[id];
twt_oper = nla_get_u8(twt_oper_attr);
if (!twt_oper_attr) {
hdd_err("TWT parameters NOT specified");
hdd_err("TWT operation NOT specified");
return -EINVAL;
}
id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS;
twt_param_attr = tb[id];
if (!twt_param_attr) {
if (!twt_param_attr &&
twt_oper != QCA_WLAN_TWT_GET_CAPABILITIES) {
hdd_err("TWT parameters NOT specified");
return -EINVAL;
}
twt_oper = nla_get_u8(twt_oper_attr);
hdd_debug("twt: TWT Operation 0x%x", twt_oper);
hdd_debug("TWT Operation 0x%x", twt_oper);
switch (twt_oper) {
case QCA_WLAN_TWT_SET:
@@ -2150,6 +2278,9 @@ static int hdd_twt_configure(struct hdd_adapter *adapter,
case QCA_WLAN_TWT_NUDGE:
ret = hdd_twt_nudge_session(adapter, twt_param_attr);
break;
case QCA_WLAN_TWT_GET_CAPABILITIES:
ret = hdd_twt_get_capabilities(adapter, twt_param_attr);
break;
default:
hdd_err("Invalid TWT Operation");
ret = -EINVAL;
@@ -2204,6 +2335,7 @@ __wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy,
}
errno = hdd_twt_configure(adapter, tb);
return errno;
}