|
@@ -101,7 +101,7 @@ static void tcp_v6_hash(struct sock *sk)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static __inline__ __sum16 tcp_v6_check(struct tcphdr *th, int len,
|
|
|
+static __inline__ __sum16 tcp_v6_check(int len,
|
|
|
struct in6_addr *saddr,
|
|
|
struct in6_addr *daddr,
|
|
|
__wsum base)
|
|
@@ -501,7 +501,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
|
|
|
if (skb) {
|
|
|
struct tcphdr *th = tcp_hdr(skb);
|
|
|
|
|
|
- th->check = tcp_v6_check(th, skb->len,
|
|
|
+ th->check = tcp_v6_check(skb->len,
|
|
|
&treq->loc_addr, &treq->rmt_addr,
|
|
|
csum_partial(th, skb->len, skb->csum));
|
|
|
|
|
@@ -942,6 +942,41 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct ipv6hdr *iph = ipv6_hdr(skb);
|
|
|
+
|
|
|
+ switch (skb->ip_summed) {
|
|
|
+ case CHECKSUM_COMPLETE:
|
|
|
+ if (!tcp_v6_check(skb->len, &iph->saddr, &iph->daddr,
|
|
|
+ skb->csum)) {
|
|
|
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* fall through */
|
|
|
+ case CHECKSUM_NONE:
|
|
|
+ NAPI_GRO_CB(skb)->flush = 1;
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return tcp_gro_receive(head, skb);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(tcp6_gro_receive);
|
|
|
+
|
|
|
+int tcp6_gro_complete(struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct ipv6hdr *iph = ipv6_hdr(skb);
|
|
|
+ struct tcphdr *th = tcp_hdr(skb);
|
|
|
+
|
|
|
+ th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
|
|
|
+ &iph->saddr, &iph->daddr, 0);
|
|
|
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
|
|
|
+
|
|
|
+ return tcp_gro_complete(skb);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(tcp6_gro_complete);
|
|
|
+
|
|
|
static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
|
|
|
u32 ts, struct tcp_md5sig_key *key, int rst)
|
|
|
{
|
|
@@ -1429,14 +1464,14 @@ out:
|
|
|
static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
|
|
|
{
|
|
|
if (skb->ip_summed == CHECKSUM_COMPLETE) {
|
|
|
- if (!tcp_v6_check(tcp_hdr(skb), skb->len, &ipv6_hdr(skb)->saddr,
|
|
|
+ if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr,
|
|
|
&ipv6_hdr(skb)->daddr, skb->csum)) {
|
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- skb->csum = ~csum_unfold(tcp_v6_check(tcp_hdr(skb), skb->len,
|
|
|
+ skb->csum = ~csum_unfold(tcp_v6_check(skb->len,
|
|
|
&ipv6_hdr(skb)->saddr,
|
|
|
&ipv6_hdr(skb)->daddr, 0));
|
|
|
|
|
@@ -2062,6 +2097,8 @@ static struct inet6_protocol tcpv6_protocol = {
|
|
|
.err_handler = tcp_v6_err,
|
|
|
.gso_send_check = tcp_v6_gso_send_check,
|
|
|
.gso_segment = tcp_tso_segment,
|
|
|
+ .gro_receive = tcp6_gro_receive,
|
|
|
+ .gro_complete = tcp6_gro_complete,
|
|
|
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
|
|
|
};
|
|
|
|