xref: /openbmc/linux/net/mptcp/options.c (revision eda7acddf8080bb2d022a8d4b8b2345eb80c63ec)
1*eda7acddSPeter Krystad // SPDX-License-Identifier: GPL-2.0
2*eda7acddSPeter Krystad /* Multipath TCP
3*eda7acddSPeter Krystad  *
4*eda7acddSPeter Krystad  * Copyright (c) 2017 - 2019, Intel Corporation.
5*eda7acddSPeter Krystad  */
6*eda7acddSPeter Krystad 
7*eda7acddSPeter Krystad #include <linux/kernel.h>
8*eda7acddSPeter Krystad #include <net/tcp.h>
9*eda7acddSPeter Krystad #include <net/mptcp.h>
10*eda7acddSPeter Krystad #include "protocol.h"
11*eda7acddSPeter Krystad 
12*eda7acddSPeter Krystad void mptcp_parse_option(const unsigned char *ptr, int opsize,
13*eda7acddSPeter Krystad 			struct tcp_options_received *opt_rx)
14*eda7acddSPeter Krystad {
15*eda7acddSPeter Krystad 	struct mptcp_options_received *mp_opt = &opt_rx->mptcp;
16*eda7acddSPeter Krystad 	u8 subtype = *ptr >> 4;
17*eda7acddSPeter Krystad 	u8 version;
18*eda7acddSPeter Krystad 	u8 flags;
19*eda7acddSPeter Krystad 
20*eda7acddSPeter Krystad 	switch (subtype) {
21*eda7acddSPeter Krystad 	case MPTCPOPT_MP_CAPABLE:
22*eda7acddSPeter Krystad 		if (opsize != TCPOLEN_MPTCP_MPC_SYN &&
23*eda7acddSPeter Krystad 		    opsize != TCPOLEN_MPTCP_MPC_ACK)
24*eda7acddSPeter Krystad 			break;
25*eda7acddSPeter Krystad 
26*eda7acddSPeter Krystad 		version = *ptr++ & MPTCP_VERSION_MASK;
27*eda7acddSPeter Krystad 		if (version != MPTCP_SUPPORTED_VERSION)
28*eda7acddSPeter Krystad 			break;
29*eda7acddSPeter Krystad 
30*eda7acddSPeter Krystad 		flags = *ptr++;
31*eda7acddSPeter Krystad 		if (!((flags & MPTCP_CAP_FLAG_MASK) == MPTCP_CAP_HMAC_SHA1) ||
32*eda7acddSPeter Krystad 		    (flags & MPTCP_CAP_EXTENSIBILITY))
33*eda7acddSPeter Krystad 			break;
34*eda7acddSPeter Krystad 
35*eda7acddSPeter Krystad 		/* RFC 6824, Section 3.1:
36*eda7acddSPeter Krystad 		 * "For the Checksum Required bit (labeled "A"), if either
37*eda7acddSPeter Krystad 		 * host requires the use of checksums, checksums MUST be used.
38*eda7acddSPeter Krystad 		 * In other words, the only way for checksums not to be used
39*eda7acddSPeter Krystad 		 * is if both hosts in their SYNs set A=0."
40*eda7acddSPeter Krystad 		 *
41*eda7acddSPeter Krystad 		 * Section 3.3.0:
42*eda7acddSPeter Krystad 		 * "If a checksum is not present when its use has been
43*eda7acddSPeter Krystad 		 * negotiated, the receiver MUST close the subflow with a RST as
44*eda7acddSPeter Krystad 		 * it is considered broken."
45*eda7acddSPeter Krystad 		 *
46*eda7acddSPeter Krystad 		 * We don't implement DSS checksum - fall back to TCP.
47*eda7acddSPeter Krystad 		 */
48*eda7acddSPeter Krystad 		if (flags & MPTCP_CAP_CHECKSUM_REQD)
49*eda7acddSPeter Krystad 			break;
50*eda7acddSPeter Krystad 
51*eda7acddSPeter Krystad 		mp_opt->mp_capable = 1;
52*eda7acddSPeter Krystad 		mp_opt->sndr_key = get_unaligned_be64(ptr);
53*eda7acddSPeter Krystad 		ptr += 8;
54*eda7acddSPeter Krystad 
55*eda7acddSPeter Krystad 		if (opsize == TCPOLEN_MPTCP_MPC_ACK) {
56*eda7acddSPeter Krystad 			mp_opt->rcvr_key = get_unaligned_be64(ptr);
57*eda7acddSPeter Krystad 			ptr += 8;
58*eda7acddSPeter Krystad 			pr_debug("MP_CAPABLE sndr=%llu, rcvr=%llu",
59*eda7acddSPeter Krystad 				 mp_opt->sndr_key, mp_opt->rcvr_key);
60*eda7acddSPeter Krystad 		} else {
61*eda7acddSPeter Krystad 			pr_debug("MP_CAPABLE sndr=%llu", mp_opt->sndr_key);
62*eda7acddSPeter Krystad 		}
63*eda7acddSPeter Krystad 		break;
64*eda7acddSPeter Krystad 
65*eda7acddSPeter Krystad 	case MPTCPOPT_DSS:
66*eda7acddSPeter Krystad 		pr_debug("DSS");
67*eda7acddSPeter Krystad 		mp_opt->dss = 1;
68*eda7acddSPeter Krystad 		break;
69*eda7acddSPeter Krystad 
70*eda7acddSPeter Krystad 	default:
71*eda7acddSPeter Krystad 		break;
72*eda7acddSPeter Krystad 	}
73*eda7acddSPeter Krystad }
74*eda7acddSPeter Krystad 
75*eda7acddSPeter Krystad void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
76*eda7acddSPeter Krystad {
77*eda7acddSPeter Krystad 	if ((OPTION_MPTCP_MPC_SYN |
78*eda7acddSPeter Krystad 	     OPTION_MPTCP_MPC_ACK) & opts->suboptions) {
79*eda7acddSPeter Krystad 		u8 len;
80*eda7acddSPeter Krystad 
81*eda7acddSPeter Krystad 		if (OPTION_MPTCP_MPC_SYN & opts->suboptions)
82*eda7acddSPeter Krystad 			len = TCPOLEN_MPTCP_MPC_SYN;
83*eda7acddSPeter Krystad 		else
84*eda7acddSPeter Krystad 			len = TCPOLEN_MPTCP_MPC_ACK;
85*eda7acddSPeter Krystad 
86*eda7acddSPeter Krystad 		*ptr++ = htonl((TCPOPT_MPTCP << 24) | (len << 16) |
87*eda7acddSPeter Krystad 			       (MPTCPOPT_MP_CAPABLE << 12) |
88*eda7acddSPeter Krystad 			       (MPTCP_SUPPORTED_VERSION << 8) |
89*eda7acddSPeter Krystad 			       MPTCP_CAP_HMAC_SHA1);
90*eda7acddSPeter Krystad 		put_unaligned_be64(opts->sndr_key, ptr);
91*eda7acddSPeter Krystad 		ptr += 2;
92*eda7acddSPeter Krystad 		if (OPTION_MPTCP_MPC_ACK & opts->suboptions) {
93*eda7acddSPeter Krystad 			put_unaligned_be64(opts->rcvr_key, ptr);
94*eda7acddSPeter Krystad 			ptr += 2;
95*eda7acddSPeter Krystad 		}
96*eda7acddSPeter Krystad 	}
97*eda7acddSPeter Krystad }
98