diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index 3fcb49a0f77bbdf4b4fe84ad51da51e8cca11f33..36fa98fd3991fba1dc7426388cbfc21483e1a65a 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -228,6 +228,7 @@ ECNE return ECNE; CWR return CWR; SHUTDOWN_COMPLETE return SHUTDOWN_COMPLETE; flgs return FLAGS; +len return LEN; tag return TAG; a_rwnd return A_RWND; is return IS; diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index 6dbdf550a2965976c5ebc4f445a1f981eb22ea35..9608afcd7e898601c8e2b32c8de1fa21f592b0ec 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -499,7 +499,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %token <reserved> DATA INIT INIT_ACK HEARTBEAT HEARTBEAT_ACK ABORT %token <reserved> SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECNE CWR %token <reserved> SHUTDOWN_COMPLETE -%token <reserved> FLAGS TAG A_RWND OS IS TSN SID SSN PPID GAPS DUPS +%token <reserved> FLAGS LEN TAG A_RWND OS IS TSN SID SSN PPID GAPS DUPS %token <floating> FLOAT %token <integer> INTEGER HEX_INTEGER %token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR @@ -551,7 +551,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <chunk_list_item> sctp_cookie_echo_chunk_spec sctp_cookie_ack_chunk_spec %type <chunk_list_item> sctp_ecne_chunk_spec sctp_cwr_chunk_spec %type <chunk_list_item> sctp_shutdown_complete_chunk_spec -%type <integer> opt_flags +%type <integer> opt_flags opt_data_chunk_len %type <integer> opt_a_rwnd opt_os opt_is opt_tsn opt_sid opt_ssn opt_ppid %type <sack_block_list> opt_gaps gap_list opt_dups dup_list %type <sack_block_list_item> gap dup @@ -763,13 +763,22 @@ sctp_chunk_spec | sctp_shutdown_complete_chunk_spec { $$ = $1; } ; +opt_data_chunk_len +: { $$ = -1; } +| LEN '=' INTEGER {if (!is_valid_u16($3) || + $3 < sizeof(struct sctp_data_chunk)) { + semantic_error("length value out of range"); + } + $$ = $3; +} + opt_flags : { $$ = -1; } | FLAGS '=' HEX_INTEGER {if (!is_valid_u8($3)) { semantic_error("flags value out of range"); } - $$ = $3;} -; + $$ = $3; +} opt_a_rwnd : { $$ = -1; } @@ -878,8 +887,8 @@ dup ; sctp_data_chunk_spec -: DATA '[' opt_flags opt_tsn opt_sid opt_ssn opt_ppid ']' { - $$ = sctp_data_chunk_new($3, $4, $5, $6, $7); +: DATA '[' opt_flags opt_data_chunk_len opt_tsn opt_sid opt_ssn opt_ppid ']' { + $$ = sctp_data_chunk_new($3, $4, $5, $6, $7, $8); } sctp_init_chunk_spec diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c index 7731e80f39bf8a6967f8b2eee5891e0b22ffa396..8b7817bb31366f5c97401b8ab205a7af9dc9505e 100644 --- a/gtests/net/packetdrill/sctp_packet.c +++ b/gtests/net/packetdrill/sctp_packet.c @@ -126,23 +126,36 @@ sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags) } struct sctp_chunk_list_item * -sctp_data_chunk_new(s64 flgs, s64 tsn, s64 sid, s64 ssn, s64 ppid) +sctp_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 ssn, s64 ppid) { struct sctp_data_chunk *chunk; u32 flags; - u16 payload_len = 1000; + u16 length, padding_length; flags = 0; - chunk = malloc(sizeof(struct sctp_data_chunk) + payload_len); + if (len == -1) { + length = (u16)sizeof(struct sctp_data_chunk); + } else { + length = (u16)len; + } + padding_length = length % 4; + if (padding_length > 0) { + padding_length = 4 - padding_length; + } + chunk = malloc(length + padding_length); assert(chunk != NULL); chunk->type = SCTP_DATA_CHUNK_TYPE; if (flgs == -1) { chunk->flags = 0; flags |= FLAG_CHUNK_FLAGS_NOCHECK; } else { - chunk->flags = (u8)flgs; + chunk->flags = (u8)flgs; + } + chunk->length = htons(length); + if (len == -1) { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + flags |= FLAG_CHUNK_VALUE_NOCHECK; } - chunk->length = htons(sizeof(struct sctp_data_chunk) + payload_len); if (tsn == -1) { chunk->tsn = htonl(0); flags |= FLAG_DATA_CHUNK_TSN_NOCHECK; @@ -167,10 +180,10 @@ sctp_data_chunk_new(s64 flgs, s64 tsn, s64 sid, s64 ssn, s64 ppid) } else { chunk->ppid = htons((u32)ppid); } - memset(chunk->data, 0, payload_len); + memset(chunk->data, 0, + length + padding_length - sizeof(struct sctp_data_chunk)); return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, - (u32)sizeof(struct sctp_data_chunk) + payload_len, - flags); + length, flags); } struct sctp_chunk_list_item * diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h index 6f03fc71360e8baf7567931ae913e7078cc94407..6ac35603d36b5fb834fbb36b8865984ce96020bb 100644 --- a/gtests/net/packetdrill/sctp_packet.h +++ b/gtests/net/packetdrill/sctp_packet.h @@ -86,7 +86,7 @@ sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags); #define FLAG_DATA_CHUNK_PPID_NOCHECK 0x00000800 struct sctp_chunk_list_item * -sctp_data_chunk_new(s64 flgs, s64 tsn, s64 sid, s64 ssn, s64 ppid); +sctp_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 ssn, s64 ppid); #define FLAG_INIT_CHUNK_A_RWND_NOCHECK 0x00000100 #define FLAG_INIT_CHUNK_OS_NOCHECK 0x00000200 diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_active.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_active.pkt index 5b348acaf98ec1cc42ca21bfb6776aa19806a095..c08bb3dffa370a57b44dbafb692fac3dc2d59225 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_active.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_active.pkt @@ -13,15 +13,15 @@ +0.0 > sctp: DATA[tsn=0 sid=0 ssn=0 ppid=0] +0.1 < sctp: SACK[tsn=0 a_rwnd=1500 gaps=[] dups=[]] // Receive some data -+1.0 < sctp: DATA[flgs=0x3 tsn=3 sid=0 ssn=0 ppid=0] // How to handle ++1.0 < sctp: DATA[flgs=0x3 len=1016 tsn=3 sid=0 ssn=0 ppid=0] // How to handle +0.0 read(3, ..., 2000) = 1000 +0.0 > sctp: SACK[tsn=3] // Receive more data, observe delayed SACK -+1.0 < sctp: DATA[flgs=0x0b tsn=4 sid=0 ssn=1 ppid=0] ++1.0 < sctp: DATA[flgs=0x0b len=1016 tsn=4 sid=0 ssn=1 ppid=0] +0.0 read(3, ..., 2000) = 1000 +0.0 > sctp: SACK[tsn=4] // Tear down the association +0.0 close(3) = 0 +0.0 > sctp: SHUTDOWN[tsn=4] +0.1 < sctp: SHUTDOWN_ACK[] -+0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0x01] ++0.0 > sctp: SHUTDOWN_COMPLETE[] diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt index 716c4c4e7be1f0da1536535c1d5e44301b3a3e32..b6b5c711b0fb2a3d5ee56db5f1922864ebcb8e3a 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt @@ -4,7 +4,7 @@ +0.0 listen(3, 1) = 0 +0.0 < sctp: INIT[tag=1 a_rwnd=1500 os=1 is=1 tsn=0] +0.0 > sctp: INIT_ACK[tag=2 tsn=10] // faked cookie -+0.1 < sctp: COOKIE_ECHO[]; DATA[tsn=0 sid=0 ssn=0 ppid=0]// syntax not clear ++0.1 < sctp: COOKIE_ECHO[]; DATA[flgs=0x03 len=1016 tsn=0 sid=0 ssn=0 ppid=0]// syntax not clear +0.0 > sctp: COOKIE_ACK[]; SACK[tsn=0] +0.0 accept(3, ..., ...) = 4 +0.0 read(4, ..., 1000) = 1000 @@ -13,11 +13,11 @@ +0.0 > sctp: DATA[tsn=10 sid=0 ssn=0 ppid=0] +0.1 < sctp: SACK[tsn=10 a_rwnd=1500 gaps=[] dups=[]] // Receive some data -+1.0 < sctp: DATA[tsn=1 sid=0 ssn=1 ppid=0] // How to handle payload? ++1.0 < sctp: DATA[flgs=0x03 len=1016 tsn=1 sid=0 ssn=1 ppid=0] // How to handle payload? +0.0 read(4, ..., 2000) = 1000 +0.2 > sctp: SACK[tsn=1] // Receive more data, observe delayed SACKi -+1.0 < sctp: DATA[tsn=2 sid=0 ssn=2 ppid=0] ++1.0 < sctp: DATA[flgs=0x03 len=1016 tsn=2 sid=0 ssn=2 ppid=0] +0.0 read(4, ..., 2000) = 1000 +0.2 > sctp: SACK[tsn=2] // Tear down the association