diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 147 |
1 files changed, 81 insertions, 66 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index febfd595a40d..fe6d40418c0b 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/jhash.h> | 38 | #include <linux/jhash.h> |
| 39 | #include <linux/ipsec.h> | 39 | #include <linux/ipsec.h> |
| 40 | #include <linux/times.h> | 40 | #include <linux/times.h> |
| 41 | #include <linux/slab.h> | ||
| 41 | 42 | ||
| 42 | #include <linux/ipv6.h> | 43 | #include <linux/ipv6.h> |
| 43 | #include <linux/icmpv6.h> | 44 | #include <linux/icmpv6.h> |
| @@ -74,6 +75,9 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | |||
| 74 | struct request_sock *req); | 75 | struct request_sock *req); |
| 75 | 76 | ||
| 76 | 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); | ||
| 77 | 81 | ||
| 78 | static const struct inet_connection_sock_af_ops ipv6_mapped; | 82 | static const struct inet_connection_sock_af_ops ipv6_mapped; |
| 79 | static const struct inet_connection_sock_af_ops ipv6_specific; | 83 | static const struct inet_connection_sock_af_ops ipv6_specific; |
| @@ -125,7 +129,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 125 | struct inet_connection_sock *icsk = inet_csk(sk); | 129 | struct inet_connection_sock *icsk = inet_csk(sk); |
| 126 | struct ipv6_pinfo *np = inet6_sk(sk); | 130 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 127 | struct tcp_sock *tp = tcp_sk(sk); | 131 | struct tcp_sock *tp = tcp_sk(sk); |
| 128 | struct in6_addr *saddr = NULL, *final_p = NULL, final; | 132 | struct in6_addr *saddr = NULL, *final_p, final; |
| 129 | struct flowi fl; | 133 | struct flowi fl; |
| 130 | struct dst_entry *dst; | 134 | struct dst_entry *dst; |
| 131 | int addr_type; | 135 | int addr_type; |
| @@ -246,12 +250,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 246 | fl.fl_ip_dport = usin->sin6_port; | 250 | fl.fl_ip_dport = usin->sin6_port; |
| 247 | fl.fl_ip_sport = inet->inet_sport; | 251 | fl.fl_ip_sport = inet->inet_sport; |
| 248 | 252 | ||
| 249 | if (np->opt && np->opt->srcrt) { | 253 | final_p = fl6_update_dst(&fl, np->opt, &final); |
| 250 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | ||
| 251 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 252 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 253 | final_p = &final; | ||
| 254 | } | ||
| 255 | 254 | ||
| 256 | security_sk_classify_flow(sk, &fl); | 255 | security_sk_classify_flow(sk, &fl); |
| 257 | 256 | ||
| @@ -349,6 +348,11 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 349 | if (sk->sk_state == TCP_CLOSE) | 348 | if (sk->sk_state == TCP_CLOSE) |
| 350 | goto out; | 349 | goto out; |
| 351 | 350 | ||
| 351 | if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) { | ||
| 352 | NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP); | ||
| 353 | goto out; | ||
| 354 | } | ||
| 355 | |||
| 352 | tp = tcp_sk(sk); | 356 | tp = tcp_sk(sk); |
| 353 | seq = ntohl(th->seq); | 357 | seq = ntohl(th->seq); |
| 354 | if (sk->sk_state != TCP_LISTEN && | 358 | if (sk->sk_state != TCP_LISTEN && |
| @@ -468,7 +472,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
| 468 | struct ipv6_pinfo *np = inet6_sk(sk); | 472 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 469 | struct sk_buff * skb; | 473 | struct sk_buff * skb; |
| 470 | struct ipv6_txoptions *opt = NULL; | 474 | struct ipv6_txoptions *opt = NULL; |
| 471 | struct in6_addr * final_p = NULL, final; | 475 | struct in6_addr * final_p, final; |
| 472 | struct flowi fl; | 476 | struct flowi fl; |
| 473 | struct dst_entry *dst; | 477 | struct dst_entry *dst; |
| 474 | int err = -1; | 478 | int err = -1; |
| @@ -485,12 +489,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
| 485 | security_req_classify_flow(req, &fl); | 489 | security_req_classify_flow(req, &fl); |
| 486 | 490 | ||
| 487 | opt = np->opt; | 491 | opt = np->opt; |
| 488 | if (opt && opt->srcrt) { | 492 | final_p = fl6_update_dst(&fl, opt, &final); |
| 489 | struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; | ||
| 490 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 491 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 492 | final_p = &final; | ||
| 493 | } | ||
| 494 | 493 | ||
| 495 | err = ip6_dst_lookup(sk, &dst, &fl); | 494 | err = ip6_dst_lookup(sk, &dst, &fl); |
| 496 | if (err) | 495 | if (err) |
| @@ -502,14 +501,10 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
| 502 | 501 | ||
| 503 | skb = tcp_make_synack(sk, dst, req, rvp); | 502 | skb = tcp_make_synack(sk, dst, req, rvp); |
| 504 | if (skb) { | 503 | if (skb) { |
| 505 | struct tcphdr *th = tcp_hdr(skb); | 504 | __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); |
| 506 | |||
| 507 | th->check = tcp_v6_check(skb->len, | ||
| 508 | &treq->loc_addr, &treq->rmt_addr, | ||
| 509 | csum_partial(th, skb->len, skb->csum)); | ||
| 510 | 505 | ||
| 511 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | 506 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); |
| 512 | err = ip6_xmit(sk, skb, &fl, opt, 0); | 507 | err = ip6_xmit(sk, skb, &fl, opt); |
| 513 | err = net_xmit_eval(err); | 508 | err = net_xmit_eval(err); |
| 514 | } | 509 | } |
| 515 | 510 | ||
| @@ -520,6 +515,13 @@ done: | |||
| 520 | return err; | 515 | return err; |
| 521 | } | 516 | } |
| 522 | 517 | ||
| 518 | static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req, | ||
| 519 | struct request_values *rvp) | ||
| 520 | { | ||
| 521 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | ||
| 522 | return tcp_v6_send_synack(sk, req, rvp); | ||
| 523 | } | ||
| 524 | |||
| 523 | static inline void syn_flood_warning(struct sk_buff *skb) | 525 | static inline void syn_flood_warning(struct sk_buff *skb) |
| 524 | { | 526 | { |
| 525 | #ifdef CONFIG_SYN_COOKIES | 527 | #ifdef CONFIG_SYN_COOKIES |
| @@ -592,7 +594,7 @@ static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer, | |||
| 592 | kfree(newkey); | 594 | kfree(newkey); |
| 593 | return -ENOMEM; | 595 | return -ENOMEM; |
| 594 | } | 596 | } |
| 595 | sk->sk_route_caps &= ~NETIF_F_GSO_MASK; | 597 | sk_nocaps_add(sk, NETIF_F_GSO_MASK); |
| 596 | } | 598 | } |
| 597 | if (tcp_alloc_md5sig_pool(sk) == NULL) { | 599 | if (tcp_alloc_md5sig_pool(sk) == NULL) { |
| 598 | kfree(newkey); | 600 | kfree(newkey); |
| @@ -729,7 +731,7 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, | |||
| 729 | return -ENOMEM; | 731 | return -ENOMEM; |
| 730 | 732 | ||
| 731 | tp->md5sig_info = p; | 733 | tp->md5sig_info = p; |
| 732 | sk->sk_route_caps &= ~NETIF_F_GSO_MASK; | 734 | sk_nocaps_add(sk, NETIF_F_GSO_MASK); |
| 733 | } | 735 | } |
| 734 | 736 | ||
| 735 | newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); | 737 | newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); |
| @@ -876,7 +878,7 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
| 876 | 878 | ||
| 877 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | 879 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { |
| 878 | if (net_ratelimit()) { | 880 | if (net_ratelimit()) { |
| 879 | printk(KERN_INFO "MD5 Hash %s for (%pI6, %u)->(%pI6, %u)\n", | 881 | printk(KERN_INFO "MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n", |
| 880 | genhash ? "failed" : "mismatch", | 882 | genhash ? "failed" : "mismatch", |
| 881 | &ip6h->saddr, ntohs(th->source), | 883 | &ip6h->saddr, ntohs(th->source), |
| 882 | &ip6h->daddr, ntohs(th->dest)); | 884 | &ip6h->daddr, ntohs(th->dest)); |
| @@ -890,10 +892,11 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
| 890 | struct request_sock_ops tcp6_request_sock_ops __read_mostly = { | 892 | struct request_sock_ops tcp6_request_sock_ops __read_mostly = { |
| 891 | .family = AF_INET6, | 893 | .family = AF_INET6, |
| 892 | .obj_size = sizeof(struct tcp6_request_sock), | 894 | .obj_size = sizeof(struct tcp6_request_sock), |
| 893 | .rtx_syn_ack = tcp_v6_send_synack, | 895 | .rtx_syn_ack = tcp_v6_rtx_synack, |
| 894 | .send_ack = tcp_v6_reqsk_send_ack, | 896 | .send_ack = tcp_v6_reqsk_send_ack, |
| 895 | .destructor = tcp_v6_reqsk_destructor, | 897 | .destructor = tcp_v6_reqsk_destructor, |
| 896 | .send_reset = tcp_v6_send_reset | 898 | .send_reset = tcp_v6_send_reset, |
| 899 | .syn_ack_timeout = tcp_syn_ack_timeout, | ||
| 897 | }; | 900 | }; |
| 898 | 901 | ||
| 899 | #ifdef CONFIG_TCP_MD5SIG | 902 | #ifdef CONFIG_TCP_MD5SIG |
| @@ -909,22 +912,29 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = { | |||
| 909 | .twsk_destructor= tcp_twsk_destructor, | 912 | .twsk_destructor= tcp_twsk_destructor, |
| 910 | }; | 913 | }; |
| 911 | 914 | ||
| 912 | static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | 915 | static void __tcp_v6_send_check(struct sk_buff *skb, |
| 916 | struct in6_addr *saddr, struct in6_addr *daddr) | ||
| 913 | { | 917 | { |
| 914 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 915 | struct tcphdr *th = tcp_hdr(skb); | 918 | struct tcphdr *th = tcp_hdr(skb); |
| 916 | 919 | ||
| 917 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 920 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
| 918 | th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); | 921 | th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0); |
| 919 | skb->csum_start = skb_transport_header(skb) - skb->head; | 922 | skb->csum_start = skb_transport_header(skb) - skb->head; |
| 920 | skb->csum_offset = offsetof(struct tcphdr, check); | 923 | skb->csum_offset = offsetof(struct tcphdr, check); |
| 921 | } else { | 924 | } else { |
| 922 | th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, | 925 | th->check = tcp_v6_check(skb->len, saddr, daddr, |
| 923 | csum_partial(th, th->doff<<2, | 926 | csum_partial(th, th->doff << 2, |
| 924 | skb->csum)); | 927 | skb->csum)); |
| 925 | } | 928 | } |
| 926 | } | 929 | } |
| 927 | 930 | ||
| 931 | static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb) | ||
| 932 | { | ||
| 933 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 934 | |||
| 935 | __tcp_v6_send_check(skb, &np->saddr, &np->daddr); | ||
| 936 | } | ||
| 937 | |||
| 928 | static int tcp_v6_gso_send_check(struct sk_buff *skb) | 938 | static int tcp_v6_gso_send_check(struct sk_buff *skb) |
| 929 | { | 939 | { |
| 930 | struct ipv6hdr *ipv6h; | 940 | struct ipv6hdr *ipv6h; |
| @@ -937,11 +947,8 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) | |||
| 937 | th = tcp_hdr(skb); | 947 | th = tcp_hdr(skb); |
| 938 | 948 | ||
| 939 | th->check = 0; | 949 | th->check = 0; |
| 940 | th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, | ||
| 941 | IPPROTO_TCP, 0); | ||
| 942 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
| 943 | skb->csum_offset = offsetof(struct tcphdr, check); | ||
| 944 | skb->ip_summed = CHECKSUM_PARTIAL; | 950 | skb->ip_summed = CHECKSUM_PARTIAL; |
| 951 | __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); | ||
| 945 | return 0; | 952 | return 0; |
| 946 | } | 953 | } |
| 947 | 954 | ||
| @@ -1006,7 +1013,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
| 1006 | skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); | 1013 | skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); |
| 1007 | 1014 | ||
| 1008 | t1 = (struct tcphdr *) skb_push(buff, tot_len); | 1015 | t1 = (struct tcphdr *) skb_push(buff, tot_len); |
| 1009 | skb_reset_transport_header(skb); | 1016 | skb_reset_transport_header(buff); |
| 1010 | 1017 | ||
| 1011 | /* Swap the send and the receive. */ | 1018 | /* Swap the send and the receive. */ |
| 1012 | memset(t1, 0, sizeof(*t1)); | 1019 | memset(t1, 0, sizeof(*t1)); |
| @@ -1038,15 +1045,14 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
| 1038 | } | 1045 | } |
| 1039 | #endif | 1046 | #endif |
| 1040 | 1047 | ||
| 1041 | buff->csum = csum_partial(t1, tot_len, 0); | ||
| 1042 | |||
| 1043 | memset(&fl, 0, sizeof(fl)); | 1048 | memset(&fl, 0, sizeof(fl)); |
| 1044 | ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); | 1049 | ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); |
| 1045 | ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr); | 1050 | ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr); |
| 1046 | 1051 | ||
| 1047 | t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst, | 1052 | buff->ip_summed = CHECKSUM_PARTIAL; |
| 1048 | tot_len, IPPROTO_TCP, | 1053 | buff->csum = 0; |
| 1049 | buff->csum); | 1054 | |
| 1055 | __tcp_v6_send_check(buff, &fl.fl6_src, &fl.fl6_dst); | ||
| 1050 | 1056 | ||
| 1051 | fl.proto = IPPROTO_TCP; | 1057 | fl.proto = IPPROTO_TCP; |
| 1052 | fl.oif = inet6_iif(skb); | 1058 | fl.oif = inet6_iif(skb); |
| @@ -1061,7 +1067,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
| 1061 | if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { | 1067 | if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { |
| 1062 | if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { | 1068 | if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { |
| 1063 | skb_dst_set(buff, dst); | 1069 | skb_dst_set(buff, dst); |
| 1064 | ip6_xmit(ctl_sk, buff, &fl, NULL, 0); | 1070 | ip6_xmit(ctl_sk, buff, &fl, NULL); |
| 1065 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); | 1071 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); |
| 1066 | if (rst) | 1072 | if (rst) |
| 1067 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); | 1073 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); |
| @@ -1151,7 +1157,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | |||
| 1151 | } | 1157 | } |
| 1152 | 1158 | ||
| 1153 | #ifdef CONFIG_SYN_COOKIES | 1159 | #ifdef CONFIG_SYN_COOKIES |
| 1154 | if (!th->rst && !th->syn && th->ack) | 1160 | if (!th->syn) |
| 1155 | sk = cookie_v6_check(sk, skb); | 1161 | sk = cookie_v6_check(sk, skb); |
| 1156 | #endif | 1162 | #endif |
| 1157 | return sk; | 1163 | return sk; |
| @@ -1224,12 +1230,12 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1224 | goto drop_and_free; | 1230 | goto drop_and_free; |
| 1225 | 1231 | ||
| 1226 | /* Secret recipe starts with IP addresses */ | 1232 | /* Secret recipe starts with IP addresses */ |
| 1227 | d = &ipv6_hdr(skb)->daddr.s6_addr32[0]; | 1233 | d = (__force u32 *)&ipv6_hdr(skb)->daddr.s6_addr32[0]; |
| 1228 | *mess++ ^= *d++; | 1234 | *mess++ ^= *d++; |
| 1229 | *mess++ ^= *d++; | 1235 | *mess++ ^= *d++; |
| 1230 | *mess++ ^= *d++; | 1236 | *mess++ ^= *d++; |
| 1231 | *mess++ ^= *d++; | 1237 | *mess++ ^= *d++; |
| 1232 | d = &ipv6_hdr(skb)->saddr.s6_addr32[0]; | 1238 | d = (__force u32 *)&ipv6_hdr(skb)->saddr.s6_addr32[0]; |
| 1233 | *mess++ ^= *d++; | 1239 | *mess++ ^= *d++; |
| 1234 | *mess++ ^= *d++; | 1240 | *mess++ ^= *d++; |
| 1235 | *mess++ ^= *d++; | 1241 | *mess++ ^= *d++; |
| @@ -1263,13 +1269,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1263 | treq = inet6_rsk(req); | 1269 | treq = inet6_rsk(req); |
| 1264 | ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr); | 1270 | ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr); |
| 1265 | ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr); | 1271 | ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr); |
| 1266 | if (!want_cookie) | 1272 | if (!want_cookie || tmp_opt.tstamp_ok) |
| 1267 | TCP_ECN_create_request(req, tcp_hdr(skb)); | 1273 | TCP_ECN_create_request(req, tcp_hdr(skb)); |
| 1268 | 1274 | ||
| 1269 | if (want_cookie) { | 1275 | if (!isn) { |
| 1270 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); | ||
| 1271 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
| 1272 | } else if (!isn) { | ||
| 1273 | if (ipv6_opt_accepted(sk, skb) || | 1276 | if (ipv6_opt_accepted(sk, skb) || |
| 1274 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 1277 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
| 1275 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { | 1278 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { |
| @@ -1282,8 +1285,12 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1282 | if (!sk->sk_bound_dev_if && | 1285 | if (!sk->sk_bound_dev_if && |
| 1283 | ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) | 1286 | ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) |
| 1284 | treq->iif = inet6_iif(skb); | 1287 | treq->iif = inet6_iif(skb); |
| 1285 | 1288 | if (!want_cookie) { | |
| 1286 | isn = tcp_v6_init_sequence(skb); | 1289 | isn = tcp_v6_init_sequence(skb); |
| 1290 | } else { | ||
| 1291 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); | ||
| 1292 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
| 1293 | } | ||
| 1287 | } | 1294 | } |
| 1288 | tcp_rsk(req)->snt_isn = isn; | 1295 | tcp_rsk(req)->snt_isn = isn; |
| 1289 | 1296 | ||
| @@ -1376,18 +1383,13 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1376 | goto out_overflow; | 1383 | goto out_overflow; |
| 1377 | 1384 | ||
| 1378 | if (dst == NULL) { | 1385 | if (dst == NULL) { |
| 1379 | struct in6_addr *final_p = NULL, final; | 1386 | struct in6_addr *final_p, final; |
| 1380 | struct flowi fl; | 1387 | struct flowi fl; |
| 1381 | 1388 | ||
| 1382 | memset(&fl, 0, sizeof(fl)); | 1389 | memset(&fl, 0, sizeof(fl)); |
| 1383 | fl.proto = IPPROTO_TCP; | 1390 | fl.proto = IPPROTO_TCP; |
| 1384 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | 1391 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); |
| 1385 | if (opt && opt->srcrt) { | 1392 | final_p = fl6_update_dst(&fl, opt, &final); |
| 1386 | struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; | ||
| 1387 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 1388 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 1389 | final_p = &final; | ||
| 1390 | } | ||
| 1391 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); | 1393 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); |
| 1392 | fl.oif = sk->sk_bound_dev_if; | 1394 | fl.oif = sk->sk_bound_dev_if; |
| 1393 | fl.mark = sk->sk_mark; | 1395 | fl.mark = sk->sk_mark; |
| @@ -1667,6 +1669,7 @@ ipv6_pktoptions: | |||
| 1667 | static int tcp_v6_rcv(struct sk_buff *skb) | 1669 | static int tcp_v6_rcv(struct sk_buff *skb) |
| 1668 | { | 1670 | { |
| 1669 | struct tcphdr *th; | 1671 | struct tcphdr *th; |
| 1672 | struct ipv6hdr *hdr; | ||
| 1670 | struct sock *sk; | 1673 | struct sock *sk; |
| 1671 | int ret; | 1674 | int ret; |
| 1672 | struct net *net = dev_net(skb->dev); | 1675 | struct net *net = dev_net(skb->dev); |
| @@ -1693,12 +1696,13 @@ static int tcp_v6_rcv(struct sk_buff *skb) | |||
| 1693 | goto bad_packet; | 1696 | goto bad_packet; |
| 1694 | 1697 | ||
| 1695 | th = tcp_hdr(skb); | 1698 | th = tcp_hdr(skb); |
| 1699 | hdr = ipv6_hdr(skb); | ||
| 1696 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); | 1700 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); |
| 1697 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + | 1701 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + |
| 1698 | skb->len - th->doff*4); | 1702 | skb->len - th->doff*4); |
| 1699 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); | 1703 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); |
| 1700 | TCP_SKB_CB(skb)->when = 0; | 1704 | TCP_SKB_CB(skb)->when = 0; |
| 1701 | TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb)); | 1705 | TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(hdr); |
| 1702 | TCP_SKB_CB(skb)->sacked = 0; | 1706 | TCP_SKB_CB(skb)->sacked = 0; |
| 1703 | 1707 | ||
| 1704 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); | 1708 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); |
| @@ -1709,6 +1713,11 @@ process: | |||
| 1709 | if (sk->sk_state == TCP_TIME_WAIT) | 1713 | if (sk->sk_state == TCP_TIME_WAIT) |
| 1710 | goto do_time_wait; | 1714 | goto do_time_wait; |
| 1711 | 1715 | ||
| 1716 | if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) { | ||
| 1717 | NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP); | ||
| 1718 | goto discard_and_relse; | ||
| 1719 | } | ||
| 1720 | |||
| 1712 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1721 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
| 1713 | goto discard_and_relse; | 1722 | goto discard_and_relse; |
| 1714 | 1723 | ||
| @@ -1732,8 +1741,11 @@ process: | |||
| 1732 | if (!tcp_prequeue(sk, skb)) | 1741 | if (!tcp_prequeue(sk, skb)) |
| 1733 | ret = tcp_v6_do_rcv(sk, skb); | 1742 | ret = tcp_v6_do_rcv(sk, skb); |
| 1734 | } | 1743 | } |
| 1735 | } else | 1744 | } else if (unlikely(sk_add_backlog(sk, skb))) { |
| 1736 | sk_add_backlog(sk, skb); | 1745 | bh_unlock_sock(sk); |
| 1746 | NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP); | ||
| 1747 | goto discard_and_relse; | ||
| 1748 | } | ||
| 1737 | bh_unlock_sock(sk); | 1749 | bh_unlock_sock(sk); |
| 1738 | 1750 | ||
| 1739 | sock_put(sk); | 1751 | sock_put(sk); |
| @@ -2105,7 +2117,7 @@ static struct tcp_seq_afinfo tcp6_seq_afinfo = { | |||
| 2105 | }, | 2117 | }, |
| 2106 | }; | 2118 | }; |
| 2107 | 2119 | ||
| 2108 | int tcp6_proc_init(struct net *net) | 2120 | int __net_init tcp6_proc_init(struct net *net) |
| 2109 | { | 2121 | { |
| 2110 | return tcp_proc_register(net, &tcp6_seq_afinfo); | 2122 | return tcp_proc_register(net, &tcp6_seq_afinfo); |
| 2111 | } | 2123 | } |
| @@ -2130,6 +2142,8 @@ struct proto tcpv6_prot = { | |||
| 2130 | .setsockopt = tcp_setsockopt, | 2142 | .setsockopt = tcp_setsockopt, |
| 2131 | .getsockopt = tcp_getsockopt, | 2143 | .getsockopt = tcp_getsockopt, |
| 2132 | .recvmsg = tcp_recvmsg, | 2144 | .recvmsg = tcp_recvmsg, |
| 2145 | .sendmsg = tcp_sendmsg, | ||
| 2146 | .sendpage = tcp_sendpage, | ||
| 2133 | .backlog_rcv = tcp_v6_do_rcv, | 2147 | .backlog_rcv = tcp_v6_do_rcv, |
| 2134 | .hash = tcp_v6_hash, | 2148 | .hash = tcp_v6_hash, |
| 2135 | .unhash = inet_unhash, | 2149 | .unhash = inet_unhash, |
| @@ -2148,6 +2162,7 @@ struct proto tcpv6_prot = { | |||
| 2148 | .twsk_prot = &tcp6_timewait_sock_ops, | 2162 | .twsk_prot = &tcp6_timewait_sock_ops, |
| 2149 | .rsk_prot = &tcp6_request_sock_ops, | 2163 | .rsk_prot = &tcp6_request_sock_ops, |
| 2150 | .h.hashinfo = &tcp_hashinfo, | 2164 | .h.hashinfo = &tcp_hashinfo, |
| 2165 | .no_autobind = true, | ||
| 2151 | #ifdef CONFIG_COMPAT | 2166 | #ifdef CONFIG_COMPAT |
| 2152 | .compat_setsockopt = compat_tcp_setsockopt, | 2167 | .compat_setsockopt = compat_tcp_setsockopt, |
| 2153 | .compat_getsockopt = compat_tcp_getsockopt, | 2168 | .compat_getsockopt = compat_tcp_getsockopt, |
| @@ -2174,18 +2189,18 @@ static struct inet_protosw tcpv6_protosw = { | |||
| 2174 | INET_PROTOSW_ICSK, | 2189 | INET_PROTOSW_ICSK, |
| 2175 | }; | 2190 | }; |
| 2176 | 2191 | ||
| 2177 | static int tcpv6_net_init(struct net *net) | 2192 | static int __net_init tcpv6_net_init(struct net *net) |
| 2178 | { | 2193 | { |
| 2179 | return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, | 2194 | return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, |
| 2180 | SOCK_RAW, IPPROTO_TCP, net); | 2195 | SOCK_RAW, IPPROTO_TCP, net); |
| 2181 | } | 2196 | } |
| 2182 | 2197 | ||
| 2183 | static void tcpv6_net_exit(struct net *net) | 2198 | static void __net_exit tcpv6_net_exit(struct net *net) |
| 2184 | { | 2199 | { |
| 2185 | inet_ctl_sock_destroy(net->ipv6.tcp_sk); | 2200 | inet_ctl_sock_destroy(net->ipv6.tcp_sk); |
| 2186 | } | 2201 | } |
| 2187 | 2202 | ||
| 2188 | static void tcpv6_net_exit_batch(struct list_head *net_exit_list) | 2203 | static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list) |
| 2189 | { | 2204 | { |
| 2190 | inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6); | 2205 | inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6); |
| 2191 | } | 2206 | } |
