diff options
author | Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> | 2018-01-07 21:36:37 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-08 21:58:49 +0300 |
commit | bbd21b247cb596a426a1df0ad7658f141f558f86 (patch) | |
tree | 9aefd55eb3c584b12bd910bfc2a8f813206d01a7 /drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c | |
parent | c597897b08cb56e6a8b240245c074d43d1fde735 (diff) | |
download | linux-bbd21b247cb596a426a1df0ad7658f141f558f86.tar.xz |
net: qualcomm: rmnet: Add support for RX checksum offload
When using the MAPv4 packet format, receive checksum offload can be
enabled in hardware. The checksum computation over pseudo header is
not offloaded but the rest of the checksum computation over
the payload is offloaded. This applies only for TCP / UDP packets
which are not fragmented.
rmnet validates the TCP/UDP checksum for the packet using the checksum
from the checksum trailer added to the packet by hardware. The
validation performed is as following -
1. Perform 1's complement over the checksum value from the trailer
2. Compute 1's complement checksum over IPv4 / IPv6 header and
subtracts it from the value from step 1
3. Computes 1's complement checksum over IPv4 / IPv6 pseudo header and
adds it to the value from step 2
4. Subtracts the checksum value from the TCP / UDP header from the
value from step 3.
5. Compares the value from step 4 to the checksum value from the
TCP / UDP header.
6. If the comparison in step 5 succeeds, CHECKSUM_UNNECESSARY is set
and the packet is passed on to network stack. If there is a
failure, then the packet is passed on as such without modifying
the ip_summed field.
The checksum field is also checked for UDP checksum 0 as per RFC 768
and for unexpected TCP checksum of 0.
If checksum offload is disabled when using MAPv4 packet format in
receive path, the packet is queued as is to network stack without
the validations above.
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c')
-rw-r--r-- | drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c index 8f8c4f205166..340945857d23 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c @@ -66,8 +66,8 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, struct rmnet_port *port) { struct rmnet_endpoint *ep; + u16 len, pad; u8 mux_id; - u16 len; if (RMNET_MAP_GET_CD_BIT(skb)) { if (port->data_format & RMNET_INGRESS_FORMAT_MAP_COMMANDS) @@ -77,7 +77,8 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, } mux_id = RMNET_MAP_GET_MUX_ID(skb); - len = RMNET_MAP_GET_LENGTH(skb) - RMNET_MAP_GET_PAD(skb); + pad = RMNET_MAP_GET_PAD(skb); + len = RMNET_MAP_GET_LENGTH(skb) - pad; if (mux_id >= RMNET_MAX_LOGICAL_EP) goto free_skb; @@ -90,8 +91,14 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, /* Subtract MAP header */ skb_pull(skb, sizeof(struct rmnet_map_header)); - skb_trim(skb, len); rmnet_set_skb_proto(skb); + + if (port->data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV4) { + if (!rmnet_map_checksum_downlink_packet(skb, len + pad)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + + skb_trim(skb, len); rmnet_deliver_skb(skb); return; @@ -115,7 +122,7 @@ rmnet_map_ingress_handler(struct sk_buff *skb, } if (port->data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) { - while ((skbn = rmnet_map_deaggregate(skb)) != NULL) + while ((skbn = rmnet_map_deaggregate(skb, port)) != NULL) __rmnet_map_ingress_handler(skbn, port); consume_skb(skb); |