From bbae800e1475eae18e37ea3a8543e18242c47cc7 Mon Sep 17 00:00:00 2001 From: Surabhi Vishnoi Date: Mon, 13 Feb 2023 11:14:20 +0530 Subject: [PATCH] qcacmn: Fix checksum offload logic for rx packets Currently, hardware supports checksum offload for only ipv4, tcpv4/v6 and udpv4/v6 packets. But driver sets checksum as CHECKSUM_UNNECESSARY for all rx packets if tcp_udp_err and ip_err bit in rx_attention_tlv is not set. If driver sets CHECKSUM_UNNECESSARY in skb then network stack will not validate checksum and will reply to even wrong checksum packets which is incorrect. So, fix is to set checksum for all rx packets other than ipv4, tcpv4/v6 and udpv4/v6 to CHECKSUM_NONE instead of CHECKSUM_UNNECESSARY so that network stack validates checksum. Change-Id: Ifb9c74fb729361da6db715fa667f926b71ce948f CRs-Fixed: 3378925 --- dp/wifi3.0/dp_rx.h | 30 +++++++++++++++++++++++++----- qdf/inc/qdf_net_types.h | 2 ++ qdf/linux/src/qdf_nbuf.c | 1 + 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index 77c5859343..2797ea25ef 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -2542,13 +2542,33 @@ void dp_rx_cksum_offload(struct dp_pdev *pdev, hal_rx_tlv_csum_err_get(pdev->soc->hal_soc, rx_tlv_hdr, &ip_csum_err, &tcp_udp_csum_er); - if (qdf_likely(!ip_csum_err && !tcp_udp_csum_er)) { - cksum.l4_result = QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY; - qdf_nbuf_set_rx_cksum(nbuf, &cksum); + if (qdf_nbuf_is_ipv4_pkt(nbuf)) { + if (qdf_likely(!ip_csum_err)) { + cksum.l4_result = QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY; + if (qdf_nbuf_is_ipv4_udp_pkt(nbuf) || + qdf_nbuf_is_ipv4_tcp_pkt(nbuf)) { + if (qdf_likely(!tcp_udp_csum_er)) + cksum.csum_level = 1; + else + DP_STATS_INCC(pdev, + err.tcp_udp_csum_err, 1, + tcp_udp_csum_er); + } + } else { + DP_STATS_INCC(pdev, err.ip_csum_err, 1, ip_csum_err); + } + } else if (qdf_nbuf_is_ipv6_udp_pkt(nbuf) || + qdf_nbuf_is_ipv6_tcp_pkt(nbuf)) { + if (qdf_likely(!tcp_udp_csum_er)) + cksum.l4_result = QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY; + else + DP_STATS_INCC(pdev, err.tcp_udp_csum_err, 1, + tcp_udp_csum_er); } else { - DP_STATS_INCC(pdev, err.ip_csum_err, 1, ip_csum_err); - DP_STATS_INCC(pdev, err.tcp_udp_csum_err, 1, tcp_udp_csum_er); + cksum.l4_result = QDF_NBUF_RX_CKSUM_NONE; } + + qdf_nbuf_set_rx_cksum(nbuf, &cksum); } #else static inline diff --git a/qdf/inc/qdf_net_types.h b/qdf/inc/qdf_net_types.h index 4cb797ab13..3cf00039ab 100644 --- a/qdf/inc/qdf_net_types.h +++ b/qdf/inc/qdf_net_types.h @@ -275,11 +275,13 @@ typedef enum { * typedef qdf_nbuf_rx_cksum_t - receive checksum type * @l4_type: L4 type * @l4_result: L4 result + * @csum_level: indicates number of checksum are calculated */ typedef struct { qdf_nbuf_l4_rx_cksum_type_t l4_type; qdf_nbuf_l4_rx_cksum_result_t l4_result; uint32_t val; + uint32_t csum_level; } qdf_nbuf_rx_cksum_t; #define QDF_ARP_REQ 1 /* ARP request */ diff --git a/qdf/linux/src/qdf_nbuf.c b/qdf/linux/src/qdf_nbuf.c index 05a37f1176..d247f34869 100644 --- a/qdf/linux/src/qdf_nbuf.c +++ b/qdf/linux/src/qdf_nbuf.c @@ -1276,6 +1276,7 @@ __qdf_nbuf_set_rx_cksum(struct sk_buff *skb, qdf_nbuf_rx_cksum_t *cksum) break; case QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY: skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->csum_level = cksum->csum_level; break; case QDF_NBUF_RX_CKSUM_TCP_UDP_HW: skb->ip_summed = CHECKSUM_PARTIAL;