xref: /openbmc/linux/net/mptcp/options.c (revision cec37a6e41aae7bf3df9a3da783380a4d9325fd8)
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;
17eda7acddSPeter Krystad 	u8 version;
18eda7acddSPeter Krystad 	u8 flags;
19eda7acddSPeter Krystad 
20eda7acddSPeter Krystad 	switch (subtype) {
21eda7acddSPeter Krystad 	case MPTCPOPT_MP_CAPABLE:
22eda7acddSPeter Krystad 		if (opsize != TCPOLEN_MPTCP_MPC_SYN &&
23eda7acddSPeter Krystad 		    opsize != TCPOLEN_MPTCP_MPC_ACK)
24eda7acddSPeter Krystad 			break;
25eda7acddSPeter Krystad 
26eda7acddSPeter Krystad 		version = *ptr++ & MPTCP_VERSION_MASK;
27eda7acddSPeter Krystad 		if (version != MPTCP_SUPPORTED_VERSION)
28eda7acddSPeter Krystad 			break;
29eda7acddSPeter Krystad 
30eda7acddSPeter Krystad 		flags = *ptr++;
31eda7acddSPeter Krystad 		if (!((flags & MPTCP_CAP_FLAG_MASK) == MPTCP_CAP_HMAC_SHA1) ||
32eda7acddSPeter Krystad 		    (flags & MPTCP_CAP_EXTENSIBILITY))
33eda7acddSPeter Krystad 			break;
34eda7acddSPeter Krystad 
35eda7acddSPeter Krystad 		/* RFC 6824, Section 3.1:
36eda7acddSPeter Krystad 		 * "For the Checksum Required bit (labeled "A"), if either
37eda7acddSPeter Krystad 		 * host requires the use of checksums, checksums MUST be used.
38eda7acddSPeter Krystad 		 * In other words, the only way for checksums not to be used
39eda7acddSPeter Krystad 		 * is if both hosts in their SYNs set A=0."
40eda7acddSPeter Krystad 		 *
41eda7acddSPeter Krystad 		 * Section 3.3.0:
42eda7acddSPeter Krystad 		 * "If a checksum is not present when its use has been
43eda7acddSPeter Krystad 		 * negotiated, the receiver MUST close the subflow with a RST as
44eda7acddSPeter Krystad 		 * it is considered broken."
45eda7acddSPeter Krystad 		 *
46eda7acddSPeter Krystad 		 * We don't implement DSS checksum - fall back to TCP.
47eda7acddSPeter Krystad 		 */
48eda7acddSPeter Krystad 		if (flags & MPTCP_CAP_CHECKSUM_REQD)
49eda7acddSPeter Krystad 			break;
50eda7acddSPeter Krystad 
51eda7acddSPeter Krystad 		mp_opt->mp_capable = 1;
52eda7acddSPeter Krystad 		mp_opt->sndr_key = get_unaligned_be64(ptr);
53eda7acddSPeter Krystad 		ptr += 8;
54eda7acddSPeter Krystad 
55eda7acddSPeter Krystad 		if (opsize == TCPOLEN_MPTCP_MPC_ACK) {
56eda7acddSPeter Krystad 			mp_opt->rcvr_key = get_unaligned_be64(ptr);
57eda7acddSPeter Krystad 			ptr += 8;
58eda7acddSPeter Krystad 			pr_debug("MP_CAPABLE sndr=%llu, rcvr=%llu",
59eda7acddSPeter Krystad 				 mp_opt->sndr_key, mp_opt->rcvr_key);
60eda7acddSPeter Krystad 		} else {
61eda7acddSPeter Krystad 			pr_debug("MP_CAPABLE sndr=%llu", mp_opt->sndr_key);
62eda7acddSPeter Krystad 		}
63eda7acddSPeter Krystad 		break;
64eda7acddSPeter Krystad 
65eda7acddSPeter Krystad 	case MPTCPOPT_DSS:
66eda7acddSPeter Krystad 		pr_debug("DSS");
67eda7acddSPeter Krystad 		mp_opt->dss = 1;
68eda7acddSPeter Krystad 		break;
69eda7acddSPeter Krystad 
70eda7acddSPeter Krystad 	default:
71eda7acddSPeter Krystad 		break;
72eda7acddSPeter Krystad 	}
73eda7acddSPeter Krystad }
74eda7acddSPeter Krystad 
75*cec37a6eSPeter Krystad void mptcp_get_options(const struct sk_buff *skb,
76*cec37a6eSPeter Krystad 		       struct tcp_options_received *opt_rx)
77*cec37a6eSPeter Krystad {
78*cec37a6eSPeter Krystad 	const unsigned char *ptr;
79*cec37a6eSPeter Krystad 	const struct tcphdr *th = tcp_hdr(skb);
80*cec37a6eSPeter Krystad 	int length = (th->doff * 4) - sizeof(struct tcphdr);
81*cec37a6eSPeter Krystad 
82*cec37a6eSPeter Krystad 	ptr = (const unsigned char *)(th + 1);
83*cec37a6eSPeter Krystad 
84*cec37a6eSPeter Krystad 	while (length > 0) {
85*cec37a6eSPeter Krystad 		int opcode = *ptr++;
86*cec37a6eSPeter Krystad 		int opsize;
87*cec37a6eSPeter Krystad 
88*cec37a6eSPeter Krystad 		switch (opcode) {
89*cec37a6eSPeter Krystad 		case TCPOPT_EOL:
90*cec37a6eSPeter Krystad 			return;
91*cec37a6eSPeter Krystad 		case TCPOPT_NOP:	/* Ref: RFC 793 section 3.1 */
92*cec37a6eSPeter Krystad 			length--;
93*cec37a6eSPeter Krystad 			continue;
94*cec37a6eSPeter Krystad 		default:
95*cec37a6eSPeter Krystad 			opsize = *ptr++;
96*cec37a6eSPeter Krystad 			if (opsize < 2) /* "silly options" */
97*cec37a6eSPeter Krystad 				return;
98*cec37a6eSPeter Krystad 			if (opsize > length)
99*cec37a6eSPeter Krystad 				return;	/* don't parse partial options */
100*cec37a6eSPeter Krystad 			if (opcode == TCPOPT_MPTCP)
101*cec37a6eSPeter Krystad 				mptcp_parse_option(ptr, opsize, opt_rx);
102*cec37a6eSPeter Krystad 			ptr += opsize - 2;
103*cec37a6eSPeter Krystad 			length -= opsize;
104*cec37a6eSPeter Krystad 		}
105*cec37a6eSPeter Krystad 	}
106*cec37a6eSPeter Krystad }
107*cec37a6eSPeter Krystad 
108*cec37a6eSPeter Krystad bool mptcp_syn_options(struct sock *sk, unsigned int *size,
109*cec37a6eSPeter Krystad 		       struct mptcp_out_options *opts)
110*cec37a6eSPeter Krystad {
111*cec37a6eSPeter Krystad 	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
112*cec37a6eSPeter Krystad 
113*cec37a6eSPeter Krystad 	if (subflow->request_mptcp) {
114*cec37a6eSPeter Krystad 		pr_debug("local_key=%llu", subflow->local_key);
115*cec37a6eSPeter Krystad 		opts->suboptions = OPTION_MPTCP_MPC_SYN;
116*cec37a6eSPeter Krystad 		opts->sndr_key = subflow->local_key;
117*cec37a6eSPeter Krystad 		*size = TCPOLEN_MPTCP_MPC_SYN;
118*cec37a6eSPeter Krystad 		return true;
119*cec37a6eSPeter Krystad 	}
120*cec37a6eSPeter Krystad 	return false;
121*cec37a6eSPeter Krystad }
122*cec37a6eSPeter Krystad 
123*cec37a6eSPeter Krystad void mptcp_rcv_synsent(struct sock *sk)
124*cec37a6eSPeter Krystad {
125*cec37a6eSPeter Krystad 	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
126*cec37a6eSPeter Krystad 	struct tcp_sock *tp = tcp_sk(sk);
127*cec37a6eSPeter Krystad 
128*cec37a6eSPeter Krystad 	pr_debug("subflow=%p", subflow);
129*cec37a6eSPeter Krystad 	if (subflow->request_mptcp && tp->rx_opt.mptcp.mp_capable) {
130*cec37a6eSPeter Krystad 		subflow->mp_capable = 1;
131*cec37a6eSPeter Krystad 		subflow->remote_key = tp->rx_opt.mptcp.sndr_key;
132*cec37a6eSPeter Krystad 	} else {
133*cec37a6eSPeter Krystad 		tcp_sk(sk)->is_mptcp = 0;
134*cec37a6eSPeter Krystad 	}
135*cec37a6eSPeter Krystad }
136*cec37a6eSPeter Krystad 
137*cec37a6eSPeter Krystad bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
138*cec37a6eSPeter Krystad 			       unsigned int *size, unsigned int remaining,
139*cec37a6eSPeter Krystad 			       struct mptcp_out_options *opts)
140*cec37a6eSPeter Krystad {
141*cec37a6eSPeter Krystad 	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
142*cec37a6eSPeter Krystad 
143*cec37a6eSPeter Krystad 	if (subflow->mp_capable && !subflow->fourth_ack) {
144*cec37a6eSPeter Krystad 		opts->suboptions = OPTION_MPTCP_MPC_ACK;
145*cec37a6eSPeter Krystad 		opts->sndr_key = subflow->local_key;
146*cec37a6eSPeter Krystad 		opts->rcvr_key = subflow->remote_key;
147*cec37a6eSPeter Krystad 		*size = TCPOLEN_MPTCP_MPC_ACK;
148*cec37a6eSPeter Krystad 		subflow->fourth_ack = 1;
149*cec37a6eSPeter Krystad 		pr_debug("subflow=%p, local_key=%llu, remote_key=%llu",
150*cec37a6eSPeter Krystad 			 subflow, subflow->local_key, subflow->remote_key);
151*cec37a6eSPeter Krystad 		return true;
152*cec37a6eSPeter Krystad 	}
153*cec37a6eSPeter Krystad 	return false;
154*cec37a6eSPeter Krystad }
155*cec37a6eSPeter Krystad 
156*cec37a6eSPeter Krystad bool mptcp_synack_options(const struct request_sock *req, unsigned int *size,
157*cec37a6eSPeter Krystad 			  struct mptcp_out_options *opts)
158*cec37a6eSPeter Krystad {
159*cec37a6eSPeter Krystad 	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
160*cec37a6eSPeter Krystad 
161*cec37a6eSPeter Krystad 	if (subflow_req->mp_capable) {
162*cec37a6eSPeter Krystad 		opts->suboptions = OPTION_MPTCP_MPC_SYNACK;
163*cec37a6eSPeter Krystad 		opts->sndr_key = subflow_req->local_key;
164*cec37a6eSPeter Krystad 		*size = TCPOLEN_MPTCP_MPC_SYNACK;
165*cec37a6eSPeter Krystad 		pr_debug("subflow_req=%p, local_key=%llu",
166*cec37a6eSPeter Krystad 			 subflow_req, subflow_req->local_key);
167*cec37a6eSPeter Krystad 		return true;
168*cec37a6eSPeter Krystad 	}
169*cec37a6eSPeter Krystad 	return false;
170*cec37a6eSPeter Krystad }
171*cec37a6eSPeter Krystad 
172eda7acddSPeter Krystad void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
173eda7acddSPeter Krystad {
174eda7acddSPeter Krystad 	if ((OPTION_MPTCP_MPC_SYN |
175*cec37a6eSPeter Krystad 	     OPTION_MPTCP_MPC_SYNACK |
176eda7acddSPeter Krystad 	     OPTION_MPTCP_MPC_ACK) & opts->suboptions) {
177eda7acddSPeter Krystad 		u8 len;
178eda7acddSPeter Krystad 
179eda7acddSPeter Krystad 		if (OPTION_MPTCP_MPC_SYN & opts->suboptions)
180eda7acddSPeter Krystad 			len = TCPOLEN_MPTCP_MPC_SYN;
181*cec37a6eSPeter Krystad 		else if (OPTION_MPTCP_MPC_SYNACK & opts->suboptions)
182*cec37a6eSPeter Krystad 			len = TCPOLEN_MPTCP_MPC_SYNACK;
183eda7acddSPeter Krystad 		else
184eda7acddSPeter Krystad 			len = TCPOLEN_MPTCP_MPC_ACK;
185eda7acddSPeter Krystad 
186eda7acddSPeter Krystad 		*ptr++ = htonl((TCPOPT_MPTCP << 24) | (len << 16) |
187eda7acddSPeter Krystad 			       (MPTCPOPT_MP_CAPABLE << 12) |
188eda7acddSPeter Krystad 			       (MPTCP_SUPPORTED_VERSION << 8) |
189eda7acddSPeter Krystad 			       MPTCP_CAP_HMAC_SHA1);
190eda7acddSPeter Krystad 		put_unaligned_be64(opts->sndr_key, ptr);
191eda7acddSPeter Krystad 		ptr += 2;
192eda7acddSPeter Krystad 		if (OPTION_MPTCP_MPC_ACK & opts->suboptions) {
193eda7acddSPeter Krystad 			put_unaligned_be64(opts->rcvr_key, ptr);
194eda7acddSPeter Krystad 			ptr += 2;
195eda7acddSPeter Krystad 		}
196eda7acddSPeter Krystad 	}
197eda7acddSPeter Krystad }
198