From 53af5949e3ad5b511e64d6992d51ef78e98c0229 Mon Sep 17 00:00:00 2001
From: hoelscher <jens.hoelscher@fh-muenster.de>
Date: Tue, 6 Oct 2015 17:33:00 +0200
Subject: [PATCH] Add support for SCTP_ADAPTATION_LAYER [gs]etsockopt

---
 gtests/net/packetdrill/lexer.l                |  1 +
 gtests/net/packetdrill/parser.y               | 22 ++++++++-
 gtests/net/packetdrill/run_system_call.c      | 45 +++++++++++++++++++
 gtests/net/packetdrill/script.c               | 40 +++++++++++++++++
 gtests/net/packetdrill/script.h               | 16 ++++++-
 gtests/net/packetdrill/symbols_freebsd.c      |  1 +
 gtests/net/packetdrill/symbols_linux.c        | 14 +++++-
 .../bsd/sctp/sctp_get_socket_options.pkt      |  3 ++
 8 files changed, 138 insertions(+), 4 deletions(-)

diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index 92a6d229..53e33af7 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -242,6 +242,7 @@ spp_ipv6_flowlabel		return SPP_IPV6_FLOWLABEL_; /* avoid name clash */
 spp_dscp			return SPP_DSCP_; /* avoid name clash */
 se_type				return SE_TYPE;
 se_on				return SE_ON;
+ssb_adaptation_ind		return SSB_ADAPTATION_IND;
 CHUNK				return CHUNK;
 DATA				return DATA;
 INIT				return INIT;
diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index 151546a1..36b09f92 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -536,7 +536,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %token <reserved> SPP_ADDRESS SPP_HBINTERVAL SPP_PATHMAXRXT SPP_PATHMTU
 %token <reserved> SPP_FLAGS SPP_IPV6_FLOWLABEL_ SPP_DSCP_
 %token <reserved> SASOC_ASOCMAXRXT SASOC_NUMBER_PEER_DESTINATIONS SASOC_PEER_RWND 
-%token <reserved> SASOC_LOCAL_RWND SASOC_COOKIE_LIFE SE_TYPE SE_ON
+%token <reserved> SASOC_LOCAL_RWND SASOC_COOKIE_LIFE SE_TYPE SE_ON SSB_ADAPTATION_IND
 %token <floating> FLOAT
 %token <integer> INTEGER HEX_INTEGER
 %token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR
@@ -585,7 +585,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <expression> spinfo_address spinfo_state spinfo_cwnd spinfo_srtt spinfo_rto spinfo_mtu
 %type <expression> sasoc_asocmaxrxt sasoc_number_peer_destinations sasoc_peer_rwnd 
 %type <expression> sasoc_local_rwnd sasoc_cookie_life sctp_assocparams 
-%type <expression> sctp_event se_type se_on
+%type <expression> sctp_event se_type se_on sctp_setadaptation
 %type <errno_info> opt_errno
 %type <chunk_list> sctp_chunk_list_spec
 %type <chunk_list_item> sctp_chunk_spec
@@ -2374,6 +2374,9 @@ expression
 | sctp_event        {
 	$$ = $1;
 }
+| sctp_setadaptation{
+	$$ = $1;
+}
 ;
 
 decimal_integer
@@ -3005,6 +3008,21 @@ sctp_event
 }
 ;
 
+sctp_setadaptation
+: '{' SSB_ADAPTATION_IND '=' INTEGER '}' {
+#ifdef SCTP_ADAPTATION_LAYER
+	$$ = new_expression(EXPR_SCTP_SETADAPTATION);
+	$$->value.sctp_setadaptation = calloc(1, sizeof(struct sctp_setadaptation));
+	if (!is_valid_u32($4)) {
+		semantic_error("ssb_adaptation_ind out of range");
+	}
+	$$->value.sctp_setadaptation->ssb_adaptation_ind = new_integer_expression($4, "%u");
+#elif
+	$$ = NULL;
+#endif
+}
+;
+
 opt_errno
 :                   { $$ = NULL; }
 | WORD note         {
diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index c550a868..27954fe7 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -2257,6 +2257,27 @@ static int check_sctp_event(struct sctp_event_expr *expr,
 }
 #endif
 
+#ifdef SCTP_ADAPTATION_LAYER
+static int check_sctp_setadaptation(struct sctp_setadaptation_expr *expr,
+				    struct sctp_setadaptation *sctp_setadaptation,
+				    char **error)
+{
+	if (expr->ssb_adaptation_ind->type != EXPR_ELLIPSIS) {
+		u32 ssb_adaptation_ind;
+
+		if (get_u32(expr->ssb_adaptation_ind, &ssb_adaptation_ind, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_setadaptation->ssb_adaptation_ind != ssb_adaptation_ind) {
+			asprintf(error, "Bad getsockopt sctp_setadaptation.ssb_adaptation_ind: expected: %u actual: %u",
+				 ssb_adaptation_ind, sctp_setadaptation->ssb_adaptation_ind);
+			return STATUS_ERR;
+		}
+	}
+	return STATUS_OK;
+}
+#endif
+
 static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 			      struct expression_list *args, char **error)
 {
@@ -2394,6 +2415,11 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
                         free(live_optval);
                         return STATUS_ERR;
                 }
+#endif
+#ifdef SCTP_ADAPTATION_LAYER
+	} else if (val_expression->type == EXPR_SCTP_SETADAPTATION) {
+		live_optval = malloc(sizeof(struct sctp_setadaptation));
+		live_optlen = sizeof(struct sctp_setadaptation);
 #endif
 	} else {
 		s32_bracketed_arg(args, 3, &script_optval, error);
@@ -2489,6 +2515,13 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 			free(live_optval);
 			return STATUS_ERR;
 		}
+#endif
+#ifdef SCTP_ADAPTATION_LAYER
+	} else if (val_expression->type == EXPR_SCTP_SETADAPTATION) {
+		if (check_sctp_setadaptation(val_expression->value.sctp_setadaptation, live_optval, error)) {
+			free(live_optval);
+			return STATUS_ERR;
+		}
 #endif
 	} else {
 		if (*(int*)live_optval != script_optval) {
@@ -2536,6 +2569,9 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 #ifdef SCTP_EVENT
 	struct sctp_event event;
 #endif
+#ifdef SCTP_ADAPTATION_LAYER
+	struct sctp_setadaptation setadaptation;
+#endif
 #ifdef SCTP_PEER_ADDR_PARAMS
 	struct sctp_paddrparams paddrparams;
 #ifdef linux
@@ -2725,6 +2761,15 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 		optval = &event;
 		break;
 #endif
+#ifdef SCTP_ADAPTATION_LAYER
+	case EXPR_SCTP_SETADAPTATION:
+		if (get_u32(val_expression->value.sctp_setadaptation->ssb_adaptation_ind,
+			   &setadaptation.ssb_adaptation_ind, error)) {
+			return STATUS_ERR;
+		}
+		optval = &setadaptation;
+		break;
+#endif
 #ifdef SCTP_PEER_ADDR_PARAMS
 	case EXPR_SCTP_PEER_ADDR_PARAMS:
 		paddrparams.spp_assoc_id = 0;
diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c
index 729475db..43df660d 100644
--- a/gtests/net/packetdrill/script.c
+++ b/gtests/net/packetdrill/script.c
@@ -93,6 +93,10 @@ struct expression_type_entry expression_type_table[] = {
 #ifdef SCTP_EVENT
 	{ EXPR_SCTP_EVENT,	     "sctp_event"      },
 #endif
+#ifdef SCTP_ADAPTATION_LAYER
+	{ EXPR_SCTP_SETADAPTATION,   "sctp_setadaptation"},
+#endif
+
 	{ NUM_EXPR_TYPES,            NULL}
 };
 
@@ -389,6 +393,11 @@ void free_expression(struct expression *expression)
 		free_expression(expression->value.sctp_event->se_type);
 		free_expression(expression->value.sctp_event->se_on);
 		break;
+#endif
+#ifdef SCTP_ADAPTATION_LAYER
+	case EXPR_SCTP_SETADAPTATION:
+		free_expression(expression->value.sctp_setadaptation->ssb_adaptation_ind);
+		break;
 #endif
 	case EXPR_WORD:
 		assert(expression->value.string);
@@ -950,6 +959,32 @@ static int evaluate_sctp_accocparams_expression(struct expression *in,
 }
 #endif
 
+#ifdef SCTP_ADAPTATION_LAYER
+static int evaluate_sctp_setadaptation_expression(struct expression *in,
+						  struct expression *out,
+						  char **error)
+{
+        struct sctp_setadaptation_expr *in_adaptation;
+        struct sctp_setadaptation_expr *out_adaptation;
+
+        assert(in->type == EXPR_SCTP_SETADAPTATION);
+        assert(in->value.sctp_setadaptation);
+        assert(out->type == EXPR_SCTP_SETADAPTATION);
+
+        out->value.sctp_setadaptation = calloc(1, sizeof(struct sctp_setadaptation_expr));
+                     
+        in_adaptation = in->value.sctp_setadaptation;
+        out_adaptation = out->value.sctp_setadaptation;
+                     
+        if (evaluate(in_adaptation->ssb_adaptation_ind,
+		     &out_adaptation->ssb_adaptation_ind,
+		     error))
+		return STATUS_ERR;
+
+	return STATUS_OK;
+}
+#endif
+
 static int evaluate(struct expression *in,
 		    struct expression **out_ptr, char **error)
 {
@@ -1020,6 +1055,11 @@ static int evaluate(struct expression *in,
 	case EXPR_SCTP_EVENT:
 		result = evaluate_sctp_event_expression(in, out, error);
 		break;
+#endif
+#ifdef SCTP_ADAPTATION_LAYER
+	case EXPR_SCTP_SETADAPTATION:
+		result = evaluate_sctp_setadaptation_expression(in, out, error);
+		break;
 #endif
 	case EXPR_WORD:
 		out->type = EXPR_INTEGER;
diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h
index 64715541..3711795e 100644
--- a/gtests/net/packetdrill/script.h
+++ b/gtests/net/packetdrill/script.h
@@ -73,6 +73,9 @@ enum expression_t {
 #endif
 #ifdef SCTP_EVENT
 	EXPR_SCTP_EVENT,	  /* struct sctp_event to for SCTP_EVENT */
+#endif
+#ifdef SCTP_ADAPTATION_LAYER
+	EXPR_SCTP_SETADAPTATION, /* struct sctp_setadaptation for SCTP_ADATTATION_LAYER */
 #endif
 	NUM_EXPR_TYPES,
 };
@@ -121,6 +124,10 @@ struct expression {
 #ifdef SCTP_EVENT
 		struct sctp_event_expr *sctp_event;
 #endif
+#ifdef SCTP_ADAPTATION_LAYER
+		struct sctp_setadaptation_expr *sctp_setadaptation;
+#endif
+
 	} value;
 	const char *format;	/* the printf format for printing the value */
 };
@@ -255,13 +262,20 @@ struct sctp_assocparams_expr {
 #endif
 
 #ifdef SCTP_EVENT
-/* Parse tree for sctp_enevt struct in [gs]etsockopt syscall. */
+/* Parse tree for sctp_event struct in [gs]etsockopt syscall. */
 struct sctp_event_expr {
 	struct expression *se_type;
 	struct expression *se_on;
 };
 #endif
 
+#ifdef SCTP_ADAPTATION_LAYER
+/* Parse tree for sctp_setadaptation struct in [gs]etsockopt syscall. */
+struct sctp_setadaptation_expr {
+	struct expression *ssb_adaptation_ind;
+};
+#endif
+
 /* 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 6576badb..779c8aab 100644
--- a/gtests/net/packetdrill/symbols_freebsd.c
+++ b/gtests/net/packetdrill/symbols_freebsd.c
@@ -83,6 +83,7 @@ struct int_symbol platform_symbols_table[] = {
 	{ SCTP_ASSOCINFO,                   "SCTP_ASSOCINFO"                  },
 	{ SCTP_INITMSG,                     "SCTP_INITMSG"                    },
 	{ SCTP_NODELAY,                     "SCTP_NODELAY"                    },
+	{ SCTP_ADAPTATION_LAYER,	    "SCTP_ADAPTATION_LAYER"           },
 	{ SCTP_MAXSEG,                      "SCTP_MAXSEG"                     },
 	{ SCTP_DELAYED_SACK,                "SCTP_DELAYED_SACK"               },
 	{ SCTP_MAX_BURST,                   "SCTP_MAX_BURST"                  },
diff --git a/gtests/net/packetdrill/symbols_linux.c b/gtests/net/packetdrill/symbols_linux.c
index 2fe28908..2eccf3d2 100644
--- a/gtests/net/packetdrill/symbols_linux.c
+++ b/gtests/net/packetdrill/symbols_linux.c
@@ -140,25 +140,37 @@ struct int_symbol platform_symbols_table[] = {
 	{ SPP_SACKDELAY_DISABLE,            "SPP_SACKDELAY_DISABLE"           },
 #ifdef SCTP_ASSOC_CHANGE
 	{ SCTP_ASSOC_CHANGE,                "SCTP_ASSOC_CHANGE"               },
+#endif
 #ifdef SCTP_PEER_ADDR_CHANGE
 	{ SCTP_PEER_ADDR_CHANGE,            "SCTP_PEER_ADDR_CHANGE"           },
+#endif
 #ifdef SCTP_REMOTE_ERROR
 	{ SCTP_REMOTE_ERROR,                "SCTP_REMOTE_ERROR"               },
+#endif
 #ifdef SCTP_SEND_FAILED
 	{ SCTP_SEND_FAILED,                 "SCTP_SEND_FAILED"                },
+#endif
 #ifdef SCTP_SHUTDOWN_EVENT
 	{ SCTP_SHUTDOWN_EVENT,              "SCTP_SHUTDOWN_EVENT"             },
+#endif
 #ifdef SCTP_ADAPTATION_INDICATION
 	{ SCTP_ADAPTATION_INDICATION,       "SCTP_ADAPTATION_INDICATION"      },
+#endif
 #ifdef SCTP_ADAPTION_INDICATION
         { SCTP_ADAPTION_INDICATION,         "SCTP_ADAPTION_INDICATION"        },
+#endif
 #ifdef SCTP_PARTIAL_DELIVERY_EVENT
 	{ SCTP_PARTIAL_DELIVERY_EVENT,      "SCTP_PARTIAL_DELIVERY_EVENT"     },
+#endif
 #ifdef SCTP_AUTHENTICATION_EVENT
 	{ SCTP_AUTHENTICATION_EVENT,        "SCTP_AUTHENTICATION_EVENT"       },
+#endif
 #ifdef SCTP_SENDER_DRY_EVENT
         { SCTP_SENDER_DRY_EVENT,            "SCTP_SENDER_DRY_EVENT"           },
-
+#endif
+#ifdef SCTP_ADAPTATION_LAYER
+	{ SCTP_ADAPTATION_LAYER,            "SCTP_ADAPTATION_LAYER"           },
+#endif
 #if 0
 	{ SPP_IPV6_FLOWLABEL,               "SPP_IPV6_FLOWLABEL"              },
 	{ SPP_DSCP,                         "SPP_DSCP"                        },
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 cf8dda78..7671c7d2 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
@@ -110,4 +110,7 @@ spp_hbinterval=300, spp_pathmaxrxt=..., spp_pathmtu=1468, spp_flags=521, spp_ipv
 +0 setsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=1}, 8) = 0
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=1}, [8]) = 0
 
++0 setsockopt(3, IPPROTO_SCTP, SCTP_ADAPTATION_LAYER, {ssb_adaptation_ind=2}, 4) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_ADAPTATION_LAYER, {ssb_adaptation_ind=2}, [4]) = 0
+
 +0 close(3) = 0
-- 
GitLab