From d4d6c1f6395c1f5345561a8e7d0bf0179c16c160 Mon Sep 17 00:00:00 2001
From: hoelscher <jens.hoelscher@fh-muenster.de>
Date: Fri, 27 Nov 2015 22:47:08 +0100
Subject: [PATCH] add support for sctp_get_assoc_id_lists for [gs]etsockopt,
 shoult end in an error but didn't do taht for one-to-one socket

---
 gtests/net/packetdrill/lexer.l                |  2 +
 gtests/net/packetdrill/parser.y               | 24 ++++++++-
 gtests/net/packetdrill/run_system_call.c      | 53 +++++++++++++++++++
 gtests/net/packetdrill/script.c               | 35 ++++++++++++
 gtests/net/packetdrill/script.h               |  8 +++
 gtests/net/packetdrill/symbols_freebsd.c      |  1 +
 .../getsockopt/sctp_get_assoc_id_list.pkt     |  2 +-
 7 files changed, 123 insertions(+), 2 deletions(-)

diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index 668f5e43..b8aaa23f 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -382,6 +382,8 @@ sai_assoc_id                    return SAI_ASSOC_ID;
 sn_type                         return SN_TYPE;
 sn_length                       return SN_LENGTH;
 sn_flags                        return SN_FLAGS;
+gaids_number_of_ids             return GAIDS_NUMBER_OF_IDS;
+gaids_assoc_id			return GAIDS_ASSOC_ID;
 CHUNK				return CHUNK;
 DATA				return DATA;
 INIT				return INIT;
diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index b3be7ede..1e15b1b8 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -564,6 +564,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %token <reserved> SPC_TYPE SPC_FLAGS SPC_LENGTH SPC_AADDR SPC_STATE SPC_ERROR SPC_ASSOC_ID
 %token <reserved> SSF_TYPE SSF_LENGTH SSF_FLAGS SSF_ERROR SSF_INFO SSF_ASSOC_ID SSF_DATA
 %token <reserved> SAI_TYPE SAI_FLAGS SAI_LENGTH SAI_ADAPTATION_IND SAI_ASSOC_ID
+%token <reserved> GAIDS_NUMBER_OF_IDS GAIDS_ASSOC_ID
 %token <reserved> SN_TYPE SN_FLAGS SN_LENGTH
 %token <floating> FLOAT
 %token <integer> INTEGER HEX_INTEGER
@@ -635,7 +636,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <expression> sctp_paddr_change spc_type spc_flags spc_length spc_aaddr spc_error spc_state
 %type <expression> sctp_send_failed ssf_type ssf_length ssf_flags ssf_error ssf_info ssf_data
 %type <expression> sctp_adaptation_event sai_type sai_flags sai_length sai_adaptation_ind
-%type <expression> sctp_tlv sn_type sn_flags sn_length
+%type <expression> sctp_tlv sn_type sn_flags sn_length sctp_assoc_ids gaids_number_of_ids
 %type <errno_info> opt_errno
 %type <chunk_list> sctp_chunk_list_spec
 %type <chunk_list_item> sctp_chunk_spec
@@ -2547,6 +2548,9 @@ expression
 | sctp_recvv_rn     {
 	$$ = $1;
 }
+| sctp_assoc_ids    {
+	$$ = $1;
+}
 | null              {
 	$$ = $1;
 }
@@ -4763,6 +4767,24 @@ sctp_tlv
 }
 ;
 
+gaids_number_of_ids
+: GAIDS_NUMBER_OF_IDS '=' INTEGER {
+	if (!is_valid_u32($3)) {
+		semantic_error("gaids_number_of_ids out of range");
+	}
+	$$ = new_integer_expression($3, "%u");
+}
+| GAIDS_NUMBER_OF_IDS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sctp_assoc_ids
+: '{' gaids_number_of_ids ',' GAIDS_ASSOC_ID '=' array '}' {
+	$$ = new_expression(EXPR_SCTP_ASSOC_IDS);
+	$$->value.sctp_assoc_ids = calloc(1, sizeof(struct sctp_assoc_ids_expr));
+	$$->value.sctp_assoc_ids->gaids_number_of_ids = $2;
+	$$->value.sctp_assoc_ids->gaids_assoc_id = $6;
+};
+
 opt_errno
 :                   { $$ = NULL; }
 | WORD note         {
diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index 330258a2..c1d65ded 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -2982,6 +2982,45 @@ static int check_sctp_hamcalgo(struct sctp_hmacalgo_expr *expr,
 	return STATUS_OK;
 }
 
+static int check_sctp_assoc_ids(struct sctp_assoc_ids_expr *expr,
+			        struct sctp_assoc_ids *sctp_assoc_ids,
+			        char **error) {
+	int list_len = 0, i = 0;
+	struct expression *assoc_id;  
+	struct expression_list *ids;
+
+	if (check_u32_expr(expr->gaids_number_of_ids, sctp_assoc_ids->gaids_number_of_ids,
+			   "sctp_assoc_ids.gaids_number_of_ids", error)) {
+		return STATUS_ERR;
+	}
+	ids = expr->gaids_assoc_id->value.list;
+	list_len = expression_list_length(ids);
+	if (list_len != sctp_assoc_ids->gaids_number_of_ids) {
+		asprintf(error, "live gaids_number_if_ids unequal to length if expected gaids_assoc_id. actual %u, expected %d", 
+			sctp_assoc_ids->gaids_number_of_ids, list_len);
+		return STATUS_ERR;
+	}
+	if (list_len == 1) {
+		assoc_id = get_arg(ids, 0, error);
+		if (assoc_id->type == EXPR_ELLIPSIS) {
+			return STATUS_OK;
+		}
+	}
+	for (i = 0; i < list_len; i++) {
+		assoc_id = get_arg(ids, i, error);
+		sctp_assoc_t script_id;
+		if (get_sctp_assoc_t(assoc_id, &script_id, error)) {
+			return STATUS_ERR;
+		}
+		if (script_id != sctp_assoc_ids->gaids_assoc_id[i]) {
+			asprintf(error, "sctp_assoc_ids.gaids_assoc_id[%d]. expected %u, actual %u",
+				 i, script_id, sctp_assoc_ids->gaids_assoc_id[i]);
+			return STATUS_ERR;
+		}
+	}
+	return STATUS_OK;
+}
+
 static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 			      struct expression_list *args, char **error)
 {
@@ -3226,6 +3265,14 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 		live_optval = malloc(sizeof(struct sctp_setadaptation));
 		live_optlen = sizeof(struct sctp_setadaptation);
 		break;
+#endif
+#ifdef SCTP_GET_ASSOC_ID_LIST
+	case EXPR_SCTP_ASSOC_IDS: {
+		s32 len = expression_list_length(val_expression->value.sctp_assoc_ids->gaids_assoc_id->value.list);
+		live_optval = malloc(sizeof(u32) + (sizeof(sctp_assoc_t) * len));
+		live_optlen = sizeof(u32) + (sizeof(sctp_assoc_t) * len);
+		break;
+	}
 #endif
 	case EXPR_LIST:
 		s32_bracketed_arg(args, 3, &script_optval, error);
@@ -3347,6 +3394,12 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 	case EXPR_SCTP_SETADAPTATION:
 		result = check_sctp_setadaptation(val_expression->value.sctp_setadaptation, live_optval, error);
 		break;
+#endif
+#ifdef SCTP_GET_ASSOC_ID_LIST
+	case EXPR_SCTP_ASSOC_IDS: {
+		result = check_sctp_assoc_ids(val_expression->value.sctp_assoc_ids, live_optval, error);
+		break;
+		}
 #endif
 	case EXPR_LIST:
 		if (*(int*)live_optval != script_optval) {
diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c
index 4da1ea3a..dc0cd46e 100644
--- a/gtests/net/packetdrill/script.c
+++ b/gtests/net/packetdrill/script.c
@@ -103,6 +103,7 @@ struct expression_type_entry expression_type_table[] = {
 	{ EXPR_SCTP_SEND_FAILED_EVENT,"sctp_send_failed_event"},
 	{ EXPR_SCTP_TLV,             "sctp_tlv"        },
 	{ EXPR_SCTP_EXTRCVINFO,      "sctp_extrcvinfo" },
+	{ EXPR_SCTP_ASSOC_IDS,       "sctp_assoc_ids"  },
 	{ NUM_EXPR_TYPES,            NULL}
 };
 
@@ -580,6 +581,10 @@ void free_expression(struct expression *expression)
 		free_expression(expression->value.sctp_extrcvinfo->serinfo_next_ppid);
 		free_expression(expression->value.sctp_extrcvinfo->sinfo_assoc_id);
 		break;
+	case EXPR_SCTP_ASSOC_IDS:
+		free_expression(expression->value.sctp_assoc_ids->gaids_number_of_ids);
+		free_expression(expression->value.sctp_assoc_ids->gaids_assoc_id);
+		break;
 	case EXPR_WORD:
 		assert(expression->value.string);
 		free(expression->value.string);
@@ -2247,6 +2252,33 @@ static int evaluate_sctp_extrcvinfo_expression(struct expression *in,
 	return STATUS_OK;
 }
 
+static int evaluate_sctp_assoc_ids_expression(struct expression *in,
+					      struct expression *out,
+					      char **error)
+{
+	struct sctp_assoc_ids_expr *in_ids;
+	struct sctp_assoc_ids_expr *out_ids;
+
+	assert(in->type == EXPR_SCTP_ASSOC_IDS);
+	assert(in->value.sctp_assoc_ids);
+	assert(out->type == EXPR_SCTP_ASSOC_IDS);
+
+	out->value.sctp_assoc_ids = calloc(1, sizeof(struct sctp_assoc_ids_expr));
+
+	in_ids = in->value.sctp_assoc_ids;
+	out_ids = out->value.sctp_assoc_ids;
+
+	if (evaluate(in_ids->gaids_number_of_ids,
+		     &out_ids->gaids_number_of_ids,
+		     error))
+		return STATUS_ERR;
+	if (evaluate(in_ids->gaids_assoc_id,
+		     &out_ids->gaids_assoc_id,
+		     error))
+		return STATUS_ERR;
+	return STATUS_OK;
+}
+
 static int evaluate(struct expression *in,
 		    struct expression **out_ptr, char **error)
 {
@@ -2380,6 +2412,9 @@ static int evaluate(struct expression *in,
 	case EXPR_SCTP_EXTRCVINFO:
 		result = evaluate_sctp_extrcvinfo_expression(in, out, error);
 		break;
+	case EXPR_SCTP_ASSOC_IDS:
+		result = evaluate_sctp_assoc_ids_expression(in, out, error);
+		break;
 	case EXPR_WORD:
 		out->type = EXPR_INTEGER;
 		if (symbol_to_int(in->value.string,
diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h
index e4358679..56388a4b 100644
--- a/gtests/net/packetdrill/script.h
+++ b/gtests/net/packetdrill/script.h
@@ -83,6 +83,7 @@ enum expression_t {
 	EXPR_SCTP_SEND_FAILED_EVENT, /* expression tree for sctp_send_failed_event */
 	EXPR_SCTP_TLV,            /* expression tree for sctp_notifications_stopped_event */
 	EXPR_SCTP_EXTRCVINFO,     /* expression tree for sctp_extrcvinfo struct in cmsghdr */
+	EXPR_SCTP_ASSOC_IDS,      /* expression tree for sctp_assoc_ids struct for [gs]etsockopt */
 	NUM_EXPR_TYPES,
 };
 /* Convert an expression type to a human-readable string */
@@ -139,6 +140,7 @@ struct expression {
 		struct sctp_send_failed_event_expr *sctp_send_failed_event;
 		struct sctp_tlv_expr *sctp_tlv;
 		struct sctp_extrcvinfo_expr *sctp_extrcvinfo;
+		struct sctp_assoc_ids_expr *sctp_assoc_ids;
 	} value;
 	const char *format;	/* the printf format for printing the value */
 };
@@ -523,6 +525,12 @@ struct sctp_extrcvinfo_expr {
 	struct expression *sinfo_assoc_id;
 };
 
+/* Parse tree for sctp_extrcvinfo struct for cmsg. */
+struct sctp_assoc_ids_expr {
+	struct expression *gaids_number_of_ids;
+	struct expression *gaids_assoc_id;
+};
+
 /* The errno-related info from strace to summarize a system call error */
 struct errno_spec {
 	const char *errno_macro;	/* errno symbol (C macro name) */
diff --git a/gtests/net/packetdrill/symbols_freebsd.c b/gtests/net/packetdrill/symbols_freebsd.c
index 83f436d6..15707ec6 100644
--- a/gtests/net/packetdrill/symbols_freebsd.c
+++ b/gtests/net/packetdrill/symbols_freebsd.c
@@ -108,6 +108,7 @@ struct int_symbol platform_symbols_table[] = {
 	{ SCTP_STATUS,                      "SCTP_STATUS"                     },
 	{ SCTP_GET_PEER_ADDR_INFO,          "SCTP_GET_PEER_ADDR_INFO"         },
 	{ SCTP_GET_ASSOC_NUMBER,            "SCTP_GET_ASSOC_NUMBER"           },
+	{ SCTP_GET_ASSOC_ID_LIST,           "SCTP_GET_ASSOC_ID_LIST"          },
 	{ SCTP_FRAGMENT_INTERLEAVE,         "SCTP_FRAGMENT_INTERLEAVE"        },
 #if defined(SCTP_INTERLEAVING_SUPPORTED)
 	{ SCTP_INTERLEAVING_SUPPORTED,      "SCTP_INTERLEAVING_SUPPORTED"     },
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/api_tests/getsockopt/sctp_get_assoc_id_list.pkt b/gtests/net/packetdrill/tests/bsd/sctp/api_tests/getsockopt/sctp_get_assoc_id_list.pkt
index 8d6b9cd8..e09f741f 100644
--- a/gtests/net/packetdrill/tests/bsd/sctp/api_tests/getsockopt/sctp_get_assoc_id_list.pkt
+++ b/gtests/net/packetdrill/tests/bsd/sctp/api_tests/getsockopt/sctp_get_assoc_id_list.pkt
@@ -10,6 +10,6 @@
 
 +0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 
-+0 getsockopt(3, IPPROTO_SCTP, SCTP_GET_ASSOC_ID_LIST, {gaids_number_of_ids=0, gaids_assoc_id=[...]}, [0]) = -1
++0 getsockopt(3, IPPROTO_SCTP, SCTP_GET_ASSOC_ID_LIST, {gaids_number_of_ids=1, gaids_assoc_id=[3]}, [8]) = -1
 
 +0 close(3) = 0
-- 
GitLab