From 5357c39a8366108a2f8a20d8ff4183344b36bf57 Mon Sep 17 00:00:00 2001
From: hoelscher <jens.hoelscher@fh-muenster.de>
Date: Tue, 20 Oct 2015 07:51:15 +0200
Subject: [PATCH] add support for notification sctp_sender_dry_event

---
 gtests/net/packetdrill/lexer.l                |  4 ++
 gtests/net/packetdrill/parser.y               | 58 +++++++++++++++++
 gtests/net/packetdrill/run_system_call.c      | 65 ++++++++++++++++++-
 gtests/net/packetdrill/script.c               | 46 +++++++++++++
 gtests/net/packetdrill/script.h               | 10 +++
 gtests/net/packetdrill/symbols_freebsd.c      |  1 +
 .../tests/bsd/sctp/sctp_notifications.pkt     | 20 ++++++
 7 files changed, 203 insertions(+), 1 deletion(-)

diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index fdb44cee..cc958793 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -291,6 +291,10 @@ recvv_nxtinfo                   return RECVV_NXTINFO;
 sse_type                        return SSE_TYPE;
 sse_flags                       return SSE_FLAGS;
 sse_length                      return SSE_LENGTH;
+sender_dry_type                 return SENDER_DRY_TYPE;
+sender_dry_flags                return SENDER_DRY_FLAGS;
+sender_dry_length               return SENDER_DRY_LENGTH;
+sender_dry_assoc_id             return SENDER_DRY_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 344826a8..2f413edc 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -548,6 +548,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %token <reserved> NXT_SID NXT_FLAGS NXT_PPID NXT_LENGTH
 %token <reserved> RECVV_RCVINFO RECVV_NXTINFO
 %token <reserved> SSE_TYPE SSE_FLAGS SSE_LENGTH
+%token <reserved> SENDER_DRY_TYPE SENDER_DRY_FLAGS SENDER_DRY_LENGTH SENDER_DRY_ASSOC_ID
 %token <rexerved> _SCTP_DATA_IO_EVENT_ _SCTP_ASSOCIATION_EVENT_ _SCTP_ADDRESS_EVENT_
 %token <reserved> _SCTP_SEND_FAILURE_EVENT_ _SCTP_PEER_ERROR_EVENT_ _SCTP_SHUTDOWN_EVENT_
 %token <reserved> _SCTP_PARTIAL_DELIVERY_EVENT_ _SCTP_ADAPTATION_LAYER_EVENT_
@@ -608,6 +609,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <expression> sctp_rcvinfo rcv_sid rcv_ssn rcv_flags rcv_ppid rcv_tsn rcv_cumtsn rcv_context
 %type <expression> sctp_nxtinfo nxt_sid nxt_flags nxt_ppid nxt_length sctp_recvv_rn
 %type <expression> sctp_shutdown_event sse_type sse_flags sse_length
+%type <expression> sctp_sender_dry_event sender_dry_type sender_dry_flags sender_dry_length sender_dry_assoc_id
 %type <expression> sctp_event_subscribe
 %type <errno_info> opt_errno
 %type <chunk_list> sctp_chunk_list_spec
@@ -2584,6 +2586,7 @@ sockaddr
 data
 : ELLIPSIS { new_expression(EXPR_ELLIPSIS); }
 | sctp_shutdown_event { $$ = $1; }
+| sctp_sender_dry_event { $$ = $1; }
 ;
 
 msghdr
@@ -3569,6 +3572,61 @@ sctp_shutdown_event
 	$$->value.sctp_shutdown_event->sse_length = $6;
 };
 
+sender_dry_type
+: SENDER_DRY_TYPE '=' INTEGER {
+	if (!is_valid_u16($3)) {
+		semantic_error("sender_dry_type out of range");
+	}
+	$$ = new_integer_expression($3, "%hu");
+}
+| SENDER_DRY_TYPE '=' WORD {
+	$$ = new_expression(EXPR_WORD);
+	$$->value.string = $3;
+}
+| SENDER_DRY_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sender_dry_flags
+: SENDER_DRY_FLAGS '=' INTEGER {
+	if (!is_valid_u16($3)) {
+		semantic_error("sender_dry_flags out of range");
+	}
+	$$ = new_integer_expression($3, "%hu");
+}
+| SENDER_DRY_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sender_dry_length
+: SENDER_DRY_LENGTH '=' INTEGER {
+	if (!is_valid_u32($3)) {
+		semantic_error("sender_dry_length out of range");
+	}
+	$$ = new_integer_expression($3, "%u");
+}
+| SENDER_DRY_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sender_dry_assoc_id
+: SENDER_DRY_ASSOC_ID '=' INTEGER {
+	if (!is_valid_u32($3)) {
+		semantic_error("sender_dry_assoc_id out of range");
+	}
+	$$ = new_integer_expression($3, "%u");
+}
+| SENDER_DRY_ASSOC_ID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sctp_sender_dry_event
+: '{'sender_dry_type ',' sender_dry_flags ',' sender_dry_length ',' sender_dry_assoc_id '}' {
+	$$ = new_expression(EXPR_SCTP_SENDER_DRY_EVENT);
+	$$->value.sctp_sender_dry_event = calloc(1, sizeof(struct sctp_sender_dry_event_expr));
+	$$->value.sctp_sender_dry_event->sender_dry_type = $2;
+	$$->value.sctp_sender_dry_event->sender_dry_flags = $4;
+	$$->value.sctp_sender_dry_event->sender_dry_length = $6;
+	$$->value.sctp_sender_dry_event->sender_dry_assoc_id = $8;
+}
+;
+
 opt_errno
 :                   { $$ = NULL; }
 | WORD note         {
diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index db8e46ca..cb55f62b 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -460,7 +460,8 @@ static int iovec_new(struct expression *expression,
 		iov_expr = list->expression->value.iovec;
 
 		assert(iov_expr->iov_base->type == EXPR_ELLIPSIS ||
-		       iov_expr->iov_base->type == EXPR_SCTP_SHUTDOWN_EVENT);
+		       iov_expr->iov_base->type == EXPR_SCTP_SHUTDOWN_EVENT ||
+		       iov_expr->iov_base->type == EXPR_SCTP_SENDER_DRY_EVENT);
 		assert(iov_expr->iov_len->type == EXPR_INTEGER);
 
 		len = iov_expr->iov_len->value.num;
@@ -3918,6 +3919,62 @@ static int check_sctp_shutdown_event(struct sctp_shutdown_event_expr *expr,
 	return STATUS_OK;
 }
 #endif
+#ifdef __FreeBSD__
+static int check_sctp_sender_dry_event(struct sctp_sender_dry_event_expr *expr,
+				       struct sctp_sender_dry_event *sctp_event,
+				       char **error) {
+	if (expr->sender_dry_type->type != EXPR_ELLIPSIS) {
+		u16 sender_dry_type;
+		 
+		if (get_u16(expr->sender_dry_type, &sender_dry_type, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_event->sender_dry_type != sender_dry_type) {
+			asprintf(error, "sctp_sender_dry_event.sender_dry_type: expected: %hu actual: %hu",
+				 sender_dry_type, sctp_event->sender_dry_type);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sender_dry_flags->type != EXPR_ELLIPSIS) {
+		u16 sender_dry_flags;
+		 
+		if (get_u16(expr->sender_dry_flags, &sender_dry_flags, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_event->sender_dry_flags != sender_dry_flags) {
+			asprintf(error, "sctp_sender_dry_event.sender_dry_flags: expected: %hu actual: %hu",
+				 sender_dry_flags, sctp_event->sender_dry_flags);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sender_dry_type->type != EXPR_ELLIPSIS) {
+		u32 sender_dry_length;
+		 
+		if (get_u32(expr->sender_dry_length, &sender_dry_length, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_event->sender_dry_length != sender_dry_length) {
+			asprintf(error, "sctp_sender_dry_event.sender_dry_length: expected: %u actual: %u",
+				 sender_dry_length, sctp_event->sender_dry_length);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sender_dry_assoc_id->type != EXPR_ELLIPSIS) {
+		u32 sender_dry_assoc_id;
+		 
+		if (get_u32(expr->sender_dry_assoc_id, &sender_dry_assoc_id, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_event->sender_dry_assoc_id != sender_dry_assoc_id) {
+			asprintf(error, "sctp_sender_dry_event.sender_dry_assoc_id: expected: %u actual: %u",
+				 sender_dry_assoc_id, sctp_event->sender_dry_assoc_id);
+			return STATUS_ERR;
+		}
+	}
+
+	return STATUS_OK;
+}
+#endif
 
 #if defined(__FreeBSD__)
 static int check_sctp_notification(struct iovec *iov,
@@ -3943,6 +4000,12 @@ static int check_sctp_notification(struct iovec *iov,
 						      error))
 				return STATUS_ERR;
 			break;
+		case EXPR_SCTP_SENDER_DRY_EVENT:
+			if (check_sctp_sender_dry_event(script_iov_base->value.sctp_sender_dry_event,
+						       (struct sctp_sender_dry_event *) iov->iov_base,
+						       error))
+				return STATUS_ERR;
+			break;
 		case EXPR_ELLIPSIS:
 			break;
 		default:
diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c
index 9f162ddf..d81e4e5b 100644
--- a/gtests/net/packetdrill/script.c
+++ b/gtests/net/packetdrill/script.c
@@ -87,6 +87,7 @@ struct expression_type_entry expression_type_table[] = {
 	{ EXPR_SCTP_NXTINFO,         "sctp_nxtinfo"    },
 	{ EXPR_SCTP_RECVV_RN,        "sctp_recvv_rn "  },
 	{ EXPR_SCTP_SHUTDOWN_EVENT,  "sctp_shutdown_event"},
+	{ EXPR_SCTP_SENDER_DRY_EVENT,"sctp_sender_dry_event"},
 	{ NUM_EXPR_TYPES,            NULL}
 };
 
@@ -435,6 +436,12 @@ void free_expression(struct expression *expression)
 		free_expression(expression->value.sctp_shutdown_event->sse_flags);
 		free_expression(expression->value.sctp_shutdown_event->sse_length);
 		break;
+	case EXPR_SCTP_SENDER_DRY_EVENT:
+		free_expression(expression->value.sctp_sender_dry_event->sender_dry_type);
+		free_expression(expression->value.sctp_sender_dry_event->sender_dry_flags);
+		free_expression(expression->value.sctp_sender_dry_event->sender_dry_length);
+		free_expression(expression->value.sctp_sender_dry_event->sender_dry_assoc_id);
+		break;
 	case EXPR_WORD:
 		assert(expression->value.string);
 		free(expression->value.string);
@@ -1378,6 +1385,42 @@ static int evaluate_sctp_shutdown_event_expression(struct expression *in,
 	return STATUS_OK;
 }
 
+static int evaluate_sctp_sender_dry_event_expression(struct expression *in,
+						     struct expression *out,
+						     char **error)
+{
+	struct sctp_sender_dry_event_expr *in_event;
+	struct sctp_sender_dry_event_expr *out_event;
+
+	assert(in->type == EXPR_SCTP_SENDER_DRY_EVENT);
+	assert(in->value.sctp_sender_dry_event);
+	assert(out->type == EXPR_SCTP_SENDER_DRY_EVENT);
+
+	out->value.sctp_sender_dry_event = calloc(1, sizeof(struct sctp_sender_dry_event_expr));
+
+	in_event = in->value.sctp_sender_dry_event;
+	out_event = out->value.sctp_sender_dry_event;
+
+	if (evaluate(in_event->sender_dry_type,
+		     &out_event->sender_dry_type,
+		     error))
+		return STATUS_ERR;
+	if (evaluate(in_event->sender_dry_flags,
+		     &out_event->sender_dry_flags,
+		     error))
+		return STATUS_ERR;
+	if (evaluate(in_event->sender_dry_length,
+		     &out_event->sender_dry_length,
+		     error))
+		return STATUS_ERR;
+	if (evaluate(in_event->sender_dry_assoc_id,
+		     &out_event->sender_dry_assoc_id,
+		     error))
+		return STATUS_ERR;
+
+	return STATUS_OK;
+}
+
 static int evaluate(struct expression *in,
 		    struct expression **out_ptr, char **error)
 {
@@ -1466,6 +1509,9 @@ static int evaluate(struct expression *in,
 	case EXPR_SCTP_SHUTDOWN_EVENT:
 		result = evaluate_sctp_shutdown_event_expression(in, out, error);
 		break;
+	case EXPR_SCTP_SENDER_DRY_EVENT:
+		result = evaluate_sctp_sender_dry_event_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 95ca7231..fbcf3009 100644
--- a/gtests/net/packetdrill/script.h
+++ b/gtests/net/packetdrill/script.h
@@ -67,6 +67,7 @@ enum expression_t {
 	EXPR_SCTP_NXTINFO,        /* struct sctp_nxtinfo for syscall sctp_recvv */
 	EXPR_SCTP_RECVV_RN,       /* struct sctp_recvv_rn for syscall sctp_recvv */
 	EXPR_SCTP_SHUTDOWN_EVENT, /* expression tree for sctp_shutdown_event */
+	EXPR_SCTP_SENDER_DRY_EVENT, /* expression tree for sctp_sender_dry_event */
 	NUM_EXPR_TYPES,
 };
 /* Convert an expression type to a human-readable string */
@@ -107,6 +108,7 @@ struct expression {
 		struct sctp_nxtinfo_expr *sctp_nxtinfo;
 		struct sctp_recvv_rn_expr *sctp_recvv_rn;
 		struct sctp_shutdown_event_expr *sctp_shutdown_event;
+		struct sctp_sender_dry_event_expr *sctp_sender_dry_event;
 	} value;
 	const char *format;	/* the printf format for printing the value */
 };
@@ -324,6 +326,14 @@ struct sctp_shutdown_event_expr {
 	struct expression *sse_length;
 };
 
+/* Parse tree for sctp_shutdown_event for notifications. */
+struct sctp_sender_dry_event_expr {
+	struct expression *sender_dry_type;
+	struct expression *sender_dry_flags;
+	struct expression *sender_dry_length;
+	struct expression *sender_dry_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 8f8bd758..63c501f5 100644
--- a/gtests/net/packetdrill/symbols_freebsd.c
+++ b/gtests/net/packetdrill/symbols_freebsd.c
@@ -169,6 +169,7 @@ struct int_symbol platform_symbols_table[] = {
 	{ SCTP_REMOTE_ERROR,                "SCTP_REMOTE_ERROR"               },
 	{ SCTP_SEND_FAILED,                 "SCTP_SEND_FAILED"                },
 	{ SCTP_SHUTDOWN_EVENT,              "SCTP_SHUTDOWN_EVENT"             },
+	{ SCTP_SENDER_DRY_EVENT,            "SCTP_SENDER_DRY_EVENT"           },
 	{ SCTP_ADAPTATION_INDICATION,       "SCTP_ADAPTATION_INDICATION"      }, 
 	{ SCTP_ADAPTION_INDICATION,         "SCTP_ADAPTION_INDICATION"        },
 	{ SCTP_PARTIAL_DELIVERY_EVENT,      "SCTP_PARTIAL_DELIVERY_EVENT"     },
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_notifications.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_notifications.pkt
index d6662b38..df4d613c 100644
--- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_notifications.pkt
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_notifications.pkt
@@ -10,6 +10,26 @@
 +0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 //enable shutdown events
 +0.0 setsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=1}, 8) = 0
++0.0 getsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=1}, [8]) = 0
++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=0}, 8) = 0
++0.0 getsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=0}, [8]) = 0
+
++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_EVENTS, {sctp_data_io_event=1, sctp_association_event=1, sctp_address_event=0, sctp_send_failure_event=1,
+sctp_peer_error_event=0, sctp_shutdown_event=1, sctp_partial_delivery_event=0, sctp_adaptation_layer_event=0, sctp_authentication_event=0,
+sctp_sender_dry_event=0}, 11) = 0
++0.0 getsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=1}, [8]) = 0
++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_EVENTS, {sctp_data_io_event=1, sctp_association_event=1, sctp_address_event=0, sctp_send_failure_event=1,
+sctp_peer_error_event=0, sctp_shutdown_event=0, sctp_partial_delivery_event=0, sctp_adaptation_layer_event=0, sctp_authentication_event=0,
+sctp_sender_dry_event=0}, 11) = 0
+
++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SENDER_DRY_EVENT, se_on=1}, 8) = 0
++0.0 sctp_recvv(3, [{iov_base={sender_dry_type=SCTP_SENDER_DRY_EVENT, sender_dry_flags=0, sender_dry_length=12, sender_dry_assoc_id=3}, iov_len=1000}], 1,
+..., 20, NULL, [0], [SCTP_RECVV_NOINFO], [MSG_NOTIFICATION|MSG_EOR]) = 12
+
+
+
++0.0 getsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=0}, [8]) = 0
++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=1}, 8) = 0
 // Tear down the association
 +0.0 < sctp: SHUTDOWN[flgs=0, cum_tsn=0]
 *    > sctp: SHUTDOWN_ACK[flgs=0]
-- 
GitLab