diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c66b90f71c9b..acd32e3f1b68 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -94,6 +94,18 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, | |||
94 | } | 94 | } |
95 | #endif | 95 | #endif |
96 | 96 | ||
97 | static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) | ||
98 | { | ||
99 | struct dst_entry *dst = skb_dst(skb); | ||
100 | const struct rt6_info *rt = (const struct rt6_info *)dst; | ||
101 | |||
102 | dst_hold(dst); | ||
103 | sk->sk_rx_dst = dst; | ||
104 | inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; | ||
105 | if (rt->rt6i_node) | ||
106 | inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum; | ||
107 | } | ||
108 | |||
97 | static void tcp_v6_hash(struct sock *sk) | 109 | static void tcp_v6_hash(struct sock *sk) |
98 | { | 110 | { |
99 | if (sk->sk_state != TCP_CLOSE) { | 111 | if (sk->sk_state != TCP_CLOSE) { |
@@ -391,8 +403,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
391 | tp->mtu_info = ntohl(info); | 403 | tp->mtu_info = ntohl(info); |
392 | if (!sock_owned_by_user(sk)) | 404 | if (!sock_owned_by_user(sk)) |
393 | tcp_v6_mtu_reduced(sk); | 405 | tcp_v6_mtu_reduced(sk); |
394 | else | 406 | else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, |
395 | set_bit(TCP_MTU_REDUCED_DEFERRED, &tp->tsq_flags); | 407 | &tp->tsq_flags)) |
408 | sock_hold(sk); | ||
396 | goto out; | 409 | goto out; |
397 | } | 410 | } |
398 | 411 | ||
@@ -1270,6 +1283,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1270 | 1283 | ||
1271 | newsk->sk_gso_type = SKB_GSO_TCPV6; | 1284 | newsk->sk_gso_type = SKB_GSO_TCPV6; |
1272 | __ip6_dst_store(newsk, dst, NULL, NULL); | 1285 | __ip6_dst_store(newsk, dst, NULL, NULL); |
1286 | inet6_sk_rx_dst_set(newsk, skb); | ||
1273 | 1287 | ||
1274 | newtcp6sk = (struct tcp6_sock *)newsk; | 1288 | newtcp6sk = (struct tcp6_sock *)newsk; |
1275 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; | 1289 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; |
@@ -1447,7 +1461,17 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1447 | opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC)); | 1461 | opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC)); |
1448 | 1462 | ||
1449 | if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ | 1463 | if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ |
1464 | struct dst_entry *dst = sk->sk_rx_dst; | ||
1465 | |||
1450 | sock_rps_save_rxhash(sk, skb); | 1466 | sock_rps_save_rxhash(sk, skb); |
1467 | if (dst) { | ||
1468 | if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif || | ||
1469 | dst->ops->check(dst, np->rx_dst_cookie) == NULL) { | ||
1470 | dst_release(dst); | ||
1471 | sk->sk_rx_dst = NULL; | ||
1472 | } | ||
1473 | } | ||
1474 | |||
1451 | if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) | 1475 | if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) |
1452 | goto reset; | 1476 | goto reset; |
1453 | if (opt_skb) | 1477 | if (opt_skb) |
@@ -1705,9 +1729,9 @@ static void tcp_v6_early_demux(struct sk_buff *skb) | |||
1705 | struct dst_entry *dst = sk->sk_rx_dst; | 1729 | struct dst_entry *dst = sk->sk_rx_dst; |
1706 | struct inet_sock *icsk = inet_sk(sk); | 1730 | struct inet_sock *icsk = inet_sk(sk); |
1707 | if (dst) | 1731 | if (dst) |
1708 | dst = dst_check(dst, 0); | 1732 | dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); |
1709 | if (dst && | 1733 | if (dst && |
1710 | icsk->rx_dst_ifindex == inet6_iif(skb)) | 1734 | icsk->rx_dst_ifindex == skb->skb_iif) |
1711 | skb_dst_set_noref(skb, dst); | 1735 | skb_dst_set_noref(skb, dst); |
1712 | } | 1736 | } |
1713 | } | 1737 | } |
@@ -1723,6 +1747,7 @@ static const struct inet_connection_sock_af_ops ipv6_specific = { | |||
1723 | .queue_xmit = inet6_csk_xmit, | 1747 | .queue_xmit = inet6_csk_xmit, |
1724 | .send_check = tcp_v6_send_check, | 1748 | .send_check = tcp_v6_send_check, |
1725 | .rebuild_header = inet6_sk_rebuild_header, | 1749 | .rebuild_header = inet6_sk_rebuild_header, |
1750 | .sk_rx_dst_set = inet6_sk_rx_dst_set, | ||
1726 | .conn_request = tcp_v6_conn_request, | 1751 | .conn_request = tcp_v6_conn_request, |
1727 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1752 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1728 | .net_header_len = sizeof(struct ipv6hdr), | 1753 | .net_header_len = sizeof(struct ipv6hdr), |
@@ -1754,6 +1779,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = { | |||
1754 | .queue_xmit = ip_queue_xmit, | 1779 | .queue_xmit = ip_queue_xmit, |
1755 | .send_check = tcp_v4_send_check, | 1780 | .send_check = tcp_v4_send_check, |
1756 | .rebuild_header = inet_sk_rebuild_header, | 1781 | .rebuild_header = inet_sk_rebuild_header, |
1782 | .sk_rx_dst_set = inet_sk_rx_dst_set, | ||
1757 | .conn_request = tcp_v6_conn_request, | 1783 | .conn_request = tcp_v6_conn_request, |
1758 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1784 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1759 | .net_header_len = sizeof(struct iphdr), | 1785 | .net_header_len = sizeof(struct iphdr), |