forked from mirrors/linux
		
	mptcp: Handle incoming 32-bit DATA_FIN values
The peer may send a DATA_FIN mapping with either a 32-bit or 64-bit
sequence number. When a 32-bit sequence number is received for the
DATA_FIN, it must be expanded to 64 bits before comparing it to the
last acked sequence number. This expansion was missing.
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/93
Fixes: 3721b9b646 ("mptcp: Track received DATA_FIN sequence number and add related helpers")
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
							
								
									917944da3b
								
							
						
					
					
						commit
						1a49b2c2a5
					
				
					 3 changed files with 18 additions and 7 deletions
				
			
		|  | @ -782,7 +782,7 @@ static void update_una(struct mptcp_sock *msk, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq) | bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq, bool use_64bit) | ||||||
| { | { | ||||||
| 	/* Skip if DATA_FIN was already received.
 | 	/* Skip if DATA_FIN was already received.
 | ||||||
| 	 * If updating simultaneously with the recvmsg loop, values | 	 * If updating simultaneously with the recvmsg loop, values | ||||||
|  | @ -792,7 +792,8 @@ bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq) | ||||||
| 	if (READ_ONCE(msk->rcv_data_fin) || !READ_ONCE(msk->first)) | 	if (READ_ONCE(msk->rcv_data_fin) || !READ_ONCE(msk->first)) | ||||||
| 		return false; | 		return false; | ||||||
| 
 | 
 | ||||||
| 	WRITE_ONCE(msk->rcv_data_fin_seq, data_fin_seq); | 	WRITE_ONCE(msk->rcv_data_fin_seq, | ||||||
|  | 		   expand_ack(READ_ONCE(msk->ack_seq), data_fin_seq, use_64bit)); | ||||||
| 	WRITE_ONCE(msk->rcv_data_fin, 1); | 	WRITE_ONCE(msk->rcv_data_fin, 1); | ||||||
| 
 | 
 | ||||||
| 	return true; | 	return true; | ||||||
|  | @ -875,7 +876,7 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb, | ||||||
| 	 */ | 	 */ | ||||||
| 	if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { | 	if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { | ||||||
| 		if (mp_opt.data_fin && mp_opt.data_len == 1 && | 		if (mp_opt.data_fin && mp_opt.data_len == 1 && | ||||||
| 		    mptcp_update_rcv_data_fin(msk, mp_opt.data_seq) && | 		    mptcp_update_rcv_data_fin(msk, mp_opt.data_seq, mp_opt.dsn64) && | ||||||
| 		    schedule_work(&msk->work)) | 		    schedule_work(&msk->work)) | ||||||
| 			sock_hold(subflow->conn); | 			sock_hold(subflow->conn); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -387,7 +387,7 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk); | ||||||
| bool mptcp_finish_join(struct sock *sk); | bool mptcp_finish_join(struct sock *sk); | ||||||
| void mptcp_data_acked(struct sock *sk); | void mptcp_data_acked(struct sock *sk); | ||||||
| void mptcp_subflow_eof(struct sock *sk); | void mptcp_subflow_eof(struct sock *sk); | ||||||
| bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq); | bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq, bool use_64bit); | ||||||
| 
 | 
 | ||||||
| void __init mptcp_token_init(void); | void __init mptcp_token_init(void); | ||||||
| static inline void mptcp_token_init_request(struct request_sock *req) | static inline void mptcp_token_init_request(struct request_sock *req) | ||||||
|  |  | ||||||
|  | @ -731,7 +731,8 @@ static enum mapping_status get_mapping_status(struct sock *ssk, | ||||||
| 
 | 
 | ||||||
| 	if (mpext->data_fin == 1) { | 	if (mpext->data_fin == 1) { | ||||||
| 		if (data_len == 1) { | 		if (data_len == 1) { | ||||||
| 			bool updated = mptcp_update_rcv_data_fin(msk, mpext->data_seq); | 			bool updated = mptcp_update_rcv_data_fin(msk, mpext->data_seq, | ||||||
|  | 								 mpext->dsn64); | ||||||
| 			pr_debug("DATA_FIN with no payload seq=%llu", mpext->data_seq); | 			pr_debug("DATA_FIN with no payload seq=%llu", mpext->data_seq); | ||||||
| 			if (subflow->map_valid) { | 			if (subflow->map_valid) { | ||||||
| 				/* A DATA_FIN might arrive in a DSS
 | 				/* A DATA_FIN might arrive in a DSS
 | ||||||
|  | @ -748,8 +749,17 @@ static enum mapping_status get_mapping_status(struct sock *ssk, | ||||||
| 				return MAPPING_DATA_FIN; | 				return MAPPING_DATA_FIN; | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			mptcp_update_rcv_data_fin(msk, mpext->data_seq + data_len); | 			u64 data_fin_seq = mpext->data_seq + data_len; | ||||||
| 			pr_debug("DATA_FIN with mapping seq=%llu", mpext->data_seq + data_len); | 
 | ||||||
|  | 			/* If mpext->data_seq is a 32-bit value, data_fin_seq
 | ||||||
|  | 			 * must also be limited to 32 bits. | ||||||
|  | 			 */ | ||||||
|  | 			if (!mpext->dsn64) | ||||||
|  | 				data_fin_seq &= GENMASK_ULL(31, 0); | ||||||
|  | 
 | ||||||
|  | 			mptcp_update_rcv_data_fin(msk, data_fin_seq, mpext->dsn64); | ||||||
|  | 			pr_debug("DATA_FIN with mapping seq=%llu dsn64=%d", | ||||||
|  | 				 data_fin_seq, mpext->dsn64); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		/* Adjust for DATA_FIN using 1 byte of sequence space */ | 		/* Adjust for DATA_FIN using 1 byte of sequence space */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Mat Martineau
						Mat Martineau