diff --git a/gtests/net/mptcp/fastclose/receive_fastclose_with_ack.pkt b/gtests/net/mptcp/fastclose/receive_fastclose_with_ack.pkt index 286469f3..5875e489 100644 --- a/gtests/net/mptcp/fastclose/receive_fastclose_with_ack.pkt +++ b/gtests/net/mptcp/fastclose/receive_fastclose_with_ack.pkt @@ -25,7 +25,7 @@ // send another ack fastclose, this time with matching key +0.1 < . 2001:2001(0) win 450 // expect peer to reset all subflows now: -+0.01 > R. 1:1(0) ack 2001 ++0.01 > R. 1:1(0) ack 2001 // more data, expect a reset and win0 (no socket anymore) +1.0 < P. 2001:3001(1000) ack 1 win 450 diff --git a/gtests/net/mptcp/fastclose/receive_fastclose_with_ack_multi_v4.pkt b/gtests/net/mptcp/fastclose/receive_fastclose_with_ack_multi_v4.pkt index 93debe67..e973b5ec 100644 --- a/gtests/net/mptcp/fastclose/receive_fastclose_with_ack_multi_v4.pkt +++ b/gtests/net/mptcp/fastclose/receive_fastclose_with_ack_multi_v4.pkt @@ -46,8 +46,8 @@ +0.1 < . 1002:1002(0) win 450 // expect peer to reset both subflows now: -+0.0 > addr[saddr0] > addr[caddr0] R. 1:1(0) ack 1001 -+0.0 > addr[saddr1] > addr[caddr1] R. 1:1(0) ack 1002 ++0.0 > addr[saddr0] > addr[caddr0] R. 1:1(0) ack 1001 ++0.0 > addr[saddr1] > addr[caddr1] R. 1:1(0) ack 1002 +0 read(4, ..., 2002) = 2001 +0 close(4) = 0 diff --git a/gtests/net/mptcp/fastclose/receive_fastclose_with_rst_multi_v4.pkt b/gtests/net/mptcp/fastclose/receive_fastclose_with_rst_multi_v4.pkt index d28bd6b9..74903d6d 100644 --- a/gtests/net/mptcp/fastclose/receive_fastclose_with_rst_multi_v4.pkt +++ b/gtests/net/mptcp/fastclose/receive_fastclose_with_rst_multi_v4.pkt @@ -44,7 +44,7 @@ +0.1 < R. 1002:1002(0) win 450 // expect peer to reset the original flow now: -+0.0 > addr[saddr0] > addr[caddr0] R. 1:1(0) ack 1001 ++0.0 > addr[saddr0] > addr[caddr0] R. 1:1(0) ack 1001 +0 read(4, ..., 2002) = 2001 +0 close(4) = 0 diff --git a/gtests/net/mptcp/mp_join/mp_join_server_bad_token.pkt b/gtests/net/mptcp/mp_join/mp_join_server_bad_token.pkt index 8e120e22..98a503cc 100644 --- a/gtests/net/mptcp/mp_join/mp_join_server_bad_token.pkt +++ b/gtests/net/mptcp/mp_join/mp_join_server_bad_token.pkt @@ -11,5 +11,5 @@ +0 bind(3, ..., ...) = 0 +0 listen(3, 1) = 0 -+0.0 < S 0:0(0) win 65535 -+0.0 > R. 0:0(0) ack 1 ++0.0 < S 0:0(0) win 65535 ++0.0 > R. 0:0(0) ack 1 diff --git a/gtests/net/mptcp/mp_reset/mp_reset_multi_v4.pkt b/gtests/net/mptcp/mp_reset/mp_reset_multi_v4.pkt new file mode 100644 index 00000000..be551729 --- /dev/null +++ b/gtests/net/mptcp/mp_reset/mp_reset_multi_v4.pkt @@ -0,0 +1,56 @@ +// connection initiated by packetdrill +--tolerance_usecs=100000 +`../common/defaults.sh` + ++0 `../common/server.sh` + ++0 socket(..., SOCK_STREAM, IPPROTO_MPTCP) = 3 ++0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + ++0 bind(3, ..., ...) = 0 ++0 listen(3, 1) = 0 ++0.0 < addr[caddr0] > addr[saddr0] S 0:0(0) win 65535 ++0.0 > S. 0:0(0) ack 1 ++0.0 < . 1:1(0) ack 1 win 256 ++0 accept(3, ..., ...) = 4 + +// add_addr ++0.0 > . 1:1(0) ack 1 +// +0.0 < . 1:1(0) ack 1 win 256 + ++0.2 < P. 1:1001(1000) ack 1 win 450 ++0.0 > . 1:1(0) ack 1001 + ++0.2 < P. 1:1(0) ack 1 win 450 ++0.0 > . 1:1(0) ack 1001 + +// add another subflow. ++0.5 < addr[caddr1] > addr[saddr1] S 0:0(0) win 65535 ++0.0 > S. 0:0(0) ack 1 ++0.0 < . 1:1(0) ack 1 win 256 ++0.0 > . 1:1(0) ack 1 + +// send more data. ++0.2 < P. 1:1002(1001) ack 1 win 450 ++0 > . 1:1(0) ack 1002 + +// send rst option. RST is not set, so it should have no effect. ++0 < . 1002:1002(0) win 256 + +// again, this time with RST but out of window. ++0.1 < R. 3001:3001(0) win 450 +// ... expect challenge ack. ++0 > . 1:1(0) ack 1002 + +// again. RST the 2nd subflow. ++0.1 < R. 1002:1002(0) win 450 + +// This should result in a RST, since subflow was closed. ++0.2 < P. 1:1002(1001) ack 1 win 450 ++0 > R 1:1(0) + +// More data. ++0.2 < addr[caddr0] > addr[saddr0] P. 1001:2003(1002) ack 1 win 450 + ++1 read(4, ..., 3004) = 3003 ++0 close(4) = 0 diff --git a/gtests/net/mptcp/mp_reset/mp_reset_single.pkt b/gtests/net/mptcp/mp_reset/mp_reset_single.pkt new file mode 100644 index 00000000..0400dae1 --- /dev/null +++ b/gtests/net/mptcp/mp_reset/mp_reset_single.pkt @@ -0,0 +1,32 @@ +// connection initiated by packetdrill +--tolerance_usecs=100000 +`../common/defaults.sh` + ++0 socket(..., SOCK_STREAM, IPPROTO_MPTCP) = 3 ++0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + ++0 bind(3, ..., ...) = 0 ++0 listen(3, 1) = 0 ++0 < S 0:0(0) win 32792 ++0 > S. 0:0(0) ack 1 ++0.01 < . 1:1(0) ack 1 win 256 ++0 accept(3, ..., ...) = 4 + +// ignore, out of window ++0 < R. 1002:1002(0) win 256 ++0 > . 1:1(0) ack 1 + +// ignore, TCP RST flag not set ++0 < . 1:1(0) win 256 + ++0.0 write(4, ..., 1000) = 1000 ++0 > P. 1:1001(1000) ack 1 ++0 < P. 1:1(0) ack 1001 win 256 + +// should work. ++0 < R. 1:1(0) win 256 + +// probe. SF should be closed... ++0 < . 1:1(0) win 256 +// .. and a reset should be sent. ++0 > R 0:0(0) diff --git a/gtests/net/mptcp/mp_reset/mp_reset_single_tcp.pkt b/gtests/net/mptcp/mp_reset/mp_reset_single_tcp.pkt new file mode 100644 index 00000000..8dc59e6e --- /dev/null +++ b/gtests/net/mptcp/mp_reset/mp_reset_single_tcp.pkt @@ -0,0 +1,32 @@ +// connection initiated by packetdrill +--tolerance_usecs=100000 +`../common/defaults.sh` + ++0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 ++0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + ++0 bind(3, ..., ...) = 0 ++0 listen(3, 1) = 0 ++0 < S 0:0(0) win 32792 ++0 > S. 0:0(0) ack 1 ++0.01 < . 1:1(0) ack 1 win 256 ++0 accept(3, ..., ...) = 4 + +// ignore, out of window ++0 < R. 1002:1002(0) win 256 ++0 > . 1:1(0) ack 1 + +// ignore, TCP RST flag not set ++0 < . 1:1(0) win 256 + ++0.0 write(4, ..., 1000) = 1000 ++0 > P. 1:1001(1000) ack 1 ++0 < P. 1:1(0) ack 1001 win 256 + +// should work. ++0 < R. 1:1(0) win 256 + +// probe. ++0 < . 1:1(0) win 256 +// .. and a reset should be sent. ++0 > R 0:0(0) diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index e274bc4b..0556e9ea 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -246,6 +246,7 @@ flag_e return FLAG_E; flag_f return FLAG_F; flag_g return FLAG_G; flag_h return FLAG_H; +flag_t return FLAG_T; no_flags return NO_FLAGS; nokey return NOKEY; mp_join_syn return MP_JOIN_SYN; @@ -261,6 +262,7 @@ list_id return LIST_ID; mp_prio return MP_PRIO; mp_fail return MP_FAIL; mp_fastclose return MP_FASTCLOSE; +mp_reset return MP_TCPRST; rand return RAND; sender_hmac return SENDER_HMAC; hmac return ADD_ADDR_HMAC; diff --git a/gtests/net/packetdrill/mptcp.h b/gtests/net/packetdrill/mptcp.h index 483ebf23..02a3e1a8 100644 --- a/gtests/net/packetdrill/mptcp.h +++ b/gtests/net/packetdrill/mptcp.h @@ -40,6 +40,7 @@ #define MP_PRIO_SUBTYPE 5 // TODO, Change Subflow Priority #define MP_FAIL_SUBTYPE 6 // TODO #define MP_FASTCLOSE_SUBTYPE 7 // TODO => enhancement +#define MP_TCPRST_SUBTYPE 8 /* MPTCP options subtypes length */ @@ -86,6 +87,8 @@ #define TCPOLEN_MP_FAIL 12 // MP_FASTCLOSE #define TCPOLEN_MP_FASTCLOSE 12 +// MP_RESET +#define TCPOLEN_MP_TCPRST 4 // MPTCP Flags #define MP_CAPABLE_FLAGS 1 #define MP_CAPABLE_FLAGS_CS 129 //With checksum @@ -107,6 +110,8 @@ #define MPTCP_VER_DEFAULT MPTCPV1 +#define MP_TCPRST_FLAG_T 1 + //SUBFLOW states #define ESTABLISHED 1 //for Subflow state #define PRE_ESTABLISHED 0 //Subflow state diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index 66ae0b61..da7ee908 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -845,7 +845,7 @@ struct tcp_option *dss_do_dsn_dack( int dack_type, int dack_val, %token U32 U64 PTR %token ACK ECR EOL MSS NOP SACK SACKOK TIMESTAMP VAL WIN WSCALE %token URG MD5 FAST_OPEN FAST_OPEN_EXP -%token MP_CAPABLE MP_CAPABLE_NO_CS MP_FASTCLOSE FLAG_A FLAG_B FLAG_C FLAG_D FLAG_E FLAG_F FLAG_G FLAG_H NO_FLAGS +%token MP_CAPABLE MP_CAPABLE_NO_CS MP_FASTCLOSE FLAG_A FLAG_B FLAG_C FLAG_D FLAG_E FLAG_F FLAG_G FLAG_H FLAG_T NO_FLAGS %token MPCAPABLE V0 V1 NOKEY MPCDATALEN %token MP_JOIN_SYN MP_JOIN_ACK MP_JOIN_SYN_ACK %token DSS DACK4 DSN4 DACK8 DSN8 FIN SSN DLL NOCS CKSUM ADDR ADDRESS_ID BACKUP TOKEN AUTO RAND @@ -854,6 +854,7 @@ struct tcp_option *dss_do_dsn_dack( int dack_type, int dack_val, %token ADD_ADDRESS ADD_ADDR_IPV4 ADD_ADDR_IPV6 PORT MP_FAIL %token REMOVE_ADDRESS ADDRESSES_ID LIST_ID %token MP_PRIO +%token MP_TCPRST %token TOS FLAGS FLOWLABEL %token ECT0 ECT1 CE ECT01 NO_ECN %token IPV4 IPV6 ICMP UDP RAW GRE MTU ID @@ -883,6 +884,8 @@ struct tcp_option *dss_do_dsn_dack( int dack_type, int dack_val, %type opt_mpls_stack_bottom %type opt_icmp_mtu fin ssn dll dss_checksum %type mp_capable_no_cs is_backup address_id rand port +%type mptcprst_reason mptcprst_flags_list mptcprst_flags mptcprst_flag + %type flag_a flag_b flag_c flag_d flag_e flag_f flag_g flag_h no_flags %type mpc_ver mpc_flags_list mpc_flags mpc_flag mpc_keys mpc_data %type gre_flags_list gre_flags gre_flag @@ -2048,6 +2051,27 @@ mpc_data } ; +mptcprst_reason +: INTEGER { + if(!is_valid_u8($1)) + semantic_error("mp_reset: reason code should be a 8 bits unsigned integer."); + $$ = $1; +} + +mptcprst_flags_list +: FLAGS '[' mptcprst_flags ']' { $$ = $3; } +| { $$ = 0; } +; + +mptcprst_flags +: mptcprst_flag { $$ = $1; } +; + +mptcprst_flag +: NO_FLAGS { $$ = 0; } +| FLAG_T { $$ = MP_TCPRST_FLAG_T; } +; + tcp_option : NOP { $$ = tcp_option_new(TCPOPT_NOP, 1); } | EOL { $$ = tcp_option_new(TCPOPT_EOL, 1); } @@ -2302,6 +2326,14 @@ tcp_option $$->data.mp_prio.flags = $2; $$->data.mp_capable.subtype = MP_PRIO_SUBTYPE; } +| MP_TCPRST mptcprst_reason mptcprst_flags_list { + $$ = tcp_option_new(TCPOPT_MPTCP, TCPOLEN_MP_TCPRST); + $$->data.mp_tcprst.reason = $2; + $$->data.mp_tcprst.flag_transient = ($3 & MP_TCPRST_FLAG_T); + $$->data.mp_tcprst.reserved_bits = ZERO_RESERVED; + + $$->data.mp_capable.subtype = MP_TCPRST_SUBTYPE; +} | MP_FAIL dsn { if($2.type == 4) semantic_error("Value assigned to a MP_FAIL option is not a valid unsigned 64 bits number."); diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c index d2b916a3..67fde65d 100644 --- a/gtests/net/packetdrill/run_packet.c +++ b/gtests/net/packetdrill/run_packet.c @@ -1237,6 +1237,14 @@ bool same_mptcp_opt(struct tcp_option *opt_a, struct tcp_option *opt_b, struct p if(opt_a->data.mp_fastclose.receiver_key != opt_b->data.mp_fastclose.receiver_key) return false; break; + case MP_TCPRST_SUBTYPE: + if(opt_a->data.mp_tcprst.reason != opt_b->data.mp_tcprst.reason) + return false; + if(opt_a->data.mp_tcprst.flag_transient != opt_b->data.mp_tcprst.flag_transient) + return false; + if(opt_a->data.mp_tcprst.reserved_bits != opt_b->data.mp_tcprst.reserved_bits) + return false; + break; default: return false; } diff --git a/gtests/net/packetdrill/tcp_options.h b/gtests/net/packetdrill/tcp_options.h index e82e3d0c..ba8d8755 100644 --- a/gtests/net/packetdrill/tcp_options.h +++ b/gtests/net/packetdrill/tcp_options.h @@ -376,6 +376,25 @@ struct tcp_option { +---------------------------------------------------------------+ */ } __packed mp_fastclose; + struct { + #if __BYTE_ORDER == __LITTLE_ENDIAN + __u8 flag_transient:1, reserved_bits:3; + __u8 subtype:4; + __u8 reason; + #elif __BYTE_ORDER == __BIG_ENDIAN + __u8 subtype:4; + __u8 reserved_bits:3, flag_transient:1; + __u8 reason; + #else + #error "Adjust your defines" + #endif + /* + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +---------------+---------------+-------+-----------------------+ + | Kind | Length |Subtype|U V W T| Reason | + +---------------+---------------+-------+-----------------------+ + */ + } __packed mp_tcprst; /*******END MPTCP options*********/ } data; } __packed; diff --git a/gtests/net/packetdrill/tcp_options_to_string.c b/gtests/net/packetdrill/tcp_options_to_string.c index d8d772c4..716497a9 100644 --- a/gtests/net/packetdrill/tcp_options_to_string.c +++ b/gtests/net/packetdrill/tcp_options_to_string.c @@ -473,6 +473,11 @@ int tcp_options_to_string(struct packet *packet, fprintf(s, "mp_fastclose receiver key: %lu", (unsigned long)option->data.mp_fastclose.receiver_key); break; + case MP_TCPRST_SUBTYPE: + fprintf(s, "mp_reset %u", option->data.mp_tcprst.reason); + if (option->data.mp_tcprst.flag_transient) + fprintf(s, "flags [ flag_t ]"); + break; default: fprintf(s, "unknown MPTCP subtype"); break;