From de587f3f0251af54291be97e1caff676937701d3 Mon Sep 17 00:00:00 2001 From: Aomx <aomx@riseup.net> Date: Tue, 12 Jul 2016 18:47:37 +0200 Subject: [PATCH] first commit regarding support of forward-tsn-chunk --- gtests/net/packetdrill/lexer.l | 1 + gtests/net/packetdrill/parser.y | 41 ++++++++- gtests/net/packetdrill/sctp.h | 14 +++ gtests/net/packetdrill/sctp_packet.c | 128 +++++++++++++++++++++++++++ gtests/net/packetdrill/sctp_packet.h | 31 +++++++ 5 files changed, 214 insertions(+), 1 deletion(-) diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index da93842b..0a33a0eb 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -555,6 +555,7 @@ SHUTDOWN_COMPLETE return SHUTDOWN_COMPLETE; I-DATA return I_DATA; PAD return PAD; RECONFIG return RECONFIG; +FORWARD_TSN return FORWARD_TSN; type return TYPE; flgs return FLAGS; len return LEN; diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index dc41710d..e78a2a86 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -472,6 +472,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, struct sctp_u16_list_item *u16_item; struct sctp_sack_block_list_item *sack_block_list_item; struct sctp_sack_block_list *sack_block_list; + struct sctp_forward_tsn_sids_list *forward_tsn_sids_list; + struct sctp_forward_tsn_sids_list_item *forward_tsn_sids_list_item; struct sctp_address_type_list_item *address_type_list_item; struct sctp_address_type_list *address_type_list; struct sctp_parameter_type_list_item *parameter_type_list_item; @@ -519,7 +521,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %token <reserved> SPINFO_MTU GAUTH_ASSOC_ID GAUTH_NUMBER_OF_CHUNKS GAUTH_CHUNKS %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 I_DATA PAD RECONFIG +%token <reserved> SHUTDOWN_COMPLETE I_DATA PAD RECONFIG FORWARD_TSN %token <reserved> TYPE FLAGS LEN %token <reserved> TAG A_RWND OS IS TSN SID SSN MID PPID FSN CUM_TSN GAPS DUPS %token <reserved> PARAMETER HEARTBEAT_INFORMATION IPV4_ADDRESS IPV6_ADDRESS @@ -675,6 +677,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <chunk_list_item> sctp_shutdown_complete_chunk_spec %type <chunk_list_item> sctp_i_data_chunk_spec %type <chunk_list_item> sctp_pad_chunk_spec sctp_reconfig_chunk_spec +%type <chunk_list_item> sctp_forward_tsn_spec %type <parameter_list> opt_parameter_list_spec sctp_parameter_list_spec %type <parameter_list_item> sctp_parameter_spec %type <parameter_list_item> sctp_generic_parameter_spec @@ -722,6 +725,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <u16_item> u16_item %type <sack_block_list> opt_gaps gap_list opt_dups dup_list %type <sack_block_list_item> gap dup +%type <forward_tsn_sids_list> opt_stream_identifier sids_list +%type <forward_tsn_sids_list_item> sid %type <address_type_list> address_types_list %type <address_type_list_item> address_type %type <parameter_type_list> parameter_types_list @@ -1053,6 +1058,7 @@ sctp_chunk_spec | sctp_i_data_chunk_spec { $$ = $1; } | sctp_pad_chunk_spec { $$ = $1; } | sctp_reconfig_chunk_spec { $$ = $1; } +| sctp_forward_tsn_spec { $$ = $1; } ; chunk_type @@ -1122,6 +1128,9 @@ chunk_type | RECONFIG { $$ = SCTP_RECONFIG_CHUNK_TYPE; } +| FORWARD_TSN { + $$ = SCTP_FORWARD_TSN_CHUNK_TYPE; +} ; opt_chunk_type @@ -1564,6 +1573,31 @@ dup } ; +opt_stream_identifier +: SIDS '=' ELLIPSIS { $$ = NULL; } +| SIDS '=' '[' ELLIPSIS ']' { $$ = NULL; } +| SIDS '=' '[' sids_list ']' { $$ = $4; } +; + +sids_list +: { $$ = sctp_forward_tsn_sids_list_new(); } +| sid { $$ =sctp_forward_tsn_sids_list_new(); + sctp_forward_tsn_sids_list_append($$, $1); } +| sids_list ',' sid { $$ = $1; + sctp_forward_tsn_sids_list_append($1, $3); } +; + +sid: INTEGER ':' INTEGER { + if (!is_valid_u16($1)) { + semantic_error("stream identifier out of range"); + } + if (!is_valid_u16($3)) { + semantic_error("stream sequence number out of range"); + } + $$ = sctp_forward_tsn_sids_list_item_new($1, $3); +} +; + sctp_generic_chunk_spec : CHUNK '[' opt_chunk_type ',' opt_flags ',' opt_len ',' opt_val ']' { if (($7 != -1) && @@ -1695,6 +1729,11 @@ sctp_pad_chunk_spec $$ = sctp_pad_chunk_new($3, $5, NULL); } +sctp_forward_tsn_spec +: FORWARD_TSN '[' opt_cum_tsn ',' opt_stream_identifier']' { + $$ = sctp_forward_tsn_chunk_new($3, $5); +} + opt_req_sn : REQ_SN '=' INTEGER { if (!is_valid_u32($3)) { diff --git a/gtests/net/packetdrill/sctp.h b/gtests/net/packetdrill/sctp.h index 0b95445b..7ae514f7 100644 --- a/gtests/net/packetdrill/sctp.h +++ b/gtests/net/packetdrill/sctp.h @@ -55,6 +55,7 @@ struct sctp_common_header { #define SCTP_I_DATA_CHUNK_TYPE 0x40 #define SCTP_RECONFIG_CHUNK_TYPE 0x82 #define SCTP_PAD_CHUNK_TYPE 0x84 +#define SCTP_FORWARD_TSN_CHUNK_TYPE 0xc0 #define MAX_SCTP_CHUNK_BYTES 0xffff @@ -241,6 +242,19 @@ struct sctp_reconfig_chunk { __u8 parameter[]; } __packed; +struct sctp_stream_identifier_block { + __u16 stream; + __u16 stream_sequence; +} __packed; + +struct sctp_forward_tsn_chunk { + __u8 type; + __u8 flags; + __be16 length; + __be32 cum_tsn; + struct sctp_stream_identifier_block stream_identifier_blocks[]; +} __packed; + #define SCTP_HEARTBEAT_INFORMATION_PARAMETER_TYPE 0x0001 #define SCTP_IPV4_ADDRESS_PARAMETER_TYPE 0x0005 #define SCTP_IPV6_ADDRESS_PARAMETER_TYPE 0x0006 diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c index 725d59ba..a0ee2576 100644 --- a/gtests/net/packetdrill/sctp_packet.c +++ b/gtests/net/packetdrill/sctp_packet.c @@ -234,6 +234,65 @@ sctp_sack_block_list_item_dup_new(u32 tsn) return item; } +struct sctp_forward_tsn_sids_list * +sctp_forward_tsn_sids_list_new () { + struct sctp_forward_tsn_sids_list *list; + + list = malloc(sizeof(struct sctp_forward_tsn_sids_list)); + assert(list != NULL); + list->first = NULL; + list->last = NULL; + list->nr_entries = 0; + return list; +} + +void +sctp_forward_tsn_sids_list_append(struct sctp_forward_tsn_sids_list *list, + struct sctp_forward_tsn_sids_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_forward_tsn_sids_list_free (struct sctp_forward_tsn_sids_list *list) { + struct sctp_forward_tsn_sids_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_forward_tsn_sids_list_item * +sctp_forward_tsn_sids_list_item_new(u16 stream_identifier, u16 stream_sequence_number) { + struct sctp_forward_tsn_sids_list_item *item; + + item = malloc(sizeof(struct sctp_forward_tsn_sids_list_item)); + assert(item != NULL); + item->next = NULL; + item->stream_identifier = stream_identifier; + item->stream_sequence_number= stream_sequence_number; + return item; +} + struct sctp_address_type_list * sctp_address_type_list_new(void) { @@ -1283,6 +1342,62 @@ sctp_pad_chunk_new(s64 flgs, s64 len, u8* padding) sctp_cause_list_new()); } +struct sctp_chunk_list_item * +sctp_forward_tsn_chunk_new(u32 cum_tsn, struct sctp_forward_tsn_sids_list *sids) { + struct sctp_forward_tsn_chunk *chunk; + struct sctp_forward_tsn_sids_list_item *item; + + DEBUGP("sctp_forward_tsn_chunk_new called with cum_tsn = %d and sids_list = %p", cum_tsn, sids); + + u32 flags; + u32 length; + u16 i, nr_sids; + + flags = 0; + length = sizeof(struct sctp_forward_tsn_chunk); + if (sids == NULL) { + nr_sids = 0; + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + flags |= FLAG_FORWARD_TSN_CHUNK_SIDS_NOCHECK; + } else { + nr_sids = sids->nr_entries; + length += nr_sids * sizeof(struct sctp_stream_identifier_block); + } + + assert(is_valid_u16(length)); + assert(length % 4 == 0); + chunk = malloc(length); + assert(chunk != NULL); + chunk->type = SCTP_FORWARD_TSN_CHUNK_TYPE; + chunk->flags = 0; + chunk->length = htons(length); + if (cum_tsn == -1) { + chunk->cum_tsn = htonl(0); + flags |= FLAG_FORWARD_TSN_CHUNK_CUM_TSN_NOCHECK; + } else { + chunk->cum_tsn = htonl((u32)cum_tsn); + } + + if (nr_sids == 0 || sids == NULL) { + flags |= FLAG_FORWARD_TSN_CHUNK_SIDS_NOCHECK; + } + + if (sids != NULL) { + for (i = 0, item = sids->first; + (i < nr_sids) && (item != NULL); + i++, item = item->next) { + chunk->stream_identifier_blocks[i].stream= htons(item->stream_identifier); + chunk->stream_identifier_blocks[i].stream_sequence = htons(item->stream_sequence_number); + } + + assert((i == nr_sids) && (item == NULL)); + } + return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, + length, flags, + sctp_parameter_list_new(), + sctp_cause_list_new()); +} + struct sctp_chunk_list_item * sctp_reconfig_chunk_new(s64 flgs, struct sctp_parameter_list *parameters) { @@ -2966,6 +3081,19 @@ new_sctp_packet(int address_family, break; case SCTP_RECONFIG_CHUNK_TYPE: break; + case SCTP_FORWARD_TSN_CHUNK_TYPE: + if (chunk_item->flags & FLAG_FORWARD_TSN_CHUNK_CUM_TSN_NOCHECK) { + asprintf(error, + "cum tsn must be specified for inbound packets"); + return NULL; + } + if (chunk_item->flags & FLAG_FORWARD_TSN_CHUNK_SIDS_NOCHECK) { + // TODO: is this true or are FORWARD-TSN-Chunks that only contain the new cum tsn valid? + asprintf(error, + "at least one stream number and stream sequence number must be specified for inbound packets"); + return NULL; + } + break; default: if (chunk_item->flags & FLAG_CHUNK_TYPE_NOCHECK) { asprintf(error, diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h index 01922281..8d34127f 100644 --- a/gtests/net/packetdrill/sctp_packet.h +++ b/gtests/net/packetdrill/sctp_packet.h @@ -104,6 +104,31 @@ sctp_sack_block_list_item_gap_new(u16 start, u16 end); struct sctp_sack_block_list_item * sctp_sack_block_list_item_dup_new(u32 tsn); +struct sctp_forward_tsn_sids_list_item { + struct sctp_forward_tsn_sids_list_item *next; + u16 stream_identifier; + u16 stream_sequence_number; +}; + +struct sctp_forward_tsn_sids_list { + struct sctp_forward_tsn_sids_list_item *first; + struct sctp_forward_tsn_sids_list_item *last; + u16 nr_entries; +}; + +struct sctp_forward_tsn_sids_list * +sctp_forward_tsn_sids_list_new (); + +void +sctp_forward_tsn_sids_list_append(struct sctp_forward_tsn_sids_list *list, + struct sctp_forward_tsn_sids_list_item *item); + +void sctp_forward_tsn_sids_list_free (struct sctp_forward_tsn_sids_list *list); + +struct sctp_forward_tsn_sids_list_item * +sctp_forward_tsn_sids_list_item_new(u16 stream_identifier, u16 stream_sequence_number); + + struct sctp_address_type_list_item { struct sctp_address_type_list_item *next; u16 address_type; @@ -313,6 +338,12 @@ sctp_i_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 res, s64 mid, struct sctp_chunk_list_item * sctp_pad_chunk_new(s64 flgs, s64 len, u8* padding); +#define FLAG_FORWARD_TSN_CHUNK_CUM_TSN_NOCHECK 0x00000100 +#define FLAG_FORWARD_TSN_CHUNK_SIDS_NOCHECK 0x00000200 + +struct sctp_chunk_list_item * +sctp_forward_tsn_chunk_new(u32 cum_tsn, struct sctp_forward_tsn_sids_list *sids_list); + struct sctp_chunk_list_item * sctp_reconfig_chunk_new(s64 flgs, struct sctp_parameter_list *parameters); -- GitLab