Add hooks to parse and format the MP_CAPABLE option. This option is handled according to MPTCP version 0 (RFC6824). MPTCP version 1 MP_CAPABLE (RFC6824bis/RFC8684) will be added later in coordination with related code changes.
Unified · Split
| @@ -78,6 +78,16 @@ struct tcp_sack_block { · 77 unmodified lines | ||
| 78 | 78 | #define TCP_SACK_SEEN (1 << 0) /*1 = peer is SACK capable, */ |
| 79 | 79 | #define TCP_DSACK_SEEN (1 << 2) /*1 = DSACK was received from peer*/ |
| 80 | 80 | |
| 81 | +#if IS_ENABLED(CONFIG_MPTCP) | |
| 82 | +struct mptcp_options_received { | |
| 83 | + u64 sndr_key; | |
| 84 | + u64 rcvr_key; | |
| 85 | + u8 mp_capable : 1, | |
| 86 | + mp_join : 1, | |
| 87 | + dss : 1; | |
| 88 | +}; | |
| 89 | +#endif | |
| 90 | + | |
| 81 | 91 | struct tcp_options_received { |
| 82 | 92 | /* PAWS/RTTM data */ |
| 83 | 93 | int ts_recent_stamp;/* Time we stored ts_recent (for aging) */ |
| @@ -95,6 +105,9 @@ struct tcp_options_received { · 11 unmodified lines | ||
| 95 | 105 | u8 num_sacks; /* Number of SACK blocks */ |
| 96 | 106 | u16 user_mss; /* mss requested by user in ioctl */ |
| 97 | 107 | u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ |
| 108 | +#if IS_ENABLED(CONFIG_MPTCP) | |
| 109 | + struct mptcp_options_received mptcp; | |
| 110 | +#endif | |
| 98 | 111 | }; |
| 99 | 112 | |
| 100 | 113 | static inline void tcp_clear_options(struct tcp_options_received *rx_opt) |
| @@ -104,6 +117,11 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt) · 3 unmodified lines | ||
| 104 | 117 | #if IS_ENABLED(CONFIG_SMC) |
| 105 | 118 | rx_opt->smc_ok = 0; |
| 106 | 119 | #endif |
| 120 | +#if IS_ENABLED(CONFIG_MPTCP) | |
| 121 | + rx_opt->mptcp.mp_capable = 0; | |
| 122 | + rx_opt->mptcp.mp_join = 0; | |
| 123 | + rx_opt->mptcp.dss = 0; | |
| 124 | +#endif | |
| 107 | 125 | } |
| 108 | 126 | |
| 109 | 127 | /* This is the max number of SACKS that we'll generate and process. It's safe |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #define __NET_MPTCP_H |
| 10 | 10 | |
| 11 | 11 | #include <linux/skbuff.h> |
| 12 | +#include <linux/tcp.h> | |
| 12 | 13 | #include <linux/types.h> |
| 13 | 14 | |
| 14 | 15 | /* MPTCP sk_buff extension data */ |
| @@ -26,10 +27,22 @@ struct mptcp_ext { · 11 unmodified lines | ||
| 26 | 27 | /* one byte hole */ |
| 27 | 28 | }; |
| 28 | 29 | |
| 30 | +struct mptcp_out_options { | |
| 31 | +#if IS_ENABLED(CONFIG_MPTCP) | |
| 32 | + u16 suboptions; | |
| 33 | + u64 sndr_key; | |
| 34 | + u64 rcvr_key; | |
| 35 | +#endif | |
| 36 | +}; | |
| 37 | + | |
| 29 | 38 | #ifdef CONFIG_MPTCP |
| 30 | 39 | |
| 31 | 40 | void mptcp_init(void); |
| 32 | 41 | |
| 42 | +void mptcp_parse_option(const unsigned char *ptr, int opsize, | |
| 43 | + struct tcp_options_received *opt_rx); | |
| 44 | +void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts); | |
| 45 | + | |
| 33 | 46 | /* move the skb extension owership, with the assumption that 'to' is |
| 34 | 47 | * newly allocated |
| 35 | 48 | */ |
| @@ -76,6 +89,11 @@ static inline void mptcp_init(void) · 40 unmodified lines | ||
| 76 | 89 | { |
| 77 | 90 | } |
| 78 | 91 | |
| 92 | +static inline void mptcp_parse_option(const unsigned char *ptr, int opsize, | |
| 93 | + struct tcp_options_received *opt_rx) | |
| 94 | +{ | |
| 95 | +} | |
| 96 | + | |
| 79 | 97 | static inline void mptcp_skb_ext_move(struct sk_buff *to, |
| 80 | 98 | const struct sk_buff *from) |
| 81 | 99 | { |
| @@ -79,6 +79,7 @@ · 78 unmodified lines | ||
| 79 | 79 | #include <trace/events/tcp.h> |
| 80 | 80 | #include <linux/jump_label_ratelimit.h> |
| 81 | 81 | #include <net/busy_poll.h> |
| 82 | +#include <net/mptcp.h> | |
| 82 | 83 | |
| 83 | 84 | int sysctl_tcp_max_orphans __read_mostly = NR_FILE; |
| 84 | 85 | |
| @@ -3924,6 +3925,10 @@ void tcp_parse_options(const struct net *net, · 3839 unmodified lines | ||
| 3924 | 3925 | */ |
| 3925 | 3926 | break; |
| 3926 | 3927 | #endif |
| 3928 | + case TCPOPT_MPTCP: | |
| 3929 | + mptcp_parse_option(ptr, opsize, opt_rx); | |
| 3930 | + break; | |
| 3931 | + | |
| 3927 | 3932 | case TCPOPT_FASTOPEN: |
| 3928 | 3933 | tcp_parse_fastopen_option( |
| 3929 | 3934 | opsize - TCPOLEN_FASTOPEN_BASE, |
| @@ -38,6 +38,7 @@ · 37 unmodified lines | ||
| 38 | 38 | #define pr_fmt(fmt) "TCP: " fmt |
| 39 | 39 | |
| 40 | 40 | #include <net/tcp.h> |
| 41 | +#include <net/mptcp.h> | |
| 41 | 42 | |
| 42 | 43 | #include <linux/compiler.h> |
| 43 | 44 | #include <linux/gfp.h> |
| @@ -414,6 +415,7 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp) · 370 unmodified lines | ||
| 414 | 415 | #define OPTION_WSCALE (1 << 3) |
| 415 | 416 | #define OPTION_FAST_OPEN_COOKIE (1 << 8) |
| 416 | 417 | #define OPTION_SMC (1 << 9) |
| 418 | +#define OPTION_MPTCP (1 << 10) | |
| 417 | 419 | |
| 418 | 420 | static void smc_options_write(__be32 *ptr, u16 *options) |
| 419 | 421 | { |
| @@ -439,8 +441,17 @@ struct tcp_out_options { · 19 unmodified lines | ||
| 439 | 441 | __u8 *hash_location; /* temporary pointer, overloaded */ |
| 440 | 442 | __u32 tsval, tsecr; /* need to include OPTION_TS */ |
| 441 | 443 | struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ |
| 444 | + struct mptcp_out_options mptcp; | |
| 442 | 445 | }; |
| 443 | 446 | |
| 447 | +static void mptcp_options_write(__be32 *ptr, struct tcp_out_options *opts) | |
| 448 | +{ | |
| 449 | +#if IS_ENABLED(CONFIG_MPTCP) | |
| 450 | + if (unlikely(OPTION_MPTCP & opts->options)) | |
| 451 | + mptcp_write_options(ptr, &opts->mptcp); | |
| 452 | +#endif | |
| 453 | +} | |
| 454 | + | |
| 444 | 455 | /* Write previously computed TCP options to the packet. |
| 445 | 456 | * |
| 446 | 457 | * Beware: Something in the Internet is very sensitive to the ordering of |
| @@ -549,6 +560,8 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, · 102 unmodified lines | ||
| 549 | 560 | } |
| 550 | 561 | |
| 551 | 562 | smc_options_write(ptr, &options); |
| 563 | + | |
| 564 | + mptcp_options_write(ptr, opts); | |
| 552 | 565 | } |
| 553 | 566 | |
| 554 | 567 | static void smc_set_option(const struct tcp_sock *tp, |
| @@ -1,4 +1,4 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | obj-$(CONFIG_MPTCP) += mptcp.o |
| 3 | 3 | |
| 4 | −mptcp-y := protocol.o | |
| 4 | +mptcp-y := protocol.o options.o | |
| @@ -0,0 +1,97 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* Multipath TCP | |
| 3 | + * | |
| 4 | + * Copyright (c) 2017 - 2019, Intel Corporation. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +#include <linux/kernel.h> | |
| 8 | +#include <net/tcp.h> | |
| 9 | +#include <net/mptcp.h> | |
| 10 | +#include "protocol.h" | |
| 11 | + | |
| 12 | +void mptcp_parse_option(const unsigned char *ptr, int opsize, | |
| 13 | + struct tcp_options_received *opt_rx) | |
| 14 | +{ | |
| 15 | + struct mptcp_options_received *mp_opt = &opt_rx->mptcp; | |
| 16 | + u8 subtype = *ptr >> 4; | |
| 17 | + u8 version; | |
| 18 | + u8 flags; | |
| 19 | + | |
| 20 | + switch (subtype) { | |
| 21 | + case MPTCPOPT_MP_CAPABLE: | |
| 22 | + if (opsize != TCPOLEN_MPTCP_MPC_SYN && | |
| 23 | + opsize != TCPOLEN_MPTCP_MPC_ACK) | |
| 24 | + break; | |
| 25 | + | |
| 26 | + version = *ptr++ & MPTCP_VERSION_MASK; | |
| 27 | + if (version != MPTCP_SUPPORTED_VERSION) | |
| 28 | + break; | |
| 29 | + | |
| 30 | + flags = *ptr++; | |
| 31 | + if (!((flags & MPTCP_CAP_FLAG_MASK) == MPTCP_CAP_HMAC_SHA1) || | |
| 32 | + (flags & MPTCP_CAP_EXTENSIBILITY)) | |
| 33 | + break; | |
| 34 | + | |
| 35 | + /* RFC 6824, Section 3.1: | |
| 36 | + * "For the Checksum Required bit (labeled "A"), if either | |
| 37 | + * host requires the use of checksums, checksums MUST be used. | |
| 38 | + * In other words, the only way for checksums not to be used | |
| 39 | + * is if both hosts in their SYNs set A=0." | |
| 40 | + * | |
| 41 | + * Section 3.3.0: | |
| 42 | + * "If a checksum is not present when its use has been | |
| 43 | + * negotiated, the receiver MUST close the subflow with a RST as | |
| 44 | + * it is considered broken." | |
| 45 | + * | |
| 46 | + * We don't implement DSS checksum - fall back to TCP. | |
| 47 | + */ | |
| 48 | + if (flags & MPTCP_CAP_CHECKSUM_REQD) | |
| 49 | + break; | |
| 50 | + | |
| 51 | + mp_opt->mp_capable = 1; | |
| 52 | + mp_opt->sndr_key = get_unaligned_be64(ptr); | |
| 53 | + ptr += 8; | |
| 54 | + | |
| 55 | + if (opsize == TCPOLEN_MPTCP_MPC_ACK) { | |
| 56 | + mp_opt->rcvr_key = get_unaligned_be64(ptr); | |
| 57 | + ptr += 8; | |
| 58 | + pr_debug("MP_CAPABLE sndr=%llu, rcvr=%llu", | |
| 59 | + mp_opt->sndr_key, mp_opt->rcvr_key); | |
| 60 | + } else { | |
| 61 | + pr_debug("MP_CAPABLE sndr=%llu", mp_opt->sndr_key); | |
| 62 | + } | |
| 63 | + break; | |
| 64 | + | |
| 65 | + case MPTCPOPT_DSS: | |
| 66 | + pr_debug("DSS"); | |
| 67 | + mp_opt->dss = 1; | |
| 68 | + break; | |
| 69 | + | |
| 70 | + default: | |
| 71 | + break; | |
| 72 | + } | |
| 73 | +} | |
| 74 | + | |
| 75 | +void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts) | |
| 76 | +{ | |
| 77 | + if ((OPTION_MPTCP_MPC_SYN | | |
| 78 | + OPTION_MPTCP_MPC_ACK) & opts->suboptions) { | |
| 79 | + u8 len; | |
| 80 | + | |
| 81 | + if (OPTION_MPTCP_MPC_SYN & opts->suboptions) | |
| 82 | + len = TCPOLEN_MPTCP_MPC_SYN; | |
| 83 | + else | |
| 84 | + len = TCPOLEN_MPTCP_MPC_ACK; | |
| 85 | + | |
| 86 | + *ptr++ = htonl((TCPOPT_MPTCP << 24) | (len << 16) | | |
| 87 | + (MPTCPOPT_MP_CAPABLE << 12) | | |
| 88 | + (MPTCP_SUPPORTED_VERSION << 8) | | |
| 89 | + MPTCP_CAP_HMAC_SHA1); | |
| 90 | + put_unaligned_be64(opts->sndr_key, ptr); | |
| 91 | + ptr += 2; | |
| 92 | + if (OPTION_MPTCP_MPC_ACK & opts->suboptions) { | |
| 93 | + put_unaligned_be64(opts->rcvr_key, ptr); | |
| 94 | + ptr += 2; | |
| 95 | + } | |
| 96 | + } | |
| 97 | +} | |
| @@ -7,6 +7,35 @@ · 6 unmodified lines | ||
| 7 | 7 | #ifndef __MPTCP_PROTOCOL_H |
| 8 | 8 | #define __MPTCP_PROTOCOL_H |
| 9 | 9 | |
| 10 | +#define MPTCP_SUPPORTED_VERSION 0 | |
| 11 | + | |
| 12 | +/* MPTCP option bits */ | |
| 13 | +#define OPTION_MPTCP_MPC_SYN BIT(0) | |
| 14 | +#define OPTION_MPTCP_MPC_SYNACK BIT(1) | |
| 15 | +#define OPTION_MPTCP_MPC_ACK BIT(2) | |
| 16 | + | |
| 17 | +/* MPTCP option subtypes */ | |
| 18 | +#define MPTCPOPT_MP_CAPABLE 0 | |
| 19 | +#define MPTCPOPT_MP_JOIN 1 | |
| 20 | +#define MPTCPOPT_DSS 2 | |
| 21 | +#define MPTCPOPT_ADD_ADDR 3 | |
| 22 | +#define MPTCPOPT_RM_ADDR 4 | |
| 23 | +#define MPTCPOPT_MP_PRIO 5 | |
| 24 | +#define MPTCPOPT_MP_FAIL 6 | |
| 25 | +#define MPTCPOPT_MP_FASTCLOSE 7 | |
| 26 | + | |
| 27 | +/* MPTCP suboption lengths */ | |
| 28 | +#define TCPOLEN_MPTCP_MPC_SYN 12 | |
| 29 | +#define TCPOLEN_MPTCP_MPC_SYNACK 12 | |
| 30 | +#define TCPOLEN_MPTCP_MPC_ACK 20 | |
| 31 | + | |
| 32 | +/* MPTCP MP_CAPABLE flags */ | |
| 33 | +#define MPTCP_VERSION_MASK (0x0F) | |
| 34 | +#define MPTCP_CAP_CHECKSUM_REQD BIT(7) | |
| 35 | +#define MPTCP_CAP_EXTENSIBILITY BIT(6) | |
| 36 | +#define MPTCP_CAP_HMAC_SHA1 BIT(0) | |
| 37 | +#define MPTCP_CAP_FLAG_MASK (0x3F) | |
| 38 | + | |
| 10 | 39 | /* MPTCP connection sock */ |
| 11 | 40 | struct mptcp_sock { |
| 12 | 41 | /* inet_connection_sock must be the first member */ |