diff options
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ac16795486ea..f3e52bc98980 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1672,6 +1672,7 @@ process: | |||
1672 | 1672 | ||
1673 | if (sk->sk_state == TCP_NEW_SYN_RECV) { | 1673 | if (sk->sk_state == TCP_NEW_SYN_RECV) { |
1674 | struct request_sock *req = inet_reqsk(sk); | 1674 | struct request_sock *req = inet_reqsk(sk); |
1675 | bool req_stolen = false; | ||
1675 | struct sock *nsk; | 1676 | struct sock *nsk; |
1676 | 1677 | ||
1677 | sk = req->rsk_listener; | 1678 | sk = req->rsk_listener; |
@@ -1694,10 +1695,20 @@ process: | |||
1694 | th = (const struct tcphdr *)skb->data; | 1695 | th = (const struct tcphdr *)skb->data; |
1695 | iph = ip_hdr(skb); | 1696 | iph = ip_hdr(skb); |
1696 | tcp_v4_fill_cb(skb, iph, th); | 1697 | tcp_v4_fill_cb(skb, iph, th); |
1697 | nsk = tcp_check_req(sk, skb, req, false); | 1698 | nsk = tcp_check_req(sk, skb, req, false, &req_stolen); |
1698 | } | 1699 | } |
1699 | if (!nsk) { | 1700 | if (!nsk) { |
1700 | reqsk_put(req); | 1701 | reqsk_put(req); |
1702 | if (req_stolen) { | ||
1703 | /* Another cpu got exclusive access to req | ||
1704 | * and created a full blown socket. | ||
1705 | * Try to feed this packet to this socket | ||
1706 | * instead of discarding it. | ||
1707 | */ | ||
1708 | tcp_v4_restore_cb(skb); | ||
1709 | sock_put(sk); | ||
1710 | goto lookup; | ||
1711 | } | ||
1701 | goto discard_and_relse; | 1712 | goto discard_and_relse; |
1702 | } | 1713 | } |
1703 | if (nsk == sk) { | 1714 | if (nsk == sk) { |