diff mbox series

[2/3] net:ethernet:rmnet:Support for downlink MAPv5 csum offload

Message ID 1613079324-20166-3-git-send-email-sharathv@codeaurora.org
State New
Headers show
Series net:qualcomm:rmnet:Enable Mapv5. | expand

Commit Message

Sharath Chandra Vurukala Feb. 11, 2021, 9:35 p.m. UTC
Adding support for processing of Mapv5 downlink packets.
It involves parsing the Mapv5 packet and checking the csum header
to know whether the hardware has validated the checksum and is
valid or not.

Based on the checksum valid bit the corresponding stats are
incremented and skb->ip_summed is marked either CHECKSUM_UNNECESSARY
or left as CHEKSUM_NONE to let network stack revalidated the checksum
and update the respective snmp stats.

Signed-off-by: Sharath Chandra Vurukala <sharathv@codeaurora.org>
---
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h |  3 +-
 .../net/ethernet/qualcomm/rmnet/rmnet_handlers.c   | 19 ++++++----
 drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h    | 32 +++++++++++++++-
 .../net/ethernet/qualcomm/rmnet/rmnet_map_data.c   | 44 +++++++++++++++++++++-
 include/linux/if_rmnet.h                           | 17 +++++++--
 include/uapi/linux/if_link.h                       |  1 +
 6 files changed, 102 insertions(+), 14 deletions(-)

Comments

Jakub Kicinski Feb. 12, 2021, 2:04 a.m. UTC | #1
On Fri, 12 Feb 2021 03:05:23 +0530 Sharath Chandra Vurukala wrote:
> +/* MAP CSUM headers */

> +struct rmnet_map_v5_csum_header {

> +	u8  next_hdr:1;

> +	u8  header_type:7;

> +	u8  hw_reserved:5;

> +	u8  priority:1;

> +	u8  hw_reserved_bit:1;

> +	u8  csum_valid_required:1;

> +	__be16 reserved;

> +} __aligned(1);


Will this work on big endian?
kernel test robot Feb. 12, 2021, 4:53 a.m. UTC | #2
Hi Sharath,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on ipvs/master]
[also build test ERROR on linus/master sparc-next/master v5.11-rc7 next-20210211]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Sharath-Chandra-Vurukala/docs-networking-Add-documentation-for-MAP-v5/20210212-063547
base:   https://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs.git master
config: arm64-allyesconfig (attached as .config)
compiler: aarch64-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/293142d706c02bf2e6ce7acb4e04ebb6cf4a2a63
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Sharath-Chandra-Vurukala/docs-networking-Add-documentation-for-MAP-v5/20210212-063547
        git checkout 293142d706c02bf2e6ce7acb4e04ebb6cf4a2a63
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

Note: the linux-review/Sharath-Chandra-Vurukala/docs-networking-Add-documentation-for-MAP-v5/20210212-063547 HEAD 7f0a1e35c1d1c17de5873aded88d5dadfedce2fb builds fine.
      It only hurts bisectibility.

All errors (new ones prefixed by >>):

   drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c: In function 'rmnet_map_egress_handler':
>> drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c:153:15: error: too few arguments to function 'rmnet_map_add_map_header'

     153 |  map_header = rmnet_map_add_map_header(skb, additional_header_len, 0);
         |               ^~~~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c:14:
   drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h:66:26: note: declared here
      66 | struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~
   At top level:
   drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h:76:11: warning: 'rmnet_map_get_next_hdr_type' defined but not used [-Wunused-function]
      76 | static u8 rmnet_map_get_next_hdr_type(struct sk_buff *skb)
         |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~
--
>> drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c:270:26: error: conflicting types for 'rmnet_map_add_map_header'

     270 | struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c:12:
   drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h:66:26: note: previous declaration of 'rmnet_map_add_map_header' was here
      66 | struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~


vim +/rmnet_map_add_map_header +153 drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c

ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  129  
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  130  static int rmnet_map_egress_handler(struct sk_buff *skb,
56470c927f1ba1 Subash Abhinov Kasiviswanathan 2017-10-11  131  				    struct rmnet_port *port, u8 mux_id,
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  132  				    struct net_device *orig_dev)
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  133  {
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  134  	int required_headroom, additional_header_len;
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  135  	struct rmnet_map_header *map_header;
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  136  
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  137  	additional_header_len = 0;
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  138  	required_headroom = sizeof(struct rmnet_map_header);
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  139  
14452ca3b5ce30 Subash Abhinov Kasiviswanathan 2018-03-21  140  	if (port->data_format & RMNET_FLAGS_EGRESS_MAP_CKSUMV4) {
5eb5f8608ef118 Subash Abhinov Kasiviswanathan 2018-01-07  141  		additional_header_len = sizeof(struct rmnet_map_ul_csum_header);
5eb5f8608ef118 Subash Abhinov Kasiviswanathan 2018-01-07  142  		required_headroom += additional_header_len;
5eb5f8608ef118 Subash Abhinov Kasiviswanathan 2018-01-07  143  	}
5eb5f8608ef118 Subash Abhinov Kasiviswanathan 2018-01-07  144  
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  145  	if (skb_headroom(skb) < required_headroom) {
6392ff3c8e4c23 Subash Abhinov Kasiviswanathan 2018-10-02  146  		if (pskb_expand_head(skb, required_headroom, 0, GFP_ATOMIC))
1eece799d3f611 Subash Abhinov Kasiviswanathan 2018-05-15  147  			return -ENOMEM;
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  148  	}
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  149  
14452ca3b5ce30 Subash Abhinov Kasiviswanathan 2018-03-21  150  	if (port->data_format & RMNET_FLAGS_EGRESS_MAP_CKSUMV4)
5eb5f8608ef118 Subash Abhinov Kasiviswanathan 2018-01-07  151  		rmnet_map_checksum_uplink_packet(skb, orig_dev);
5eb5f8608ef118 Subash Abhinov Kasiviswanathan 2018-01-07  152  
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29 @153  	map_header = rmnet_map_add_map_header(skb, additional_header_len, 0);
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  154  	if (!map_header)
1eece799d3f611 Subash Abhinov Kasiviswanathan 2018-05-15  155  		return -ENOMEM;
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  156  
56470c927f1ba1 Subash Abhinov Kasiviswanathan 2017-10-11  157  	map_header->mux_id = mux_id;
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  158  
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  159  	skb->protocol = htons(ETH_P_MAP);
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  160  
cf2fe57b0cc220 Subash Abhinov Kasiviswanathan 2017-12-11  161  	return 0;
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  162  }
ceed73a2cf4aff Subash Abhinov Kasiviswanathan 2017-08-29  163  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Alex Elder Feb. 12, 2021, 2:01 p.m. UTC | #3
On 2/11/21 8:04 PM, Jakub Kicinski wrote:
> On Fri, 12 Feb 2021 03:05:23 +0530 Sharath Chandra Vurukala wrote:

>> +/* MAP CSUM headers */

>> +struct rmnet_map_v5_csum_header {

>> +	u8  next_hdr:1;

>> +	u8  header_type:7;

>> +	u8  hw_reserved:5;

>> +	u8  priority:1;

>> +	u8  hw_reserved_bit:1;

>> +	u8  csum_valid_required:1;

>> +	__be16 reserved;

>> +} __aligned(1);

> 

> Will this work on big endian?


Sort of related to this point...

I'm sure the response to this will be to add two versions
of the definition, surrounded __LITTLE_ENDIAN_BITFIELD
and __BIG_ENDIAN_BITFIELD tests.

I really find this non-intuitive, and every time I
look at it I have to think about it a bit to figure
out where the bits actually lie in the word.

I know this pattern is used elsewhere in the networking
code, but that doesn't make it any easier for me to
understand...

Can we used mask, defined in host byte order, to
specify the positions of these fields?

I proposed a change at one time that did this and
this *_ENDIAN_BITFIELD thing was used instead.

I will gladly implement this change (completely
separate from what's being done here), but thought
it might be best to see what people think about it
before doing that work.

					-Alex
Subash Abhinov Kasiviswanathan Feb. 12, 2021, 5:49 p.m. UTC | #4
On 2021-02-12 07:01, Alex Elder wrote:
> On 2/11/21 8:04 PM, Jakub Kicinski wrote:

>> On Fri, 12 Feb 2021 03:05:23 +0530 Sharath Chandra Vurukala wrote:

>>> +/* MAP CSUM headers */

>>> +struct rmnet_map_v5_csum_header {

>>> +	u8  next_hdr:1;

>>> +	u8  header_type:7;

>>> +	u8  hw_reserved:5;

>>> +	u8  priority:1;

>>> +	u8  hw_reserved_bit:1;

>>> +	u8  csum_valid_required:1;

>>> +	__be16 reserved;

>>> +} __aligned(1);

>> 

>> Will this work on big endian?

> 

> Sort of related to this point...

> 

> I'm sure the response to this will be to add two versions

> of the definition, surrounded __LITTLE_ENDIAN_BITFIELD

> and __BIG_ENDIAN_BITFIELD tests.

> 

> I really find this non-intuitive, and every time I

> look at it I have to think about it a bit to figure

> out where the bits actually lie in the word.

> 

> I know this pattern is used elsewhere in the networking

> code, but that doesn't make it any easier for me to

> understand...

> 

> Can we used mask, defined in host byte order, to

> specify the positions of these fields?

> 

> I proposed a change at one time that did this and

> this *_ENDIAN_BITFIELD thing was used instead.

> 

> I will gladly implement this change (completely

> separate from what's being done here), but thought

> it might be best to see what people think about it

> before doing that work.

> 

> 					-Alex


Our preference is to stick with __LITTLE_ENDIAN_BITFIELD
& __BIG_ENDIAN_BITFIELD definitions similar to other
networking definitions.
Jakub Kicinski Feb. 12, 2021, 6:51 p.m. UTC | #5
On Fri, 12 Feb 2021 08:01:15 -0600 Alex Elder wrote:
> On 2/11/21 8:04 PM, Jakub Kicinski wrote:

> > On Fri, 12 Feb 2021 03:05:23 +0530 Sharath Chandra Vurukala wrote:  

> >> +/* MAP CSUM headers */

> >> +struct rmnet_map_v5_csum_header {

> >> +	u8  next_hdr:1;

> >> +	u8  header_type:7;

> >> +	u8  hw_reserved:5;

> >> +	u8  priority:1;

> >> +	u8  hw_reserved_bit:1;

> >> +	u8  csum_valid_required:1;

> >> +	__be16 reserved;

> >> +} __aligned(1);  

> > 

> > Will this work on big endian?  

> 

> Sort of related to this point...

> 

> I'm sure the response to this will be to add two versions

> of the definition, surrounded __LITTLE_ENDIAN_BITFIELD

> and __BIG_ENDIAN_BITFIELD tests.

> 

> I really find this non-intuitive, and every time I

> look at it I have to think about it a bit to figure

> out where the bits actually lie in the word.

> 

> I know this pattern is used elsewhere in the networking

> code, but that doesn't make it any easier for me to

> understand...

> 

> Can we used mask, defined in host byte order, to

> specify the positions of these fields?

> 

> I proposed a change at one time that did this and

> this *_ENDIAN_BITFIELD thing was used instead.

> 

> I will gladly implement this change (completely

> separate from what's being done here), but thought

> it might be best to see what people think about it

> before doing that work.


Most definitely agree, please convert.
Alex Elder Feb. 12, 2021, 7:06 p.m. UTC | #6
On 2/12/21 12:51 PM, Jakub Kicinski wrote:
> On Fri, 12 Feb 2021 08:01:15 -0600 Alex Elder wrote:

>> On 2/11/21 8:04 PM, Jakub Kicinski wrote:

>>> On Fri, 12 Feb 2021 03:05:23 +0530 Sharath Chandra Vurukala wrote:

>>>> +/* MAP CSUM headers */

>>>> +struct rmnet_map_v5_csum_header {

>>>> +	u8  next_hdr:1;

>>>> +	u8  header_type:7;

>>>> +	u8  hw_reserved:5;

>>>> +	u8  priority:1;

>>>> +	u8  hw_reserved_bit:1;

>>>> +	u8  csum_valid_required:1;

>>>> +	__be16 reserved;

>>>> +} __aligned(1);

>>>

>>> Will this work on big endian?

>>

>> Sort of related to this point...

>>

>> I'm sure the response to this will be to add two versions

>> of the definition, surrounded __LITTLE_ENDIAN_BITFIELD

>> and __BIG_ENDIAN_BITFIELD tests.

>>

>> I really find this non-intuitive, and every time I

>> look at it I have to think about it a bit to figure

>> out where the bits actually lie in the word.

>>

>> I know this pattern is used elsewhere in the networking

>> code, but that doesn't make it any easier for me to

>> understand...

>>

>> Can we used mask, defined in host byte order, to

>> specify the positions of these fields?

>>

>> I proposed a change at one time that did this and

>> this *_ENDIAN_BITFIELD thing was used instead.

>>

>> I will gladly implement this change (completely

>> separate from what's being done here), but thought

>> it might be best to see what people think about it

>> before doing that work.

> 

> Most definitely agree, please convert.


KS, would you like me to do this to the existing code
first?

I don't think it will take me very long.  If it were
a priority I could probably get it done by the end of
today, but I'd want to ensure the result worked for
the testing you do.

					-Alex
Subash Abhinov Kasiviswanathan Feb. 12, 2021, 8:11 p.m. UTC | #7
On 2021-02-12 12:06, Alex Elder wrote:
> On 2/12/21 12:51 PM, Jakub Kicinski wrote:

>> On Fri, 12 Feb 2021 08:01:15 -0600 Alex Elder wrote:

>>> On 2/11/21 8:04 PM, Jakub Kicinski wrote:

>>>> On Fri, 12 Feb 2021 03:05:23 +0530 Sharath Chandra Vurukala wrote:

>>>>> +/* MAP CSUM headers */

>>>>> +struct rmnet_map_v5_csum_header {

>>>>> +	u8  next_hdr:1;

>>>>> +	u8  header_type:7;

>>>>> +	u8  hw_reserved:5;

>>>>> +	u8  priority:1;

>>>>> +	u8  hw_reserved_bit:1;

>>>>> +	u8  csum_valid_required:1;

>>>>> +	__be16 reserved;

>>>>> +} __aligned(1);

>>>> 

>>>> Will this work on big endian?

>>> 

>>> Sort of related to this point...

>>> 

>>> I'm sure the response to this will be to add two versions

>>> of the definition, surrounded __LITTLE_ENDIAN_BITFIELD

>>> and __BIG_ENDIAN_BITFIELD tests.

>>> 

>>> I really find this non-intuitive, and every time I

>>> look at it I have to think about it a bit to figure

>>> out where the bits actually lie in the word.

>>> 

>>> I know this pattern is used elsewhere in the networking

>>> code, but that doesn't make it any easier for me to

>>> understand...

>>> 

>>> Can we used mask, defined in host byte order, to

>>> specify the positions of these fields?

>>> 

>>> I proposed a change at one time that did this and

>>> this *_ENDIAN_BITFIELD thing was used instead.

>>> 

>>> I will gladly implement this change (completely

>>> separate from what's being done here), but thought

>>> it might be best to see what people think about it

>>> before doing that work.

>> 

>> Most definitely agree, please convert.

> 

> KS, would you like me to do this to the existing code

> first?

> 

> I don't think it will take me very long.  If it were

> a priority I could probably get it done by the end of

> today, but I'd want to ensure the result worked for

> the testing you do.

> 

> 					-Alex


Sorry, I am not convinced that it is helping
to improve anything. It just adds a big
overhead of testing everything again without any
apparent improvement of performance or readablity
of code.
diff mbox series

Patch

diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
index 8d8d469..d4d61471 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -1,5 +1,6 @@ 
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2013-2014, 2016-2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2018 The Linux Foundation.
+ * All rights reserved.
  *
  * RMNET Data configuration engine
  */
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
index 3d7d3ab..70ad6a7 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -1,5 +1,5 @@ 
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 2021, The Linux Foundation. All rights reserved.
  *
  * RMNET Data ingress/egress handler
  */
@@ -57,8 +57,8 @@  __rmnet_map_ingress_handler(struct sk_buff *skb,
 			    struct rmnet_port *port)
 {
 	struct rmnet_endpoint *ep;
+	u8 mux_id, next_hdr;
 	u16 len, pad;
-	u8 mux_id;
 
 	if (RMNET_MAP_GET_CD_BIT(skb)) {
 		if (port->data_format & RMNET_FLAGS_INGRESS_MAP_COMMANDS)
@@ -70,6 +70,7 @@  __rmnet_map_ingress_handler(struct sk_buff *skb,
 	mux_id = RMNET_MAP_GET_MUX_ID(skb);
 	pad = RMNET_MAP_GET_PAD(skb);
 	len = RMNET_MAP_GET_LENGTH(skb) - pad;
+	next_hdr = RMNET_MAP_GET_NH_BIT(skb);
 
 	if (mux_id >= RMNET_MAX_LOGICAL_EP)
 		goto free_skb;
@@ -80,15 +81,19 @@  __rmnet_map_ingress_handler(struct sk_buff *skb,
 
 	skb->dev = ep->egress_dev;
 
-	/* Subtract MAP header */
-	skb_pull(skb, sizeof(struct rmnet_map_header));
-	rmnet_set_skb_proto(skb);
-
-	if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) {
+	if (next_hdr &&
+	    (port->data_format & (RMNET_FLAGS_INGRESS_MAP_CKSUMV5))) {
+		if (rmnet_map_process_next_hdr_packet(skb, len))
+			goto free_skb;
+	} else if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) {
 		if (!rmnet_map_checksum_downlink_packet(skb, len + pad))
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
 
+	/* Subtract MAP header */
+	skb_pull(skb, sizeof(struct rmnet_map_header));
+	rmnet_set_skb_proto(skb);
+
 	skb_trim(skb, len);
 	rmnet_deliver_skb(skb);
 	return;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
index 576501d..55d293c 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
@@ -1,5 +1,5 @@ 
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _RMNET_MAP_H_
@@ -23,6 +23,12 @@  struct rmnet_map_control_command {
 	};
 }  __aligned(1);
 
+enum rmnet_map_v5_header_type {
+	RMNET_MAP_HEADER_TYPE_UNKNOWN,
+	RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD = 0x2,
+	RMNET_MAP_HEADER_TYPE_ENUM_LENGTH
+};
+
 enum rmnet_map_commands {
 	RMNET_MAP_COMMAND_NONE,
 	RMNET_MAP_COMMAND_FLOW_DISABLE,
@@ -44,6 +50,9 @@  enum rmnet_map_commands {
 #define RMNET_MAP_GET_LENGTH(Y) (ntohs(((struct rmnet_map_header *) \
 					(Y)->data)->pkt_len))
 
+#define RMNET_MAP_GET_NH_BIT(Y)  (((struct rmnet_map_header *) \
+				    (Y)->data)->next_hdr)
+
 #define RMNET_MAP_COMMAND_REQUEST     0
 #define RMNET_MAP_COMMAND_ACK         1
 #define RMNET_MAP_COMMAND_UNSUPPORTED 2
@@ -55,10 +64,29 @@  enum rmnet_map_commands {
 struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
 				      struct rmnet_port *port);
 struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb,
-						  int hdrlen, int pad);
+						  int hdrlen,
+						  struct rmnet_port *port,
+						  int pad);
 void rmnet_map_command(struct sk_buff *skb, struct rmnet_port *port);
 int rmnet_map_checksum_downlink_packet(struct sk_buff *skb, u16 len);
 void rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
 				      struct net_device *orig_dev);
+int rmnet_map_process_next_hdr_packet(struct sk_buff *skb, u16 len);
+
+static u8 rmnet_map_get_next_hdr_type(struct sk_buff *skb)
+{
+	unsigned char *data = skb->data;
+
+	data += sizeof(struct rmnet_map_header);
+	return ((struct rmnet_map_v5_csum_header *)data)->header_type;
+}
+
+static inline bool rmnet_map_get_csum_valid(struct sk_buff *skb)
+{
+	unsigned char *data = skb->data;
+
+	data += sizeof(struct rmnet_map_header);
+	return ((struct rmnet_map_v5_csum_header *)data)->csum_valid_required;
+}
 
 #endif /* _RMNET_MAP_H_ */
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
index 21d3816..3d7e03f 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
@@ -1,5 +1,5 @@ 
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 2021, The Linux Foundation. All rights reserved.
  *
  * RMNET Data MAP protocol
  */
@@ -311,6 +311,7 @@  struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb,
 struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
 				      struct rmnet_port *port)
 {
+	unsigned char *data = skb->data, *next_hdr = NULL;
 	struct rmnet_map_header *maph;
 	struct sk_buff *skbn;
 	u32 packet_len;
@@ -323,6 +324,12 @@  struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
 
 	if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4)
 		packet_len += sizeof(struct rmnet_map_dl_csum_trailer);
+	else if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV5) {
+		if (!maph->cd_bit) {
+			packet_len += sizeof(struct rmnet_map_v5_csum_header);
+			next_hdr = data + sizeof(*maph);
+		}
+	}
 
 	if (((int)skb->len - (int)packet_len) < 0)
 		return NULL;
@@ -331,6 +338,11 @@  struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
 	if (ntohs(maph->pkt_len) == 0)
 		return NULL;
 
+	if (next_hdr &&
+	    ((struct rmnet_map_v5_csum_header *)next_hdr)->header_type !=
+	     RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD)
+		return NULL;
+
 	skbn = alloc_skb(packet_len + RMNET_MAP_DEAGGR_SPACING, GFP_ATOMIC);
 	if (!skbn)
 		return NULL;
@@ -428,3 +440,33 @@  void rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
 
 	priv->stats.csum_sw++;
 }
+
+/* Process a MAPv5 packet header */
+int rmnet_map_process_next_hdr_packet(struct sk_buff *skb,
+				      u16 len)
+{
+	struct rmnet_priv *priv = netdev_priv(skb->dev);
+	int rc = 0;
+
+	switch (rmnet_map_get_next_hdr_type(skb)) {
+	case RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD:
+		if (unlikely(!(skb->dev->features & NETIF_F_RXCSUM))) {
+			priv->stats.csum_sw++;
+		} else if (rmnet_map_get_csum_valid(skb)) {
+			priv->stats.csum_ok++;
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		} else {
+			priv->stats.csum_valid_unset++;
+		}
+
+		/* Pull csum v5 header */
+		skb_pull(skb, sizeof(struct rmnet_map_v5_csum_header));
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
diff --git a/include/linux/if_rmnet.h b/include/linux/if_rmnet.h
index 9661416..81acd0b 100644
--- a/include/linux/if_rmnet.h
+++ b/include/linux/if_rmnet.h
@@ -1,5 +1,5 @@ 
 /* SPDX-License-Identifier: GPL-2.0-only
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019, 2021 The Linux Foundation. All rights reserved.
  */
 
 #ifndef _LINUX_IF_RMNET_H_
@@ -8,11 +8,11 @@ 
 struct rmnet_map_header {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
 	u8  pad_len:6;
-	u8  reserved_bit:1;
+	u8  next_hdr:1;
 	u8  cd_bit:1;
 #elif defined (__BIG_ENDIAN_BITFIELD)
 	u8  cd_bit:1;
-	u8  reserved_bit:1;
+	u8  next_hdr:1;
 	u8  pad_len:6;
 #else
 #error	"Please fix <asm/byteorder.h>"
@@ -52,4 +52,15 @@  struct rmnet_map_ul_csum_header {
 #endif
 } __aligned(1);
 
+/* MAP CSUM headers */
+struct rmnet_map_v5_csum_header {
+	u8  next_hdr:1;
+	u8  header_type:7;
+	u8  hw_reserved:5;
+	u8  priority:1;
+	u8  hw_reserved_bit:1;
+	u8  csum_valid_required:1;
+	__be16 reserved;
+} __aligned(1);
+
 #endif /* !(_LINUX_IF_RMNET_H_) */
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 82708c6..838bd29 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -1233,6 +1233,7 @@  enum {
 #define RMNET_FLAGS_INGRESS_MAP_COMMANDS          (1U << 1)
 #define RMNET_FLAGS_INGRESS_MAP_CKSUMV4           (1U << 2)
 #define RMNET_FLAGS_EGRESS_MAP_CKSUMV4            (1U << 3)
+#define RMNET_FLAGS_INGRESS_MAP_CKSUMV5           (1U << 4)
 
 enum {
 	IFLA_RMNET_UNSPEC,