From e1d55385f261d16a479585317c4604b1a2a3b29d Mon Sep 17 00:00:00 2001
From: Hoelscher <jens.hoelscher@fh-muenster.de>
Date: Fri, 11 Mar 2016 17:13:55 +0100
Subject: [PATCH] add support for reconfig chunk

---
 gtests/net/packetdrill/lexer.l                |   6 +
 gtests/net/packetdrill/parser.y               |  95 ++++++++++-
 gtests/net/packetdrill/run_packet.c           |  78 +++++++++
 gtests/net/packetdrill/run_system_call.c      |   9 +-
 gtests/net/packetdrill/sctp.h                 |  21 ++-
 gtests/net/packetdrill/sctp_chunk_to_string.c |  77 +++++++++
 gtests/net/packetdrill/sctp_packet.c          | 150 ++++++++++++++++++
 gtests/net/packetdrill/sctp_packet.h          |  30 ++++
 .../sctp/sctp_reconfig/sctp_reset_streams.pkt |   1 -
 9 files changed, 456 insertions(+), 11 deletions(-)

diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index f54f7a59..71be6360 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 3ac46b64..9c4d58a2 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 819587d9..7746efff 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 492abf05..0db21c3b 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 0c737cf6..6a85c2cf 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 027873a9..51cb105e 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 7c11497e..ff1df004 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 4defa504..50d3bb8a 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 90731a2c..b44f2bd4 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,
-- 
GitLab