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