From 90924bfd58f9fb27512e20483c60b32819c865b6 Mon Sep 17 00:00:00 2001 From: Julian Cordes <julian.cordes@gmail.com> Date: Fri, 22 Jul 2016 15:12:45 +0200 Subject: [PATCH] first commit regarding i_foward_tsn chunk support --- gtests/net/packetdrill/parser.y | 46 +++++++++- gtests/net/packetdrill/sctp.h | 16 ++++ gtests/net/packetdrill/sctp_packet.c | 124 +++++++++++++++++++++++++++ gtests/net/packetdrill/sctp_packet.h | 31 +++++++ 4 files changed, 214 insertions(+), 3 deletions(-) diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index f2bc2b49..e35640e3 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -474,6 +474,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, struct sctp_sack_block_list *sack_block_list; struct sctp_forward_tsn_ids_list *forward_tsn_ids_list; struct sctp_forward_tsn_ids_list_item *forward_tsn_ids_list_item; + struct sctp_i_forward_tsn_ids_list *i_forward_tsn_ids_list; + struct sctp_i_forward_tsn_ids_list_item *i_forward_tsn_ids_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; @@ -521,7 +523,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 FORWARD_TSN +%token <reserved> SHUTDOWN_COMPLETE I_DATA PAD RECONFIG FORWARD_TSN I_FORWARD_TSN %token <reserved> TYPE FLAGS LEN %token <reserved> TAG A_RWND OS IS TSN SID SSN MID PPID FSN CUM_TSN GAPS NR_GAPS DUPS %token <reserved> PARAMETER HEARTBEAT_INFORMATION IPV4_ADDRESS IPV6_ADDRESS @@ -677,7 +679,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 <chunk_list_item> sctp_forward_tsn_spec sctp_i_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 @@ -726,8 +728,10 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <u16_item> u16_item %type <sack_block_list> opt_gaps opt_nr_gaps gap_list opt_dups dup_list %type <sack_block_list_item> gap dup -%type <forward_tsn_ids_list> opt_stream_identifier ids_list +%type <forward_tsn_ids_list> opt_stream_identifier ids_list %type <forward_tsn_ids_list_item> id +%type <i_forward_tsn_ids_list> opt_i_forward_tsn_stream_identifier i_forward_tsn_ids_list +%type <i_forward_tsn_ids_list_item> i_forward_tsn_id %type <address_type_list> address_types_list %type <address_type_list_item> address_type %type <parameter_type_list> parameter_types_list @@ -1061,6 +1065,7 @@ sctp_chunk_spec | sctp_pad_chunk_spec { $$ = $1; } | sctp_reconfig_chunk_spec { $$ = $1; } | sctp_forward_tsn_spec { $$ = $1; } +| sctp_i_forward_tsn_spec { $$ = $1; } ; chunk_type @@ -1610,6 +1615,36 @@ id } ; +opt_i_forward_tsn_stream_identifier +: IDS '=' ELLIPSIS { $$ = NULL; } +| IDS '=' '[' ELLIPSIS ']' { $$ = NULL; } +| IDS '=' '[' i_forward_tsn_ids_list ']' { $$ = $4; } +; + +i_forward_tsn_ids_list +: { $$ = sctp_i_forward_tsn_ids_list_new(); } +| i_forward_tsn_id { $$ =sctp_i_forward_tsn_ids_list_new(); + sctp_i_forward_tsn_ids_list_append($$, $1); } +| i_forward_tsn_ids_list ',' i_forward_tsn_id { $$ = $1; + sctp_i_forward_tsn_ids_list_append($1, $3); } +; + +i_forward_tsn_id +: '{' WORD ',' INTEGER ',' INTEGER '}' { + char *c = $2; + if (*c != 'O' || *c != 'U') { + semantic_error("either O for ordered or U for unordered must be specified"); + } + if (!is_valid_u16($4)) { + semantic_error("stream identifier out of range"); + } + if (!is_valid_u16($6)) { + semantic_error("stream sequence number out of range"); + } + $$ = sctp_i_forward_tsn_ids_list_item_new(*c, $4, $6); +} +; + sctp_generic_chunk_spec : CHUNK '[' opt_chunk_type ',' opt_flags ',' opt_len ',' opt_val ']' { if (($7 != -1) && @@ -1752,6 +1787,11 @@ sctp_forward_tsn_spec $$ = sctp_forward_tsn_chunk_new($3, $5); } +sctp_i_forward_tsn_spec +: I_FORWARD_TSN '[' opt_cum_tsn ',' opt_i_forward_tsn_stream_identifier']' { + $$ = sctp_i_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 6a17a416..e8d0650b 100644 --- a/gtests/net/packetdrill/sctp.h +++ b/gtests/net/packetdrill/sctp.h @@ -57,6 +57,8 @@ struct sctp_common_header { #define SCTP_RECONFIG_CHUNK_TYPE 0x82 #define SCTP_PAD_CHUNK_TYPE 0x84 #define SCTP_FORWARD_TSN_CHUNK_TYPE 0xc0 +#define SCTP_I_FORWARD_TSN_CHUNK_TYPE 0xc2 + #define MAX_SCTP_CHUNK_BYTES 0xffff @@ -281,6 +283,20 @@ struct sctp_forward_tsn_chunk { struct sctp_stream_identifier_block stream_identifier_blocks[]; } __packed; +struct sctp_i_forward_tsn_identifier_block { + __u16 stream_identifier; + __u16 reserved; + __u32 message_identifier; +}; + +struct sctp_i_forward_tsn_chunk { + __u8 type; + __u8 flags; + __be16 length; + __be32 cum_tsn; + struct sctp_i_forward_tsn_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 ad704891..866abba6 100644 --- a/gtests/net/packetdrill/sctp_packet.c +++ b/gtests/net/packetdrill/sctp_packet.c @@ -293,6 +293,66 @@ sctp_forward_tsn_ids_list_item_new(u16 stream_identifier, u16 stream_sequence_nu return item; } +struct sctp_i_forward_tsn_ids_list * +sctp_i_forward_tsn_ids_list_new () { + struct sctp_i_forward_tsn_ids_list *list; + + list = malloc(sizeof(struct sctp_i_forward_tsn_ids_list)); + assert(list != NULL); + list->first = NULL; + list->last = NULL; + list->nr_entries = 0; + return list; +} + +void +sctp_i_forward_tsn_ids_list_append(struct sctp_i_forward_tsn_ids_list *list, + struct sctp_i_forward_tsn_ids_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_i_forward_tsn_ids_list_free (struct sctp_i_forward_tsn_ids_list *list) { + struct sctp_i_forward_tsn_ids_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_i_forward_tsn_ids_list_item * +sctp_i_forward_tsn_ids_list_item_new(char u_bit_set, u16 stream_identifier, u32 message_identifier) { + struct sctp_i_forward_tsn_ids_list_item *item; + + item = malloc(sizeof(struct sctp_i_forward_tsn_ids_list_item)); + assert(item != NULL); + item->next = NULL; + item->stream_identifier = stream_identifier; + item->u_bit_set = u_bit_set; + item->message_identifier = message_identifier; + return item; +} + struct sctp_address_type_list * sctp_address_type_list_new(void) { @@ -1495,6 +1555,70 @@ sctp_forward_tsn_chunk_new(u32 cum_tsn, struct sctp_forward_tsn_ids_list *sids) sctp_cause_list_new()); } +struct sctp_chunk_list_item * +sctp_i_forward_tsn_chunk_new(u32 cum_tsn, struct sctp_i_forward_tsn_ids_list *ids_list) { + struct sctp_i_forward_tsn_chunk *chunk; + struct sctp_i_forward_tsn_ids_list_item *item; + + DEBUGP("sctp_i_forward_tsn_chunk_new called with cum_tsn = %d and sids_list = %p", cum_tsn, ids_list); + + u32 flags; + u32 length; + u16 i, nr_ids; + + flags = 0; + length = sizeof(struct sctp_i_forward_tsn_chunk); + if (ids_list == NULL) { + nr_ids = 0; + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + flags |= FLAG_I_FORWARD_TSN_CHUNK_IDS_NOCHECK; + } else { + nr_ids = ids_list->nr_entries; + length += nr_ids * sizeof(struct sctp_i_forward_tsn_identifier_block); + } + + assert(is_valid_u16(length)); + assert(length % 4 == 0); + chunk = malloc(length); + assert(chunk != NULL); + chunk->type = SCTP_I_FORWARD_TSN_CHUNK_TYPE; + chunk->flags = 0; + chunk->length = htons(length); + if (cum_tsn == -1) { + chunk->cum_tsn = htonl(0); + flags |= FLAG_I_FORWARD_TSN_CHUNK_CUM_TSN_NOCHECK; + } else { + chunk->cum_tsn = htonl((u32)cum_tsn); + } + + if (nr_ids == 0 || ids_list == NULL) { + flags |= FLAG_I_FORWARD_TSN_CHUNK_IDS_NOCHECK; + } + + if (ids_list != NULL) { + for (i = 0, item = ids_list->first; + (i < nr_ids) && (item != NULL); + i++, item = item->next) { + chunk->stream_identifier_blocks[i].stream_identifier= htons(item->stream_identifier); + if (item->u_bit_set == 'U') { + //TODO: htons required here? + chunk->stream_identifier_blocks[i].reserved = htons(0x01); + } + else if (item->u_bit_set == 'O') { + chunk->stream_identifier_blocks[i].reserved = 0; + } + + chunk->stream_identifier_blocks[i].message_identifier = htonl(item->message_identifier); + } + + assert((i == nr_ids) && (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) { diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h index f41521fd..ea7ddece 100644 --- a/gtests/net/packetdrill/sctp_packet.h +++ b/gtests/net/packetdrill/sctp_packet.h @@ -130,6 +130,31 @@ struct sctp_forward_tsn_ids_list_item * sctp_forward_tsn_ids_list_item_new(u16 stream_identifier, u16 stream_sequence_number); +struct sctp_i_forward_tsn_ids_list_item { + struct sctp_i_forward_tsn_ids_list_item *next; + char u_bit_set; + u16 stream_identifier; + u32 message_identifier; +}; + +struct sctp_i_forward_tsn_ids_list { + struct sctp_i_forward_tsn_ids_list_item *first; + struct sctp_i_forward_tsn_ids_list_item *last; + u16 nr_entries; +}; + +struct sctp_i_forward_tsn_ids_list * +sctp_i_forward_tsn_ids_list_new (); + +void +sctp_i_forward_tsn_ids_list_append(struct sctp_i_forward_tsn_ids_list *list, + struct sctp_i_forward_tsn_ids_list_item *item); + +void sctp_i_forward_tsn_ids_list_free (struct sctp_i_forward_tsn_ids_list *list); + +struct sctp_i_forward_tsn_ids_list_item * +sctp_i_forward_tsn_ids_list_item_new(char u_bit_set, u16 stream_identifier, u32 message_identifier); + struct sctp_address_type_list_item { struct sctp_address_type_list_item *next; u16 address_type; @@ -357,6 +382,12 @@ sctp_pad_chunk_new(s64 flgs, s64 len, u8* padding); struct sctp_chunk_list_item * sctp_forward_tsn_chunk_new(u32 cum_tsn, struct sctp_forward_tsn_ids_list *sids_list); +#define FLAG_I_FORWARD_TSN_CHUNK_CUM_TSN_NOCHECK 0x00000100 +#define FLAG_I_FORWARD_TSN_CHUNK_IDS_NOCHECK 0x00000200 + +struct sctp_chunk_list_item * +sctp_i_forward_tsn_chunk_new(u32 cum_tsn, struct sctp_i_forward_tsn_ids_list *ids_list); + struct sctp_chunk_list_item * sctp_reconfig_chunk_new(s64 flgs, struct sctp_parameter_list *parameters); -- GitLab