diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2010-04-10 22:15:54 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-11 18:29:08 -0400 |
commit | 8ad50d96db58c58ba67ec1c6f9d3dae0db52338a (patch) | |
tree | f5ebb8a02edcc15b9a8f534909fe908334e364a5 /net/ipv6 | |
parent | 419f9f896074ce8b21e88066e6f3515f18e5641c (diff) |
tcp: Handle CHECKSUM_PARTIAL for SYNACK packets for IPv6
tcp: Handle CHECKSUM_PARTIAL for SYNACK packets for IPv6
This patch moves the common code between tcp_v6_send_check and
tcp_v6_gso_send_check into a new function __tcp_v6_send_check.
It then uses the new function in tcp_v6_send_synack as well as
tcp_v6_send_response so that they handle CHECKSUM_PARTIAL properly.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Yinghai <yinghai.lu@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 37 |
1 files changed, 19 insertions, 18 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c92ebe8f80d5..f84c506c588a 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -75,6 +75,9 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | |||
75 | struct request_sock *req); | 75 | struct request_sock *req); |
76 | 76 | ||
77 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); | 77 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); |
78 | static void __tcp_v6_send_check(struct sk_buff *skb, | ||
79 | struct in6_addr *saddr, | ||
80 | struct in6_addr *daddr); | ||
78 | 81 | ||
79 | static const struct inet_connection_sock_af_ops ipv6_mapped; | 82 | static const struct inet_connection_sock_af_ops ipv6_mapped; |
80 | static const struct inet_connection_sock_af_ops ipv6_specific; | 83 | static const struct inet_connection_sock_af_ops ipv6_specific; |
@@ -503,11 +506,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
503 | 506 | ||
504 | skb = tcp_make_synack(sk, dst, req, rvp); | 507 | skb = tcp_make_synack(sk, dst, req, rvp); |
505 | if (skb) { | 508 | if (skb) { |
506 | struct tcphdr *th = tcp_hdr(skb); | 509 | __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); |
507 | |||
508 | th->check = tcp_v6_check(skb->len, | ||
509 | &treq->loc_addr, &treq->rmt_addr, | ||
510 | csum_partial(th, skb->len, skb->csum)); | ||
511 | 510 | ||
512 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | 511 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); |
513 | err = ip6_xmit(sk, skb, &fl, opt, 0); | 512 | err = ip6_xmit(sk, skb, &fl, opt, 0); |
@@ -918,22 +917,29 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = { | |||
918 | .twsk_destructor= tcp_twsk_destructor, | 917 | .twsk_destructor= tcp_twsk_destructor, |
919 | }; | 918 | }; |
920 | 919 | ||
921 | static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | 920 | static void __tcp_v6_send_check(struct sk_buff *skb, |
921 | struct in6_addr *saddr, struct in6_addr *daddr) | ||
922 | { | 922 | { |
923 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
924 | struct tcphdr *th = tcp_hdr(skb); | 923 | struct tcphdr *th = tcp_hdr(skb); |
925 | 924 | ||
926 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 925 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
927 | th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); | 926 | th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0); |
928 | skb->csum_start = skb_transport_header(skb) - skb->head; | 927 | skb->csum_start = skb_transport_header(skb) - skb->head; |
929 | skb->csum_offset = offsetof(struct tcphdr, check); | 928 | skb->csum_offset = offsetof(struct tcphdr, check); |
930 | } else { | 929 | } else { |
931 | th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, | 930 | th->check = tcp_v6_check(skb->len, saddr, daddr, |
932 | csum_partial(th, th->doff<<2, | 931 | csum_partial(th, th->doff << 2, |
933 | skb->csum)); | 932 | skb->csum)); |
934 | } | 933 | } |
935 | } | 934 | } |
936 | 935 | ||
936 | static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | ||
937 | { | ||
938 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
939 | |||
940 | __tcp_v6_send_check(skb, &np->saddr, &np->daddr); | ||
941 | } | ||
942 | |||
937 | static int tcp_v6_gso_send_check(struct sk_buff *skb) | 943 | static int tcp_v6_gso_send_check(struct sk_buff *skb) |
938 | { | 944 | { |
939 | struct ipv6hdr *ipv6h; | 945 | struct ipv6hdr *ipv6h; |
@@ -946,11 +952,8 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) | |||
946 | th = tcp_hdr(skb); | 952 | th = tcp_hdr(skb); |
947 | 953 | ||
948 | th->check = 0; | 954 | th->check = 0; |
949 | th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, | ||
950 | IPPROTO_TCP, 0); | ||
951 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
952 | skb->csum_offset = offsetof(struct tcphdr, check); | ||
953 | skb->ip_summed = CHECKSUM_PARTIAL; | 955 | skb->ip_summed = CHECKSUM_PARTIAL; |
956 | __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); | ||
954 | return 0; | 957 | return 0; |
955 | } | 958 | } |
956 | 959 | ||
@@ -1053,9 +1056,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
1053 | ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); | 1056 | ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); |
1054 | ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr); | 1057 | ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr); |
1055 | 1058 | ||
1056 | t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst, | 1059 | __tcp_v6_send_check(buff, &fl.fl6_src, &fl.fl6_dst); |
1057 | tot_len, IPPROTO_TCP, | ||
1058 | buff->csum); | ||
1059 | 1060 | ||
1060 | fl.proto = IPPROTO_TCP; | 1061 | fl.proto = IPPROTO_TCP; |
1061 | fl.oif = inet6_iif(skb); | 1062 | fl.oif = inet6_iif(skb); |