From 31797fa6a8830dd04f51c8c9d9665aea2f28b27e Mon Sep 17 00:00:00 2001 From: "Poddar, Siddarth" Date: Mon, 22 Jan 2018 17:24:15 +0530 Subject: [PATCH] qcacld-3.0: Extend debug stats Extend to collect connectivity check stats other than ARP such as DNS, TCP SYN/SYN-ACK/ACK, and Ipv4. Add extra attributes in existing vendor command(set/reset and get NUD debug stats) for above connectvitiy stats. CRs-Fixed: 2161889 Change-Id: I037c4ec29b181a0b3117ae2abbc7a2229b373ac2 --- core/cds/inc/cds_api.h | 8 +- core/cds/src/cds_api.c | 18 +- core/dp/txrx/ol_tx_send.c | 14 +- core/hdd/inc/wlan_hdd_main.h | 113 +++++- core/hdd/inc/wlan_hdd_tx_rx.h | 12 + core/hdd/src/wlan_hdd_assoc.c | 2 + core/hdd/src/wlan_hdd_cfg80211.c | 663 +++++++++++++++++++++++++++++-- core/hdd/src/wlan_hdd_cfg80211.h | 19 + core/hdd/src/wlan_hdd_main.c | 9 + core/hdd/src/wlan_hdd_ocb.c | 1 + core/hdd/src/wlan_hdd_tx_rx.c | 291 +++++++++++++- 11 files changed, 1091 insertions(+), 59 deletions(-) diff --git a/core/cds/inc/cds_api.h b/core/cds/inc/cds_api.h index ee79bbf272aa2..1920c8203cf87 100644 --- a/core/cds/inc/cds_api.h +++ b/core/cds/inc/cds_api.h @@ -590,7 +590,13 @@ bool cds_is_group_addr(uint8_t *mac_addr) return false; } -uint32_t cds_get_arp_stats_gw_ip(void); +/** + * cds_get_arp_stats_gw_ip() - get arp stats track IP + * @context: osif dev + * + * Return: ARP stats IP to track. + */ +uint32_t cds_get_arp_stats_gw_ip(void *context); void cds_incr_arp_stats_tx_tgt_delivered(void); void cds_incr_arp_stats_tx_tgt_acked(void); diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c index e1e51829d1b50..855b1e4be76a1 100644 --- a/core/cds/src/cds_api.c +++ b/core/cds/src/cds_api.c @@ -2776,22 +2776,18 @@ cds_print_htc_credit_history(uint32_t count, qdf_abstract_print *print, } #endif -/** - * cds_get_arp_stats_gw_ip() - get arp stats track IP - * - * Return: ARP stats IP to track - */ -uint32_t cds_get_arp_stats_gw_ip(void) +uint32_t cds_get_arp_stats_gw_ip(void *context) { - struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter = (struct hdd_adapter *)context; - hdd_ctx = (struct hdd_context *) (gp_cds_context->pHDDContext); - if (!hdd_ctx) { - cds_err("Hdd Context is Null"); + if (unlikely(adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "Magic cookie(%x) for adapter sanity verification is invalid", + adapter->magic); return 0; } - return hdd_ctx->track_arp_ip; + return adapter->track_arp_ip; } /** diff --git a/core/dp/txrx/ol_tx_send.c b/core/dp/txrx/ol_tx_send.c index eaba416998275..a707a52762bad 100644 --- a/core/dp/txrx/ol_tx_send.c +++ b/core/dp/txrx/ol_tx_send.c @@ -631,15 +631,21 @@ static inline void ol_tx_timestamp(ol_txrx_pdev_handle pdev, /** * ol_tx_update_arp_stats() - update ARP packet TX stats + * @tx_desc: tx desc * @netbuf: buffer + * @status: htt status * * * Return: none */ -static void ol_tx_update_arp_stats(qdf_nbuf_t netbuf, - enum htt_tx_status status) +static void ol_tx_update_arp_stats(struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t netbuf, + enum htt_tx_status status) { - uint32_t tgt_ip = cds_get_arp_stats_gw_ip(); + uint32_t tgt_ip; + + qdf_assert(tx_desc); + tgt_ip = cds_get_arp_stats_gw_ip(tx_desc->vdev->osif_dev); if (tgt_ip == qdf_nbuf_get_arp_tgt_ip(netbuf)) { if (status != htt_tx_status_download_fail) @@ -703,7 +709,7 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, if (QDF_NBUF_CB_GET_PACKET_TYPE(netbuf) == QDF_NBUF_CB_PACKET_TYPE_ARP) { if (qdf_nbuf_data_is_arp_req(netbuf)) - ol_tx_update_arp_stats(netbuf, status); + ol_tx_update_arp_stats(tx_desc, netbuf, status); } if (tx_desc->pkt_type != OL_TX_FRM_TSO) { diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 6319c99f40adf..57fc217a2724e 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -307,6 +307,9 @@ #endif #define MAX_USER_COMMAND_SIZE 4096 +#define DNS_DOMAIN_NAME_MAX_LEN 255 +#define ICMPv6_ADDR_LEN 16 + #define HDD_MIN_TX_POWER (-100) /* minimum tx power */ #define HDD_MAX_TX_POWER (+100) /* maximum tx power */ @@ -464,6 +467,19 @@ struct hdd_pmf_stats { }; #endif +/** + * struct hdd_arp_stats_s - arp debug stats count + * @tx_arp_req_count: no. of arp req received from network stack + * @rx_arp_rsp_count: no. of arp res received from FW + * @tx_dropped: no. of arp req dropped at hdd layer + * @rx_dropped: no. of arp res dropped + * @rx_delivered: no. of arp res delivered to network stack + * @rx_refused: no of arp rsp refused (not delivered) to network stack + * @tx_host_fw_sent: no of arp req sent by FW OTA + * @rx_host_drop_reorder: no of arp res dropped by host + * @rx_fw_cnt: no of arp res received by FW + * @tx_ack_cnt: no of arp req acked by FW + */ struct hdd_arp_stats_s { uint16_t tx_arp_req_count; uint16_t rx_arp_rsp_count; @@ -478,14 +494,87 @@ struct hdd_arp_stats_s { }; /** - * struct hdd_stats - per-adapter statistics - * @summary_stat: Summary stats reported by firmware - * @class_a_stat: "Class A" stats reported by firmware - * @class_d_stat: "Class D" stats reported by firmware - * @per_chain_rssi_stats: Per-chain RSSI stats - * @tx_rx_stats: Tx & Rx stats - * @hdd_pmf_stats: Protected Management Frame stats + * struct hdd_dns_stats_s - dns debug stats count + * @tx_dns_req_count: no. of dns query received from network stack + * @rx_dns_rsp_count: no. of dns res received from FW + * @tx_dropped: no. of dns query dropped at hdd layer + * @rx_delivered: no. of dns res delivered to network stack + * @rx_refused: no of dns res refused (not delivered) to network stack + * @tx_host_fw_sent: no of dns query sent by FW OTA + * @rx_host_drop: no of dns res dropped by host + * @tx_ack_cnt: no of dns req acked by FW */ +struct hdd_dns_stats_s { + uint16_t tx_dns_req_count; + uint16_t rx_dns_rsp_count; + uint16_t tx_dropped; + uint16_t rx_delivered; + uint16_t rx_refused; + uint16_t tx_host_fw_sent; + uint16_t rx_host_drop; + uint16_t tx_ack_cnt; +}; + +/** + * struct hdd_tcp_stats_s - tcp debug stats count + * @tx_tcp_syn_count: no. of tcp syn received from network stack + * @@tx_tcp_ack_count: no. of tcp ack received from network stack + * @rx_tcp_syn_ack_count: no. of tcp syn ack received from FW + * @tx_tcp_syn_dropped: no. of tcp syn dropped at hdd layer + * @tx_tcp_ack_dropped: no. of tcp ack dropped at hdd layer + * @rx_delivered: no. of tcp syn ack delivered to network stack + * @rx_refused: no of tcp syn ack refused (not delivered) to network stack + * @tx_tcp_syn_host_fw_sent: no of tcp syn sent by FW OTA + * @@tx_tcp_ack_host_fw_sent: no of tcp ack sent by FW OTA + * @rx_host_drop: no of tcp syn ack dropped by host + * @tx_tcp_syn_ack_cnt: no of tcp syn acked by FW + * @tx_tcp_syn_ack_cnt: no of tcp ack acked by FW + * @is_tcp_syn_ack_rcv: flag to check tcp syn ack received or not + * @is_tcp_ack_sent: flag to check tcp ack sent or not + */ +struct hdd_tcp_stats_s { + uint16_t tx_tcp_syn_count; + uint16_t tx_tcp_ack_count; + uint16_t rx_tcp_syn_ack_count; + uint16_t tx_tcp_syn_dropped; + uint16_t tx_tcp_ack_dropped; + uint16_t rx_delivered; + uint16_t rx_refused; + uint16_t tx_tcp_syn_host_fw_sent; + uint16_t tx_tcp_ack_host_fw_sent; + uint16_t rx_host_drop; + uint16_t rx_fw_cnt; + uint16_t tx_tcp_syn_ack_cnt; + uint16_t tx_tcp_ack_ack_cnt; + bool is_tcp_syn_ack_rcv; + bool is_tcp_ack_sent; + +}; + +/** + * struct hdd_icmpv4_stats_s - icmpv4 debug stats count + * @tx_icmpv4_req_count: no. of icmpv4 req received from network stack + * @rx_icmpv4_rsp_count: no. of icmpv4 res received from FW + * @tx_dropped: no. of icmpv4 req dropped at hdd layer + * @rx_delivered: no. of icmpv4 res delivered to network stack + * @rx_refused: no of icmpv4 res refused (not delivered) to network stack + * @tx_host_fw_sent: no of icmpv4 req sent by FW OTA + * @rx_host_drop: no of icmpv4 res dropped by host + * @rx_fw_cnt: no of icmpv4 res received by FW + * @tx_ack_cnt: no of icmpv4 req acked by FW + */ +struct hdd_icmpv4_stats_s { + uint16_t tx_icmpv4_req_count; + uint16_t rx_icmpv4_rsp_count; + uint16_t tx_dropped; + uint16_t rx_delivered; + uint16_t rx_refused; + uint16_t tx_host_fw_sent; + uint16_t rx_host_drop; + uint16_t rx_fw_cnt; + uint16_t tx_ack_cnt; +}; + struct hdd_stats { tCsrSummaryStatsInfo summary_stat; tCsrGlobalClassAStatsInfo class_a_stat; @@ -493,6 +582,9 @@ struct hdd_stats { struct csr_per_chain_rssi_stats_info per_chain_rssi_stats; struct hdd_tx_rx_stats tx_rx_stats; struct hdd_arp_stats_s hdd_arp_stats; + struct hdd_dns_stats_s hdd_dns_stats; + struct hdd_tcp_stats_s hdd_tcp_stats; + struct hdd_icmpv4_stats_s hdd_icmpv4_stats; #ifdef WLAN_FEATURE_11W struct hdd_pmf_stats hdd_pmf_stats; #endif @@ -1211,6 +1303,13 @@ struct hdd_adapter { bool con_status; bool dad; uint8_t active_ac; + uint32_t pkt_type_bitmap; + uint32_t track_arp_ip; + uint8_t dns_payload[256]; + uint32_t track_dns_domain_len; + uint32_t track_src_port; + uint32_t track_dest_port; + uint32_t track_dest_ipv4; uint32_t mon_chan; uint32_t mon_bandwidth; diff --git a/core/hdd/inc/wlan_hdd_tx_rx.h b/core/hdd/inc/wlan_hdd_tx_rx.h index 56bcbc18f6a15..c8c4d51c319c2 100644 --- a/core/hdd/inc/wlan_hdd_tx_rx.h +++ b/core/hdd/inc/wlan_hdd_tx_rx.h @@ -65,6 +65,18 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf); QDF_STATUS hdd_get_peer_sta_id(struct hdd_station_ctx *sta_ctx, struct qdf_mac_addr *peer_mac_addr, uint8_t *sta_id); +/** + * hdd_tx_rx_collect_connectivity_stats_info() - collect connectivity stats + * @skb: pointer to skb data + * @adapter: pointer to vdev apdapter + * @action: action done on pkt. + * @pkt_type: data pkt type + * + * Return: None + */ +void hdd_tx_rx_collect_connectivity_stats_info(struct sk_buff *skb, + void *adapter, enum connectivity_stats_pkt_status action, + uint8_t *pkt_type); /** * hdd_tx_queue_cb() - Disable/Enable the Transmit Queues diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 28fe753e3ff5c..7d6b208c63e21 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -1985,6 +1985,7 @@ QDF_STATUS hdd_roam_register_sta(struct hdd_adapter *adapter, /* Register the vdev transmit and receive functions */ qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); txrx_ops.rx.rx = hdd_rx_packet_cbk; + txrx_ops.rx.stats_rx = hdd_tx_rx_collect_connectivity_stats_info; adapter->txrx_vdev = (void *)cdp_get_vdev_from_vdev_id(soc, (struct cdp_pdev *)pdev, @@ -3826,6 +3827,7 @@ QDF_STATUS hdd_roam_register_tdlssta(struct hdd_adapter *adapter, (struct cdp_pdev *)pdev, adapter->session_id), adapter, &txrx_ops); adapter->tx_fn = txrx_ops.tx.tx; + txrx_ops.rx.stats_rx = hdd_tx_rx_collect_connectivity_stats_info; /* Register the Station with TL... */ qdf_status = cdp_peer_register(soc, diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 3a6eb00e2fe70..5ccccd36e02b7 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -12409,9 +12409,266 @@ 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_DATA_PKT_INFO \ + QCA_ATTR_NUD_STATS_SET_DATA_PKT_INFO +#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 }, + [STATS_SET_DATA_PKT_INFO] = {.type = NLA_U32 }, +}; + +/* define short names for the global vendor params */ +#define CONNECTIVITY_STATS_SET_INVALID \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_SET_INVALID +#define STATS_PKT_INFO_TYPE \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_STATS_PKT_INFO_TYPE +#define STATS_DNS_DOMAIN_NAME \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DNS_DOMAIN_NAME +#define STATS_SRC_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_SRC_PORT +#define STATS_DEST_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DEST_PORT +#define STATS_DEST_IPV4 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DEST_IPV4 +#define STATS_DEST_IPV6 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DEST_IPV6 +#define CONNECTIVITY_STATS_SET_MAX \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_SET_MAX + +const struct nla_policy +qca_wlan_vendor_set_connectivity_check_stats[CONNECTIVITY_STATS_SET_MAX + 1] = { + [STATS_PKT_INFO_TYPE] = {.type = NLA_U32 }, + [STATS_DNS_DOMAIN_NAME] = {.type = NLA_BINARY, + .len = DNS_DOMAIN_NAME_MAX_LEN }, + [STATS_SRC_PORT] = {.type = NLA_U32 }, + [STATS_DEST_PORT] = {.type = NLA_U32 }, + [STATS_DEST_IPV4] = {.type = NLA_U32 }, + [STATS_DEST_IPV6] = {.type = NLA_BINARY, + .len = ICMPv6_ADDR_LEN }, +}; + +/** + * hdd_dns_unmake_name_query() - Convert an uncompressed DNS name to a + * NUL-terminated string + * @name: DNS name + * + * Return: Produce a printable version of a DNS name. + */ +static inline uint8_t *hdd_dns_unmake_name_query(uint8_t *name) +{ + uint8_t *p; + unsigned int len; + + p = name; + while ((len = *p)) { + *(p++) = '.'; + p += len; + } + + return name + 1; +} + +/** + * hdd_dns_make_name_query() - Convert a standard NUL-terminated string + * to DNS name + * @string: Name as a NUL-terminated string + * @buf: Buffer in which to place DNS name + * + * DNS names consist of "element" pairs. + * + * Return: Byte following constructed DNS name + */ +static uint8_t *hdd_dns_make_name_query(const uint8_t *string, uint8_t *buf) +{ + uint8_t *length_byte = buf++; + uint8_t c; + + while ((c = *(string++))) { + if (c == '.') { + *length_byte = buf - length_byte - 1; + length_byte = buf; + } + *(buf++) = c; + } + *length_byte = buf - length_byte - 1; + *(buf++) = '\0'; + return buf; +} + +/** + * hdd_set_clear_connectivity_check_stats_info() - set/clear stats info + * @adapter: Pointer to hdd adapter + * @arp_stats_params: arp stats structure to be sent to FW + * @tb: nl attribute + * @is_set_stats: set/clear stats + * + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_set_clear_connectivity_check_stats_info( + struct hdd_adapter *adapter, + struct set_arp_stats_params *arp_stats_params, + struct nlattr **tb, bool is_set_stats) +{ + struct nlattr *tb2[CONNECTIVITY_STATS_SET_MAX + 1]; + struct nlattr *curr_attr = NULL; + int err = 0; + uint32_t pkt_bitmap; + int rem; + + /* Clear All Stats command has come */ + if (!is_set_stats) { + arp_stats_params->pkt_type_bitmap = adapter->pkt_type_bitmap; + /* DNS tracking is not supported in FW. */ + arp_stats_params->pkt_type_bitmap &= + ~CONNECTIVITY_CHECK_SET_DNS; + arp_stats_params->flag = false; + arp_stats_params->pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; + qdf_mem_zero(&adapter->hdd_stats.hdd_arp_stats, + sizeof(adapter->hdd_stats.hdd_arp_stats)); + qdf_mem_zero(&adapter->hdd_stats.hdd_dns_stats, + sizeof(adapter->hdd_stats.hdd_dns_stats)); + qdf_mem_zero(&adapter->hdd_stats.hdd_tcp_stats, + sizeof(adapter->hdd_stats.hdd_tcp_stats)); + qdf_mem_zero(&adapter->hdd_stats.hdd_icmpv4_stats, + sizeof(adapter->hdd_stats.hdd_icmpv4_stats)); + adapter->track_arp_ip = 0; + qdf_mem_zero(adapter->dns_payload, + adapter->track_dns_domain_len); + adapter->track_dns_domain_len = 0; + adapter->track_src_port = 0; + adapter->track_dest_port = 0; + adapter->track_dest_ipv4 = 0; + adapter->pkt_type_bitmap = 0; + goto end; + } + + /* Set NUD command for start tracking is received. */ + nla_for_each_nested(curr_attr, + tb[STATS_SET_DATA_PKT_INFO], + rem) { + + if (wlan_cfg80211_nla_parse(tb2, + CONNECTIVITY_STATS_SET_MAX, + nla_data(curr_attr), nla_len(curr_attr), + qca_wlan_vendor_set_connectivity_check_stats)) { + hdd_err("nla_parse failed"); + err = -EINVAL; + goto end; + } + + if (tb2[STATS_PKT_INFO_TYPE]) { + pkt_bitmap = nla_get_u32(tb2[STATS_PKT_INFO_TYPE]); + if (!pkt_bitmap) { + hdd_err("pkt tracking bitmap is empty"); + err = -EINVAL; + goto end; + } + arp_stats_params->pkt_type_bitmap = pkt_bitmap; + arp_stats_params->flag = true; + adapter->pkt_type_bitmap |= + arp_stats_params->pkt_type_bitmap; + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_ARP) { + if (!tb[STATS_GW_IPV4]) { + hdd_err("GW ipv4 address is not present"); + err = -EINVAL; + goto end; + } + arp_stats_params->ip_addr = + nla_get_u32(tb[STATS_GW_IPV4]); + arp_stats_params->pkt_type = + WLAN_NUD_STATS_ARP_PKT_TYPE; + adapter->track_arp_ip = + arp_stats_params->ip_addr; + qdf_mem_zero(&adapter->hdd_stats.hdd_arp_stats, + sizeof(adapter->hdd_stats. + hdd_arp_stats)); + } + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_DNS) { + uint8_t *domain_name; + + if (!tb2[STATS_DNS_DOMAIN_NAME]) { + hdd_err("DNS domain id is not present"); + err = -EINVAL; + goto end; + } + domain_name = + nla_data(tb2[STATS_DNS_DOMAIN_NAME]); + adapter->track_dns_domain_len = + nla_len(tb2[STATS_DNS_DOMAIN_NAME]); + hdd_dns_make_name_query(domain_name, + adapter->dns_payload); + /* DNS tracking is not supported in FW. */ + arp_stats_params->pkt_type_bitmap &= + ~CONNECTIVITY_CHECK_SET_DNS; + qdf_mem_zero(&adapter->hdd_stats.hdd_dns_stats, + sizeof(adapter->hdd_stats. + hdd_dns_stats)); + } + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE) { + if (!tb2[STATS_SRC_PORT] || + !tb2[STATS_DEST_PORT]) { + hdd_err("Source/Dest port is not present"); + err = -EINVAL; + goto end; + } + arp_stats_params->tcp_src_port = + nla_get_u32(tb2[STATS_SRC_PORT]); + arp_stats_params->tcp_dst_port = + nla_get_u32(tb2[STATS_DEST_PORT]); + adapter->track_src_port = + arp_stats_params->tcp_src_port; + adapter->track_dest_port = + arp_stats_params->tcp_dst_port; + qdf_mem_zero(&adapter->hdd_stats.hdd_tcp_stats, + sizeof(adapter->hdd_stats. + hdd_tcp_stats)); + } + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_ICMPV4) { + if (!tb2[STATS_DEST_IPV4]) { + hdd_err("destination ipv4 address to track ping packets is not present"); + err = -EINVAL; + goto end; + } + arp_stats_params->icmp_ipv4 = + nla_get_u32(tb2[STATS_DEST_IPV4]); + adapter->track_dest_ipv4 = + arp_stats_params->icmp_ipv4; + qdf_mem_zero(&adapter->hdd_stats.hdd_tcp_stats, + sizeof(adapter->hdd_stats. + hdd_tcp_stats)); + } + } else { + hdd_err("stats list empty"); + err = -EINVAL; + goto end; + } + } + +end: + return err; +} void hdd_update_cca_info_cb(void *context, uint32_t congestion, - uint32_t vdev_id) + uint32_t vdev_id) { struct hdd_context *hdd_ctx = (struct hdd_context *)context; int status; @@ -12556,25 +12813,6 @@ static int wlan_hdd_cfg80211_set_trace_level(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. @@ -12595,7 +12833,7 @@ static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, struct net_device *dev = wdev->netdev; struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - struct set_arp_stats_params arp_stats_params; + struct set_arp_stats_params arp_stats_params = {0}; int err = 0; hdd_enter(); @@ -12623,25 +12861,65 @@ static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, } 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; + /* tracking is enabled for stats other than arp. */ + if (tb[STATS_SET_DATA_PKT_INFO]) { + err = hdd_set_clear_connectivity_check_stats_info( + adapter, + &arp_stats_params, tb, true); + if (err) + return -EINVAL; + + /* + * if only tracking dns, then don't send + * wmi command to FW. + */ + if (!arp_stats_params.pkt_type_bitmap) + return err; + } else { + 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]); + adapter->track_arp_ip = arp_stats_params.ip_addr; + + 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.flag = true; - arp_stats_params.ip_addr = nla_get_u32(tb[STATS_GW_IPV4]); - hdd_ctx->track_arp_ip = arp_stats_params.ip_addr; } else { - arp_stats_params.flag = false; + /* clear tracking stats of other data types as well*/ + if (adapter->pkt_type_bitmap) { + err = hdd_set_clear_connectivity_check_stats_info( + adapter, + &arp_stats_params, tb, false); + if (err) + return -EINVAL; + + /* + * if only tracking dns, then don't send + * wmi command to FW. + */ + if (!arp_stats_params.pkt_type_bitmap) + return err; + } else { + arp_stats_params.flag = false; + 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; + } } - if (arp_stats_params.flag) + + 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->session_id; if (QDF_STATUS_SUCCESS != @@ -12712,9 +12990,45 @@ static int wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE #define AP_LINK_DAD \ QCA_ATTR_NUD_STATS_IS_DAD +#define DATA_PKT_STATS \ + QCA_ATTR_NUD_STATS_DATA_PKT_STATS #define STATS_GET_MAX \ QCA_ATTR_NUD_STATS_GET_MAX +#define CHECK_STATS_INVALID \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_INVALID +#define CHECK_STATS_PKT_TYPE \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_TYPE +#define CHECK_STATS_PKT_DNS_DOMAIN_NAME \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DNS_DOMAIN_NAME +#define CHECK_STATS_PKT_SRC_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_SRC_PORT +#define CHECK_STATS_PKT_DEST_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DEST_PORT +#define CHECK_STATS_PKT_DEST_IPV4 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DEST_IPV4 +#define CHECK_STATS_PKT_DEST_IPV6 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DEST_IPV6 +#define CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV +#define CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC +#define CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC +#define CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS +#define CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC +#define CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC +#define CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV +#define CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP +#define CHECK_DATA_STATS_MAX \ + QCA_ATTR_CONNECTIVITY_CHECK_DATA_STATS_MAX + + const struct nla_policy qca_wlan_vendor_get_nud_stats[STATS_GET_MAX + 1] = { [COUNT_FROM_NETDEV] = {.type = NLA_U16 }, @@ -12727,8 +13041,278 @@ qca_wlan_vendor_get_nud_stats[STATS_GET_MAX + 1] = { [RSP_COUNT_OUT_OF_ORDER_DROP] = {.type = NLA_U16 }, [AP_LINK_ACTIVE] = {.type = NLA_FLAG }, [AP_LINK_DAD] = {.type = NLA_FLAG }, + [DATA_PKT_STATS] = {.type = NLA_U16 }, }; +/** + * hdd_populate_dns_stats_info() - send dns stats info to network stack + * @adapter: pointer to adapter context + * @skb: pointer to skb + * + * + * Return: An error code or 0 on success. + */ +static int hdd_populate_dns_stats_info(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ + uint8_t *dns_query; + + dns_query = qdf_mem_malloc(adapter->track_dns_domain_len + 1); + if (!dns_query) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: mem alloc fail.", __func__); + return -EINVAL; + } + + qdf_mem_copy(dns_query, adapter->dns_payload, + adapter->track_dns_domain_len); + + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_DNS) || + nla_put(skb, CHECK_STATS_PKT_DNS_DOMAIN_NAME, + adapter->track_dns_domain_len, + hdd_dns_unmake_name_query(dns_query)) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + adapter->hdd_stats.hdd_dns_stats.tx_dns_req_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hdd_dns_stats.tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_dns_stats.tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + adapter->hdd_stats.hdd_dns_stats.tx_ack_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC, + adapter->hdd_stats.hdd_dns_stats.rx_dns_rsp_count) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV, + adapter->hdd_stats.hdd_dns_stats.rx_delivered) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP, + adapter->hdd_stats.hdd_dns_stats.rx_host_drop)) { + hdd_err("nla put fail"); + qdf_mem_free(dns_query); + kfree_skb(skb); + return -EINVAL; + } + qdf_mem_free(dns_query); + return 0; +} + +/** + * hdd_populate_tcp_stats_info() - send tcp stats info to network stack + * @adapter: pointer to adapter context + * @skb: pointer to skb + * @pkt_type: tcp pkt type + * + * Return: An error code or 0 on success. + */ +static int hdd_populate_tcp_stats_info(struct hdd_adapter *adapter, + struct sk_buff *skb, + uint8_t pkt_type) +{ + switch (pkt_type) { + case CONNECTIVITY_CHECK_SET_TCP_SYN: + /* Fill info for tcp syn packets (tx packet) */ + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_TCP_SYN) || + nla_put_u16(skb, CHECK_STATS_PKT_SRC_PORT, + adapter->track_src_port) || + nla_put_u16(skb, CHECK_STATS_PKT_DEST_PORT, + adapter->track_dest_port) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + adapter->hdd_stats.hdd_tcp_stats.tx_tcp_syn_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_syn_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_syn_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + adapter->hdd_stats.hdd_tcp_stats.tx_tcp_syn_ack_cnt)) { + hdd_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + break; + case CONNECTIVITY_CHECK_SET_TCP_SYN_ACK: + /* Fill info for tcp syn-ack packets (rx packet) */ + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_TCP_SYN_ACK) || + nla_put_u16(skb, CHECK_STATS_PKT_SRC_PORT, + adapter->track_src_port) || + nla_put_u16(skb, CHECK_STATS_PKT_DEST_PORT, + adapter->track_dest_port) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_tcp_stats.rx_fw_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC, + adapter->hdd_stats.hdd_tcp_stats. + rx_tcp_syn_ack_count) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV, + adapter->hdd_stats.hdd_tcp_stats.rx_delivered) || + nla_put_u16(skb, + CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP, + adapter->hdd_stats.hdd_tcp_stats.rx_host_drop)) { + hdd_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + break; + case CONNECTIVITY_CHECK_SET_TCP_ACK: + /* Fill info for tcp ack packets (tx packet) */ + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_TCP_ACK) || + nla_put_u16(skb, CHECK_STATS_PKT_SRC_PORT, + adapter->track_src_port) || + nla_put_u16(skb, CHECK_STATS_PKT_DEST_PORT, + adapter->track_dest_port) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + adapter->hdd_stats.hdd_tcp_stats.tx_tcp_ack_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_ack_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_ack_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + adapter->hdd_stats.hdd_tcp_stats.tx_tcp_ack_ack_cnt)) { + hdd_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + break; + default: + break; + } + return 0; +} + +/** + * hdd_populate_icmpv4_stats_info() - send icmpv4 stats info to network stack + * @adapter: pointer to adapter context + * @skb: pointer to skb + * + * + * Return: An error code or 0 on success. + */ +static int hdd_populate_icmpv4_stats_info(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_ICMPV4) || + nla_put_u32(skb, CHECK_STATS_PKT_DEST_IPV4, + adapter->track_dest_ipv4) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + adapter->hdd_stats.hdd_icmpv4_stats.tx_icmpv4_req_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hdd_icmpv4_stats.tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_icmpv4_stats.tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + adapter->hdd_stats.hdd_icmpv4_stats.tx_ack_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_icmpv4_stats.rx_fw_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC, + adapter->hdd_stats.hdd_icmpv4_stats.rx_icmpv4_rsp_count) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV, + adapter->hdd_stats.hdd_icmpv4_stats.rx_delivered) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP, + adapter->hdd_stats.hdd_icmpv4_stats.rx_host_drop)) { + hdd_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + return 0; +} + +/** + * hdd_populate_connectivity_check_stats_info() - send connectivity stats info + * to network stack + * @adapter: pointer to adapter context + * @skb: pointer to skb + * + * + * Return: An error code or 0 on success. + */ + +static int hdd_populate_connectivity_check_stats_info( + struct hdd_adapter *adapter, struct sk_buff *skb) +{ + struct nlattr *connect_stats, *connect_info; + uint32_t count = 0; + + connect_stats = nla_nest_start(skb, DATA_PKT_STATS); + if (connect_stats == NULL) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + if (adapter->pkt_type_bitmap & CONNECTIVITY_CHECK_SET_DNS) { + connect_info = nla_nest_start(skb, count); + if (connect_info == NULL) { + hdd_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + + if (hdd_populate_dns_stats_info(adapter, skb)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + } + + if (adapter->pkt_type_bitmap & CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE) { + connect_info = nla_nest_start(skb, count); + if (connect_info == NULL) { + hdd_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + if (hdd_populate_tcp_stats_info(adapter, skb, + CONNECTIVITY_CHECK_SET_TCP_SYN)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + + connect_info = nla_nest_start(skb, count); + if (connect_info == NULL) { + hdd_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + if (hdd_populate_tcp_stats_info(adapter, skb, + CONNECTIVITY_CHECK_SET_TCP_SYN_ACK)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + + connect_info = nla_nest_start(skb, count); + if (connect_info == NULL) { + hdd_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + if (hdd_populate_tcp_stats_info(adapter, skb, + CONNECTIVITY_CHECK_SET_TCP_ACK)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + } + + if (adapter->pkt_type_bitmap & CONNECTIVITY_CHECK_SET_ICMPV4) { + connect_info = nla_nest_start(skb, count); + if (connect_info == NULL) { + hdd_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + + if (hdd_populate_icmpv4_stats_info(adapter, skb)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + } + + nla_nest_end(skb, connect_stats); + return 0; + +put_attr_fail: + hdd_err("QCA_WLAN_VENDOR_ATTR put fail. count %u", count); + return -EINVAL; +} + + /** * __wlan_hdd_cfg80211_get_nud_stats() - get arp stats command to firmware * @wiphy: pointer to wireless wiphy structure. @@ -12753,6 +13337,7 @@ static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, struct hdd_context *hdd_ctx = wiphy_priv(wiphy); struct get_arp_stats_params arp_stats_params; void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t pkt_type_bitmap; struct sk_buff *skb; hdd_enter(); @@ -12834,7 +13419,15 @@ static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, if (adapter->dad) nla_put_flag(skb, AP_LINK_DAD); - hdd_ctx->track_arp_ip = 0; + pkt_type_bitmap = adapter->pkt_type_bitmap; + /* ARP tracking is done above. */ + pkt_type_bitmap &= ~CONNECTIVITY_CHECK_SET_ARP; + + if (pkt_type_bitmap) { + if (hdd_populate_connectivity_check_stats_info(adapter, skb)) + return -EINVAL; + } + cfg80211_vendor_cmd_reply(skb); return err; } diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index c23400fb5df73..094868b706c66 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -37,6 +37,7 @@ #include #include #include +#include struct hdd_context; @@ -227,6 +228,24 @@ struct cfg80211_bss * wlan_hdd_cfg80211_update_bss_db(struct hdd_adapter *adapter, struct csr_roam_info *roam_info); +#define CONNECTIVITY_CHECK_SET_ARP \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_ARP +#define CONNECTIVITY_CHECK_SET_DNS \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_DNS +#define CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE +#define CONNECTIVITY_CHECK_SET_ICMPV4 \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_ICMPV4 +#define CONNECTIVITY_CHECK_SET_ICMPV6 \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_ICMPV6 +#define CONNECTIVITY_CHECK_SET_TCP_SYN \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_SYN +#define CONNECTIVITY_CHECK_SET_TCP_SYN_ACK \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_SYN_ACK +#define CONNECTIVITY_CHECK_SET_TCP_ACK \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_ACK + + int wlan_hdd_cfg80211_pmksa_candidate_notify(struct hdd_adapter *adapter, struct csr_roam_info *roam_info, int index, bool preauth); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index ec0eea713275f..e9eafd3ff7de9 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -10763,6 +10763,15 @@ static void hdd_get_nud_stats_cb(void *data, struct rsp_stats *rsp) adapter->dad |= rsp->dad_detected; adapter->con_status = rsp->connect_status; + /* Flag true indicates connectivity check stats present. */ + if (rsp->connect_stats_present) { + hdd_info("rsp->tcp_ack_recvd :%x", rsp->tcp_ack_recvd); + hdd_info("rsp->icmpv4_rsp_recvd :%x", rsp->icmpv4_rsp_recvd); + adapter->hdd_stats.hdd_tcp_stats.rx_fw_cnt = rsp->tcp_ack_recvd; + adapter->hdd_stats.hdd_icmpv4_stats.rx_fw_cnt = + rsp->icmpv4_rsp_recvd; + } + spin_lock(&hdd_context_lock); context = &hdd_ctx->nud_stats_context; complete(&context->response_event); diff --git a/core/hdd/src/wlan_hdd_ocb.c b/core/hdd/src/wlan_hdd_ocb.c index 57779546710c8..6c72788146dfa 100644 --- a/core/hdd/src/wlan_hdd_ocb.c +++ b/core/hdd/src/wlan_hdd_ocb.c @@ -266,6 +266,7 @@ static int hdd_ocb_register_sta(struct hdd_adapter *adapter) (struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc, (struct cdp_pdev *)pdev, adapter->session_id), adapter, &txrx_ops); + txrx_ops.rx.stats_rx = hdd_tx_rx_collect_connectivity_stats_info; adapter->tx_fn = txrx_ops.tx.tx; qdf_status = cdp_peer_register(soc, diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index 100b324f9e3b3..e263954a68ed5 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -63,6 +63,7 @@ #include #include "wlan_hdd_rx_monitor.h" #include "wlan_hdd_power.h" +#include "wlan_hdd_cfg80211.h" #include #ifdef QCA_LL_TX_FLOW_CONTROL_V2 @@ -548,6 +549,263 @@ static inline bool hdd_is_tx_allowed(struct sk_buff *skb, uint8_t peer_id) FL("Invalid peer state for Tx: %d"), peer_state); return false; } +/** + * hdd_tx_rx_is_dns_domain_name_match() - function to check whether dns + * domain name in the received skb matches with the tracking dns domain + * name or not + * + * @skb: pointer to skb + * @adapter: pointer to adapter + * + * Returns: true if matches else false + */ +static bool hdd_tx_rx_is_dns_domain_name_match(struct sk_buff *skb, + struct hdd_adapter *adapter) +{ + uint8_t *domain_name; + + if (adapter->track_dns_domain_len == 0) + return false; + + domain_name = qdf_nbuf_get_dns_domain_name(skb, + adapter->track_dns_domain_len); + if (strncmp(domain_name, adapter->dns_payload, + adapter->track_dns_domain_len) == 0) + return true; + else + return false; +} + +void hdd_tx_rx_collect_connectivity_stats_info(struct sk_buff *skb, + void *context, + enum connectivity_stats_pkt_status action, + uint8_t *pkt_type) +{ + uint32_t pkt_type_bitmap; + struct hdd_adapter *adapter = NULL; + + adapter = (struct hdd_adapter *)context; + if (unlikely(adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "Magic cookie(%x) for adapter sanity verification is invalid", + adapter->magic); + return; + } + + /* ARP tracking is done already. */ + pkt_type_bitmap = adapter->pkt_type_bitmap; + pkt_type_bitmap &= ~CONNECTIVITY_CHECK_SET_ARP; + + if (!pkt_type_bitmap) + return; + + switch (action) { + case PKT_TYPE_REQ: + case PKT_TYPE_TX_HOST_FW_SENT: + if (qdf_nbuf_is_icmp_pkt(skb)) { + if (qdf_nbuf_data_is_icmpv4_req(skb) && + (adapter->track_dest_ipv4 == + qdf_nbuf_get_icmpv4_tgt_ip(skb))) { + *pkt_type = CONNECTIVITY_CHECK_SET_ICMPV4; + if (action == PKT_TYPE_REQ) { + ++adapter->hdd_stats.hdd_icmpv4_stats. + tx_icmpv4_req_count; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : ICMPv4 Req packet", + __func__); + } else + /* host receives tx completion */ + ++adapter->hdd_stats.hdd_icmpv4_stats. + tx_host_fw_sent; + } + } else if (qdf_nbuf_is_ipv4_tcp_pkt(skb)) { + if (qdf_nbuf_data_is_tcp_syn(skb) && + (adapter->track_dest_port == + qdf_nbuf_data_get_tcp_dst_port(skb))) { + *pkt_type = CONNECTIVITY_CHECK_SET_TCP_SYN; + if (action == PKT_TYPE_REQ) { + ++adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_syn_count; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : TCP Syn packet", + __func__); + } else + /* host receives tx completion */ + ++adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_syn_host_fw_sent; + } else if ((adapter->hdd_stats.hdd_tcp_stats. + is_tcp_syn_ack_rcv || adapter->hdd_stats. + hdd_tcp_stats.is_tcp_ack_sent) && + qdf_nbuf_data_is_tcp_ack(skb) && + (adapter->track_dest_port == + qdf_nbuf_data_get_tcp_dst_port(skb))) { + *pkt_type = CONNECTIVITY_CHECK_SET_TCP_ACK; + if (action == PKT_TYPE_REQ && + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_syn_ack_rcv) { + ++adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_ack_count; + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_syn_ack_rcv = false; + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_ack_sent = true; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : TCP Ack packet", + __func__); + } else if (action == PKT_TYPE_TX_HOST_FW_SENT && + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_ack_sent) { + /* host receives tx completion */ + ++adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_ack_host_fw_sent; + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_ack_sent = false; + } + } + } else if (qdf_nbuf_is_ipv4_udp_pkt(skb)) { + if (qdf_nbuf_data_is_dns_query(skb) && + hdd_tx_rx_is_dns_domain_name_match(skb, adapter)) { + *pkt_type = CONNECTIVITY_CHECK_SET_DNS; + if (action == PKT_TYPE_REQ) { + ++adapter->hdd_stats.hdd_dns_stats. + tx_dns_req_count; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : DNS query packet", + __func__); + } else + /* host receives tx completion */ + ++adapter->hdd_stats.hdd_dns_stats. + tx_host_fw_sent; + } + } + break; + + case PKT_TYPE_RSP: + if (qdf_nbuf_is_icmp_pkt(skb)) { + if (qdf_nbuf_data_is_icmpv4_rsp(skb) && + (adapter->track_dest_ipv4 == + qdf_nbuf_get_icmpv4_src_ip(skb))) { + ++adapter->hdd_stats.hdd_icmpv4_stats. + rx_icmpv4_rsp_count; + *pkt_type = + CONNECTIVITY_CHECK_SET_ICMPV4; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : ICMPv4 Res packet", __func__); + } + } else if (qdf_nbuf_is_ipv4_tcp_pkt(skb)) { + if (qdf_nbuf_data_is_tcp_syn_ack(skb) && + (adapter->track_dest_port == + qdf_nbuf_data_get_tcp_src_port(skb))) { + ++adapter->hdd_stats.hdd_tcp_stats. + rx_tcp_syn_ack_count; + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_syn_ack_rcv = true; + *pkt_type = + CONNECTIVITY_CHECK_SET_TCP_SYN_ACK; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : TCP Syn ack packet", __func__); + } + } else if (qdf_nbuf_is_ipv4_udp_pkt(skb)) { + if (qdf_nbuf_data_is_dns_response(skb) && + hdd_tx_rx_is_dns_domain_name_match(skb, adapter)) { + ++adapter->hdd_stats.hdd_dns_stats. + rx_dns_rsp_count; + *pkt_type = CONNECTIVITY_CHECK_SET_DNS; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : DNS response packet", __func__); + } + } + break; + + case PKT_TYPE_TX_DROPPED: + switch (*pkt_type) { + case CONNECTIVITY_CHECK_SET_ICMPV4: + ++adapter->hdd_stats.hdd_icmpv4_stats.tx_dropped; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : ICMPv4 Req packet dropped", __func__); + break; + case CONNECTIVITY_CHECK_SET_TCP_SYN: + ++adapter->hdd_stats.hdd_tcp_stats.tx_tcp_syn_dropped; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : TCP syn packet dropped", __func__); + break; + case CONNECTIVITY_CHECK_SET_TCP_ACK: + ++adapter->hdd_stats.hdd_tcp_stats.tx_tcp_ack_dropped; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : TCP ack packet dropped", __func__); + break; + case CONNECTIVITY_CHECK_SET_DNS: + ++adapter->hdd_stats.hdd_dns_stats.tx_dropped; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : DNS query packet dropped", __func__); + break; + default: + break; + } + break; + case PKT_TYPE_RX_DELIVERED: + switch (*pkt_type) { + case CONNECTIVITY_CHECK_SET_ICMPV4: + ++adapter->hdd_stats.hdd_icmpv4_stats.rx_delivered; + break; + case CONNECTIVITY_CHECK_SET_TCP_SYN_ACK: + ++adapter->hdd_stats.hdd_tcp_stats.rx_delivered; + break; + case CONNECTIVITY_CHECK_SET_DNS: + ++adapter->hdd_stats.hdd_dns_stats.rx_delivered; + break; + default: + break; + } + break; + case PKT_TYPE_RX_REFUSED: + switch (*pkt_type) { + case CONNECTIVITY_CHECK_SET_ICMPV4: + ++adapter->hdd_stats.hdd_icmpv4_stats.rx_refused; + break; + case CONNECTIVITY_CHECK_SET_TCP_SYN_ACK: + ++adapter->hdd_stats.hdd_tcp_stats.rx_refused; + break; + case CONNECTIVITY_CHECK_SET_DNS: + ++adapter->hdd_stats.hdd_dns_stats.rx_refused; + break; + default: + break; + } + break; + case PKT_TYPE_TX_ACK_CNT: + switch (*pkt_type) { + case CONNECTIVITY_CHECK_SET_ICMPV4: + ++adapter->hdd_stats.hdd_icmpv4_stats.tx_ack_cnt; + break; + case CONNECTIVITY_CHECK_SET_TCP_SYN: + ++adapter->hdd_stats.hdd_tcp_stats.tx_tcp_syn_ack_cnt; + break; + case CONNECTIVITY_CHECK_SET_TCP_ACK: + ++adapter->hdd_stats.hdd_tcp_stats.tx_tcp_ack_ack_cnt; + break; + case CONNECTIVITY_CHECK_SET_DNS: + ++adapter->hdd_stats.hdd_dns_stats.tx_ack_cnt; + break; + default: + break; + } + break; + default: + break; + } +} /** * __hdd_hard_start_xmit() - Transmit a frame @@ -573,6 +831,7 @@ static int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct hdd_station_ctx *sta_ctx = &adapter->session.station; struct qdf_mac_addr *mac_addr; bool pkt_proto_logged = false; + uint8_t pkt_type = 0; #ifdef QCA_PKT_PROTO_TRACE uint8_t proto_type = 0; #endif @@ -607,6 +866,10 @@ static int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) "%s : ARP packet", __func__); } } + /* track connectivity stats */ + if (adapter->pkt_type_bitmap) + hdd_tx_rx_collect_connectivity_stats_info(skb, adapter, + PKT_TYPE_REQ, &pkt_type); if (cds_is_driver_recovering()) { QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_WARN, @@ -828,6 +1091,11 @@ drop_pkt_accounting: "%s : ARP packet dropped", __func__); } + /* track connectivity stats */ + if (adapter->pkt_type_bitmap) + hdd_tx_rx_collect_connectivity_stats_info(skb, adapter, + PKT_TYPE_TX_DROPPED, &pkt_type); + return NETDEV_TX_OK; } @@ -1240,6 +1508,7 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf) unsigned int cpu_index; struct qdf_mac_addr *mac_addr; bool wake_lock = false; + uint8_t pkt_type = 0; bool proto_pkt_logged = false; bool track_arp = false; @@ -1292,6 +1561,10 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf) track_arp = true; } } + /* track connectivity stats */ + if (adapter->pkt_type_bitmap) + hdd_tx_rx_collect_connectivity_stats_info(skb, adapter, + PKT_TYPE_RSP, &pkt_type); sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); if ((sta_ctx->conn_info.proxyARPService) && @@ -1396,19 +1669,35 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf) if (track_arp) ++adapter->hdd_stats.hdd_arp_stats. rx_delivered; + /* track connectivity stats */ + if (adapter->pkt_type_bitmap) + hdd_tx_rx_collect_connectivity_stats_info( + skb, adapter, + PKT_TYPE_RX_DELIVERED, + &pkt_type); } else { ++adapter->hdd_stats.tx_rx_stats. rx_refused[cpu_index]; if (track_arp) ++adapter->hdd_stats.hdd_arp_stats. rx_refused; + /* track connectivity stats */ + if (adapter->pkt_type_bitmap) + hdd_tx_rx_collect_connectivity_stats_info( + skb, adapter, + PKT_TYPE_RX_REFUSED, &pkt_type); } } else { ++adapter->hdd_stats.tx_rx_stats. rx_delivered[cpu_index]; if (track_arp) ++adapter->hdd_stats.hdd_arp_stats. - rx_delivered; + rx_delivered; + /* track connectivity stats */ + if (adapter->pkt_type_bitmap) + hdd_tx_rx_collect_connectivity_stats_info( + skb, adapter, + PKT_TYPE_RX_DELIVERED, &pkt_type); } }