diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index f54f7a597db864f2b2ea752f2b9dc01d9271a932..d08de406abf29e75d688d980ae48386a0358d02d 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,20 @@ 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; +INCOMING_SSN_RESET return INCOMING_SSN_RESET; +SSN_TSN_RESET return SSN_TSN_RESET; +RECONFIG_RESPONSE return RECONFIG_RESPONSE; +ADD_OUTGOING_STREAMS return ADD_OUTGOING_STREAMS; +ADD_INCOMING_STREAMS return ADD_INCOMING_STREAMS; +req_sn return REQ_SN; +resp_sn return RESP_SN; +last_tsn return LAST_TSN; +sids return SIDS; +result return RESULT; +sender_next_tsn return SENDER_NEXT_TSN; +receiver_next_tsn return RECEIVER_NEXT_TSN; +number_of_new_streams return NUMBER_OF_NEW_STREAMS; 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..8fc4ff21c6a17c58fea7acd92946352fec23cf54 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -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,17 @@ 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 REQ_SN RESP_SN LAST_TSN SIDS INCOMING_SSN_RESET +%token <reserved> RECONFIG_RESPONSE RESULT SENDER_NEXT_TSN RECEIVER_NEXT_TSN +%token <reserved> SSN_TSN_RESET ADD_INCOMING_STREAMS NUMBER_OF_NEW_STREAMS +%token <reserved> ADD_OUTGOING_STREAMS %token <reserved> ADDR INCR TYPES PARAMS %token <reserved> IPV4_TYPE IPV6_TYPE HOSTNAME_TYPE %token <reserved> CAUSE @@ -667,8 +673,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 +688,10 @@ 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 <parameter_list_item> outgoing_ssn_reset_request incoming_ssn_reset_request +%type <parameter_list_item> reconfig_response ssn_tsn_reset_request +%type <parameter_list_item> add_outgoing_streams_request add_incoming_streams_request %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 @@ -704,9 +713,12 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <integer> opt_shutdown_complete_flags opt_i_data_flags opt_len %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_cum_tsn opt_ppid opt_sender_next_tsn opt_receiver_next_tsn +%type <integer> opt_req_sn opt_resp_sn opt_last_tsn opt_result opt_number_of_new_streams %type <byte_list> opt_val opt_info byte_list chunk_types_list %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 +1051,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 +1117,9 @@ chunk_type } | PAD { $$ = SCTP_PAD_CHUNK_TYPE; +} +| RECONFIG { + $$ = SCTP_RECONFIG_CHUNK_TYPE; } ; @@ -1175,6 +1191,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 +1694,147 @@ sctp_pad_chunk_spec $$ = sctp_pad_chunk_new($3, $5, NULL); } +opt_req_sn +: REQ_SN '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("req_sn out of range"); + } + $$ = $3; +} +| REQ_SN '=' ELLIPSIS { $$ = -1; } +; + +opt_resp_sn +: RESP_SN '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("resp_sn out of range"); + } + $$ = $3; +} +| RESP_SN '=' ELLIPSIS { $$ = -1; } +; + +opt_last_tsn +: LAST_TSN '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("last_tsn out of range"); + } + $$ = $3; +} +| LAST_TSN '=' ELLIPSIS { $$ = -1; } +; + +opt_result +: RESULT '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("result out of range"); + } + $$ = $3; +} +| RESULT '=' 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_request { $$ = $1; } +| incoming_ssn_reset_request { $$ = $1; } +| ssn_tsn_reset_request { $$ = $1; } +| reconfig_response { $$ = $1; } +| add_outgoing_streams_request { $$ = $1; } +| add_incoming_streams_request { $$ = $1; } +; + +opt_sender_next_tsn +: SENDER_NEXT_TSN '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("sender_next_tsn out of range"); + } + $$ = $3; +} +| SENDER_NEXT_TSN '=' ELLIPSIS { $$ = -1; } +; + +opt_receiver_next_tsn +: RECEIVER_NEXT_TSN '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("receiver_next_tsn out of range"); + } + $$ = $3; +} +| RECEIVER_NEXT_TSN '=' ELLIPSIS { $$ = -1; } +; + +opt_number_of_new_streams +: NUMBER_OF_NEW_STREAMS '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("number_of_new_streams out of range"); + } + $$ = $3; +} +| NUMBER_OF_NEW_STREAMS '=' ELLIPSIS { $$ = -1; } +; + +outgoing_ssn_reset_request +: OUTGOING_SSN_RESET '[' opt_req_sn ',' opt_resp_sn ',' opt_last_tsn ']' { + $$ = sctp_outgoing_ssn_reset_request_parameter_new($3, $5, $7, NULL); +} +| OUTGOING_SSN_RESET '[' opt_req_sn ',' opt_resp_sn ',' opt_last_tsn ',' SIDS '=' '[' u16_list ']' ']' { + $$ = sctp_outgoing_ssn_reset_request_parameter_new($3, $5, $7, $12); +} +; + +incoming_ssn_reset_request +: INCOMING_SSN_RESET '[' opt_req_sn ']' { + $$ = sctp_incoming_ssn_reset_request_parameter_new($3, NULL); +} +| INCOMING_SSN_RESET '[' opt_req_sn ',' SIDS '=' '[' u16_list ']' ']' { + $$ = sctp_incoming_ssn_reset_request_parameter_new($3, $8); +} +; + +ssn_tsn_reset_request +: SSN_TSN_RESET '[' opt_req_sn ']' { + $$ = sctp_ssn_tsn_reset_request_parameter_new($3); +} +; + +reconfig_response +: RECONFIG_RESPONSE '[' opt_resp_sn ',' opt_result ']' { + $$ = sctp_reconfig_response_parameter_new($3, $5, -2, -2); +} +| RECONFIG_RESPONSE '[' opt_resp_sn ',' opt_result ',' opt_sender_next_tsn ',' opt_receiver_next_tsn']' { + $$ = sctp_reconfig_response_parameter_new($3, $5, $7, $9); +} +; + +add_outgoing_streams_request +: ADD_OUTGOING_STREAMS '[' opt_req_sn ',' opt_number_of_new_streams ']' { + $$ = sctp_add_outgoing_streams_request_parameter_new($3, $5); +} +; + +add_incoming_streams_request +: ADD_INCOMING_STREAMS '[' opt_req_sn ',' opt_number_of_new_streams ']' { + $$ = sctp_add_incoming_streams_request_parameter_new($3, $5); +} +; + +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 b4d4a43bf020d77fd751e5ac7b6ddcce3b81c122..e93c4dca40aff5c80b4ca2abcdbc53cd332026b7 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,66 @@ 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) + remote_diff); + break; + } + case SCTP_INCOMING_SSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_incoming_ssn_reset_request_parameter *reset; + reset = (struct sctp_incoming_ssn_reset_request_parameter *)parameter; + reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + break; + } + case SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_ssn_tsn_reset_request_parameter *reset; + reset = (struct sctp_ssn_tsn_reset_request_parameter *)parameter; + reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + break; + } + case SCTP_RECONFIG_RESPONSE_PARAMETER_TYPE: { + struct sctp_reconfig_response_parameter *response; + response = (struct sctp_reconfig_response_parameter *)parameter; + response->respsn = htonl(htonl(response->respsn) + local_diff); + if (response->length == sizeof(struct sctp_reconfig_response_parameter)) { + response->receiver_next_tsn = htonl(htonl(response->receiver_next_tsn) + local_diff); + response->sender_next_tsn = htonl(htonl(response->sender_next_tsn) + remote_diff); + } + break; + } + case SCTP_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_TYPE: { + struct sctp_add_outgoing_streams_request_parameter *request; + request = (struct sctp_add_outgoing_streams_request_parameter *)parameter; + request->reqsn = htonl(htonl(request->reqsn) + remote_diff); + break; + } + case SCTP_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_TYPE: { + struct sctp_add_incoming_streams_request_parameter *request; + request = (struct sctp_add_incoming_streams_request_parameter *)parameter; + request->reqsn = htonl(htonl(request->reqsn) + remote_diff); + break; + } + default: + //do nothing + break; + } + } + } + break; default: break; } @@ -871,6 +932,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 +993,67 @@ 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) + local_diff); + break; + } + case SCTP_INCOMING_SSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_incoming_ssn_reset_request_parameter *reset; + reset = (struct sctp_incoming_ssn_reset_request_parameter *)parameter; + reset->reqsn = htonl(ntohl(reset->reqsn) + local_diff); + break; + } + case SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_ssn_tsn_reset_request_parameter *reset; + reset = (struct sctp_ssn_tsn_reset_request_parameter *)parameter; + reset->reqsn = htonl(ntohl(reset->reqsn) + local_diff); + break; + } + case SCTP_RECONFIG_RESPONSE_PARAMETER_TYPE: { + struct sctp_reconfig_response_parameter *response; + response = (struct sctp_reconfig_response_parameter *)parameter; + response->respsn = htonl(htonl(response->respsn) + remote_diff); + if (response->length == sizeof(struct sctp_reconfig_response_parameter)) { + response->receiver_next_tsn = htonl(htonl(response->receiver_next_tsn) + local_diff); + response->sender_next_tsn = htonl(htonl(response->sender_next_tsn) + remote_diff); + } + break; + } + case SCTP_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_TYPE: { + struct sctp_add_outgoing_streams_request_parameter *request; + request = (struct sctp_add_outgoing_streams_request_parameter *)parameter; + request->reqsn = htonl(htonl(request->reqsn) + local_diff); + break; + } + case SCTP_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_TYPE: { + struct sctp_add_incoming_streams_request_parameter *request; + request = (struct sctp_add_incoming_streams_request_parameter *)parameter; + request->reqsn = htonl(htonl(request->reqsn) + local_diff); + break; + } + default: + //do nothing + break; + } + } + } + break; default: break; } @@ -1058,6 +1181,24 @@ static int check_field( return STATUS_OK; } +/* Check whether the given field of a packet matches the expected + * value, and emit a human-readable error message if not. + */ +static int check_field_u16( + const char *name, /* human-readable name of the header field */ + u16 expected, /* value script hopes to see */ + u16 actual, /* actual value seen during test */ + char **error) /* human-readable error string on failure */ +{ + if (actual != expected) { + asprintf(error, "live packet field %s: " + "expected: %hu (0x%x) vs actual: %hu (0x%x)", + name, expected, expected, actual, actual); + return STATUS_ERR; + } + return STATUS_OK; +} + /* Verify that the actual ECN bits are as the script expected. */ static int verify_outbound_live_ecn(enum ip_ecn_t ecn, u8 actual_ecn_bits, @@ -1198,7 +1339,6 @@ static int verify_sctp_parameters(u8 *begin, u16 length, struct sctp_parameter *script_parameter; struct sctp_parameter_list_item *script_parameter_item; u32 flags; - for (actual_parameter = sctp_parameters_begin(begin, length, &iter, error), script_parameter_item = script_chunk_item->parameter_list->first; actual_parameter != NULL && script_parameter_item != NULL; @@ -1230,14 +1370,160 @@ static int verify_sctp_parameters(u8 *begin, u16 length, error))) { return STATUS_ERR; } - if ((flags & FLAG_PARAMETER_VALUE_NOCHECK) == 0) { - assert((flags & FLAG_PARAMETER_LENGTH_NOCHECK) == 0); - if (memcmp(script_parameter->value, - actual_parameter->value, - ntohs(actual_parameter->length) - sizeof(struct sctp_parameter))) { - asprintf(error, "live packet parameter value not as expected"); + switch (ntohs(actual_parameter->type)) { + case SCTP_OUTGOING_SSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_outgoing_ssn_reset_request_parameter *live_reset, *script_reset; + int sids_len = 0, i = 0; + + live_reset = (struct sctp_outgoing_ssn_reset_request_parameter *)actual_parameter; + script_reset = (struct sctp_outgoing_ssn_reset_request_parameter *)script_parameter; + if ((flags & FLAG_RECONFIG_REQ_SN_NOCHECK ? STATUS_OK : + check_field("outgoing_ssn_reset_request_parameter.req_sn", + ntohl(script_reset->reqsn), + ntohl(live_reset->reqsn), + error)) || + (flags & FLAG_RECONFIG_RESP_SN_NOCHECK ? STATUS_OK : + check_field("outgoing_ssn_reset_request_parameter.resp_sn", + ntohl(script_reset->respsn), + ntohl(live_reset->respsn), + error)) || + (flags & FLAG_RECONFIG_LAST_TSN_NOCHECK ? STATUS_OK : + check_field("outgoing_ssn_reset_request_parameter.last_tsn", + ntohl(script_reset->last_tsn), + ntohl(live_reset->last_tsn), + error))) { + return STATUS_ERR; + } + sids_len = ntohs(script_reset->length) - sizeof(struct sctp_outgoing_ssn_reset_request_parameter); + for (i = 0; i<(sids_len / sizeof(u16)); i++) { + if (check_field_u16("outgoing_ssn_reset_request_parameter.sids", + ntohs(script_reset->sids[i]), + ntohs(live_reset->sids[i]), + error)) { + return STATUS_ERR; + } + } + break; + } + case SCTP_INCOMING_SSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_incoming_ssn_reset_request_parameter *live_reset, *script_reset; + int sids_len = 0, i = 0; + + live_reset = (struct sctp_incoming_ssn_reset_request_parameter *)actual_parameter; + script_reset = (struct sctp_incoming_ssn_reset_request_parameter *)script_parameter; + if ((flags & FLAG_RECONFIG_REQ_SN_NOCHECK ? STATUS_OK : + check_field("incoming_ssn_reset_request_parameter.req_sn", + ntohl(script_reset->reqsn), + ntohl(live_reset->reqsn), + error))) { + return STATUS_ERR; + } + sids_len = ntohs(script_reset->length) - sizeof(struct sctp_incoming_ssn_reset_request_parameter); + for (i = 0; i<(sids_len / sizeof(u16)); i++) { + if (check_field_u16("incoming_ssn_reset_request_parameter.sids", + ntohs(script_reset->sids[i]), + ntohs(live_reset->sids[i]), + error)) { + return STATUS_ERR; + } + } + break; + } + case SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_ssn_tsn_reset_request_parameter *live_reset, *script_reset; + + live_reset = (struct sctp_ssn_tsn_reset_request_parameter *)actual_parameter; + script_reset = (struct sctp_ssn_tsn_reset_request_parameter *)script_parameter; + if ((flags & FLAG_RECONFIG_REQ_SN_NOCHECK ? STATUS_OK : + check_field("ssn_tsn_reset_request_parameter.req_sn", + ntohl(script_reset->reqsn), + ntohl(live_reset->reqsn), + error))) { + return STATUS_ERR; + } + break; + } + case SCTP_RECONFIG_RESPONSE_PARAMETER_TYPE: { + struct sctp_reconfig_response_parameter *live_resp, *script_resp; + + live_resp = (struct sctp_reconfig_response_parameter *)actual_parameter; + script_resp = (struct sctp_reconfig_response_parameter *)script_parameter; + if ((flags & FLAG_RECONFIG_RESP_SN_NOCHECK ? STATUS_OK : + check_field("reconfig_response_parameter.resp_sn", + ntohl(script_resp->respsn), + ntohl(live_resp->respsn), + error)) || + (flags & FLAG_RECONFIG_RESULT_NOCHECK ? STATUS_OK : + check_field("reconfig_response_parameter.result", + ntohl(script_resp->result), + ntohl(live_resp->result), + error))) { + return STATUS_ERR; + } + if (live_resp->length == sizeof(struct sctp_reconfig_response_parameter)) { + if ((flags & FLAG_RECONFIG_SENDER_NEXT_TSN_NOCHECK ? STATUS_OK : + check_field("ssn_tsn_reset_request_parameter.sender_next_tsn", + ntohl(script_resp->sender_next_tsn), + ntohl(live_resp->sender_next_tsn), + error)) || + (flags & FLAG_RECONFIG_RECEIVER_NEXT_TSN_NOCHECK ? STATUS_OK : + check_field("sctp_reconfig_response_parameter.receiver_next_tsn", + ntohl(script_resp->receiver_next_tsn), + ntohl(live_resp->receiver_next_tsn), + error))) { + return STATUS_ERR; + } + } + break; + } + case SCTP_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_TYPE: { + struct sctp_add_outgoing_streams_request_parameter *live_add, *script_add; + + live_add = (struct sctp_add_outgoing_streams_request_parameter *)actual_parameter; + script_add = (struct sctp_add_outgoing_streams_request_parameter *)script_parameter; + if ((flags & FLAG_RECONFIG_REQ_SN_NOCHECK ? STATUS_OK : + check_field("add_outgoing_streams_request_parameter_parameter.req_sn", + ntohl(script_add->reqsn), + ntohl(live_add->reqsn), + error)) || + (flags & FLAG_RECONFIG_NUMBER_OF_NEW_STREAMS_NOCHECK ? STATUS_OK : + check_field_u16("add_outgoing_streams_request_parameter.number_of_new_streams", + ntohs(script_add->number_of_new_streams), + ntohs(live_add->number_of_new_streams), + error))) { + return STATUS_ERR; + } + break; + } + case SCTP_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_TYPE: { + struct sctp_add_incoming_streams_request_parameter *live_add, *script_add; + + live_add = (struct sctp_add_incoming_streams_request_parameter *)actual_parameter; + script_add = (struct sctp_add_incoming_streams_request_parameter *)script_parameter; + if ((flags & FLAG_RECONFIG_REQ_SN_NOCHECK ? STATUS_OK : + check_field("add_incoming_streams_request_parameter.req_sn", + ntohl(script_add->reqsn), + ntohl(live_add->reqsn), + error)) || + (flags & FLAG_RECONFIG_NUMBER_OF_NEW_STREAMS_NOCHECK ? STATUS_OK : + check_field_u16("add_incoming_streams_request_parameter.number_of_new_streams", + ntohs(script_add->number_of_new_streams), + ntohs(live_add->number_of_new_streams), + error))) { return STATUS_ERR; } + break; + } + default: + if ((flags & FLAG_PARAMETER_VALUE_NOCHECK) == 0) { + assert((flags & FLAG_PARAMETER_LENGTH_NOCHECK) == 0); + if (memcmp(script_parameter->value, + actual_parameter->value, + ntohs(actual_parameter->length) - sizeof(struct sctp_parameter))) { + asprintf(error, "live packet parameter value not as expected"); + return STATUS_ERR; + } + } } } if (actual_parameter != NULL) { @@ -1246,6 +1532,7 @@ static int verify_sctp_parameters(u8 *begin, u16 length, if (script_parameter_item != NULL) { DEBUGP("script chunk contains more parameters than actual chunk\n"); } + if ((actual_parameter != NULL) || (script_parameter_item != NULL)) { asprintf(error, "live chunk and expected chunk have not the same number of parameters"); @@ -1709,6 +1996,29 @@ 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_chunk_list_item *script_chunk_item, + u32 flags, char **error) +{ + struct sctp_init_chunk *script_chunk; + int parameter_length; + + script_chunk = (struct sctp_init_chunk *)script_chunk_item->chunk; + parameter_length = ntohs(actual_chunk->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; + } + //TODO: check Parameter + return verify_sctp_parameters(actual_chunk->parameter, + parameter_length, + script_chunk_item, + error); +} + /* Verify that required actual SCTP packet fields are as the script expected. */ static int verify_sctp( const struct packet *actual_packet, @@ -1849,6 +2159,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, + script_chunk_item, + flags, error); + break; default: result = STATUS_ERR; assert(!"unsupported SCTP chunk type"); diff --git a/gtests/net/packetdrill/sctp.h b/gtests/net/packetdrill/sctp.h index 0c737cf6ea67070986509d8604b8a7925e43e24e..badde3425886c0ce13f01fa1d9bbf36e84d542ea 100644 --- a/gtests/net/packetdrill/sctp.h +++ b/gtests/net/packetdrill/sctp.h @@ -53,6 +53,7 @@ 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 @@ -233,6 +234,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,6 +249,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_INCOMING_SSN_RESET_REQUEST_PARAMETER_TYPE 0x000e +#define SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_TYPE 0x000f +#define SCTP_RECONFIG_RESPONSE_PARAMETER_TYPE 0x0010 +#define SCTP_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_TYPE 0x0011 +#define SCTP_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_TYPE 0x0012 #define SCTP_ECN_CAPABLE_PARAMETER_TYPE 0x8000 #define SCTP_SUPPORTED_EXTENSIONS_PARAMETER_TYPE 0x8008 #define SCTP_PAD_PARAMETER_TYPE 0x8005 @@ -326,6 +340,53 @@ 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; + +struct sctp_incoming_ssn_reset_request_parameter { + __be16 type; + __be16 length; + __be32 reqsn; + __be16 sids[]; +} __packed; + +struct sctp_ssn_tsn_reset_request_parameter { + __be16 type; + __be16 length; + __be32 reqsn; +} __packed; + +struct sctp_reconfig_response_parameter { + __be16 type; + __be16 length; + __be32 respsn; + __be32 result; + __be32 sender_next_tsn; + __be32 receiver_next_tsn; +} __packed; + +struct sctp_add_outgoing_streams_request_parameter { + __be16 type; + __be16 length; + __be32 reqsn; + __be16 number_of_new_streams; + __be16 reserved; +} __packed; + +struct sctp_add_incoming_streams_request_parameter { + __be16 type; + __be16 length; + __be32 reqsn; + __be16 number_of_new_streams; + __be16 reserved; +} __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 diff --git a/gtests/net/packetdrill/sctp_chunk_to_string.c b/gtests/net/packetdrill/sctp_chunk_to_string.c index 027873a947c3b8b21fa4eec314a20a63a29a1ee2..007581c42bcf91b89313fd72a3388f9ec8e6b7a8 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,153 @@ 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, "req_sn=%u, ", reqsn); + fprintf(s, "resp_sn=%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]); + if (len > 0) + fprintf(s, ", "); + fprintf(s, "%hu", sid); + } + fputs("]", s); + return STATUS_OK; +} + +static int sctp_incoming_ssn_reset_request_parameter_to_string( + FILE *s, + struct sctp_incoming_ssn_reset_request_parameter *parameter, + char **error) +{ + u16 length; + u32 reqsn; + int len; + + length = ntohs(parameter->length); + reqsn = ntohl(parameter->reqsn); + fputs("INCOMING_SSN_RESET[", s); + fprintf(s, "len=%hu, ", length); + fprintf(s, "req_sn=%u ,", reqsn); + fputs("sids=[", s); + for(len = 0; len < ((length-8)/sizeof(u16)); len++) { + u16 sid; + sid = ntohs(parameter->sids[len]); + if (len > 0) + fprintf(s, ", "); + fprintf(s, "%hu", sid); + } + fputs("]", s); + return STATUS_OK; +} + +static int sctp_ssn_tsn_reset_request_parameter_to_string( + FILE *s, + struct sctp_ssn_tsn_reset_request_parameter *parameter, + char **error) +{ + u16 length; + u32 reqsn; + + length = ntohs(parameter->length); + reqsn = ntohl(parameter->reqsn); + + fputs("SSN_TSN_RESET[", s); + fprintf(s, "len=%hu, ", length); + fprintf(s, "req_sn=%u", reqsn); + fputs("]", s); + return STATUS_OK; +} + +static int sctp_reconfig_response_parameter_to_string( + FILE *s, + struct sctp_reconfig_response_parameter *parameter, + char **error) +{ + u16 length; + u32 respsn; + u32 result; + u32 sender_next_tsn; + u32 receiver_next_tsn; + + length = ntohs(parameter->length); + respsn = ntohl(parameter->respsn); + result = ntohl(parameter->result); + + fputs("RECONFIG_RESPONSE[", s); + fprintf(s, "len=%hu, ", length); + fprintf(s, "resp_sn=%u, ", respsn); + fprintf(s, "result=%u", result); + if (length == sizeof(struct sctp_reconfig_response_parameter)){ + sender_next_tsn = ntohl(parameter->sender_next_tsn); + receiver_next_tsn = ntohl(parameter->receiver_next_tsn); + fprintf(s, ", sender_next_tsn=%u, ", sender_next_tsn); + fprintf(s, "receiver_next_tsn=%u", receiver_next_tsn); + } + fputs("]", s); + return STATUS_OK; +} + +static int sctp_add_outgoing_streams_request_parameter_to_string( + FILE *s, + struct sctp_add_outgoing_streams_request_parameter *parameter, + char **error) +{ + u16 length; + u32 reqsn; + u16 number_of_new_streams; + + length = ntohs(parameter->length); + reqsn = ntohl(parameter->reqsn); + number_of_new_streams = ntohs(parameter->number_of_new_streams); + + fputs("ADD_OUTGOING_STREAMS[", s); + fprintf(s, "len=%hu, ", length); + fprintf(s, "req_sn=%u, ", reqsn); + fprintf(s, "number_of_new_streams=%hu", number_of_new_streams); + fputs("]", s); + return STATUS_OK; +} + +static int sctp_add_incoming_streams_request_parameter_to_string( + FILE *s, + struct sctp_add_incoming_streams_request_parameter *parameter, + char **error) +{ + u16 length; + u32 reqsn; + u16 number_of_new_streams; + + length = ntohs(parameter->length); + reqsn = ntohl(parameter->reqsn); + number_of_new_streams = ntohs(parameter->number_of_new_streams); + + fputs("ADD_INCOMING_STREAMS[", s); + fprintf(s, "len=%hu, ", length); + fprintf(s, "req_sn=%u, ", reqsn); + fprintf(s, "number_of_new_streams=%hu", number_of_new_streams); + fputs("]", s); + return STATUS_OK; +} + static int sctp_unknown_parameter_to_string( FILE *s, struct sctp_parameter *parameter, @@ -419,6 +569,30 @@ 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; + case SCTP_INCOMING_SSN_RESET_REQUEST_PARAMETER_TYPE: + result = sctp_incoming_ssn_reset_request_parameter_to_string(s, + (struct sctp_incoming_ssn_reset_request_parameter *)parameter, error); + break; + case SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_TYPE: + result = sctp_ssn_tsn_reset_request_parameter_to_string(s, + (struct sctp_ssn_tsn_reset_request_parameter *)parameter, error); + break; + case SCTP_RECONFIG_RESPONSE_PARAMETER_TYPE: + result = sctp_reconfig_response_parameter_to_string(s, + (struct sctp_reconfig_response_parameter *)parameter, error); + break; + case SCTP_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_TYPE: + result = sctp_add_outgoing_streams_request_parameter_to_string(s, + (struct sctp_add_outgoing_streams_request_parameter *)parameter, error); + break; + case SCTP_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_TYPE: + result = sctp_add_incoming_streams_request_parameter_to_string(s, + (struct sctp_add_incoming_streams_request_parameter *)parameter, error); + break; default: result = sctp_unknown_parameter_to_string(s, parameter, error); break; @@ -1374,6 +1548,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 +1676,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..2c5232c06d31bb31f89016ffb73899ee9c40bb8e 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,229 @@ sctp_pad_parameter_new(s64 len, u8 *padding) parameter_length, flags); } +struct sctp_parameter_list_item * +sctp_outgoing_ssn_reset_request_parameter_new(s64 reqsn, s64 respsn, s64 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); + if (reqsn == -1) { + flags |= FLAG_RECONFIG_REQ_SN_NOCHECK; + parameter->reqsn = 0; + } else { + parameter->reqsn = htonl((u32)reqsn); + } + if (respsn == -1) { + flags |= FLAG_RECONFIG_RESP_SN_NOCHECK; + parameter->respsn = 0; + } else { + parameter->respsn = htonl((u32)respsn); + } + if (last_tsn == -1) { + flags |= FLAG_RECONFIG_LAST_TSN_NOCHECK; + parameter->last_tsn = 0; + } else { + parameter->last_tsn = htonl((u32)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_incoming_ssn_reset_request_parameter_new(s64 reqsn, struct sctp_u16_list *sids) +{ + struct sctp_incoming_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_incoming_ssn_reset_request_parameter) + (sizeof(u16) * sid_len); + + parameter = malloc(parameter_length); + assert(parameter != NULL); + + parameter->type = htons(SCTP_INCOMING_SSN_RESET_REQUEST_PARAMETER_TYPE); + parameter->length = htons(parameter_length); + if (reqsn == -1) { + flags |= FLAG_RECONFIG_REQ_SN_NOCHECK; + parameter->reqsn = 0; + } else { + parameter->reqsn = htonl((u32)reqsn); + } + 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_reconfig_response_parameter_new(s64 respsn, s64 result, s64 sender_next_tsn, s64 receiver_next_tsn) +{ + struct sctp_reconfig_response_parameter *parameter; + u32 flags = 0; + u16 parameter_length; + + parameter_length = sizeof(struct sctp_reconfig_response_parameter); + if (receiver_next_tsn == -2 && sender_next_tsn == -2) { + parameter_length -=sizeof(u32); + parameter_length -=sizeof(u32); + } + parameter = malloc(parameter_length); + assert(parameter != NULL); + + parameter->type = htons(SCTP_RECONFIG_RESPONSE_PARAMETER_TYPE); + parameter->length = htons(parameter_length); + + if (respsn == -1) { + flags |= FLAG_RECONFIG_RESP_SN_NOCHECK; + parameter->respsn = 0; + } else { + parameter->respsn = htonl((u32)respsn); + } + if (result == -1) { + flags |= FLAG_RECONFIG_RESULT_NOCHECK; + parameter->result = 0; + } else { + parameter->result = htonl((u32)result); + } + if (receiver_next_tsn != -2 && sender_next_tsn != -2) { + if (sender_next_tsn == -1) { + flags |= FLAG_RECONFIG_SENDER_NEXT_TSN_NOCHECK; + parameter->sender_next_tsn = 0; + } else { + parameter->sender_next_tsn = htonl((u32)sender_next_tsn); + } + if (receiver_next_tsn == -1) { + flags |= FLAG_RECONFIG_RECEIVER_NEXT_TSN_NOCHECK; + parameter->receiver_next_tsn = 0; + } else { + parameter->receiver_next_tsn = htonl((u32)receiver_next_tsn); + } + } + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + parameter_length, flags); +} + +struct sctp_parameter_list_item * +sctp_ssn_tsn_reset_request_parameter_new(s64 reqsn) +{ + struct sctp_ssn_tsn_reset_request_parameter *parameter; + u32 flags = 0; + u16 parameter_length; + + parameter_length = sizeof(struct sctp_ssn_tsn_reset_request_parameter); + + parameter = malloc(parameter_length); + assert(parameter != NULL); + + parameter->type = htons(SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_TYPE); + parameter->length = htons(parameter_length); + + if (reqsn == -1) { + flags |= FLAG_RECONFIG_REQ_SN_NOCHECK; + parameter->reqsn = 0; + } else { + parameter->reqsn = htonl((u32)reqsn); + } + + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + parameter_length, flags); +} + +struct sctp_parameter_list_item * +sctp_add_outgoing_streams_request_parameter_new(s64 reqsn, s32 number_of_new_streams) +{ + struct sctp_add_outgoing_streams_request_parameter *parameter; + u32 flags = 0; + u16 parameter_length; + + parameter_length = sizeof(struct sctp_add_outgoing_streams_request_parameter); + + parameter = malloc(parameter_length); + assert(parameter != NULL); + + parameter->type = htons(SCTP_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_TYPE); + parameter->length = htons(parameter_length); + parameter->reserved = 0; + + if (reqsn == -1) { + flags |= FLAG_RECONFIG_REQ_SN_NOCHECK; + parameter->reqsn = 0; + } else { + parameter->reqsn = htonl((u32)reqsn); + } + if (reqsn == -1) { + flags |= FLAG_RECONFIG_NUMBER_OF_NEW_STREAMS_NOCHECK; + parameter->number_of_new_streams = 0; + } else { + parameter->number_of_new_streams = htons((u16)number_of_new_streams); + } + + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + parameter_length, flags); +} + +struct sctp_parameter_list_item * +sctp_add_incoming_streams_request_parameter_new(s64 reqsn, s32 number_of_new_streams) +{ + struct sctp_add_incoming_streams_request_parameter *parameter; + u32 flags = 0; + u16 parameter_length; + + parameter_length = sizeof(struct sctp_add_incoming_streams_request_parameter); + + parameter = malloc(parameter_length); + assert(parameter != NULL); + + parameter->type = htons(SCTP_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_TYPE); + parameter->length = htons(parameter_length); + parameter->reserved = 0; + + if (reqsn == -1) { + flags |= FLAG_RECONFIG_REQ_SN_NOCHECK; + parameter->reqsn = 0; + } else { + parameter->reqsn = htonl((u32)reqsn); + } + if (reqsn == -1) { + flags |= FLAG_RECONFIG_NUMBER_OF_NEW_STREAMS_NOCHECK; + parameter->number_of_new_streams = 0; + } else { + parameter->number_of_new_streams = htons((u16)number_of_new_streams); + } + + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + parameter_length, flags); +} + struct sctp_parameter_list_item * sctp_ecn_capable_parameter_new(void) { @@ -2313,9 +2651,81 @@ new_sctp_packet(int address_family, for (parameter_item = chunk_item->parameter_list->first; parameter_item != NULL; parameter_item = parameter_item->next) { - if (ntohs(parameter_item->parameter->type) == - SCTP_STATE_COOKIE_PARAMETER_TYPE) { + switch(ntohs(parameter_item->parameter->type)) { + case SCTP_STATE_COOKIE_PARAMETER_TYPE: continue; + case SCTP_OUTGOING_SSN_RESET_REQUEST_PARAMETER_TYPE: + if (parameter_item->flags & FLAG_RECONFIG_REQ_SN_NOCHECK) { + asprintf(error, + "reqsn value must be specified for inbound packets"); + return NULL; + } + if (parameter_item->flags & FLAG_RECONFIG_RESP_SN_NOCHECK) { + asprintf(error, + "respsn value must be specified for inbound packets"); + return NULL; + } + if (parameter_item->flags & FLAG_RECONFIG_LAST_TSN_NOCHECK) { + asprintf(error, + "last_tsn value must be specified for inbound packets"); + return NULL; + } + break; + case SCTP_INCOMING_SSN_RESET_REQUEST_PARAMETER_TYPE: + if (parameter_item->flags & FLAG_RECONFIG_REQ_SN_NOCHECK) { + asprintf(error, + "reqsn value must be specified for inbound packets"); + return NULL; + } + break; + case SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_TYPE: + if (parameter_item->flags & FLAG_RECONFIG_REQ_SN_NOCHECK) { + asprintf(error, + "reqsn value must be specified for inbound packets"); + return NULL; + } + break; + case SCTP_RECONFIG_RESPONSE_PARAMETER_TYPE: + if (parameter_item->flags & FLAG_RECONFIG_RESULT_NOCHECK) { + asprintf(error, + "result value must be specified for inbound packets"); + return NULL; + } + if (parameter_item->flags & FLAG_RECONFIG_SENDER_NEXT_TSN_NOCHECK) { + asprintf(error, + "sender_next_tsn value must be specified for inbound packets"); + return NULL; + } + if (parameter_item->flags & FLAG_RECONFIG_RECEIVER_NEXT_TSN_NOCHECK) { + asprintf(error, + "receiver_next_tsn value must be specified for inbound packets"); + return NULL; + } + break; + case SCTP_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_TYPE: + if (parameter_item->flags & FLAG_RECONFIG_REQ_SN_NOCHECK) { + asprintf(error, + "reqsn value must be specified for inbound packets"); + return NULL; + } + if (parameter_item->flags & FLAG_RECONFIG_NUMBER_OF_NEW_STREAMS_NOCHECK) { + asprintf(error, + "number_of_new_streams value must be specified for inbound packets"); + return NULL; + } + case SCTP_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_TYPE: + if (parameter_item->flags & FLAG_RECONFIG_REQ_SN_NOCHECK) { + asprintf(error, + "reqsn value must be specified for inbound packets"); + return NULL; + } + if (parameter_item->flags & FLAG_RECONFIG_NUMBER_OF_NEW_STREAMS_NOCHECK) { + asprintf(error, + "number_of_new_streams value must be specified for inbound packets"); + return NULL; + } + default: + break; } if (parameter_item->flags & FLAG_PARAMETER_LENGTH_NOCHECK) { asprintf(error, @@ -2507,6 +2917,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..74f93229200f29b6656a768436551e0cb510ea95 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,34 @@ sctp_supported_extensions_parameter_new(struct sctp_byte_list *list); struct sctp_parameter_list_item * sctp_pad_parameter_new(s64 len, u8 *padding); +#define FLAG_RECONFIG_REQ_SN_NOCHECK 0x00000010 +#define FLAG_RECONFIG_RESP_SN_NOCHECK 0x00000020 +#define FLAG_RECONFIG_LAST_TSN_NOCHECK 0x00000040 + +struct sctp_parameter_list_item * +sctp_outgoing_ssn_reset_request_parameter_new(s64 reqsn, s64 respsn, s64 last_tsn, struct sctp_u16_list *sids); + +struct sctp_parameter_list_item * +sctp_incoming_ssn_reset_request_parameter_new(s64 reqsn, struct sctp_u16_list *sids); + +struct sctp_parameter_list_item * +sctp_ssn_tsn_reset_request_parameter_new(s64 reqsn); + +#define FLAG_RECONFIG_RESULT_NOCHECK 0x00000010 +#define FLAG_RECONFIG_SENDER_NEXT_TSN_NOCHECK 0x00000040 +#define FLAG_RECONFIG_RECEIVER_NEXT_TSN_NOCHECK 0x00000080 + +struct sctp_parameter_list_item * +sctp_reconfig_response_parameter_new(s64 respsn, s64 result, s64 sender_next_tsn, s64 receiver_next_tsn); + +#define FLAG_RECONFIG_NUMBER_OF_NEW_STREAMS_NOCHECK 0x00000080 + +struct sctp_parameter_list_item * +sctp_add_outgoing_streams_request_parameter_new(s64 reqsn, s32 number_of_new_streams); + +struct sctp_parameter_list_item * +sctp_add_incoming_streams_request_parameter_new(s64 reqsn, s32 number_of_new_streams); + struct sctp_parameter_list * sctp_parameter_list_new(void); diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/add_incoming_streams.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/add_incoming_streams.pkt new file mode 100644 index 0000000000000000000000000000000000000000..756ffe60766cd3a9e2b95a687e4f7d24d35ad212 --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/add_incoming_streams.pkt @@ -0,0 +1,35 @@ +--tolerance_usecs=100000 + +// Create a non-blocking 1-to-1 style socket + 0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 ++0.0 fcntl(3, F_GETFL) = 0x02 (flags O_RDWR) ++0.0 fcntl(3, F_SETFL, O_RDWR | O_NONBLOCK) = 0 + ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=3, assoc_value=SCTP_ENABLE_RESET_STREAM_REQ}, 8) = 0 ++0.0 getsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=3, assoc_value=SCTP_ENABLE_RESET_STREAM_REQ}, [8]) = 0 + +// Trigger the active associtation setup ++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...] ++0.0 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=1, STATE_COOKIE[len=4, val=...], SUPPORTED_EXTENSIONS[types=[0x82]]] ++0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...] ++0.0 < sctp: COOKIE_ACK[flgs=0] + +// Check if the setup was sucessful ++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 +// Generate some traffic so the tsn and ssn increase ++0.0 write(3, ..., 1000) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]] + ++0.0 write(3, ..., 1000) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=1, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=1500, gaps=[], dups=[]] + +// Reset Stream 0 ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_ADD_STREAMS, {sas_assoc_id=3, + sas_instrms=10, + sas_outstrms=0}, 8) = 0 ++0.0 > sctp: RECONFIG[flgs=0, ADD_INCOMING_STREAMS[req_sn=1, number_of_new_streams=10]] + ++1.0 close(3) = 0 diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/add_outgoing_streams.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/add_outgoing_streams.pkt new file mode 100644 index 0000000000000000000000000000000000000000..88f99244b6499152afd5d629555f53b0f4c24f0f --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/add_outgoing_streams.pkt @@ -0,0 +1,35 @@ +--tolerance_usecs=100000 + +// Create a non-blocking 1-to-1 style socket + 0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 ++0.0 fcntl(3, F_GETFL) = 0x02 (flags O_RDWR) ++0.0 fcntl(3, F_SETFL, O_RDWR | O_NONBLOCK) = 0 + ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=3, assoc_value=SCTP_ENABLE_RESET_STREAM_REQ}, 8) = 0 ++0.0 getsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=3, assoc_value=SCTP_ENABLE_RESET_STREAM_REQ}, [8]) = 0 + +// Trigger the active associtation setup ++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...] ++0.0 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=1, STATE_COOKIE[len=4, val=...], SUPPORTED_EXTENSIONS[types=[0x82]]] ++0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...] ++0.0 < sctp: COOKIE_ACK[flgs=0] + +// Check if the setup was sucessful ++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 +// Generate some traffic so the tsn and ssn increase ++0.0 write(3, ..., 1000) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]] + ++0.0 write(3, ..., 1000) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=1, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=1500, gaps=[], dups=[]] + +// Reset Stream 0 ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_ADD_STREAMS, {sas_assoc_id=3, + sas_instrms=0, + sas_outstrms=10}, 8) = 0 ++0.0 > sctp: RECONFIG[flgs=0, ADD_OUTGOING_STREAMS[req_sn=1, number_of_new_streams=10]] + ++1.0 close(3) = 0 diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_incoming_ssn.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_incoming_ssn.pkt new file mode 100644 index 0000000000000000000000000000000000000000..1f6ef829eaf57128b79e5c45ecbc4a8b56f80729 --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_incoming_ssn.pkt @@ -0,0 +1,38 @@ +--tolerance_usecs=100000 + +// Create a non-blocking 1-to-1 style socket + 0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 ++0.0 fcntl(3, F_GETFL) = 0x02 (flags O_RDWR) ++0.0 fcntl(3, F_SETFL, O_RDWR | O_NONBLOCK) = 0 + ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=3, assoc_value=SCTP_ENABLE_RESET_STREAM_REQ}, 8) = 0 ++0.0 getsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=3, assoc_value=SCTP_ENABLE_RESET_STREAM_REQ}, [8]) = 0 + +// Trigger the active associtation setup ++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...] ++0.0 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=1, STATE_COOKIE[len=4, val=...], SUPPORTED_EXTENSIONS[types=[0x82]]] ++0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...] ++0.0 < sctp: COOKIE_ACK[flgs=0] + +// Check if the setup was sucessful ++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 +// Generate some traffic so the tsn and ssn increase ++0.0 write(3, ..., 1000) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]] + ++0.0 write(3, ..., 1000) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=1, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=1500, gaps=[], dups=[]] + +// Reset Stream 0 ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_RESET_STREAMS, {srs_assoc_id=3, + srs_flags=SCTP_STREAM_RESET_INCOMING, + srs_number_streams=0, + srs_stream_list=[]}, 8) = 0 ++0.0 > sctp: RECONFIG[flgs=0, INCOMING_SSN_RESET[req_sn=1]] ++0.0 < sctp: RECONFIG[flgs=0, OUTGOING_SSN_RESET[req_sn=1, resp_sn=1, last_tsn=0, sids=[]]] ++0.0 > sctp: RECONFIG[flgs=0, RECONFIG_RESPONSE[resp_sn=1, result=1]] + ++1.0 close(3) = 0 diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_incoming_ssn_passiv.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_incoming_ssn_passiv.pkt new file mode 100644 index 0000000000000000000000000000000000000000..85d71afdd2e14d109c22679aa6189541f798d1db --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_incoming_ssn_passiv.pkt @@ -0,0 +1,43 @@ + --tolerance_usecs=100000 ++0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 +// Check the handshake with en empty(!) cookie + ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=0, assoc_value=SCTP_ENABLE_RESET_STREAM_REQ}, 8) = 0 + ++0.0 bind(3, ..., ...) = 0 ++0.0 listen(3, 1) = 0 ++0.0 < sctp: INIT[flgs=0, tag=1, a_rwnd=1500, os=1, is=1, tsn=1, + ECN_CAPABLE[], + SUPPORTED_EXTENSIONS[types=[RECONFIG]], + COOKIE_PRESERVATIVE[incr=12345], + SUPPORTED_ADDRESS_TYPES[types=[IPv4]]] ++0.0 > sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=..., os=..., is=..., tsn=10, ...] ++0.1 < sctp: COOKIE_ECHO[flgs=0, len=..., val=...] ++0.0 > sctp: COOKIE_ACK[flgs=0] + ++0.0 accept(3, ..., ...) = 4 + ++1.0 write(4, ..., 1000) = 1000 +* > sctp: DATA[flgs=BE, len=1016, tsn=10, sid=0, ssn=0, ppid=0] ++0.1 < sctp: SACK[flgs=0, cum_tsn=10, a_rwnd=1500, gaps=[], dups=[]] + +// Send some data. ++1.0 write(4, ..., 1000) = 1000 +* > sctp: DATA[flgs=BE, len=1016, tsn=11, sid=0, ssn=1, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=11, a_rwnd=1500, gaps=[], dups=[]] + ++0.1 < sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0] +* > sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=..., gaps=[], dups=[]] ++0.0 read(4, ..., 1000) = 1000 + ++0.1 < sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=1, ppid=0] +* > sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=..., gaps=[], dups=[]] ++0.0 read(4, ..., 1000) = 1000 + ++0.1 < sctp: DATA[flgs=BE, len=1016, tsn=3, sid=0, ssn=2, ppid=0] +* > sctp: SACK[flgs=0, cum_tsn=3, a_rwnd=..., gaps=[], dups=[]] ++0.0 read(4, ..., 1000) = 1000 + ++0.0 < sctp: RECONFIG[flgs=0, INCOMING_SSN_RESET[req_sn=1, sids=[0]]] ++0.0 > sctp: RECONFIG[flgs=0, OUTGOING_SSN_RESET[req_sn=..., resp_sn=..., last_tsn=..., sids=[]]]; RECONFIG[flgs=0, RECONFIG_RESPONSE[resp_sn=1, result=1]] ++0.0 < sctp: RECONFIG[flgs=0, RECONFIG_RESPONSE[resp_sn=10, result=1]] diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_outgoing_ssn.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_outgoing_ssn.pkt new file mode 100644 index 0000000000000000000000000000000000000000..21c179cb224a9f5c82e224845825ff42e2d7f1cf --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_outgoing_ssn.pkt @@ -0,0 +1,37 @@ +--tolerance_usecs=100000 + +// Create a non-blocking 1-to-1 style socket + 0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 ++0.0 fcntl(3, F_GETFL) = 0x02 (flags O_RDWR) ++0.0 fcntl(3, F_SETFL, O_RDWR | O_NONBLOCK) = 0 + ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=3, assoc_value=SCTP_ENABLE_RESET_STREAM_REQ}, 8) = 0 ++0.0 getsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=3, assoc_value=SCTP_ENABLE_RESET_STREAM_REQ}, [8]) = 0 + +// Trigger the active associtation setup ++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...] ++0.0 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=1, STATE_COOKIE[len=4, val=...], SUPPORTED_EXTENSIONS[types=[0x82]]] ++0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...] ++0.0 < sctp: COOKIE_ACK[flgs=0] + +// Check if the setup was sucessful ++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 +// Generate some traffic so the tsn and ssn increase ++0.0 write(3, ..., 1000) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]] + ++0.0 write(3, ..., 1000) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=1, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=1500, gaps=[], dups=[]] + +// Reset Stream 0 ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_RESET_STREAMS, {srs_assoc_id=3, + srs_flags=SCTP_STREAM_RESET_OUTGOING, + srs_number_streams=2, + srs_stream_list=[0, 1]}, 12) = 0 ++0.0 > sctp: RECONFIG[flgs=0, OUTGOING_SSN_RESET[req_sn=1, resp_sn=0, last_tsn=2, sids=[]]] ++0.0 < sctp: RECONFIG[flgs=0, RECONFIG_RESPONSE[resp_sn=1, result=1]] + ++1.0 close(3) = 0 diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_outgoing_ssn_passiv.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_outgoing_ssn_passiv.pkt new file mode 100644 index 0000000000000000000000000000000000000000..e130bb9792abc07930d7f6b71d5fbf870ba45311 --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_outgoing_ssn_passiv.pkt @@ -0,0 +1,38 @@ + --tolerance_usecs=100000 ++0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 +// Check the handshake with en empty(!) cookie + ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=0, assoc_value=SCTP_ENABLE_RESET_STREAM_REQ}, 8) = 0 + ++0.0 bind(3, ..., ...) = 0 ++0.0 listen(3, 1) = 0 ++0.0 < sctp: INIT[flgs=0, tag=1, a_rwnd=1500, os=1, is=1, tsn=1, + ECN_CAPABLE[], + SUPPORTED_EXTENSIONS[types=[RECONFIG]], + COOKIE_PRESERVATIVE[incr=12345], + SUPPORTED_ADDRESS_TYPES[types=[IPv4]]] ++0.0 > sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=..., os=..., is=..., tsn=10, ...] ++0.1 < sctp: COOKIE_ECHO[flgs=0, len=..., val=...] ++0.0 > sctp: COOKIE_ACK[flgs=0] + ++0.0 accept(3, ..., ...) = 4 + ++1.0 write(4, ..., 1000) = 1000 +* > sctp: DATA[flgs=BE, len=1016, tsn=10, sid=0, ssn=0, ppid=0] ++0.1 < sctp: SACK[flgs=0, cum_tsn=10, a_rwnd=1500, gaps=[], dups=[]] + +// Send some data. ++1.0 write(4, ..., 1000) = 1000 +* > sctp: DATA[flgs=BE, len=1016, tsn=11, sid=0, ssn=1, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=11, a_rwnd=1500, gaps=[], dups=[]] + ++0.1 < sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0] +* > sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=..., gaps=[], dups=[]] ++0.0 read(4, ..., 1000) = 1000 + ++0.1 < sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=1, ppid=0] +* > sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=..., gaps=[], dups=[]] ++0.0 read(4, ..., 1000) = 1000 + ++0.0 < sctp: RECONFIG[flgs=0, OUTGOING_SSN_RESET[req_sn=0, resp_sn=0, last_tsn=11, sids=[0]]] ++0.0 > sctp: RECONFIG[flgs=0, RECONFIG_RESPONSE[resp_sn=..., result=...]] diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_ssn_tsn.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_ssn_tsn.pkt new file mode 100644 index 0000000000000000000000000000000000000000..2d38a7d3b1c801d1f258109f16ff9fe9f253229c --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_ssn_tsn.pkt @@ -0,0 +1,34 @@ +--tolerance_usecs=100000 + +// Create a non-blocking 1-to-1 style socket + 0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 ++0.0 fcntl(3, F_GETFL) = 0x02 (flags O_RDWR) ++0.0 fcntl(3, F_SETFL, O_RDWR | O_NONBLOCK) = 0 + ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=3, assoc_value=SCTP_ENABLE_RESET_ASSOC_REQ}, 8) = 0 ++0.0 getsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=3, assoc_value=SCTP_ENABLE_RESET_ASSOC_REQ}, [8]) = 0 + +// Trigger the active associtation setup ++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...] ++0.0 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=1, STATE_COOKIE[len=4, val=...], SUPPORTED_EXTENSIONS[types=[0x82]]] ++0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...] ++0.0 < sctp: COOKIE_ACK[flgs=0] + +// Check if the setup was sucessful ++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 +// Generate some traffic so the tsn and ssn increase ++0.0 write(3, ..., 1000) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]] + ++0.0 write(3, ..., 1000) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=1, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=1500, gaps=[], dups=[]] + +// Reset Stream 0 ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_RESET_ASSOC, [3], 12) = 0 ++0.0 > sctp: RECONFIG[flgs=0, SSN_TSN_RESET[req_sn=1]] ++0.0 < sctp: RECONFIG[flgs=0, RECONFIG_RESPONSE[resp_sn=1, result=1]] + ++1.0 close(3) = 0 diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_ssn_tsn_passiv.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_ssn_tsn_passiv.pkt new file mode 100644 index 0000000000000000000000000000000000000000..76e0a88a1938ab70800a308e2c8d429b566654b3 --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_ssn_tsn_passiv.pkt @@ -0,0 +1,38 @@ + --tolerance_usecs=100000 ++0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 +// Check the handshake with en empty(!) cookie + ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, {assoc_id=0, assoc_value=SCTP_ENABLE_RESET_ASSOC_REQ}, 8) = 0 + ++0.0 bind(3, ..., ...) = 0 ++0.0 listen(3, 1) = 0 ++0.0 < sctp: INIT[flgs=0, tag=1, a_rwnd=1500, os=1, is=1, tsn=1, + ECN_CAPABLE[], + SUPPORTED_EXTENSIONS[types=[RECONFIG]], + COOKIE_PRESERVATIVE[incr=12345], + SUPPORTED_ADDRESS_TYPES[types=[IPv4]]] ++0.0 > sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=..., os=..., is=..., tsn=10, ...] ++0.1 < sctp: COOKIE_ECHO[flgs=0, len=..., val=...] ++0.0 > sctp: COOKIE_ACK[flgs=0] + ++0.0 accept(3, ..., ...) = 4 + ++1.0 write(4, ..., 1000) = 1000 +* > sctp: DATA[flgs=BE, len=1016, tsn=10, sid=0, ssn=0, ppid=0] ++0.1 < sctp: SACK[flgs=0, cum_tsn=10, a_rwnd=1500, gaps=[], dups=[]] + +// Send some data. ++1.0 write(4, ..., 1000) = 1000 +* > sctp: DATA[flgs=BE, len=1016, tsn=11, sid=0, ssn=1, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=11, a_rwnd=1500, gaps=[], dups=[]] + ++0.1 < sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0] +* > sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=..., gaps=[], dups=[]] ++0.0 read(4, ..., 1000) = 1000 + ++0.1 < sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=1, ppid=0] +* > sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=..., gaps=[], dups=[]] ++0.0 read(4, ..., 1000) = 1000 + ++0.0 < sctp: RECONFIG[flgs=0, SSN_TSN_RESET[req_sn=0]] ++0.0 > sctp: RECONFIG[flgs=0, RECONFIG_RESPONSE[resp_sn=0, result=0, sender_next_tsn=0, receiver_next_tsn=0]]