xref: /openbmc/linux/net/mptcp/options.c (revision 648ef4b88673dadb8463bf0d4b10fbf33d55def8)
1eda7acddSPeter Krystad // SPDX-License-Identifier: GPL-2.0
2eda7acddSPeter Krystad /* Multipath TCP
3eda7acddSPeter Krystad  *
4eda7acddSPeter Krystad  * Copyright (c) 2017 - 2019, Intel Corporation.
5eda7acddSPeter Krystad  */
6eda7acddSPeter Krystad 
7eda7acddSPeter Krystad #include <linux/kernel.h>
8eda7acddSPeter Krystad #include <net/tcp.h>
9eda7acddSPeter Krystad #include <net/mptcp.h>
10eda7acddSPeter Krystad #include "protocol.h"
11eda7acddSPeter Krystad 
12eda7acddSPeter Krystad void mptcp_parse_option(const unsigned char *ptr, int opsize,
13eda7acddSPeter Krystad 			struct tcp_options_received *opt_rx)
14eda7acddSPeter Krystad {
15eda7acddSPeter Krystad 	struct mptcp_options_received *mp_opt = &opt_rx->mptcp;
16eda7acddSPeter Krystad 	u8 subtype = *ptr >> 4;
17*648ef4b8SMat Martineau 	int expected_opsize;
18eda7acddSPeter Krystad 	u8 version;
19eda7acddSPeter Krystad 	u8 flags;
20eda7acddSPeter Krystad 
21eda7acddSPeter Krystad 	switch (subtype) {
22eda7acddSPeter Krystad 	case MPTCPOPT_MP_CAPABLE:
23eda7acddSPeter Krystad 		if (opsize != TCPOLEN_MPTCP_MPC_SYN &&
24eda7acddSPeter Krystad 		    opsize != TCPOLEN_MPTCP_MPC_ACK)
25eda7acddSPeter Krystad 			break;
26eda7acddSPeter Krystad 
27eda7acddSPeter Krystad 		version = *ptr++ & MPTCP_VERSION_MASK;
28eda7acddSPeter Krystad 		if (version != MPTCP_SUPPORTED_VERSION)
29eda7acddSPeter Krystad 			break;
30eda7acddSPeter Krystad 
31eda7acddSPeter Krystad 		flags = *ptr++;
32eda7acddSPeter Krystad 		if (!((flags & MPTCP_CAP_FLAG_MASK) == MPTCP_CAP_HMAC_SHA1) ||
33eda7acddSPeter Krystad 		    (flags & MPTCP_CAP_EXTENSIBILITY))
34eda7acddSPeter Krystad 			break;
35eda7acddSPeter Krystad 
36eda7acddSPeter Krystad 		/* RFC 6824, Section 3.1:
37eda7acddSPeter Krystad 		 * "For the Checksum Required bit (labeled "A"), if either
38eda7acddSPeter Krystad 		 * host requires the use of checksums, checksums MUST be used.
39eda7acddSPeter Krystad 		 * In other words, the only way for checksums not to be used
40eda7acddSPeter Krystad 		 * is if both hosts in their SYNs set A=0."
41eda7acddSPeter Krystad 		 *
42eda7acddSPeter Krystad 		 * Section 3.3.0:
43eda7acddSPeter Krystad 		 * "If a checksum is not present when its use has been
44eda7acddSPeter Krystad 		 * negotiated, the receiver MUST close the subflow with a RST as
45eda7acddSPeter Krystad 		 * it is considered broken."
46eda7acddSPeter Krystad 		 *
47eda7acddSPeter Krystad 		 * We don't implement DSS checksum - fall back to TCP.
48eda7acddSPeter Krystad 		 */
49eda7acddSPeter Krystad 		if (flags & MPTCP_CAP_CHECKSUM_REQD)
50eda7acddSPeter Krystad 			break;
51eda7acddSPeter Krystad 
52eda7acddSPeter Krystad 		mp_opt->mp_capable = 1;
53eda7acddSPeter Krystad 		mp_opt->sndr_key = get_unaligned_be64(ptr);
54eda7acddSPeter Krystad 		ptr += 8;
55eda7acddSPeter Krystad 
56eda7acddSPeter Krystad 		if (opsize == TCPOLEN_MPTCP_MPC_ACK) {
57eda7acddSPeter Krystad 			mp_opt->rcvr_key = get_unaligned_be64(ptr);
58eda7acddSPeter Krystad 			ptr += 8;
59eda7acddSPeter Krystad 			pr_debug("MP_CAPABLE sndr=%llu, rcvr=%llu",
60eda7acddSPeter Krystad 				 mp_opt->sndr_key, mp_opt->rcvr_key);
61eda7acddSPeter Krystad 		} else {
62eda7acddSPeter Krystad 			pr_debug("MP_CAPABLE sndr=%llu", mp_opt->sndr_key);
63eda7acddSPeter Krystad 		}
64eda7acddSPeter Krystad 		break;
65eda7acddSPeter Krystad 
66eda7acddSPeter Krystad 	case MPTCPOPT_DSS:
67eda7acddSPeter Krystad 		pr_debug("DSS");
68*648ef4b8SMat Martineau 		ptr++;
69*648ef4b8SMat Martineau 
70*648ef4b8SMat Martineau 		flags = (*ptr++) & MPTCP_DSS_FLAG_MASK;
71*648ef4b8SMat Martineau 		mp_opt->data_fin = (flags & MPTCP_DSS_DATA_FIN) != 0;
72*648ef4b8SMat Martineau 		mp_opt->dsn64 = (flags & MPTCP_DSS_DSN64) != 0;
73*648ef4b8SMat Martineau 		mp_opt->use_map = (flags & MPTCP_DSS_HAS_MAP) != 0;
74*648ef4b8SMat Martineau 		mp_opt->ack64 = (flags & MPTCP_DSS_ACK64) != 0;
75*648ef4b8SMat Martineau 		mp_opt->use_ack = (flags & MPTCP_DSS_HAS_ACK);
76*648ef4b8SMat Martineau 
77*648ef4b8SMat Martineau 		pr_debug("data_fin=%d dsn64=%d use_map=%d ack64=%d use_ack=%d",
78*648ef4b8SMat Martineau 			 mp_opt->data_fin, mp_opt->dsn64,
79*648ef4b8SMat Martineau 			 mp_opt->use_map, mp_opt->ack64,
80*648ef4b8SMat Martineau 			 mp_opt->use_ack);
81*648ef4b8SMat Martineau 
82*648ef4b8SMat Martineau 		expected_opsize = TCPOLEN_MPTCP_DSS_BASE;
83*648ef4b8SMat Martineau 
84*648ef4b8SMat Martineau 		if (mp_opt->use_ack) {
85*648ef4b8SMat Martineau 			if (mp_opt->ack64)
86*648ef4b8SMat Martineau 				expected_opsize += TCPOLEN_MPTCP_DSS_ACK64;
87*648ef4b8SMat Martineau 			else
88*648ef4b8SMat Martineau 				expected_opsize += TCPOLEN_MPTCP_DSS_ACK32;
89*648ef4b8SMat Martineau 		}
90*648ef4b8SMat Martineau 
91*648ef4b8SMat Martineau 		if (mp_opt->use_map) {
92*648ef4b8SMat Martineau 			if (mp_opt->dsn64)
93*648ef4b8SMat Martineau 				expected_opsize += TCPOLEN_MPTCP_DSS_MAP64;
94*648ef4b8SMat Martineau 			else
95*648ef4b8SMat Martineau 				expected_opsize += TCPOLEN_MPTCP_DSS_MAP32;
96*648ef4b8SMat Martineau 		}
97*648ef4b8SMat Martineau 
98*648ef4b8SMat Martineau 		/* RFC 6824, Section 3.3:
99*648ef4b8SMat Martineau 		 * If a checksum is present, but its use had
100*648ef4b8SMat Martineau 		 * not been negotiated in the MP_CAPABLE handshake,
101*648ef4b8SMat Martineau 		 * the checksum field MUST be ignored.
102*648ef4b8SMat Martineau 		 */
103*648ef4b8SMat Martineau 		if (opsize != expected_opsize &&
104*648ef4b8SMat Martineau 		    opsize != expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM)
105*648ef4b8SMat Martineau 			break;
106*648ef4b8SMat Martineau 
107eda7acddSPeter Krystad 		mp_opt->dss = 1;
108*648ef4b8SMat Martineau 
109*648ef4b8SMat Martineau 		if (mp_opt->use_ack) {
110*648ef4b8SMat Martineau 			if (mp_opt->ack64) {
111*648ef4b8SMat Martineau 				mp_opt->data_ack = get_unaligned_be64(ptr);
112*648ef4b8SMat Martineau 				ptr += 8;
113*648ef4b8SMat Martineau 			} else {
114*648ef4b8SMat Martineau 				mp_opt->data_ack = get_unaligned_be32(ptr);
115*648ef4b8SMat Martineau 				ptr += 4;
116*648ef4b8SMat Martineau 			}
117*648ef4b8SMat Martineau 
118*648ef4b8SMat Martineau 			pr_debug("data_ack=%llu", mp_opt->data_ack);
119*648ef4b8SMat Martineau 		}
120*648ef4b8SMat Martineau 
121*648ef4b8SMat Martineau 		if (mp_opt->use_map) {
122*648ef4b8SMat Martineau 			if (mp_opt->dsn64) {
123*648ef4b8SMat Martineau 				mp_opt->data_seq = get_unaligned_be64(ptr);
124*648ef4b8SMat Martineau 				ptr += 8;
125*648ef4b8SMat Martineau 			} else {
126*648ef4b8SMat Martineau 				mp_opt->data_seq = get_unaligned_be32(ptr);
127*648ef4b8SMat Martineau 				ptr += 4;
128*648ef4b8SMat Martineau 			}
129*648ef4b8SMat Martineau 
130*648ef4b8SMat Martineau 			mp_opt->subflow_seq = get_unaligned_be32(ptr);
131*648ef4b8SMat Martineau 			ptr += 4;
132*648ef4b8SMat Martineau 
133*648ef4b8SMat Martineau 			mp_opt->data_len = get_unaligned_be16(ptr);
134*648ef4b8SMat Martineau 			ptr += 2;
135*648ef4b8SMat Martineau 
136*648ef4b8SMat Martineau 			pr_debug("data_seq=%llu subflow_seq=%u data_len=%u",
137*648ef4b8SMat Martineau 				 mp_opt->data_seq, mp_opt->subflow_seq,
138*648ef4b8SMat Martineau 				 mp_opt->data_len);
139*648ef4b8SMat Martineau 		}
140*648ef4b8SMat Martineau 
141eda7acddSPeter Krystad 		break;
142eda7acddSPeter Krystad 
143eda7acddSPeter Krystad 	default:
144eda7acddSPeter Krystad 		break;
145eda7acddSPeter Krystad 	}
146eda7acddSPeter Krystad }
147eda7acddSPeter Krystad 
148cec37a6eSPeter Krystad void mptcp_get_options(const struct sk_buff *skb,
149cec37a6eSPeter Krystad 		       struct tcp_options_received *opt_rx)
150cec37a6eSPeter Krystad {
151cec37a6eSPeter Krystad 	const unsigned char *ptr;
152cec37a6eSPeter Krystad 	const struct tcphdr *th = tcp_hdr(skb);
153cec37a6eSPeter Krystad 	int length = (th->doff * 4) - sizeof(struct tcphdr);
154cec37a6eSPeter Krystad 
155cec37a6eSPeter Krystad 	ptr = (const unsigned char *)(th + 1);
156cec37a6eSPeter Krystad 
157cec37a6eSPeter Krystad 	while (length > 0) {
158cec37a6eSPeter Krystad 		int opcode = *ptr++;
159cec37a6eSPeter Krystad 		int opsize;
160cec37a6eSPeter Krystad 
161cec37a6eSPeter Krystad 		switch (opcode) {
162cec37a6eSPeter Krystad 		case TCPOPT_EOL:
163cec37a6eSPeter Krystad 			return;
164cec37a6eSPeter Krystad 		case TCPOPT_NOP:	/* Ref: RFC 793 section 3.1 */
165cec37a6eSPeter Krystad 			length--;
166cec37a6eSPeter Krystad 			continue;
167cec37a6eSPeter Krystad 		default:
168cec37a6eSPeter Krystad 			opsize = *ptr++;
169cec37a6eSPeter Krystad 			if (opsize < 2) /* "silly options" */
170cec37a6eSPeter Krystad 				return;
171cec37a6eSPeter Krystad 			if (opsize > length)
172cec37a6eSPeter Krystad 				return;	/* don't parse partial options */
173cec37a6eSPeter Krystad 			if (opcode == TCPOPT_MPTCP)
174cec37a6eSPeter Krystad 				mptcp_parse_option(ptr, opsize, opt_rx);
175cec37a6eSPeter Krystad 			ptr += opsize - 2;
176cec37a6eSPeter Krystad 			length -= opsize;
177cec37a6eSPeter Krystad 		}
178cec37a6eSPeter Krystad 	}
179cec37a6eSPeter Krystad }
180cec37a6eSPeter Krystad 
181cec37a6eSPeter Krystad bool mptcp_syn_options(struct sock *sk, unsigned int *size,
182cec37a6eSPeter Krystad 		       struct mptcp_out_options *opts)
183cec37a6eSPeter Krystad {
184cec37a6eSPeter Krystad 	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
185cec37a6eSPeter Krystad 
186cec37a6eSPeter Krystad 	if (subflow->request_mptcp) {
187cec37a6eSPeter Krystad 		pr_debug("local_key=%llu", subflow->local_key);
188cec37a6eSPeter Krystad 		opts->suboptions = OPTION_MPTCP_MPC_SYN;
189cec37a6eSPeter Krystad 		opts->sndr_key = subflow->local_key;
190cec37a6eSPeter Krystad 		*size = TCPOLEN_MPTCP_MPC_SYN;
191cec37a6eSPeter Krystad 		return true;
192cec37a6eSPeter Krystad 	}
193cec37a6eSPeter Krystad 	return false;
194cec37a6eSPeter Krystad }
195cec37a6eSPeter Krystad 
196cec37a6eSPeter Krystad void mptcp_rcv_synsent(struct sock *sk)
197cec37a6eSPeter Krystad {
198cec37a6eSPeter Krystad 	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
199cec37a6eSPeter Krystad 	struct tcp_sock *tp = tcp_sk(sk);
200cec37a6eSPeter Krystad 
201cec37a6eSPeter Krystad 	pr_debug("subflow=%p", subflow);
202cec37a6eSPeter Krystad 	if (subflow->request_mptcp && tp->rx_opt.mptcp.mp_capable) {
203cec37a6eSPeter Krystad 		subflow->mp_capable = 1;
204cec37a6eSPeter Krystad 		subflow->remote_key = tp->rx_opt.mptcp.sndr_key;
205cec37a6eSPeter Krystad 	} else {
206cec37a6eSPeter Krystad 		tcp_sk(sk)->is_mptcp = 0;
207cec37a6eSPeter Krystad 	}
208cec37a6eSPeter Krystad }
209cec37a6eSPeter Krystad 
2106d0060f6SMat Martineau static bool mptcp_established_options_mp(struct sock *sk, unsigned int *size,
2116d0060f6SMat Martineau 					 unsigned int remaining,
212cec37a6eSPeter Krystad 					 struct mptcp_out_options *opts)
213cec37a6eSPeter Krystad {
214cec37a6eSPeter Krystad 	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
215cec37a6eSPeter Krystad 
2166d0060f6SMat Martineau 	if (!subflow->fourth_ack) {
217cec37a6eSPeter Krystad 		opts->suboptions = OPTION_MPTCP_MPC_ACK;
218cec37a6eSPeter Krystad 		opts->sndr_key = subflow->local_key;
219cec37a6eSPeter Krystad 		opts->rcvr_key = subflow->remote_key;
220cec37a6eSPeter Krystad 		*size = TCPOLEN_MPTCP_MPC_ACK;
221cec37a6eSPeter Krystad 		subflow->fourth_ack = 1;
222cec37a6eSPeter Krystad 		pr_debug("subflow=%p, local_key=%llu, remote_key=%llu",
223cec37a6eSPeter Krystad 			 subflow, subflow->local_key, subflow->remote_key);
224cec37a6eSPeter Krystad 		return true;
225cec37a6eSPeter Krystad 	}
226cec37a6eSPeter Krystad 	return false;
227cec37a6eSPeter Krystad }
228cec37a6eSPeter Krystad 
2296d0060f6SMat Martineau static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow,
2306d0060f6SMat Martineau 				 struct mptcp_ext *ext)
2316d0060f6SMat Martineau {
2326d0060f6SMat Martineau 	ext->data_fin = 1;
2336d0060f6SMat Martineau 
2346d0060f6SMat Martineau 	if (!ext->use_map) {
2356d0060f6SMat Martineau 		/* RFC6824 requires a DSS mapping with specific values
2366d0060f6SMat Martineau 		 * if DATA_FIN is set but no data payload is mapped
2376d0060f6SMat Martineau 		 */
2386d0060f6SMat Martineau 		ext->use_map = 1;
2396d0060f6SMat Martineau 		ext->dsn64 = 1;
2406d0060f6SMat Martineau 		ext->data_seq = mptcp_sk(subflow->conn)->write_seq;
2416d0060f6SMat Martineau 		ext->subflow_seq = 0;
2426d0060f6SMat Martineau 		ext->data_len = 1;
2436d0060f6SMat Martineau 	} else {
2446d0060f6SMat Martineau 		/* If there's an existing DSS mapping, DATA_FIN consumes
2456d0060f6SMat Martineau 		 * 1 additional byte of mapping space.
2466d0060f6SMat Martineau 		 */
2476d0060f6SMat Martineau 		ext->data_len++;
2486d0060f6SMat Martineau 	}
2496d0060f6SMat Martineau }
2506d0060f6SMat Martineau 
2516d0060f6SMat Martineau static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
2526d0060f6SMat Martineau 					  unsigned int *size,
2536d0060f6SMat Martineau 					  unsigned int remaining,
2546d0060f6SMat Martineau 					  struct mptcp_out_options *opts)
2556d0060f6SMat Martineau {
2566d0060f6SMat Martineau 	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
2576d0060f6SMat Martineau 	unsigned int dss_size = 0;
2586d0060f6SMat Martineau 	struct mptcp_ext *mpext;
2596d0060f6SMat Martineau 	struct mptcp_sock *msk;
2606d0060f6SMat Martineau 	unsigned int ack_size;
2616d0060f6SMat Martineau 	u8 tcp_fin;
2626d0060f6SMat Martineau 
2636d0060f6SMat Martineau 	if (skb) {
2646d0060f6SMat Martineau 		mpext = mptcp_get_ext(skb);
2656d0060f6SMat Martineau 		tcp_fin = TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN;
2666d0060f6SMat Martineau 	} else {
2676d0060f6SMat Martineau 		mpext = NULL;
2686d0060f6SMat Martineau 		tcp_fin = 0;
2696d0060f6SMat Martineau 	}
2706d0060f6SMat Martineau 
2716d0060f6SMat Martineau 	if (!skb || (mpext && mpext->use_map) || tcp_fin) {
2726d0060f6SMat Martineau 		unsigned int map_size;
2736d0060f6SMat Martineau 
2746d0060f6SMat Martineau 		map_size = TCPOLEN_MPTCP_DSS_BASE + TCPOLEN_MPTCP_DSS_MAP64;
2756d0060f6SMat Martineau 
2766d0060f6SMat Martineau 		remaining -= map_size;
2776d0060f6SMat Martineau 		dss_size = map_size;
2786d0060f6SMat Martineau 		if (mpext)
2796d0060f6SMat Martineau 			opts->ext_copy = *mpext;
2806d0060f6SMat Martineau 
2816d0060f6SMat Martineau 		if (skb && tcp_fin &&
2826d0060f6SMat Martineau 		    subflow->conn->sk_state != TCP_ESTABLISHED)
2836d0060f6SMat Martineau 			mptcp_write_data_fin(subflow, &opts->ext_copy);
2846d0060f6SMat Martineau 	}
2856d0060f6SMat Martineau 
2866d0060f6SMat Martineau 	ack_size = TCPOLEN_MPTCP_DSS_ACK64;
2876d0060f6SMat Martineau 
2886d0060f6SMat Martineau 	/* Add kind/length/subtype/flag overhead if mapping is not populated */
2896d0060f6SMat Martineau 	if (dss_size == 0)
2906d0060f6SMat Martineau 		ack_size += TCPOLEN_MPTCP_DSS_BASE;
2916d0060f6SMat Martineau 
2926d0060f6SMat Martineau 	dss_size += ack_size;
2936d0060f6SMat Martineau 
2946d0060f6SMat Martineau 	msk = mptcp_sk(mptcp_subflow_ctx(sk)->conn);
2956d0060f6SMat Martineau 	if (msk) {
2966d0060f6SMat Martineau 		opts->ext_copy.data_ack = msk->ack_seq;
2976d0060f6SMat Martineau 	} else {
2986d0060f6SMat Martineau 		mptcp_crypto_key_sha(mptcp_subflow_ctx(sk)->remote_key,
2996d0060f6SMat Martineau 				     NULL, &opts->ext_copy.data_ack);
3006d0060f6SMat Martineau 		opts->ext_copy.data_ack++;
3016d0060f6SMat Martineau 	}
3026d0060f6SMat Martineau 
3036d0060f6SMat Martineau 	opts->ext_copy.ack64 = 1;
3046d0060f6SMat Martineau 	opts->ext_copy.use_ack = 1;
3056d0060f6SMat Martineau 
3066d0060f6SMat Martineau 	*size = ALIGN(dss_size, 4);
3076d0060f6SMat Martineau 	return true;
3086d0060f6SMat Martineau }
3096d0060f6SMat Martineau 
3106d0060f6SMat Martineau bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
3116d0060f6SMat Martineau 			       unsigned int *size, unsigned int remaining,
3126d0060f6SMat Martineau 			       struct mptcp_out_options *opts)
3136d0060f6SMat Martineau {
3146d0060f6SMat Martineau 	unsigned int opt_size = 0;
3156d0060f6SMat Martineau 	bool ret = false;
3166d0060f6SMat Martineau 
3176d0060f6SMat Martineau 	if (mptcp_established_options_mp(sk, &opt_size, remaining, opts))
3186d0060f6SMat Martineau 		ret = true;
3196d0060f6SMat Martineau 	else if (mptcp_established_options_dss(sk, skb, &opt_size, remaining,
3206d0060f6SMat Martineau 					       opts))
3216d0060f6SMat Martineau 		ret = true;
3226d0060f6SMat Martineau 
3236d0060f6SMat Martineau 	/* we reserved enough space for the above options, and exceeding the
3246d0060f6SMat Martineau 	 * TCP option space would be fatal
3256d0060f6SMat Martineau 	 */
3266d0060f6SMat Martineau 	if (WARN_ON_ONCE(opt_size > remaining))
3276d0060f6SMat Martineau 		return false;
3286d0060f6SMat Martineau 
3296d0060f6SMat Martineau 	*size += opt_size;
3306d0060f6SMat Martineau 	remaining -= opt_size;
3316d0060f6SMat Martineau 
3326d0060f6SMat Martineau 	return ret;
3336d0060f6SMat Martineau }
3346d0060f6SMat Martineau 
335cec37a6eSPeter Krystad bool mptcp_synack_options(const struct request_sock *req, unsigned int *size,
336cec37a6eSPeter Krystad 			  struct mptcp_out_options *opts)
337cec37a6eSPeter Krystad {
338cec37a6eSPeter Krystad 	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
339cec37a6eSPeter Krystad 
340cec37a6eSPeter Krystad 	if (subflow_req->mp_capable) {
341cec37a6eSPeter Krystad 		opts->suboptions = OPTION_MPTCP_MPC_SYNACK;
342cec37a6eSPeter Krystad 		opts->sndr_key = subflow_req->local_key;
343cec37a6eSPeter Krystad 		*size = TCPOLEN_MPTCP_MPC_SYNACK;
344cec37a6eSPeter Krystad 		pr_debug("subflow_req=%p, local_key=%llu",
345cec37a6eSPeter Krystad 			 subflow_req, subflow_req->local_key);
346cec37a6eSPeter Krystad 		return true;
347cec37a6eSPeter Krystad 	}
348cec37a6eSPeter Krystad 	return false;
349cec37a6eSPeter Krystad }
350cec37a6eSPeter Krystad 
351*648ef4b8SMat Martineau void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
352*648ef4b8SMat Martineau 			    struct tcp_options_received *opt_rx)
353*648ef4b8SMat Martineau {
354*648ef4b8SMat Martineau 	struct mptcp_options_received *mp_opt;
355*648ef4b8SMat Martineau 	struct mptcp_ext *mpext;
356*648ef4b8SMat Martineau 
357*648ef4b8SMat Martineau 	mp_opt = &opt_rx->mptcp;
358*648ef4b8SMat Martineau 
359*648ef4b8SMat Martineau 	if (!mp_opt->dss)
360*648ef4b8SMat Martineau 		return;
361*648ef4b8SMat Martineau 
362*648ef4b8SMat Martineau 	mpext = skb_ext_add(skb, SKB_EXT_MPTCP);
363*648ef4b8SMat Martineau 	if (!mpext)
364*648ef4b8SMat Martineau 		return;
365*648ef4b8SMat Martineau 
366*648ef4b8SMat Martineau 	memset(mpext, 0, sizeof(*mpext));
367*648ef4b8SMat Martineau 
368*648ef4b8SMat Martineau 	if (mp_opt->use_map) {
369*648ef4b8SMat Martineau 		mpext->data_seq = mp_opt->data_seq;
370*648ef4b8SMat Martineau 		mpext->subflow_seq = mp_opt->subflow_seq;
371*648ef4b8SMat Martineau 		mpext->data_len = mp_opt->data_len;
372*648ef4b8SMat Martineau 		mpext->use_map = 1;
373*648ef4b8SMat Martineau 		mpext->dsn64 = mp_opt->dsn64;
374*648ef4b8SMat Martineau 	}
375*648ef4b8SMat Martineau 
376*648ef4b8SMat Martineau 	if (mp_opt->use_ack) {
377*648ef4b8SMat Martineau 		mpext->data_ack = mp_opt->data_ack;
378*648ef4b8SMat Martineau 		mpext->use_ack = 1;
379*648ef4b8SMat Martineau 		mpext->ack64 = mp_opt->ack64;
380*648ef4b8SMat Martineau 	}
381*648ef4b8SMat Martineau 
382*648ef4b8SMat Martineau 	mpext->data_fin = mp_opt->data_fin;
383*648ef4b8SMat Martineau }
384*648ef4b8SMat Martineau 
385eda7acddSPeter Krystad void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
386eda7acddSPeter Krystad {
387eda7acddSPeter Krystad 	if ((OPTION_MPTCP_MPC_SYN |
388cec37a6eSPeter Krystad 	     OPTION_MPTCP_MPC_SYNACK |
389eda7acddSPeter Krystad 	     OPTION_MPTCP_MPC_ACK) & opts->suboptions) {
390eda7acddSPeter Krystad 		u8 len;
391eda7acddSPeter Krystad 
392eda7acddSPeter Krystad 		if (OPTION_MPTCP_MPC_SYN & opts->suboptions)
393eda7acddSPeter Krystad 			len = TCPOLEN_MPTCP_MPC_SYN;
394cec37a6eSPeter Krystad 		else if (OPTION_MPTCP_MPC_SYNACK & opts->suboptions)
395cec37a6eSPeter Krystad 			len = TCPOLEN_MPTCP_MPC_SYNACK;
396eda7acddSPeter Krystad 		else
397eda7acddSPeter Krystad 			len = TCPOLEN_MPTCP_MPC_ACK;
398eda7acddSPeter Krystad 
399eda7acddSPeter Krystad 		*ptr++ = htonl((TCPOPT_MPTCP << 24) | (len << 16) |
400eda7acddSPeter Krystad 			       (MPTCPOPT_MP_CAPABLE << 12) |
401eda7acddSPeter Krystad 			       (MPTCP_SUPPORTED_VERSION << 8) |
402eda7acddSPeter Krystad 			       MPTCP_CAP_HMAC_SHA1);
403eda7acddSPeter Krystad 		put_unaligned_be64(opts->sndr_key, ptr);
404eda7acddSPeter Krystad 		ptr += 2;
405eda7acddSPeter Krystad 		if (OPTION_MPTCP_MPC_ACK & opts->suboptions) {
406eda7acddSPeter Krystad 			put_unaligned_be64(opts->rcvr_key, ptr);
407eda7acddSPeter Krystad 			ptr += 2;
408eda7acddSPeter Krystad 		}
409eda7acddSPeter Krystad 	}
4106d0060f6SMat Martineau 
4116d0060f6SMat Martineau 	if (opts->ext_copy.use_ack || opts->ext_copy.use_map) {
4126d0060f6SMat Martineau 		struct mptcp_ext *mpext = &opts->ext_copy;
4136d0060f6SMat Martineau 		u8 len = TCPOLEN_MPTCP_DSS_BASE;
4146d0060f6SMat Martineau 		u8 flags = 0;
4156d0060f6SMat Martineau 
4166d0060f6SMat Martineau 		if (mpext->use_ack) {
4176d0060f6SMat Martineau 			len += TCPOLEN_MPTCP_DSS_ACK64;
4186d0060f6SMat Martineau 			flags = MPTCP_DSS_HAS_ACK | MPTCP_DSS_ACK64;
4196d0060f6SMat Martineau 		}
4206d0060f6SMat Martineau 
4216d0060f6SMat Martineau 		if (mpext->use_map) {
4226d0060f6SMat Martineau 			len += TCPOLEN_MPTCP_DSS_MAP64;
4236d0060f6SMat Martineau 
4246d0060f6SMat Martineau 			/* Use only 64-bit mapping flags for now, add
4256d0060f6SMat Martineau 			 * support for optional 32-bit mappings later.
4266d0060f6SMat Martineau 			 */
4276d0060f6SMat Martineau 			flags |= MPTCP_DSS_HAS_MAP | MPTCP_DSS_DSN64;
4286d0060f6SMat Martineau 			if (mpext->data_fin)
4296d0060f6SMat Martineau 				flags |= MPTCP_DSS_DATA_FIN;
4306d0060f6SMat Martineau 		}
4316d0060f6SMat Martineau 
4326d0060f6SMat Martineau 		*ptr++ = htonl((TCPOPT_MPTCP << 24) |
4336d0060f6SMat Martineau 			       (len  << 16) |
4346d0060f6SMat Martineau 			       (MPTCPOPT_DSS << 12) |
4356d0060f6SMat Martineau 			       (flags));
4366d0060f6SMat Martineau 
4376d0060f6SMat Martineau 		if (mpext->use_ack) {
4386d0060f6SMat Martineau 			put_unaligned_be64(mpext->data_ack, ptr);
4396d0060f6SMat Martineau 			ptr += 2;
4406d0060f6SMat Martineau 		}
4416d0060f6SMat Martineau 
4426d0060f6SMat Martineau 		if (mpext->use_map) {
4436d0060f6SMat Martineau 			put_unaligned_be64(mpext->data_seq, ptr);
4446d0060f6SMat Martineau 			ptr += 2;
4456d0060f6SMat Martineau 			put_unaligned_be32(mpext->subflow_seq, ptr);
4466d0060f6SMat Martineau 			ptr += 1;
4476d0060f6SMat Martineau 			put_unaligned_be32(mpext->data_len << 16 |
4486d0060f6SMat Martineau 					   TCPOPT_NOP << 8 | TCPOPT_NOP, ptr);
4496d0060f6SMat Martineau 		}
4506d0060f6SMat Martineau 	}
451eda7acddSPeter Krystad }
452