From 0aacdfff5eb50f246713a8b5d6f201b146cd6661 Mon Sep 17 00:00:00 2001
From: hoelscher <jens.hoelscher@fh-muenster.de>
Date: Thu, 1 Oct 2015 22:45:47 +0200
Subject: [PATCH] Modify socketoption sctp_initmsg to use expressions

---
 gtests/net/packetdrill/parser.y               | 59 ++++++++----
 gtests/net/packetdrill/run_system_call.c      | 89 ++++++++++++++++++-
 gtests/net/packetdrill/script.c               | 48 +++++++++-
 gtests/net/packetdrill/script.h               | 13 ++-
 .../bsd/sctp/sctp_get_socket_options.pkt      | 18 ++--
 5 files changed, 200 insertions(+), 27 deletions(-)

diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index a33fc4e8..14a3a50f 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -573,7 +573,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <expression> linger l_onoff l_linger
 %type <expression> sctp_status sstat_state sstat_rwnd sstat_unackdata sstat_penddata
 %type <expression> sstat_instrms sstat_outstrms sstat_fragmentation_point sstat_primary
-%type <expression> sctp_initmsg sctp_assoc_value sctp_stream_value sctp_sackinfo
+%type <expression> sctp_initmsg sinit_num_ostreams sinit_max_instreams sinit_max_attempts 
+%type <expression> sinit_max_init_timeo sctp_assoc_value sctp_stream_value sctp_sackinfo
 %type <expression> sctp_rtoinfo srto_initial srto_max srto_min sctp_paddrinfo
 %type <expression> sctp_paddrparams spp_address spp_hbinterval spp_pathmtu spp_pathmaxrxt
 %type <expression> spp_flags spp_ipv6_flowlabel spp_dscp
@@ -2551,29 +2552,55 @@ sctp_rtoinfo
 }
 ;
 
-sctp_initmsg
-: '{' SINIT_NUM_OSTREAMS '=' INTEGER ',' SINIT_MAX_INSTREAMS '=' INTEGER ',' SINIT_MAX_ATTEMPTS '=' INTEGER ',' SINIT_MAX_INIT_TIMEO '=' INTEGER '}' {
-#ifdef SCTP_INITMSG
-	$$ = new_expression(EXPR_SCTP_INITMSG);
-	if (!is_valid_u16($4)) {
+sinit_num_ostreams
+: SINIT_NUM_OSTREAMS '=' INTEGER {
+	if (!is_valid_u16($3)) {
 		semantic_error("sinit_num_ostreams out of range");
 	}
-	$$->value.sctp_initmsg.sinit_num_ostreams = $4;
-	if (!is_valid_u16($8)) {
+	$$ = new_integer_expression($3, "%hu");
+}
+| SINIT_NUM_OSTREAMS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sinit_max_instreams
+: SINIT_MAX_INSTREAMS '=' INTEGER {
+	if (!is_valid_u16($3)) {
 		semantic_error("sinit_max_instreams out of range");
 	}
-	$$->value.sctp_initmsg.sinit_max_instreams = $8;
-	if (!is_valid_u16($12)) {
+	$$ = new_integer_expression($3, "%hu");
+}
+| SINIT_MAX_INSTREAMS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sinit_max_attempts
+: SINIT_MAX_ATTEMPTS '=' INTEGER {
+	if (!is_valid_u16($3)) {
 		semantic_error("sinit_max_attempts out of range");
 	}
-	$$->value.sctp_initmsg.sinit_max_attempts = $12;
-	if (!is_valid_u16($16)) {
+	$$ = new_integer_expression($3, "%hu");
+}
+| SINIT_MAX_ATTEMPTS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sinit_max_init_timeo
+: SINIT_MAX_INIT_TIMEO '=' INTEGER {
+	if (!is_valid_u16($3)) {
 		semantic_error("sinit_max_init_timeo out of range");
 	}
-	$$->value.sctp_initmsg.sinit_max_init_timeo = $16;
-#else
-	$$ = NULL;
-#endif
+	$$ = new_integer_expression($3, "%hu");
+}
+| SINIT_MAX_INIT_TIMEO '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sctp_initmsg
+: '{' sinit_num_ostreams ',' sinit_max_instreams ',' sinit_max_attempts ',' sinit_max_init_timeo '}' 
+{
+	$$ = new_expression(EXPR_SCTP_INITMSG);
+	$$->value.sctp_paddrinfo = calloc(1, sizeof(struct sctp_initmsg_expr));
+	$$->value.sctp_initmsg->sinit_num_ostreams = $2;
+	$$->value.sctp_initmsg->sinit_max_instreams = $4;
+	$$->value.sctp_initmsg->sinit_max_attempts = $6;
+	$$->value.sctp_initmsg->sinit_max_init_timeo = $8;
 }
 ;
 
diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index ad128901..15fcbaf7 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -1748,6 +1748,62 @@ static int check_sctp_rtoinfo(struct sctp_rtoinfo_expr *expr,
 }
 #endif
 
+#ifdef SCTP_INITMSG
+static int check_sctp_initmsg(struct sctp_initmsg_expr *expr,
+                              struct sctp_initmsg *sctp_initmsg, char **error)
+{
+	if (expr->sinit_num_ostreams->type != EXPR_ELLIPSIS) {
+		u16 sinit_num_ostreams;
+
+		if (get_u16(expr->sinit_num_ostreams, &sinit_num_ostreams, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_initmsg->sinit_num_ostreams != sinit_num_ostreams) {
+			asprintf(error, "Bad getsockopt sctp_initmsg.sinit_num_ostreams: expected: %hu actual: %hu",
+				 sinit_num_ostreams, sctp_initmsg->sinit_num_ostreams);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sinit_max_instreams->type != EXPR_ELLIPSIS) {
+		u16 sinit_max_instreams;
+
+		if (get_u16(expr->sinit_max_instreams, &sinit_max_instreams, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_initmsg->sinit_max_instreams != sinit_max_instreams) {
+			asprintf(error, "Bad getsockopt sctp_initmsg.sinit_max_instreams: expected: %hu actual: %hu",
+				 sinit_max_instreams, sctp_initmsg->sinit_max_instreams);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sinit_max_attempts->type != EXPR_ELLIPSIS) {
+		u16 sinit_max_attempts;
+
+		if (get_u16(expr->sinit_max_attempts, &sinit_max_attempts, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_initmsg->sinit_max_attempts != sinit_max_attempts) {
+			asprintf(error, "Bad getsockopt sctp_initmsg.sinit_max_attempts: expected: %hu actual: %hu",
+				 sinit_max_attempts, sctp_initmsg->sinit_max_attempts);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sinit_max_init_timeo->type != EXPR_ELLIPSIS) {
+		u16 sinit_max_init_timeo;
+
+		if (get_u16(expr->sinit_max_init_timeo, &sinit_max_init_timeo, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_initmsg->sinit_max_init_timeo != sinit_max_init_timeo) {
+			asprintf(error, "Bad getsockopt sctp_initmsg.sinit_max_init_timeo: expected: %hu actual: %hu",
+				 sinit_max_init_timeo, sctp_initmsg->sinit_max_init_timeo);
+			return STATUS_ERR;
+		}
+	}
+	return STATUS_OK;
+}
+#endif
+
 #ifdef SCTP_STATUS
 static int check_sctp_paddrinfo(struct sctp_paddrinfo_expr *expr,
 			        struct sctp_paddrinfo *sctp_paddrinfo,
@@ -2093,6 +2149,11 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 		live_optlen = (socklen_t)sizeof(struct sctp_rtoinfo);
 		((struct sctp_rtoinfo*)live_optval)->srto_assoc_id = 0;
 #endif
+#ifdef SCTP_INITMSG
+	} else if (val_expression->type == EXPR_SCTP_INITMSG) {
+		live_optval = malloc(sizeof(struct sctp_initmsg));
+		live_optlen = (socklen_t)sizeof(struct sctp_initmsg);
+#endif
 #ifdef SCTP_STATUS
 	} else if (val_expression->type == EXPR_SCTP_STATUS) {
 		live_optval = malloc(sizeof(struct sctp_status));
@@ -2173,6 +2234,13 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 			return STATUS_ERR;
 		}
 #endif
+#ifdef SCTP_INITMSG
+	} else if (val_expression->type == EXPR_SCTP_INITMSG) {
+		if (check_sctp_initmsg(val_expression->value.sctp_initmsg, live_optval, error)) {
+			free(live_optval);
+			return STATUS_ERR;
+		}
+#endif
 #ifdef SCTP_STATUS
 	} else if (val_expression->type == EXPR_SCTP_STATUS) {
 		if (check_sctp_status(val_expression->value.sctp_status, live_optval, error)) {
@@ -2221,6 +2289,9 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 	struct expression *val_expression;
 	struct linger linger;
 	struct sctp_rtoinfo rtoinfo;
+#if defined(SCTP_INITMSG)
+	struct sctp_initmsg initmsg;
+#endif
 #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
 	struct sctp_assoc_value assoc_value;
 #endif
@@ -2286,7 +2357,23 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 #endif
 #ifdef SCTP_INITMSG
 	case EXPR_SCTP_INITMSG:
-		optval = &val_expression->value.sctp_initmsg;
+		if (get_u16(val_expression->value.sctp_initmsg->sinit_num_ostreams,
+			    &initmsg.sinit_num_ostreams, error)) {
+		return STATUS_ERR;
+		}
+		if (get_u16(val_expression->value.sctp_initmsg->sinit_max_instreams,
+			    &initmsg.sinit_max_instreams, error)) {
+			return STATUS_ERR;
+		}
+		if (get_u16(val_expression->value.sctp_initmsg->sinit_max_attempts,
+			    &initmsg.sinit_max_attempts, error)) {
+			return STATUS_ERR;
+		}
+		if (get_u16(val_expression->value.sctp_initmsg->sinit_max_init_timeo,
+			    &initmsg.sinit_max_init_timeo, error)) {
+			return STATUS_ERR;
+		}
+		optval = &initmsg;
 		break;
 #endif
 #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c
index 419f45ca..6088b01f 100644
--- a/gtests/net/packetdrill/script.c
+++ b/gtests/net/packetdrill/script.c
@@ -314,6 +314,12 @@ void free_expression(struct expression *expression)
 #endif
 #ifdef SCTP_INITMSG
 	case EXPR_SCTP_INITMSG:
+		assert(expression->value.sctp_initmsg);
+		free_expression(expression->value.sctp_initmsg->sinit_num_ostreams);
+		free_expression(expression->value.sctp_initmsg->sinit_max_instreams);
+		free_expression(expression->value.sctp_initmsg->sinit_max_attempts);
+		free_expression(expression->value.sctp_initmsg->sinit_max_init_timeo);
+		break;
 #endif
 #ifdef SCTP_DELAYED_SACK
 	case EXPR_SCTP_SACKINFO:
@@ -581,6 +587,43 @@ static int evaluate_sctp_rtoinfo_expression(struct expression *in,
 }
 #endif
 
+#ifdef SCTP_INITMSG
+static int evaluate_sctp_initmsg_expression(struct expression *in,
+					    struct expression *out,
+					    char **error)
+{
+	struct sctp_initmsg_expr *in_initmsg;
+	struct sctp_initmsg_expr *out_initmsg;
+
+	assert(in->type == EXPR_SCTP_INITMSG);
+	assert(in->value.sctp_initmsg);
+	assert(out->type == EXPR_SCTP_INITMSG);
+
+	out->value.sctp_initmsg = calloc(1, sizeof(struct sctp_initmsg_expr));
+
+	in_initmsg = in->value.sctp_initmsg;
+	out_initmsg = out->value.sctp_initmsg;
+
+	if (evaluate(in_initmsg->sinit_num_ostreams,
+		     &out_initmsg->sinit_num_ostreams,
+		     error))
+		return STATUS_ERR;
+	if (evaluate(in_initmsg->sinit_max_instreams,
+		     &out_initmsg->sinit_max_instreams,
+		     error))
+		return STATUS_ERR;
+	if (evaluate(in_initmsg->sinit_max_attempts,
+		     &out_initmsg->sinit_max_attempts,
+		     error))
+		return STATUS_ERR;
+	if (evaluate(in_initmsg->sinit_max_init_timeo,
+		     &out_initmsg->sinit_max_init_timeo,
+		     error))
+		return STATUS_ERR;
+	return STATUS_OK;
+}
+#endif
+
 #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
 static int evaluate_sctp_assoc_value_expression(struct expression *in,
 						struct expression *out,
@@ -814,9 +857,8 @@ static int evaluate(struct expression *in,
 		break;
 #endif
 #ifdef SCTP_INITMSG
-	case EXPR_SCTP_INITMSG:		/* copy as-is */
-		memcpy(&out->value.sctp_initmsg, &in->value.sctp_initmsg,
-		       sizeof(in->value.sctp_initmsg));
+	case EXPR_SCTP_INITMSG:
+		evaluate_sctp_initmsg_expression(in, out, error);
 		break;
 #endif
 #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h
index cbdfad27..d0401bb9 100644
--- a/gtests/net/packetdrill/script.h
+++ b/gtests/net/packetdrill/script.h
@@ -89,7 +89,7 @@ struct expression {
 		struct sctp_rtoinfo_expr *sctp_rtoinfo;
 #endif
 #ifdef SCTP_INITMSG
-		struct sctp_initmsg sctp_initmsg;
+		struct sctp_initmsg_expr *sctp_initmsg;
 #endif
 #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
 		struct sctp_assoc_value_expr *sctp_assoc_value;
@@ -162,6 +162,17 @@ struct sctp_rtoinfo_expr {
 };
 #endif
 
+
+#ifdef SCTP_INITMSG
+/* Parse tree for a sctp_initmsg struct in a [gs]etsockopt syscall. */
+struct sctp_initmsg_expr {
+	struct expression *sinit_num_ostreams;
+	struct expression *sinit_max_instreams;
+	struct expression *sinit_max_attempts;
+	struct expression *sinit_max_init_timeo;
+};
+#endif
+
 #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
 /* Parse tree for a sctp_assoc_value struct in a [gs]etsockopt syscall. */
 struct sctp_assoc_value_expr {
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt
index 7983e824..a2ec201a 100644
--- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt
@@ -43,22 +43,22 @@ sstat_primary={ spinfo_state=SCTP_ACTIVE, spinfo_cwnd=4464, spinfo_srtt=..., spi
 
 
 +0 setsockopt(3, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, {spp_address={sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")},
-spp_hbinterval=300, spp_pathmtu=1468, spp_pathmaxrxt=..., spp_flags=SPP_DSCP|SPP_HB_ENABLE, spp_ipv6_flowlabel=0, spp_dscp=0}, 152) = 0
+spp_hbinterval=300, spp_pathmaxrxt=8, spp_pathmtu=1468, spp_flags=SPP_DSCP|SPP_HB_ENABLE, spp_ipv6_flowlabel=0, spp_dscp=0}, 152) = 0
 
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, {spp_address={sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")},
-spp_hbinterval=300, spp_pathmtu=1468, spp_pathmaxrxt=..., spp_flags=SPP_DSCP|SPP_HB_ENABLE|SPP_PMTUD_ENABLE, spp_ipv6_flowlabel=0, spp_dscp=0}, [152]) = 0
+spp_hbinterval=300, spp_pathmaxrxt=8, spp_pathmtu=1468, spp_flags=SPP_DSCP|SPP_HB_ENABLE|SPP_PMTUD_ENABLE, spp_ipv6_flowlabel=0, spp_dscp=0}, [152]) = 0
 
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, {spp_address={sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")},
-spp_hbinterval=..., spp_pathmtu=1468, spp_pathmaxrxt=..., spp_flags=..., spp_ipv6_flowlabel=0, spp_dscp=0}, [152]) = 0
+spp_hbinterval=..., spp_pathmaxrxt=..., spp_pathmtu=1468, spp_flags=..., spp_ipv6_flowlabel=0, spp_dscp=0}, [152]) = 0
 
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, {spp_address={sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")},
-spp_hbinterval=300, spp_pathmtu=..., spp_pathmaxrxt=..., spp_flags=521, spp_ipv6_flowlabel=0, spp_dscp=0}, [152]) = 0
+spp_hbinterval=300, spp_pathmaxrxt=..., spp_pathmtu=..., spp_flags=521, spp_ipv6_flowlabel=0, spp_dscp=0}, [152]) = 0
 
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, {spp_address={sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")},
-spp_hbinterval=300, spp_pathmtu=1468, spp_pathmaxrxt=..., spp_flags=521, spp_ipv6_flowlabel=..., spp_dscp=0}, [152]) = 0
+spp_hbinterval=300, spp_pathmaxrxt=..., spp_pathmtu=1468, spp_flags=521, spp_ipv6_flowlabel=..., spp_dscp=0}, [152]) = 0
 
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, {spp_address={sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")},
-spp_hbinterval=300, spp_pathmtu=1468, spp_pathmaxrxt=..., spp_flags=521, spp_ipv6_flowlabel=0, spp_dscp=...}, [152]) = 0
+spp_hbinterval=300, spp_pathmaxrxt=..., spp_pathmtu=1468, spp_flags=521, spp_ipv6_flowlabel=0, spp_dscp=...}, [152]) = 0
 
 +0 setsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=1, linger=30}, 8) = 0
 +0 getsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=128, linger=30}, [8]) = 0
@@ -72,4 +72,10 @@ spp_hbinterval=300, spp_pathmtu=1468, spp_pathmaxrxt=..., spp_flags=521, spp_ipv
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=..., srto_min=50}, [16]) = 0
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=200, srto_min=...}, [16]) = 0
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_MAXSEG, {assoc_value=1452}, [8]) = 0
+
++0 setsockopt(3, IPPROTO_SCTP, SCTP_INITMSG, {sinit_num_ostreams=2, sinit_max_instreams=2, sinit_max_attempts=2, sinit_max_init_timeo=30}, 8) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_INITMSG, {sinit_num_ostreams=2, sinit_max_instreams=2, sinit_max_attempts=2, sinit_max_init_timeo=30}, [8]) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_INITMSG, {sinit_num_ostreams=..., sinit_max_instreams=2, sinit_max_attempts=2, sinit_max_init_timeo=30}, [8]) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_INITMSG, {sinit_num_ostreams=2, sinit_max_instreams=..., sinit_max_attempts=2, sinit_max_init_timeo=30}, [8]) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_INITMSG, {sinit_num_ostreams=2, sinit_max_instreams=2, sinit_max_attempts=..., sinit_max_init_timeo=30}, [8]) = 0
 +0 close(3) = 0
-- 
GitLab