diff options
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 61 | 
1 files changed, 41 insertions, 20 deletions
| diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index c6bc0c4d19c6..94e28350f420 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -848,7 +848,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,  			tcp_time_stamp_raw() + tcp_rsk(req)->ts_off,  			req->ts_recent,  			0, -			tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr, +			tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->saddr,  					  AF_INET),  			inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0,  			ip_hdr(skb)->tos); @@ -1591,6 +1591,34 @@ int tcp_filter(struct sock *sk, struct sk_buff *skb)  }  EXPORT_SYMBOL(tcp_filter); +static void tcp_v4_restore_cb(struct sk_buff *skb) +{ +	memmove(IPCB(skb), &TCP_SKB_CB(skb)->header.h4, +		sizeof(struct inet_skb_parm)); +} + +static void tcp_v4_fill_cb(struct sk_buff *skb, const struct iphdr *iph, +			   const struct tcphdr *th) +{ +	/* This is tricky : We move IPCB at its correct location into TCP_SKB_CB() +	 * barrier() makes sure compiler wont play fool^Waliasing games. +	 */ +	memmove(&TCP_SKB_CB(skb)->header.h4, IPCB(skb), +		sizeof(struct inet_skb_parm)); +	barrier(); + +	TCP_SKB_CB(skb)->seq = ntohl(th->seq); +	TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + +				    skb->len - th->doff * 4); +	TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); +	TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); +	TCP_SKB_CB(skb)->tcp_tw_isn = 0; +	TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); +	TCP_SKB_CB(skb)->sacked	 = 0; +	TCP_SKB_CB(skb)->has_rxtstamp = +			skb->tstamp || skb_hwtstamps(skb)->hwtstamp; +} +  /*   *	From tcp_input.c   */ @@ -1631,24 +1659,6 @@ int tcp_v4_rcv(struct sk_buff *skb)  	th = (const struct tcphdr *)skb->data;  	iph = ip_hdr(skb); -	/* This is tricky : We move IPCB at its correct location into TCP_SKB_CB() -	 * barrier() makes sure compiler wont play fool^Waliasing games. -	 */ -	memmove(&TCP_SKB_CB(skb)->header.h4, IPCB(skb), -		sizeof(struct inet_skb_parm)); -	barrier(); - -	TCP_SKB_CB(skb)->seq = ntohl(th->seq); -	TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + -				    skb->len - th->doff * 4); -	TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); -	TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); -	TCP_SKB_CB(skb)->tcp_tw_isn = 0; -	TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); -	TCP_SKB_CB(skb)->sacked	 = 0; -	TCP_SKB_CB(skb)->has_rxtstamp = -			skb->tstamp || skb_hwtstamps(skb)->hwtstamp; -  lookup:  	sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source,  			       th->dest, sdif, &refcounted); @@ -1679,14 +1689,19 @@ process:  		sock_hold(sk);  		refcounted = true;  		nsk = NULL; -		if (!tcp_filter(sk, skb)) +		if (!tcp_filter(sk, skb)) { +			th = (const struct tcphdr *)skb->data; +			iph = ip_hdr(skb); +			tcp_v4_fill_cb(skb, iph, th);  			nsk = tcp_check_req(sk, skb, req, false); +		}  		if (!nsk) {  			reqsk_put(req);  			goto discard_and_relse;  		}  		if (nsk == sk) {  			reqsk_put(req); +			tcp_v4_restore_cb(skb);  		} else if (tcp_child_process(sk, nsk, skb)) {  			tcp_v4_send_reset(nsk, skb);  			goto discard_and_relse; @@ -1712,6 +1727,7 @@ process:  		goto discard_and_relse;  	th = (const struct tcphdr *)skb->data;  	iph = ip_hdr(skb); +	tcp_v4_fill_cb(skb, iph, th);  	skb->dev = NULL; @@ -1742,6 +1758,8 @@ no_tcp_socket:  	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))  		goto discard_it; +	tcp_v4_fill_cb(skb, iph, th); +  	if (tcp_checksum_complete(skb)) {  csum_error:  		__TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); @@ -1768,6 +1786,8 @@ do_time_wait:  		goto discard_it;  	} +	tcp_v4_fill_cb(skb, iph, th); +  	if (tcp_checksum_complete(skb)) {  		inet_twsk_put(inet_twsk(sk));  		goto csum_error; @@ -1784,6 +1804,7 @@ do_time_wait:  		if (sk2) {  			inet_twsk_deschedule_put(inet_twsk(sk));  			sk = sk2; +			tcp_v4_restore_cb(skb);  			refcounted = false;  			goto process;  		} |