From d9b9256c0c3ec0ad0ae4477f6ce3760385c8d06e Mon Sep 17 00:00:00 2001
From: Hoelscher <jens.hoelscher@fh-muenster.de>
Date: Mon, 14 Mar 2016 19:42:46 +0100
Subject: [PATCH] add support for add_outgoing_streams parameter

---
 gtests/net/packetdrill/lexer.l                |  1 +
 gtests/net/packetdrill/parser.y               | 11 ++++-
 gtests/net/packetdrill/run_packet.c           | 12 +++++
 gtests/net/packetdrill/sctp.h                 |  9 ++++
 gtests/net/packetdrill/sctp_chunk_to_string.c | 25 +++++++++++
 gtests/net/packetdrill/sctp_packet.c          | 44 +++++++++++++++++++
 gtests/net/packetdrill/sctp_packet.h          |  3 ++
 7 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index 5ecfac26..d08de406 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -570,6 +570,7 @@ 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;
diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index 776a238f..c8278217 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -528,6 +528,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %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
@@ -689,7 +690,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %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 incoming_ssn_reset_request
-%type <parameter_list_item> reconfig_response ssn_tsn_reset_request add_incoming_streams_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
@@ -1748,6 +1750,7 @@ sctp_reconfig_parameter_spec
 | incoming_ssn_reset_request	{ $$ = $1; }
 | ssn_tsn_reset_request		{ $$ = $1; }
 | reconfig_response		{ $$ = $1; }
+| add_outgoing_streams_request  { $$ = $1; }
 | add_incoming_streams_request  { $$ = $1; }
 ;
  
@@ -1814,6 +1817,12 @@ reconfig_response
 }
 ;
 
+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);
diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c
index 2e91a37c..9951aa06 100644
--- a/gtests/net/packetdrill/run_packet.c
+++ b/gtests/net/packetdrill/run_packet.c
@@ -780,6 +780,12 @@ static int map_inbound_sctp_packet(
 						}
 						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;
@@ -1029,6 +1035,12 @@ static int map_outbound_live_sctp_packet(
 						}
 						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;
diff --git a/gtests/net/packetdrill/sctp.h b/gtests/net/packetdrill/sctp.h
index bd590b52..e388ebb2 100644
--- a/gtests/net/packetdrill/sctp.h
+++ b/gtests/net/packetdrill/sctp.h
@@ -252,6 +252,7 @@ struct sctp_reconfig_chunk {
 #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
@@ -368,6 +369,14 @@ struct sctp_reconfig_response_parameter {
 	__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;
diff --git a/gtests/net/packetdrill/sctp_chunk_to_string.c b/gtests/net/packetdrill/sctp_chunk_to_string.c
index d4124883..729d6297 100644
--- a/gtests/net/packetdrill/sctp_chunk_to_string.c
+++ b/gtests/net/packetdrill/sctp_chunk_to_string.c
@@ -421,6 +421,27 @@ static int sctp_reconfig_response_parameter_to_string(
 	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,
@@ -564,6 +585,10 @@ static int sctp_parameter_to_string(FILE *s,
 		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);
diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c
index 5a30c97d..1e60c071 100644
--- a/gtests/net/packetdrill/sctp_packet.c
+++ b/gtests/net/packetdrill/sctp_packet.c
@@ -1951,6 +1951,39 @@ sctp_ssn_tsn_reset_request_parameter_new(s64 reqsn)
 					    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)
 {
@@ -2669,6 +2702,17 @@ new_sctp_packet(int address_family,
 						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,
diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h
index e468018c..74f93229 100644
--- a/gtests/net/packetdrill/sctp_packet.h
+++ b/gtests/net/packetdrill/sctp_packet.h
@@ -398,6 +398,9 @@ sctp_reconfig_response_parameter_new(s64 respsn, s64 result, s64 sender_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);
 
-- 
GitLab