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:
parent
131f3d3a15
commit
d77a69adc1
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue