Skip to content

Commit 323410e

Browse files
committed
Merge branch 'mptcp-Exchange-MPTCP-DATA_FIN-DATA_ACK-before-TCP-FIN'
Mat Martineau says: ==================== mptcp: Exchange MPTCP DATA_FIN/DATA_ACK before TCP FIN This series allows the MPTCP-level connection to be closed with the peers exchanging DATA_FIN and DATA_ACK according to the state machine in appendix D of RFC 8684. The process is very similar to the TCP disconnect state machine. The prior code sends DATA_FIN only when TCP FIN packets are sent, and does not allow for the MPTCP-level connection to be half-closed. Patch 8 ("mptcp: Use full MPTCP-level disconnect state machine") is the core of the series. Earlier patches in the series have some small fixes and helpers in preparation, and the final four small patches do some cleanup. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 0003041 + 721e908 commit 323410e

File tree

4 files changed

+306
-66
lines changed

4 files changed

+306
-66
lines changed

net/mptcp/options.c

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -451,17 +451,22 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb,
451451
static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow,
452452
struct sk_buff *skb, struct mptcp_ext *ext)
453453
{
454+
u64 data_fin_tx_seq = READ_ONCE(mptcp_sk(subflow->conn)->write_seq);
455+
454456
if (!ext->use_map || !skb->len) {
455457
/* RFC6824 requires a DSS mapping with specific values
456458
* if DATA_FIN is set but no data payload is mapped
457459
*/
458460
ext->data_fin = 1;
459461
ext->use_map = 1;
460462
ext->dsn64 = 1;
461-
ext->data_seq = subflow->data_fin_tx_seq;
463+
/* The write_seq value has already been incremented, so
464+
* the actual sequence number for the DATA_FIN is one less.
465+
*/
466+
ext->data_seq = data_fin_tx_seq - 1;
462467
ext->subflow_seq = 0;
463468
ext->data_len = 1;
464-
} else if (ext->data_seq + ext->data_len == subflow->data_fin_tx_seq) {
469+
} else if (ext->data_seq + ext->data_len == data_fin_tx_seq) {
465470
/* If there's an existing DSS mapping and it is the
466471
* final mapping, DATA_FIN consumes 1 additional byte of
467472
* mapping space.
@@ -477,22 +482,17 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
477482
struct mptcp_out_options *opts)
478483
{
479484
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
485+
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
480486
unsigned int dss_size = 0;
487+
u64 snd_data_fin_enable;
481488
struct mptcp_ext *mpext;
482-
struct mptcp_sock *msk;
483489
unsigned int ack_size;
484490
bool ret = false;
485-
u8 tcp_fin;
486491

487-
if (skb) {
488-
mpext = mptcp_get_ext(skb);
489-
tcp_fin = TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN;
490-
} else {
491-
mpext = NULL;
492-
tcp_fin = 0;
493-
}
492+
mpext = skb ? mptcp_get_ext(skb) : NULL;
493+
snd_data_fin_enable = READ_ONCE(msk->snd_data_fin_enable);
494494

495-
if (!skb || (mpext && mpext->use_map) || tcp_fin) {
495+
if (!skb || (mpext && mpext->use_map) || snd_data_fin_enable) {
496496
unsigned int map_size;
497497

498498
map_size = TCPOLEN_MPTCP_DSS_BASE + TCPOLEN_MPTCP_DSS_MAP64;
@@ -502,7 +502,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
502502
if (mpext)
503503
opts->ext_copy = *mpext;
504504

505-
if (skb && tcp_fin && subflow->data_fin_tx_enable)
505+
if (skb && snd_data_fin_enable)
506506
mptcp_write_data_fin(subflow, skb, &opts->ext_copy);
507507
ret = true;
508508
}
@@ -511,7 +511,6 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
511511
* if the first subflow may have the already the remote key handy
512512
*/
513513
opts->ext_copy.use_ack = 0;
514-
msk = mptcp_sk(subflow->conn);
515514
if (!READ_ONCE(msk->can_ack)) {
516515
*size = ALIGN(dss_size, 4);
517516
return ret;
@@ -783,6 +782,22 @@ static void update_una(struct mptcp_sock *msk,
783782
}
784783
}
785784

785+
bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq)
786+
{
787+
/* Skip if DATA_FIN was already received.
788+
* If updating simultaneously with the recvmsg loop, values
789+
* should match. If they mismatch, the peer is misbehaving and
790+
* we will prefer the most recent information.
791+
*/
792+
if (READ_ONCE(msk->rcv_data_fin) || !READ_ONCE(msk->first))
793+
return false;
794+
795+
WRITE_ONCE(msk->rcv_data_fin_seq, data_fin_seq);
796+
WRITE_ONCE(msk->rcv_data_fin, 1);
797+
798+
return true;
799+
}
800+
786801
static bool add_addr_hmac_valid(struct mptcp_sock *msk,
787802
struct mptcp_options_received *mp_opt)
788803
{
@@ -853,6 +868,20 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
853868
if (mp_opt.use_ack)
854869
update_una(msk, &mp_opt);
855870

871+
/* Zero-data-length packets are dropped by the caller and not
872+
* propagated to the MPTCP layer, so the skb extension does not
873+
* need to be allocated or populated. DATA_FIN information, if
874+
* present, needs to be updated here before the skb is freed.
875+
*/
876+
if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) {
877+
if (mp_opt.data_fin && mp_opt.data_len == 1 &&
878+
mptcp_update_rcv_data_fin(msk, mp_opt.data_seq) &&
879+
schedule_work(&msk->work))
880+
sock_hold(subflow->conn);
881+
882+
return;
883+
}
884+
856885
mpext = skb_ext_add(skb, SKB_EXT_MPTCP);
857886
if (!mpext)
858887
return;

0 commit comments

Comments
 (0)