From ad02436939aa851e5f1ff7b4789def14cc3da726 Mon Sep 17 00:00:00 2001
From: hoelscher <jens.hoelscher@fh-muenster.de>
Date: Fri, 27 Nov 2015 18:43:13 +0100
Subject: [PATCH] add support for sctp_hmac_ident sockopt

---
 gtests/net/packetdrill/lexer.l                |   2 +
 gtests/net/packetdrill/parser.y               |  29 ++++-
 gtests/net/packetdrill/run_system_call.c      | 100 ++++++++++++++++++
 gtests/net/packetdrill/script.c               |  37 +++++++
 gtests/net/packetdrill/script.h               |   8 ++
 gtests/net/packetdrill/symbols_freebsd.c      |   3 +
 .../api_tests/getsockopt/sctp_hmac_ident.pkt  |   2 +-
 7 files changed, 177 insertions(+), 4 deletions(-)

diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index 63e848bf..668f5e43 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -212,6 +212,8 @@ iov_len				return IOV_LEN;
 [.][.][.]			return ELLIPSIS;
 assoc_id			return ASSOC_ID;
 assoc_value			return ASSOC_VALUE;
+shmac_number_of_idents		return SHMAC_NUMBER_OF_IDENTS;
+shmac_idents			return SHMAC_IDENTS;
 stream_id			return STREAM_ID;
 stream_value			return STREAM_VALUE;
 scact_assoc_id			return SCACT_ASSOC_ID;
diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index 932fbf70..b3be7ede 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -506,7 +506,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %token <reserved> SRTO_ASSOC_ID SRTO_INITIAL SRTO_MAX SRTO_MIN
 %token <reserved> SINIT_NUM_OSTREAMS SINIT_MAX_INSTREAMS SINIT_MAX_ATTEMPTS
 %token <reserved> SINIT_MAX_INIT_TIMEO
-%token <reserved> ASSOC_ID ASSOC_VALUE
+%token <reserved> ASSOC_ID ASSOC_VALUE SHMAC_NUMBER_OF_IDENTS SHMAC_IDENTS
 %token <reserved> STREAM_ID STREAM_VALUE
 %token <reserved> SCACT_ASSOC_ID SCACT_KEYNUMBER SACK_ASSOC_ID SACK_DELAY SACK_FREQ
 %token <reserved> SSTAT_ASSOC_ID SSTAT_STATE SSTAT_RWND SSTAT_UNACKDATA SSTAT_PENDDATA
@@ -606,7 +606,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
+%type <expression> sinit_max_init_timeo sctp_assoc_value sctp_stream_value sctp_hmacalgo
+%type <expression> shmac_number_of_idents
 %type <expression> sctp_authkeyid scact_keynumber 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
@@ -2483,7 +2484,10 @@ expression
 | sctp_assoc_value  {
 	$$ = $1;
 }
-| sctp_stream_value  {
+| sctp_hmacalgo     {
+	$$ = $1;
+}
+| sctp_stream_value {
 	$$ = $1;
 }
 | sctp_authkeyid    {
@@ -2914,6 +2918,25 @@ sctp_assoc_value
 	$$->value.sctp_assoc_value->assoc_value = $4;
 }
 ;
+
+shmac_number_of_idents
+: SHMAC_NUMBER_OF_IDENTS '=' INTEGER {
+	if (!is_valid_u32($3)) {
+		semantic_error("shmac_number_of_idents out of range");
+	}
+	$$ = new_integer_expression($3, "%u");
+}
+| SHMAC_NUMBER_OF_IDENTS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sctp_hmacalgo
+: '{' shmac_number_of_idents ',' SHMAC_IDENTS '=' array '}' {
+	$$ = new_expression(EXPR_SCTP_HMACALGO);
+	$$->value.sctp_hmacalgo = calloc(1, sizeof(struct sctp_assoc_value_expr));
+	$$->value.sctp_hmacalgo->shmac_number_of_idents = $2;
+	$$->value.sctp_hmacalgo->shmac_idents = $6;
+}
+
 scact_keynumber
 : SCACT_KEYNUMBER '=' INTEGER {
 	if (!is_valid_u16($3)) {
diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index cc4e9589..330258a2 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -755,6 +755,48 @@ static int check_u8array_expr(struct expression *expr_list, u8 *data, size_t dat
 }
 #endif
 
+#if defined(__FreeBSD__) || defined(linux)
+static int check_u16array_expr(struct expression *expr_list, u16 *data, int data_len, char *val_name, char **error) {
+	if ( expr_list->type != EXPR_ELLIPSIS) {
+		struct expression *expr = NULL;
+		unsigned int i;
+
+		switch(expr_list->type) {
+		case EXPR_LIST:
+			if (data_len != expression_list_length(expr_list->value.list)) {
+				asprintf(error, "%s length: expected: %u actual %zu",
+					 val_name, expression_list_length(expr_list->value.list), data_len);
+				return STATUS_ERR;
+			}
+			for (i = 0; i < data_len; i++) {
+				expr = get_arg(expr_list->value.list, i, error);
+				if (expr->type != EXPR_ELLIPSIS) {
+					u16 script_val;
+
+					if (get_u16(expr, &script_val, error)) {
+						return STATUS_ERR;
+					}
+					if (script_val != data[i]) {
+						asprintf(error, "%s[%d]: expected: %hu actual: %hu",
+							val_name, i, script_val, data[i]);
+						return STATUS_ERR;
+					}
+				}
+			}
+			break;
+		case EXPR_NULL:
+			if (data != NULL)
+				return STATUS_ERR;
+			break;
+		default: asprintf(error, "Bad expressiontype for %s", val_name);
+			return STATUS_ERR;
+			break;
+		}
+	}
+	return STATUS_OK;
+}
+#endif
+
 /* Free all the space used by the given iovec. */
 static void iovec_free(struct iovec *iov, size_t iov_len)
 {
@@ -2923,6 +2965,23 @@ static int check_sctp_setadaptation(struct sctp_setadaptation_expr *expr,
 }
 #endif
 
+static int check_sctp_hamcalgo(struct sctp_hmacalgo_expr *expr,
+			       struct sctp_hmacalgo *sctp_hmacalgo,
+			       char **error) {
+	if (check_u32_expr(expr->shmac_number_of_idents, sctp_hmacalgo->shmac_number_of_idents,
+			   "sctp_hmacalgo.shmac_number_of_idents", error))
+		return STATUS_ERR;
+	if (check_type(expr->shmac_idents, EXPR_LIST, error)) {
+		return STATUS_ERR;
+	}
+	if (check_u16array_expr(expr->shmac_idents, sctp_hmacalgo->shmac_idents,
+				sctp_hmacalgo->shmac_number_of_idents,
+				"sctp_hmacalgo.shmac_idents", error))
+		return STATUS_ERR;
+
+	return STATUS_OK;
+}
+
 static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 			      struct expression_list *args, char **error)
 {
@@ -3072,6 +3131,12 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 		}
 		break;
 #endif
+#ifdef SCTP_HMAC_IDENT
+	case EXPR_SCTP_HMACALGO:
+		live_optval = malloc(sizeof(struct sctp_hmacalgo));
+		live_optlen = sizeof(struct sctp_hmacalgo);
+		break;
+#endif
 #ifdef SCTP_SS_VALUE
 	case EXPR_SCTP_STREAM_VALUE:
 		live_optval = malloc(sizeof(struct sctp_stream_value));
@@ -3238,6 +3303,11 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 		result = check_sctp_assoc_value(val_expression->value.sctp_assoc_value, live_optval, error);
 		break;
 #endif
+#ifdef SCTP_HMAC_IDENT
+	case EXPR_SCTP_HMACALGO:
+		result = check_sctp_hamcalgo(val_expression->value.sctp_hmacalgo, live_optval, error);
+		break;
+#endif		
 #ifdef SCTP_SS_VALUE
 	case EXPR_SCTP_STREAM_VALUE:
 		result = check_sctp_stream_value(val_expression->value.sctp_stream_value, live_optval, error);
@@ -3459,6 +3529,33 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 		optval = &assoc_value;
 		break;
 #endif
+#ifdef SCTP_HMAC_IDENT
+	case EXPR_SCTP_HMACALGO: {
+		int len, i;
+		struct sctp_hmacalgo *hmacalgo;
+		struct expression_list *list;
+
+		if (check_type(val_expression->value.sctp_hmacalgo->shmac_idents, EXPR_LIST, error)) {
+			return STATUS_ERR;
+		}
+		list = val_expression->value.sctp_hmacalgo->shmac_idents->value.list;
+		len = expression_list_length(list);
+		hmacalgo = malloc(sizeof(u32) + (sizeof(u16) * len));
+
+		if (get_u32(val_expression->value.sctp_hmacalgo->shmac_number_of_idents,
+			    &hmacalgo->shmac_number_of_idents, error)) {
+			free(hmacalgo);
+			return STATUS_ERR;
+		}
+		for (i = 0; i < len; i++) {
+			struct expression *expr;
+			expr = get_arg(list, i, error);
+			get_u16(expr, &(hmacalgo->shmac_idents[i]), error);
+		}
+		optval = &hmacalgo;
+		break;
+		}
+#endif
 #ifdef SCTP_SS_VALUE
 	case EXPR_SCTP_STREAM_VALUE:
 		stream_value.assoc_id = 0;
@@ -3740,6 +3837,9 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 	result = setsockopt(live_fd, level, optname, optval, optlen);
 
 	return end_syscall(state, syscall, CHECK_EXACT, result, error);
+#ifdef SCTP_HMAC_IDENT
+	free(optval);
+#endif
 }
 
 static int syscall_poll(struct state *state, struct syscall_spec *syscall,
diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c
index 30a5d678..4da1ea3a 100644
--- a/gtests/net/packetdrill/script.c
+++ b/gtests/net/packetdrill/script.c
@@ -70,6 +70,7 @@ struct expression_type_entry expression_type_table[] = {
 	{ EXPR_SCTP_RTOINFO,         "sctp_rtoinfo"},
 	{ EXPR_SCTP_INITMSG,         "sctp_initmsg"},
 	{ EXPR_SCTP_ASSOC_VALUE,     "sctp_assoc_value"},
+	{ EXPR_SCTP_HMACALGO,        "sctp_hmacalgo"},
 	{ EXPR_SCTP_AUTHKEYID,       "sctp_authkeyid"},
 	{ EXPR_SCTP_SACKINFO,        "sctp_sackinfo"},
 	{ EXPR_SCTP_STATUS,          "sctp_status"},
@@ -321,6 +322,11 @@ void free_expression(struct expression *expression)
 		free_expression(expression->value.sctp_rtoinfo->srto_max);
 		free_expression(expression->value.sctp_rtoinfo->srto_min);
 		break;
+	case EXPR_SCTP_HMACALGO:
+		assert(expression->value.sctp_hmacalgo);
+		free_expression(expression->value.sctp_hmacalgo->shmac_number_of_idents);
+		free_expression(expression->value.sctp_hmacalgo->shmac_idents);
+		break;
 	case EXPR_SCTP_ASSOC_VALUE:
 		assert(expression->value.sctp_assoc_value);
 		free_expression(expression->value.sctp_assoc_value->assoc_id);
@@ -868,6 +874,34 @@ static int evaluate_sctp_initmsg_expression(struct expression *in,
 	return STATUS_OK;
 }
 
+static int evaluate_sctp_hmacalgo_expression(struct expression *in,
+					     struct expression *out,
+					     char **error)
+{
+	struct sctp_hmacalgo_expr *in_hmac;
+	struct sctp_hmacalgo_expr *out_hmac;
+
+	assert(in->type == EXPR_SCTP_HMACALGO);
+	assert(in->value.sctp_hmacalgo);
+	assert(out->type == EXPR_SCTP_HMACALGO);
+
+	out->value.sctp_hmacalgo = calloc(1, sizeof(struct sctp_hmacalgo_expr));
+
+	in_hmac = in->value.sctp_hmacalgo;
+	out_hmac = out->value.sctp_hmacalgo;
+
+	if (evaluate(in_hmac->shmac_number_of_idents,
+	             &out_hmac->shmac_number_of_idents,
+	             error))
+		return STATUS_ERR;
+	if (evaluate(in_hmac->shmac_idents,
+	             &out_hmac->shmac_idents,
+	             error))
+		return STATUS_ERR;
+
+	return STATUS_OK;
+}
+
 static int evaluate_sctp_assoc_value_expression(struct expression *in,
 						struct expression *out,
 						char **error)
@@ -2244,6 +2278,9 @@ static int evaluate(struct expression *in,
 	case EXPR_SCTP_ASSOCPARAMS:
 		result = evaluate_sctp_accocparams_expression(in, out, error);
 		break;
+	case EXPR_SCTP_HMACALGO:
+		result = evaluate_sctp_hmacalgo_expression(in, out, error);
+		break;
 	case EXPR_SCTP_INITMSG:
 		result = evaluate_sctp_initmsg_expression(in, out, error);
 		break;
diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h
index c38efbeb..e4358679 100644
--- a/gtests/net/packetdrill/script.h
+++ b/gtests/net/packetdrill/script.h
@@ -50,6 +50,7 @@ enum expression_t {
 	EXPR_SCTP_RTOINFO,	  /* struct sctp_rtoinfo for SCTP_RTOINFO */
 	EXPR_SCTP_INITMSG,	  /* struct sctp_initmsg for SCTP_INITMSG */
 	EXPR_SCTP_ASSOC_VALUE,	  /* struct sctp_assoc_value */
+	EXPR_SCTP_HMACALGO,       /* expression tree for sctp_hmacalgo struct for [gs]etsockopt */
 	EXPR_SCTP_AUTHKEYID,      /* expression tree for sctp_authkeyid struct for [gs]etsockopt */
 	EXPR_SCTP_SACKINFO,	  /* struct sctp_sack_info_expr for */
 	EXPR_SCTP_STATUS,	  /* struct sctp_status for SCTP_STATUS */
@@ -104,6 +105,7 @@ struct expression {
 		struct pollfd_expr *pollfd;
 		struct sctp_rtoinfo_expr *sctp_rtoinfo;
 		struct sctp_initmsg_expr *sctp_initmsg;
+		struct sctp_hmacalgo_expr *sctp_hmacalgo;
 		struct sctp_assoc_value_expr *sctp_assoc_value;
 		struct sctp_authkeyid_expr *sctp_authkeyid;
 		struct sctp_sack_info_expr *sctp_sack_info;
@@ -210,6 +212,12 @@ struct sctp_initmsg_expr {
 	struct expression *sinit_max_init_timeo;
 };
 
+/* Parse tree for a sctp_hmacalgo struct in a [gs]etsockopt syscall. */
+struct sctp_hmacalgo_expr {
+	struct expression *shmac_number_of_idents;
+	struct expression *shmac_idents;
+};
+
 /* Parse tree for a sctp_assoc_value struct in a [gs]etsockopt syscall. */
 struct sctp_assoc_value_expr {
 	struct expression *assoc_id;
diff --git a/gtests/net/packetdrill/symbols_freebsd.c b/gtests/net/packetdrill/symbols_freebsd.c
index a13803ce..7cbc44b8 100644
--- a/gtests/net/packetdrill/symbols_freebsd.c
+++ b/gtests/net/packetdrill/symbols_freebsd.c
@@ -91,6 +91,7 @@ struct int_symbol platform_symbols_table[] = {
 	{ SCTP_DEFAULT_SEND_PARAM,          "SCTP_DEFAULT_SEND_PARAM"         },
 	{ SCTP_I_WANT_MAPPED_V4_ADDR,       "SCTP_I_WANT_MAPPED_V4_ADDR"      },
 	{ SCTP_MAXSEG,                      "SCTP_MAXSEG"                     },
+	{ SCTP_HMAC_IDENT,                  "SCTP_HMAC_IDENT"                 },
 	{ SCTP_AUTH_ACTIVE_KEY,             "SCTP_AUTH_ACTIVE_KEY"            },
 	{ SCTP_DELAYED_SACK,                "SCTP_DELAYED_SACK"               },
 	{ SCTP_MAX_BURST,                   "SCTP_MAX_BURST"                  },
@@ -246,6 +247,8 @@ struct int_symbol platform_symbols_table[] = {
 	{ SCTP_DSTADDRV6,                   "SCTP_DSTADDRV6"                  },
 	{ SCTP_EXTRCV,                      "SCTP_EXTRCV"                     },
 	{ SCTP_USE_EXT_RCVINFO,             "SCTP_USE_EXT_RCVINFO"            },
+	{ SCTP_AUTH_HMAC_ID_SHA1,           "SCTP_AUTH_HMAC_ID_SHA1"          },
+	{ SCTP_AUTH_HMAC_ID_SHA256,         "SCTP_AUTH_HMAC_ID_SHA256"        },
 	/* /usr/include/netinet/tcp.h */
 	{ TCP_NODELAY,                      "TCP_NODELAY"                     },
 	{ TCP_MAXSEG,                       "TCP_MAXSEG"                      },
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/api_tests/getsockopt/sctp_hmac_ident.pkt b/gtests/net/packetdrill/tests/bsd/sctp/api_tests/getsockopt/sctp_hmac_ident.pkt
index 5b531a63..2388a9c2 100644
--- a/gtests/net/packetdrill/tests/bsd/sctp/api_tests/getsockopt/sctp_hmac_ident.pkt
+++ b/gtests/net/packetdrill/tests/bsd/sctp/api_tests/getsockopt/sctp_hmac_ident.pkt
@@ -10,7 +10,7 @@
 
 +0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 
-+0 setsockopt(3, IPPROTO_SCTP, SCTP_HMAC_IDENT, {shmac_number_of_idents=2, shmac_idents=[SCTP_AUTH_HMAC_ID_SHA1, SCTP_AUTH_HMAC_ID_SHA256]}, 8) = 0
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_HMAC_IDENT, {shmac_number_of_idents=2, shmac_idents=[SCTP_AUTH_HMAC_ID_SHA1, SCTP_AUTH_HMAC_ID_SHA256]}, [8]) = 0
++0 setsockopt(3, IPPROTO_SCTP, SCTP_HMAC_IDENT, {shmac_number_of_idents=2, shmac_idents=[SCTP_AUTH_HMAC_ID_SHA1, SCTP_AUTH_HMAC_ID_SHA256]}, 8) = 0
 
 +0 close(3) = 0
-- 
GitLab