diff options
| author | Anurag Chouhan <achouhan@codeaurora.org> | 2017-02-23 20:43:24 +0530 |
|---|---|---|
| committer | Sandeep Puligilla <spuligil@codeaurora.org> | 2017-03-15 08:40:14 -0700 |
| commit | e8611a91f1a32606ff764601a0b82101ea4e8d6e (patch) | |
| tree | 8d6492a4d4ce41e6db8a75cda3ab6311e57c4eaf | |
| parent | 246097a6aac6cc9d4e9a99bf03b575a3321af609 (diff) | |
qcacld-3.0: Add Vendor command to set/get NUD debug stats
Add vendor commands to set/reset and get NUD debug stats
from firmware.
Change-Id: I773c04bb3f7c6d5ed28528cf2174b3d63de57d98
CRs-Fixed: 2011456
| -rw-r--r-- | core/hdd/inc/wlan_hdd_main.h | 45 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_cfg80211.c | 311 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_cfg80211.h | 72 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_main.c | 66 | ||||
| -rw-r--r-- | core/mac/inc/sir_api.h | 46 | ||||
| -rw-r--r-- | core/mac/src/include/sir_params.h | 4 | ||||
| -rw-r--r-- | core/sme/inc/sme_api.h | 10 | ||||
| -rw-r--r-- | core/sme/inc/sme_internal.h | 1 | ||||
| -rw-r--r-- | core/sme/src/common/sme_api.c | 108 | ||||
| -rw-r--r-- | core/wma/inc/wma_internal.h | 2 | ||||
| -rw-r--r-- | core/wma/inc/wma_types.h | 2 | ||||
| -rw-r--r-- | core/wma/src/wma_features.c | 62 | ||||
| -rw-r--r-- | core/wma/src/wma_main.c | 59 |
13 files changed, 786 insertions, 2 deletions
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 9e8ef1dcc1db..b4e1fcbf6c9a 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -270,6 +270,13 @@ #define SCAN_REJECT_THRESHOLD_TIME 300000 /* Time is in msec, equal to 5 mins */ +/* wait time for nud stats in milliseconds */ +#define WLAN_WAIT_TIME_NUD_STATS 800 +/* nud stats skb max length */ +#define WLAN_NUD_STATS_LEN 800 +/* ARP packet type for NUD debug stats */ +#define WLAN_NUD_STATS_ARP_PKT_TYPE 1 + /* * @eHDD_SCAN_REJECT_DEFAULT: default value * @eHDD_CONNECTION_IN_PROGRESS: connection is in progress @@ -410,6 +417,20 @@ typedef struct hdd_pmf_stats_s { } hdd_pmf_stats_t; #endif +struct hdd_arp_stats_s { + uint16_t tx_count; + uint16_t rx_count; + uint16_t tx_dropped; + uint16_t rx_dropped; + uint16_t rx_delivered; + uint16_t rx_refused; + uint16_t tx_host_fw_sent; + uint16_t rx_host_drop_reorder; + uint16_t tx_fw_cnt; + uint16_t rx_fw_cnt; + uint16_t tx_ack_cnt; +}; + typedef struct hdd_stats_s { tCsrSummaryStatsInfo summary_stat; tCsrGlobalClassAStatsInfo ClassA_stat; @@ -419,6 +440,7 @@ typedef struct hdd_stats_s { tCsrPerStaStatsInfo perStaStats; struct csr_per_chain_rssi_stats_info per_chain_rssi_stats; hdd_tx_rx_stats_t hddTxRxStats; + struct hdd_arp_stats_s hdd_arp_stats; #ifdef WLAN_FEATURE_11W hdd_pmf_stats_t hddPmfStats; #endif @@ -1192,6 +1214,8 @@ struct hdd_adapter_s { */ uint8_t cfg80211_disconnect_reason; struct lfr_firmware_status lfr_fw_status; + bool con_status; + bool dad; }; /* @@ -1379,6 +1403,14 @@ struct suspend_resume_stats { uint32_t suspend_fail[SUSPEND_FAIL_MAX_COUNT]; }; +/** + * struct hdd_nud_stats_context - hdd NUD stats context + * @response_event: NUD stats request wait event + */ +struct hdd_nud_stats_context { + struct completion response_event; +}; + /** Adapter structure definition */ struct hdd_context_s { /** Global CDS context */ @@ -1662,6 +1694,7 @@ struct hdd_context_s { uint32_t no_of_probe_req_ouis; struct vendor_oui *probe_req_voui; + struct hdd_nud_stats_context nud_stats_context; }; /*--------------------------------------------------------------------------- @@ -2119,4 +2152,16 @@ void hdd_set_roaming_in_progress(bool value); bool hdd_check_for_opened_interfaces(hdd_context_t *hdd_ctx); void wlan_hdd_start_sap(hdd_adapter_t *ap_adapter, bool reinit); void hdd_set_rx_mode_rps(hdd_context_t *hdd_ctx, void *padapter, bool enable); + +/** + * hdd_init_nud_stats_ctx() - initialize NUD stats context + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static inline void hdd_init_nud_stats_ctx(hdd_context_t *hdd_ctx) +{ + init_completion(&hdd_ctx->nud_stats_context.response_event); + return; +} #endif /* end #if !defined(WLAN_HDD_MAIN_H) */ diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 836d6dc46582..64f99d868aed 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -1083,6 +1083,10 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = .vendor_id = QCA_NL80211_VENDOR_ID, .subcmd = QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH }, + [QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET, + }, }; /** @@ -8564,6 +8568,297 @@ static int wlan_hdd_cfg80211_set_fast_roaming(struct wiphy *wiphy, return ret; } +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_setarp_stats_cmd() + */ +#define STATS_SET_INVALID \ + QCA_ATTR_NUD_STATS_SET_INVALID +#define STATS_SET_START \ + QCA_ATTR_NUD_STATS_SET_START +#define STATS_GW_IPV4 \ + QCA_ATTR_NUD_STATS_GW_IPV4 +#define STATS_SET_MAX \ + QCA_ATTR_NUD_STATS_SET_MAX + +const struct nla_policy +qca_wlan_vendor_set_nud_stats[STATS_SET_MAX + 1] = { + [STATS_SET_START] = {.type = NLA_FLAG }, + [STATS_GW_IPV4] = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to send arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct nlattr *tb[STATS_SET_MAX + 1]; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct set_arp_stats_params arp_stats_params; + int err = 0; + + ENTER(); + + err = wlan_hdd_validate_context(hdd_ctx); + if (0 != err) + return err; + + err = nla_parse(tb, STATS_SET_MAX, data, data_len, + qca_wlan_vendor_set_nud_stats); + if (err) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s STATS_SET_START ATTR", __func__); + return err; + } + + if (tb[STATS_SET_START]) { + if (!tb[STATS_GW_IPV4]) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s STATS_SET_START CMD", __func__); + return -EINVAL; + } + arp_stats_params.flag = true; + arp_stats_params.ip_addr = nla_get_u32(tb[STATS_GW_IPV4]); + } else { + arp_stats_params.flag = false; + } + if (arp_stats_params.flag) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s STATS_SET_START Cleared!!", __func__); + qdf_mem_zero(&adapter->hdd_stats.hdd_arp_stats, + sizeof(adapter->hdd_stats.hdd_arp_stats)); + } + + arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; + arp_stats_params.vdev_id = adapter->sessionId; + + if (QDF_STATUS_SUCCESS != + sme_set_nud_debug_stats(hdd_ctx->hHal, &arp_stats_params)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s STATS_SET_START CMD Failed!!", __func__); + return -EINVAL; + } + + EXIT(); + + return err; +} + +/** + * wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to send arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_nud_stats(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#undef STATS_SET_INVALID +#undef STATS_SET_START +#undef STATS_GW_IPV4 +#undef STATS_SET_MAX + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_setarp_stats_cmd() + */ +#define STATS_GET_INVALID \ + QCA_ATTR_NUD_STATS_SET_INVALID +#define COUNT_FROM_NETDEV \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV +#define COUNT_TO_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC +#define RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC +#define COUNT_TX_SUCCESS \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS +#define RSP_RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC +#define RSP_RX_COUNT_BY_UPPER_MAC \ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC +#define RSP_COUNT_TO_NETDEV \ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV +#define RSP_COUNT_OUT_OF_ORDER_DROP \ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP +#define AP_LINK_ACTIVE \ + QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE +#define AP_LINK_DAD \ + QCA_ATTR_NUD_STATS_AP_LINK_DAD +#define STATS_GET_MAX \ + QCA_ATTR_NUD_STATS_GET_MAX + +const struct nla_policy +qca_wlan_vendor_get_nud_stats[STATS_GET_MAX + 1] = { + [COUNT_FROM_NETDEV] = {.type = NLA_U16 }, + [COUNT_TO_LOWER_MAC] = {.type = NLA_U16 }, + [RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 }, + [COUNT_TX_SUCCESS] = {.type = NLA_U16 }, + [RSP_RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 }, + [RSP_RX_COUNT_BY_UPPER_MAC] = {.type = NLA_U16 }, + [RSP_COUNT_TO_NETDEV] = {.type = NLA_U16 }, + [RSP_COUNT_OUT_OF_ORDER_DROP] = {.type = NLA_U16 }, + [AP_LINK_ACTIVE] = {.type = NLA_FLAG }, + [AP_LINK_DAD] = {.type = NLA_FLAG }, +}; + +/** + * __wlan_hdd_cfg80211_get_nud_stats() - get arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to get arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int err = 0; + unsigned long rc; + struct hdd_nud_stats_context *context; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct get_arp_stats_params arp_stats_params; + struct sk_buff *skb; + + ENTER(); + + err = wlan_hdd_validate_context(hdd_ctx); + if (0 != err) + return err; + + arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; + arp_stats_params.vdev_id = adapter->sessionId; + + spin_lock(&hdd_context_lock); + context = &hdd_ctx->nud_stats_context; + INIT_COMPLETION(context->response_event); + spin_unlock(&hdd_context_lock); + + if (QDF_STATUS_SUCCESS != + sme_get_nud_debug_stats(hdd_ctx->hHal, &arp_stats_params)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s STATS_SET_START CMD Failed!!", __func__); + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies( + WLAN_WAIT_TIME_NUD_STATS)); + if (!rc) { + hdd_err("Target response timed out request "); + return -ETIMEDOUT; + } + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + WLAN_NUD_STATS_LEN); + if (!skb) { + hdd_err("%s: cfg80211_vendor_cmd_alloc_reply_skb failed", + __func__); + return -ENOMEM; + } + + if (nla_put_u16(skb, COUNT_FROM_NETDEV, + adapter->hdd_stats.hdd_arp_stats.tx_count) || + nla_put_u16(skb, COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hdd_arp_stats.tx_host_fw_sent) || + nla_put_u16(skb, RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_arp_stats.tx_fw_cnt) || + nla_put_u16(skb, COUNT_TX_SUCCESS, + adapter->hdd_stats.hdd_arp_stats.tx_ack_cnt) || + nla_put_u16(skb, RSP_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_arp_stats.rx_fw_cnt) || + nla_put_u16(skb, RSP_RX_COUNT_BY_UPPER_MAC, + adapter->hdd_stats.hdd_arp_stats.rx_count) || + nla_put_u16(skb, RSP_COUNT_TO_NETDEV, + adapter->hdd_stats.hdd_arp_stats.rx_delivered) || + nla_put_u16(skb, RSP_COUNT_OUT_OF_ORDER_DROP, + adapter->hdd_stats.hdd_arp_stats. + rx_host_drop_reorder)) { + hdd_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + if (adapter->con_status) + nla_put_flag(skb, AP_LINK_ACTIVE); + if (adapter->dad) + nla_put_flag(skb, AP_LINK_DAD); + + cfg80211_vendor_cmd_reply(skb); + return err; +} + +/** + * wlan_hdd_cfg80211_get_nud_stats() - get arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to get arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_nud_stats(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#undef QCA_ATTR_NUD_STATS_SET_INVALID +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS +#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV +#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP +#undef QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE +#undef QCA_ATTR_NUD_STATS_GET_MAX + const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { { .info.vendor_id = QCA_NL80211_VENDOR_ID, @@ -9185,6 +9480,22 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_set_sar_power_limits }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_nud_stats + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_nud_stats + }, }; /** diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index c667d9b41db7..172fe7166f9d 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -304,6 +304,10 @@ typedef enum { * (SAR) power limits. A critical regulation for FCC compliance, OEMs * require methods to set SAR limits on TX power of WLAN/WWAN. * enum qca_vendor_attr_sar_limits attributes are used with this command. + * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET + * Start / Stop the NUD stats collections + * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET + * Get the NUD stats, represented by the enum qca_attr_nud_stats_get */ enum qca_nl80211_vendor_subcmds { @@ -460,6 +464,8 @@ enum qca_nl80211_vendor_subcmds { /* Set Specific Absorption Rate(SAR) Power Limits */ QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS = 146, + QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET = 149, + QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET = 150, }; /** @@ -665,6 +671,7 @@ enum qca_wlan_vendor_attr_get_station_info { * P2P listen offload index * @QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH_INDEX: SAP * conditional channel switch index + * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX: NUD DEBUG Stats index */ enum qca_nl80211_vendor_subcmds_index { @@ -739,6 +746,71 @@ enum qca_nl80211_vendor_subcmds_index { #endif /* WLAN_FEATURE_NAN_DATAPATH */ QCA_NL80211_VENDOR_SUBCMD_P2P_LO_EVENT_INDEX, QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH_INDEX, + QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX, +}; + +/** + * enum qca_attr_nud_stats_set - attribute to vendor subcmd + * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET. This carry the requisite + * information to start / stop the NUD stats collection. + * @QCA_ATTR_NUD_STATS_SET_START: set nud debug stats + * Flag to Start / Stop the NUD stats collection + * Start - If included , Stop - If not included + * @QCA_ATTR_NUD_STATS_GW_IPV4: set gatway ipv4 address + * IPv4 address of Default Gateway (in network byte order) + */ +enum qca_attr_nud_stats_set { + QCA_ATTR_NUD_STATS_SET_INVALID = 0, + QCA_ATTR_NUD_STATS_SET_START = 1, + QCA_ATTR_NUD_STATS_GW_IPV4 = 2, + /* keep last */ + QCA_ATTR_NUD_STATS_SET_LAST, + QCA_ATTR_NUD_STATS_SET_MAX = + QCA_ATTR_NUD_STATS_SET_LAST - 1, +}; + +/** + * enum qca_attr_nud_stats_get - attribute to vendor subcmd + * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET. This carry the requisite + * NUD stats collected when queried. + * @QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV: ARP Request Count from net + * dev + * @QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC: ARP Request Count sent + * to lower MAC from upper MAC + * @QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC: ARP Request Count + * received by lower MAC from upper MAC + * @QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS: ARP Request Count successfully + * transmitted by the device + * @QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC: ARP Response Count + * received by lower MAC + * @QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC: ARP Response Count + * received by upper MAC + * @QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV: ARP Response Count delivered + * to netdev + * @QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP: ARP Response Count + * delivered to netdev + * @QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE: Flag indicating if the Stations + * Link to AP is active. + * Active Link - If exists, Inactive link - If not included + * @QCA_ATTR_NUD_STATS_AP_LINK_DAD: Flag indicating if the Stations + * Duplicate Address detected. + */ +enum qca_attr_nud_stats_get { + QCA_ATTR_NUD_STATS_GET_INVALID = 0, + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV = 1, + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC = 2, + QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC = 3, + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS = 4, + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC = 5, + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC = 6, + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV = 7, + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP = 8, + QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE = 9, + QCA_ATTR_NUD_STATS_AP_LINK_DAD = 10, + /* keep last */ + QCA_ATTR_NUD_STATS_GET_LAST, + QCA_ATTR_NUD_STATS_GET_MAX = + QCA_ATTR_NUD_STATS_GET_LAST - 1, }; /** diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 5f32fcbe3125..dadc7a7bd7b3 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -6766,6 +6766,7 @@ static int hdd_context_init(hdd_context_t *hdd_ctx) hdd_ctx->max_intf_count = CSR_ROAM_SESSION_MAX; hdd_init_ll_stats_ctx(); + hdd_init_nud_stats_ctx(hdd_ctx); init_completion(&hdd_ctx->mc_sus_event_var); init_completion(&hdd_ctx->ready_to_suspend); @@ -8801,6 +8802,66 @@ void hdd_wlan_update_target_info(hdd_context_t *hdd_ctx, void *context) } /** + * hdd_get_nud_stats_cb() - callback api to update the stats + * received from the firmware + * @data: pointer to adapter. + * @rsp: pointer to data received from FW. + * + * This is called when wlan driver received response event for + * get arp stats to firmware. + * + * Return: None + */ +static void hdd_get_nud_stats_cb(void *data, struct rsp_stats *rsp) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)data; + struct hdd_nud_stats_context *context; + int status; + hdd_adapter_t *adapter = NULL; + + ENTER(); + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, rsp->vdev_id); + if (NULL == adapter) + return; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + if (!rsp) { + hdd_err("data is null"); + return; + } + + hdd_notice("rsp->arp_req_enqueue :%x", rsp->arp_req_enqueue); + hdd_notice("rsp->arp_req_tx_success :%x", rsp->arp_req_tx_success); + hdd_notice("rsp->arp_req_tx_failure :%x", rsp->arp_req_tx_failure); + hdd_notice("rsp->arp_rsp_recvd :%x", rsp->arp_rsp_recvd); + hdd_notice("rsp->out_of_order_arp_rsp_drop_cnt :%x", + rsp->out_of_order_arp_rsp_drop_cnt); + hdd_notice("rsp->dad_detected :%x", rsp->dad_detected); + hdd_notice("rsp->connect_status :%x", rsp->connect_status); + hdd_notice("rsp->ba_session_establishment_status :%x", + rsp->ba_session_establishment_status); + + adapter->hdd_stats.hdd_arp_stats.tx_fw_cnt = rsp->arp_req_enqueue; + adapter->hdd_stats.hdd_arp_stats.rx_fw_cnt = rsp->arp_rsp_recvd; + adapter->hdd_stats.hdd_arp_stats.tx_ack_cnt = rsp->arp_req_tx_success; + adapter->dad |= rsp->dad_detected; + adapter->con_status = rsp->connect_status; + + spin_lock(&hdd_context_lock); + context = &hdd_ctx->nud_stats_context; + complete(&context->response_event); + spin_unlock(&hdd_context_lock); + + EXIT(); + + return; +} + +/** * hdd_register_cb - Register HDD callbacks. * @hdd_ctx: HDD context * @@ -8847,7 +8908,10 @@ int hdd_register_cb(hdd_context_t *hdd_ctx) } sme_set_rssi_threshold_breached_cb(hdd_ctx->hHal, - hdd_rssi_threshold_breached); + hdd_rssi_threshold_breached); + + sme_set_nud_debug_stats_cb(hdd_ctx->hHal, + hdd_get_nud_stats_cb); status = sme_bpf_offload_register_callback(hdd_ctx->hHal, hdd_get_bpf_offload_cb); diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 644b8a8476c2..e3a32c780cd5 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -7027,4 +7027,50 @@ struct sme_rcpi_req { struct qdf_mac_addr mac_addr; }; +/** + * struct rsp_stats - arp packet stats + * @arp_req_enqueue: fw tx count + * @arp_req_tx_success: tx ack count + * @arp_req_tx_failure: tx ack fail count + * @arp_rsp_recvd: rx fw count + * @out_of_order_arp_rsp_drop_cnt: out of order count + * @dad_detected: dad detected + * @connect_status: connection status + * @ba_session_establishment_status: BA session status + */ +struct rsp_stats { + uint32_t vdev_id; + uint32_t arp_req_enqueue; + uint32_t arp_req_tx_success; + uint32_t arp_req_tx_failure; + uint32_t arp_rsp_recvd; + uint32_t out_of_order_arp_rsp_drop_cnt; + uint32_t dad_detected; + uint32_t connect_status; + uint32_t ba_session_establishment_status; +}; + +/** + * struct set_arp_stats_params - set/reset arp stats + * @vdev_id: session id + * @flag: enable/disable stats + * @pkt_type: type of packet(1 - arp) + * @ip_addr: subnet ipv4 address in case of encrypted packets + */ +struct set_arp_stats_params { + uint32_t vdev_id; + uint8_t flag; + uint8_t pkt_type; + uint32_t ip_addr; +}; + +/** + * struct get_arp_stats_params - get arp stats from firmware + * @pkt_type: packet type(1 - ARP) + * @vdev_id: session id + */ +struct get_arp_stats_params { + uint8_t pkt_type; + uint32_t vdev_id; +}; #endif /* __SIR_API_H */ diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h index 87455ced90a1..05805f6dabcc 100644 --- a/core/mac/src/include/sir_params.h +++ b/core/mac/src/include/sir_params.h @@ -99,7 +99,6 @@ typedef enum { ADVANCE_TDLS = 29, TDLS_OFF_CHANNEL = 30, #endif - /* MAX_FEATURE_SUPPORTED = 128 */ } placeHolderInCapBitmap; @@ -652,6 +651,9 @@ typedef struct sSirMbMsgP2p { #define SIR_HAL_ENABLE_BCAST_FILTER (SIR_HAL_ITC_MSG_TYPES_BEGIN + 373) #define SIR_HAL_DISABLE_BCAST_FILTER (SIR_HAL_ITC_MSG_TYPES_BEGIN + 374) +/* ARP Debug stats */ +#define SIR_HAL_SET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 375) +#define SIR_HAL_GET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 376) #define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index d272398257ec..884c84164691 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -1452,6 +1452,16 @@ void sme_set_cc_src(tHalHandle hal_handle, enum country_src); #ifdef WLAN_FEATURE_WOW_PULSE QDF_STATUS sme_set_wow_pulse(struct wow_pulse_mode *wow_pulse_set_info); #endif +/* ARP DEBUG STATS */ +QDF_STATUS sme_set_nud_debug_stats(tHalHandle hal, + struct set_arp_stats_params + *set_stats_param); +QDF_STATUS sme_get_nud_debug_stats(tHalHandle hal, + struct get_arp_stats_params + *get_stats_param); +QDF_STATUS sme_set_nud_debug_stats_cb(tHalHandle hal, + void (*cb)(void *, struct rsp_stats *)); + #ifdef WLAN_FEATURE_UDP_RESPONSE_OFFLOAD QDF_STATUS sme_set_udp_resp_offload(struct udp_resp_offload *pudp_resp_cmd); diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index 7052d49bb90b..50f2f8b13633 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -259,6 +259,7 @@ typedef struct tagSmeStruct { struct sir_lost_link_info *lost_link_info); void (*rso_cmd_status_cb)(void *hdd_context, struct rso_cmd_status *rso_status); + void (*get_arp_stats_cb)(void *, struct rsp_stats *); } tSmeStruct, *tpSmeStruct; #endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 88c337211272..031fda30ab18 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -15364,6 +15364,41 @@ QDF_STATUS sme_set_rssi_threshold_breached_cb(tHalHandle h_hal, } /** + * sme_set_nud_debug_stats_cb() - set nud debug stats callback + * @hal: global hal handle + * @cb: callback function pointer + * + * This function stores nud debug stats callback function. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_nud_debug_stats_cb(tHalHandle hal, + void (*cb)(void *, struct rsp_stats *)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac; + + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hal is not valid")); + return QDF_STATUS_E_INVAL; + } + mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + return status; + } + + mac->sme.get_arp_stats_cb = cb; + sme_release_global_lock(&mac->sme); + return status; +} + +/** * sme_set_rssi_threshold_breached_cb() - Reset rssi threshold breached callback * @hal: global hal handle * @@ -17616,3 +17651,76 @@ free_scan_flter: return status; } +/* ARP DEBUG STATS */ + +/** + * sme_set_nud_debug_stats() - sme api to set nud debug stats + * @hal: handle to hal + * @set_stats_param: pointer to set stats param + * + * Return: Return QDF_STATUS. + */ +QDF_STATUS sme_set_nud_debug_stats(tHalHandle hal, + struct set_arp_stats_params + *set_stats_param) +{ + struct set_arp_stats_params *arp_set_param; + cds_msg_t msg; + + arp_set_param = qdf_mem_malloc(sizeof(*arp_set_param)); + if (arp_set_param == NULL) { + hdd_err("Memory allocation failure"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(arp_set_param, set_stats_param, sizeof(*arp_set_param)); + + msg.type = WMA_SET_ARP_STATS_REQ; + msg.reserved = 0; + msg.bodyptr = arp_set_param; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + hdd_err("Not able to post message to WDA"); + qdf_mem_free(arp_set_param); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_get_nud_debug_stats() - sme api to get nud debug stats + * @hal: handle to hal + * @get_stats_param: pointer to set stats param + * + * Return: Return QDF_STATUS. + */ +QDF_STATUS sme_get_nud_debug_stats(tHalHandle hal, + struct get_arp_stats_params + *get_stats_param) +{ + struct get_arp_stats_params *arp_get_param; + cds_msg_t msg; + + arp_get_param = qdf_mem_malloc(sizeof(*arp_get_param)); + if (arp_get_param == NULL) { + hdd_err("Memory allocation failure"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(arp_get_param, get_stats_param, sizeof(*arp_get_param)); + + msg.type = WMA_GET_ARP_STATS_REQ; + msg.reserved = 0; + msg.bodyptr = arp_get_param; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + hdd_err("Not able to post message to WDA"); + qdf_mem_free(arp_get_param); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index ee3454b40eb7..45f1c72f0e90 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -1348,4 +1348,6 @@ wma_send_vdev_start_to_fw(t_wma_handle *wma, struct vdev_start_params *params); */ QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id); +int wma_get_arp_stats_handler(void *handle, uint8_t *data, + uint32_t data_len); #endif diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h index 0cde7ff2cab4..2ea83e7fe949 100644 --- a/core/wma/inc/wma_types.h +++ b/core/wma/inc/wma_types.h @@ -494,6 +494,8 @@ #define WDA_SET_UDP_RESP_OFFLOAD SIR_HAL_SET_UDP_RESP_OFFLOAD #define WMA_SET_PER_ROAM_CONFIG_CMD SIR_HAL_SET_PER_ROAM_CONFIG_CMD +#define WMA_SET_ARP_STATS_REQ SIR_HAL_SET_ARP_STATS_REQ +#define WMA_GET_ARP_STATS_REQ SIR_HAL_GET_ARP_STATS_REQ /* Bit 6 will be used to control BD rate for Management frames */ #define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index f1f3a3ac4ccd..4a89445b2109 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -8626,6 +8626,68 @@ QDF_STATUS wma_encrypt_decrypt_msg(WMA_HANDLE handle, } /** + * wma_get_arp_stats_handler() - handle arp stats data + * indicated by FW + * @handle: wma context + * @data: event buffer + * @data len: length of event buffer + * + * Return: 0 on success + */ +int wma_get_arp_stats_handler(void *handle, uint8_t *data, + uint32_t data_len) +{ + WMI_VDEV_GET_ARP_STAT_EVENTID_param_tlvs *param_buf; + wmi_vdev_get_arp_stats_event_fixed_param *data_event; + struct rsp_stats rsp; + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + ENTER(); + + if (!mac) { + WMA_LOGE("%s: Invalid mac context", __func__); + return -EINVAL; + } + + if (!mac->sme.get_arp_stats_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + if (data == NULL) { + WMA_LOGE("%s: invalid pointer", __func__); + return -EINVAL; + } + param_buf = (WMI_VDEV_GET_ARP_STAT_EVENTID_param_tlvs *)data; + if (!param_buf) { + WMA_LOGE("%s: Invalid get arp stats event", __func__); + return -EINVAL; + } + data_event = param_buf->fixed_param; + if (!data_event) { + WMA_LOGE("%s: Invalid get arp stats data event", __func__); + return -EINVAL; + } + rsp.arp_req_enqueue = data_event->arp_req_enqueue; + rsp.vdev_id = data_event->vdev_id; + rsp.arp_req_tx_success = data_event->arp_req_tx_success; + rsp.arp_req_tx_failure = data_event->arp_req_tx_failure; + rsp.arp_rsp_recvd = data_event->arp_rsp_recvd; + rsp.out_of_order_arp_rsp_drop_cnt = + data_event->out_of_order_arp_rsp_drop_cnt; + rsp.dad_detected = data_event->dad_detected; + rsp.connect_status = data_event->connect_status; + rsp.ba_session_establishment_status = + data_event->ba_session_establishment_status; + + mac->sme.get_arp_stats_cb(mac->hHdd, &rsp); + + EXIT(); + + return 0; +} + +/** * wma_encrypt_decrypt_msg_handler() - handle encrypt/decrypt data * indicated by FW * @handle: wma context diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index cf49754a4eeb..7475cd99825e 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -2329,6 +2329,13 @@ QDF_STATUS wma_open(void *cds_context, wma_stats_event_handler, WMA_RX_SERIALIZER_CTX); + /* register for stats response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_GET_ARP_STAT_EVENTID, + wma_get_arp_stats_handler, + WMA_RX_SERIALIZER_CTX); + + #ifdef WLAN_POWER_DEBUGFS /* register for Chip Power stats event */ wmi_unified_register_event_handler(wma_handle->wmi_handle, @@ -6325,6 +6332,48 @@ void wma_mc_discard_msg(cds_msg_t *msg) msg->type = 0; } +static void wma_set_arp_req_stats(WMA_HANDLE handle, + struct set_arp_stats_params *req_buf) +{ + int status; + struct set_arp_stats *arp_stats; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot send per roam config", + __func__); + return; + } + + arp_stats = (struct set_arp_stats *)req_buf; + status = wmi_unified_set_arp_stats_req(wma_handle->wmi_handle, + arp_stats); + if (status != EOK) + WMA_LOGE("%s: failed to set arp stats to FW", + __func__); +} + +static void wma_get_arp_req_stats(WMA_HANDLE handle, + struct get_arp_stats_params *req_buf) +{ + int status; + struct get_arp_stats *arp_stats; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot send per roam config", + __func__); + return; + } + + arp_stats = (struct get_arp_stats *)req_buf; + status = wmi_unified_get_arp_stats_req(wma_handle->wmi_handle, + arp_stats); + if (status != EOK) + WMA_LOGE("%s: failed to send get arp stats to FW", + __func__); +} + /** * wma_mc_process_msg() - process wma messages and call appropriate function. * @cds_context: cds context @@ -7179,6 +7228,16 @@ QDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg) wma_configure_non_arp_broadcast_filter(wma_handle, (struct broadcast_filter_request *) msg->bodyptr); break; + case WMA_SET_ARP_STATS_REQ: + wma_set_arp_req_stats(wma_handle, + (struct set_arp_stats_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_GET_ARP_STATS_REQ: + wma_get_arp_req_stats(wma_handle, + (struct get_arp_stats_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; default: WMA_LOGE("Unhandled WMA message of type %d", msg->type); if (msg->bodyptr) |
