net: rmnet_data: Fix incorrect UL checksum offload logic

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.

Change-Id: Ia00e3f364e9732b182b7aebe843beb443269fd9e
Signed-off-by: Chinmay Agarwal <chinagar@codeaurora.org>
This commit is contained in:
Chinmay Agarwal 2020-07-17 18:09:02 +05:30 • committed by Gerrit - the friendly Code Review server
commit 6ee188aa79
2 changed files with 13 additions and 8 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2017, 2020 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -64,11 +64,11 @@ struct rmnet_map_ul_checksum_header_s {
unsigned short checksum_start_offset;
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned short checksum_insert_offset:14;
unsigned short udp_ip4_ind:1;
unsigned short udp_ind:1;
unsigned short cks_en:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned short cks_en:1;
unsigned short udp_ip4_ind:1;
unsigned short udp_ind:1;
unsigned short checksum_insert_offset:14;
#else
#error "Please fix <asm/byteorder.h>"

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -625,9 +625,9 @@ static void rmnet_map_fill_ipv4_packet_ul_checksum_header
ul_header->checksum_insert_offset = skb->csum_offset;
ul_header->cks_en = 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 checksum_insert_offset to network order */
hdr++;
*hdr = htons(*hdr);
@ -638,13 +638,18 @@ static void rmnet_map_fill_ipv6_packet_ul_checksum_header
(void *iphdr, struct rmnet_map_ul_checksum_header_s *ul_header,
struct sk_buff *skb)
{
struct ipv6hdr *ip6h = (struct ipv6hdr *)iphdr;
unsigned short *hdr = (unsigned short *)ul_header;
ul_header->checksum_start_offset = htons((unsigned short)
(skb_transport_header(skb) - (unsigned char *)iphdr));
ul_header->checksum_insert_offset = skb->csum_offset;
ul_header->cks_en = 1;
ul_header->udp_ip4_ind = 0;
if (ip6h->nexthdr == IPPROTO_UDP)
ul_header->udp_ind = 1;
else
ul_header->udp_ind = 0;
/* Changing checksum_insert_offset to network order */
hdr++;
*hdr = htons(*hdr);
@ -747,7 +752,7 @@ sw_checksum:
ul_header->checksum_start_offset = 0;
ul_header->checksum_insert_offset = 0;
ul_header->cks_en = 0;
ul_header->udp_ip4_ind = 0;
ul_header->udp_ind = 0;
done:
return ret;
}