diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index e462478e282b7d5d8055b223a2e3ba784263e24e..ecf60c4d6272ff7b49e9ee95a51c6acb6fbff3c1 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -212,6 +212,7 @@ sinit_num_ostreams return SINIT_NUM_OSTREAMS; sinit_max_instreams return SINIT_MAX_INSTREAMS; sinit_max_attempts return SINIT_MAX_ATTEMPTS; sinit_max_init_timeo return SINIT_MAX_INIT_TIMEO; +CHUNK return CHUNK; DATA return DATA; INIT return INIT; INIT_ACK return INIT_ACK; @@ -228,6 +229,7 @@ ECNE return ECNE; CWR return CWR; SHUTDOWN_COMPLETE return SHUTDOWN_COMPLETE; PAD return PAD; +type return TYPE; flgs return FLAGS; len return LEN; tag return TAG; diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index da6c940c9cc0da85e00d891a0a031a89aa47e8fc..f11d5410da6af35adf00d938233ba777bcabf68d 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -466,6 +466,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, struct packet *packet; struct sctp_chunk_list_item *chunk_list_item; struct sctp_chunk_list *chunk_list; + struct sctp_byte_list_item *byte_list_item; + struct sctp_byte_list *byte_list; struct sctp_sack_block_list_item *sack_block_list_item; struct sctp_sack_block_list *sack_block_list; struct sctp_address_type_list_item *address_type_list_item; @@ -501,10 +503,11 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %token <reserved> SINIT_MAX_INIT_TIMEO %token <reserved> ASSOC_VALUE %token <reserved> SACK_DELAY SACK_FREQ -%token <reserved> DATA INIT INIT_ACK HEARTBEAT HEARTBEAT_ACK ABORT +%token <reserved> CHUNK DATA INIT INIT_ACK HEARTBEAT HEARTBEAT_ACK ABORT %token <reserved> SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECNE CWR %token <reserved> SHUTDOWN_COMPLETE PAD -%token <reserved> FLAGS LEN TAG A_RWND OS IS TSN SID SSN PPID CUM_TSN GAPS DUPS +%token <reserved> TYPE FLAGS LEN +%token <reserved> TAG A_RWND OS IS TSN SID SSN PPID CUM_TSN GAPS DUPS %token <reserved> HEARTBEAT_INFORMATION IPV4_ADDRESS IPV6_ADDRESS STATE_COOKIE %token <reserved> UNRECOGNIZED_PARAMETER COOKIE_PRESERVATIVE HOSTNAME_ADDRESS %token <reserved> SUPPORTED_ADDRESS_TYPES ECN_CAPABLE @@ -550,6 +553,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <errno_info> opt_errno %type <chunk_list> sctp_chunk_list_spec %type <chunk_list_item> sctp_chunk_spec +%type <chunk_list_item> sctp_generic_chunk_spec %type <chunk_list_item> sctp_data_chunk_spec %type <chunk_list_item> sctp_init_chunk_spec sctp_init_ack_chunk_spec %type <chunk_list_item> sctp_sack_chunk_spec @@ -574,11 +578,12 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <parameter_list_item> sctp_supported_address_types_parameter_spec %type <parameter_list_item> sctp_ecn_capable_parameter_spec %type <parameter_list_item> sctp_pad_parameter_spec - -%type <integer> opt_flags opt_data_flags opt_abort_flags +%type <integer> opt_chunk_type opt_flags opt_data_flags opt_abort_flags %type <integer> opt_shutdown_complete_flags opt_chunk_len %type <integer> opt_tag opt_a_rwnd opt_os opt_is opt_tsn opt_sid opt_ssn %type <integer> opt_cum_tsn opt_ppid +%type <byte_list> opt_val byte_list +%type <byte_list_item> byte %type <sack_block_list> opt_gaps gap_list opt_dups dup_list %type <sack_block_list_item> gap dup %type <address_type_list> address_types_list @@ -774,7 +779,8 @@ sctp_chunk_list_spec ; sctp_chunk_spec -: sctp_data_chunk_spec { $$ = $1; } +: sctp_generic_chunk_spec { $$ = $1; } +| sctp_data_chunk_spec { $$ = $1; } | sctp_init_chunk_spec { $$ = $1; } | sctp_init_ack_chunk_spec { $$ = $1; } | sctp_sack_chunk_spec { $$ = $1; } @@ -792,13 +798,19 @@ sctp_chunk_spec | sctp_pad_chunk_spec { $$ = $1; } ; -opt_chunk_len -: LEN '=' ELLIPSIS { $$ = -1; } -| LEN '=' INTEGER { - if (!is_valid_u16($3)) { - semantic_error("length value out of range"); +opt_chunk_type +: TYPE '=' ELLIPSIS { $$ = -1; } +| TYPE '=' HEX_INTEGER { + if (!is_valid_u8($3)) { + semantic_error("type value out of range"); } - $$ = $3; + $$ = $3; +} +| TYPE '=' INTEGER { + if (!is_valid_u8($3)) { + semantic_error("type value out of range"); + } + $$ = $3; } ; @@ -818,6 +830,45 @@ opt_flags } ; +opt_chunk_len +: LEN '=' ELLIPSIS { $$ = -1; } +| LEN '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("length value out of range"); + } + $$ = $3; +} +; + +opt_val +: VAL '=' ELLIPSIS { $$ = NULL; } +| VAL '=' '[' ELLIPSIS ']' { $$ = NULL; } +| VAL '=' '[' byte_list ']' { $$ = $4; } +; + +byte_list +: { $$ = sctp_byte_list_new(); } +| byte { $$ = sctp_byte_list_new(); + sctp_byte_list_append($$, $1); } +| byte_list ',' byte { $$ = $1; + sctp_byte_list_append($1, $3); } +; + +byte +: HEX_INTEGER { + if (!is_valid_u8($1)) { + semantic_error("byte value out of range"); + } + $$ = sctp_byte_list_item_new($1); +} +| INTEGER { + if (!is_valid_u8($1)) { + semantic_error("byte value out of range"); + } + $$ = sctp_byte_list_item_new($1); +} +; + opt_data_flags : FLAGS '=' ELLIPSIS { $$ = -1; } | FLAGS '=' HEX_INTEGER { @@ -924,7 +975,7 @@ opt_shutdown_complete_flags | FLAGS '=' INTEGER { if (!is_valid_u8($3)) { semantic_error("flags value out of range"); - } + } $$ = $3; } | FLAGS '=' WORD { @@ -1089,6 +1140,21 @@ dup } ; +sctp_generic_chunk_spec +: CHUNK '[' opt_chunk_type ',' opt_flags ',' opt_chunk_len ',' opt_val ']' { + if (($7 != -1) && ($7 < sizeof(struct sctp_chunk))) { + semantic_error("length value out of range"); + } + if (($7 != -1) && ($9 != NULL) && + ($7 != sizeof(struct sctp_chunk) + $9->nr_entries)) { + semantic_error("length value incompatible with val"); + } + if (($7 == -1) && ($9 != NULL)) { + semantic_error("length needs to be specified"); + } + $$ = sctp_generic_chunk_new($3, $5, $7, $9); +} + sctp_data_chunk_spec : DATA '[' opt_data_flags ',' opt_chunk_len ',' opt_tsn ',' opt_sid ',' opt_ssn ',' opt_ppid ']' { if (($5 != -1) && ($5 < sizeof(struct sctp_data_chunk))) { diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c index f3eec362655eafa63504e269afc32c5fb498f740..4ca10243af80244cca5712b36db24c188e985a72 100644 --- a/gtests/net/packetdrill/sctp_packet.c +++ b/gtests/net/packetdrill/sctp_packet.c @@ -29,10 +29,72 @@ /* * ToDo: - * - Add support for parameters (fix hard coded state cookie in INIT-ACK) * - Add support for error causes */ +struct sctp_byte_list * +sctp_byte_list_new(void) +{ + struct sctp_byte_list *list; + + list = malloc(sizeof(struct sctp_byte_list)); + assert(list != NULL); + list->first = NULL; + list->last = NULL; + list->nr_entries = 0; + return list; +} + +void +sctp_byte_list_append(struct sctp_byte_list *list, + struct sctp_byte_list_item *item) +{ + assert(item->next == NULL); + if (list->last == NULL) { + assert(list->first == NULL); + assert(list->nr_entries == 0); + list->first = item; + } else { + assert(list->first != NULL); + list->last->next = item; + } + list->last = item; + list->nr_entries++; +} + +void +sctp_byte_list_free(struct sctp_byte_list *list) +{ + struct sctp_byte_list_item *current_item, *next_item; + + if (list == NULL) { + return; + } + current_item = list->first; + while (current_item != NULL) { + assert(list->nr_entries > 0); + next_item = current_item->next; + assert(next_item != NULL || current_item == list->last); + free(current_item); + current_item = next_item; + list->nr_entries--; + } + assert(list->nr_entries == 0); + free(list); +} + +struct sctp_byte_list_item * +sctp_byte_list_item_new(u8 byte) +{ + struct sctp_byte_list_item *item; + + item = malloc(sizeof(struct sctp_byte_list_item)); + assert(item != NULL); + item->next = NULL; + item->byte = byte; + return item; +} + struct sctp_sack_block_list * sctp_sack_block_list_new(void) { @@ -188,6 +250,64 @@ sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags, return item; } +struct sctp_chunk_list_item * +sctp_generic_chunk_new(s64 type, s64 flgs, s64 len, + struct sctp_byte_list *bytes) +{ + struct sctp_chunk *chunk; + struct sctp_byte_list_item *item; + u32 flags; + u16 length, padding_length, i; + + flags = 0; + if (bytes == NULL) { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + flags |= FLAG_CHUNK_VALUE_NOCHECK; + } + if (len == -1) { + length = (u16)sizeof(struct sctp_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); + if (type == -1) { + chunk->type = 0; + flags |= FLAG_CHUNK_TYPE_NOCHECK; + } else { + chunk->type = (u8)type; + } + if (flgs == -1) { + chunk->flags = 0; + flags |= FLAG_CHUNK_FLAGS_NOCHECK; + } else { + chunk->flags = (u8)flgs; + } + chunk->length = htons(length); + if (len == -1) { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + flags |= FLAG_CHUNK_VALUE_NOCHECK; + } + if (bytes != NULL) { + for (i = 0, item = bytes->first; + item != NULL; + i++, item = item->next) { + chunk->value[i] = item->byte; + } + } else { + memset(chunk->value, 0, length - sizeof(struct sctp_chunk)); + } + memset(chunk->value + (length - sizeof(struct sctp_chunk)), + 0, padding_length); + return sctp_chunk_list_item_new(chunk, + length + padding_length, + flags, sctp_parameter_list_new()); +} + struct sctp_chunk_list_item * sctp_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 ssn, s64 ppid) { @@ -1535,8 +1655,22 @@ new_sctp_packet(int address_family, } break; default: - asprintf(error, "Unknown chunk type 0x%02x", chunk_item->chunk->type); - return NULL; + if (chunk_item->flags & FLAG_CHUNK_TYPE_NOCHECK) { + asprintf(error, + "chunk type must be specified for inbound packets"); + return NULL; + } + if (chunk_item->flags & FLAG_CHUNK_FLAGS_NOCHECK) { + asprintf(error, + "chunk flags must be specified for inbound packets"); + return NULL; + } + if (chunk_item->flags & FLAG_CHUNK_LENGTH_NOCHECK) { + asprintf(error, + "chunk length must be specified for inbound packets"); + return NULL; + } + break; } } } diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h index 51b0bcc9e15e270ee3cfa31ee62d8d9a44907ade..b8cc7ef1581ec2acf22866287c4b1f6ee3eb1e5e 100644 --- a/gtests/net/packetdrill/sctp_packet.h +++ b/gtests/net/packetdrill/sctp_packet.h @@ -29,6 +29,30 @@ #include "packet.h" #include "sctp.h" +struct sctp_byte_list_item { + struct sctp_byte_list_item *next; + u8 byte; +}; + +struct sctp_byte_list { + struct sctp_byte_list_item *first; + struct sctp_byte_list_item *last; + u16 nr_entries; +}; + +struct sctp_byte_list * +sctp_byte_list_new(void); + +void +sctp_byte_list_append(struct sctp_byte_list *list, + struct sctp_byte_list_item *item); + +void +sctp_byte_list_free(struct sctp_byte_list *list); + +struct sctp_byte_list_item * +sctp_byte_list_item_new(u8 byte); + struct sctp_sack_block_list_item { struct sctp_sack_block_list_item *next; union sctp_sack_block block; @@ -113,14 +137,18 @@ struct sctp_chunk_list { u32 length; }; +struct sctp_chunk_list_item * +sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags, + struct sctp_parameter_list *list); + #define FLAG_CHUNK_TYPE_NOCHECK 0x00000001 #define FLAG_CHUNK_FLAGS_NOCHECK 0x00000002 #define FLAG_CHUNK_LENGTH_NOCHECK 0x00000004 #define FLAG_CHUNK_VALUE_NOCHECK 0x00000008 struct sctp_chunk_list_item * -sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags, - struct sctp_parameter_list *list); +sctp_generic_chunk_new(s64 type, s64 flgs, s64 len, + struct sctp_byte_list *bytes); #define FLAG_DATA_CHUNK_TSN_NOCHECK 0x00000100 #define FLAG_DATA_CHUNK_SID_NOCHECK 0x00000200