net: qualcomm: rmnet: Fix incorrect UL checksum offload logic [Linux 4.19.66]

This Linux kernel change "net: qualcomm: rmnet: Fix incorrect UL checksum offload logic" is included in the Linux 4.19.66 release. This change is authored by Subash Abhinov Kasiviswanathan <subashab [at] codeaurora.org> on Thu Jul 25 12:07:12 2019 -0600. The commit for this change in Linux stable tree is 44b96a3 (patch) which is from upstream commit a7cf3d2. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream a7cf3d2.

net: qualcomm: rmnet: Fix incorrect UL checksum offload logic

[ Upstream commit a7cf3d24ee6081930feb4c830a7f6f16ebe31c49 ]

The udp_ip4_ind bit is set only for IPv4 UDP non-fragmented packets
so that the hardware can flip the checksum to 0xFFFF if the computed
checksum is 0 per RFC768.

However, this bit had to be set for IPv6 UDP non fragmented packets
as well per hardware requirements. Otherwise, IPv6 UDP packets
with computed checksum as 0 were transmitted by hardware and were
dropped in the network.

In addition to setting this bit for IPv6 UDP, the field is also
appropriately renamed to udp_ind as part of this change.

Fixes: 5eb5f8608ef1 ("net: qualcomm: rmnet: Add support for TX checksum offload")
Cc: Sean Tranchetti <[email protected]>
Signed-off-by: Subash Abhinov Kasiviswanathan <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

There are 15 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h      |  2 +-
 drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c | 13 +++++++++----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
index 884f1f5..70879a3 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
@@ -59,7 +59,7 @@ struct rmnet_map_dl_csum_trailer {
 struct rmnet_map_ul_csum_header {
    __be16 csum_start_offset;
    u16 csum_insert_offset:14;
-   u16 udp_ip4_ind:1;
+   u16 udp_ind:1;
    u16 csum_enabled:1;
 } __aligned(1);

diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
index 57a9c31..b2090ce 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
@@ -215,9 +215,9 @@ static void rmnet_map_complement_ipv4_txporthdr_csum_field(void *iphdr)
    ul_header->csum_insert_offset = skb->csum_offset;
    ul_header->csum_enabled = 1;
    if (ip4h->protocol == IPPROTO_UDP)
-       ul_header->udp_ip4_ind = 1;
+       ul_header->udp_ind = 1;
    else
-       ul_header->udp_ip4_ind = 0;
+       ul_header->udp_ind = 0;

    /* Changing remaining fields to network order */
    hdr++;
@@ -248,6 +248,7 @@ static void rmnet_map_complement_ipv6_txporthdr_csum_field(void *ip6hdr)
                  struct rmnet_map_ul_csum_header *ul_header,
                  struct sk_buff *skb)
 {
+   struct ipv6hdr *ip6h = (struct ipv6hdr *)ip6hdr;
    __be16 *hdr = (__be16 *)ul_header, offset;

    offset = htons((__force u16)(skb_transport_header(skb) -
@@ -255,7 +256,11 @@ static void rmnet_map_complement_ipv6_txporthdr_csum_field(void *ip6hdr)
    ul_header->csum_start_offset = offset;
    ul_header->csum_insert_offset = skb->csum_offset;
    ul_header->csum_enabled = 1;
-   ul_header->udp_ip4_ind = 0;
+
+   if (ip6h->nexthdr == IPPROTO_UDP)
+       ul_header->udp_ind = 1;
+   else
+       ul_header->udp_ind = 0;

    /* Changing remaining fields to network order */
    hdr++;
@@ -428,7 +433,7 @@ void rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
    ul_header->csum_start_offset = 0;
    ul_header->csum_insert_offset = 0;
    ul_header->csum_enabled = 0;
-   ul_header->udp_ip4_ind = 0;
+   ul_header->udp_ind = 0;

    priv->stats.csum_sw++;
 }

Leave a Reply

Your email address will not be published. Required fields are marked *