diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 64 |
1 files changed, 39 insertions, 25 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 075f540ec197..6603511e3673 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; |
@@ -350,6 +353,11 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
350 | if (sk->sk_state == TCP_CLOSE) | 353 | if (sk->sk_state == TCP_CLOSE) |
351 | goto out; | 354 | goto out; |
352 | 355 | ||
356 | if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) { | ||
357 | NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP); | ||
358 | goto out; | ||
359 | } | ||
360 | |||
353 | tp = tcp_sk(sk); | 361 | tp = tcp_sk(sk); |
354 | seq = ntohl(th->seq); | 362 | seq = ntohl(th->seq); |
355 | if (sk->sk_state != TCP_LISTEN && | 363 | if (sk->sk_state != TCP_LISTEN && |
@@ -503,14 +511,10 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
503 | 511 | ||
504 | skb = tcp_make_synack(sk, dst, req, rvp); | 512 | skb = tcp_make_synack(sk, dst, req, rvp); |
505 | if (skb) { | 513 | if (skb) { |
506 | struct tcphdr *th = tcp_hdr(skb); | 514 | __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 | 515 | ||
512 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | 516 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); |
513 | err = ip6_xmit(sk, skb, &fl, opt, 0); | 517 | err = ip6_xmit(sk, skb, &fl, opt); |
514 | err = net_xmit_eval(err); | 518 | err = net_xmit_eval(err); |
515 | } | 519 | } |
516 | 520 | ||
@@ -918,22 +922,29 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = { | |||
918 | .twsk_destructor= tcp_twsk_destructor, | 922 | .twsk_destructor= tcp_twsk_destructor, |
919 | }; | 923 | }; |
920 | 924 | ||
921 | static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | 925 | static void __tcp_v6_send_check(struct sk_buff *skb, |
926 | struct in6_addr *saddr, struct in6_addr *daddr) | ||
922 | { | 927 | { |
923 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
924 | struct tcphdr *th = tcp_hdr(skb); | 928 | struct tcphdr *th = tcp_hdr(skb); |
925 | 929 | ||
926 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 930 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
927 | th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); | 931 | th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0); |
928 | skb->csum_start = skb_transport_header(skb) - skb->head; | 932 | skb->csum_start = skb_transport_header(skb) - skb->head; |
929 | skb->csum_offset = offsetof(struct tcphdr, check); | 933 | skb->csum_offset = offsetof(struct tcphdr, check); |
930 | } else { | 934 | } else { |
931 | th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, | 935 | th->check = tcp_v6_check(skb->len, saddr, daddr, |
932 | csum_partial(th, th->doff<<2, | 936 | csum_partial(th, th->doff << 2, |
933 | skb->csum)); | 937 | skb->csum)); |
934 | } | 938 | } |
935 | } | 939 | } |
936 | 940 | ||
941 | static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb) | ||
942 | { | ||
943 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
944 | |||
945 | __tcp_v6_send_check(skb, &np->saddr, &np->daddr); | ||
946 | } | ||
947 | |||
937 | static int tcp_v6_gso_send_check(struct sk_buff *skb) | 948 | static int tcp_v6_gso_send_check(struct sk_buff *skb) |
938 | { | 949 | { |
939 | struct ipv6hdr *ipv6h; | 950 | struct ipv6hdr *ipv6h; |
@@ -946,11 +957,8 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) | |||
946 | th = tcp_hdr(skb); | 957 | th = tcp_hdr(skb); |
947 | 958 | ||
948 | th->check = 0; | 959 | 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; | 960 | skb->ip_summed = CHECKSUM_PARTIAL; |
961 | __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); | ||
954 | return 0; | 962 | return 0; |
955 | } | 963 | } |
956 | 964 | ||
@@ -1047,15 +1055,14 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
1047 | } | 1055 | } |
1048 | #endif | 1056 | #endif |
1049 | 1057 | ||
1050 | buff->csum = csum_partial(t1, tot_len, 0); | ||
1051 | |||
1052 | memset(&fl, 0, sizeof(fl)); | 1058 | memset(&fl, 0, sizeof(fl)); |
1053 | ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); | 1059 | ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); |
1054 | ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr); | 1060 | ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr); |
1055 | 1061 | ||
1056 | t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst, | 1062 | buff->ip_summed = CHECKSUM_PARTIAL; |
1057 | tot_len, IPPROTO_TCP, | 1063 | buff->csum = 0; |
1058 | buff->csum); | 1064 | |
1065 | __tcp_v6_send_check(buff, &fl.fl6_src, &fl.fl6_dst); | ||
1059 | 1066 | ||
1060 | fl.proto = IPPROTO_TCP; | 1067 | fl.proto = IPPROTO_TCP; |
1061 | fl.oif = inet6_iif(skb); | 1068 | fl.oif = inet6_iif(skb); |
@@ -1070,7 +1077,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
1070 | if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { | 1077 | if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { |
1071 | if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { | 1078 | if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { |
1072 | skb_dst_set(buff, dst); | 1079 | skb_dst_set(buff, dst); |
1073 | ip6_xmit(ctl_sk, buff, &fl, NULL, 0); | 1080 | ip6_xmit(ctl_sk, buff, &fl, NULL); |
1074 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); | 1081 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); |
1075 | if (rst) | 1082 | if (rst) |
1076 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); | 1083 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); |
@@ -1233,12 +1240,12 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1233 | goto drop_and_free; | 1240 | goto drop_and_free; |
1234 | 1241 | ||
1235 | /* Secret recipe starts with IP addresses */ | 1242 | /* Secret recipe starts with IP addresses */ |
1236 | d = &ipv6_hdr(skb)->daddr.s6_addr32[0]; | 1243 | d = (__force u32 *)&ipv6_hdr(skb)->daddr.s6_addr32[0]; |
1237 | *mess++ ^= *d++; | 1244 | *mess++ ^= *d++; |
1238 | *mess++ ^= *d++; | 1245 | *mess++ ^= *d++; |
1239 | *mess++ ^= *d++; | 1246 | *mess++ ^= *d++; |
1240 | *mess++ ^= *d++; | 1247 | *mess++ ^= *d++; |
1241 | d = &ipv6_hdr(skb)->saddr.s6_addr32[0]; | 1248 | d = (__force u32 *)&ipv6_hdr(skb)->saddr.s6_addr32[0]; |
1242 | *mess++ ^= *d++; | 1249 | *mess++ ^= *d++; |
1243 | *mess++ ^= *d++; | 1250 | *mess++ ^= *d++; |
1244 | *mess++ ^= *d++; | 1251 | *mess++ ^= *d++; |
@@ -1676,6 +1683,7 @@ ipv6_pktoptions: | |||
1676 | static int tcp_v6_rcv(struct sk_buff *skb) | 1683 | static int tcp_v6_rcv(struct sk_buff *skb) |
1677 | { | 1684 | { |
1678 | struct tcphdr *th; | 1685 | struct tcphdr *th; |
1686 | struct ipv6hdr *hdr; | ||
1679 | struct sock *sk; | 1687 | struct sock *sk; |
1680 | int ret; | 1688 | int ret; |
1681 | struct net *net = dev_net(skb->dev); | 1689 | struct net *net = dev_net(skb->dev); |
@@ -1702,12 +1710,13 @@ static int tcp_v6_rcv(struct sk_buff *skb) | |||
1702 | goto bad_packet; | 1710 | goto bad_packet; |
1703 | 1711 | ||
1704 | th = tcp_hdr(skb); | 1712 | th = tcp_hdr(skb); |
1713 | hdr = ipv6_hdr(skb); | ||
1705 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); | 1714 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); |
1706 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + | 1715 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + |
1707 | skb->len - th->doff*4); | 1716 | skb->len - th->doff*4); |
1708 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); | 1717 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); |
1709 | TCP_SKB_CB(skb)->when = 0; | 1718 | TCP_SKB_CB(skb)->when = 0; |
1710 | TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb)); | 1719 | TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(hdr); |
1711 | TCP_SKB_CB(skb)->sacked = 0; | 1720 | TCP_SKB_CB(skb)->sacked = 0; |
1712 | 1721 | ||
1713 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); | 1722 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); |
@@ -1718,6 +1727,11 @@ process: | |||
1718 | if (sk->sk_state == TCP_TIME_WAIT) | 1727 | if (sk->sk_state == TCP_TIME_WAIT) |
1719 | goto do_time_wait; | 1728 | goto do_time_wait; |
1720 | 1729 | ||
1730 | if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) { | ||
1731 | NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP); | ||
1732 | goto discard_and_relse; | ||
1733 | } | ||
1734 | |||
1721 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1735 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
1722 | goto discard_and_relse; | 1736 | goto discard_and_relse; |
1723 | 1737 | ||