forked from mirrors/linux
		
	mptcp: Track received DATA_FIN sequence number and add related helpers
Incoming DATA_FIN headers need to propagate the presence of the DATA_FIN bit and the associated sequence number to the MPTCP layer, even when arriving on a bare ACK that does not get added to the receive queue. Add structure members to store the DATA_FIN information and helpers to set and check those values. Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									7279da6145
								
							
						
					
					
						commit
						3721b9b646
					
				
					 3 changed files with 115 additions and 10 deletions
				
			
		|  | @ -782,6 +782,22 @@ static void update_una(struct mptcp_sock *msk, | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq) | ||||
| { | ||||
| 	/* Skip if DATA_FIN was already received.
 | ||||
| 	 * If updating simultaneously with the recvmsg loop, values | ||||
| 	 * should match. If they mismatch, the peer is misbehaving and | ||||
| 	 * we will prefer the most recent information. | ||||
| 	 */ | ||||
| 	if (READ_ONCE(msk->rcv_data_fin) || !READ_ONCE(msk->first)) | ||||
| 		return false; | ||||
| 
 | ||||
| 	WRITE_ONCE(msk->rcv_data_fin_seq, data_fin_seq); | ||||
| 	WRITE_ONCE(msk->rcv_data_fin, 1); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static bool add_addr_hmac_valid(struct mptcp_sock *msk, | ||||
| 				struct mptcp_options_received *mp_opt) | ||||
| { | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ | |||
| #include <net/inet_hashtables.h> | ||||
| #include <net/protocol.h> | ||||
| #include <net/tcp.h> | ||||
| #include <net/tcp_states.h> | ||||
| #if IS_ENABLED(CONFIG_MPTCP_IPV6) | ||||
| #include <net/transp_v6.h> | ||||
| #endif | ||||
|  | @ -163,6 +164,101 @@ static bool mptcp_subflow_dsn_valid(const struct mptcp_sock *msk, | |||
| 	return mptcp_subflow_data_available(ssk); | ||||
| } | ||||
| 
 | ||||
| static bool mptcp_pending_data_fin(struct sock *sk, u64 *seq) | ||||
| { | ||||
| 	struct mptcp_sock *msk = mptcp_sk(sk); | ||||
| 
 | ||||
| 	if (READ_ONCE(msk->rcv_data_fin) && | ||||
| 	    ((1 << sk->sk_state) & | ||||
| 	     (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2))) { | ||||
| 		u64 rcv_data_fin_seq = READ_ONCE(msk->rcv_data_fin_seq); | ||||
| 
 | ||||
| 		if (msk->ack_seq == rcv_data_fin_seq) { | ||||
| 			if (seq) | ||||
| 				*seq = rcv_data_fin_seq; | ||||
| 
 | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static void mptcp_set_timeout(const struct sock *sk, const struct sock *ssk) | ||||
| { | ||||
| 	long tout = ssk && inet_csk(ssk)->icsk_pending ? | ||||
| 				      inet_csk(ssk)->icsk_timeout - jiffies : 0; | ||||
| 
 | ||||
| 	if (tout <= 0) | ||||
| 		tout = mptcp_sk(sk)->timer_ival; | ||||
| 	mptcp_sk(sk)->timer_ival = tout > 0 ? tout : TCP_RTO_MIN; | ||||
| } | ||||
| 
 | ||||
| static void mptcp_check_data_fin(struct sock *sk) | ||||
| { | ||||
| 	struct mptcp_sock *msk = mptcp_sk(sk); | ||||
| 	u64 rcv_data_fin_seq; | ||||
| 
 | ||||
| 	if (__mptcp_check_fallback(msk) || !msk->first) | ||||
| 		return; | ||||
| 
 | ||||
| 	/* Need to ack a DATA_FIN received from a peer while this side
 | ||||
| 	 * of the connection is in ESTABLISHED, FIN_WAIT1, or FIN_WAIT2. | ||||
| 	 * msk->rcv_data_fin was set when parsing the incoming options | ||||
| 	 * at the subflow level and the msk lock was not held, so this | ||||
| 	 * is the first opportunity to act on the DATA_FIN and change | ||||
| 	 * the msk state. | ||||
| 	 * | ||||
| 	 * If we are caught up to the sequence number of the incoming | ||||
| 	 * DATA_FIN, send the DATA_ACK now and do state transition.  If | ||||
| 	 * not caught up, do nothing and let the recv code send DATA_ACK | ||||
| 	 * when catching up. | ||||
| 	 */ | ||||
| 
 | ||||
| 	if (mptcp_pending_data_fin(sk, &rcv_data_fin_seq)) { | ||||
| 		struct mptcp_subflow_context *subflow; | ||||
| 
 | ||||
| 		msk->ack_seq++; | ||||
| 		WRITE_ONCE(msk->rcv_data_fin, 0); | ||||
| 
 | ||||
| 		sk->sk_shutdown |= RCV_SHUTDOWN; | ||||
| 
 | ||||
| 		switch (sk->sk_state) { | ||||
| 		case TCP_ESTABLISHED: | ||||
| 			inet_sk_state_store(sk, TCP_CLOSE_WAIT); | ||||
| 			break; | ||||
| 		case TCP_FIN_WAIT1: | ||||
| 			inet_sk_state_store(sk, TCP_CLOSING); | ||||
| 			break; | ||||
| 		case TCP_FIN_WAIT2: | ||||
| 			inet_sk_state_store(sk, TCP_CLOSE); | ||||
| 			// @@ Close subflows now?
 | ||||
| 			break; | ||||
| 		default: | ||||
| 			/* Other states not expected */ | ||||
| 			WARN_ON_ONCE(1); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		mptcp_set_timeout(sk, NULL); | ||||
| 		mptcp_for_each_subflow(msk, subflow) { | ||||
| 			struct sock *ssk = mptcp_subflow_tcp_sock(subflow); | ||||
| 
 | ||||
| 			lock_sock(ssk); | ||||
| 			tcp_send_ack(ssk); | ||||
| 			release_sock(ssk); | ||||
| 		} | ||||
| 
 | ||||
| 		sk->sk_state_change(sk); | ||||
| 
 | ||||
| 		if (sk->sk_shutdown == SHUTDOWN_MASK || | ||||
| 		    sk->sk_state == TCP_CLOSE) | ||||
| 			sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_HUP); | ||||
| 		else | ||||
| 			sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk, | ||||
| 					   struct sock *ssk, | ||||
| 					   unsigned int *bytes) | ||||
|  | @ -303,16 +399,6 @@ static void __mptcp_flush_join_list(struct mptcp_sock *msk) | |||
| 	spin_unlock_bh(&msk->join_list_lock); | ||||
| } | ||||
| 
 | ||||
| static void mptcp_set_timeout(const struct sock *sk, const struct sock *ssk) | ||||
| { | ||||
| 	long tout = ssk && inet_csk(ssk)->icsk_pending ? | ||||
| 				      inet_csk(ssk)->icsk_timeout - jiffies : 0; | ||||
| 
 | ||||
| 	if (tout <= 0) | ||||
| 		tout = mptcp_sk(sk)->timer_ival; | ||||
| 	mptcp_sk(sk)->timer_ival = tout > 0 ? tout : TCP_RTO_MIN; | ||||
| } | ||||
| 
 | ||||
| static bool mptcp_timer_pending(struct sock *sk) | ||||
| { | ||||
| 	return timer_pending(&inet_csk(sk)->icsk_retransmit_timer); | ||||
|  |  | |||
|  | @ -193,12 +193,14 @@ struct mptcp_sock { | |||
| 	u64		remote_key; | ||||
| 	u64		write_seq; | ||||
| 	u64		ack_seq; | ||||
| 	u64		rcv_data_fin_seq; | ||||
| 	atomic64_t	snd_una; | ||||
| 	unsigned long	timer_ival; | ||||
| 	u32		token; | ||||
| 	unsigned long	flags; | ||||
| 	bool		can_ack; | ||||
| 	bool		fully_established; | ||||
| 	bool		rcv_data_fin; | ||||
| 	bool		snd_data_fin_enable; | ||||
| 	spinlock_t	join_list_lock; | ||||
| 	struct work_struct work; | ||||
|  | @ -385,6 +387,7 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk); | |||
| bool mptcp_finish_join(struct sock *sk); | ||||
| void mptcp_data_acked(struct sock *sk); | ||||
| void mptcp_subflow_eof(struct sock *sk); | ||||
| bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq); | ||||
| 
 | ||||
| void __init mptcp_token_init(void); | ||||
| static inline void mptcp_token_init_request(struct request_sock *req) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Mat Martineau
						Mat Martineau