qcacld-3.0: Add vendor command to get sta info

Add subcmd QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO and related attributes.

Change-Id: I2bd90d90666b95902dc0821d762adbc5c5e675c6
CRs-fixed: 2592863
This commit is contained in:
Min Liu
2019-10-21 15:30:42 +08:00
committed by snandini
orang tua 3787826aed
melakukan 57c9424490
5 mengubah file dengan 512 tambahan dan 6 penghapusan

Melihat File

@@ -925,8 +925,9 @@ struct hdd_mic_work {
* @tx_bytes: bytes transmitted to this station
* @rx_packets: packets received from this station
* @rx_bytes: bytes received from this station
* @rx_retries: cumulative retry counts
* @tx_failed: number of failed transmissions
* @tx_retries: cumulative retry counts
* @tx_failed: the number of failed frames
* @tx_succeed: the number of succeed frames
* @rssi: The signal strength (dbm)
* @tx_rate: last used tx rate info
* @rx_rate: last used rx rate info
@@ -940,6 +941,7 @@ struct hdd_fw_txrx_stats {
uint64_t rx_bytes;
uint32_t tx_retries;
uint32_t tx_failed;
uint32_t tx_succeed;
int8_t rssi;
struct hdd_rate_info tx_rate;
struct hdd_rate_info rx_rate;

Melihat File

@@ -174,7 +174,7 @@ char *sta_info_string_from_dbgid(wlan_sta_info_dbgid id);
* @rate_flags: Rate Flags for this connection
* @ecsa_capable: Extended CSA capabilities
* @max_phy_rate: Calcuated maximum phy rate based on mode, nss, mcs etc.
* @tx_packets: Packets send to current station
* @tx_packets: The number of frames from host to firmware
* @tx_bytes: Bytes send to current station
* @rx_packets: Packets received from current station
* @rx_bytes: Bytes received from current station
@@ -184,6 +184,7 @@ char *sta_info_string_from_dbgid(wlan_sta_info_dbgid id);
* @rx_rate: Rx rate with current station reported from F/W
* @ampdu: Ampdu enable or not of the station
* @sgi_enable: Short GI enable or not of the station
* @guard_interval: Guard interval
* @tx_stbc: Tx Space-time block coding enable/disable
* @rx_stbc: Rx Space-time block coding enable/disable
* @ch_width: Channel Width of the connection
@@ -211,6 +212,13 @@ char *sta_info_string_from_dbgid(wlan_sta_info_dbgid id);
* MSB of rx_mc_bc_cnt indicates whether FW supports rx_mc_bc_cnt
* feature or not, if first bit is 1 it indicates that FW supports this
* feature, if it is 0 it indicates FW doesn't support this feature
* @tx_retry_succeed: the number of frames retried but successfully transmit
* @tx_retry_exhaust: the number of frames retried but finally failed
* from host to firmware
* @tx_total_fw: the number of all frames from firmware to remote station
* @tx_retry_fw: the number of retried frames from firmware to remote station
* @tx_retry_exhaust_fw: the number of frames retried but finally failed from
* firmware to remote station
* @sta_info: The sta_info node for the station info list maintained in adapter
* @assoc_req_ies: Assoc request IEs of the peer station
* @ref_cnt: Reference count to synchronize sta_info access
@@ -242,6 +250,7 @@ struct hdd_station_info {
uint32_t rx_rate;
bool ampdu;
bool sgi_enable;
enum txrate_gi guard_interval;
bool tx_stbc;
bool rx_stbc;
tSirMacHTChannelWidth ch_width;
@@ -265,6 +274,11 @@ struct hdd_station_info {
uint8_t support_mode;
uint32_t rx_retry_cnt;
uint32_t rx_mc_bc_cnt;
uint32_t tx_retry_succeed;
uint32_t tx_retry_exhaust;
uint32_t tx_total_fw;
uint32_t tx_retry_fw;
uint32_t tx_retry_exhaust_fw;
qdf_list_node_t sta_node;
struct wlan_ies assoc_req_ies;
qdf_atomic_t ref_cnt;

Melihat File

@@ -38,6 +38,11 @@
#include "wlan_hdd_sta_info.h"
#include "wlan_hdd_object_manager.h"
#include <cdp_txrx_handle.h>
#include <cdp_txrx_stats_struct.h>
#include <cdp_txrx_peer_ops.h>
#include <cdp_txrx_host_stats.h>
/*
* define short names for the global vendor params
* used by __wlan_hdd_cfg80211_get_station_cmd()
@@ -130,6 +135,12 @@ hdd_get_station_policy[STATION_MAX + 1] = {
[STATION_REMOTE] = {.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE},
};
const struct nla_policy
hdd_get_sta_policy[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX + 1] = {
[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC] = {.type = NLA_BINARY,
.len = QDF_MAC_ADDR_SIZE},
};
static int hdd_get_sta_congestion(struct hdd_adapter *adapter,
uint32_t *congestion)
{
@@ -1473,3 +1484,451 @@ int32_t hdd_cfg80211_get_station_cmd(struct wiphy *wiphy,
return errno;
}
/**
* hdd_get_peer_stats - get peer statistics information
* @adapter: pointer to adapter
* @stainfo: station information
*
* This function gets peer statistics information
*
* Return : 0 on success and errno on failure
*/
static int hdd_get_peer_stats(struct hdd_adapter *adapter,
struct hdd_station_info *stainfo)
{
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
struct cdp_peer_stats *peer_stats;
struct stats_event *stats;
QDF_STATUS status;
int ret;
peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
if (!peer_stats)
return -ENOMEM;
status = cdp_host_get_peer_stats(soc, adapter->vdev_id,
stainfo->sta_mac.bytes, peer_stats);
if (status != QDF_STATUS_SUCCESS) {
hdd_err("cdp_host_get_peer_stats failed");
return -EINVAL;
}
stainfo->rx_retry_cnt = peer_stats->rx.rx_retries;
stainfo->rx_mc_bc_cnt = peer_stats->rx.multicast.num +
peer_stats->rx.bcast.num;
qdf_mem_free(peer_stats);
peer_stats = NULL;
stats = wlan_cfg80211_mc_cp_stats_get_peer_stats(adapter->vdev,
stainfo->sta_mac.bytes,
&ret);
if (ret || !stats) {
wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
hdd_err("Failed to get peer stats info");
return -EINVAL;
}
stainfo->tx_retry_succeed = stats->peer_stats_info_ext->tx_retries -
stats->peer_stats_info_ext->tx_failed;
/* This host counter is not supported
* since currently tx retry is not done in host side
*/
stainfo->tx_retry_exhaust = 0;
stainfo->tx_total_fw = stats->peer_stats_info_ext->tx_packets;
stainfo->tx_retry_fw = stats->peer_stats_info_ext->tx_retries;
stainfo->tx_retry_exhaust_fw = stats->peer_stats_info_ext->tx_failed;
wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
return 0;
}
/**
* hdd_add_peer_stats_get_len - get data length used in
* hdd_add_peer_stats()
* @stainfo: station information
*
* This function calculates the data length used in
* hdd_add_peer_stats()
*
* Return: total data length used in hdd_add_peer_stats()
*/
static uint32_t
hdd_add_peer_stats_get_len(struct hdd_station_info *stainfo)
{
return (nla_attr_size(sizeof(stainfo->rx_retry_cnt)) +
nla_attr_size(sizeof(stainfo->rx_mc_bc_cnt)) +
nla_attr_size(sizeof(stainfo->tx_retry_succeed)) +
nla_attr_size(sizeof(stainfo->tx_retry_exhaust)) +
nla_attr_size(sizeof(stainfo->tx_total_fw)) +
nla_attr_size(sizeof(stainfo->tx_retry_fw)) +
nla_attr_size(sizeof(stainfo->tx_retry_exhaust_fw)));
}
/**
* hdd_add_peer_stats - add peer statistics information
* @skb: pointer to response skb buffer
* @stainfo: station information
*
* This function adds peer statistics information to response skb buffer
*
* Return : 0 on success and errno on failure
*/
static int hdd_add_peer_stats(struct sk_buff *skb,
struct hdd_station_info *stainfo)
{
if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_RETRY_COUNT,
stainfo->rx_retry_cnt)) {
hdd_err("Failed to put rx_retry_cnt");
goto fail;
}
if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BC_MC_COUNT,
stainfo->rx_mc_bc_cnt)) {
hdd_err("Failed to put rx_mc_bc_cnt");
goto fail;
}
if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_SUCCEED,
stainfo->tx_retry_succeed)) {
hdd_err("Failed to put tx_retry_succeed");
goto fail;
}
if (nla_put_u32(skb,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_EXHAUSTED,
stainfo->tx_retry_exhaust)) {
hdd_err("Failed to put tx_retry_exhaust");
goto fail;
}
if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_TOTAL,
stainfo->tx_total_fw)) {
hdd_err("Failed to put tx_total_fw");
goto fail;
}
if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY,
stainfo->tx_retry_fw)) {
hdd_err("Failed to put tx_retry_fw");
goto fail;
}
if (nla_put_u32(skb,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED,
stainfo->tx_retry_exhaust_fw)) {
hdd_err("Failed to put tx_retry_exhaust_fw");
goto fail;
}
return 0;
fail:
return -EINVAL;
}
/**
* hdd_get_station_info_ex() - send STA info to userspace, for STA mode only
* @hdd_ctx: pointer to hdd context
* @adapter: pointer to adapter
* @mac_addr: self mac address
*
* Return: 0 if success else error status
*/
static int hdd_get_station_info_ex(struct hdd_context *hdd_ctx,
struct hdd_adapter *adapter,
struct qdf_mac_addr mac_addr)
{
struct sk_buff *skb = NULL;
uint32_t nl_buf_len;
struct hdd_station_ctx *hdd_sta_ctx;
struct hdd_station_info stainfo;
hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
if (!hdd_sta_ctx) {
hdd_err_rl("Invalid hdd_sta_ctx");
return -EINVAL;
}
if (!qdf_is_macaddr_equal(&mac_addr, &adapter->mac_addr)) {
hdd_err_rl("Invalid MAC address");
return -EINVAL;
}
qdf_mem_copy(&stainfo.sta_mac, &mac_addr, sizeof(stainfo.sta_mac));
if (hdd_get_peer_stats(adapter, &stainfo)) {
hdd_err_rl("hdd_get_peer_stats fail");
return -EINVAL;
}
nl_buf_len = NLMSG_HDRLEN;
nl_buf_len += nla_attr_size(QDF_MAC_ADDR_SIZE) +
hdd_add_peer_stats_get_len(&stainfo);
skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len);
if (!skb) {
hdd_err_rl("cfg80211_vendor_cmd_alloc_reply_skb failed");
return -ENOMEM;
}
if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC,
QDF_MAC_ADDR_SIZE, mac_addr.bytes)) {
hdd_err_rl("Failed to put MAC address");
goto fail;
}
if (hdd_add_peer_stats(skb, &stainfo)) {
hdd_err_rl("hdd_add_peer_stats fail");
goto fail;
}
return cfg80211_vendor_cmd_reply(skb);
fail:
if (skb)
kfree_skb(skb);
return -EINVAL;
}
/**
* hdd_get_connected_station_info_ex() - get connected peer's info
* @hdd_ctx: hdd context
* @adapter: hostapd interface
* @stainfo: pointer to hdd_station_info
*
* This function collect and indicate the connected peer's info
*
* Return: 0 on success, otherwise error value
*/
static int hdd_get_connected_station_info_ex(struct hdd_context *hdd_ctx,
struct hdd_adapter *adapter,
struct hdd_station_info *stainfo)
{
struct sk_buff *skb = NULL;
uint32_t nl_buf_len, guard_interval;
bool sap_get_peer_info;
struct nl80211_sta_flag_update sta_flags = {0};
QDF_STATUS status;
if (hdd_get_peer_stats(adapter, stainfo)) {
hdd_err_rl("hdd_get_peer_stats fail");
return -EINVAL;
}
nl_buf_len = NLMSG_HDRLEN;
nl_buf_len += nla_attr_size(QDF_MAC_ADDR_SIZE);
status = ucfg_mlme_get_sap_get_peer_info(hdd_ctx->psoc,
&sap_get_peer_info);
if (status != QDF_STATUS_SUCCESS)
hdd_err_rl("Unable to fetch sap ger peer info");
if (sap_get_peer_info)
nl_buf_len += hdd_add_peer_stats_get_len(stainfo);
if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY)
nl_buf_len += nla_attr_size(sizeof(sta_flags)) +
nla_attr_size(sizeof(guard_interval));
skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len);
if (!skb) {
hdd_err_rl("cfg80211_vendor_cmd_alloc_reply_skb failed");
goto fail;
}
if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC,
QDF_MAC_ADDR_SIZE, stainfo->sta_mac.bytes)) {
hdd_err_rl("Failed to put MAC address");
goto fail;
}
if (sap_get_peer_info && hdd_add_peer_stats(skb, stainfo)) {
hdd_err_rl("hdd_add_peer_stats fail");
goto fail;
}
if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) {
sta_flags.mask = QCA_VENDOR_WLAN_STA_FLAG_AMPDU |
QCA_VENDOR_WLAN_STA_FLAG_TX_STBC |
QCA_VENDOR_WLAN_STA_FLAG_RX_STBC;
if (stainfo->ampdu)
sta_flags.set |= QCA_VENDOR_WLAN_STA_FLAG_AMPDU;
if (stainfo->tx_stbc)
sta_flags.set |= QCA_VENDOR_WLAN_STA_FLAG_TX_STBC;
if (stainfo->rx_stbc)
sta_flags.set |= QCA_VENDOR_WLAN_STA_FLAG_RX_STBC;
if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_FLAGS,
sizeof(sta_flags), &sta_flags)) {
hdd_err_rl("Failed to put STA flags");
goto fail;
}
switch (stainfo->guard_interval) {
case TXRATE_GI_0_8_US:
guard_interval = QCA_VENDOR_WLAN_STA_GI_800_NS;
break;
case TXRATE_GI_0_4_US:
guard_interval = QCA_VENDOR_WLAN_STA_GI_400_NS;
break;
case TXRATE_GI_1_6_US:
guard_interval = QCA_VENDOR_WLAN_STA_GI_1600_NS;
break;
case TXRATE_GI_3_2_US:
guard_interval = QCA_VENDOR_WLAN_STA_GI_3200_NS;
break;
default:
hdd_err_rl("Invalid guard_interval %d",
stainfo->guard_interval);
goto fail;
}
if (nla_put_u32(skb,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_GUARD_INTERVAL,
guard_interval)) {
hdd_err_rl("Failed to put guard_interval");
goto fail;
}
}
return cfg80211_vendor_cmd_reply(skb);
fail:
if (skb)
kfree_skb(skb);
return -EINVAL;
}
/**
* hdd_get_station_remote_ex() - get remote peer's info, for SAP/GO mode only
* @hdd_ctx: hdd context
* @adapter: hostapd interface
* @mac_addr: mac address of requested peer
*
* This function collect and indicate the remote peer's info
*
* Return: 0 on success, otherwise error value
*/
static int hdd_get_station_remote_ex(struct hdd_context *hdd_ctx,
struct hdd_adapter *adapter,
struct qdf_mac_addr mac_addr)
{
bool is_associated = false;
struct hdd_station_info *stainfo =
hdd_get_sta_info_by_mac(&adapter->sta_info_list,
mac_addr.bytes,
STA_INFO_HDD_GET_STATION_REMOTE);
/* For now, only connected STAs are supported */
if (!stainfo) {
hdd_err_rl("Failed to get peer STA");
return -EINVAL;
}
is_associated = hdd_is_peer_associated(adapter, &mac_addr);
if (!is_associated) {
hdd_err_rl("Peer STA is not associated");
return -EINVAL;
}
return hdd_get_connected_station_info_ex(hdd_ctx, adapter, stainfo);
}
/**
* __hdd_cfg80211_get_sta_info_cmd() - Handle get sta info vendor cmd
* @wiphy: pointer to wireless phy
* @wdev: wireless device
* @data: data
* @data_len: data length
*
* Handles QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO.
* Validate cmd attributes and send the station info to upper layers.
*
* Return: Success(0) or reason code for failure
*/
static int
__hdd_cfg80211_get_sta_info_cmd(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data,
int data_len)
{
struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
struct net_device *dev = wdev->netdev;
struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX + 1];
struct qdf_mac_addr mac_addr;
int32_t status;
hdd_enter_dev(dev);
if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE ||
hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE) {
hdd_err_rl("Command not allowed in FTM / Monitor mode");
status = -EPERM;
goto out;
}
status = wlan_hdd_validate_context(hdd_ctx);
if (status != 0)
goto out;
status = wlan_cfg80211_nla_parse(tb,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX,
data, data_len,
hdd_get_sta_policy);
if (status) {
hdd_err_rl("Invalid ATTR");
goto out;
}
if (!tb[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC]) {
hdd_err_rl("MAC address is not present");
status = -EINVAL;
goto out;
}
nla_memcpy(mac_addr.bytes, tb[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC],
QDF_MAC_ADDR_SIZE);
hdd_debug("STA " QDF_MAC_ADDR_STR, QDF_MAC_ADDR_ARRAY(mac_addr.bytes));
switch (adapter->device_mode) {
case QDF_STA_MODE:
case QDF_P2P_CLIENT_MODE:
status = hdd_get_station_info_ex(hdd_ctx, adapter, mac_addr);
break;
case QDF_SAP_MODE:
case QDF_P2P_GO_MODE:
status = hdd_get_station_remote_ex(hdd_ctx, adapter, mac_addr);
break;
default:
hdd_err_rl("Invalid device_mode: %d", adapter->device_mode);
status = -EINVAL;
goto out;
}
hdd_exit();
out:
return status;
}
int32_t hdd_cfg80211_get_sta_info_cmd(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data,
int data_len)
{
struct osif_vdev_sync *vdev_sync;
int errno;
errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
if (errno)
return errno;
errno = __hdd_cfg80211_get_sta_info_cmd(wiphy, wdev, data, data_len);
osif_vdev_sync_op_stop(vdev_sync);
return errno;
}

Melihat File

@@ -46,6 +46,26 @@ int32_t hdd_cfg80211_get_station_cmd(struct wiphy *wiphy,
const void *data,
int data_len);
extern const struct nla_policy hdd_get_sta_policy[
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX + 1];
/**
* wlan_hdd_cfg80211_get_sta_info_cmd() - Handle get sta info vendor cmd
* @wiphy: corestack handler
* @wdev: wireless device
* @data: data
* @data_len: data length
*
* Handles QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO.
* Validate cmd attributes and send the station info to upper layers.
*
* Return: Success(0) or reason code for failure
*/
int32_t hdd_cfg80211_get_sta_info_cmd(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data,
int data_len);
#define FEATURE_STATION_INFO_VENDOR_COMMANDS \
{ \
.info.vendor_id = QCA_NL80211_VENDOR_ID, \
@@ -56,6 +76,16 @@ int32_t hdd_cfg80211_get_station_cmd(struct wiphy *wiphy,
.doit = hdd_cfg80211_get_station_cmd, \
vendor_command_policy(hdd_get_station_policy, \
QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX) \
}, \
{ \
.info.vendor_id = QCA_NL80211_VENDOR_ID, \
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO, \
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | \
WIPHY_VENDOR_CMD_NEED_NETDEV | \
WIPHY_VENDOR_CMD_NEED_RUNNING, \
.doit = hdd_cfg80211_get_sta_info_cmd, \
vendor_command_policy(hdd_get_sta_policy, \
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX) \
},
#else /* FEATURE_STATION_INFO */
#define FEATURE_STATION_INFO_VENDOR_COMMANDS

Melihat File

@@ -4274,11 +4274,11 @@ static uint8_t hdd_get_rate_flags(uint32_t rate,
}
/**
* wlan_hdd_fill_rate_info() - fill HDD rate info from SIR peer info
* wlan_hdd_fill_rate_info() - fill HDD rate info from peer info
* @txrx_stats: pointer to txrx stats to be filled with rate info
* @peer_info: SIR peer info pointer
* @peer_info: peer info pointer
*
* This function is used to fill HDD rate info rom SIR peer info
* This function is used to fill HDD rate info from peer info
*
* Return: None
*/
@@ -4407,6 +4407,7 @@ static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
txrx_stats.rx_bytes = stats->peer_stats_info_ext->rx_bytes;
txrx_stats.tx_retries = stats->peer_stats_info_ext->tx_retries;
txrx_stats.tx_failed = stats->peer_stats_info_ext->tx_failed;
txrx_stats.tx_succeed = stats->peer_stats_info_ext->tx_succeed;
txrx_stats.rssi = stats->peer_stats_info_ext->rssi
+ WLAN_HDD_TGT_NOISE_FLOOR_DBM;
wlan_hdd_fill_rate_info(&txrx_stats, stats->peer_stats_info_ext);