diff options
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 31 | 
1 files changed, 18 insertions, 13 deletions
| diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index d9416b5162bc..5b027c69cbc5 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -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,  					    ireq->ir_rmt_addr, -					    ireq->opt); +					    ireq_opt_deref(ireq));  		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)  { -	kfree(inet_rsk(req)->opt); +	kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1));  }  #ifdef CONFIG_TCP_MD5SIG @@ -1265,10 +1265,11 @@ static void tcp_v4_init_req(struct request_sock *req,  			    struct sk_buff *skb)  {  	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_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, @@ -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_rcv_saddr_set(newsk, ireq->ir_loc_addr);  	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_ttl	      = ip_hdr(skb)->ttl;  	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)  		goto put_and_exit;  	*own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); -	if (*own_req) +	if (likely(*own_req)) {  		tcp_move_syn(newtp, req); - +		ireq->ireq_opt = NULL; +	} else { +		newinet->inet_opt = NULL; +	}  	return newsk;  exit_overflow: @@ -1416,6 +1419,7 @@ exit:  	tcp_listendrop(sk);  	return NULL;  put_and_exit: +	newinet->inet_opt = NULL;  	inet_csk_prepare_forced_close(newsk);  	tcp_done(newsk);  	goto exit; @@ -1503,23 +1507,23 @@ csum_err:  }  EXPORT_SYMBOL(tcp_v4_do_rcv); -void tcp_v4_early_demux(struct sk_buff *skb) +int tcp_v4_early_demux(struct sk_buff *skb)  {  	const struct iphdr *iph;  	const struct tcphdr *th;  	struct sock *sk;  	if (skb->pkt_type != PACKET_HOST) -		return; +		return 0;  	if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct tcphdr))) -		return; +		return 0;  	iph = ip_hdr(skb);  	th = tcp_hdr(skb);  	if (th->doff < sizeof(struct tcphdr) / 4) -		return; +		return 0;  	sk = __inet_lookup_established(dev_net(skb->dev), &tcp_hashinfo,  				       iph->saddr, th->source, @@ -1538,6 +1542,7 @@ void tcp_v4_early_demux(struct sk_buff *skb)  				skb_dst_set_noref(skb, dst);  		}  	} +	return 0;  }  bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb) |