diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index 357e47227b02cf926f6e9e47279c333474a58b20..1f7ed9d5064590e085dc2c59e8cfae27fa5ac099 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -278,6 +278,9 @@ nxt_ppid                        return NXT_PPID;
 nxt_length                      return NXT_LENGTH;
 recvv_rcvinfo                   return RECVV_RCVINFO;
 recvv_nxtinfo                   return RECVV_NXTINFO;
+sse_type                        return SSE_TYPE;
+sse_flags                       return SSE_FLAGS;
+sse_length                      return SSE_LENGTH;
 CHUNK				return CHUNK;
 DATA				return DATA;
 INIT				return INIT;
diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index 35c278a374e511c3312ae9f72f2a683d52de789b..3fefbb34ec33739c92f881be48b697ad0be61b20 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -547,6 +547,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %token <reserved> RCV_SID RCV_SSN RCV_FLAGS RCV_PPID RCV_TSN RCV_CUMTSN RCV_CONTEXT
 %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 <floating> FLOAT
 %token <integer> INTEGER HEX_INTEGER
 %token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR
@@ -581,7 +582,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <string> function_name
 %type <expression_list> expression_list function_arguments
 %type <expression> expression binary_expression array
-%type <expression> decimal_integer hex_integer
+%type <expression> decimal_integer hex_integer data
 %type <expression> inaddr sockaddr msghdr iovec pollfd opt_revents
 %type <expression> linger l_onoff l_linger
 %type <expression> sctp_status sstat_state sstat_rwnd sstat_unackdata sstat_penddata
@@ -602,6 +603,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <expression> sctp_prinfo sctp_authinfo pr_policy sctp_sendv_spa
 %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 <errno_info> opt_errno
 %type <chunk_list> sctp_chunk_list_spec
 %type <chunk_list_item> sctp_chunk_spec
@@ -2546,7 +2548,7 @@ sockaddr
 #endif
 		ipv4->sin_port = htons($10);
 		if (inet_pton(AF_INET, $17, &ipv4->sin_addr) == 1) {
-			$$ = new_expression(EXPR_SOCKET_ADDRESS_IPV4);
+		$$ = new_expression(EXPR_SOCKET_ADDRESS_IPV4);
 			$$->value.socket_address_ipv4 = ipv4;
 		} else {
 			free(ipv4);
@@ -2571,6 +2573,11 @@ sockaddr
 }
 ;
 
+data
+: ELLIPSIS { new_expression(EXPR_ELLIPSIS); }
+| sctp_shutdown_event { $$ = $1; }
+;
+
 msghdr
 : '{' MSG_NAME '(' ELLIPSIS ')' '=' ELLIPSIS ','
       MSG_IOV '(' decimal_integer ')' '=' array ','
@@ -2588,18 +2595,18 @@ msghdr
 ;
 
 iovec
-: '{' ELLIPSIS ',' decimal_integer '}' {
+: '{' data ',' decimal_integer '}' {
 	struct iovec_expr *iov_expr = calloc(1, sizeof(struct iovec_expr));
 	$$ = new_expression(EXPR_IOVEC);
 	$$->value.iovec = iov_expr;
-	iov_expr->iov_base = new_expression(EXPR_ELLIPSIS);
+	iov_expr->iov_base = $2;
 	iov_expr->iov_len = $4;
 }
-| '{' IOV_BASE '=' ELLIPSIS ',' IOV_LEN '=' decimal_integer '}' {
+| '{' IOV_BASE '=' data ',' IOV_LEN '=' decimal_integer '}' {
 	struct iovec_expr *iov_expr = calloc(1, sizeof(struct iovec_expr));
 	$$ = new_expression(EXPR_IOVEC);
 	$$->value.iovec = iov_expr;
-	iov_expr->iov_base = new_expression(EXPR_ELLIPSIS);
+	iov_expr->iov_base = $4;
 	iov_expr->iov_len = $8;
 }
 ;
@@ -3460,6 +3467,49 @@ sctp_recvv_rn
 }
 ;
 
+sse_type 
+: SSE_TYPE '=' INTEGER {
+	if (!is_valid_u16($3)) {
+		semantic_error("sse_type out of range");
+	}
+	$$ = new_integer_expression($3, "%hu");
+}
+| SSE_TYPE '=' WORD {
+	$$ = new_expression(EXPR_WORD);
+	$$->value.string = $3;
+}
+| SSE_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sse_flags 
+: SSE_FLAGS '=' INTEGER {
+	if (!is_valid_u16($3)) {
+		semantic_error("sse_flags out of range");
+	}
+	$$ = new_integer_expression($3, "%hu");
+}
+| SSE_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sse_length 
+: SSE_LENGTH '=' INTEGER {
+	if (!is_valid_u32($3)) {
+		semantic_error("sse_length out of range");
+	}
+	$$ = new_integer_expression($3, "%u");
+}
+| SSE_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+sctp_shutdown_event
+: '{' sse_type ',' sse_flags ',' sse_length '}' {
+	$$ = new_expression(EXPR_SCTP_SHUTDOWN_EVENT);
+	$$->value.sctp_shutdown_event = calloc(1, sizeof(struct sctp_shutdown_event_expr));
+	$$->value.sctp_shutdown_event->sse_type = $2;
+	$$->value.sctp_shutdown_event->sse_flags = $4;
+	$$->value.sctp_shutdown_event->sse_length = $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 30e43bf6d1d0433829ed7b071dd024351880129b..782f9a3f2569e1fbfb939ae5ce42a8d7218318fa 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -1,3 +1,4 @@
+
 /*
  * Copyright 2013 Google Inc.
  *
@@ -48,6 +49,11 @@
 
 static int to_live_fd(struct state *state, int script_fd, int *live_fd,
 		      char **error);
+#if defined(__FreeBSD__)
+static int check_sctp_notification(struct iovec *iov, struct expression *iovec_expr,
+				   char **error);
+#endif
+
 
 /* Provide a wrapper for the Linux gettid() system call (glibc does not). */
 static pid_t gettid(void)
@@ -453,7 +459,8 @@ static int iovec_new(struct expression *expression,
 
 		iov_expr = list->expression->value.iovec;
 
-		assert(iov_expr->iov_base->type == EXPR_ELLIPSIS);
+		assert(iov_expr->iov_base->type == EXPR_ELLIPSIS ||
+		       iov_expr->iov_base->type == EXPR_SCTP_SHUTDOWN_EVENT);
 		assert(iov_expr->iov_len->type == EXPR_INTEGER);
 
 		len = iov_expr->iov_len->value.num;
@@ -1389,6 +1396,9 @@ static int syscall_recvmsg(struct state *state, struct syscall_spec *syscall,
 		asprintf(error, "Expected msg_flags 0x%08X but got 0x%08X",
 			 expected_msg_flags, msg->msg_flags);
 		goto error_out;
+	} else if (msg->msg_flags & MSG_NOTIFICATION) {
+		if (check_sctp_notification(msg->msg_iov, msg_expression->value.msghdr->msg_iov, error))
+			goto error_out;
 	}
 
 	status = STATUS_OK;
@@ -2552,7 +2562,7 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 
 	if (live_optlen != script_optlen) {
 		asprintf(error, "optlen: expected: %d actual: %d",
-		         (int)script_optlen, (int)live_optlen);
+			 (int)script_optlen, (int)live_optlen);
 		free(live_optval);
 		return STATUS_ERR;
 	}
@@ -2721,15 +2731,15 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 	case EXPR_SCTP_RTOINFO:
 		rtoinfo.srto_assoc_id = 0;
 		if (get_u32(val_expression->value.sctp_rtoinfo->srto_initial,
-		            &rtoinfo.srto_initial, error)) {
+			    &rtoinfo.srto_initial, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u32(val_expression->value.sctp_rtoinfo->srto_max,
-		            &rtoinfo.srto_max, error)) {
+			    &rtoinfo.srto_max, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u32(val_expression->value.sctp_rtoinfo->srto_min,
-		            &rtoinfo.srto_min, error)) {
+			    &rtoinfo.srto_min, error)) {
 			return STATUS_ERR;
 		}
 		optval = &rtoinfo;
@@ -2739,23 +2749,23 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 	case EXPR_SCTP_ASSOCPARAMS:
 		assocparams.sasoc_assoc_id = 0;
 		if (get_u16(val_expression->value.sctp_assocparams->sasoc_asocmaxrxt,
-		            &assocparams.sasoc_asocmaxrxt, error)) {
+			    &assocparams.sasoc_asocmaxrxt, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u16(val_expression->value.sctp_assocparams->sasoc_number_peer_destinations,
-		            &assocparams.sasoc_number_peer_destinations, error)) {
+			    &assocparams.sasoc_number_peer_destinations, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u32(val_expression->value.sctp_assocparams->sasoc_peer_rwnd,
-		            &assocparams.sasoc_peer_rwnd, error)) {
+			    &assocparams.sasoc_peer_rwnd, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u32(val_expression->value.sctp_assocparams->sasoc_local_rwnd,
-		            &assocparams.sasoc_local_rwnd, error)) {
+			    &assocparams.sasoc_local_rwnd, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u32(val_expression->value.sctp_assocparams->sasoc_cookie_life,
-		            &assocparams.sasoc_cookie_life, error)) {
+			    &assocparams.sasoc_cookie_life, error)) {
 			return STATUS_ERR;
 		}
 		optval = &assocparams;
@@ -2786,7 +2796,7 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 	case EXPR_SCTP_ASSOC_VALUE:
 		assoc_value.assoc_id = 0;
 		if (get_u32(val_expression->value.sctp_assoc_value->assoc_value,
-		            &assoc_value.assoc_value, error)) {
+			    &assoc_value.assoc_value, error)) {
 			return STATUS_ERR;
 		}
 		optval = &assoc_value;
@@ -2796,11 +2806,11 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 	case EXPR_SCTP_STREAM_VALUE:
 		stream_value.assoc_id = 0;
 		if (get_u16(val_expression->value.sctp_stream_value->stream_id,
-		            &stream_value.stream_id, error)) {
+			    &stream_value.stream_id, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u16(val_expression->value.sctp_stream_value->stream_value,
-		            &stream_value.stream_value, error)) {
+			    &stream_value.stream_value, error)) {
 			return STATUS_ERR;
 		}
 		optval = &stream_value;
@@ -2810,11 +2820,11 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 	case EXPR_SCTP_SACKINFO:
 		sack_info.sack_assoc_id = 0;
 		if (get_u32(val_expression->value.sctp_sack_info->sack_delay,
-		            &sack_info.sack_delay, error)) {
+			    &sack_info.sack_delay, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u32(val_expression->value.sctp_sack_info->sack_freq,
-		            &sack_info.sack_freq, error)) {
+			    &sack_info.sack_freq, error)) {
 			return STATUS_ERR;
 		}
 		optval = &sack_info;
@@ -2886,46 +2896,46 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 	case EXPR_SCTP_PEER_ADDR_PARAMS:
 		paddrparams.spp_assoc_id = 0;
 		if (get_sockstorage_arg(val_expression->value.sctp_paddrparams->spp_address,
-				        &paddrparams.spp_address, live_fd)) {
+					&paddrparams.spp_address, live_fd)) {
 			asprintf(error, "can't determine spp_address");
 			return STATUS_ERR;
 		}
 		if (get_u32(val_expression->value.sctp_paddrparams->spp_hbinterval,
-		            &paddrparams.spp_hbinterval, error)) {
+			    &paddrparams.spp_hbinterval, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u16(val_expression->value.sctp_paddrparams->spp_pathmaxrxt,
-		            &paddrparams.spp_pathmaxrxt, error)) {
+			    &paddrparams.spp_pathmaxrxt, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u32(val_expression->value.sctp_paddrparams->spp_pathmtu,
-		            &paddrparams.spp_pathmtu, error)) {
+			    &paddrparams.spp_pathmtu, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u32(val_expression->value.sctp_paddrparams->spp_flags,
-		            &paddrparams.spp_flags, error)) {
+			    &paddrparams.spp_flags, error)) {
 			return STATUS_ERR;
 		}
 #ifdef __FreeBSD__
 		if (get_u32(val_expression->value.sctp_paddrparams->spp_ipv6_flowlabel,
-		            &paddrparams.spp_ipv6_flowlabel, error)) {
+			    &paddrparams.spp_ipv6_flowlabel, error)) {
 			return STATUS_ERR;
 		}
 		if (get_u8(val_expression->value.sctp_paddrparams->spp_dscp,
-		           &paddrparams.spp_dscp, error)) {
+			   &paddrparams.spp_dscp, error)) {
 			return STATUS_ERR;
 		}
 #endif
 #ifdef linux
 		if (get_u32(val_expression->value.sctp_paddrparams->spp_ipv6_flowlabel,
-		            &spp_ipv6_flowlabel, error)) {
+			    &spp_ipv6_flowlabel, error)) {
 			return STATUS_ERR;
 		} else if (spp_ipv6_flowlabel != 0) {
 			asprintf(error, "Linux doesn't support paddrparams.spp_ipv6_flowlabel");
 			return STATUS_ERR;
 		}
 		if (get_u8(val_expression->value.sctp_paddrparams->spp_dscp,
-		           &spp_dscp, error)) {
+			   &spp_dscp, error)) {
 			return STATUS_ERR;
 		} else if (spp_dscp != 0) {
 			asprintf(error, "Linux doesn't support paddrparams.spp_dscp");
@@ -3679,6 +3689,85 @@ static int check_sctp_nxtinfo(struct sctp_nxtinfo_expr *expr,
 }
 #endif
 
+#if defined(__FreeBSD__)
+static int check_sctp_shutdown_event(struct sctp_shutdown_event_expr *expr,
+				     struct sctp_shutdown_event *sctp_event,
+				     char **error) {
+	if (expr->sse_type->type != EXPR_ELLIPSIS) {
+		u16 sse_type;
+		 
+		if (get_u16(expr->sse_type, &sse_type, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_event->sse_type != sse_type) {
+			asprintf(error, "sctp_shutdown_event.sse_type: expected: %hu actual: %hu",
+				 sse_type, sctp_event->sse_type);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sse_flags->type != EXPR_ELLIPSIS) {
+		u16 sse_flags;
+		 
+		if (get_u16(expr->sse_flags, &sse_flags, error)) {
+			return STATUS_ERR;		}
+		if (sctp_event->sse_flags != sse_flags) {
+			asprintf(error, "sctp_shutdown_event.sse_flags: expected: %hu actual: %hu",
+				 sse_flags, sctp_event->sse_flags);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sse_length->type != EXPR_ELLIPSIS) {
+		u32 sse_length;
+
+		if (get_u32(expr->sse_length, &sse_length, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_event->sse_length != sse_length) {
+			asprintf(error, "sctp_shutdown_event.sse_length: expected: %u actual: %u",
+				 sse_length, sctp_event->sse_length);
+			return STATUS_ERR;
+		}
+	}
+	return STATUS_OK;
+}
+#endif
+
+#if defined(__FreeBSD__)
+static int check_sctp_notification(struct iovec *iov,
+				   struct expression *iovec_expr,
+				   char **error) {
+	struct expression_list *iovec_expr_list;
+	struct expression *script_iov, *script_iov_base;
+	if (iovec_expr == NULL)
+		return STATUS_ERR;
+	if (check_type(iovec_expr, EXPR_LIST, error))
+		return STATUS_ERR;
+	iovec_expr_list = iovec_expr->value.list;
+	int i=0;
+	while (iovec_expr_list != NULL) {
+		script_iov = iovec_expr_list->expression;
+		if (check_type(script_iov, EXPR_IOVEC, error))
+			return STATUS_ERR;
+		script_iov_base = script_iov->value.iovec->iov_base;
+		switch (script_iov_base->type) {
+		case EXPR_SCTP_SHUTDOWN_EVENT:
+			if (check_sctp_shutdown_event(script_iov_base->value.sctp_shutdown_event,
+						      (struct sctp_shutdown_event *) iov->iov_base,
+						      error))
+				return STATUS_ERR;
+			break;
+		case EXPR_ELLIPSIS:
+			break;
+		default:
+			break;
+		}
+		i++;
+		iovec_expr_list = iovec_expr_list->next;
+	}
+	return STATUS_OK;
+}
+#endif
+
 #if defined(__FreeBSD__)
 static int check_sctp_recvv_rn(struct sctp_recvv_rn_expr *expr,
 			       struct sctp_recvv_rn *sctp_recvv_rn,
@@ -3745,10 +3834,10 @@ static int syscall_sctp_recvv(struct state *state, struct syscall_spec *syscall,
 	} else if (info_expr->type == EXPR_SCTP_RECVV_RN) {
 		info = &recvv_rn;
 	} else {
-		return STATUS_ERR;
+		goto error_out;
 	}
 	if (u32_bracketed_arg(args, 6, &infolen, error)) {
-		return STATUS_ERR;
+		goto error_out;
 	}
 	infotype = 0;
 	flags = 0;
@@ -3763,17 +3852,12 @@ static int syscall_sctp_recvv(struct state *state, struct syscall_spec *syscall,
 
 	result = sctp_recvv(live_fd, iov, iovlen, (struct sockaddr *)from, &fromlen, info, &infolen, &infotype, &flags);
 
-	iovec_free(iov, script_iovec_list_len);
+	if (end_syscall(state, syscall, CHECK_EXACT, result, error))
+		goto error_out;
 
-	if (end_syscall(state, syscall, CHECK_EXACT, result, error)) {
-		free(from);
-		return STATUS_ERR;
-	}
 	if (from != NULL) {
-		if (check_sockaddr(addr_expr, from, error)) {
-			free(from);
-			return STATUS_ERR;
-		}
+		if (check_sockaddr(addr_expr, from, error))
+			goto error_out;
 	}
 	free(from);
 
@@ -3781,64 +3865,72 @@ static int syscall_sctp_recvv(struct state *state, struct syscall_spec *syscall,
 	if (infotype_expr->type != EXPR_ELLIPSIS) {
 		s32 script_infotype;
 		if (s32_bracketed_arg(args, 7, &script_infotype, error))
-			return STATUS_ERR;
+			goto error_out;
 
 		if (infotype != script_infotype) {
 			asprintf(error, "sctp_recvv infotype: expected: %u actual: %u",
 				 script_infotype, infotype);
-			return STATUS_ERR;
+			goto error_out;
 		}
 	}
 	switch(infotype) {
 	case SCTP_RECVV_NOINFO:
 		if (infolen != 0) {
 			asprintf(error, "infolen returned bad size for null. expected 0, actual %u", infolen);
-			return STATUS_ERR;
+			goto error_out;
 		}
 		break;
 	case SCTP_RECVV_RCVINFO:
 		if (infolen != sizeof(struct sctp_rcvinfo)) {
 			asprintf(error, "infolen returned bad size for sctp_rcvinfo. expected %u, actual %u",
 				 sizeof(struct sctp_rcvinfo), infolen);
-			return STATUS_ERR;
+			goto error_out;
 		}
 		if (check_sctp_rcvinfo(info_expr->value.sctp_rcvinfo, info, error))
-			return STATUS_ERR;
+			goto error_out;
 		break;
 	case SCTP_RECVV_NXTINFO:
 		if (infolen != sizeof(struct sctp_nxtinfo)) {
 			asprintf(error, "infolen returned bad size for sctp_nxtinfo. expected %u, actual %u",
 				 sizeof(struct sctp_nxtinfo), infolen);
-			return STATUS_ERR;
+			goto error_out;
 		}
 		if (check_sctp_nxtinfo(info_expr->value.sctp_nxtinfo, info, error))
-			return STATUS_ERR;
+			goto error_out;
 		break;
 	case SCTP_RECVV_RN:
 		if (infolen != sizeof(struct sctp_recvv_rn)) {
 			asprintf(error, "infolen returned bad size for sctp_recvv_rn. expected %u, actual %u",
 				 sizeof(struct sctp_recvv_rn), infolen);
-			return STATUS_ERR;
+			goto error_out;
 		}
 		if (check_sctp_recvv_rn(info_expr->value.sctp_recvv_rn, info, error))
-			return STATUS_ERR;
+			goto error_out;
 		break;
 	default:
-		return STATUS_ERR;
+		goto error_out;
 		break;
 	}
 	flags_expr = get_arg(args, 8, error);
 	if (flags_expr->type != EXPR_ELLIPSIS) {
 		s32 script_flags;
 		if (s32_bracketed_arg(args, 8, &script_flags, error))
-			return STATUS_ERR;
+			goto error_out;
 		if (flags != script_flags) {
 			asprintf(error, "sctp_recvv flags bad return value. expected %d, actual %d",
 				 script_flags, flags);
-			return STATUS_ERR;
+			goto error_out;
+		} else if (flags & MSG_NOTIFICATION) {
+			if (check_sctp_notification(iov, iovec_expr_list, error))
+				goto error_out;
 		}
 	}
+	iovec_free(iov, script_iovec_list_len);	
 	return STATUS_OK;
+error_out:
+	free(from);
+	iovec_free(iov, script_iovec_list_len);	
+	return STATUS_ERR;
 #else
 	asprintf(error, "sctp_recvv is not supported");
 	return STATUS_ERR;
diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c
index 82f724aefceb861dd490a4473d45191149bdbcd2..eaeea6aedce6d6657596cd72edb0d81541e7666d 100644
--- a/gtests/net/packetdrill/script.c
+++ b/gtests/net/packetdrill/script.c
@@ -85,6 +85,7 @@ struct expression_type_entry expression_type_table[] = {
 	{ EXPR_SCTP_RCVINFO,         "sctp_rcvinfo"    },
 	{ EXPR_SCTP_NXTINFO,         "sctp_nxtinfo"    },
 	{ EXPR_SCTP_RECVV_RN,        "sctp_recvv_rn "  },
+	{ EXPR_SCTP_SHUTDOWN_EVENT,  "sctp_shutdown_event"},
 	{ NUM_EXPR_TYPES,            NULL}
 };
 
@@ -416,6 +417,11 @@ void free_expression(struct expression *expression)
 		free_expression(expression->value.sctp_recvv_rn->recvv_rcvinfo);
 		free_expression(expression->value.sctp_recvv_rn->recvv_nxtinfo);
 		break;
+	case EXPR_SCTP_SHUTDOWN_EVENT:
+		free_expression(expression->value.sctp_shutdown_event->sse_type);
+		free_expression(expression->value.sctp_shutdown_event->sse_flags);
+		free_expression(expression->value.sctp_shutdown_event->sse_length);
+		break;
 	case EXPR_WORD:
 		assert(expression->value.string);
 		free(expression->value.string);
@@ -1244,19 +1250,18 @@ static int evaluate_sctp_recvv_rn_expression(struct expression *in,
 					    struct expression *out,
 					    char **error)
 {
-        struct sctp_recvv_rn_expr *in_rn;
-        struct sctp_recvv_rn_expr *out_rn;
+	struct sctp_recvv_rn_expr *in_rn;
+	struct sctp_recvv_rn_expr *out_rn;
 
-        assert(in->type == EXPR_SCTP_RECVV_RN);
-        assert(in->value.sctp_recvv_rn);
-        assert(out->type == EXPR_SCTP_RECVV_RN);
+	assert(in->type == EXPR_SCTP_RECVV_RN);
+	assert(in->value.sctp_recvv_rn);
+	assert(out->type == EXPR_SCTP_RECVV_RN);
 
-        out->value.sctp_recvv_rn = calloc(1, sizeof(struct sctp_recvv_rn_expr));
-                     
-        in_rn = in->value.sctp_recvv_rn;
-        out_rn = out->value.sctp_recvv_rn;
-                     
-        if (evaluate(in_rn->recvv_rcvinfo,
+	out->value.sctp_recvv_rn = calloc(1, sizeof(struct sctp_recvv_rn_expr));
+	in_rn = in->value.sctp_recvv_rn;
+	out_rn = out->value.sctp_recvv_rn;
+
+	if (evaluate(in_rn->recvv_rcvinfo,
 		     &out_rn->recvv_rcvinfo,
 		     error))
 		return STATUS_ERR;
@@ -1267,6 +1272,39 @@ static int evaluate_sctp_recvv_rn_expression(struct expression *in,
 
 	return STATUS_OK;
 }
+
+static int evaluate_sctp_shutdown_event_expression(struct expression *in,
+						   struct expression *out,
+						   char **error)
+{
+	struct sctp_shutdown_event_expr *in_event;
+	struct sctp_shutdown_event_expr *out_event;
+
+	assert(in->type == EXPR_SCTP_SHUTDOWN_EVENT);
+	assert(in->value.sctp_shutdown_event);
+	assert(out->type == EXPR_SCTP_SHUTDOWN_EVENT);
+
+	out->value.sctp_shutdown_event = calloc(1, sizeof(struct sctp_shutdown_event_expr));
+
+	in_event = in->value.sctp_shutdown_event;
+	out_event = out->value.sctp_shutdown_event;
+
+	if (evaluate(in_event->sse_type,
+		     &out_event->sse_type,
+		     error))
+		return STATUS_ERR;
+	if (evaluate(in_event->sse_flags,
+		     &out_event->sse_flags,
+		     error))
+		return STATUS_ERR;
+	if (evaluate(in_event->sse_length,
+		     &out_event->sse_length,
+		     error))
+		return STATUS_ERR;
+
+	return STATUS_OK;
+}
+
 static int evaluate(struct expression *in,
 		    struct expression **out_ptr, char **error)
 {
@@ -1349,6 +1387,9 @@ static int evaluate(struct expression *in,
 	case EXPR_SCTP_RECVV_RN:
 		result = evaluate_sctp_recvv_rn_expression(in, out, error);
 		break;
+	case EXPR_SCTP_SHUTDOWN_EVENT:
+		result = evaluate_sctp_shutdown_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 c47ec124700990434b1da23d934fa328db4515e9..effbd57118eae1592ffc4c1ae51cac61037947f0 100644
--- a/gtests/net/packetdrill/script.h
+++ b/gtests/net/packetdrill/script.h
@@ -65,6 +65,7 @@ enum expression_t {
 	EXPR_SCTP_RCVINFO,        /* struct sctp_rcvinfo for syscall sctp_recvv */
 	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 */
 	NUM_EXPR_TYPES,
 };
 /* Convert an expression type to a human-readable string */
@@ -103,6 +104,7 @@ struct expression {
 		struct sctp_rcvinfo_expr *sctp_rcvinfo;
 		struct sctp_nxtinfo_expr *sctp_nxtinfo;
 		struct sctp_recvv_rn_expr *sctp_recvv_rn;
+		struct sctp_shutdown_event_expr *sctp_shutdown_event;
 	} value;
 	const char *format;	/* the printf format for printing the value */
 };
@@ -299,6 +301,13 @@ struct sctp_recvv_rn_expr {
 	struct expression *recvv_nxtinfo;
 };
 
+/* Parse tree for sctp_shutdown_event for notifications. */
+struct sctp_shutdown_event_expr {
+	struct expression *sse_type;
+	struct expression *sse_flags;
+	struct expression *sse_length;
+};
+
 /* 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/tests/bsd/sctp/sctp_notifications.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_notifications.pkt
new file mode 100644
index 0000000000000000000000000000000000000000..d6662b3851cc802630a15a777b6fe4678a05de0c
--- /dev/null
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_notifications.pkt
@@ -0,0 +1,21 @@
++0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3
++0.0 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
++0.0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
+// Check the handshake with an empty(!) cookie
++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)
++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...]
++0.1 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=1, STATE_COOKIE[len=4, val=...]]
++0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...]
++0.1 < sctp: COOKIE_ACK[flgs=0]
++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
+// Tear down the association
++0.0 < sctp: SHUTDOWN[flgs=0, cum_tsn=0]
+*    > sctp: SHUTDOWN_ACK[flgs=0]
++0.0 < sctp: SHUTDOWN_COMPLETE[flgs=0]
++0.0 recvmsg(3, {msg_name(...)=..., 
+		 msg_iov(1)=[{iov_base={sse_type=SCTP_SHUTDOWN_EVENT, sse_flags=0, sse_length=12}, iov_len=1000}],
+		 msg_flags=MSG_NOTIFICATION|MSG_EOR}, 0) = 12
+//+0.0 sctp_recvv(3, [{iov_base={sse_type=SCTP_SHUTDOWN_EVENT, sse_flags=1, sse_length=12}, iov_len=1000}], 1,
+//..., 20, NULL, [0], [SCTP_RECVV_NOINFO], [MSG_NOTIFICATION|MSG_EOR]) = 12