Skip to content

Commit f296234

Browse files
Peter Krystaddavem330
authored andcommitted
mptcp: Add handling of incoming MP_JOIN requests
Process the MP_JOIN option in a SYN packet with the same flow as MP_CAPABLE but when the third ACK is received add the subflow to the MPTCP socket subflow list instead of adding it to the TCP socket accept queue. The subflow is added at the end of the subflow list so it will not interfere with the existing subflows operation and no data is expected to be transmitted on it. Co-developed-by: Florian Westphal <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Co-developed-by: Paolo Abeni <[email protected]> Signed-off-by: Paolo Abeni <[email protected]> Signed-off-by: Peter Krystad <[email protected]> Signed-off-by: Mat Martineau <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1b1c7a0 commit f296234

File tree

8 files changed

+390
-46
lines changed

8 files changed

+390
-46
lines changed

include/linux/tcp.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,13 @@ struct mptcp_options_received {
9292
add_addr : 1,
9393
rm_addr : 1,
9494
family : 4,
95-
echo : 1;
95+
echo : 1,
96+
backup : 1;
97+
u32 token;
98+
u32 nonce;
99+
u64 thmac;
100+
u8 hmac[20];
101+
u8 join_id;
96102
u8 use_map:1,
97103
dsn64:1,
98104
data_fin:1,

include/net/mptcp.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ struct mptcp_out_options {
4242
u8 addr_id;
4343
u64 ahmac;
4444
u8 rm_id;
45+
u8 join_id;
46+
u8 backup;
47+
u32 nonce;
48+
u64 thmac;
4549
struct mptcp_ext ext_copy;
4650
#endif
4751
};
@@ -115,6 +119,8 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
115119
skb_ext_find(from, SKB_EXT_MPTCP));
116120
}
117121

122+
bool mptcp_sk_is_subflow(const struct sock *sk);
123+
118124
#else
119125

120126
static inline void mptcp_init(void)
@@ -181,6 +187,11 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
181187
return true;
182188
}
183189

190+
static inline bool mptcp_sk_is_subflow(const struct sock *sk)
191+
{
192+
return false;
193+
}
194+
184195
#endif /* CONFIG_MPTCP */
185196

186197
#if IS_ENABLED(CONFIG_MPTCP_IPV6)

net/ipv4/tcp_minisocks.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,12 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
774774
if (!child)
775775
goto listen_overflow;
776776

777+
if (own_req && sk_is_mptcp(child) && mptcp_sk_is_subflow(child)) {
778+
reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req);
779+
inet_csk_reqsk_queue_drop_and_put(sk, req);
780+
return child;
781+
}
782+
777783
sock_rps_save_rxhash(child, skb);
778784
tcp_synack_rtt_meas(child, req);
779785
*req_stolen = !own_req;

net/mptcp/options.c

Lines changed: 95 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,38 @@ void mptcp_parse_option(const struct sk_buff *skb, const unsigned char *ptr,
9696
mp_opt->rcvr_key, mp_opt->data_len);
9797
break;
9898

99+
case MPTCPOPT_MP_JOIN:
100+
mp_opt->mp_join = 1;
101+
if (opsize == TCPOLEN_MPTCP_MPJ_SYN) {
102+
mp_opt->backup = *ptr++ & MPTCPOPT_BACKUP;
103+
mp_opt->join_id = *ptr++;
104+
mp_opt->token = get_unaligned_be32(ptr);
105+
ptr += 4;
106+
mp_opt->nonce = get_unaligned_be32(ptr);
107+
ptr += 4;
108+
pr_debug("MP_JOIN bkup=%u, id=%u, token=%u, nonce=%u",
109+
mp_opt->backup, mp_opt->join_id,
110+
mp_opt->token, mp_opt->nonce);
111+
} else if (opsize == TCPOLEN_MPTCP_MPJ_SYNACK) {
112+
mp_opt->backup = *ptr++ & MPTCPOPT_BACKUP;
113+
mp_opt->join_id = *ptr++;
114+
mp_opt->thmac = get_unaligned_be64(ptr);
115+
ptr += 8;
116+
mp_opt->nonce = get_unaligned_be32(ptr);
117+
ptr += 4;
118+
pr_debug("MP_JOIN bkup=%u, id=%u, thmac=%llu, nonce=%u",
119+
mp_opt->backup, mp_opt->join_id,
120+
mp_opt->thmac, mp_opt->nonce);
121+
} else if (opsize == TCPOLEN_MPTCP_MPJ_ACK) {
122+
ptr += 2;
123+
memcpy(mp_opt->hmac, ptr, MPTCPOPT_HMAC_LEN);
124+
pr_debug("MP_JOIN hmac");
125+
} else {
126+
pr_warn("MP_JOIN bad option size");
127+
mp_opt->mp_join = 0;
128+
}
129+
break;
130+
99131
case MPTCPOPT_DSS:
100132
pr_debug("DSS");
101133
ptr++;
@@ -572,37 +604,80 @@ bool mptcp_synack_options(const struct request_sock *req, unsigned int *size,
572604
pr_debug("subflow_req=%p, local_key=%llu",
573605
subflow_req, subflow_req->local_key);
574606
return true;
607+
} else if (subflow_req->mp_join) {
608+
opts->suboptions = OPTION_MPTCP_MPJ_SYNACK;
609+
opts->backup = subflow_req->backup;
610+
opts->join_id = subflow_req->local_id;
611+
opts->thmac = subflow_req->thmac;
612+
opts->nonce = subflow_req->local_nonce;
613+
pr_debug("req=%p, bkup=%u, id=%u, thmac=%llu, nonce=%u",
614+
subflow_req, opts->backup, opts->join_id,
615+
opts->thmac, opts->nonce);
616+
*size = TCPOLEN_MPTCP_MPJ_SYNACK;
617+
return true;
575618
}
576619
return false;
577620
}
578621

579-
static bool check_fully_established(struct mptcp_subflow_context *subflow,
622+
static bool check_fully_established(struct mptcp_sock *msk, struct sock *sk,
623+
struct mptcp_subflow_context *subflow,
580624
struct sk_buff *skb,
581625
struct mptcp_options_received *mp_opt)
582626
{
583627
/* here we can process OoO, in-window pkts, only in-sequence 4th ack
584-
* are relevant
628+
* will make the subflow fully established
585629
*/
586-
if (likely(subflow->fully_established ||
587-
TCP_SKB_CB(skb)->seq != subflow->ssn_offset + 1))
588-
return true;
630+
if (likely(subflow->fully_established)) {
631+
/* on passive sockets, check for 3rd ack retransmission
632+
* note that msk is always set by subflow_syn_recv_sock()
633+
* for mp_join subflows
634+
*/
635+
if (TCP_SKB_CB(skb)->seq == subflow->ssn_offset + 1 &&
636+
TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq &&
637+
subflow->mp_join && mp_opt->mp_join &&
638+
READ_ONCE(msk->pm.server_side))
639+
tcp_send_ack(sk);
640+
goto fully_established;
641+
}
642+
643+
/* we should process OoO packets before the first subflow is fully
644+
* established, but not expected for MP_JOIN subflows
645+
*/
646+
if (TCP_SKB_CB(skb)->seq != subflow->ssn_offset + 1)
647+
return subflow->mp_capable;
589648

590-
if (mp_opt->use_ack)
649+
if (mp_opt->use_ack) {
650+
/* subflows are fully established as soon as we get any
651+
* additional ack.
652+
*/
591653
subflow->fully_established = 1;
654+
goto fully_established;
655+
}
592656

593-
if (subflow->can_ack)
594-
return true;
657+
WARN_ON_ONCE(subflow->can_ack);
595658

596659
/* If the first established packet does not contain MP_CAPABLE + data
597660
* then fallback to TCP
598661
*/
599662
if (!mp_opt->mp_capable) {
600663
subflow->mp_capable = 0;
601-
tcp_sk(mptcp_subflow_tcp_sock(subflow))->is_mptcp = 0;
664+
tcp_sk(sk)->is_mptcp = 0;
602665
return false;
603666
}
667+
668+
subflow->fully_established = 1;
604669
subflow->remote_key = mp_opt->sndr_key;
605670
subflow->can_ack = 1;
671+
672+
fully_established:
673+
if (likely(subflow->pm_notified))
674+
return true;
675+
676+
subflow->pm_notified = 1;
677+
if (subflow->mp_join)
678+
mptcp_pm_subflow_established(msk, subflow);
679+
else
680+
mptcp_pm_fully_established(msk);
606681
return true;
607682
}
608683

@@ -641,7 +716,7 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
641716
struct mptcp_ext *mpext;
642717

643718
mp_opt = &opt_rx->mptcp;
644-
if (!check_fully_established(subflow, skb, mp_opt))
719+
if (!check_fully_established(msk, sk, subflow, skb, mp_opt))
645720
return;
646721

647722
if (mp_opt->add_addr && add_addr_hmac_valid(msk, mp_opt)) {
@@ -700,8 +775,6 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
700775
}
701776

702777
mpext->data_fin = mp_opt->data_fin;
703-
704-
mptcp_pm_fully_established(msk);
705778
}
706779

707780
void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
@@ -787,6 +860,16 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
787860
0, opts->rm_id);
788861
}
789862

863+
if (OPTION_MPTCP_MPJ_SYNACK & opts->suboptions) {
864+
*ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
865+
TCPOLEN_MPTCP_MPJ_SYNACK,
866+
opts->backup, opts->join_id);
867+
put_unaligned_be64(opts->thmac, ptr);
868+
ptr += 2;
869+
put_unaligned_be32(opts->nonce, ptr);
870+
ptr += 1;
871+
}
872+
790873
if (opts->ext_copy.use_ack || opts->ext_copy.use_map) {
791874
struct mptcp_ext *mpext = &opts->ext_copy;
792875
u8 len = TCPOLEN_MPTCP_DSS_BASE;

net/mptcp/protocol.c

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -104,19 +104,6 @@ static struct socket *__mptcp_socket_create(struct mptcp_sock *msk, int state)
104104
return ssock;
105105
}
106106

107-
static struct sock *mptcp_subflow_get(const struct mptcp_sock *msk)
108-
{
109-
struct mptcp_subflow_context *subflow;
110-
111-
sock_owned_by_me((const struct sock *)msk);
112-
113-
mptcp_for_each_subflow(msk, subflow) {
114-
return mptcp_subflow_tcp_sock(subflow);
115-
}
116-
117-
return NULL;
118-
}
119-
120107
static void __mptcp_move_skb(struct mptcp_sock *msk, struct sock *ssk,
121108
struct sk_buff *skb,
122109
unsigned int offset, size_t copy_len)
@@ -391,6 +378,43 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
391378
return ret;
392379
}
393380

381+
static struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
382+
{
383+
struct mptcp_subflow_context *subflow;
384+
struct sock *backup = NULL;
385+
386+
sock_owned_by_me((const struct sock *)msk);
387+
388+
mptcp_for_each_subflow(msk, subflow) {
389+
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
390+
391+
if (!sk_stream_memory_free(ssk)) {
392+
struct socket *sock = ssk->sk_socket;
393+
394+
if (sock) {
395+
clear_bit(MPTCP_SEND_SPACE, &msk->flags);
396+
smp_mb__after_atomic();
397+
398+
/* enables sk->write_space() callbacks */
399+
set_bit(SOCK_NOSPACE, &sock->flags);
400+
}
401+
402+
return NULL;
403+
}
404+
405+
if (subflow->backup) {
406+
if (!backup)
407+
backup = ssk;
408+
409+
continue;
410+
}
411+
412+
return ssk;
413+
}
414+
415+
return backup;
416+
}
417+
394418
static void ssk_check_wmem(struct mptcp_sock *msk, struct sock *ssk)
395419
{
396420
struct socket *sock;
@@ -438,10 +462,17 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
438462
return ret >= 0 ? ret + copied : (copied ? copied : ret);
439463
}
440464

441-
ssk = mptcp_subflow_get(msk);
442-
if (!ssk) {
443-
release_sock(sk);
444-
return -ENOTCONN;
465+
ssk = mptcp_subflow_get_send(msk);
466+
while (!sk_stream_memory_free(sk) || !ssk) {
467+
ret = sk_stream_wait_memory(sk, &timeo);
468+
if (ret)
469+
goto out;
470+
471+
ssk = mptcp_subflow_get_send(msk);
472+
if (list_empty(&msk->conn_list)) {
473+
ret = -ENOTCONN;
474+
goto out;
475+
}
445476
}
446477

447478
pr_debug("conn_list->subflow=%p", ssk);
@@ -1070,6 +1101,37 @@ static void mptcp_sock_graft(struct sock *sk, struct socket *parent)
10701101
write_unlock_bh(&sk->sk_callback_lock);
10711102
}
10721103

1104+
bool mptcp_finish_join(struct sock *sk)
1105+
{
1106+
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
1107+
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
1108+
struct sock *parent = (void *)msk;
1109+
struct socket *parent_sock;
1110+
1111+
pr_debug("msk=%p, subflow=%p", msk, subflow);
1112+
1113+
/* mptcp socket already closing? */
1114+
if (inet_sk_state_load(parent) != TCP_ESTABLISHED)
1115+
return false;
1116+
1117+
if (!msk->pm.server_side)
1118+
return true;
1119+
1120+
/* passive connection, attach to msk socket */
1121+
parent_sock = READ_ONCE(parent->sk_socket);
1122+
if (parent_sock && !sk->sk_socket)
1123+
mptcp_sock_graft(sk, parent_sock);
1124+
1125+
return mptcp_pm_allow_new_subflow(msk);
1126+
}
1127+
1128+
bool mptcp_sk_is_subflow(const struct sock *sk)
1129+
{
1130+
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
1131+
1132+
return subflow->mp_join == 1;
1133+
}
1134+
10731135
static bool mptcp_memory_free(const struct sock *sk, int wake)
10741136
{
10751137
struct mptcp_sock *msk = mptcp_sk(sk);

0 commit comments

Comments
 (0)