From 4acf383d093d245c8792d7099b42fd0f5c589b21 Mon Sep 17 00:00:00 2001
From: Hoelscher <jens.hoelscher@fh-muenster.de>
Date: Mon, 14 Mar 2016 12:27:08 +0100
Subject: [PATCH] add support for reconfig_response parameter

---
 gtests/net/packetdrill/lexer.l                |  5 +-
 gtests/net/packetdrill/parser.y               | 59 +++++++++++++--
 gtests/net/packetdrill/run_packet.c           | 20 ++++++
 gtests/net/packetdrill/sctp.h                 | 10 +++
 gtests/net/packetdrill/sctp_chunk_to_string.c | 31 +++++++-
 gtests/net/packetdrill/sctp_packet.c          | 71 +++++++++++++++++--
 gtests/net/packetdrill/sctp_packet.h          | 12 +++-
 .../sctp/sctp_reconfig/reset_outgoing_ssn.pkt |  2 +-
 .../reset_outgoing_ssn_passiv.pkt             |  2 +-
 9 files changed, 196 insertions(+), 16 deletions(-)

diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index e6decf23..17e8f55e 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -567,11 +567,14 @@ gaps				return GAPS;
 dups				return DUPS;
 adaptation_code_point		return ADAPTATION_CODE_POINT;
 OUTGOING_SSN_RESET		return OUTGOING_SSN_RESET;
+RECONFIG_RESPONSE		return RECONFIG_RESPONSE;
 req_sn				return REQ_SN;
 resp_sn				return RESP_SN;
 last_tsn			return LAST_TSN;
-result				return RESULT;
 sids				return SIDS;
+result				return RESULT;
+sender_next_tsn			return SENDER_NEXT_TSN;
+receiver_next_tsn		return RECEIVER_NEXT_TSN;
 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 eaa91c25..a9051530 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -525,7 +525,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %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 RESULT
+%token <reserved> OUTGOING_SSN_RESET REQ_SN RESP_SN LAST_TSN SIDS 
+%token <reserved> RECONFIG_RESPONSE RESULT SENDER_NEXT_TSN RECEIVER_NEXT_TSN
 %token <reserved> ADDR INCR TYPES PARAMS
 %token <reserved> IPV4_TYPE IPV6_TYPE HOSTNAME_TYPE
 %token <reserved> CAUSE
@@ -686,6 +687,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %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 sctp_reconfig_parameter_spec
+%type <parameter_list_item> outgoing_ssn_reset_request reconfig_response
 %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
@@ -707,8 +709,8 @@ 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_req_sn opt_resp_sn opt_last_tsn
+%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
 %type <byte_list> opt_val opt_info byte_list chunk_types_list
 %type <byte_list_item> byte 
 %type <u16_list> u16_list
@@ -1690,7 +1692,7 @@ sctp_pad_chunk_spec
 
 opt_req_sn
 : REQ_SN '=' INTEGER {
-	if (!is_valid_u16($3)) {
+	if (!is_valid_u32($3)) {
 		semantic_error("req_sn out of range");
 	}
 	$$ = $3;
@@ -1700,7 +1702,7 @@ opt_req_sn
 
 opt_resp_sn
 : RESP_SN '=' INTEGER {
-	if (!is_valid_u16($3)) {
+	if (!is_valid_u32($3)) {
 		semantic_error("resp_sn out of range");
 	}
 	$$ = $3;
@@ -1710,7 +1712,7 @@ opt_resp_sn
 
 opt_last_tsn
 : LAST_TSN '=' INTEGER {
-	if (!is_valid_u16($3)) {
+	if (!is_valid_u32($3)) {
 		semantic_error("last_tsn out of range");
 	}
 	$$ = $3;
@@ -1718,6 +1720,16 @@ opt_last_tsn
 | 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();
@@ -1730,7 +1742,31 @@ sctp_reconfig_parameter_list_spec
 ;
 
 sctp_reconfig_parameter_spec
-: OUTGOING_SSN_RESET '[' opt_req_sn ',' opt_resp_sn ',' opt_last_tsn ']' {
+:outgoing_ssn_reset_request { $$ = $1; }
+|reconfig_response          { $$ = $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; }
+;
+
+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 ']' ']' {
@@ -1738,6 +1774,15 @@ sctp_reconfig_parameter_spec
 }
 ;
 
+reconfig_response
+:RECONFIG_RESPONSE '[' opt_resp_sn ',' opt_result ']' {
+	$$ = sctp_reconfig_response_new($3, $5, -2, -2);
+}
+|RECONFIG_RESPONSE '[' opt_resp_sn ',' opt_result ',' opt_sender_next_tsn ',' opt_receiver_next_tsn']' {
+	$$ = sctp_reconfig_response_new($3, $5, $7, $9);
+}
+;
+
 sctp_reconfig_chunk_spec
 : RECONFIG '[' opt_flags ',' sctp_reconfig_parameter_list_spec ']' {
 	$$ = sctp_reconfig_chunk_new($3, $5);
diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c
index 190de08e..79953ee8 100644
--- a/gtests/net/packetdrill/run_packet.c
+++ b/gtests/net/packetdrill/run_packet.c
@@ -758,6 +758,16 @@ static int map_inbound_sctp_packet(
 						reset->last_tsn = htonl(ntohl(reset->last_tsn) + 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;
+					}
 					default:
 						//do nothing
 						break;
@@ -979,6 +989,16 @@ static int map_outbound_live_sctp_packet(
 						reset->last_tsn = htonl(ntohl(reset->last_tsn) + 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;
+					}
 					default:
 						//do nothing
 						break;
diff --git a/gtests/net/packetdrill/sctp.h b/gtests/net/packetdrill/sctp.h
index 6a85c2cf..84bdeff7 100644
--- a/gtests/net/packetdrill/sctp.h
+++ b/gtests/net/packetdrill/sctp.h
@@ -249,6 +249,7 @@ struct sctp_reconfig_chunk {
 #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_RECONFIG_RESPONSE_PARAMETER_TYPE           0x0010
 #define SCTP_ECN_CAPABLE_PARAMETER_TYPE			0x8000
 #define SCTP_SUPPORTED_EXTENSIONS_PARAMETER_TYPE	0x8008
 #define SCTP_PAD_PARAMETER_TYPE				0x8005
@@ -342,6 +343,15 @@ struct sctp_outgoing_ssn_reset_request_parameter {
 	__be16 sids[];
 } __packed;
 
+struct sctp_reconfig_response_parameter {
+	__be16 type;
+	__be16 length;
+	__be32 respsn;
+	__be32 result;
+	__be32 sender_next_tsn;
+	__be32 receiver_next_tsn;
+} __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 4f305262..c3634c54 100644
--- a/gtests/net/packetdrill/sctp_chunk_to_string.c
+++ b/gtests/net/packetdrill/sctp_chunk_to_string.c
@@ -348,6 +348,31 @@ static int sctp_outgoing_ssn_reset_request_parameter_to_string(
 	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 sender_next_tsn;
+	u32 receiver_next_tsn;
+
+	length = ntohs(parameter->length);
+	respsn = ntohl(parameter->respsn);
+	fputs("RECONFIG_RESPONSE[", s);
+	fprintf(s, "len=%hu, ", length);
+	fprintf(s, "resp_sn=%u", respsn);
+	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_unknown_parameter_to_string(
 	FILE *s,
 	struct sctp_parameter *parameter,
@@ -457,7 +482,11 @@ static int sctp_parameter_to_string(FILE *s,
 	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;		
+		break;
+	case SCTP_RECONFIG_RESPONSE_PARAMETER_TYPE:
+		result = sctp_reconfig_response_parameter_to_string(s,
+			(struct sctp_reconfig_response_parameter *)parameter, error);
+		break;
 	default:
 		result = sctp_unknown_parameter_to_string(s, parameter, error);
 		break;
diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c
index ff1df004..126d1f51 100644
--- a/gtests/net/packetdrill/sctp_packet.c
+++ b/gtests/net/packetdrill/sctp_packet.c
@@ -1795,7 +1795,7 @@ 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)
+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;
@@ -1813,9 +1813,24 @@ sctp_outgoing_ssn_reset_request_parameter_new(u32 reqsn, u32 respsn, u32 last_ts
 
 	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 (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) {
@@ -1827,6 +1842,54 @@ sctp_outgoing_ssn_reset_request_parameter_new(u32 reqsn, u32 respsn, u32 last_ts
 					    parameter_length, flags);
 }
 
+struct sctp_parameter_list_item *
+sctp_reconfig_response_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_ecn_capable_parameter_new(void)
 {
diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h
index 50d3bb8a..530530e9 100644
--- a/gtests/net/packetdrill/sctp_packet.h
+++ b/gtests/net/packetdrill/sctp_packet.h
@@ -376,8 +376,18 @@ 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                            0x00000001
+#define FLAG_RECONFIG_RESP_SN_NOCHECK                           0x00000002
+#define FLAG_RECONFIG_LAST_TSN_NOCHECK                          0x00000004
+
+struct sctp_parameter_list_item *
+sctp_outgoing_ssn_reset_request_parameter_new(s64 reqsn, s64 respsn, s64 last_tsn, struct sctp_u16_list *sids);
+
+#define FLAG_RECONFIG_RESULT_NOCHECK                            0x00000001
+#define FLAG_RECONFIG_SENDER_NEXT_TSN_NOCHECK                   0x00000004
+#define FLAG_RECONFIG_RECEIVER_NEXT_TSN_NOCHECK                 0x00000008
 struct sctp_parameter_list_item *
-sctp_outgoing_ssn_reset_request_parameter_new(u32 reqsn, u32 respsn, u32 last_tsn, struct sctp_u16_list *sids);
+sctp_reconfig_response_new(s64 respsn, s64 result, s64 sender_next_tsn, s64 receiver_next_tsn);
 
 struct sctp_parameter_list *
 sctp_parameter_list_new(void);
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
index 5424fcf0..21c179cb 100644
--- 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
@@ -32,6 +32,6 @@
                                                       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=0, result=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_outgoing_ssn_passiv.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_reconfig/reset_outgoing_ssn_passiv.pkt
index 56d50dc0..45f0576e 100644
--- 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
@@ -35,4 +35,4 @@
 +0.0 read(4, ..., 1000) = 1000
 
 +0.0 < sctp: RECONFIG[flgs=0, OUTGOING_SSN_RESET[req_sn=0, resp_sn=10, last_tsn=2, sids=[0]]]
-+0.0 > sctp: RECONFIG[flgs=0, RECONFIG_RESPONSE[resp_sn=10, result=0]]
++0.0 > sctp: RECONFIG[flgs=0, RECONFIG_RESPONSE[resp_sn=0, result=0]]
-- 
GitLab