|
@@ -877,7 +877,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,
|
|
|
|
|
|
err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr,
|
|
err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr,
|
|
ireq->ir_rmt_addr,
|
|
ireq->ir_rmt_addr,
|
|
- ireq->opt);
|
|
|
|
|
|
+ rcu_dereference(ireq->ireq_opt));
|
|
err = net_xmit_eval(err);
|
|
err = net_xmit_eval(err);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -889,7 +889,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,
|
|
*/
|
|
*/
|
|
static void tcp_v4_reqsk_destructor(struct request_sock *req)
|
|
static void tcp_v4_reqsk_destructor(struct request_sock *req)
|
|
{
|
|
{
|
|
- kfree(inet_rsk(req)->opt);
|
|
|
|
|
|
+ kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1));
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
@@ -1265,10 +1265,11 @@ static void tcp_v4_init_req(struct request_sock *req,
|
|
struct sk_buff *skb)
|
|
struct sk_buff *skb)
|
|
{
|
|
{
|
|
struct inet_request_sock *ireq = inet_rsk(req);
|
|
struct inet_request_sock *ireq = inet_rsk(req);
|
|
|
|
+ struct net *net = sock_net(sk_listener);
|
|
|
|
|
|
sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr);
|
|
sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr);
|
|
sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr);
|
|
sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr);
|
|
- ireq->opt = tcp_v4_save_options(sock_net(sk_listener), skb);
|
|
|
|
|
|
+ RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(net, skb));
|
|
}
|
|
}
|
|
|
|
|
|
static struct dst_entry *tcp_v4_route_req(const struct sock *sk,
|
|
static struct dst_entry *tcp_v4_route_req(const struct sock *sk,
|
|
@@ -1355,10 +1356,9 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
|
|
sk_daddr_set(newsk, ireq->ir_rmt_addr);
|
|
sk_daddr_set(newsk, ireq->ir_rmt_addr);
|
|
sk_rcv_saddr_set(newsk, ireq->ir_loc_addr);
|
|
sk_rcv_saddr_set(newsk, ireq->ir_loc_addr);
|
|
newsk->sk_bound_dev_if = ireq->ir_iif;
|
|
newsk->sk_bound_dev_if = ireq->ir_iif;
|
|
- newinet->inet_saddr = ireq->ir_loc_addr;
|
|
|
|
- inet_opt = ireq->opt;
|
|
|
|
- rcu_assign_pointer(newinet->inet_opt, inet_opt);
|
|
|
|
- ireq->opt = NULL;
|
|
|
|
|
|
+ newinet->inet_saddr = ireq->ir_loc_addr;
|
|
|
|
+ inet_opt = rcu_dereference(ireq->ireq_opt);
|
|
|
|
+ RCU_INIT_POINTER(newinet->inet_opt, inet_opt);
|
|
newinet->mc_index = inet_iif(skb);
|
|
newinet->mc_index = inet_iif(skb);
|
|
newinet->mc_ttl = ip_hdr(skb)->ttl;
|
|
newinet->mc_ttl = ip_hdr(skb)->ttl;
|
|
newinet->rcv_tos = ip_hdr(skb)->tos;
|
|
newinet->rcv_tos = ip_hdr(skb)->tos;
|
|
@@ -1403,9 +1403,12 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
|
|
if (__inet_inherit_port(sk, newsk) < 0)
|
|
if (__inet_inherit_port(sk, newsk) < 0)
|
|
goto put_and_exit;
|
|
goto put_and_exit;
|
|
*own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
|
|
*own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
|
|
- if (*own_req)
|
|
|
|
|
|
+ if (likely(*own_req)) {
|
|
tcp_move_syn(newtp, req);
|
|
tcp_move_syn(newtp, req);
|
|
-
|
|
|
|
|
|
+ ireq->ireq_opt = NULL;
|
|
|
|
+ } else {
|
|
|
|
+ newinet->inet_opt = NULL;
|
|
|
|
+ }
|
|
return newsk;
|
|
return newsk;
|
|
|
|
|
|
exit_overflow:
|
|
exit_overflow:
|
|
@@ -1416,6 +1419,7 @@ exit:
|
|
tcp_listendrop(sk);
|
|
tcp_listendrop(sk);
|
|
return NULL;
|
|
return NULL;
|
|
put_and_exit:
|
|
put_and_exit:
|
|
|
|
+ newinet->inet_opt = NULL;
|
|
inet_csk_prepare_forced_close(newsk);
|
|
inet_csk_prepare_forced_close(newsk);
|
|
tcp_done(newsk);
|
|
tcp_done(newsk);
|
|
goto exit;
|
|
goto exit;
|