The MPTCP reset option allows to carry a mptcp-specific error code that provides more information on the nature of a connection reset. Reset option data received gets stored in the subflow context so it can be sent to userspace via the 'subflow closed' netlink event. When a subflow is closed, the desired error code that should be sent to the peer is also placed in the subflow context structure. If a reset is sent before subflow establishment could complete, e.g. on HMAC failure during an MP_JOIN operation, the mptcp skb extension is used to store the reset information.
Unified · Split
| @@ -30,8 +30,8 @@ struct mptcp_ext { · 29 unmodified lines | |||
| 30 | ack64:1, | 30 | ack64:1, |
| 31 | mpc_map:1, | 31 | mpc_map:1, |
| 32 | frozen:1, | 32 | frozen:1, |
| 33 | __unused:1; | 33 | reset_transient:1; |
| 34 | /* one byte hole */ | 34 | u8 reset_reason:4; |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | #define MPTCP_RM_IDS_MAX 8 | 37 | #define MPTCP_RM_IDS_MAX 8 |
| @@ -58,6 +58,8 @@ struct mptcp_out_options { · 20 unmodified lines | |||
| 58 | struct mptcp_rm_list rm_list; | 58 | struct mptcp_rm_list rm_list; |
| 59 | u8 join_id; | 59 | u8 join_id; |
| 60 | u8 backup; | 60 | u8 backup; |
| 61 | u8 reset_reason:4; | ||
| 62 | u8 reset_transient:1; | ||
| 61 | u32 nonce; | 63 | u32 nonce; |
| 62 | u64 thmac; | 64 | u64 thmac; |
| 63 | u32 token; | 65 | u32 token; |
| @@ -156,6 +158,16 @@ void mptcp_seq_show(struct seq_file *seq); · 92 unmodified lines | |||
| 156 | int mptcp_subflow_init_cookie_req(struct request_sock *req, | 158 | int mptcp_subflow_init_cookie_req(struct request_sock *req, |
| 157 | const struct sock *sk_listener, | 159 | const struct sock *sk_listener, |
| 158 | struct sk_buff *skb); | 160 | struct sk_buff *skb); |
| 161 | |||
| 162 | __be32 mptcp_get_reset_option(const struct sk_buff *skb); | ||
| 163 | |||
| 164 | static inline __be32 mptcp_reset_option(const struct sk_buff *skb) | ||
| 165 | { | ||
| 166 | if (skb_ext_exist(skb, SKB_EXT_MPTCP)) | ||
| 167 | return mptcp_get_reset_option(skb); | ||
| 168 | |||
| 169 | return htonl(0u); | ||
| 170 | } | ||
| 159 | #else | 171 | #else |
| 160 | 172 | ||
| 161 | static inline void mptcp_init(void) | 173 | static inline void mptcp_init(void) |
| @@ -236,6 +248,8 @@ static inline int mptcp_subflow_init_cookie_req(struct request_sock *req, · 74 unmodified lines | |||
| 236 | { | 248 | { |
| 237 | return 0; /* TCP fallback */ | 249 | return 0; /* TCP fallback */ |
| 238 | } | 250 | } |
| 251 | |||
| 252 | static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { return htonl(0u); } | ||
| 239 | #endif /* CONFIG_MPTCP */ | 253 | #endif /* CONFIG_MPTCP */ |
| 240 | 254 | ||
| 241 | #if IS_ENABLED(CONFIG_MPTCP_IPV6) | 255 | #if IS_ENABLED(CONFIG_MPTCP_IPV6) |
| @@ -174,10 +174,21 @@ enum mptcp_event_attr { · 173 unmodified lines | |||
| 174 | MPTCP_ATTR_FLAGS, /* u16 */ | 174 | MPTCP_ATTR_FLAGS, /* u16 */ |
| 175 | MPTCP_ATTR_TIMEOUT, /* u32 */ | 175 | MPTCP_ATTR_TIMEOUT, /* u32 */ |
| 176 | MPTCP_ATTR_IF_IDX, /* s32 */ | 176 | MPTCP_ATTR_IF_IDX, /* s32 */ |
| 177 | MPTCP_ATTR_RESET_REASON,/* u32 */ | ||
| 178 | MPTCP_ATTR_RESET_FLAGS, /* u32 */ | ||
| 177 | 179 | ||
| 178 | __MPTCP_ATTR_AFTER_LAST | 180 | __MPTCP_ATTR_AFTER_LAST |
| 179 | }; | 181 | }; |
| 180 | 182 | ||
| 181 | #define MPTCP_ATTR_MAX (__MPTCP_ATTR_AFTER_LAST - 1) | 183 | #define MPTCP_ATTR_MAX (__MPTCP_ATTR_AFTER_LAST - 1) |
| 182 | 184 | ||
| 185 | /* MPTCP Reset reason codes, rfc8684 */ | ||
| 186 | #define MPTCP_RST_EUNSPEC 0 | ||
| 187 | #define MPTCP_RST_EMPTCP 1 | ||
| 188 | #define MPTCP_RST_ERESOURCE 2 | ||
| 189 | #define MPTCP_RST_EPROHIBIT 3 | ||
| 190 | #define MPTCP_RST_EWQ2BIG 4 | ||
| 191 | #define MPTCP_RST_EBADPERF 5 | ||
| 192 | #define MPTCP_RST_EMIDDLEBOX 6 | ||
| 193 | |||
| 183 | #endif /* _UAPI_MPTCP_H */ | 194 | #endif /* _UAPI_MPTCP_H */ |
| @@ -655,14 +655,18 @@ EXPORT_SYMBOL(tcp_v4_send_check); · 654 unmodified lines | |||
| 655 | * Exception: precedence violation. We do not implement it in any case. | 655 | * Exception: precedence violation. We do not implement it in any case. |
| 656 | */ | 656 | */ |
| 657 | 657 | ||
| 658 | #ifdef CONFIG_TCP_MD5SIG | ||
| 659 | #define OPTION_BYTES TCPOLEN_MD5SIG_ALIGNED | ||
| 660 | #else | ||
| 661 | #define OPTION_BYTES sizeof(__be32) | ||
| 662 | #endif | ||
| 663 | |||
| 658 | static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) | 664 | static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) |
| 659 | { | 665 | { |
| 660 | const struct tcphdr *th = tcp_hdr(skb); | 666 | const struct tcphdr *th = tcp_hdr(skb); |
| 661 | struct { | 667 | struct { |
| 662 | struct tcphdr th; | 668 | struct tcphdr th; |
| 663 | #ifdef CONFIG_TCP_MD5SIG | 669 | __be32 opt[OPTION_BYTES / sizeof(__be32)]; |
| 664 | __be32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; | ||
| 665 | #endif | ||
| 666 | } rep; | 670 | } rep; |
| 667 | struct ip_reply_arg arg; | 671 | struct ip_reply_arg arg; |
| 668 | #ifdef CONFIG_TCP_MD5SIG | 672 | #ifdef CONFIG_TCP_MD5SIG |
| @@ -770,6 +774,17 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) · 101 unmodified lines | |||
| 770 | ip_hdr(skb)->daddr, &rep.th); | 774 | ip_hdr(skb)->daddr, &rep.th); |
| 771 | } | 775 | } |
| 772 | #endif | 776 | #endif |
| 777 | /* Can't co-exist with TCPMD5, hence check rep.opt[0] */ | ||
| 778 | if (rep.opt[0] == 0) { | ||
| 779 | __be32 mrst = mptcp_reset_option(skb); | ||
| 780 | |||
| 781 | if (mrst) { | ||
| 782 | rep.opt[0] = mrst; | ||
| 783 | arg.iov[0].iov_len += sizeof(mrst); | ||
| 784 | rep.th.doff = arg.iov[0].iov_len / 4; | ||
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 773 | arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, | 788 | arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, |
| 774 | ip_hdr(skb)->saddr, /* XXX */ | 789 | ip_hdr(skb)->saddr, /* XXX */ |
| 775 | arg.iov[0].iov_len, IPPROTO_TCP, 0); | 790 | arg.iov[0].iov_len, IPPROTO_TCP, 0); |
| @@ -879,8 +879,8 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 · 878 unmodified lines | |||
| 879 | struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); | 879 | struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); |
| 880 | struct sock *ctl_sk = net->ipv6.tcp_sk; | 880 | struct sock *ctl_sk = net->ipv6.tcp_sk; |
| 881 | unsigned int tot_len = sizeof(struct tcphdr); | 881 | unsigned int tot_len = sizeof(struct tcphdr); |
| 882 | __be32 mrst = 0, *topt; | ||
| 882 | struct dst_entry *dst; | 883 | struct dst_entry *dst; |
| 883 | __be32 *topt; | ||
| 884 | __u32 mark = 0; | 884 | __u32 mark = 0; |
| 885 | 885 | ||
| 886 | if (tsecr) | 886 | if (tsecr) |
| @@ -890,6 +890,15 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 · 3 unmodified lines | |||
| 890 | tot_len += TCPOLEN_MD5SIG_ALIGNED; | 890 | tot_len += TCPOLEN_MD5SIG_ALIGNED; |
| 891 | #endif | 891 | #endif |
| 892 | 892 | ||
| 893 | #ifdef CONFIG_MPTCP | ||
| 894 | if (rst && !key) { | ||
| 895 | mrst = mptcp_reset_option(skb); | ||
| 896 | |||
| 897 | if (mrst) | ||
| 898 | tot_len += sizeof(__be32); | ||
| 899 | } | ||
| 900 | #endif | ||
| 901 | |||
| 893 | buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, | 902 | buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, |
| 894 | GFP_ATOMIC); | 903 | GFP_ATOMIC); |
| 895 | if (!buff) | 904 | if (!buff) |
| @@ -920,6 +929,9 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 · 24 unmodified lines | |||
| 920 | *topt++ = htonl(tsecr); | 929 | *topt++ = htonl(tsecr); |
| 921 | } | 930 | } |
| 922 | 931 | ||
| 932 | if (mrst) | ||
| 933 | *topt++ = mrst; | ||
| 934 | |||
| 923 | #ifdef CONFIG_TCP_MD5SIG | 935 | #ifdef CONFIG_TCP_MD5SIG |
| 924 | if (key) { | 936 | if (key) { |
| 925 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | | 937 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | |
| @@ -305,6 +305,18 @@ static void mptcp_parse_option(const struct sk_buff *skb, · 304 unmodified lines | |||
| 305 | mp_opt->fastclose = 1; | 305 | mp_opt->fastclose = 1; |
| 306 | break; | 306 | break; |
| 307 | 307 | ||
| 308 | case MPTCPOPT_RST: | ||
| 309 | if (opsize != TCPOLEN_MPTCP_RST) | ||
| 310 | break; | ||
| 311 | |||
| 312 | if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) | ||
| 313 | break; | ||
| 314 | mp_opt->reset = 1; | ||
| 315 | flags = *ptr++; | ||
| 316 | mp_opt->reset_transient = flags & MPTCP_RST_TRANSIENT; | ||
| 317 | mp_opt->reset_reason = *ptr; | ||
| 318 | break; | ||
| 319 | |||
| 308 | default: | 320 | default: |
| 309 | break; | 321 | break; |
| 310 | } | 322 | } |
| @@ -327,6 +339,7 @@ void mptcp_get_options(const struct sk_buff *skb, · 16 unmodified lines | |||
| 327 | mp_opt->rm_addr = 0; | 339 | mp_opt->rm_addr = 0; |
| 328 | mp_opt->dss = 0; | 340 | mp_opt->dss = 0; |
| 329 | mp_opt->mp_prio = 0; | 341 | mp_opt->mp_prio = 0; |
| 342 | mp_opt->reset = 0; | ||
| 330 | 343 | ||
| 331 | length = (th->doff * 4) - sizeof(struct tcphdr); | 344 | length = (th->doff * 4) - sizeof(struct tcphdr); |
| 332 | ptr = (const unsigned char *)(th + 1); | 345 | ptr = (const unsigned char *)(th + 1); |
| @@ -726,6 +739,22 @@ static bool mptcp_established_options_mp_prio(struct sock *sk, · 393 unmodified lines | |||
| 726 | return true; | 739 | return true; |
| 727 | } | 740 | } |
| 728 | 741 | ||
| 742 | static noinline void mptcp_established_options_rst(struct sock *sk, struct sk_buff *skb, | ||
| 743 | unsigned int *size, | ||
| 744 | unsigned int remaining, | ||
| 745 | struct mptcp_out_options *opts) | ||
| 746 | { | ||
| 747 | const struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); | ||
| 748 | |||
| 749 | if (remaining < TCPOLEN_MPTCP_RST) | ||
| 750 | return; | ||
| 751 | |||
| 752 | *size = TCPOLEN_MPTCP_RST; | ||
| 753 | opts->suboptions |= OPTION_MPTCP_RST; | ||
| 754 | opts->reset_transient = subflow->reset_transient; | ||
| 755 | opts->reset_reason = subflow->reset_reason; | ||
| 756 | } | ||
| 757 | |||
| 729 | bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, | 758 | bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, |
| 730 | unsigned int *size, unsigned int remaining, | 759 | unsigned int *size, unsigned int remaining, |
| 731 | struct mptcp_out_options *opts) | 760 | struct mptcp_out_options *opts) |
| @@ -741,11 +770,10 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, · 9 unmodified lines | |||
| 741 | if (unlikely(__mptcp_check_fallback(msk))) | 770 | if (unlikely(__mptcp_check_fallback(msk))) |
| 742 | return false; | 771 | return false; |
| 743 | 772 | ||
| 744 | /* prevent adding of any MPTCP related options on reset packet | 773 | if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) { |
| 745 | * until we support MP_TCPRST/MP_FASTCLOSE | 774 | mptcp_established_options_rst(sk, skb, size, remaining, opts); |
| 746 | */ | 775 | return true; |
| 747 | if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) | 776 | } |
| 748 | return false; | ||
| 749 | 777 | ||
| 750 | snd_data_fin = mptcp_data_fin_enabled(msk); | 778 | snd_data_fin = mptcp_data_fin_enabled(msk); |
| 751 | if (mptcp_established_options_mp(sk, skb, snd_data_fin, &opt_size, remaining, opts)) | 779 | if (mptcp_established_options_mp(sk, skb, snd_data_fin, &opt_size, remaining, opts)) |
| @@ -1062,6 +1090,12 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) · 310 unmodified lines | |||
| 1062 | mp_opt.mp_prio = 0; | 1090 | mp_opt.mp_prio = 0; |
| 1063 | } | 1091 | } |
| 1064 | 1092 | ||
| 1093 | if (mp_opt.reset) { | ||
| 1094 | subflow->reset_seen = 1; | ||
| 1095 | subflow->reset_reason = mp_opt.reset_reason; | ||
| 1096 | subflow->reset_transient = mp_opt.reset_transient; | ||
| 1097 | } | ||
| 1098 | |||
| 1065 | if (!mp_opt.dss) | 1099 | if (!mp_opt.dss) |
| 1066 | return; | 1100 | return; |
| 1067 | 1101 | ||
| @@ -1289,6 +1323,12 @@ mp_capable_done: · 221 unmodified lines | |||
| 1289 | ptr += 5; | 1323 | ptr += 5; |
| 1290 | } | 1324 | } |
| 1291 | 1325 | ||
| 1326 | if (OPTION_MPTCP_RST & opts->suboptions) | ||
| 1327 | *ptr++ = mptcp_option(MPTCPOPT_RST, | ||
| 1328 | TCPOLEN_MPTCP_RST, | ||
| 1329 | opts->reset_transient, | ||
| 1330 | opts->reset_reason); | ||
| 1331 | |||
| 1292 | if (opts->ext_copy.use_ack || opts->ext_copy.use_map) { | 1332 | if (opts->ext_copy.use_ack || opts->ext_copy.use_map) { |
| 1293 | struct mptcp_ext *mpext = &opts->ext_copy; | 1333 | struct mptcp_ext *mpext = &opts->ext_copy; |
| 1294 | u8 len = TCPOLEN_MPTCP_DSS_BASE; | 1334 | u8 len = TCPOLEN_MPTCP_DSS_BASE; |
| @@ -1340,3 +1380,20 @@ mp_capable_done: · 45 unmodified lines | |||
| 1340 | if (tp) | 1380 | if (tp) |
| 1341 | mptcp_set_rwin(tp); | 1381 | mptcp_set_rwin(tp); |
| 1342 | } | 1382 | } |
| 1383 | |||
| 1384 | __be32 mptcp_get_reset_option(const struct sk_buff *skb) | ||
| 1385 | { | ||
| 1386 | const struct mptcp_ext *ext = mptcp_get_ext(skb); | ||
| 1387 | u8 flags, reason; | ||
| 1388 | |||
| 1389 | if (ext) { | ||
| 1390 | flags = ext->reset_transient; | ||
| 1391 | reason = ext->reset_reason; | ||
| 1392 | |||
| 1393 | return mptcp_option(MPTCPOPT_RST, TCPOLEN_MPTCP_RST, | ||
| 1394 | flags, reason); | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | return htonl(0u); | ||
| 1398 | } | ||
| 1399 | EXPORT_SYMBOL_GPL(mptcp_get_reset_option); | ||
| @@ -1687,9 +1687,21 @@ static int mptcp_event_sub_closed(struct sk_buff *skb, · 1686 unmodified lines | |||
| 1687 | const struct mptcp_sock *msk, | 1687 | const struct mptcp_sock *msk, |
| 1688 | const struct sock *ssk) | 1688 | const struct sock *ssk) |
| 1689 | { | 1689 | { |
| 1690 | const struct mptcp_subflow_context *sf; | ||
| 1691 | |||
| 1690 | if (mptcp_event_put_token_and_ssk(skb, msk, ssk)) | 1692 | if (mptcp_event_put_token_and_ssk(skb, msk, ssk)) |
| 1691 | return -EMSGSIZE; | 1693 | return -EMSGSIZE; |
| 1692 | 1694 | ||
| 1695 | sf = mptcp_subflow_ctx(ssk); | ||
| 1696 | if (!sf->reset_seen) | ||
| 1697 | return 0; | ||
| 1698 | |||
| 1699 | if (nla_put_u32(skb, MPTCP_ATTR_RESET_REASON, sf->reset_reason)) | ||
| 1700 | return -EMSGSIZE; | ||
| 1701 | |||
| 1702 | if (nla_put_u32(skb, MPTCP_ATTR_RESET_FLAGS, sf->reset_transient)) | ||
| 1703 | return -EMSGSIZE; | ||
| 1704 | |||
| 1693 | return 0; | 1705 | return 0; |
| 1694 | } | 1706 | } |
| 1695 | 1707 | ||
| @@ -3090,14 +3090,18 @@ bool mptcp_finish_join(struct sock *ssk) · 3089 unmodified lines | |||
| 3090 | pr_debug("msk=%p, subflow=%p", msk, subflow); | 3090 | pr_debug("msk=%p, subflow=%p", msk, subflow); |
| 3091 | 3091 | ||
| 3092 | /* mptcp socket already closing? */ | 3092 | /* mptcp socket already closing? */ |
| 3093 | if (!mptcp_is_fully_established(parent)) | 3093 | if (!mptcp_is_fully_established(parent)) { |
| 3094 | subflow->reset_reason = MPTCP_RST_EMPTCP; | ||
| 3094 | return false; | 3095 | return false; |
| 3096 | } | ||
| 3095 | 3097 | ||
| 3096 | if (!msk->pm.server_side) | 3098 | if (!msk->pm.server_side) |
| 3097 | goto out; | 3099 | goto out; |
| 3098 | 3100 | ||
| 3099 | if (!mptcp_pm_allow_new_subflow(msk)) | 3101 | if (!mptcp_pm_allow_new_subflow(msk)) { |
| 3102 | subflow->reset_reason = MPTCP_RST_EPROHIBIT; | ||
| 3100 | return false; | 3103 | return false; |
| 3104 | } | ||
| 3101 | 3105 | ||
| 3102 | /* active connections are already on conn_list, and we can't acquire | 3106 | /* active connections are already on conn_list, and we can't acquire |
| 3103 | * msk lock here. | 3107 | * msk lock here. |
| @@ -3111,8 +3115,10 @@ bool mptcp_finish_join(struct sock *ssk) · 7 unmodified lines | |||
| 3111 | sock_hold(ssk); | 3115 | sock_hold(ssk); |
| 3112 | } | 3116 | } |
| 3113 | spin_unlock_bh(&msk->join_list_lock); | 3117 | spin_unlock_bh(&msk->join_list_lock); |
| 3114 | if (!ret) | 3118 | if (!ret) { |
| 3119 | subflow->reset_reason = MPTCP_RST_EPROHIBIT; | ||
| 3115 | return false; | 3120 | return false; |
| 3121 | } | ||
| 3116 | 3122 | ||
| 3117 | /* attach to msk socket only after we are sure he will deal with us | 3123 | /* attach to msk socket only after we are sure he will deal with us |
| 3118 | * at close time | 3124 | * at close time |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | |||
| 26 | #define OPTION_MPTCP_RM_ADDR BIT(8) | 26 | #define OPTION_MPTCP_RM_ADDR BIT(8) |
| 27 | #define OPTION_MPTCP_FASTCLOSE BIT(9) | 27 | #define OPTION_MPTCP_FASTCLOSE BIT(9) |
| 28 | #define OPTION_MPTCP_PRIO BIT(10) | 28 | #define OPTION_MPTCP_PRIO BIT(10) |
| 29 | #define OPTION_MPTCP_RST BIT(11) | ||
| 29 | 30 | ||
| 30 | /* MPTCP option subtypes */ | 31 | /* MPTCP option subtypes */ |
| 31 | #define MPTCPOPT_MP_CAPABLE 0 | 32 | #define MPTCPOPT_MP_CAPABLE 0 |
| @@ -36,6 +37,7 @@ · 4 unmodified lines | |||
| 36 | #define MPTCPOPT_MP_PRIO 5 | 37 | #define MPTCPOPT_MP_PRIO 5 |
| 37 | #define MPTCPOPT_MP_FAIL 6 | 38 | #define MPTCPOPT_MP_FAIL 6 |
| 38 | #define MPTCPOPT_MP_FASTCLOSE 7 | 39 | #define MPTCPOPT_MP_FASTCLOSE 7 |
| 40 | #define MPTCPOPT_RST 8 | ||
| 39 | 41 | ||
| 40 | /* MPTCP suboption lengths */ | 42 | /* MPTCP suboption lengths */ |
| 41 | #define TCPOLEN_MPTCP_MPC_SYN 4 | 43 | #define TCPOLEN_MPTCP_MPC_SYN 4 |
| @@ -65,6 +67,7 @@ · 23 unmodified lines | |||
| 65 | #define TCPOLEN_MPTCP_PRIO 3 | 67 | #define TCPOLEN_MPTCP_PRIO 3 |
| 66 | #define TCPOLEN_MPTCP_PRIO_ALIGN 4 | 68 | #define TCPOLEN_MPTCP_PRIO_ALIGN 4 |
| 67 | #define TCPOLEN_MPTCP_FASTCLOSE 12 | 69 | #define TCPOLEN_MPTCP_FASTCLOSE 12 |
| 70 | #define TCPOLEN_MPTCP_RST 4 | ||
| 68 | 71 | ||
| 69 | /* MPTCP MP_JOIN flags */ | 72 | /* MPTCP MP_JOIN flags */ |
| 70 | #define MPTCPOPT_BACKUP BIT(0) | 73 | #define MPTCPOPT_BACKUP BIT(0) |
| @@ -94,6 +97,9 @@ · 23 unmodified lines | |||
| 94 | /* MPTCP MP_PRIO flags */ | 97 | /* MPTCP MP_PRIO flags */ |
| 95 | #define MPTCP_PRIO_BKUP BIT(0) | 98 | #define MPTCP_PRIO_BKUP BIT(0) |
| 96 | 99 | ||
| 100 | /* MPTCP TCPRST flags */ | ||
| 101 | #define MPTCP_RST_TRANSIENT BIT(0) | ||
| 102 | |||
| 97 | /* MPTCP socket flags */ | 103 | /* MPTCP socket flags */ |
| 98 | #define MPTCP_DATA_READY 0 | 104 | #define MPTCP_DATA_READY 0 |
| 99 | #define MPTCP_NOSPACE 1 | 105 | #define MPTCP_NOSPACE 1 |
| @@ -123,6 +129,7 @@ struct mptcp_options_received { · 23 unmodified lines | |||
| 123 | u16 mp_capable : 1, | 129 | u16 mp_capable : 1, |
| 124 | mp_join : 1, | 130 | mp_join : 1, |
| 125 | fastclose : 1, | 131 | fastclose : 1, |
| 132 | reset : 1, | ||
| 126 | dss : 1, | 133 | dss : 1, |
| 127 | add_addr : 1, | 134 | add_addr : 1, |
| 128 | rm_addr : 1, | 135 | rm_addr : 1, |
| @@ -152,6 +159,8 @@ struct mptcp_options_received { · 23 unmodified lines | |||
| 152 | }; | 159 | }; |
| 153 | u64 ahmac; | 160 | u64 ahmac; |
| 154 | u16 port; | 161 | u16 port; |
| 162 | u8 reset_reason:4; | ||
| 163 | u8 reset_transient:1; | ||
| 155 | }; | 164 | }; |
| 156 | 165 | ||
| 157 | static inline __be32 mptcp_option(u8 subopt, u8 len, u8 nib, u8 field) | 166 | static inline __be32 mptcp_option(u8 subopt, u8 len, u8 nib, u8 field) |
| @@ -422,6 +431,9 @@ struct mptcp_subflow_context { · 264 unmodified lines | |||
| 422 | u8 hmac[MPTCPOPT_HMAC_LEN]; | 431 | u8 hmac[MPTCPOPT_HMAC_LEN]; |
| 423 | u8 local_id; | 432 | u8 local_id; |
| 424 | u8 remote_id; | 433 | u8 remote_id; |
| 434 | u8 reset_seen:1; | ||
| 435 | u8 reset_transient:1; | ||
| 436 | u8 reset_reason:4; | ||
| 425 | 437 | ||
| 426 | long delegated_status; | 438 | long delegated_status; |
| 427 | struct list_head delegated_node; /* link into delegated_action, protected by local BH */ | 439 | struct list_head delegated_node; /* link into delegated_action, protected by local BH */ |
| @@ -742,7 +754,7 @@ unsigned int mptcp_pm_get_add_addr_accept_max(struct mptcp_sock *msk); · 314 unmodified lines | |||
| 742 | unsigned int mptcp_pm_get_subflows_max(struct mptcp_sock *msk); | 754 | unsigned int mptcp_pm_get_subflows_max(struct mptcp_sock *msk); |
| 743 | unsigned int mptcp_pm_get_local_addr_max(struct mptcp_sock *msk); | 755 | unsigned int mptcp_pm_get_local_addr_max(struct mptcp_sock *msk); |
| 744 | 756 | ||
| 745 | static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb) | 757 | static inline struct mptcp_ext *mptcp_get_ext(const struct sk_buff *skb) |
| 746 | { | 758 | { |
| 747 | return (struct mptcp_ext *)skb_ext_find(skb, SKB_EXT_MPTCP); | 759 | return (struct mptcp_ext *)skb_ext_find(skb, SKB_EXT_MPTCP); |
| 748 | } | 760 | } |
| @@ -115,6 +115,16 @@ static bool subflow_use_different_sport(struct mptcp_sock *msk, const struct soc · 114 unmodified lines | |||
| 115 | return inet_sk(sk)->inet_sport != inet_sk((struct sock *)msk)->inet_sport; | 115 | return inet_sk(sk)->inet_sport != inet_sk((struct sock *)msk)->inet_sport; |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | static void subflow_add_reset_reason(struct sk_buff *skb, u8 reason) | ||
| 119 | { | ||
| 120 | struct mptcp_ext *mpext = skb_ext_add(skb, SKB_EXT_MPTCP); | ||
| 121 | |||
| 122 | if (mpext) { | ||
| 123 | memset(mpext, 0, sizeof(*mpext)); | ||
| 124 | mpext->reset_reason = reason; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 118 | /* Init mptcp request socket. | 128 | /* Init mptcp request socket. |
| 119 | * | 129 | * |
| 120 | * Returns an error code if a JOIN has failed and a TCP reset | 130 | * Returns an error code if a JOIN has failed and a TCP reset |
| @@ -190,8 +200,10 @@ again: · 69 unmodified lines | |||
| 190 | subflow_req->msk = subflow_token_join_request(req); | 200 | subflow_req->msk = subflow_token_join_request(req); |
| 191 | 201 | ||
| 192 | /* Can't fall back to TCP in this case. */ | 202 | /* Can't fall back to TCP in this case. */ |
| 193 | if (!subflow_req->msk) | 203 | if (!subflow_req->msk) { |
| 204 | subflow_add_reset_reason(skb, MPTCP_RST_EMPTCP); | ||
| 194 | return -EPERM; | 205 | return -EPERM; |
| 206 | } | ||
| 195 | 207 | ||
| 196 | if (subflow_use_different_sport(subflow_req->msk, sk_listener)) { | 208 | if (subflow_use_different_sport(subflow_req->msk, sk_listener)) { |
| 197 | pr_debug("syn inet_sport=%d %d", | 209 | pr_debug("syn inet_sport=%d %d", |
| @@ -400,8 +412,10 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) · 202 unmodified lines | |||
| 400 | } else if (subflow->request_join) { | 412 | } else if (subflow->request_join) { |
| 401 | u8 hmac[SHA256_DIGEST_SIZE]; | 413 | u8 hmac[SHA256_DIGEST_SIZE]; |
| 402 | 414 | ||
| 403 | if (!mp_opt.mp_join) | 415 | if (!mp_opt.mp_join) { |
| 416 | subflow->reset_reason = MPTCP_RST_EMPTCP; | ||
| 404 | goto do_reset; | 417 | goto do_reset; |
| 418 | } | ||
| 405 | 419 | ||
| 406 | subflow->thmac = mp_opt.thmac; | 420 | subflow->thmac = mp_opt.thmac; |
| 407 | subflow->remote_nonce = mp_opt.nonce; | 421 | subflow->remote_nonce = mp_opt.nonce; |
| @@ -410,6 +424,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) · 2 unmodified lines | |||
| 410 | 424 | ||
| 411 | if (!subflow_thmac_valid(subflow)) { | 425 | if (!subflow_thmac_valid(subflow)) { |
| 412 | MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKMAC); | 426 | MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKMAC); |
| 427 | subflow->reset_reason = MPTCP_RST_EMPTCP; | ||
| 413 | goto do_reset; | 428 | goto do_reset; |
| 414 | } | 429 | } |
| 415 | 430 | ||
| @@ -438,6 +453,7 @@ fallback: · 22 unmodified lines | |||
| 438 | return; | 453 | return; |
| 439 | 454 | ||
| 440 | do_reset: | 455 | do_reset: |
| 456 | subflow->reset_transient = 0; | ||
| 441 | mptcp_subflow_reset(sk); | 457 | mptcp_subflow_reset(sk); |
| 442 | } | 458 | } |
| 443 | 459 | ||
| @@ -654,8 +670,10 @@ create_child: · 210 unmodified lines | |||
| 654 | * to reset the context to non MPTCP status. | 670 | * to reset the context to non MPTCP status. |
| 655 | */ | 671 | */ |
| 656 | if (!ctx || fallback) { | 672 | if (!ctx || fallback) { |
| 657 | if (fallback_is_fatal) | 673 | if (fallback_is_fatal) { |
| 674 | subflow_add_reset_reason(skb, MPTCP_RST_EMPTCP); | ||
| 658 | goto dispose_child; | 675 | goto dispose_child; |
| 676 | } | ||
| 659 | 677 | ||
| 660 | subflow_drop_ctx(child); | 678 | subflow_drop_ctx(child); |
| 661 | goto out; | 679 | goto out; |
| @@ -690,8 +708,10 @@ create_child: · 28 unmodified lines | |||
| 690 | struct mptcp_sock *owner; | 708 | struct mptcp_sock *owner; |
| 691 | 709 | ||
| 692 | owner = subflow_req->msk; | 710 | owner = subflow_req->msk; |
| 693 | if (!owner) | 711 | if (!owner) { |
| 712 | subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT); | ||
| 694 | goto dispose_child; | 713 | goto dispose_child; |
| 714 | } | ||
| 695 | 715 | ||
| 696 | /* move the msk reference ownership to the subflow */ | 716 | /* move the msk reference ownership to the subflow */ |
| 697 | subflow_req->msk = NULL; | 717 | subflow_req->msk = NULL; |
| @@ -1056,6 +1076,8 @@ fatal: · 358 unmodified lines | |||
| 1056 | smp_wmb(); | 1076 | smp_wmb(); |
| 1057 | ssk->sk_error_report(ssk); | 1077 | ssk->sk_error_report(ssk); |
| 1058 | tcp_set_state(ssk, TCP_CLOSE); | 1078 | tcp_set_state(ssk, TCP_CLOSE); |
| 1079 | subflow->reset_transient = 0; | ||
| 1080 | subflow->reset_reason = MPTCP_RST_EMPTCP; | ||
| 1059 | tcp_send_active_reset(ssk, GFP_ATOMIC); | 1081 | tcp_send_active_reset(ssk, GFP_ATOMIC); |
| 1060 | subflow->data_avail = 0; | 1082 | subflow->data_avail = 0; |
| 1061 | return false; | 1083 | return false; |