diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 55 |
1 files changed, 40 insertions, 15 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index a50eb306e9e2..3b6575478fcc 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -26,7 +26,6 @@ | |||
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <linux/config.h> | ||
| 30 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
| 31 | #include <linux/types.h> | 30 | #include <linux/types.h> |
| 32 | #include <linux/socket.h> | 31 | #include <linux/socket.h> |
| @@ -252,6 +251,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 252 | final_p = &final; | 251 | final_p = &final; |
| 253 | } | 252 | } |
| 254 | 253 | ||
| 254 | security_sk_classify_flow(sk, &fl); | ||
| 255 | |||
| 255 | err = ip6_dst_lookup(sk, &dst, &fl); | 256 | err = ip6_dst_lookup(sk, &dst, &fl); |
| 256 | if (err) | 257 | if (err) |
| 257 | goto failure; | 258 | goto failure; |
| @@ -270,9 +271,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 270 | ipv6_addr_copy(&np->saddr, saddr); | 271 | ipv6_addr_copy(&np->saddr, saddr); |
| 271 | inet->rcv_saddr = LOOPBACK4_IPV6; | 272 | inet->rcv_saddr = LOOPBACK4_IPV6; |
| 272 | 273 | ||
| 273 | ip6_dst_store(sk, dst, NULL); | 274 | sk->sk_gso_type = SKB_GSO_TCPV6; |
| 274 | sk->sk_route_caps = dst->dev->features & | 275 | __ip6_dst_store(sk, dst, NULL, NULL); |
| 275 | ~(NETIF_F_IP_CSUM | NETIF_F_TSO); | ||
| 276 | 276 | ||
| 277 | icsk->icsk_ext_hdr_len = 0; | 277 | icsk->icsk_ext_hdr_len = 0; |
| 278 | if (np->opt) | 278 | if (np->opt) |
| @@ -376,6 +376,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 376 | fl.oif = sk->sk_bound_dev_if; | 376 | fl.oif = sk->sk_bound_dev_if; |
| 377 | fl.fl_ip_dport = inet->dport; | 377 | fl.fl_ip_dport = inet->dport; |
| 378 | fl.fl_ip_sport = inet->sport; | 378 | fl.fl_ip_sport = inet->sport; |
| 379 | security_skb_classify_flow(skb, &fl); | ||
| 379 | 380 | ||
| 380 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { | 381 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { |
| 381 | sk->sk_err_soft = -err; | 382 | sk->sk_err_soft = -err; |
| @@ -429,7 +430,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 429 | case TCP_SYN_RECV: /* Cannot happen. | 430 | case TCP_SYN_RECV: /* Cannot happen. |
| 430 | It can, it SYNs are crossed. --ANK */ | 431 | It can, it SYNs are crossed. --ANK */ |
| 431 | if (!sock_owned_by_user(sk)) { | 432 | if (!sock_owned_by_user(sk)) { |
| 432 | TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); | ||
| 433 | sk->sk_err = err; | 433 | sk->sk_err = err; |
| 434 | sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ | 434 | sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ |
| 435 | 435 | ||
| @@ -470,6 +470,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
| 470 | fl.oif = treq->iif; | 470 | fl.oif = treq->iif; |
| 471 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 471 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
| 472 | fl.fl_ip_sport = inet_sk(sk)->sport; | 472 | fl.fl_ip_sport = inet_sk(sk)->sport; |
| 473 | security_req_classify_flow(req, &fl); | ||
| 473 | 474 | ||
| 474 | if (dst == NULL) { | 475 | if (dst == NULL) { |
| 475 | opt = np->opt; | 476 | opt = np->opt; |
| @@ -544,7 +545,7 @@ static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
| 544 | struct ipv6_pinfo *np = inet6_sk(sk); | 545 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 545 | struct tcphdr *th = skb->h.th; | 546 | struct tcphdr *th = skb->h.th; |
| 546 | 547 | ||
| 547 | if (skb->ip_summed == CHECKSUM_HW) { | 548 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
| 548 | th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); | 549 | th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); |
| 549 | skb->csum = offsetof(struct tcphdr, check); | 550 | skb->csum = offsetof(struct tcphdr, check); |
| 550 | } else { | 551 | } else { |
| @@ -554,6 +555,24 @@ static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
| 554 | } | 555 | } |
| 555 | } | 556 | } |
| 556 | 557 | ||
| 558 | static int tcp_v6_gso_send_check(struct sk_buff *skb) | ||
| 559 | { | ||
| 560 | struct ipv6hdr *ipv6h; | ||
| 561 | struct tcphdr *th; | ||
| 562 | |||
| 563 | if (!pskb_may_pull(skb, sizeof(*th))) | ||
| 564 | return -EINVAL; | ||
| 565 | |||
| 566 | ipv6h = skb->nh.ipv6h; | ||
| 567 | th = skb->h.th; | ||
| 568 | |||
| 569 | th->check = 0; | ||
| 570 | th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, | ||
| 571 | IPPROTO_TCP, 0); | ||
| 572 | skb->csum = offsetof(struct tcphdr, check); | ||
| 573 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
| 574 | return 0; | ||
| 575 | } | ||
| 557 | 576 | ||
| 558 | static void tcp_v6_send_reset(struct sk_buff *skb) | 577 | static void tcp_v6_send_reset(struct sk_buff *skb) |
| 559 | { | 578 | { |
| @@ -610,6 +629,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb) | |||
| 610 | fl.oif = inet6_iif(skb); | 629 | fl.oif = inet6_iif(skb); |
| 611 | fl.fl_ip_dport = t1->dest; | 630 | fl.fl_ip_dport = t1->dest; |
| 612 | fl.fl_ip_sport = t1->source; | 631 | fl.fl_ip_sport = t1->source; |
| 632 | security_skb_classify_flow(skb, &fl); | ||
| 613 | 633 | ||
| 614 | /* sk = NULL, but it is safe for now. RST socket required. */ | 634 | /* sk = NULL, but it is safe for now. RST socket required. */ |
| 615 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { | 635 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { |
| @@ -676,6 +696,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 | |||
| 676 | fl.oif = inet6_iif(skb); | 696 | fl.oif = inet6_iif(skb); |
| 677 | fl.fl_ip_dport = t1->dest; | 697 | fl.fl_ip_dport = t1->dest; |
| 678 | fl.fl_ip_sport = t1->source; | 698 | fl.fl_ip_sport = t1->source; |
| 699 | security_skb_classify_flow(skb, &fl); | ||
| 679 | 700 | ||
| 680 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { | 701 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { |
| 681 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { | 702 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { |
| @@ -805,6 +826,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 805 | 826 | ||
| 806 | tcp_rsk(req)->snt_isn = isn; | 827 | tcp_rsk(req)->snt_isn = isn; |
| 807 | 828 | ||
| 829 | security_inet_conn_request(sk, skb, req); | ||
| 830 | |||
| 808 | if (tcp_v6_send_synack(sk, req, NULL)) | 831 | if (tcp_v6_send_synack(sk, req, NULL)) |
| 809 | goto drop; | 832 | goto drop; |
| 810 | 833 | ||
| @@ -815,7 +838,6 @@ drop: | |||
| 815 | if (req) | 838 | if (req) |
| 816 | reqsk_free(req); | 839 | reqsk_free(req); |
| 817 | 840 | ||
| 818 | TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); | ||
| 819 | return 0; /* don't send reset */ | 841 | return 0; /* don't send reset */ |
| 820 | } | 842 | } |
| 821 | 843 | ||
| @@ -909,6 +931,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 909 | fl.oif = sk->sk_bound_dev_if; | 931 | fl.oif = sk->sk_bound_dev_if; |
| 910 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 932 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
| 911 | fl.fl_ip_sport = inet_sk(sk)->sport; | 933 | fl.fl_ip_sport = inet_sk(sk)->sport; |
| 934 | security_req_classify_flow(req, &fl); | ||
| 912 | 935 | ||
| 913 | if (ip6_dst_lookup(sk, &dst, &fl)) | 936 | if (ip6_dst_lookup(sk, &dst, &fl)) |
| 914 | goto out; | 937 | goto out; |
| @@ -930,9 +953,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 930 | * comment in that function for the gory details. -acme | 953 | * comment in that function for the gory details. -acme |
| 931 | */ | 954 | */ |
| 932 | 955 | ||
| 933 | ip6_dst_store(newsk, dst, NULL); | 956 | newsk->sk_gso_type = SKB_GSO_TCPV6; |
| 934 | newsk->sk_route_caps = dst->dev->features & | 957 | __ip6_dst_store(newsk, dst, NULL, NULL); |
| 935 | ~(NETIF_F_IP_CSUM | NETIF_F_TSO); | ||
| 936 | 958 | ||
| 937 | newtcp6sk = (struct tcp6_sock *)newsk; | 959 | newtcp6sk = (struct tcp6_sock *)newsk; |
| 938 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; | 960 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; |
| @@ -1011,7 +1033,7 @@ out: | |||
| 1011 | 1033 | ||
| 1012 | static int tcp_v6_checksum_init(struct sk_buff *skb) | 1034 | static int tcp_v6_checksum_init(struct sk_buff *skb) |
| 1013 | { | 1035 | { |
| 1014 | if (skb->ip_summed == CHECKSUM_HW) { | 1036 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
| 1015 | if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, | 1037 | if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, |
| 1016 | &skb->nh.ipv6h->daddr,skb->csum)) { | 1038 | &skb->nh.ipv6h->daddr,skb->csum)) { |
| 1017 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1039 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| @@ -1053,7 +1075,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
| 1053 | if (skb->protocol == htons(ETH_P_IP)) | 1075 | if (skb->protocol == htons(ETH_P_IP)) |
| 1054 | return tcp_v4_do_rcv(sk, skb); | 1076 | return tcp_v4_do_rcv(sk, skb); |
| 1055 | 1077 | ||
| 1056 | if (sk_filter(sk, skb, 0)) | 1078 | if (sk_filter(sk, skb)) |
| 1057 | goto discard; | 1079 | goto discard; |
| 1058 | 1080 | ||
| 1059 | /* | 1081 | /* |
| @@ -1210,12 +1232,12 @@ process: | |||
| 1210 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1232 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
| 1211 | goto discard_and_relse; | 1233 | goto discard_and_relse; |
| 1212 | 1234 | ||
| 1213 | if (sk_filter(sk, skb, 0)) | 1235 | if (sk_filter(sk, skb)) |
| 1214 | goto discard_and_relse; | 1236 | goto discard_and_relse; |
| 1215 | 1237 | ||
| 1216 | skb->dev = NULL; | 1238 | skb->dev = NULL; |
| 1217 | 1239 | ||
| 1218 | bh_lock_sock(sk); | 1240 | bh_lock_sock_nested(sk); |
| 1219 | ret = 0; | 1241 | ret = 0; |
| 1220 | if (!sock_owned_by_user(sk)) { | 1242 | if (!sock_owned_by_user(sk)) { |
| 1221 | #ifdef CONFIG_NET_DMA | 1243 | #ifdef CONFIG_NET_DMA |
| @@ -1469,7 +1491,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) | |||
| 1469 | dest->s6_addr32[0], dest->s6_addr32[1], | 1491 | dest->s6_addr32[0], dest->s6_addr32[1], |
| 1470 | dest->s6_addr32[2], dest->s6_addr32[3], destp, | 1492 | dest->s6_addr32[2], dest->s6_addr32[3], destp, |
| 1471 | sp->sk_state, | 1493 | sp->sk_state, |
| 1472 | tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq, | 1494 | tp->write_seq-tp->snd_una, |
| 1495 | (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq), | ||
| 1473 | timer_active, | 1496 | timer_active, |
| 1474 | jiffies_to_clock_t(timer_expires - jiffies), | 1497 | jiffies_to_clock_t(timer_expires - jiffies), |
| 1475 | icsk->icsk_retransmits, | 1498 | icsk->icsk_retransmits, |
| @@ -1605,6 +1628,8 @@ struct proto tcpv6_prot = { | |||
| 1605 | static struct inet6_protocol tcpv6_protocol = { | 1628 | static struct inet6_protocol tcpv6_protocol = { |
| 1606 | .handler = tcp_v6_rcv, | 1629 | .handler = tcp_v6_rcv, |
| 1607 | .err_handler = tcp_v6_err, | 1630 | .err_handler = tcp_v6_err, |
| 1631 | .gso_send_check = tcp_v6_gso_send_check, | ||
| 1632 | .gso_segment = tcp_tso_segment, | ||
| 1608 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | 1633 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, |
| 1609 | }; | 1634 | }; |
| 1610 | 1635 | ||
