diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h index c29231bd70..0c68982d2f 100644 --- a/dp/inc/cdp_txrx_stats_struct.h +++ b/dp/inc/cdp_txrx_stats_struct.h @@ -1144,6 +1144,7 @@ struct cdp_htt_rx_pdev_stats { * @mec:Multicast Echo check * @mesh_filter: Mesh Filtered packets * @mon_rx_drop: packets dropped on monitor vap + * @wifi_parse: rxdma errors due to wifi parse error * @pkts: total packets replenished * @rxdma_err: rxdma errors for replenished * @nbuf_alloc_fail: nbuf alloc failed @@ -1154,6 +1155,7 @@ struct cdp_htt_rx_pdev_stats { * @mesh_mem_alloc: Mesh Rx Stats Alloc fail * @tso_desc_cnt: TSO descriptors * @sg_desc_cnt: SG Descriptors + * @vlan_tag_stp_cnt: Vlan tagged Stp packets in wifi parse error * @desc_alloc_fail: desc alloc failed errors * @ip_csum_err: ip checksum errors * @tcp_udp_csum_err: tcp/udp checksum errors @@ -1173,6 +1175,7 @@ struct cdp_pdev_stats { uint32_t mec; uint32_t mesh_filter; uint32_t mon_rx_drop; + uint32_t wifi_parse; } dropped; struct { @@ -1188,6 +1191,7 @@ struct cdp_pdev_stats { uint32_t mesh_mem_alloc; uint32_t tso_desc_cnt; uint32_t sg_desc_cnt; + uint32_t vlan_tag_stp_cnt; /* Rx errors */ struct { diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 66ef870804..71ebf38e67 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -6726,6 +6726,8 @@ dp_print_pdev_rx_stats(struct dp_pdev *pdev) DP_PRINT_STATS("Dropped:"); DP_PRINT_STATS(" msdu_not_done = %d", pdev->stats.dropped.msdu_not_done); + DP_PRINT_STATS(" wifi parse = %d", + pdev->stats.dropped.wifi_parse); DP_PRINT_STATS(" mon_rx_drop = %d", pdev->stats.dropped.mon_rx_drop); DP_PRINT_STATS(" mec_drop = %d", @@ -6737,6 +6739,8 @@ dp_print_pdev_rx_stats(struct dp_pdev *pdev) pdev->stats.rx.to_stack.num); DP_PRINT_STATS(" Bytes = %llu", pdev->stats.rx.to_stack.bytes); + DP_PRINT_STATS(" vlan_tag_stp_cnt = %d", + pdev->stats.vlan_tag_stp_cnt); DP_PRINT_STATS("Multicast/Broadcast:"); DP_PRINT_STATS(" Packets = %d", pdev->stats.rx.multicast.num); diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index 12db05c098..e24b7e97ef 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -119,6 +119,16 @@ struct dp_rx_desc { (((_cookie) & RX_DESC_COOKIE_INDEX_MASK) >> \ RX_DESC_COOKIE_INDEX_SHIFT) +/* DOC: Offset to obtain LLC hdr + * + * In the case of Wifi parse error + * to reach LLC header from beginning + * of VLAN tag we need to skip 8 bytes. + * Vlan_tag(4)+length(2)+length added + * by HW(2) = 8 bytes. + */ +#define DP_SKIP_VLAN 8 + /* *dp_rx_xor_block() - xor block of data *@b: destination data block @@ -1036,4 +1046,9 @@ static inline void dp_rx_desc_prep(struct dp_rx_desc *rx_desc, qdf_nbuf_t nbuf) rx_desc->unmapped = 0; } #endif /* RX_DESC_DEBUG_CHECK */ + +void dp_rx_process_rxdma_err(struct dp_soc *soc, qdf_nbuf_t nbuf, + uint8_t *rx_tlv_hdr, struct dp_peer *peer, + uint8_t err_code); + #endif /* _DP_RX_H */ diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 8048170ac2..2d9fd4c73e 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -31,6 +31,7 @@ #endif #include "dp_rx_defrag.h" #include /* LLC_SNAP_HDR_LEN */ +#include "qdf_net_types.h" /** * dp_rx_mcast_echo_check() - check if the mcast pkt is a loop @@ -843,18 +844,20 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, qdf_nbuf_t nbuf, } /** - * dp_rx_process_err_unencrypted() - Function to deliver rxdma unencrypted_err - * frames to OS + * dp_rx_process_rxdma_err() - Function to deliver rxdma unencrypted_err + * frames to OS or wifi parse errors. * @soc: core DP main context * @nbuf: buffer pointer * @rx_tlv_hdr: start of rx tlv header * @peer: peer reference + * @err_code: rxdma err code * * Return: None */ -static void -dp_rx_process_err_unencrypted(struct dp_soc *soc, qdf_nbuf_t nbuf, - uint8_t *rx_tlv_hdr, struct dp_peer *peer) +void +dp_rx_process_rxdma_err(struct dp_soc *soc, qdf_nbuf_t nbuf, + uint8_t *rx_tlv_hdr, struct dp_peer *peer, + uint8_t err_code) { uint32_t pkt_len, l2_hdr_offset; uint16_t msdu_len; @@ -913,6 +916,21 @@ dp_rx_process_err_unencrypted(struct dp_soc *soc, qdf_nbuf_t nbuf, */ qdf_nbuf_pull_head(nbuf, l2_hdr_offset + RX_PKT_TLVS_LEN); + if (err_code == HAL_RXDMA_ERR_WIFI_PARSE) { + uint8_t *pkt_type; + + pkt_type = qdf_nbuf_data(nbuf) + (2 * QDF_MAC_ADDR_SIZE); + if (*(uint16_t *)pkt_type == htons(QDF_ETH_TYPE_8021Q) && + *(uint16_t *)(pkt_type + DP_SKIP_VLAN) == htons(QDF_LLC_STP)) { + DP_STATS_INC(vdev->pdev, vlan_tag_stp_cnt, 1); + goto process_mesh; + } else { + DP_STATS_INC(vdev->pdev, dropped.wifi_parse, 1); + qdf_nbuf_free(nbuf); + return; + } + } + if (vdev->rx_decap_type == htt_cmn_pkt_type_raw) goto process_mesh; @@ -937,24 +955,24 @@ dp_rx_process_err_unencrypted(struct dp_soc *soc, qdf_nbuf_t nbuf, process_mesh: - /* Drop & free packet if mesh mode not enabled */ - if (!vdev->mesh_vdev) { + if (!vdev->mesh_vdev && err_code == HAL_RXDMA_ERR_UNENCRYPTED) { qdf_nbuf_free(nbuf); DP_STATS_INC(soc, rx.err.invalid_vdev, 1); return; } - if (dp_rx_filter_mesh_packets(vdev, nbuf, rx_tlv_hdr) - == QDF_STATUS_SUCCESS) { - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_MED, - FL("mesh pkt filtered")); - DP_STATS_INC(vdev->pdev, dropped.mesh_filter, 1); + if (vdev->mesh_vdev) { + if (dp_rx_filter_mesh_packets(vdev, nbuf, rx_tlv_hdr) + == QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_MED, + FL("mesh pkt filtered")); + DP_STATS_INC(vdev->pdev, dropped.mesh_filter, 1); - qdf_nbuf_free(nbuf); - return; + qdf_nbuf_free(nbuf); + return; + } + dp_rx_fill_mesh_stats(vdev, nbuf, rx_tlv_hdr, peer); } - dp_rx_fill_mesh_stats(vdev, nbuf, rx_tlv_hdr, peer); - process_rx: if (qdf_unlikely(hal_rx_msdu_end_da_is_mcbc_get(rx_tlv_hdr) && (vdev->rx_decap_type == @@ -1481,13 +1499,14 @@ done: switch (wbm_err_info.rxdma_err_code) { case HAL_RXDMA_ERR_UNENCRYPTED: - dp_rx_process_err_unencrypted( - soc, nbuf, - rx_tlv_hdr, peer); + + case HAL_RXDMA_ERR_WIFI_PARSE: + dp_rx_process_rxdma_err(soc, nbuf, + rx_tlv_hdr, peer, + wbm_err_info.rxdma_err_code); nbuf = next; if (peer) - dp_peer_unref_del_find_by_id( - peer); + dp_peer_unref_del_find_by_id(peer); continue; case HAL_RXDMA_ERR_TKIP_MIC: diff --git a/qdf/inc/qdf_net_types.h b/qdf/inc/qdf_net_types.h index bbce5f036f..fdf61628bc 100644 --- a/qdf/inc/qdf_net_types.h +++ b/qdf/inc/qdf_net_types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -60,6 +60,7 @@ typedef __in6_addr_t in6_addr_t; #define QDF_ETH_TYPE_IPV4 0x0800 /* IPV4 */ #define QDF_ETH_TYPE_IPV6 0x86dd /* IPV6 */ +#define QDF_ETH_TYPE_8021Q 0x8100 /* 802.1Q vlan protocol */ #define QDF_IEEE80211_4ADDR_HDR_LEN 30 #define QDF_IEEE80211_3ADDR_HDR_LEN 24 #define QDF_IEEE80211_FC0_SUBTYPE_QOS 0x80 @@ -68,6 +69,13 @@ typedef __in6_addr_t in6_addr_t; #define QDF_NET_IS_MAC_MULTICAST(_a) (*(_a) & 0x01) +/** + * In LLC header individual LSAP address 0x42 in + * DSAP and SSAP signifies IEEE 802.1 Bridge + * Spanning Tree Protocol + */ +#define QDF_LLC_STP 0x4242 + typedef struct qdf_net_ethaddr { uint8_t addr[QDF_NET_ETH_LEN]; } qdf_net_ethaddr_t;