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 | #define TCP_SACK_SEEN (1 << 0) /*1 = peer is SACK capable, */ | 78 | #define TCP_SACK_SEEN (1 << 0) /*1 = peer is SACK capable, */ |
| 79 | #define TCP_DSACK_SEEN (1 << 2) /*1 = DSACK was received from peer*/ | 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 | struct tcp_options_received { | 91 | struct tcp_options_received { |
| 82 | /* PAWS/RTTM data */ | 92 | /* PAWS/RTTM data */ |
| 83 | int ts_recent_stamp;/* Time we stored ts_recent (for aging) */ | 93 | int ts_recent_stamp;/* Time we stored ts_recent (for aging) */ |
| @@ -95,6 +105,9 @@ struct tcp_options_received { · 11 unmodified lines | |||
| 95 | u8 num_sacks; /* Number of SACK blocks */ | 105 | u8 num_sacks; /* Number of SACK blocks */ |
| 96 | u16 user_mss; /* mss requested by user in ioctl */ | 106 | u16 user_mss; /* mss requested by user in ioctl */ |
| 97 | u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ | 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 | static inline void tcp_clear_options(struct tcp_options_received *rx_opt) | 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 | #if IS_ENABLED(CONFIG_SMC) | 117 | #if IS_ENABLED(CONFIG_SMC) |
| 105 | rx_opt->smc_ok = 0; | 118 | rx_opt->smc_ok = 0; |
| 106 | #endif | 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 | /* This is the max number of SACKS that we'll generate and process. It's safe | 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 | #define __NET_MPTCP_H | 9 | #define __NET_MPTCP_H |
| 10 | 10 | ||
| 11 | #include <linux/skbuff.h> | 11 | #include <linux/skbuff.h> |
| 12 | #include <linux/tcp.h> | ||
| 12 | #include <linux/types.h> | 13 | #include <linux/types.h> |
| 13 | 14 | ||
| 14 | /* MPTCP sk_buff extension data */ | 15 | /* MPTCP sk_buff extension data */ |
| @@ -26,10 +27,22 @@ struct mptcp_ext { · 11 unmodified lines | |||
| 26 | /* one byte hole */ | 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 | #ifdef CONFIG_MPTCP | 38 | #ifdef CONFIG_MPTCP |
| 30 | 39 | ||
| 31 | void mptcp_init(void); | 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 | /* move the skb extension owership, with the assumption that 'to' is | 46 | /* move the skb extension owership, with the assumption that 'to' is |
| 34 | * newly allocated | 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 | static inline void mptcp_skb_ext_move(struct sk_buff *to, | 97 | static inline void mptcp_skb_ext_move(struct sk_buff *to, |
| 80 | const struct sk_buff *from) | 98 | const struct sk_buff *from) |
| 81 | { | 99 | { |
| @@ -79,6 +79,7 @@ · 78 unmodified lines | |||
| 79 | #include <trace/events/tcp.h> | 79 | #include <trace/events/tcp.h> |
| 80 | #include <linux/jump_label_ratelimit.h> | 80 | #include <linux/jump_label_ratelimit.h> |
| 81 | #include <net/busy_poll.h> | 81 | #include <net/busy_poll.h> |
| 82 | #include <net/mptcp.h> | ||
| 82 | 83 | ||
| 83 | int sysctl_tcp_max_orphans __read_mostly = NR_FILE; | 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 | break; | 3926 | break; |
| 3926 | #endif | 3927 | #endif |
| 3928 | case TCPOPT_MPTCP: | ||
| 3929 | mptcp_parse_option(ptr, opsize, opt_rx); | ||
| 3930 | break; | ||
| 3931 | |||
| 3927 | case TCPOPT_FASTOPEN: | 3932 | case TCPOPT_FASTOPEN: |
| 3928 | tcp_parse_fastopen_option( | 3933 | tcp_parse_fastopen_option( |
| 3929 | opsize - TCPOLEN_FASTOPEN_BASE, | 3934 | opsize - TCPOLEN_FASTOPEN_BASE, |
| @@ -38,6 +38,7 @@ · 37 unmodified lines | |||
| 38 | #define pr_fmt(fmt) "TCP: " fmt | 38 | #define pr_fmt(fmt) "TCP: " fmt |
| 39 | 39 | ||
| 40 | #include <net/tcp.h> | 40 | #include <net/tcp.h> |
| 41 | #include <net/mptcp.h> | ||
| 41 | 42 | ||
| 42 | #include <linux/compiler.h> | 43 | #include <linux/compiler.h> |
| 43 | #include <linux/gfp.h> | 44 | #include <linux/gfp.h> |
| @@ -414,6 +415,7 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp) · 370 unmodified lines | |||
| 414 | #define OPTION_WSCALE (1 << 3) | 415 | #define OPTION_WSCALE (1 << 3) |
| 415 | #define OPTION_FAST_OPEN_COOKIE (1 << 8) | 416 | #define OPTION_FAST_OPEN_COOKIE (1 << 8) |
| 416 | #define OPTION_SMC (1 << 9) | 417 | #define OPTION_SMC (1 << 9) |
| 418 | #define OPTION_MPTCP (1 << 10) | ||
| 417 | 419 | ||
| 418 | static void smc_options_write(__be32 *ptr, u16 *options) | 420 | static void smc_options_write(__be32 *ptr, u16 *options) |
| 419 | { | 421 | { |
| @@ -439,8 +441,17 @@ struct tcp_out_options { · 19 unmodified lines | |||
| 439 | __u8 *hash_location; /* temporary pointer, overloaded */ | 441 | __u8 *hash_location; /* temporary pointer, overloaded */ |
| 440 | __u32 tsval, tsecr; /* need to include OPTION_TS */ | 442 | __u32 tsval, tsecr; /* need to include OPTION_TS */ |
| 441 | struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ | 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 | /* Write previously computed TCP options to the packet. | 455 | /* Write previously computed TCP options to the packet. |
| 445 | * | 456 | * |
| 446 | * Beware: Something in the Internet is very sensitive to the ordering of | 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 | smc_options_write(ptr, &options); | 562 | smc_options_write(ptr, &options); |
| 563 | |||
| 564 | mptcp_options_write(ptr, opts); | ||
| 552 | } | 565 | } |
| 553 | 566 | ||
| 554 | static void smc_set_option(const struct tcp_sock *tp, | 567 | static void smc_set_option(const struct tcp_sock *tp, |
| @@ -1,4 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | obj-$(CONFIG_MPTCP) += mptcp.o | 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 | #ifndef __MPTCP_PROTOCOL_H | 7 | #ifndef __MPTCP_PROTOCOL_H |
| 8 | #define __MPTCP_PROTOCOL_H | 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 | /* MPTCP connection sock */ | 39 | /* MPTCP connection sock */ |
| 11 | struct mptcp_sock { | 40 | struct mptcp_sock { |
| 12 | /* inet_connection_sock must be the first member */ | 41 | /* inet_connection_sock must be the first member */ |