mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
53e5039896
The send_check logic was only interesting in cases of TCP offload and UDP UFO where the checksum needed to be initialized to the pseudo header checksum. Now we've moved that logic into the related gso_segment functions so gso_send_check is no longer needed. Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
79 lines
2.0 KiB
C
79 lines
2.0 KiB
C
/*
|
|
* IPV6 GSO/GRO offload support
|
|
* Linux INET6 implementation
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*
|
|
* TCPv6 GSO/GRO support
|
|
*/
|
|
#include <linux/skbuff.h>
|
|
#include <net/protocol.h>
|
|
#include <net/tcp.h>
|
|
#include <net/ip6_checksum.h>
|
|
#include "ip6_offload.h"
|
|
|
|
static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
|
|
struct sk_buff *skb)
|
|
{
|
|
/* Don't bother verifying checksum if we're going to flush anyway. */
|
|
if (!NAPI_GRO_CB(skb)->flush &&
|
|
skb_gro_checksum_validate(skb, IPPROTO_TCP,
|
|
ip6_gro_compute_pseudo)) {
|
|
NAPI_GRO_CB(skb)->flush = 1;
|
|
return NULL;
|
|
}
|
|
|
|
return tcp_gro_receive(head, skb);
|
|
}
|
|
|
|
static int tcp6_gro_complete(struct sk_buff *skb, int thoff)
|
|
{
|
|
const struct ipv6hdr *iph = ipv6_hdr(skb);
|
|
struct tcphdr *th = tcp_hdr(skb);
|
|
|
|
th->check = ~tcp_v6_check(skb->len - thoff, &iph->saddr,
|
|
&iph->daddr, 0);
|
|
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6;
|
|
|
|
return tcp_gro_complete(skb);
|
|
}
|
|
|
|
struct sk_buff *tcp6_gso_segment(struct sk_buff *skb,
|
|
netdev_features_t features)
|
|
{
|
|
struct tcphdr *th;
|
|
|
|
if (!pskb_may_pull(skb, sizeof(*th)))
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
|
|
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
|
|
struct tcphdr *th = tcp_hdr(skb);
|
|
|
|
/* Set up pseudo header, usually expect stack to have done
|
|
* this.
|
|
*/
|
|
|
|
th->check = 0;
|
|
skb->ip_summed = CHECKSUM_PARTIAL;
|
|
__tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
|
|
}
|
|
|
|
return tcp_gso_segment(skb, features);
|
|
}
|
|
static const struct net_offload tcpv6_offload = {
|
|
.callbacks = {
|
|
.gso_segment = tcp6_gso_segment,
|
|
.gro_receive = tcp6_gro_receive,
|
|
.gro_complete = tcp6_gro_complete,
|
|
},
|
|
};
|
|
|
|
int __init tcpv6_offload_init(void)
|
|
{
|
|
return inet6_add_offload(&tcpv6_offload, IPPROTO_TCP);
|
|
}
|