net: rmnet_data: Add support for MAPv4 data format

Add the MAPv4 ingress and data format handlers. MAPv4 requires the
checksum for uplink TCP and UDP packets to be 1's complemented
before passing the packet onto the physical netdevice.

This workaround is needed due to failures seen in hardware while
processing translated packets.

Change-Id: Ib79382fa7e8b2bd0c1adbe68b8de75f1602df10b
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
This commit is contained in:
Subash Abhinov Kasiviswanathan 2015-09-02 14:44:08 -06:00 committed by Gerrit - the friendly Code Review server
parent 131f3d3a15
commit d77a69adc1
4 changed files with 55 additions and 9 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2015, 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
@ -24,6 +24,7 @@
#define RMNET_EGRESS_FORMAT_AGGREGATION (1<<2)
#define RMNET_EGRESS_FORMAT_MUXING (1<<3)
#define RMNET_EGRESS_FORMAT_MAP_CKSUMV3 (1<<4)
#define RMNET_EGRESS_FORMAT_MAP_CKSUMV4 (1<<5)
#define RMNET_INGRESS_FIX_ETHERNET (1<<0)
#define RMNET_INGRESS_FORMAT_MAP (1<<1)
@ -31,6 +32,7 @@
#define RMNET_INGRESS_FORMAT_DEMUXING (1<<3)
#define RMNET_INGRESS_FORMAT_MAP_COMMANDS (1<<4)
#define RMNET_INGRESS_FORMAT_MAP_CKSUMV3 (1<<5)
#define RMNET_INGRESS_FORMAT_MAP_CKSUMV4 (1<<6)
/* ***************** Netlink API ******************************************** */
#define RMNET_NETLINK_PROTO 31

View File

@ -312,7 +312,8 @@ static rx_handler_result_t _rmnet_map_ingress_handler(struct sk_buff *skb,
if (config->ingress_data_format & RMNET_INGRESS_FORMAT_DEMUXING)
skb->dev = ep->egress_dev;
if (config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV3) {
if ((config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV3) ||
(config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV4)) {
ckresult = rmnet_map_checksum_downlink_packet(skb);
trace_rmnet_map_checksum_downlink_packet(skb, ckresult);
rmnet_stats_dl_checksum(ckresult);
@ -401,7 +402,8 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
additional_header_length = 0;
required_headroom = sizeof(struct rmnet_map_header_s);
if (config->egress_data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV3) {
if ((config->egress_data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV3) ||
(config->egress_data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV4)) {
required_headroom +=
sizeof(struct rmnet_map_ul_checksum_header_s);
additional_header_length +=
@ -418,8 +420,10 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
}
}
if (config->egress_data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV3) {
ckresult = rmnet_map_checksum_uplink_packet(skb, orig_dev);
if ((config->egress_data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV3) ||
(config->egress_data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV4)) {
ckresult = rmnet_map_checksum_uplink_packet
(skb, orig_dev, config->egress_data_format);
trace_rmnet_map_checksum_uplink_packet(orig_dev, ckresult);
rmnet_stats_ul_checksum(ckresult);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2015, 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
@ -145,6 +145,6 @@ void rmnet_map_aggregate(struct sk_buff *skb,
int rmnet_map_checksum_downlink_packet(struct sk_buff *skb);
int rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
struct net_device *orig_dev);
struct net_device *orig_dev, uint32_t egress_data_format);
#endif /* _RMNET_MAP_H_ */

View File

@ -133,7 +133,8 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
maph = (struct rmnet_map_header_s *) skb->data;
packet_len = ntohs(maph->pkt_len) + sizeof(struct rmnet_map_header_s);
if (config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV3)
if ((config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV3) ||
(config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV4))
packet_len += sizeof(struct rmnet_map_dl_checksum_trailer_s);
if ((((int)skb->len) - ((int)packet_len)) < 0) {
@ -655,6 +656,37 @@ static void rmnet_map_fill_ipv6_packet_ul_checksum_header(void *iphdr,
skb->ip_summed = CHECKSUM_NONE;
}
static void rmnet_map_complement_ipv4_txporthdr_csum_field(void *iphdr)
{
struct iphdr *ip4h = (struct iphdr *)iphdr;
void *txporthdr;
uint16_t *csum;
txporthdr = iphdr + ip4h->ihl*4;
if ((ip4h->protocol == IPPROTO_TCP) ||
(ip4h->protocol == IPPROTO_UDP)) {
csum = (uint16_t *)rmnet_map_get_checksum_field(ip4h->protocol,
txporthdr);
*csum = ~(*csum);
}
}
static void rmnet_map_complement_ipv6_txporthdr_csum_field(void *ip6hdr)
{
struct ipv6hdr *ip6h = (struct ipv6hdr *)ip6hdr;
void *txporthdr;
uint16_t *csum;
txporthdr = ip6hdr + sizeof(struct ipv6hdr);
if ((ip6h->nexthdr == IPPROTO_TCP) || (ip6h->nexthdr == IPPROTO_UDP)) {
csum = (uint16_t *)rmnet_map_get_checksum_field(ip6h->nexthdr,
txporthdr);
*csum = ~(*csum);
}
}
/**
* rmnet_map_checksum_uplink_packet() - Generates UL checksum
* meta info header
@ -669,7 +701,7 @@ static void rmnet_map_fill_ipv6_packet_ul_checksum_header(void *iphdr,
* - RMNET_MAP_CHECKSUM_SW: Unsupported packet for UL checksum offload.
*/
int rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
struct net_device *orig_dev)
struct net_device *orig_dev, uint32_t egress_data_format)
{
unsigned char ip_version;
struct rmnet_map_ul_checksum_header_s *ul_header;
@ -692,10 +724,18 @@ int rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
if (ip_version == 0x04) {
rmnet_map_fill_ipv4_packet_ul_checksum_header(iphdr,
ul_header, skb);
if (egress_data_format &
RMNET_EGRESS_FORMAT_MAP_CKSUMV4)
rmnet_map_complement_ipv4_txporthdr_csum_field(
iphdr);
return RMNET_MAP_CHECKSUM_OK;
} else if (ip_version == 0x06) {
rmnet_map_fill_ipv6_packet_ul_checksum_header(iphdr,
ul_header, skb);
if (egress_data_format &
RMNET_EGRESS_FORMAT_MAP_CKSUMV4)
rmnet_map_complement_ipv6_txporthdr_csum_field(
iphdr);
return RMNET_MAP_CHECKSUM_OK;
} else {
ret = RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION;