diff --git a/gtests/net/packetdrill/packet.c b/gtests/net/packetdrill/packet.c
index a5edfebe07eeca5d3ea2f53ae8078265c620e4b2..406e34659560622b0dfac625fca6490ffce94185 100644
--- a/gtests/net/packetdrill/packet.c
+++ b/gtests/net/packetdrill/packet.c
@@ -177,6 +177,11 @@ static struct packet *packet_copy_with_headroom(struct packet *old_packet,
 	packet->udplite	= offset_ptr(old_base, new_base, old_packet->udplite);
 	packet->icmpv4	= offset_ptr(old_base, new_base, old_packet->icmpv4);
 	packet->icmpv6	= offset_ptr(old_base, new_base, old_packet->icmpv6);
+        
+        if (old_packet->chunk_list == NULL) {
+		packet->chunk_list = NULL;
+		return packet;
+        }
 
 	/* Go through the SCTP specific lists */
 	for (old_chunk_item = old_packet->chunk_list->first;
diff --git a/gtests/net/packetdrill/packet.h b/gtests/net/packetdrill/packet.h
index 8e931ec28528670813bf29749eb3f205f0d84528..a51c9e1162421ed59f972a2bec91e86fdda3045c 100644
--- a/gtests/net/packetdrill/packet.h
+++ b/gtests/net/packetdrill/packet.h
@@ -105,11 +105,12 @@ struct packet {
 
 	s64 time_usecs;		/* wall time of receive/send if non-zero */
 
-	u32 flags;		/* various meta-flags */
-#define FLAG_WIN_NOCHECK	0x1  /* don't check TCP receive window */
-#define FLAG_OPTIONS_NOCHECK	0x2  /* don't check TCP options */
-#define FLAGS_SCTP_BAD_CRC32C   0x4  /* compute bad CRC32C for SCTP packets */
-#define FLAGS_SCTP_EXPLICIT_TAG 0x8  /* verification tag specified */
+	u32 flags;		  /* various meta-flags */
+#define FLAG_WIN_NOCHECK          0x1  /* don't check TCP receive window */
+#define FLAG_OPTIONS_NOCHECK      0x2  /* don't check TCP options */
+#define FLAGS_SCTP_BAD_CRC32C     0x4  /* compute bad CRC32C for SCTP packets */
+#define FLAGS_SCTP_EXPLICIT_TAG   0x8  /* verification tag specified */
+#define FLAGS_SCTP_GENERIC_PACKET 0x10 /* set if it is a generic packet */
 
 	enum ip_ecn_t ecn;	/* IPv4/IPv6 ECN treatment for packet */
 
diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index 7613efa1c7c60a9a96ec94edcb888d8fc645dc66..f5c85b66fe083778b3a6556f247c61649b1f9dae 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -933,6 +933,72 @@ sctp_packet_spec
 
 	$$ = packet_encapsulate_and_free(outer, inner);
 }
+| packet_prefix opt_ip_info SCTP ':' '[' byte_list ']' {
+	char *error = NULL;
+	struct packet *outer = $1, *inner = NULL;
+	enum direction_t direction = outer->direction;
+
+	inner = new_sctp_generic_packet(in_config->wire_protocol, direction, $2,
+	                                -1, false, $6, &error);
+	if (inner == NULL) {
+		assert(error != NULL);
+        semantic_error(error);
+		free(error);
+	}
+
+	$$ = packet_encapsulate_and_free(outer, inner);
+}
+| packet_prefix opt_ip_info SCTP '(' BAD_CRC32C ')' ':'  '[' byte_list ']' {
+	char *error = NULL;
+	struct packet *outer = $1, *inner = NULL;
+	enum direction_t direction = outer->direction;
+
+	inner = new_sctp_generic_packet(in_config->wire_protocol, direction, $2,
+	                                -1, true, $9, &error);
+	if (inner == NULL) {
+		assert(error != NULL);
+		semantic_error(error);
+		free(error);
+	}
+
+	$$ = packet_encapsulate_and_free(outer, inner);
+}
+| packet_prefix opt_ip_info SCTP '(' TAG '=' INTEGER ')' ':' '[' byte_list ']' {
+	char *error = NULL;
+	struct packet *outer = $1, *inner = NULL;
+	enum direction_t direction = outer->direction;
+
+	if (!is_valid_u32($7)) {
+		semantic_error("tag value out of range");
+	}
+	inner = new_sctp_generic_packet(in_config->wire_protocol, direction, $2,
+	                                $7, false, $11, &error);
+	if (inner == NULL) {
+		assert(error != NULL);
+		semantic_error(error);
+		free(error);
+	}
+
+	$$ = packet_encapsulate_and_free(outer, inner);
+}
+| packet_prefix opt_ip_info SCTP '(' BAD_CRC32C ',' TAG '=' INTEGER ')' ':' '[' byte_list ']' {
+	char *error = NULL;
+	struct packet *outer = $1, *inner = NULL;
+	enum direction_t direction = outer->direction;
+
+	if (!is_valid_u32($9)) {
+		semantic_error("tag value out of range");
+	}
+	inner = new_sctp_generic_packet(in_config->wire_protocol, direction, $2,
+	                                $9, true, $13, &error);
+	if (inner == NULL) {
+		assert(error != NULL);
+		semantic_error(error);
+		free(error);
+	}
+
+	$$ = packet_encapsulate_and_free(outer, inner);
+}
 ;
 
 sctp_chunk_list_spec
diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c
index 6d7b021b7ff6c4c8a1d4e68f6059751768896341..57069c9a6cbd5b3f847e3ee0256ad9bb176f174a 100644
--- a/gtests/net/packetdrill/run_packet.c
+++ b/gtests/net/packetdrill/run_packet.c
@@ -191,7 +191,7 @@ static struct socket *handle_listen_for_script_packet(
 	 */
 	struct config *config = state->config;
 	struct socket *socket = state->socket_under_test;	/* shortcut */
-	struct sctp_init_chunk *init;
+	u32 initiate_tag, initial_tsn;
 	struct sctp_chunk_list_item *item;
 
 	bool match = (direction == DIRECTION_INBOUND);
@@ -212,14 +212,53 @@ static struct socket *handle_listen_for_script_packet(
 		return NULL;
 
 	if (packet->sctp != NULL) {
-		assert(packet->chunk_list != NULL);
-		item = packet->chunk_list->first;
-		if ((item != NULL) &&
-		    (item->chunk->type == SCTP_INIT_CHUNK_TYPE)) {
-			init = (struct sctp_init_chunk *)item->chunk;
+		if (packet->chunk_list != NULL) {
+			item = packet->chunk_list->first;
+			if ((item != NULL) &&
+			    (item->chunk->type == SCTP_INIT_CHUNK_TYPE)) {
+				struct sctp_init_chunk *init = (struct sctp_init_chunk *)item->chunk;
+				initiate_tag = ntohl(init->initiate_tag);
+				initial_tsn = ntohl(init->initial_tsn);
+			} else {
+				return NULL;
+			}
 		} else {
-			return NULL;
+			if (packet->flags & FLAGS_SCTP_GENERIC_PACKET) {
+				struct header sctp_header;
+				unsigned int i;
+				bool found = false;
+				size_t chunk_length;
+
+				for (i = 0; i < ARRAY_SIZE(packet->headers); ++i) {
+					if (packet->headers[i].type == HEADER_SCTP) {
+						sctp_header = packet->headers[i];
+						found = true;
+						break;
+					}
+				}
+				
+				assert(found != false);
+				chunk_length = sctp_header.total_bytes - sizeof(struct sctp_common_header);
+
+				if (chunk_length < sizeof(struct sctp_init_chunk)) {
+					fprintf(stderr, "length of init chunk too short. you must specify the whole init chunk.");
+					return NULL;
+				}
+				
+				u8 *sctp_chunk_start = (u8 *) (packet->sctp + 1);
+				if (sctp_chunk_start[0] == SCTP_INIT_CHUNK_TYPE) {
+					struct sctp_init_chunk *init = (struct sctp_init_chunk *) sctp_chunk_start;
+					initiate_tag = ntohl(init->initiate_tag);
+					initial_tsn = ntohl(init->initial_tsn);
+				} else {
+					return NULL;
+				}
+			} else {
+				return NULL;
+			}
 		}
+	} else {
+		DEBUGP("packet->sctp == NULL");
 	}
 
 	/* Create a child passive socket for this incoming SYN packet.
@@ -241,8 +280,8 @@ static struct socket *handle_listen_for_script_packet(
 	if (packet->tcp != NULL) {
 		socket->script.remote_isn = ntohl(packet->tcp->seq);
 	} else {
-		socket->script.remote_initiate_tag = ntohl(init->initiate_tag);
-		socket->script.remote_initial_tsn = ntohl(init->initial_tsn);
+		socket->script.remote_initiate_tag = initiate_tag;
+		socket->script.remote_initial_tsn = initial_tsn;
 	}
 	socket->script.fd		= -1;
 
@@ -256,8 +295,8 @@ static struct socket *handle_listen_for_script_packet(
 	if (packet->tcp != NULL) {
 		socket->live.remote_isn = ntohl(packet->tcp->seq);
 	} else {
-		socket->live.remote_initiate_tag = ntohl(init->initiate_tag);
-		socket->live.remote_initial_tsn = ntohl(init->initial_tsn);
+		socket->live.remote_initiate_tag = initiate_tag;
+		socket->live.remote_initial_tsn = initial_tsn;
 	}
 	socket->live.fd			= -1;
 
@@ -2508,93 +2547,95 @@ static int do_inbound_script_packet(
 		}
 	}
 	if (packet->sctp) {
-		for (item = packet->chunk_list->first;
-		     item != NULL;
-		     item = item->next) {
-			switch (item->chunk->type) {
-			case SCTP_INIT_ACK_CHUNK_TYPE:
-				if (socket->state == SOCKET_ACTIVE_INIT_SENT) {
-					init_ack = (struct sctp_init_ack_chunk *)item->chunk;
-					DEBUGP("Moving socket in SOCKET_ACTIVE_INIT_ACK_RECEIVED\n");
-					socket->state = SOCKET_ACTIVE_INIT_ACK_RECEIVED;
-					socket->script.remote_initiate_tag = ntohl(init_ack->initiate_tag);
-					socket->script.remote_initial_tsn = ntohl(init_ack->initial_tsn);
-					socket->live.remote_initiate_tag = ntohl(init_ack->initiate_tag);
-					socket->live.remote_initial_tsn = ntohl(init_ack->initial_tsn);
-					DEBUGP("remote_initiate_tag 0x%08x, remote_initial_tsn 0x%08x\n", ntohl(init_ack->initiate_tag), ntohl(init_ack->initial_tsn));
-				}
-				break;
-			case SCTP_COOKIE_ECHO_CHUNK_TYPE:
-				if (item->flags & FLAG_CHUNK_VALUE_NOCHECK) {
-					temp_offset = socket->prepared_cookie_echo_length - item->length;
-					assert(packet->ip_bytes + temp_offset <= packet->buffer_bytes);
-					memmove((u8 *)item->chunk + item->length + temp_offset,
-						(u8 *)item->chunk + item->length,
-						packet_end(packet) - ((u8 *)item->chunk + item->length));
-					memcpy(item->chunk,
-					       socket->prepared_cookie_echo,
-					       socket->prepared_cookie_echo_length);
-					item->length = socket->prepared_cookie_echo_length;
-					packet->buffer_bytes += temp_offset;
-					packet->ip_bytes += temp_offset;
-					if (packet->ipv4) {
-						packet->ipv4->tot_len = htons(ntohs(packet->ipv4->tot_len) + temp_offset);
-					}
-					if (packet->ipv6) {
-						packet->ipv6->payload_len = htons(ntohs(packet->ipv6->payload_len) + temp_offset);
+		if (packet->chunk_list != NULL) {
+			for (item = packet->chunk_list->first;
+			     item != NULL;
+			     item = item->next) {
+				switch (item->chunk->type) {
+				case SCTP_INIT_ACK_CHUNK_TYPE:
+					if (socket->state == SOCKET_ACTIVE_INIT_SENT) {
+						init_ack = (struct sctp_init_ack_chunk *)item->chunk;
+						DEBUGP("Moving socket in SOCKET_ACTIVE_INIT_ACK_RECEIVED\n");
+						socket->state = SOCKET_ACTIVE_INIT_ACK_RECEIVED;
+						socket->script.remote_initiate_tag = ntohl(init_ack->initiate_tag);
+						socket->script.remote_initial_tsn = ntohl(init_ack->initial_tsn);
+						socket->live.remote_initiate_tag = ntohl(init_ack->initiate_tag);
+						socket->live.remote_initial_tsn = ntohl(init_ack->initial_tsn);
+						DEBUGP("remote_initiate_tag 0x%08x, remote_initial_tsn 0x%08x\n", ntohl(init_ack->initiate_tag), ntohl(init_ack->initial_tsn));
 					}
-					for (i = 0; i < PACKET_MAX_HEADERS; i++) {
-						if ((packet->ipv4 != NULL && packet->headers[i].h.ipv4 == packet->ipv4) ||
-						    (packet->ipv6 != NULL && packet->headers[i].h.ipv6 == packet->ipv6)) {
-							break;
+					break;
+				case SCTP_COOKIE_ECHO_CHUNK_TYPE:
+					if (item->flags & FLAG_CHUNK_VALUE_NOCHECK) {
+						temp_offset = socket->prepared_cookie_echo_length - item->length;
+						assert(packet->ip_bytes + temp_offset <= packet->buffer_bytes);
+						memmove((u8 *)item->chunk + item->length + temp_offset,
+							(u8 *)item->chunk + item->length,
+							packet_end(packet) - ((u8 *)item->chunk + item->length));
+						memcpy(item->chunk,
+						       socket->prepared_cookie_echo,
+						       socket->prepared_cookie_echo_length);
+						item->length = socket->prepared_cookie_echo_length;
+						packet->buffer_bytes += temp_offset;
+						packet->ip_bytes += temp_offset;
+						if (packet->ipv4) {
+							packet->ipv4->tot_len = htons(ntohs(packet->ipv4->tot_len) + temp_offset);
 						}
+						if (packet->ipv6) {
+							packet->ipv6->payload_len = htons(ntohs(packet->ipv6->payload_len) + temp_offset);
+						}
+						for (i = 0; i < PACKET_MAX_HEADERS; i++) {
+							if ((packet->ipv4 != NULL && packet->headers[i].h.ipv4 == packet->ipv4) ||
+							    (packet->ipv6 != NULL && packet->headers[i].h.ipv6 == packet->ipv6)) {
+								break;
+							}
+						}
+						assert(packet->headers[i + 1].type == HEADER_SCTP);
+						packet->headers[i].total_bytes += temp_offset;
+						packet->headers[i + 1].total_bytes += temp_offset;
+						offset += temp_offset;
 					}
-					assert(packet->headers[i + 1].type == HEADER_SCTP);
-					packet->headers[i].total_bytes += temp_offset;
-					packet->headers[i + 1].total_bytes += temp_offset;
-					offset += temp_offset;
-				}
-				if (((packet->flags & FLAGS_SCTP_BAD_CRC32C) == 0) &&
-				    (((packet->flags & FLAGS_SCTP_EXPLICIT_TAG) == 0) ||
-				     ((ntohl(packet->sctp->v_tag) == socket->script.local_initiate_tag) &&
-				      (socket->script.local_initiate_tag != 0)))) {
-					socket->state = SOCKET_PASSIVE_COOKIE_ECHO_RECEIVED;
-				}
-				break;
-			case SCTP_HEARTBEAT_ACK_CHUNK_TYPE:
-				if (item->flags & FLAG_CHUNK_VALUE_NOCHECK) {
-					temp_offset = socket->prepared_heartbeat_ack_length - item->length;
-					assert(packet->ip_bytes + temp_offset <= packet->buffer_bytes);
-					memmove((u8 *)item->chunk + item->length + temp_offset,
-						(u8 *)item->chunk + item->length,
-						packet_end(packet) - ((u8 *)item->chunk + item->length));
-					memcpy(item->chunk,
-					       socket->prepared_heartbeat_ack,
-					       socket->prepared_heartbeat_ack_length);
-					item->length = socket->prepared_heartbeat_ack_length;
-					packet->buffer_bytes += temp_offset;
-					packet->ip_bytes += temp_offset;
-					if (packet->ipv4) {
-						packet->ipv4->tot_len = htons(ntohs(packet->ipv4->tot_len) + temp_offset);
-					}
-					if (packet->ipv6) {
-						packet->ipv6->payload_len = htons(ntohs(packet->ipv6->payload_len) + temp_offset);
+					if (((packet->flags & FLAGS_SCTP_BAD_CRC32C) == 0) &&
+					    (((packet->flags & FLAGS_SCTP_EXPLICIT_TAG) == 0) ||
+					     ((ntohl(packet->sctp->v_tag) == socket->script.local_initiate_tag) &&
+					      (socket->script.local_initiate_tag != 0)))) {
+						socket->state = SOCKET_PASSIVE_COOKIE_ECHO_RECEIVED;
 					}
-					for (i = 0; i < PACKET_MAX_HEADERS; i++) {
-						if ((packet->ipv4 != NULL && packet->headers[i].h.ipv4 == packet->ipv4) ||
-						    (packet->ipv6 != NULL && packet->headers[i].h.ipv6 == packet->ipv6)) {
-							break;
+					break;
+				case SCTP_HEARTBEAT_ACK_CHUNK_TYPE:
+					if (item->flags & FLAG_CHUNK_VALUE_NOCHECK) {
+						temp_offset = socket->prepared_heartbeat_ack_length - item->length;
+						assert(packet->ip_bytes + temp_offset <= packet->buffer_bytes);
+						memmove((u8 *)item->chunk + item->length + temp_offset,
+							(u8 *)item->chunk + item->length,
+							packet_end(packet) - ((u8 *)item->chunk + item->length));
+						memcpy(item->chunk,
+						       socket->prepared_heartbeat_ack,
+						       socket->prepared_heartbeat_ack_length);
+						item->length = socket->prepared_heartbeat_ack_length;
+						packet->buffer_bytes += temp_offset;
+						packet->ip_bytes += temp_offset;
+						if (packet->ipv4) {
+							packet->ipv4->tot_len = htons(ntohs(packet->ipv4->tot_len) + temp_offset);
+						}
+						if (packet->ipv6) {
+							packet->ipv6->payload_len = htons(ntohs(packet->ipv6->payload_len) + temp_offset);
+						}
+						for (i = 0; i < PACKET_MAX_HEADERS; i++) {
+							if ((packet->ipv4 != NULL && packet->headers[i].h.ipv4 == packet->ipv4) ||
+							    (packet->ipv6 != NULL && packet->headers[i].h.ipv6 == packet->ipv6)) {
+								break;
+							}
 						}
+						assert(packet->headers[i + 1].type == HEADER_SCTP);
+						packet->headers[i].total_bytes += temp_offset;
+						packet->headers[i + 1].total_bytes += temp_offset;
+						offset += temp_offset;
 					}
-					assert(packet->headers[i + 1].type == HEADER_SCTP);
-					packet->headers[i].total_bytes += temp_offset;
-					packet->headers[i + 1].total_bytes += temp_offset;
-					offset += temp_offset;
+					break;
+				default:
+					item->chunk = (struct sctp_chunk *)((char *)item->chunk + offset);
+					break;
 				}
-				break;
-			default:
-				item->chunk = (struct sctp_chunk *)((char *)item->chunk + offset);
-				break;
 			}
 		}
 	}
diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c
index 5ddca4a72b388f1d5488bd6dd00a9e19e97d0f71..7c11497e881f6550805cce8eb55deb411d6a0796 100644
--- a/gtests/net/packetdrill/sctp_packet.c
+++ b/gtests/net/packetdrill/sctp_packet.c
@@ -1254,8 +1254,11 @@ void
 sctp_chunk_list_free(struct sctp_chunk_list *list)
 {
 	struct sctp_chunk_list_item *current_item, *next_item;
-
-	assert(list != NULL);
+	
+	if (list == NULL) {
+		return;
+	}
+	
 	current_item = list->first;
 	while (current_item != NULL) {
 		next_item = current_item->next;
@@ -2591,3 +2594,100 @@ new_sctp_packet(int address_family,
 	packet->ip_bytes = ip_bytes;
 	return packet;
 }
+
+#ifdef DEBUG_LOGGING
+static void print_sctp_byte_list(struct sctp_byte_list *list) {
+	struct sctp_byte_list_item *item;
+
+	for (item = list->first; item != NULL; item = item->next) {
+		DEBUGP("0x%.2x,", item->byte);
+	}
+}
+#endif
+
+struct packet *
+new_sctp_generic_packet(int address_family,
+                enum direction_t direction,
+                enum ip_ecn_t ecn,
+                s64 tag,
+                bool bad_crc32c,
+                struct sctp_byte_list *bytes,
+                char **error) {
+	struct packet *packet;  /* the newly-allocated result packet */
+	struct header *sctp_header;  /* the SCTP header info */
+	struct sctp_byte_list_item *item = NULL;
+	/* Calculate lengths in bytes of all sections of the packet */
+	const int ip_option_bytes = 0;
+	const int ip_header_bytes = (ip_header_min_len(address_family) +
+				     ip_option_bytes);
+	const int sctp_header_bytes = sizeof(struct sctp_common_header);
+	const int sctp_chunk_bytes = bytes->nr_entries;
+	const int ip_bytes =
+		 ip_header_bytes + sctp_header_bytes + sctp_chunk_bytes;
+	bool overbook = false;
+	u16 i;
+
+#ifdef DEBUG_LOGGING
+	print_sctp_byte_list(bytes);
+#endif
+
+	if (direction == DIRECTION_OUTBOUND) {
+		asprintf(error,
+			"generic packets can only be specified as inbound.");
+		return NULL;
+	}
+
+	/* Sanity-check all the various lengths */
+	if (ip_option_bytes & 0x3) {
+		asprintf(error, "IP options are not padded correctly "
+			 "to ensure IP header is a multiple of 4 bytes: "
+			 "%d excess bytes", ip_option_bytes & 0x3);
+		return NULL;
+	}
+	assert((ip_header_bytes & 0x3) == 0);
+
+	if (ip_bytes > MAX_SCTP_DATAGRAM_BYTES) {
+		asprintf(error, "SCTP packet too large");
+		return NULL;
+	}
+
+	/* Allocate and zero out a packet object of the desired size */
+	packet = packet_new(overbook ? MAX_SCTP_DATAGRAM_BYTES : ip_bytes);
+	memset(packet->buffer, 0, overbook ? MAX_SCTP_DATAGRAM_BYTES : ip_bytes);
+
+	packet->direction = direction;
+	packet->flags = FLAGS_SCTP_GENERIC_PACKET;
+	if (bad_crc32c) {
+		packet->flags |= FLAGS_SCTP_BAD_CRC32C;
+	}
+	if (tag != -1) {
+		packet->flags |= FLAGS_SCTP_EXPLICIT_TAG;
+	}
+	packet->ecn = ecn;
+
+	/* Set IP header fields */
+	set_packet_ip_header(packet, address_family, ip_bytes, ecn,
+			     IPPROTO_SCTP);
+
+	sctp_header = packet_append_header(packet, HEADER_SCTP, sctp_header_bytes);
+	sctp_header->total_bytes = sctp_header_bytes + sctp_chunk_bytes;
+
+	/* Find the start of the SCTP common header of the packet */
+	packet->sctp = (struct sctp_common_header *) (ip_start(packet) + ip_header_bytes);
+	u8 *sctp_chunk_start = (u8 *) (packet->sctp + 1);
+
+	/* Set SCTP header fields */
+	packet->sctp->src_port = htons(0);
+	packet->sctp->dst_port = htons(0);
+	packet->sctp->v_tag = htonl((u32)tag);
+	packet->sctp->crc32c = htonl(0);
+
+	for (i = 0, item = bytes->first; item != NULL; i++, item = item->next) {
+		sctp_chunk_start[i] = item->byte;
+	}
+
+	packet->chunk_list = NULL;
+	packet->ip_bytes = ip_bytes;
+
+	return packet;
+}
diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h
index b492ebc736cb5e504e079ac981e59d1f3b933639..4defa5042fb64632b925e127c982306a4deeda5d 100644
--- a/gtests/net/packetdrill/sctp_packet.h
+++ b/gtests/net/packetdrill/sctp_packet.h
@@ -430,4 +430,13 @@ extern struct packet *new_sctp_packet(int address_family,
 				      bool bad_crc32c,
 				      struct sctp_chunk_list *chunk_list,
 				      char **error);
+
+struct packet *
+new_sctp_generic_packet(int address_family,
+                enum direction_t direction,
+                enum ip_ecn_t ecn,
+                s64 tag,
+                bool bad_crc32c,
+                struct sctp_byte_list *bytes,
+                char **error);
 #endif /* __SCTP_PACKET_H__ */
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic.pkt
new file mode 100644
index 0000000000000000000000000000000000000000..eff794350f28d3071396f8473f62770d4e620990
--- /dev/null
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic.pkt
@@ -0,0 +1,20 @@
+// Create a non-blocking 1-to-1 style socket
+ 0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3
++0.0 bind(3, ..., ...) = 0
++0.0 fcntl(3, F_GETFL) = 0x02 (flags O_RDWR)
++0.0 fcntl(3, F_SETFL, O_RDWR | O_NONBLOCK) = 0
+// Trigger the active associtation setup
++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)
++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...]
+//+0.0 < sctp(t, tag=1): INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=1, STATE_COOKIE[len=4, val=...]]
++0.0 < sctp: [0x02, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x05, 0xDC, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x04]
++0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...]
+//+0.0 > sctp(tag=3): [0x0A, 0x00, 0x00, 0x04]
++0.0 < sctp: COOKIE_ACK[flgs=0]
+// Check if the setup was sucessful
++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
+// Tear down the association
++0.0 close(3) = 0
++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=0]
++0.1 < sctp: SHUTDOWN_ACK[flgs=0]
++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0]
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic_passive.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic_passive.pkt
new file mode 100644
index 0000000000000000000000000000000000000000..d296713a7f67c6903be0c3c273505ac394460421
--- /dev/null
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic_passive.pkt
@@ -0,0 +1,16 @@
++0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3
+// Check the handshake with en empty(!) cookie
++0.0 bind(3, ..., ...) = 0
++0.0 listen(3, 1) = 0
++0.0 < sctp: [0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0xDC, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01]
+//+0.0 < sctp: INIT[flgs=0, tag=1, a_rwnd=1500, os=1, is=1, tsn=1]
++0.0 > sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=..., os=..., is=..., tsn=1, ...]
++0.1 < sctp: COOKIE_ECHO[flgs=0, len=..., val=...]
++0.0 > sctp: COOKIE_ACK[flgs=0]
++0.0 accept(3, ..., ...) = 4
+// Tear down the association
++1.0 < sctp: SHUTDOWN[flgs=0, cum_tsn=0]
++0.0 > sctp: SHUTDOWN_ACK[flgs=0]
++0.0 < sctp: SHUTDOWN_COMPLETE[flgs=0]
++0.0 close(4) = 0
++0.0 close(3) = 0