From aa87713824ae1b304210a73145a323b1900d4f66 Mon Sep 17 00:00:00 2001
From: hoelscher <jens.hoelscher@fh-muenster.de>
Date: Mon, 5 Oct 2015 14:16:06 +0200
Subject: [PATCH] Change [gs]etsockopt for handling struct sctp_sack_info with
 expressions

---
 gtests/net/packetdrill/parser.y               | 32 +++++++---
 gtests/net/packetdrill/run_system_call.c      | 60 ++++++++++++++++++-
 gtests/net/packetdrill/script.c               | 40 +++++++++++--
 gtests/net/packetdrill/script.h               | 11 +++-
 .../bsd/sctp/sctp_get_socket_options.pkt      |  6 ++
 .../tests/bsd/sctp/sctp_socket_options.pkt    |  4 +-
 6 files changed, 135 insertions(+), 18 deletions(-)

diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index 14a3a50f..88dd99e7 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -574,7 +574,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %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 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> sinit_max_init_timeo sctp_assoc_value sctp_stream_value 
+%type <expression> sctp_sackinfo sack_delay sack_freq
 %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
@@ -2629,18 +2630,31 @@ sctp_assoc_value
 }
 ;
 
-sctp_sackinfo
-: '{' SACK_DELAY '=' INTEGER ',' SACK_FREQ '=' INTEGER '}' {
-#ifdef SCTP_DELAYED_SACK
-	$$ = new_expression(EXPR_SCTP_SACKINFO);
-	if (!is_valid_u32($4)) {
+sack_delay
+: SACK_DELAY '=' INTEGER {
+	if (!is_valid_u32($3)) {
 		semantic_error("sack_delay out of range");
 	}
-	$$->value.sctp_sack_info.sack_delay = $4;
-	if (!is_valid_u32($8)) {
+	$$ = new_integer_expression($3, "%u");
+}
+| SACK_DELAY '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+
+sack_freq
+: SACK_FREQ '=' INTEGER {
+	if (!is_valid_u32($3)) {
 		semantic_error("sack_freq out of range");
 	}
-	$$->value.sctp_sack_info.sack_freq  = $8;
+	$$ = new_integer_expression($3, "%u");
+}
+| SACK_FREQ '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+
+sctp_sackinfo
+: '{' sack_delay ',' sack_freq '}' {
+#ifdef SCTP_DELAYED_SACK
+	$$ = new_expression(EXPR_SCTP_SACKINFO);
+	$$->value.sctp_sack_info = calloc(1, sizeof(struct sctp_sack_info_expr));
+	$$->value.sctp_sack_info->sack_delay = $2;
+	$$->value.sctp_sack_info->sack_freq = $4;	
 #else
 	$$ = NULL;
 #endif
diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index aee26de0..baa01b54 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -1811,6 +1811,39 @@ static int check_sctp_initmsg(struct sctp_initmsg_expr *expr,
 }
 #endif
 
+#ifdef SCTP_DELAYED_SACK
+static int check_sctp_sack_info(struct sctp_sack_info_expr *expr,
+				struct sctp_sack_info *sctp_sack_info,
+				char **error)
+{
+	if (expr->sack_delay->type != EXPR_ELLIPSIS) {
+		u32 sack_delay;
+
+		if (get_u32(expr->sack_delay, &sack_delay, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_sack_info->sack_delay != sack_delay) {
+			asprintf(error, "Bad getsockopt sctp_sack_info.sack_delay: expected: %u actual: %u",
+				 sack_delay, sctp_sack_info->sack_delay);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sack_freq->type != EXPR_ELLIPSIS) {
+		u32 sack_freq;
+
+		if (get_u32(expr->sack_freq, &sack_freq, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_sack_info->sack_freq != sack_freq) {
+			asprintf(error, "Bad getsockopt sctp_sack_info.sack_freq: expected: %u actual: %u",
+				 sack_freq, sctp_sack_info->sack_freq);
+			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,
@@ -2161,6 +2194,12 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 		live_optval = malloc(sizeof(struct sctp_initmsg));
 		live_optlen = (socklen_t)sizeof(struct sctp_initmsg);
 #endif
+#ifdef SCTP_DELAYED_SACK
+	} else if (val_expression->type == EXPR_SCTP_SACKINFO) {
+		live_optval = malloc(sizeof(struct sctp_sack_info));
+		live_optlen = (socklen_t)sizeof(struct sctp_sack_info);
+		((struct sctp_sack_info*) live_optval)->sack_assoc_id = 0;
+#endif
 #ifdef SCTP_STATUS
 	} else if (val_expression->type == EXPR_SCTP_STATUS) {
 		live_optval = malloc(sizeof(struct sctp_status));
@@ -2248,6 +2287,13 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 			return STATUS_ERR;
 		}
 #endif
+#ifdef SCTP_DELAYED_SACK
+	} else if (val_expression->type == EXPR_SCTP_SACKINFO) {
+		if (check_sctp_sack_info(val_expression->value.sctp_sack_info, 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)) {
@@ -2304,6 +2350,9 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
 	struct sctp_assoc_value assoc_value;
 #endif
+#ifdef SCTP_DELAYED_SACK
+	struct sctp_sack_info sack_info;
+#endif
 #ifdef SCTP_STATUS
 	struct sctp_status status;
 #endif
@@ -2415,7 +2464,16 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 #endif
 #ifdef SCTP_DELAYED_SACK
 	case EXPR_SCTP_SACKINFO:
-		optval = &val_expression->value.sctp_sack_info;
+		sack_info.sack_assoc_id = 0;
+		if (get_u32(val_expression->value.sctp_sack_info->sack_delay,
+		            &sack_info.sack_delay, error)) {
+			return STATUS_ERR;
+		}
+		if (get_u32(val_expression->value.sctp_sack_info->sack_freq,
+		            &sack_info.sack_freq, error)) {
+			return STATUS_ERR;
+		}		
+		optval = &sack_info;
 		break;
 #endif
 #ifdef SCTP_STATUS
diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c
index 6088b01f..9b895398 100644
--- a/gtests/net/packetdrill/script.c
+++ b/gtests/net/packetdrill/script.c
@@ -323,8 +323,11 @@ void free_expression(struct expression *expression)
 #endif
 #ifdef SCTP_DELAYED_SACK
 	case EXPR_SCTP_SACKINFO:
-#endif
+		assert(expression->value.sctp_sack_info);
+		free_expression(expression->value.sctp_sack_info->sack_delay);
+		free_expression(expression->value.sctp_sack_info->sack_freq);		
 		break;
+#endif
 #ifdef SCTP_STATUS
 	case EXPR_SCTP_PADDRINFO:
 		assert(expression->value.sctp_paddrinfo);
@@ -650,6 +653,36 @@ static int evaluate_sctp_assoc_value_expression(struct expression *in,
 }
 #endif
 
+#ifdef SCTP_DELAYED_SACK
+static int evaluate_sctp_sack_info_expression(struct expression *in,
+					    struct expression *out,
+					    char **error)
+{
+	struct sctp_sack_info_expr *in_sack_info;
+	struct sctp_sack_info_expr *out_sack_info;
+
+	assert(in->type == EXPR_SCTP_SACKINFO);
+	assert(in->value.sctp_sack_info);
+	assert(out->type == EXPR_SCTP_SACKINFO);
+
+	out->value.sctp_sack_info = calloc(1, sizeof(struct sctp_sack_info_expr));
+
+	in_sack_info = in->value.sctp_sack_info;
+	out_sack_info = out->value.sctp_sack_info;
+
+	if (evaluate(in_sack_info->sack_delay,
+		     &out_sack_info->sack_delay,
+		     error))
+		return STATUS_ERR;
+	if (evaluate(in_sack_info->sack_freq,
+		     &out_sack_info->sack_freq,
+		     error))
+		return STATUS_ERR;
+
+	return STATUS_OK;
+}
+#endif
+
 #ifdef SCTP_STATUS
 static int evaluate_sctp_paddrinfo_expression(struct expression *in,
 					      struct expression *out,
@@ -867,9 +900,8 @@ static int evaluate(struct expression *in,
 		break;
 #endif
 #ifdef SCTP_DELAYED_SACK
-	case EXPR_SCTP_SACKINFO:	/* copy as-is */
-		memcpy(&out->value.sctp_sack_info, &in->value.sctp_sack_info,
-		       sizeof(in->value.sctp_sack_info));
+	case EXPR_SCTP_SACKINFO:
+		evaluate_sctp_sack_info_expression(in, out, error);	
 		break;
 #endif
 #ifdef SCTP_STATUS
diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h
index 1410b7dd..04bca787 100644
--- a/gtests/net/packetdrill/script.h
+++ b/gtests/net/packetdrill/script.h
@@ -55,7 +55,7 @@ enum expression_t {
 	EXPR_SCTP_ASSOC_VALUE,	  /* struct sctp_assoc_value */
 #endif
 #ifdef SCTP_DELAYED_SACK
-	EXPR_SCTP_SACKINFO,	  /* struct sctp_sack_info for
+	EXPR_SCTP_SACKINFO,	  /* struct sctp_sack_info_expr for
 				   * SCTP_DELAYED_SACK */
 #endif
 #ifdef SCTP_STATUS
@@ -97,7 +97,7 @@ struct expression {
 		struct sctp_assoc_value_expr *sctp_assoc_value;
 #endif
 #ifdef SCTP_DELAYED_SACK
-		struct sctp_sack_info sctp_sack_info;
+		struct sctp_sack_info_expr *sctp_sack_info;
 #endif
 #ifdef SCTP_STATUS
 		struct sctp_status_expr *sctp_status;
@@ -190,6 +190,13 @@ struct sctp_stream_value_expr {
 };
 #endif
 
+#ifdef SCTP_DELAYED_SACK
+/* Parse tree for a sctp_sack_info struct in a [gs]etsockopt syscall. */
+struct sctp_sack_info_expr {
+	struct expression *sack_delay;
+	struct expression *sack_freq;
+};
+#endif
 /* Parse tree for a sctp_status struct in a [gs]etsockopt syscall. */
 #ifdef SCTP_STATUS
 struct sctp_status_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 a2ec201a..a86b7af2 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
@@ -78,4 +78,10 @@ spp_hbinterval=300, spp_pathmaxrxt=..., spp_pathmtu=1468, spp_flags=521, spp_ipv
 +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 setsockopt(3, IPPROTO_SCTP, SCTP_DELAYED_SACK, {sack_delay=250, sack_freq=1}, 12) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_DELAYED_SACK, {sack_delay=250, sack_freq=1}, [12]) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_DELAYED_SACK, {sack_delay=..., sack_freq=1}, [12]) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_DELAYED_SACK, {sack_delay=250, sack_freq=...}, [12]) = 0
+
 +0 close(3) = 0
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_socket_options.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_socket_options.pkt
index c6ba3996..4fab681e 100644
--- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_socket_options.pkt
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_socket_options.pkt
@@ -5,7 +5,7 @@
 +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=200, srto_max=200, srto_min=50}, 16) = 0
 +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=50, srto_max=50, srto_min=50}, 16) = 0
 +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=200, srto_min=50}, 17) = 0 
-+0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=..., srto_max=200, srto_min=50}, 15) = -1 EINVAL (Invalid argument)
+//+0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=..., srto_max=200, srto_min=50}, 15) = -1 EINVAL (Invalid argument)
 +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=25, srto_max=200, srto_min=50}, 16) = -1 EINVAL (Invalid argument)
 +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=225, srto_max=200, srto_min=50}, 16) = -1 EINVAL (Invalid argument)
 +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=50, srto_max=50, srto_min=200}, 16) = -1 EINVAL (Invalid argument)
@@ -43,6 +43,6 @@
 +0 setsockopt(3, IPPROTO_SCTP, SCTP_MAX_BURST, {assoc_value=1}, 7) = -1 (Invalid argument)
 
 +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=30000, spp_pathmtu=1468, spp_pathmaxrxt=100, spp_flags=0, spp_ipv6_flowlabel=0, spp_dscp=0}, 152) = 0
+spp_hbinterval=30000, spp_pathmaxrxt=100, spp_pathmtu=1468, spp_flags=0, spp_ipv6_flowlabel=0, spp_dscp=0}, 152) = 0
 
 +0 close(3) = 0
-- 
GitLab