diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index f54f7a597db864f2b2ea752f2b9dc01d9271a932..71be636001c0185f76aa56fd792a241e2d909273 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -548,6 +548,7 @@ CWR return CWR; SHUTDOWN_COMPLETE return SHUTDOWN_COMPLETE; I-DATA return I_DATA; PAD return PAD; +RECONFIG return RECONFIG; type return TYPE; flgs return FLAGS; len return LEN; @@ -565,6 +566,11 @@ cum_tsn return CUM_TSN; gaps return GAPS; dups return DUPS; adaptation_code_point return ADAPTATION_CODE_POINT; +OUTGOING_SSN_RESET return OUTGOING_SSN_RESET; +reqsn return REQSN; +respsn return RESPSN; +last_tsn return LAST_TSN; +sids return SIDS; PARAMETER return PARAMETER; HEARTBEAT_INFORMATION return HEARTBEAT_INFORMATION; IPV4_ADDRESS return IPV4_ADDRESS; diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index 3ac46b6497d1788cc9038a3c95d4fa4a51b99567..9c4d58a2b325d6707c4b50340346f7a62e49690b 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -39,7 +39,7 @@ * * The semantic action code for a rule produces an output, which it * can reference using the $$ token. The set of possible types - * returned in output expressions is given in the %union section of +* returned in output expressions is given in the %union section of * the .y file. The specific type of the output for a terminal or * nonterminal symbol (corresponding to a field in the %union) is * given by the %type directive in the .y file. The action code can @@ -468,6 +468,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, struct sctp_chunk_list *chunk_list; struct sctp_byte_list_item *byte_list_item; struct sctp_byte_list *byte_list; + struct sctp_u16_list *u16_list; + 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_address_type_list_item *address_type_list_item; @@ -516,13 +518,14 @@ 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 +%token <reserved> SHUTDOWN_COMPLETE I_DATA PAD RECONFIG %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 %token <reserved> STATE_COOKIE UNRECOGNIZED_PARAMETER COOKIE_PRESERVATIVE %token <reserved> HOSTNAME_ADDRESS SUPPORTED_ADDRESS_TYPES ECN_CAPABLE %token <reserved> SUPPORTED_EXTENSIONS ADAPTATION_CODE_POINT ADAPTATION_INDICATION +%token <reserved> OUTGOING_SSN_RESET REQSN RESPSN LAST_TSN SIDS %token <reserved> ADDR INCR TYPES PARAMS %token <reserved> IPV4_TYPE IPV6_TYPE HOSTNAME_TYPE %token <reserved> CAUSE @@ -667,8 +670,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <chunk_list_item> sctp_ecne_chunk_spec sctp_cwr_chunk_spec %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 -%type <parameter_list> opt_parameter_list_spec sctp_parameter_list_spec +%type <chunk_list_item> sctp_pad_chunk_spec sctp_reconfig_chunk_spec +%type <parameter_list> opt_parameter_list_spec sctp_parameter_list_spec sctp_reconfig_parameter_list_spec %type <parameter_list_item> sctp_parameter_spec %type <parameter_list_item> sctp_generic_parameter_spec %type <parameter_list_item> sctp_heartbeat_information_parameter_spec @@ -682,7 +685,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <parameter_list_item> sctp_ecn_capable_parameter_spec %type <parameter_list_item> sctp_supported_extensions_parameter_spec %type <parameter_list_item> sctp_adaptation_indication_parameter_spec -%type <parameter_list_item> sctp_pad_parameter_spec +%type <parameter_list_item> sctp_pad_parameter_spec sctp_reconfig_parameter_spec %type <cause_list> opt_cause_list_spec sctp_cause_list_spec %type <cause_list_item> sctp_cause_spec %type <cause_list_item> sctp_generic_cause_spec @@ -705,8 +708,11 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <integer> opt_tag opt_a_rwnd opt_os opt_is opt_tsn opt_sid opt_ssn %type <integer> opt_mid opt_fsn %type <integer> opt_cum_tsn opt_ppid +%type <integer> opt_reqsn opt_respsn opt_last_tsn %type <byte_list> opt_val opt_info byte_list chunk_types_list -%type <byte_list_item> byte +%type <byte_list_item> byte +%type <u16_list> u16_list +%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 <address_type_list> address_types_list @@ -1039,6 +1045,7 @@ sctp_chunk_spec | sctp_shutdown_complete_chunk_spec { $$ = $1; } | sctp_i_data_chunk_spec { $$ = $1; } | sctp_pad_chunk_spec { $$ = $1; } +| sctp_reconfig_chunk_spec { $$ = $1; } ; chunk_type @@ -1104,6 +1111,9 @@ chunk_type } | PAD { $$ = SCTP_PAD_CHUNK_TYPE; +} +| RECONFIG { + $$ = SCTP_RECONFIG_CHUNK_TYPE; } ; @@ -1175,6 +1185,23 @@ byte } ; +u16_list +: { $$ = sctp_u16_list_new(); } +| u16_item { $$ = sctp_u16_list_new(); + sctp_u16_list_append($$, $1); } +| u16_list ',' u16_item { $$ = $1; + sctp_u16_list_append($1, $3); } +; + +u16_item +: INTEGER { + if (!is_valid_u16($1)) { + semantic_error("Integer value out of range"); + } + $$ = sctp_u16_list_item_new($1); +} +; + opt_data_flags : FLAGS '=' ELLIPSIS { $$ = -1; } | FLAGS '=' HEX_INTEGER { @@ -1661,6 +1688,62 @@ sctp_pad_chunk_spec $$ = sctp_pad_chunk_new($3, $5, NULL); } +opt_reqsn +: REQSN '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("reqsn out of range"); + } + $$ = $3; +} +| REQSN '=' ELLIPSIS { $$ = -1; } +; + +opt_respsn +: RESPSN '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("respsn out of range"); + } + $$ = $3; +} +| RESPSN '=' ELLIPSIS { $$ = -1; } +; + +opt_last_tsn +: LAST_TSN '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("last_tsn out of range"); + } + $$ = $3; +} +| LAST_TSN '=' ELLIPSIS { $$ = -1; } +; + +sctp_reconfig_parameter_list_spec +: sctp_reconfig_parameter_spec { + $$ = sctp_parameter_list_new(); + sctp_parameter_list_append($$, $1); +} +| sctp_reconfig_parameter_list_spec ',' sctp_reconfig_parameter_spec { + $$ = $1; + sctp_parameter_list_append($1, $3); +} +; + +sctp_reconfig_parameter_spec +: OUTGOING_SSN_RESET '[' opt_reqsn ',' opt_respsn ',' opt_last_tsn ']' { + $$ = sctp_outgoing_ssn_reset_request_parameter_new($3, $5, $7, NULL); +} +| OUTGOING_SSN_RESET '[' opt_reqsn ',' opt_respsn ',' opt_last_tsn ',' SIDS '=' '[' u16_list ']' ']' { + $$ = sctp_outgoing_ssn_reset_request_parameter_new($3, $5, $7, $12); +} +; + +sctp_reconfig_chunk_spec +: RECONFIG '[' opt_flags ',' sctp_reconfig_parameter_list_spec ']' { + $$ = sctp_reconfig_chunk_new($3, $5); +} +; + opt_parameter_list_spec : ',' ELLIPSIS { $$ = NULL; } | { $$ = sctp_parameter_list_new(); } diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c index 819587d9273d02aee86109e0df9a8e80fce8303a..7746efff68aaa61c1379a5ac0ae7e0c9cf3a1bc5 100644 --- a/gtests/net/packetdrill/run_packet.c +++ b/gtests/net/packetdrill/run_packet.c @@ -652,6 +652,7 @@ static int map_inbound_sctp_packet( struct sctp_cwr_chunk *cwr; struct sctp_shutdown_complete_chunk *shutdown_complete; struct sctp_i_data_chunk *i_data; + struct sctp_reconfig_chunk *reconfig; u32 local_diff, remote_diff; u32 v_tag; u16 nr_gap_blocks, nr_dup_tsns, i; @@ -738,6 +739,32 @@ static int map_inbound_sctp_packet( i_data = (struct sctp_i_data_chunk *)chunk; i_data->tsn = htonl(ntohl(i_data->tsn) + remote_diff); break; + case SCTP_RECONFIG_CHUNK_TYPE: + reconfig = (struct sctp_reconfig_chunk *)chunk; + if (reconfig->length > sizeof(struct sctp_reconfig_chunk)) { + struct sctp_parameter *parameter; + struct sctp_parameters_iterator iter; + int parameters_length = ntohs(reconfig->length) - sizeof(struct sctp_reconfig_chunk); + for (parameter = sctp_parameters_begin(reconfig->parameter, parameters_length, + &iter, error); + parameter != NULL; + parameter = sctp_parameters_next(&iter, error)) { + switch(htons(parameter->type)) { + case SCTP_OUTGOING_SSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_outgoing_ssn_reset_request_parameter *reset; + reset = (struct sctp_outgoing_ssn_reset_request_parameter *)parameter; + reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + reset->respsn = htonl(ntohl(reset->respsn) + local_diff); + reset->last_tsn = htonl(ntohl(reset->last_tsn) + local_diff); + break; + } + default: + //do nothing + break; + } + } + } + break; default: break; } @@ -871,6 +898,7 @@ static int map_outbound_live_sctp_packet( struct sctp_ecne_chunk *ecne; struct sctp_cwr_chunk *cwr; struct sctp_i_data_chunk *i_data; + struct sctp_reconfig_chunk *reconfig; u32 local_diff, remote_diff; u16 nr_gap_blocks, nr_dup_tsns, i; @@ -931,6 +959,34 @@ static int map_outbound_live_sctp_packet( i_data = (struct sctp_i_data_chunk *)chunk; i_data->tsn = htonl(ntohl(i_data->tsn) + local_diff); break; + case SCTP_RECONFIG_CHUNK_TYPE: + reconfig = (struct sctp_reconfig_chunk *)chunk; + if (reconfig->length > sizeof(struct sctp_reconfig_chunk)) { + struct sctp_parameter *parameter; + struct sctp_parameters_iterator iter; + int parameters_length = ntohs(reconfig->length) - sizeof(struct sctp_reconfig_chunk); + + for (parameter = sctp_parameters_begin(reconfig->parameter, + parameters_length, + &iter, error); + parameter != NULL; + parameter = sctp_parameters_next(&iter, error)) { + switch(htons(parameter->type)) { + case SCTP_OUTGOING_SSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_outgoing_ssn_reset_request_parameter *reset; + reset = (struct sctp_outgoing_ssn_reset_request_parameter *)parameter; + reset->reqsn = htonl(ntohl(reset->reqsn) + local_diff); + reset->respsn = htonl(ntohl(reset->respsn) + remote_diff); + reset->last_tsn = htonl(ntohl(reset->last_tsn) + remote_diff); + break; + } + default: + //do nothing + break; + } + } + } + break; default: break; } @@ -1709,6 +1765,23 @@ static int verify_pad_chunk(struct sctp_pad_chunk *actual_chunk, return STATUS_OK; } +static int verify_reconfig_chunk(struct sctp_reconfig_chunk *actual_chunk, + struct sctp_reconfig_chunk *script_chunk, + u32 flags, char **error) +{ + struct sctp_reconfig_chunk *reconfig = (struct sctp_reconfig_chunk *)actual_chunk; + int parameter_length = ntohs(reconfig->length) - sizeof(struct sctp_reconfig_chunk); + if ((flags & FLAG_CHUNK_FLAGS_NOCHECK ? STATUS_OK : + check_field("sctp_reconfig_flags", + ntohl(script_chunk->flags), + ntohl(actual_chunk->flags), + error))) { + return STATUS_ERR; + } + return verify_sctp_parameters(reconfig->parameter, parameter_length, + (struct sctp_chunk_list_item *)script_chunk, error); +} + /* Verify that required actual SCTP packet fields are as the script expected. */ static int verify_sctp( const struct packet *actual_packet, @@ -1849,6 +1922,11 @@ static int verify_sctp( (struct sctp_pad_chunk *)script_chunk, flags, error); break; + case SCTP_RECONFIG_CHUNK_TYPE: + result = verify_reconfig_chunk((struct sctp_reconfig_chunk *)actual_chunk, + (struct sctp_reconfig_chunk *)script_chunk, + flags, error); + break; default: result = STATUS_ERR; assert(!"unsupported SCTP chunk type"); diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index 492abf05310c81765388f260aaa4ac0543e85fec..0db21c3be70cf4a76a1b1a298fbc7dcba1915386 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -4020,7 +4020,14 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, get_u16(expr, &(reset_streams->srs_stream_list[i]), error); } - optval = &reset_streams; + optval = reset_streams; + printf("Assoc: %u\n",reset_streams->srs_assoc_id); + printf("flags: %u\n",reset_streams->srs_flags); + printf("number_streams: %u\n",reset_streams->srs_number_streams); + printf("Size: %zu", sizeof(struct sctp_reset_streams)); + for (i = 0; i < len; i++) { + printf("sid[%d]: %hu\n", i, reset_streams->srs_stream_list[i]); + } break; } #endif diff --git a/gtests/net/packetdrill/sctp.h b/gtests/net/packetdrill/sctp.h index 0c737cf6ea67070986509d8604b8a7925e43e24e..6a85c2cf7fa512d0cae7c0b9129acbdf1e9cc6c0 100644 --- a/gtests/net/packetdrill/sctp.h +++ b/gtests/net/packetdrill/sctp.h @@ -53,8 +53,8 @@ struct sctp_common_header { #define SCTP_CWR_CHUNK_TYPE 0x0d #define SCTP_SHUTDOWN_COMPLETE_CHUNK_TYPE 0x0e #define SCTP_I_DATA_CHUNK_TYPE 0x40 +#define SCTP_RECONFIG_CHUNK_TYPE 0x82 #define SCTP_PAD_CHUNK_TYPE 0x84 - #define MAX_SCTP_CHUNK_BYTES 0xffff struct sctp_chunk { @@ -233,6 +233,13 @@ struct sctp_pad_chunk { __u8 padding_data[]; } __packed; +struct sctp_reconfig_chunk { + __u8 type; + __u8 flags; + __be16 length; + __u8 parameter[]; +} __packed; + #define SCTP_HEARTBEAT_INFORMATION_PARAMETER_TYPE 0x0001 #define SCTP_IPV4_ADDRESS_PARAMETER_TYPE 0x0005 #define SCTP_IPV6_ADDRESS_PARAMETER_TYPE 0x0006 @@ -241,12 +248,12 @@ struct sctp_pad_chunk { #define SCTP_COOKIE_PRESERVATIVE_PARAMETER_TYPE 0x0009 #define SCTP_HOSTNAME_ADDRESS_PARAMETER_TYPE 0x000b #define SCTP_SUPPORTED_ADDRESS_TYPES_PARAMETER_TYPE 0x000c +#define SCTP_OUTGOING_SSN_RESET_REQUEST_PARAMETER_TYPE 0x000d #define SCTP_ECN_CAPABLE_PARAMETER_TYPE 0x8000 #define SCTP_SUPPORTED_EXTENSIONS_PARAMETER_TYPE 0x8008 #define SCTP_PAD_PARAMETER_TYPE 0x8005 #define SCTP_Set_Primary_Address 0xc004 #define SCTP_ADAPTATION_INDICATION_PARAMETER_TYPE 0xc006 - #define MAX_SCTP_PARAMETER_BYTES 0xffff struct sctp_parameter { @@ -326,6 +333,15 @@ struct sctp_adaptation_indication_parameter { __be32 adaptation_code_point; } __packed; +struct sctp_outgoing_ssn_reset_request_parameter { + __be16 type; + __be16 length; + __be32 reqsn; + __be32 respsn; + __be32 last_tsn; + __be16 sids[]; +} __packed; + #define SCTP_INVALID_STREAM_IDENTIFIER_CAUSE_CODE 0x0001 #define SCTP_MISSING_MANDATORY_PARAMETER_CAUSE_CODE 0x0002 #define SCTP_STALE_COOKIE_ERROR_CAUSE_CODE 0x0003 @@ -424,5 +440,4 @@ struct sctp_protocol_violation_cause { __be16 length; __u8 information[]; } __packed; - #endif /* __SCTP_HEADERS_H__ */ diff --git a/gtests/net/packetdrill/sctp_chunk_to_string.c b/gtests/net/packetdrill/sctp_chunk_to_string.c index 027873a947c3b8b21fa4eec314a20a63a29a1ee2..51cb105e0e8112598663851746446c81f7dceb12 100644 --- a/gtests/net/packetdrill/sctp_chunk_to_string.c +++ b/gtests/net/packetdrill/sctp_chunk_to_string.c @@ -290,6 +290,9 @@ static int sctp_supported_extensions_parameter_to_string( case SCTP_PAD_CHUNK_TYPE: fputs("PAD", s); break; + case SCTP_RECONFIG_CHUNK_TYPE: + fputs("RECONFIG", s); + break; default: fprintf(s, "0x%02x", parameter->chunk_type[i]); break; @@ -313,6 +316,36 @@ static int sctp_pad_parameter_to_string( return STATUS_OK; } +static int sctp_outgoing_ssn_reset_request_parameter_to_string( + FILE *s, + struct sctp_outgoing_ssn_reset_request_parameter *parameter, + char **error) +{ + u16 length; + u32 reqsn; + u32 respsn; + u32 last_tsn; + int len; + + length = ntohs(parameter->length); + reqsn = ntohl(parameter->reqsn); + respsn = ntohl(parameter->respsn); + last_tsn = ntohl(parameter->last_tsn); + fputs("OUTGOING_SSN_RESET[", s); + fprintf(s, "len=%hu, ", length); + fprintf(s, "reqsn=%u, ", reqsn); + fprintf(s, "respsn=%u, ", respsn); + fprintf(s, "last_tsn=%u, ", last_tsn); + fputs("sids=[", s); + for(len = 0; len < ((length-16)/sizeof(u16)); len++) { + u16 sid; + sid = ntohs(parameter->sids[len]); + fprintf(s, "%hu, ", sid); + } + fputs("]", s); + return STATUS_OK; +} + static int sctp_unknown_parameter_to_string( FILE *s, struct sctp_parameter *parameter, @@ -419,6 +452,10 @@ static int sctp_parameter_to_string(FILE *s, result = sctp_adaptation_indication_parameter_to_string(s, (struct sctp_adaptation_indication_parameter *)parameter, error); break; + case SCTP_OUTGOING_SSN_RESET_REQUEST_PARAMETER_TYPE: + result = sctp_outgoing_ssn_reset_request_parameter_to_string(s, + (struct sctp_outgoing_ssn_reset_request_parameter *)parameter, error); + break; default: result = sctp_unknown_parameter_to_string(s, parameter, error); break; @@ -1374,6 +1411,42 @@ static int sctp_pad_chunk_to_string( return STATUS_OK; } +static int sctp_reconfig_chunk_to_string( + FILE *s, + struct sctp_reconfig_chunk *chunk, + char **error) +{ + u16 length; + int result, parameters_length; + struct sctp_parameter *parameter; + struct sctp_parameters_iterator iter; + + length = ntohs(chunk->length); + if (length < sizeof(struct sctp_reconfig_chunk)) { + asprintf(error, "RECONFIG chunk too short (length=%u)", length); + return STATUS_ERR; + } + parameters_length = length - sizeof(struct sctp_reconfig_chunk); + fputs("RECONFIG[", s); + fprintf(s, "flgs=0x%02x, ", chunk->flags); + fprintf(s, "len=%u", length); + + for (parameter = sctp_parameters_begin(chunk->parameter, + parameters_length, + &iter, error); + parameter != NULL; + parameter = sctp_parameters_next(&iter, error)) { + fputs(", ", s); + if (*error != NULL) + break; + result = sctp_parameter_to_string(s, parameter, error); + if (result != STATUS_OK) + break; + } + fputs("]", s); + return STATUS_OK; +} + static int sctp_unknown_chunk_to_string(FILE *s, struct sctp_chunk *chunk, char **error) @@ -1466,6 +1539,10 @@ int sctp_chunk_to_string(FILE *s, struct sctp_chunk *chunk, char **error) result = sctp_pad_chunk_to_string(s, (struct sctp_pad_chunk *)chunk, error); break; + case SCTP_RECONFIG_CHUNK_TYPE: + result = sctp_reconfig_chunk_to_string(s, + (struct sctp_reconfig_chunk *)chunk, error); + break; default: result = sctp_unknown_chunk_to_string(s, chunk, error); break; diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c index 7c11497e881f6550805cce8eb55deb411d6a0796..ff1df004f4330820e3b14143ccc95521df49d870 100644 --- a/gtests/net/packetdrill/sctp_packet.c +++ b/gtests/net/packetdrill/sctp_packet.c @@ -95,6 +95,69 @@ sctp_byte_list_item_new(u8 byte) return item; } +struct sctp_u16_list * +sctp_u16_list_new(void) +{ + struct sctp_u16_list *list; + + list = malloc(sizeof(struct sctp_u16_list)); + assert(list != NULL); + list->first = NULL; + list->last = NULL; + list->nr_entries = 0; + return list; +} + +void +sctp_u16_list_append(struct sctp_u16_list *list, + struct sctp_u16_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_u16_list_free(struct sctp_u16_list *list) +{ + struct sctp_u16_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_u16_list_item * +sctp_u16_list_item_new(u16 val) +{ + struct sctp_u16_list_item *item; + + item = malloc(sizeof(struct sctp_u16_list_item)); + assert(item != NULL); + item->next = NULL; + item->value = val; + return item; +} + struct sctp_sack_block_list * sctp_sack_block_list_new(void) { @@ -1220,6 +1283,58 @@ sctp_pad_chunk_new(s64 flgs, s64 len, u8* padding) sctp_cause_list_new()); } +struct sctp_chunk_list_item * +sctp_reconfig_chunk_new(s64 flgs, struct sctp_parameter_list *parameters) +{ + struct sctp_reconfig_chunk *chunk; + struct sctp_parameter_list_item *item; + u32 flags; + u16 offset, chunk_length, padding_length, parameter_padding_length; + + flags = 0; + chunk_length = (u16)sizeof(struct sctp_reconfig_chunk); + if (parameters != NULL) { + chunk_length += parameters->length; + } + padding_length = chunk_length % 4; + if (padding_length > 0) { + padding_length = 4 - padding_length; + } + chunk = malloc(chunk_length + padding_length); + assert(chunk != NULL); + chunk->type = SCTP_RECONFIG_CHUNK_TYPE; + + if (flgs == -1) { + chunk->flags = 0; + flags |= FLAG_CHUNK_FLAGS_NOCHECK; + } else { + chunk->flags = (u8)flgs; + } + chunk->length = htons(chunk_length); + + offset = 0; + for (item = parameters->first; item != NULL; item = item->next) { + parameter_padding_length = item->length % 4; + if (parameter_padding_length > 0) { + parameter_padding_length = 4 - parameter_padding_length; + } + memcpy(chunk->parameter + offset, + item->parameter, + item->length + parameter_padding_length); + free(item->parameter); + item->parameter = (struct sctp_parameter *)(chunk->parameter + offset); + if (item->flags & FLAG_PARAMETER_LENGTH_NOCHECK) { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + } + offset += item->length + parameter_padding_length; + } + + return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, + chunk_length + padding_length, + flags, parameters, + sctp_cause_list_new()); +} + struct sctp_chunk_list * sctp_chunk_list_new(void) { @@ -1679,6 +1794,39 @@ sctp_pad_parameter_new(s64 len, u8 *padding) parameter_length, flags); } +struct sctp_parameter_list_item * +sctp_outgoing_ssn_reset_request_parameter_new(u32 reqsn, u32 respsn, u32 last_tsn, struct sctp_u16_list *sids) +{ + struct sctp_outgoing_ssn_reset_request_parameter *parameter; + u32 flags = 0; + u16 parameter_length; + int i = 0, sid_len = 0; + + if (sids != NULL) { + sid_len = sids->nr_entries; + } + + parameter_length = sizeof(struct sctp_outgoing_ssn_reset_request_parameter) + (sizeof(u16) * sid_len); + + parameter = malloc(parameter_length); + assert(parameter != NULL); + + parameter->type = htons(SCTP_OUTGOING_SSN_RESET_REQUEST_PARAMETER_TYPE); + parameter->length = htons(parameter_length); + parameter->reqsn = htonl(reqsn); + parameter->respsn = htonl(respsn); + parameter->last_tsn = htonl(last_tsn); + if (sids != NULL) { + struct sctp_u16_list_item *item; + for (item = sids->first; item != NULL; item = item->next) { + parameter->sids[i] = item->value; + } + } + + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + parameter_length, flags); +} + struct sctp_parameter_list_item * sctp_ecn_capable_parameter_new(void) { @@ -2507,6 +2655,8 @@ new_sctp_packet(int address_family, return NULL; } break; + case SCTP_RECONFIG_CHUNK_TYPE: + 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 4defa5042fb64632b925e127c982306a4deeda5d..50d3bb8a79956900bd112a82a0864322aa2c5fe3 100644 --- a/gtests/net/packetdrill/sctp_packet.h +++ b/gtests/net/packetdrill/sctp_packet.h @@ -53,6 +53,30 @@ sctp_byte_list_free(struct sctp_byte_list *list); struct sctp_byte_list_item * sctp_byte_list_item_new(u8 byte); +struct sctp_u16_list_item { + struct sctp_u16_list_item *next; + u16 value; +}; + +struct sctp_u16_list { + struct sctp_u16_list_item *first; + struct sctp_u16_list_item *last; + u16 nr_entries; +}; + +struct sctp_u16_list * +sctp_u16_list_new(void); + +void +sctp_u16_list_append(struct sctp_u16_list *list, + struct sctp_u16_list_item *item); + +void +sctp_u16_list_free(struct sctp_u16_list *list); + +struct sctp_u16_list_item * +sctp_u16_list_item_new(u16 val); + struct sctp_sack_block_list_item { struct sctp_sack_block_list_item *next; union sctp_sack_block block; @@ -289,6 +313,9 @@ 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); +struct sctp_chunk_list_item * +sctp_reconfig_chunk_new(s64 flgs, struct sctp_parameter_list *parameters); + struct sctp_chunk_list * sctp_chunk_list_new(void); @@ -349,6 +376,9 @@ sctp_supported_extensions_parameter_new(struct sctp_byte_list *list); struct sctp_parameter_list_item * sctp_pad_parameter_new(s64 len, u8 *padding); +struct sctp_parameter_list_item * +sctp_outgoing_ssn_reset_request_parameter_new(u32 reqsn, u32 respsn, u32 last_tsn, struct sctp_u16_list *sids); + struct sctp_parameter_list * sctp_parameter_list_new(void); diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/sctp_reset_streams.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/sctp_reset_streams.pkt index 90731a2c963070917685f50a977349feff4528d8..b44f2bd4c68f0be6bcc12ad9ec123ace204acb80 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/sctp_reset_streams.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/sctp_reset_streams.pkt @@ -11,7 +11,6 @@ +0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...] +0.1 < sctp: COOKIE_ACK[flgs=0] +0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 -//sendmsg(sd, msghdr, flags) +0.0 setsockopt(3, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, {spp_assoc_id=3, spp_address={sa_family=AF_INET,