diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index a43c2e669071cf25d4ef9f541476bea61087fc5b..4478ed2e8e8772fd2ca5606c8c4bbfd834d6da5d 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -203,6 +203,8 @@ noecn				return NO_ECN;
 ce				return CE;
 [.][.][.]			return ELLIPSIS;
 assoc_value			return ASSOC_VALUE;
+stream_id			return STREAM_ID;
+stream_value			return STREAM_VALUE;
 sack_delay			return SACK_DELAY;
 sack_freq			return SACK_FREQ;
 srto_initial			return SRTO_INITIAL;
@@ -248,6 +250,7 @@ COOKIE_ACK			return COOKIE_ACK;
 ECNE				return ECNE;
 CWR				return CWR;
 SHUTDOWN_COMPLETE		return SHUTDOWN_COMPLETE;
+I-DATA				return I_DATA;
 PAD				return PAD;
 type				return TYPE;
 flgs				return FLAGS;
@@ -259,7 +262,9 @@ os				return OS;
 tsn				return TSN;
 sid				return SID;
 ssn				return SSN;
+mid				return MID;
 ppid				return PPID;
+fsn				return FSN;
 cum_tsn				return CUM_TSN;
 gaps				return GAPS;
 dups				return DUPS;
@@ -273,6 +278,7 @@ COOKIE_PRESERVATIVE		return COOKIE_PRESERVATIVE;
 HOSTNAME_ADDRESS		return HOSTNAME_ADDRESS;
 SUPPORTED_ADDRESS_TYPES		return SUPPORTED_ADDRESS_TYPES;
 ECN_CAPABLE			return ECN_CAPABLE;
+SUPPORTED_EXTENSIONS		return SUPPORTED_EXTENSIONS;
 addr				return ADDR;
 incr				return INCR;
 types				return TYPES;
diff --git a/gtests/net/packetdrill/packet_to_string_test.c b/gtests/net/packetdrill/packet_to_string_test.c
index 899ef4b743168cce1d774174c076d44aa3cfac8c..8392b65e97c227b988068f43cd1f456225891da8 100644
--- a/gtests/net/packetdrill/packet_to_string_test.c
+++ b/gtests/net/packetdrill/packet_to_string_test.c
@@ -102,7 +102,7 @@ static void test_sctp_ipv6_packet_to_string(void)
 	/* An IPv6/SCTP packet. */
 	u8 data[] = {
 		/* IPv6 Base Header: */
-		0x60, 0x00, 0x00, 0x00, 0x01, 0xa0, 0x84, 0xff,
+		0x60, 0x00, 0x00, 0x00, 0x01, 0xd8, 0x84, 0xff,
 		0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22,
 		0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -110,7 +110,7 @@ static void test_sctp_ipv6_packet_to_string(void)
 		/* SCTP Common Header: */
 		0x04, 0xd2, 0x1f, 0x90,
 		0x01, 0x02, 0x03, 0x04,
-		0x6e, 0xfc, 0x47, 0x17,
+		0x24, 0x25, 0x51, 0x31,
 		/* SCTP DATA Chunk */
 		0x00, 0x0f, 0x00, 0x13,
 		0x01, 0x02, 0x03, 0x04,
@@ -118,7 +118,7 @@ static void test_sctp_ipv6_packet_to_string(void)
 		0x00, 0x00, 0x00, 0x00,
 		0x00, 0x01, 0x02, 0x00,
 		/* SCTP INIT Chunk */
-		0x01, 0x00, 0x00, 0x60,
+		0x01, 0x00, 0x00, 0x68,
 		0x00, 0x00, 0x00, 0x01,
 		0x00, 0x01, 0x00, 0x00,
 		0x00, 0x0f, 0x00, 0x0f,
@@ -138,6 +138,8 @@ static void test_sctp_ipv6_packet_to_string(void)
 		0x00, 0x05, 0x00, 0x06,
 		0x00, 0x0b, 0x00, 0x00,
 		0x80, 0x00, 0x00, 0x04,
+		0x80, 0x08, 0x00, 0x05,
+		0x40, 0x00, 0x00, 0x00,
 		0x80, 0x05, 0x00, 0x10,
 		0x50, 0x50, 0x50, 0x50,
 		0x50, 0x50, 0x50, 0x50,
@@ -224,6 +226,20 @@ static void test_sctp_ipv6_packet_to_string(void)
 		0x01, 0x02, 0x03, 0x04,
 		/* SCTP SHUTDOWN_COMPLETE Chunk */
 		0x0e, 0x01, 0x00, 0x04,
+		/* SCTP I-DATA Chunk */
+		0x40, 0x0f, 0x00, 0x17,
+		0x00, 0x00, 0x00, 0x04,
+		0x00, 0xff, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x01,
+		0x00, 0x00, 0x00, 0x00,
+		0x00, 0x01, 0x02, 0x00,
+		/* SCTP I-DATA Chunk */
+		0x40, 0x0d, 0x00, 0x17,
+		0x00, 0x00, 0x00, 0x04,
+		0x00, 0xff, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x02,
+		0x00, 0x00, 0x00, 0x01,
+		0x00, 0x01, 0x02, 0x00,
 		/* SCTP PAD Chunk */
 		0x84, 0x00, 0x00, 0x10,
 		0x50, 0x50, 0x50, 0x50,
@@ -259,6 +275,7 @@ static void test_sctp_ipv6_packet_to_string(void)
 		     "HOSTNAME_ADDRESS[addr=\"@A\"], "
 		     "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], "
 		     "ECN_CAPABLE[], "
+		     "SUPPORTED_EXTENSIONS[types=[I-DATA]], "
 		     "PAD[len=16, val=...]]; "
 		"INIT_ACK[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, "
 			 "STATE_COOKIE[len=7, val=...], "
@@ -294,6 +311,8 @@ static void test_sctp_ipv6_packet_to_string(void)
 		"ECNE[flgs=0x00, tsn=16909060]; "
 		"CWR[flgs=0x00, tsn=16909060]; "
 		"SHUTDOWN_COMPLETE[flgs=T]; "
+		"I-DATA[flgs=IUBE, len=23, tsn=4, sid=255, mid=1, ppid=0]; "
+		"I-DATA[flgs=IUE, len=23, tsn=4, sid=255, mid=2, fsn=1]; "
 		"PAD[flgs=0x00, len=16, val=...]";
 	assert(strcmp(dump, expected) == 0);
 	free(dump);
@@ -314,6 +333,7 @@ static void test_sctp_ipv6_packet_to_string(void)
 		     "HOSTNAME_ADDRESS[addr=\"@A\"], "
 		     "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], "
 		     "ECN_CAPABLE[], "
+		     "SUPPORTED_EXTENSIONS[types=[I-DATA]], "
 		     "PAD[len=16, val=...]]; "
 		"INIT_ACK[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, "
 			 "STATE_COOKIE[len=7, val=...], "
@@ -349,6 +369,8 @@ static void test_sctp_ipv6_packet_to_string(void)
 		"ECNE[flgs=0x00, tsn=16909060]; "
 		"CWR[flgs=0x00, tsn=16909060]; "
 		"SHUTDOWN_COMPLETE[flgs=T]; "
+		"I-DATA[flgs=IUBE, len=23, tsn=4, sid=255, mid=1, ppid=0]; "
+		"I-DATA[flgs=IUE, len=23, tsn=4, sid=255, mid=2, fsn=1]; "
 		"PAD[flgs=0x00, len=16, val=...]";
 	assert(strcmp(dump, expected) == 0);
 	free(dump);
@@ -369,6 +391,7 @@ static void test_sctp_ipv6_packet_to_string(void)
 		     "HOSTNAME_ADDRESS[addr=\"@A\"], "
 		     "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], "
 		     "ECN_CAPABLE[], "
+		     "SUPPORTED_EXTENSIONS[types=[I-DATA]], "
 		     "PAD[len=16, val=...]]; "
 		"INIT_ACK[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, "
 			 "STATE_COOKIE[len=7, val=...], "
@@ -404,37 +427,42 @@ static void test_sctp_ipv6_packet_to_string(void)
 		"ECNE[flgs=0x00, tsn=16909060]; "
 		"CWR[flgs=0x00, tsn=16909060]; "
 		"SHUTDOWN_COMPLETE[flgs=T]; "
+		"I-DATA[flgs=IUBE, len=23, tsn=4, sid=255, mid=1, ppid=0]; "
+		"I-DATA[flgs=IUE, len=23, tsn=4, sid=255, mid=2, fsn=1]; "
 		"PAD[flgs=0x00, len=16, val=...]"
 		"\n"
-		"0x0000: 60 00 00 00 01 a0 84 ff 00 02 00 00 00 00 00 00 " "\n"
+		"0x0000: 60 00 00 00 01 d8 84 ff 00 02 00 00 00 00 00 00 " "\n"
 		"0x0010: 00 00 00 00 00 00 22 22 00 01 00 00 00 00 00 00 " "\n"
 		"0x0020: 00 00 00 00 00 00 11 11 04 d2 1f 90 01 02 03 04 " "\n"
-		"0x0030: 6e fc 47 17 00 0f 00 13 01 02 03 04 00 ff 01 00 " "\n"
-		"0x0040: 00 00 00 00 00 01 02 00 01 00 00 60 00 00 00 01 " "\n"
+		"0x0030: 24 25 51 31 00 0f 00 13 01 02 03 04 00 ff 01 00 " "\n"
+		"0x0040: 00 00 00 00 00 01 02 00 01 00 00 68 00 00 00 01 " "\n"
 		"0x0050: 00 01 00 00 00 0f 00 0f 01 02 03 04 00 05 00 08 " "\n"
 		"0x0060: 01 02 03 04 00 06 00 14 00 00 00 00 00 00 00 00 " "\n"
 		"0x0070: 00 00 00 00 00 00 00 01 00 09 00 08 00 01 00 00 " "\n"
 		"0x0080: 00 0b 00 06 40 41 00 00 00 0c 00 0a 00 05 00 06 " "\n"
-		"0x0090: 00 0b 00 00 80 00 00 04 80 05 00 10 50 50 50 50 " "\n"
-		"0x00a0: 50 50 50 50 50 50 50 50 02 00 00 24 00 00 00 01 " "\n"
-		"0x00b0: 00 01 00 00 00 0f 00 0f 01 02 03 04 00 07 00 07 " "\n"
-		"0x00c0: 01 02 03 00 00 08 00 08 80 01 00 04 03 00 00 20 " "\n"
-		"0x00d0: 01 02 03 04 00 01 00 00 00 03 00 01 00 01 00 03 " "\n"
-		"0x00e0: 00 05 00 0f 10 00 10 14 01 02 03 04 04 00 00 0a " "\n"
-		"0x00f0: 00 01 00 06 01 02 00 00 05 00 00 0a 00 01 00 06 " "\n"
-		"0x0100: 01 02 00 00 06 01 00 04 06 00 00 80 00 01 00 08 " "\n"
-		"0x0110: 00 ff 00 00 00 02 00 0a 00 00 00 01 00 07 00 00 " "\n"
-		"0x0120: 00 03 00 08 00 01 00 00 00 04 00 04 00 05 00 0c " "\n"
-		"0x0130: 00 0b 00 06 40 41 00 00 00 06 00 0c fe 05 00 05 " "\n"
-		"0x0140: 01 00 00 00 00 07 00 04 00 08 00 10 80 0a 00 04 " "\n"
-		"0x0150: 80 0b 00 05 01 00 00 00 00 09 00 08 01 02 03 04 " "\n"
-		"0x0160: 00 0a 00 04 00 0b 00 14 00 05 00 08 01 02 03 04 " "\n"
-		"0x0170: 00 05 00 08 02 03 04 05 00 0c 00 07 42 59 45 00 " "\n"
-		"0x0180: 00 0d 00 06 40 40 00 00 07 00 00 08 01 02 03 04 " "\n"
-		"0x0190: 08 00 00 04 09 00 00 04 0a 00 00 05 45 00 00 00 " "\n"
-		"0x01a0: 0b 00 00 04 0c 00 00 08 01 02 03 04 0d 00 00 08 " "\n"
-		"0x01b0: 01 02 03 04 0e 01 00 04 84 00 00 10 50 50 50 50 " "\n"
-		"0x01c0: 50 50 50 50 50 50 50 50 " "\n";
+		"0x0090: 00 0b 00 00 80 00 00 04 80 08 00 05 40 00 00 00 " "\n"
+		"0x00a0: 80 05 00 10 50 50 50 50 50 50 50 50 50 50 50 50 " "\n"
+		"0x00b0: 02 00 00 24 00 00 00 01 00 01 00 00 00 0f 00 0f " "\n"
+		"0x00c0: 01 02 03 04 00 07 00 07 01 02 03 00 00 08 00 08 " "\n"
+		"0x00d0: 80 01 00 04 03 00 00 20 01 02 03 04 00 01 00 00 " "\n"
+		"0x00e0: 00 03 00 01 00 01 00 03 00 05 00 0f 10 00 10 14 " "\n"
+		"0x00f0: 01 02 03 04 04 00 00 0a 00 01 00 06 01 02 00 00 " "\n"
+		"0x0100: 05 00 00 0a 00 01 00 06 01 02 00 00 06 01 00 04 " "\n"
+		"0x0110: 06 00 00 80 00 01 00 08 00 ff 00 00 00 02 00 0a " "\n"
+		"0x0120: 00 00 00 01 00 07 00 00 00 03 00 08 00 01 00 00 " "\n"
+		"0x0130: 00 04 00 04 00 05 00 0c 00 0b 00 06 40 41 00 00 " "\n"
+		"0x0140: 00 06 00 0c fe 05 00 05 01 00 00 00 00 07 00 04 " "\n"
+		"0x0150: 00 08 00 10 80 0a 00 04 80 0b 00 05 01 00 00 00 " "\n"
+		"0x0160: 00 09 00 08 01 02 03 04 00 0a 00 04 00 0b 00 14 " "\n"
+		"0x0170: 00 05 00 08 01 02 03 04 00 05 00 08 02 03 04 05 " "\n"
+		"0x0180: 00 0c 00 07 42 59 45 00 00 0d 00 06 40 40 00 00 " "\n"
+		"0x0190: 07 00 00 08 01 02 03 04 08 00 00 04 09 00 00 04 " "\n"
+		"0x01a0: 0a 00 00 05 45 00 00 00 0b 00 00 04 0c 00 00 08 " "\n"
+		"0x01b0: 01 02 03 04 0d 00 00 08 01 02 03 04 0e 01 00 04 " "\n"
+		"0x01c0: 40 0f 00 17 00 00 00 04 00 ff 00 00 00 00 00 01 " "\n"
+		"0x01d0: 00 00 00 00 00 01 02 00 40 0d 00 17 00 00 00 04 " "\n"
+		"0x01e0: 00 ff 00 00 00 00 00 02 00 00 00 01 00 01 02 00 " "\n"
+		"0x01f0: 84 00 00 10 50 50 50 50 50 50 50 50 50 50 50 50 " "\n";
 	printf("expected = '%s'\n", expected);
 	assert(strcmp(dump, expected) == 0);
 	free(dump);
diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index 736897851f194bf16791c42db5f9efa678fd7c77..298dca63c6f9728a5bd2aa6edf5223ccd907760b 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -506,6 +506,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %token <reserved> SINIT_NUM_OSTREAMS SINIT_MAX_INSTREAMS SINIT_MAX_ATTEMPTS
 %token <reserved> SINIT_MAX_INIT_TIMEO
 %token <reserved> ASSOC_VALUE
+%token <reserved> STREAM_ID STREAM_VALUE
 %token <reserved> SACK_DELAY SACK_FREQ
 %token <reserved> SSTAT_STATE SSTAT_RWND SSTAT_UNACKDATA SSTAT_PENDDATA
 %token <reserved> SSTAT_INSTRMS SSTAT_OUTSTRMS SSTAT_FRAGMENTATION_POINT
@@ -513,12 +514,13 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %token <reserved> SPINFO_STATE SPINFO_CWND SPINFO_SRTT SPINFO_RTO SPINFO_MTU
 %token <reserved> CHUNK DATA INIT INIT_ACK HEARTBEAT HEARTBEAT_ACK ABORT
 %token <reserved> SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECNE CWR
-%token <reserved> SHUTDOWN_COMPLETE PAD
+%token <reserved> SHUTDOWN_COMPLETE I_DATA PAD
 %token <reserved> TYPE FLAGS LEN
-%token <reserved> TAG A_RWND OS IS TSN SID SSN PPID CUM_TSN GAPS DUPS
+%token <reserved> TAG A_RWND OS IS TSN SID SSN MID PPID FSN CUM_TSN GAPS DUPS
 %token <reserved> PARAMETER HEARTBEAT_INFORMATION IPV4_ADDRESS IPV6_ADDRESS
 %token <reserved> STATE_COOKIE UNRECOGNIZED_PARAMETER COOKIE_PRESERVATIVE
 %token <reserved> HOSTNAME_ADDRESS SUPPORTED_ADDRESS_TYPES ECN_CAPABLE
+%token <reserved> SUPPORTED_EXTENSIONS
 %token <reserved> ADDR INCR TYPES PARAMS
 %token <reserved> IPV4_TYPE IPV6_TYPE HOSTNAME_TYPE
 %token <reserved> CAUSE
@@ -571,7 +573,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <expression> linger l_onoff l_linger
 %type <expression> sctp_status sstat_state sstat_rwnd sstat_unackdata sstat_penddata
 %type <expression> sstat_instrms sstat_outstrms sstat_fragmentation_point sstat_primary
-%type <expression> sctp_initmsg sctp_assocval sctp_sackinfo
+%type <expression> sctp_initmsg sctp_assoc_value sctp_stream_value sctp_sackinfo
 %type <expression> sctp_rtoinfo srto_initial srto_max srto_min sctp_paddrinfo
 %type <expression> sctp_paddrparams spp_address spp_hbinterval spp_pathmtu spp_pathmaxrxt
 %type <expression> spp_flags spp_ipv6_flowlabel spp_dscp
@@ -591,6 +593,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <chunk_list_item> sctp_cookie_echo_chunk_spec sctp_cookie_ack_chunk_spec
 %type <chunk_list_item> sctp_ecne_chunk_spec sctp_cwr_chunk_spec
 %type <chunk_list_item> sctp_shutdown_complete_chunk_spec
+%type <chunk_list_item> sctp_i_data_chunk_spec
 %type <chunk_list_item> sctp_pad_chunk_spec
 %type <parameter_list> opt_parameter_list_spec sctp_parameter_list_spec
 %type <parameter_list_item> sctp_parameter_spec
@@ -604,6 +607,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <parameter_list_item> sctp_hostname_address_parameter_spec
 %type <parameter_list_item> sctp_supported_address_types_parameter_spec
 %type <parameter_list_item> sctp_ecn_capable_parameter_spec
+%type <parameter_list_item> sctp_supported_extensions_parameter_spec
 %type <parameter_list_item> sctp_pad_parameter_spec
 %type <cause_list> opt_cause_list_spec sctp_cause_list_spec
 %type <cause_list_item> sctp_cause_spec
@@ -621,12 +625,13 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <cause_list_item> sctp_restart_with_new_addresses_cause_spec
 %type <cause_list_item> sctp_user_initiated_abort_cause_spec
 %type <cause_list_item> sctp_protocol_violation_cause_spec
-%type <integer> opt_chunk_type opt_parameter_type opt_cause_code
+%type <integer> chunk_type opt_chunk_type opt_parameter_type opt_cause_code
 %type <integer> opt_flags opt_data_flags opt_abort_flags
-%type <integer> opt_shutdown_complete_flags opt_len
+%type <integer> opt_shutdown_complete_flags opt_i_data_flags opt_len
 %type <integer> opt_tag opt_a_rwnd opt_os opt_is opt_tsn opt_sid opt_ssn
+%type <integer> opt_mid opt_fsn
 %type <integer> opt_cum_tsn opt_ppid
-%type <byte_list> opt_val opt_info byte_list
+%type <byte_list> opt_val opt_info byte_list chunk_types_list
 %type <byte_list_item> byte
 %type <sack_block_list> opt_gaps gap_list opt_dups dup_list
 %type <sack_block_list_item> gap dup
@@ -841,21 +846,79 @@ sctp_chunk_spec
 | sctp_ecne_chunk_spec              { $$ = $1; }
 | sctp_cwr_chunk_spec               { $$ = $1; }
 | sctp_shutdown_complete_chunk_spec { $$ = $1; }
+| sctp_i_data_chunk_spec            { $$ = $1; }
 | sctp_pad_chunk_spec               { $$ = $1; }
 ;
 
-opt_chunk_type
-: TYPE '=' ELLIPSIS    { $$ = -1; }
-| TYPE '=' HEX_INTEGER {
-	if (!is_valid_u8($3)) {
+chunk_type
+: HEX_INTEGER {
+	if (!is_valid_u8($1)) {
 		semantic_error("type value out of range");
-        }
-	$$ = $3;
+	}
+	$$ = $1;
 }
-| TYPE '=' INTEGER     {
-	if (!is_valid_u8($3)) {
+| INTEGER {
+	if (!is_valid_u8($1)) {
 		semantic_error("type value out of range");
-        }
+	}
+	$$ = $1;
+}
+| DATA {
+	$$ = SCTP_DATA_CHUNK_TYPE;
+}
+| INIT {
+	$$ = SCTP_INIT_CHUNK_TYPE;
+}
+| INIT_ACK {
+	$$ = SCTP_INIT_ACK_CHUNK_TYPE;
+}
+| SACK {
+	$$ = SCTP_SACK_CHUNK_TYPE;
+}
+| HEARTBEAT {
+	$$ = SCTP_HEARTBEAT_CHUNK_TYPE;
+}
+| HEARTBEAT_ACK {
+	$$ = SCTP_HEARTBEAT_ACK_CHUNK_TYPE;
+}
+| ABORT {
+	$$ = SCTP_ABORT_CHUNK_TYPE;
+}
+| SHUTDOWN {
+	$$ = SCTP_SHUTDOWN_CHUNK_TYPE;
+}
+| SHUTDOWN_ACK {
+	$$ = SCTP_SHUTDOWN_ACK_CHUNK_TYPE;
+}
+| ERROR {
+	$$ = SCTP_ERROR_CHUNK_TYPE;
+}
+| COOKIE_ECHO {
+	$$ = SCTP_COOKIE_ECHO_CHUNK_TYPE;
+}
+| COOKIE_ACK {
+	$$ = SCTP_COOKIE_ACK_CHUNK_TYPE;
+}
+| ECNE {
+	$$ = SCTP_ECNE_CHUNK_TYPE;
+}
+| CWR {
+	$$ = SCTP_CWR_CHUNK_TYPE;
+}
+| SHUTDOWN_COMPLETE{
+	$$ = SCTP_SHUTDOWN_COMPLETE_CHUNK_TYPE;
+}
+| I_DATA {
+	$$ = SCTP_I_DATA_CHUNK_TYPE;
+}
+| PAD {
+	$$ = SCTP_PAD_CHUNK_TYPE;
+}
+;
+
+opt_chunk_type
+: TYPE '=' ELLIPSIS    { $$ = -1; }
+| TYPE '=' chunk_type {
 	$$ = $3;
 }
 ;
@@ -865,13 +928,13 @@ opt_flags
 | FLAGS '=' HEX_INTEGER {
 	if (!is_valid_u8($3)) {
 		semantic_error("flags value out of range");
-        }
+	}
 	$$ = $3;
 }
 | FLAGS '=' INTEGER     {
 	if (!is_valid_u8($3)) {
 		semantic_error("flags value out of range");
-        }
+	}
 	$$ = $3;
 }
 ;
@@ -932,7 +995,7 @@ opt_data_flags
 | FLAGS '=' INTEGER     {
 	if (!is_valid_u8($3)) {
 		semantic_error("flags value out of range");
-        }
+	}
 	$$ = $3;
 }
 | FLAGS '=' WORD        {
@@ -990,7 +1053,7 @@ opt_abort_flags
 | FLAGS '=' INTEGER     {
 	if (!is_valid_u8($3)) {
 		semantic_error("flags value out of range");
-        }
+	}
 	$$ = $3;
 }
 | FLAGS '=' WORD        {
@@ -1053,6 +1116,64 @@ opt_shutdown_complete_flags
 }
 ;
 
+opt_i_data_flags
+: FLAGS '=' ELLIPSIS    { $$ = -1; }
+| FLAGS '=' HEX_INTEGER {
+	if (!is_valid_u8($3)) {
+		semantic_error("flags value out of range");
+	}
+	$$ = $3;
+}
+| FLAGS '=' INTEGER     {
+	if (!is_valid_u8($3)) {
+		semantic_error("flags value out of range");
+	}
+	$$ = $3;
+}
+| FLAGS '=' WORD        {
+	u64 flags;
+	char *c;
+
+	flags = 0;
+	for (c = $3; *c != '\0'; c++) {
+		switch (*c) {
+		case 'I':
+			if (flags & SCTP_I_DATA_CHUNK_I_BIT) {
+				semantic_error("I-bit specified multiple times");
+			} else {
+				flags |= SCTP_I_DATA_CHUNK_I_BIT;
+			}
+			break;
+		case 'U':
+			if (flags & SCTP_I_DATA_CHUNK_U_BIT) {
+				semantic_error("U-bit specified multiple times");
+			} else {
+				flags |= SCTP_I_DATA_CHUNK_U_BIT;
+			}
+			break;
+		case 'B':
+			if (flags & SCTP_I_DATA_CHUNK_B_BIT) {
+				semantic_error("B-bit specified multiple times");
+			} else {
+				flags |= SCTP_I_DATA_CHUNK_B_BIT;
+			}
+			break;
+		case 'E':
+			if (flags & SCTP_I_DATA_CHUNK_E_BIT) {
+				semantic_error("E-bit specified multiple times");
+			} else {
+				flags |= SCTP_I_DATA_CHUNK_E_BIT;
+			}
+			break;
+		default:
+			semantic_error("Only expecting IUBE as flags");
+			break;
+		}
+	}
+	$$ = flags;
+}
+;
+
 opt_tag
 : TAG '=' ELLIPSIS { $$ = -1; }
 | TAG '=' INTEGER  {
@@ -1123,6 +1244,16 @@ opt_ssn
 }
 ;
 
+opt_mid
+: MID '=' ELLIPSIS { $$ = -1; }
+| MID '=' INTEGER  {
+	if (!is_valid_u32($3)) {
+		semantic_error("mid value out of range");
+	}
+	$$ = $3;
+}
+;
+
 opt_ppid
 : PPID '=' ELLIPSIS { $$ = -1; }
 | PPID '=' INTEGER  {
@@ -1133,6 +1264,16 @@ opt_ppid
 }
 ;
 
+opt_fsn
+: FSN '=' ELLIPSIS { $$ = -1; }
+| FSN '=' INTEGER  {
+	if (!is_valid_u32($3)) {
+		semantic_error("fsn value out of range");
+	}
+	$$ = $3;
+}
+;
+
 opt_cum_tsn
 : CUM_TSN '=' ELLIPSIS { $$ = -1; }
 | CUM_TSN '=' INTEGER  {
@@ -1268,7 +1409,7 @@ sctp_cookie_echo_chunk_spec
 	    (!is_valid_u16($5) || ($5 < sizeof(struct sctp_cookie_echo_chunk)))) {
 		semantic_error("length value out of range");
 	}
-        if (($5 != -1) && ($7 != NULL) &&
+	if (($5 != -1) && ($7 != NULL) &&
 	    ($5 != sizeof(struct sctp_cookie_echo_chunk) + $7->nr_entries)) {
 		semantic_error("length value incompatible with val");
 	}
@@ -1298,6 +1439,22 @@ sctp_shutdown_complete_chunk_spec
 	$$ = sctp_shutdown_complete_chunk_new($3);
 }
 
+sctp_i_data_chunk_spec
+: I_DATA '[' opt_i_data_flags ',' opt_len ',' opt_tsn ',' opt_sid ',' opt_mid ',' opt_ppid ']' {
+	if (($5 != -1) &&
+	    (!is_valid_u16($5) || ($5 < sizeof(struct sctp_i_data_chunk)))) {
+		semantic_error("length value out of range");
+	}
+	$$ = sctp_i_data_chunk_new($3, $5, $7, $9, 0, $11, $13, -1);
+}
+| I_DATA '[' opt_i_data_flags ',' opt_len ',' opt_tsn ',' opt_sid ',' opt_mid ',' opt_fsn ']' {
+	if (($5 != -1) &&
+	    (!is_valid_u16($5) || ($5 < sizeof(struct sctp_i_data_chunk)))) {
+		semantic_error("length value out of range");
+	}
+	$$ = sctp_i_data_chunk_new($3, $5, $7, $9, 0, $11, -1, $13);
+}
+
 sctp_pad_chunk_spec
 : PAD '[' opt_flags ',' opt_len ',' VAL '=' ELLIPSIS ']' {
 	if (($5 != -1) &&
@@ -1331,6 +1488,7 @@ sctp_parameter_spec
 | sctp_hostname_address_parameter_spec        { $$ = $1; }
 | sctp_supported_address_types_parameter_spec { $$ = $1; }
 | sctp_ecn_capable_parameter_spec             { $$ = $1; }
+| sctp_supported_extensions_parameter_spec    { $$ = $1; }
 | sctp_pad_parameter_spec                     { $$ = $1; }
 ;
 
@@ -1485,6 +1643,28 @@ sctp_ecn_capable_parameter_spec
 	$$ = sctp_ecn_capable_parameter_new();
 }
 
+chunk_types_list
+: {
+	$$ = sctp_byte_list_new();
+}
+| chunk_type {
+	$$ = sctp_byte_list_new();
+	sctp_byte_list_append($$, sctp_byte_list_item_new($1));
+}
+| chunk_types_list ',' chunk_type {
+	$$ = $1;
+	sctp_byte_list_append($1, sctp_byte_list_item_new($3));
+}
+;
+
+sctp_supported_extensions_parameter_spec
+: SUPPORTED_EXTENSIONS '[' TYPES '=' ELLIPSIS ']' {
+	$$ = sctp_supported_extensions_parameter_new(NULL);
+}
+| SUPPORTED_EXTENSIONS '[' TYPES '=' '[' chunk_types_list ']' ']' {
+	$$ = sctp_supported_extensions_parameter_new($6);
+}
+
 sctp_pad_parameter_spec
 : PAD '[' ELLIPSIS ']' {
 	$$ = sctp_pad_parameter_new(-1, NULL);
@@ -2162,7 +2342,10 @@ expression
 | sctp_initmsg      {
 	$$ = $1;
 }
-| sctp_assocval     {
+| sctp_assoc_value  {
+	$$ = $1;
+}
+| sctp_stream_value  {
 	$$ = $1;
 }
 | sctp_sackinfo     {
@@ -2394,14 +2577,25 @@ sctp_initmsg
 }
 ;
 
-sctp_assocval
-: '{' ASSOC_VALUE '=' INTEGER '}' {
-#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
-	$$ = new_expression(EXPR_SCTP_ASSOCVAL);
-	if (!is_valid_u32($4)) {
-		semantic_error("assoc_value out of range");
-	}
-	$$->value.sctp_assoc_value.assoc_value = $4;
+sctp_stream_value
+: '{' STREAM_ID '=' expression ',' STREAM_VALUE '=' expression '}' {
+#if defined(SCTP_SS_VALUE)
+	$$ = new_expression(EXPR_SCTP_STREAM_VALUE);
+	$$->value.sctp_stream_value = calloc(1, sizeof(struct sctp_stream_value_expr));
+	$$->value.sctp_stream_value->stream_id = $4;
+	$$->value.sctp_stream_value->stream_value = $8;
+#else
+	$$ = NULL;
+#endif
+}
+;
+
+sctp_assoc_value
+: '{' ASSOC_VALUE '=' expression '}' {
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+	$$ = new_expression(EXPR_SCTP_ASSOC_VALUE);
+	$$->value.sctp_assoc_value = calloc(1, sizeof(struct sctp_assoc_value_expr));
+	$$->value.sctp_assoc_value->assoc_value = $4;
 #else
 	$$ = NULL;
 #endif
diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c
index 2aa404f1ba57176b3606b61877713f125fcd1b43..ffa0d8278ebadbd5050ee852305ef454b9a01a5c 100644
--- a/gtests/net/packetdrill/run_packet.c
+++ b/gtests/net/packetdrill/run_packet.c
@@ -581,6 +581,7 @@ static int map_inbound_sctp_packet(
 	struct sctp_shutdown_chunk *shutdown;
 	struct sctp_ecne_chunk *ecne;
 	struct sctp_cwr_chunk *cwr;
+	struct sctp_i_data_chunk *i_data;
 	u32 local_diff, remote_diff;
 	u16 nr_gap_blocks, nr_dup_tsns, i;
 
@@ -642,6 +643,10 @@ static int map_inbound_sctp_packet(
 			cwr = (struct sctp_cwr_chunk *)chunk;
 			cwr->lowest_tsn = htonl(ntohl(cwr->lowest_tsn) + local_diff);
 			break;
+		case SCTP_I_DATA_CHUNK_TYPE:
+			i_data = (struct sctp_i_data_chunk *)chunk;
+			i_data->tsn = htonl(ntohl(i_data->tsn) + remote_diff);
+			break;
 		default:
 			break;
 		}
@@ -734,6 +739,7 @@ static int map_outbound_live_sctp_packet(
 	struct sctp_shutdown_chunk *shutdown;
 	struct sctp_ecne_chunk *ecne;
 	struct sctp_cwr_chunk *cwr;
+	struct sctp_i_data_chunk *i_data;
 	u32 local_diff, remote_diff;
 	u16 nr_gap_blocks, nr_dup_tsns, i;
 
@@ -790,6 +796,10 @@ static int map_outbound_live_sctp_packet(
 			cwr = (struct sctp_cwr_chunk *)chunk;
 			cwr->lowest_tsn = htonl(ntohl(cwr->lowest_tsn) + remote_diff);
 			break;
+		case SCTP_I_DATA_CHUNK_TYPE:
+			i_data = (struct sctp_i_data_chunk *)chunk;
+			i_data->tsn = htonl(ntohl(i_data->tsn) + local_diff);
+			break;
 		default:
 			break;
 		}
@@ -1522,6 +1532,44 @@ static int verify_shutdown_complete_chunk(struct sctp_shutdown_complete_chunk *a
 	return STATUS_OK;
 }
 
+static int verify_i_data_chunk(struct sctp_i_data_chunk *actual_chunk,
+                               struct sctp_i_data_chunk *script_chunk,
+                               u32 flags, char **error)
+{
+	if (check_field("sctp_i_data_chunk_tsn",
+		        ntohl(script_chunk->tsn),
+		        ntohl(actual_chunk->tsn),
+		        error) ||
+	    (flags & FLAG_I_DATA_CHUNK_SID_NOCHECK ? STATUS_OK :
+	        check_field("sctp_i_data_chunk_sid",
+		            ntohs(script_chunk->sid),
+		            ntohs(actual_chunk->sid),
+		            error)) ||
+	    (flags & FLAG_I_DATA_CHUNK_RES_NOCHECK ? STATUS_OK :
+	        check_field("sctp_i_data_chunk_res",
+		            ntohs(script_chunk->res),
+		            ntohs(actual_chunk->res),
+		            error)) ||
+	    (flags & FLAG_I_DATA_CHUNK_MID_NOCHECK? STATUS_OK :
+		check_field("sctp_i_data_chunk_mid",
+		            ntohl(script_chunk->mid),
+		            ntohl(actual_chunk->mid),
+		            error)) ||
+	    (flags & FLAG_I_DATA_CHUNK_PPID_NOCHECK? STATUS_OK :
+		check_field("sctp_i_data_chunk_ppid",
+		            ntohl(script_chunk->field.ppid),
+		            ntohl(actual_chunk->field.ppid),
+		            error)) ||
+	    (flags & FLAG_I_DATA_CHUNK_FSN_NOCHECK? STATUS_OK :
+		check_field("sctp_i_data_chunk_fsn",
+		            ntohl(script_chunk->field.fsn),
+		            ntohl(actual_chunk->field.fsn),
+		            error))) {
+		return STATUS_ERR;
+	}
+	return STATUS_OK;
+}
+
 static int verify_pad_chunk(struct sctp_pad_chunk *actual_chunk,
                             struct sctp_pad_chunk *script_chunk,
                             u32 flags, char **error)
@@ -1660,6 +1708,11 @@ static int verify_sctp(
 			                                        (struct sctp_shutdown_complete_chunk *)script_chunk,
 			                                        flags, error);
 			break;
+		case SCTP_I_DATA_CHUNK_TYPE:
+			result = verify_i_data_chunk((struct sctp_i_data_chunk *)actual_chunk,
+			                             (struct sctp_i_data_chunk *)script_chunk,
+			                             flags, error);
+			break;
 		case SCTP_PAD_CHUNK_TYPE:
 			result = verify_pad_chunk((struct sctp_pad_chunk *)actual_chunk,
 			                          (struct sctp_pad_chunk *)script_chunk,
diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index 72ea542661e460baec74c4c5a3819c1fc3b49852..065617b4748edcee0bc0b218e9dff4818078e940 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -180,6 +180,46 @@ static int check_type(struct expression *expression,
 	}
 }
 
+/* Sets the value from the expression argument, checking that it is a
+ * valid u16, and matches the expected type. Returns STATUS_OK on
+ * success; on failure returns STATUS_ERR and sets error message.
+ */
+static int get_u16(struct expression *expression,
+		   u16 *value, char **error)
+{
+	if (check_type(expression, EXPR_INTEGER, error))
+		return STATUS_ERR;
+	if ((expression->value.num > UINT16_MAX) ||
+	    (expression->value.num < 0)) {
+		asprintf(error,
+			 "Value out of range for 16-bit unsigned integer: %lld",
+			 expression->value.num);
+		return STATUS_ERR;
+	}
+	*value = expression->value.num;
+	return STATUS_OK;
+}
+
+/* Sets the value from the expression argument, checking that it is a
+ * valid u32, and matches the expected type. Returns STATUS_OK on
+ * success; on failure returns STATUS_ERR and sets error message.
+ */
+static int get_u32(struct expression *expression,
+		   u32 *value, char **error)
+{
+	if (check_type(expression, EXPR_INTEGER, error))
+		return STATUS_ERR;
+	if ((expression->value.num > UINT32_MAX) ||
+	    (expression->value.num < 0)) {
+		asprintf(error,
+			 "Value out of range for 32-bit unsigned integer: %lld",
+			 expression->value.num);
+		return STATUS_ERR;
+	}
+	*value = expression->value.num;
+	return STATUS_OK;
+}
+
 /* Sets the value from the expression argument, checking that it is a
  * valid s32 or u32, and matches the expected type. Returns STATUS_OK on
  * success; on failure returns STATUS_ERR and sets error message.
@@ -1618,6 +1658,7 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 	void *live_optval;
 	socklen_t live_optlen;
 	struct expression *val_expression;
+
 	if (check_arg_count(args, 5, error))
 		return STATUS_ERR;
 	if (s32_arg(args, 0, &script_fd, error))
@@ -1673,6 +1714,24 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 		}
 		live_params->spp_assoc_id = 0;
 		live_optval = live_params;
+#endif
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+	} else if (val_expression->type == EXPR_SCTP_ASSOC_VALUE) {
+		live_optval = malloc(sizeof(struct sctp_assoc_value));
+		live_optlen = (socklen_t)sizeof(struct sctp_assoc_value);
+		((struct sctp_assoc_value *) live_optval)->assoc_id = 0;
+#endif
+#ifdef SCTP_SS_VALUE
+	} else if (val_expression->type == EXPR_SCTP_STREAM_VALUE) {
+		live_optval = malloc(sizeof(struct sctp_stream_value));
+		live_optlen = (socklen_t)sizeof(struct sctp_stream_value);
+		((struct sctp_stream_value *) live_optval)->assoc_id = 0;
+		if (get_u16(val_expression->value.sctp_stream_value->stream_id,
+		            &((struct sctp_stream_value *) live_optval)->stream_id,
+		            error)) {
+			free(live_optval);
+			return STATUS_ERR;
+		}
 #endif
 	} else {
 		s32_bracketed_arg(args, 3, &script_optval, error);
@@ -1698,6 +1757,7 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 		struct expression *l_linger = val_expression->value.linger->l_linger;
 		struct linger *ling = live_optval;
 		int val_onoff = 0;
+
 		if (l_onoff->type != EXPR_ELLIPSIS) {
 			if (get_s32(l_onoff, &val_onoff, error)) {
 				free(live_optval);
@@ -1830,7 +1890,7 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 		if (sstat_instrms->type != EXPR_ELLIPSIS) {
 			if (get_s16(sstat_instrms, &instrms, error)) {
 				free(live_optval);
-				return STATUS_ERR;	
+				return STATUS_ERR;
 			}
 			if (live_status->sstat_instrms != instrms) {
 				asprintf(error, "Bad getsockopt SCTP_STATUS instreams: expected: %hu actual: %hu",
@@ -1888,7 +1948,7 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 					asprintf(error, "Bad getsockopt SCTP_STATUS Primary cwnd: expected: %u actual: %u",
 						cwnd, live_paddrinfo.spinfo_cwnd);
 					free(live_optval);
-					return STATUS_ERR;				
+					return STATUS_ERR;
 				}
 			}
 			if (paddrinfo_expr->spinfo_srtt->type != EXPR_ELLIPSIS) {
@@ -1924,7 +1984,7 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 					asprintf(error, "Bad getsockopt SCTP_STATUS Primary mtu: expected: %u actual: %u",
 						mtu, live_paddrinfo.spinfo_mtu);
 					free(live_optval);
-					return STATUS_ERR;					
+					return STATUS_ERR;
 				}
 			}
 		}
@@ -2017,6 +2077,57 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 			}
 		}
 #endif
+#endif
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+	} else if (val_expression->type == EXPR_SCTP_ASSOC_VALUE) {
+		struct expression *assoc_value = val_expression->value.sctp_assoc_value->assoc_value;
+		struct sctp_assoc_value *sctp_assoc_value = live_optval;
+		u32 value;
+
+		if (assoc_value->type != EXPR_ELLIPSIS) {
+			if (get_u32(assoc_value, &value, error)) {
+				free(live_optval);
+				return STATUS_ERR;
+			}
+			if (sctp_assoc_value->assoc_value != value) {
+				asprintf(error, "Bad getsockopt sctp_assoc_value.assoc_value: expected: %u actual: %u",
+					 value, sctp_assoc_value->assoc_value);
+				free(live_optval);
+				return STATUS_ERR;
+			}
+		}
+#endif
+#ifdef SCTP_SS_VALUE
+	} else if (val_expression->type == EXPR_SCTP_STREAM_VALUE) {
+		struct expression *stream_id = val_expression->value.sctp_stream_value->stream_id;
+		struct expression *stream_value = val_expression->value.sctp_stream_value->stream_value;
+		struct sctp_stream_value *sctp_stream_value = live_optval;
+		u16 value;
+
+		if (stream_id->type != EXPR_ELLIPSIS) {
+			if (get_u16(stream_id, &value, error)) {
+				free(live_optval);
+				return STATUS_ERR;
+			}
+			if (sctp_stream_value->stream_id != value) {
+				asprintf(error, "Bad getsockopt sctp_stream_value.stream_id: expected: %u actual: %u",
+					 value, sctp_stream_value->stream_id);
+				free(live_optval);
+				return STATUS_ERR;
+			}
+		}
+		if (stream_value->type != EXPR_ELLIPSIS) {
+			if (get_u16(stream_value, &value, error)) {
+				free(live_optval);
+				return STATUS_ERR;
+			}
+			if (sctp_stream_value->stream_value != value) {
+				asprintf(error, "Bad getsockopt sctp_stream_value.stream_value: expected: %u actual: %u",
+					 value, sctp_stream_value->stream_value);
+				free(live_optval);
+				return STATUS_ERR;
+			}
+		}
 #endif
 	} else {
 		if (*(int*)live_optval != script_optval) {
@@ -2036,6 +2147,12 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 	int script_fd, live_fd, level, optname, optval_s32, optlen, result;
 	void *optval = NULL;
 	struct expression *val_expression;
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+	struct sctp_assoc_value assoc_value;
+#endif
+#if defined(SCTP_SS_VALUE)
+	struct sctp_stream_value stream_value;
+#endif
 
 	if (check_arg_count(args, 5, error))
 		return STATUS_ERR;
@@ -2069,20 +2186,20 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 	} else if (val_expression->type == EXPR_SCTP_RTOINFO) {
 		struct sctp_rtoinfo *rtoinfo;
 		struct sctp_rtoinfo_expr *expr_rtoinfo  = val_expression->value.sctp_rtoinfo;
-		socklen_t live_optlen = sizeof(struct sctp_paddrparams);
+		if (expr_rtoinfo->srto_initial->type != EXPR_INTEGER ||
+			expr_rtoinfo->srto_max->type != EXPR_INTEGER ||
+			expr_rtoinfo->srto_min->type != EXPR_INTEGER) {
+			asprintf(error, "Bad setsockopt, bad inputtype for rtoinfo");
+			return STATUS_ERR;
+		}
 		rtoinfo = malloc(sizeof(struct sctp_rtoinfo));
 		memset(rtoinfo, 0, sizeof(struct sctp_rtoinfo));
 		rtoinfo->srto_assoc_id = 0;
-		if (getsockopt(live_fd, level, optname, rtoinfo, &live_optlen) == -1) {
-			asprintf(error, "Bad setsockopt, bad get actuall values");
-			free(rtoinfo);
-			return STATUS_ERR;
-		}
 		if (expr_rtoinfo->srto_initial->type != EXPR_ELLIPSIS) {
-			rtoinfo->srto_initial = expr_rtoinfo->srto_initial->value.num;	
+			rtoinfo->srto_initial = expr_rtoinfo->srto_initial->value.num;
 		}
 		if (expr_rtoinfo->srto_max->type != EXPR_ELLIPSIS) {
-			rtoinfo->srto_max = expr_rtoinfo->srto_max->value.num;		
+			rtoinfo->srto_max = expr_rtoinfo->srto_max->value.num;
 		}
 		if (expr_rtoinfo->srto_min->type != EXPR_ELLIPSIS) {
 			rtoinfo->srto_min = expr_rtoinfo->srto_min->value.num;
@@ -2093,9 +2210,27 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 	} else if (val_expression->type == EXPR_SCTP_INITMSG) {
 		optval = &val_expression->value.sctp_initmsg;
 #endif
-#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
-	} else if (val_expression->type == EXPR_SCTP_ASSOCVAL) {
-		optval = &val_expression->value.sctp_assoc_value;
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+	} else if (val_expression->type == 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)) {
+			return STATUS_ERR;
+		}
+		optval = &assoc_value;
+#endif
+#ifdef SCTP_SS_VALUE
+	} else if (val_expression->type == 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)) {
+			return STATUS_ERR;
+		}
+		if (get_u16(val_expression->value.sctp_stream_value->stream_value,
+		            &stream_value.stream_value, error)) {
+			return STATUS_ERR;
+		}
+		optval = &stream_value;
 #endif
 #ifdef SCTP_DELAYED_SACK
 	} else if (val_expression->type == EXPR_SCTP_SACKINFO) {
@@ -2169,7 +2304,7 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 		}
 #ifdef SPP_IPV6_FLOWLABEL
 		if (expr_params->spp_ipv6_flowlabel->type != EXPR_ELLIPSIS) {
-			int flowlabel; 
+			int flowlabel;
 			if (get_s32(expr_params->spp_ipv6_flowlabel, &flowlabel, error)) {
 				free(params);
 				return STATUS_ERR;
diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c
index 2490e907d6dbcb42a5d7e02eefb8ce6d277c6024..7aca4a8fe44908823e54cc3e859c2ae0133ab003 100644
--- a/gtests/net/packetdrill/script.c
+++ b/gtests/net/packetdrill/script.c
@@ -71,8 +71,8 @@ struct expression_type_entry expression_type_table[] = {
 #ifdef SCTP_INITMSG
 	{ EXPR_SCTP_INITMSG,         "sctp_initmsg"},
 #endif
-#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
-	{ EXPR_SCTP_ASSOCVAL,        "sctp_assocvalue"},
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+	{ EXPR_SCTP_ASSOC_VALUE,     "sctp_assoc_value"},
 #endif
 #ifdef SCTP_DELAYED_SACK
 	{ EXPR_SCTP_SACKINFO,        "sctp_sackinfo"},
@@ -83,6 +83,9 @@ struct expression_type_entry expression_type_table[] = {
 #endif
 #ifdef SCTP_PEER_ADDR_PARAMS
 	{ EXPR_SCTP_PEER_ADDR_PARAMS,	"sctp_peer_addr_params"},
+#endif
+#ifdef SCTP_SS_VALUE
+	{ EXPR_SCTP_STREAM_VALUE,     "sctp_stream_value"},
 #endif
 	{ NUM_EXPR_TYPES,            NULL}
 };
@@ -291,28 +294,34 @@ void free_expression(struct expression *expression)
 	case EXPR_INTEGER:
 		break;
 	case EXPR_LINGER:
+		assert(expression->value.linger);
 		free(expression->value.linger->l_onoff);
 		free(expression->value.linger->l_linger);
 		break;
 #ifdef SCTP_RTOINFO
 	case EXPR_SCTP_RTOINFO:
+		assert(expression->value.sctp_rtoinfo);
 		free(expression->value.sctp_rtoinfo->srto_initial);
 		free(expression->value.sctp_rtoinfo->srto_max);
 		free(expression->value.sctp_rtoinfo->srto_min);
 		break;
 #endif
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+	case EXPR_SCTP_ASSOC_VALUE:
+		assert(expression->value.sctp_assoc_value);
+		free(expression->value.sctp_assoc_value->assoc_value);
+		break;
+#endif
 #ifdef SCTP_INITMSG
 	case EXPR_SCTP_INITMSG:
 #endif
-#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
-	case EXPR_SCTP_ASSOCVAL:
-#endif
 #ifdef SCTP_DELAYED_SACK
 	case EXPR_SCTP_SACKINFO:
 #endif
 		break;
 #ifdef SCTP_STATUS
 	case EXPR_SCTP_PADDRINFO:
+		free(expression->value.sctp_paddrinfo);
 		free(expression->value.sctp_paddrinfo->spinfo_state);
 		free(expression->value.sctp_paddrinfo->spinfo_cwnd);
 		free(expression->value.sctp_paddrinfo->spinfo_srtt);
@@ -320,6 +329,7 @@ void free_expression(struct expression *expression)
 		free(expression->value.sctp_paddrinfo->spinfo_mtu);
 		break;
 	case EXPR_SCTP_STATUS:
+		assert(expression->value.sctp_status);
 		free(expression->value.sctp_status->sstat_state);
 		free(expression->value.sctp_status->sstat_rwnd);
 		free(expression->value.sctp_status->sstat_unackdata);
@@ -332,6 +342,7 @@ void free_expression(struct expression *expression)
 #endif
 #ifdef SCTP_PEER_ADDR_PARAMS
 	case EXPR_SCTP_PEER_ADDR_PARAMS:
+		assert(expression->value.sctp_paddrparams);
 		free(expression->value.sctp_paddrparams->spp_address);
 		free(expression->value.sctp_paddrparams->spp_hbinterval);
 		free(expression->value.sctp_paddrparams->spp_pathmaxrxt);
@@ -340,6 +351,13 @@ void free_expression(struct expression *expression)
 		free(expression->value.sctp_paddrparams->spp_ipv6_flowlabel);
 		free(expression->value.sctp_paddrparams->spp_dscp);
 		break;
+#endif
+#ifdef SCTP_SS_VALUE
+	case EXPR_SCTP_STREAM_VALUE:
+		assert(expression->value.sctp_stream_value);
+		free(expression->value.sctp_stream_value->stream_id);
+		free(expression->value.sctp_stream_value->stream_value);
+		break;
 #endif
 	case EXPR_WORD:
 		assert(expression->value.string);
@@ -516,7 +534,7 @@ static int evaluate_sctp_status_expression(struct expression *in,
 
 	in_status = in->value.sctp_status;
 	out_status = out->value.sctp_status;
-	
+
 	if (evaluate(in_status->sstat_state,
 			&out_status->sstat_state,
 			error))
@@ -577,6 +595,56 @@ static int evaluate_pollfd_expression(struct expression *in,
 	return STATUS_OK;
 }
 
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+static int evaluate_sctp_assoc_value_expression(struct expression *in,
+						struct expression *out,
+						char **error)
+{
+	struct sctp_assoc_value_expr *in_value;
+	struct sctp_assoc_value_expr *out_value;
+
+	assert(in->type == EXPR_SCTP_ASSOC_VALUE);
+	assert(in->value.sctp_assoc_value);
+	assert(out->type == EXPR_SCTP_ASSOC_VALUE);
+
+	out->value.sctp_assoc_value = calloc(1, sizeof(struct sctp_assoc_value_expr));
+
+	in_value = in->value.sctp_assoc_value;
+	out_value = out->value.sctp_assoc_value;
+
+	if (evaluate(in_value->assoc_value, &out_value->assoc_value, error))
+		return STATUS_ERR;
+
+	return STATUS_OK;
+}
+#endif
+
+#ifdef SCTP_SS_VALUE
+static int evaluate_sctp_stream_value_expression(struct expression *in,
+						 struct expression *out,
+						 char **error)
+{
+	struct sctp_stream_value_expr *in_value;
+	struct sctp_stream_value_expr *out_value;
+
+	assert(in->type == EXPR_SCTP_STREAM_VALUE);
+	assert(in->value.sctp_stream_value);
+	assert(out->type == EXPR_SCTP_STREAM_VALUE);
+
+	out->value.sctp_stream_value = calloc(1, sizeof(struct sctp_stream_value_expr));
+
+	in_value = in->value.sctp_stream_value;
+	out_value = out->value.sctp_stream_value;
+
+	if (evaluate(in_value->stream_id, &out_value->stream_id, error))
+		return STATUS_ERR;
+	if (evaluate(in_value->stream_value, &out_value->stream_value, error))
+		return STATUS_ERR;
+
+	return STATUS_OK;
+}
+#endif
+
 static int evaluate(struct expression *in,
 		    struct expression **out_ptr, char **error)
 {
@@ -612,11 +680,9 @@ static int evaluate(struct expression *in,
 		       sizeof(in->value.sctp_initmsg));
 		break;
 #endif
-#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
-	case EXPR_SCTP_ASSOCVAL:	/* copy as-is */
-		memcpy(&out->value.sctp_assoc_value,
-		       &in->value.sctp_assoc_value,
-		       sizeof(in->value.sctp_assoc_value));
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+	case EXPR_SCTP_ASSOC_VALUE:	/* copy as-is */
+		evaluate_sctp_assoc_value_expression(in, out, error);
 		break;
 #endif
 #ifdef SCTP_DELAYED_SACK
@@ -640,12 +706,17 @@ static int evaluate(struct expression *in,
 #endif
 #ifdef SCTP_PEER_ADDR_PARAMS
 	case EXPR_SCTP_PEER_ADDR_PARAMS:
-		memcpy(&out->value.sctp_paddrparams, &in->value.sctp_paddrparams, 
+		memcpy(&out->value.sctp_paddrparams, &in->value.sctp_paddrparams,
 			sizeof(in->value.sctp_paddrparams));
 		if (evaluate(in->value.sctp_paddrparams->spp_flags,
 				&out->value.sctp_paddrparams->spp_flags,
 				error))
-			return STATUS_ERR;		
+			return STATUS_ERR;
+		break;
+#endif
+#ifdef SCTP_SS_VALUE
+	case EXPR_SCTP_STREAM_VALUE:
+		evaluate_sctp_stream_value_expression(in, out, error);
 		break;
 #endif
 	case EXPR_WORD:
diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h
index e604d910f73f4d921cb1d693435c06cca6b1677b..cbdfad274d803ccb73ab942f0a75fe01a4b08f52 100644
--- a/gtests/net/packetdrill/script.h
+++ b/gtests/net/packetdrill/script.h
@@ -51,8 +51,8 @@ enum expression_t {
 #ifdef SCTP_INITMSG
 	EXPR_SCTP_INITMSG,	  /* struct sctp_initmsg for SCTP_INITMSG */
 #endif
-#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
-	EXPR_SCTP_ASSOCVAL,	  /* struct sctp_assoc_value */
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+	EXPR_SCTP_ASSOC_VALUE,	  /* struct sctp_assoc_value */
 #endif
 #ifdef SCTP_DELAYED_SACK
 	EXPR_SCTP_SACKINFO,	  /* struct sctp_sack_info for
@@ -61,6 +61,9 @@ enum expression_t {
 #ifdef SCTP_STATUS
 	EXPR_SCTP_STATUS,	  /* struct sctp_status for SCTP_STATUS */
 	EXPR_SCTP_PADDRINFO,
+#endif
+#ifdef SCTP_SS_VALUE
+	EXPR_SCTP_STREAM_VALUE,	  /* struct sctp_stream_value for SCTP_SS_VALUE */
 #endif
 	EXPR_SCTP_PEER_ADDR_PARAMS,	 /* struct for sctp_paddrparams for SCTP_PEER_ADDR_PARAMS*/
 	NUM_EXPR_TYPES,
@@ -88,8 +91,8 @@ struct expression {
 #ifdef SCTP_INITMSG
 		struct sctp_initmsg sctp_initmsg;
 #endif
-#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
-		struct sctp_assoc_value sctp_assoc_value;
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+		struct sctp_assoc_value_expr *sctp_assoc_value;
 #endif
 #ifdef SCTP_DELAYED_SACK
 		struct sctp_sack_info sctp_sack_info;
@@ -99,7 +102,10 @@ struct expression {
 		struct sctp_paddrinfo_expr *sctp_paddrinfo;
 #endif
 #ifdef SCTP_PEER_ADDR_PARAMS
-		struct sctp_paddrparams_expr *sctp_paddrparams; 
+		struct sctp_paddrparams_expr *sctp_paddrparams;
+#endif
+#ifdef SCTP_SS_VALUE
+		struct sctp_stream_value_expr *sctp_stream_value;
 #endif
 	} value;
 	const char *format;	/* the printf format for printing the value */
@@ -147,7 +153,7 @@ struct linger_expr {
 	struct expression *l_onoff;
 	struct expression *l_linger;
 };
-/* Parse tree for syscall get/setsockopt for sctp_rtoinfo*/
+/* Parse tree for a sctp_rtoinfo struct in a [gs]etsockopt syscall. */
 #ifdef SCTP_RTOINFO
 struct sctp_rtoinfo_expr {
 	struct expression *srto_initial;
@@ -156,7 +162,22 @@ struct sctp_rtoinfo_expr {
 };
 #endif
 
-/* Parse tree for syscall getsockopt for sctp_status*/
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED)
+/* Parse tree for a sctp_assoc_value struct in a [gs]etsockopt syscall. */
+struct sctp_assoc_value_expr {
+	struct expression *assoc_value;
+};
+#endif
+
+#ifdef SCTP_SS_VALUE
+/* Parse tree for a sctp_stream_value struct in a [gs]etsockopt syscall. */
+struct sctp_stream_value_expr {
+	struct expression *stream_id;
+	struct expression *stream_value;
+};
+#endif
+
+/* Parse tree for a sctp_status struct in a [gs]etsockopt syscall. */
 #ifdef SCTP_STATUS
 struct sctp_status_expr {
 	struct expression *sstat_state;
@@ -169,6 +190,7 @@ struct sctp_status_expr {
 	struct expression *sstat_primary;
 };
 
+/* Parse tree for a sctp_paddrinfo struct in a [gs]etsockopt syscall. */
 struct sctp_paddrinfo_expr {
 	struct expression *spinfo_state;
 	struct expression *spinfo_cwnd;
@@ -178,7 +200,7 @@ struct sctp_paddrinfo_expr {
 };
 #endif
 
-/* Parse tree for syscall set/getsockopt for SCTP_PEER_ADDR_PARAMS*/
+/* Parse tree for a sctp_paddrparams struct in a [gs]etsockopt syscall. */
 struct sctp_paddrparams_expr {
 	struct expression *spp_address;
 	struct expression *spp_hbinterval;
diff --git a/gtests/net/packetdrill/sctp.h b/gtests/net/packetdrill/sctp.h
index 177735b2dccaecdc834d1a816d03ceddafe209a9..dc9d2051513aca263324290f056af93ef26bfb98 100644
--- a/gtests/net/packetdrill/sctp.h
+++ b/gtests/net/packetdrill/sctp.h
@@ -52,6 +52,7 @@ struct sctp_common_header {
 #define SCTP_ECNE_CHUNK_TYPE				0x0c
 #define SCTP_CWR_CHUNK_TYPE				0x0d
 #define SCTP_SHUTDOWN_COMPLETE_CHUNK_TYPE		0x0e
+#define SCTP_I_DATA_CHUNK_TYPE				0x40
 #define SCTP_PAD_CHUNK_TYPE				0x84
 
 #define MAX_SCTP_CHUNK_BYTES	0xffff
@@ -205,6 +206,26 @@ struct sctp_shutdown_complete_chunk {
 	__be16 length;
 } __packed;
 
+#define SCTP_I_DATA_CHUNK_I_BIT				0x08
+#define SCTP_I_DATA_CHUNK_U_BIT				0x04
+#define SCTP_I_DATA_CHUNK_B_BIT				0x02
+#define SCTP_I_DATA_CHUNK_E_BIT				0x01
+
+struct sctp_i_data_chunk {
+	__u8 type;
+	__u8 flags;
+	__be16 length;
+	__be32 tsn;
+	__be16 sid;
+	__be16 res;
+	__be32 mid;
+	union {
+		__be32 ppid;
+		__be32 fsn;
+	} field;
+	__u8 data[];
+} __packed;
+
 struct sctp_pad_chunk {
 	__u8 type;
 	__u8 flags;
@@ -221,6 +242,7 @@ struct sctp_pad_chunk {
 #define SCTP_HOSTNAME_ADDRESS_PARAMETER_TYPE		0x000b
 #define SCTP_SUPPORTED_ADDRESS_TYPES_PARAMETER_TYPE	0x000c
 #define SCTP_ECN_CAPABLE_PARAMETER_TYPE			0x8000
+#define SCTP_SUPPORTED_EXTENSIONS_PARAMETER_TYPE	0x8008
 #define SCTP_PAD_PARAMETER_TYPE				0x8005
 
 #define MAX_SCTP_PARAMETER_BYTES	0xffff
@@ -284,6 +306,12 @@ struct sctp_ecn_capable_parameter {
 	__be16 length;
 } __packed;
 
+struct sctp_supported_extensions_parameter {
+	__be16 type;
+	__be16 length;
+	__u8 chunk_type[];
+} __packed;
+
 struct sctp_pad_parameter {
 	__be16 type;
 	__be16 length;
diff --git a/gtests/net/packetdrill/sctp_chunk_to_string.c b/gtests/net/packetdrill/sctp_chunk_to_string.c
index 59c246a06ed35800c8c189222b11c4446b2f0a56..8dc2ca83547de2a6f006d252430c66093c944937 100644
--- a/gtests/net/packetdrill/sctp_chunk_to_string.c
+++ b/gtests/net/packetdrill/sctp_chunk_to_string.c
@@ -219,6 +219,86 @@ static int sctp_ecn_capable_parameter_to_string(
 	return STATUS_OK;
 }
 
+static int sctp_supported_extensions_parameter_to_string(
+	FILE *s,
+	struct sctp_supported_extensions_parameter *parameter,
+	char **error)
+{
+	u16 length, nr_chunk_types, i;
+
+	length = ntohs(parameter->length);
+	if (length < sizeof(struct sctp_supported_extensions_parameter)) {
+		asprintf(error,
+			 "SUPPORTED_EXTENSIONS parameter illegal (length=%u)",
+			 length);
+		return STATUS_ERR;
+	}
+	nr_chunk_types = length - sizeof(struct sctp_supported_extensions_parameter);
+	fputs("SUPPORTED_EXTENSIONS[types=[", s);
+	for (i = 0; i < nr_chunk_types; i++) {
+		if (i > 0)
+			fputs(", ", s);
+		switch (parameter->chunk_type[i]) {
+		case SCTP_DATA_CHUNK_TYPE:
+			fputs("DATA", s);
+			break;
+		case SCTP_INIT_CHUNK_TYPE:
+			fputs("INIT", s);
+			break;
+		case SCTP_INIT_ACK_CHUNK_TYPE:
+			fputs("INIT-ACK", s);
+			break;
+		case SCTP_SACK_CHUNK_TYPE:
+			fputs("SACK", s);
+			break;
+		case SCTP_HEARTBEAT_CHUNK_TYPE:
+			fputs("HEARTBEAT", s);
+			break;
+		case SCTP_HEARTBEAT_ACK_CHUNK_TYPE:
+			fputs("HEARTBEAT-ACK", s);
+			break;
+		case SCTP_ABORT_CHUNK_TYPE:
+			fputs("ABORT", s);
+			break;
+		case SCTP_SHUTDOWN_CHUNK_TYPE:
+			fputs("SHUTDOWN", s);
+			break;
+		case SCTP_SHUTDOWN_ACK_CHUNK_TYPE:
+			fputs("SHUTDOWN-ACK", s);
+			break;
+		case SCTP_ERROR_CHUNK_TYPE:
+			fputs("ERROR", s);
+			break;
+		case SCTP_COOKIE_ECHO_CHUNK_TYPE:
+			fputs("COOKIE-ECHO", s);
+			break;
+		case SCTP_COOKIE_ACK_CHUNK_TYPE:
+			fputs("COOKIE-ACK", s);
+			break;
+		case SCTP_ECNE_CHUNK_TYPE:
+			fputs("ECNE", s);
+			break;
+		case SCTP_CWR_CHUNK_TYPE:
+			fputs("CWR", s);
+			break;
+		case SCTP_SHUTDOWN_COMPLETE_CHUNK_TYPE:
+			fputs("SHUTDOWN-COMPLETE", s);
+			break;
+		case SCTP_I_DATA_CHUNK_TYPE:
+			fputs("I-DATA", s);
+			break;
+		case SCTP_PAD_CHUNK_TYPE:
+			fputs("PAD", s);
+			break;
+		default:
+			fprintf(s, "0x%02x", parameter->chunk_type[i]);
+			break;
+		}
+	}
+	fputs("]]", s);
+	return STATUS_OK;
+}
+
 static int sctp_pad_parameter_to_string(
 	FILE *s,
 	struct sctp_pad_parameter *parameter,
@@ -305,6 +385,11 @@ static int sctp_parameter_to_string(FILE *s,
 		result = sctp_ecn_capable_parameter_to_string(s,
 			(struct sctp_ecn_capable_parameter *)parameter, error);
 		break;
+	case SCTP_SUPPORTED_EXTENSIONS_PARAMETER_TYPE:
+		result = sctp_supported_extensions_parameter_to_string(s,
+			(struct sctp_supported_extensions_parameter *)parameter,
+			error);
+		break;
 	case SCTP_PAD_PARAMETER_TYPE:
 		result = sctp_pad_parameter_to_string(s,
 			(struct sctp_pad_parameter *)parameter, error);
@@ -1206,6 +1291,49 @@ static int sctp_shutdown_complete_chunk_to_string(
 	return STATUS_OK;
 }
 
+static int sctp_i_data_chunk_to_string(FILE *s,
+				       struct sctp_i_data_chunk *chunk,
+				       char **error)
+{
+	u16 length;
+	u8 flags;
+
+	flags = chunk->flags;
+	length = ntohs(chunk->length);
+	if (length < sizeof(struct sctp_i_data_chunk)) {
+		asprintf(error, "I-DATA chunk too short (length=%u)", length);
+		return STATUS_ERR;
+	}
+	fputs("I-DATA[", s);
+	fputs("flgs=", s);
+	if ((flags & ~(SCTP_I_DATA_CHUNK_I_BIT |
+		       SCTP_I_DATA_CHUNK_U_BIT |
+		       SCTP_I_DATA_CHUNK_B_BIT |
+		       SCTP_I_DATA_CHUNK_E_BIT)) || (flags == 0x00))
+		fprintf(s, "0x%02x", chunk->flags);
+	else {
+		if (flags & SCTP_I_DATA_CHUNK_I_BIT)
+			fputc('I', s);
+		if (flags & SCTP_I_DATA_CHUNK_U_BIT)
+			fputc('U', s);
+		if (flags & SCTP_I_DATA_CHUNK_B_BIT)
+			fputc('B', s);
+		if (flags & SCTP_I_DATA_CHUNK_E_BIT)
+			fputc('E', s);
+	}
+	fputs(", ", s);
+	fprintf(s, "len=%u, ", length);
+	fprintf(s, "tsn=%u, ", ntohl(chunk->tsn));
+	fprintf(s, "sid=%d, ", ntohs(chunk->sid));
+	fprintf(s, "mid=%u, ", ntohl(chunk->mid));
+	if (flags & SCTP_I_DATA_CHUNK_B_BIT)
+		fprintf(s, "ppid=%u", ntohl(chunk->field.ppid));
+	else
+		fprintf(s, "fsn=%u", ntohl(chunk->field.fsn));
+	fputc(']', s);
+	return STATUS_OK;
+}
+
 static int sctp_pad_chunk_to_string(
 	FILE *s,
 	struct sctp_pad_chunk *chunk,
@@ -1305,6 +1433,10 @@ int sctp_chunk_to_string(FILE *s, struct sctp_chunk *chunk, char **error)
 		result = sctp_shutdown_complete_chunk_to_string(s,
 			(struct sctp_shutdown_complete_chunk *)chunk, error);
 		break;
+	case SCTP_I_DATA_CHUNK_TYPE:
+		result = sctp_i_data_chunk_to_string(s,
+			(struct sctp_i_data_chunk *)chunk, error);
+		break;
 	case SCTP_PAD_CHUNK_TYPE:
 		result = sctp_pad_chunk_to_string(s,
 			(struct sctp_pad_chunk *)chunk, error);
diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c
index ac26f2082a8d57ecdf84a538dfe0c32c52c8b2f1..23112204244cf2c4fc15ca35821e0ce182d8b48b 100644
--- a/gtests/net/packetdrill/sctp_packet.c
+++ b/gtests/net/packetdrill/sctp_packet.c
@@ -1097,6 +1097,83 @@ sctp_shutdown_complete_chunk_new(s64 flgs)
 	                                sctp_cause_list_new());
 }
 
+struct sctp_chunk_list_item *
+sctp_i_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 res, s64 mid,
+                      s64 ppid, s64 fsn)
+{
+	struct sctp_i_data_chunk *chunk;
+	u32 flags;
+	u16 length, padding_length;
+
+	flags = 0;
+	if (len == -1) {
+		length = (u16)sizeof(struct sctp_i_data_chunk);
+	} else {
+		length = (u16)len;
+	}
+	padding_length = length % 4;
+	if (padding_length > 0) {
+		padding_length = 4 - padding_length;
+	}
+	chunk = malloc(length + padding_length);
+	assert(chunk != NULL);
+	chunk->type = SCTP_I_DATA_CHUNK_TYPE;
+	if (flgs == -1) {
+		chunk->flags = 0;
+		flags |= FLAG_CHUNK_FLAGS_NOCHECK;
+	} else {
+		 chunk->flags = (u8)flgs;
+	}
+	chunk->length = htons(length);
+	if (len == -1) {
+		flags |= FLAG_CHUNK_LENGTH_NOCHECK;
+		flags |= FLAG_CHUNK_VALUE_NOCHECK;
+	}
+	if (tsn == -1) {
+		chunk->tsn = htonl(0);
+		flags |= FLAG_I_DATA_CHUNK_TSN_NOCHECK;
+	} else {
+		chunk->tsn = htonl((u32)tsn);
+	}
+	if (sid == -1) {
+		chunk->sid = htons(0);
+		flags |= FLAG_I_DATA_CHUNK_SID_NOCHECK;
+	} else {
+		chunk->sid = htons((u16)sid);
+	}
+	if (res == -1) {
+		chunk->res = htons(0);
+		flags |= FLAG_I_DATA_CHUNK_RES_NOCHECK;
+	} else {
+		chunk->res = htons((u16)res);
+	}
+	if (mid == -1) {
+		chunk->mid = htonl(0);
+		flags |= FLAG_I_DATA_CHUNK_MID_NOCHECK;
+	} else {
+		chunk->mid = htonl((u32)mid);
+	}
+	if (ppid == -1) {
+		flags |= FLAG_I_DATA_CHUNK_PPID_NOCHECK;
+	} else {
+		chunk->field.ppid = htonl((u32)ppid);
+	}
+	if (fsn == -1) {
+		flags |= FLAG_I_DATA_CHUNK_FSN_NOCHECK;
+	} else {
+		chunk->field.fsn = htonl((u32)fsn);
+	}
+	if (ppid == -1 && fsn == -1) {
+		chunk->field.ppid = htonl(0);
+	}
+	memset(chunk->data, 0,
+	       length + padding_length - sizeof(struct sctp_i_data_chunk));
+	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
+	                                length + padding_length, flags,
+	                                sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
+}
+
 struct sctp_chunk_list_item *
 sctp_pad_chunk_new(s64 flgs, s64 len, u8* padding)
 {
@@ -1256,7 +1333,7 @@ sctp_generic_parameter_new(s64 type, s64 len, struct sctp_byte_list *bytes)
 struct sctp_parameter_list_item *
 sctp_heartbeat_information_parameter_new(s64 len, struct sctp_byte_list *bytes)
 {
-	return sctp_generic_parameter_new(SCTP_HEARTBEAT_INFORMATION_PARAMETER_TYPE, len,bytes);
+	return sctp_generic_parameter_new(SCTP_HEARTBEAT_INFORMATION_PARAMETER_TYPE, len, bytes);
 }
 
 struct sctp_parameter_list_item *
@@ -1493,6 +1570,47 @@ sctp_supported_address_types_parameter_new(struct sctp_address_type_list *list)
 	                                    parameter_length, flags);
 }
 
+struct sctp_parameter_list_item *
+sctp_supported_extensions_parameter_new(struct sctp_byte_list *list)
+{
+	struct sctp_supported_extensions_parameter *parameter;
+
+	u32 flags;
+	u16 i, parameter_length, padding_length;
+	struct sctp_byte_list_item *item;
+
+	flags = 0;
+	parameter_length = sizeof(struct sctp_supported_extensions_parameter);
+	if (list == NULL) {
+		flags |= FLAG_PARAMETER_LENGTH_NOCHECK;
+		flags |= FLAG_PARAMETER_VALUE_NOCHECK;
+	} else {
+		assert(list->nr_entries <=
+		       (MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_supported_extensions_parameter)) / sizeof(u8));
+		parameter_length += list->nr_entries * sizeof(u8);
+	}
+	padding_length = parameter_length % 4;
+	if (padding_length > 0) {
+		padding_length = 4 - padding_length;
+	}
+	assert(padding_length < 4);
+	parameter = malloc(parameter_length + padding_length);
+	assert(parameter != NULL);
+	parameter->type = htons(SCTP_SUPPORTED_EXTENSIONS_PARAMETER_TYPE);
+	parameter->length = htons(parameter_length);
+	if (list != NULL) {
+		for (i = 0, item = list->first;
+		     (i < list->nr_entries) && (item != NULL);
+		     i++, item = item->next) {
+			parameter->chunk_type[i] = item->byte;
+		}
+		assert((i == list->nr_entries) && (item == NULL));
+	}
+	memset(parameter->chunk_type + list->nr_entries, 0, padding_length);
+	return sctp_parameter_list_item_new((struct sctp_parameter *)parameter,
+	                                    parameter_length, flags);
+}
+
 struct sctp_parameter_list_item *
 sctp_pad_parameter_new(s64 len, u8 *padding)
 {
diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h
index ad974346203a7f703df99db63812e90f41f2bcbb..ba972b395bb1bf338093c6b0ef1d742af2c546cc 100644
--- a/gtests/net/packetdrill/sctp_packet.h
+++ b/gtests/net/packetdrill/sctp_packet.h
@@ -275,6 +275,17 @@ sctp_cwr_chunk_new(s64 flgs, s64 lowest_tsn);
 struct sctp_chunk_list_item *
 sctp_shutdown_complete_chunk_new(s64 flgs);
 
+#define FLAG_I_DATA_CHUNK_TSN_NOCHECK           0x00000100
+#define FLAG_I_DATA_CHUNK_SID_NOCHECK           0x00000200
+#define FLAG_I_DATA_CHUNK_RES_NOCHECK           0x00000400
+#define FLAG_I_DATA_CHUNK_MID_NOCHECK           0x00000800
+#define FLAG_I_DATA_CHUNK_PPID_NOCHECK          0x00001000
+#define FLAG_I_DATA_CHUNK_FSN_NOCHECK           0x00002000
+
+struct sctp_chunk_list_item *
+sctp_i_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 res, s64 mid,
+                      s64 ppid, s64 fsn);
+
 struct sctp_chunk_list_item *
 sctp_pad_chunk_new(s64 flgs, s64 len, u8* padding);
 
@@ -329,6 +340,12 @@ sctp_ecn_capable_parameter_new(void);
 struct sctp_parameter_list_item *
 sctp_pad_parameter_new(s64 len, u8 *padding);
 
+struct sctp_parameter_list_item *
+sctp_supported_extensions_parameter_new(struct sctp_byte_list *list);
+
+struct sctp_parameter_list_item *
+sctp_pad_parameter_new(s64 len, u8 *padding);
+
 struct sctp_parameter_list *
 sctp_parameter_list_new(void);
 
diff --git a/gtests/net/packetdrill/symbols_freebsd.c b/gtests/net/packetdrill/symbols_freebsd.c
index 14eda9cf01e377000c9e3fcc118df62461ea40d3..76ca731740018907a56a8ef748efd087bc914d23 100644
--- a/gtests/net/packetdrill/symbols_freebsd.c
+++ b/gtests/net/packetdrill/symbols_freebsd.c
@@ -78,7 +78,7 @@ struct int_symbol platform_symbols_table[] = {
 	{ SO_SETFIB,                        "SO_SETFIB"                       },
 	{ SO_USER_COOKIE,                   "SO_USER_COOKIE"                  },
 
-	/* /usr/include/netinet/sctp.h */
+	/* /usr/include/netinet/sctp.h and /usr/include/netinet/sctp_uio.h */
 	{ SCTP_RTOINFO,                     "SCTP_RTOINFO"                    },
 	{ SCTP_INITMSG,                     "SCTP_INITMSG"                    },
 	{ SCTP_NODELAY,                     "SCTP_NODELAY"                    },
@@ -87,6 +87,10 @@ struct int_symbol platform_symbols_table[] = {
 	{ SCTP_MAX_BURST,                   "SCTP_MAX_BURST"                  },
 	{ SCTP_PEER_ADDR_PARAMS,            "SCTP_PEER_ADDR_PARAMS"           },
 	{ SCTP_STATUS,                      "SCTP_STATUS"                     },
+	{ SCTP_FRAGMENT_INTERLEAVE,         "SCTP_FRAGMENT_INTERLEAVE"        },
+#if defined(SCTP_INTERLEAVING_SUPPORTED)
+	{ SCTP_INTERLEAVING_SUPPORTED,      "SCTP_INTERLEAVING_SUPPORTED"     },
+#endif
 	{ SCTP_CLOSED,                      "SCTP_CLOSED"                     },
 	{ SCTP_BOUND,                       "SCTP_BOUND"                      },
 	{ SCTP_LISTEN,                      "SCTP_LISTEN"                     },
@@ -97,8 +101,52 @@ struct int_symbol platform_symbols_table[] = {
 	{ SCTP_SHUTDOWN_RECEIVED,           "SCTP_SHUTDOWN_RECEIVED"          },
 	{ SCTP_SHUTDOWN_ACK_SENT,           "SCTP_SHUTDOWN_ACK_SENT"          },
 	{ SCTP_SHUTDOWN_PENDING,            "SCTP_SHUTDOWN_PENDING"           },
-
-	/* /usr/include/netinet/sctp_uio.h */
+	/* The following constants are from
+	 * https://tools.ietf.org/html/draft-ietf-tsvwg-sctp-ndata-04
+	 * The old symbols currently being deployed are also provided.
+	 */
+	{ SCTP_PLUGGABLE_SS,                "SCTP_PLUGGABLE_SS"               },
+	{ SCTP_SS_VALUE,                    "SCTP_SS_VALUE"                   },
+	{ SCTP_SS_DEFAULT,                  "SCTP_SS_DEFAULT"                 },
+	{ SCTP_SS_ROUND_ROBIN,              "SCTP_SS_ROUND_ROBIN"             },
+	{ SCTP_SS_ROUND_ROBIN_PACKET,       "SCTP_SS_ROUND_ROBIN_PACKET"      },
+	{ SCTP_SS_PRIORITY,                 "SCTP_SS_PRIORITY"                },
+	/* The following is a typo in FreeBSD's sctp.h */
+	{ SCTP_SS_FAIR_BANDWITH,            "SCTP_SS_FAIR_BANDWITH"           },
+	{ SCTP_SS_FIRST_COME,               "SCTP_SS_FIRST_COME"              },
+#if defined(SCTP_SS_FCFS)
+	{ SCTP_SS_FCFS,                     "SCTP_SS_FCFS"                    },
+#endif
+#if defined(SCTP_SS_RR)
+	{ SCTP_SS_RR,                       "SCTP_SS_RR"                      },
+#endif
+#if defined(SCTP_SS_RR_PKT)
+	{ SCTP_SS_RR_PKT,                   "SCTP_SS_RR_PKT"                  },
+#endif
+#if defined(SCTP_SS_PRIO)
+	{ SCTP_SS_PRIO,                     "SCTP_SS_PRIO"                    },
+#endif
+#if defined(SCTP_SS_FB)
+	{ SCTP_SS_FB,                       "SCTP_SS_FB"                      },
+#endif
+#if defined(SCTP_SS_WFQ)
+	{ SCTP_SS_WFQ,                      "SCTP_SS_WFQ"                     },
+#endif
+#if defined(SCTP_SS_RR_INTER)
+	{ SCTP_SS_RR_INTER,                 "SCTP_SS_RR_INTER"                },
+#endif
+#if defined(SCTP_SS_RR_PKT_INTER)
+	{ SCTP_SS_RR_PKT_INTER,             "SCTP_SS_RR_PKT_INTER"            },
+#endif
+#if defined(SCTP_SS_PRIO_INTER)
+	{ SCTP_SS_PRIO_INTER,               "SCTP_SS_PRIO_INTER"              },
+#endif
+#if defined(SCTP_SS_FB_INTER)
+	{ SCTP_SS_FB_INTER,                 "SCTP_SS_FB_INTER"                },
+#endif
+#if defined(SCTP_SS_WFQ_INTER)
+	{ SCTP_SS_WFQ_INTER,                "SCTP_SS_WFQ_INTER"               },
+#endif
 	{ SCTP_UNCONFIRMED,                 "SCTP_UNCONFIRMED"                },
 	{ SCTP_ACTIVE,                      "SCTP_ACTIVE"                     },
 	{ SCTP_INACTIVE,                    "SCTP_INACTIVE"                   },
@@ -111,7 +159,7 @@ struct int_symbol platform_symbols_table[] = {
 	{ SPP_IPV6_FLOWLABEL,               "SPP_IPV6_FLOWLABEL"              },
 	{ SPP_DSCP,                         "SPP_DSCP"                        },
 	{ SPP_IPV4_TOS,                     "SPP_IPV4_TOS"                    },
- 
+
 	/* /usr/include/netinet/tcp.h */
 	{ TCP_NODELAY,                      "TCP_NODELAY"                     },
 	{ TCP_MAXSEG,                       "TCP_MAXSEG"                      },
diff --git a/gtests/net/packetdrill/symbols_linux.c b/gtests/net/packetdrill/symbols_linux.c
index db4e25599a982a3bdfbd95aa9d4f02da43ee2b88..df65a2cf13e77a8de902269a3c19bdeb9b61181c 100644
--- a/gtests/net/packetdrill/symbols_linux.c
+++ b/gtests/net/packetdrill/symbols_linux.c
@@ -123,6 +123,12 @@ struct int_symbol platform_symbols_table[] = {
 #endif
 #ifdef SCTP_STATUS
 	{ SCTP_STATUS,                      "SCTP_STATUS"                     },
+#endif
+#ifdef SCTP_FRAGMENT_INTERLEAVE
+	{ SCTP_FRAGMENT_INTERLEAVE,         "SCTP_FRAGMENT_INTERLEAVE"        },
+#endif
+#ifdef SCTP_INTERLEAVING_SUPPORTED
+	{ SCTP_INTERLEAVING_SUPPORTED,      "SCTP_INTERLEAVING_SUPPORTED"     },
 #endif
 	{ SCTP_CLOSED,                      "SCTP_CLOSED"                     },
 #if 0
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 4b619548f3647f87e74a8a4f2e1b533a2e0b44bc..7983e824febd71050c39bb4972f7f0f8fff03681 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
@@ -71,5 +71,5 @@ spp_hbinterval=300, spp_pathmtu=1468, spp_pathmaxrxt=..., spp_flags=521, spp_ipv
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=..., srto_max=200, srto_min=50}, [16]) = 0
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=..., srto_min=50}, [16]) = 0
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=200, srto_min=...}, [16]) = 0
-
++0 getsockopt(3, IPPROTO_SCTP, SCTP_MAXSEG, {assoc_value=1452}, [8]) = 0
 +0 close(3) = 0
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_i_data.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_i_data.pkt
new file mode 100644
index 0000000000000000000000000000000000000000..7303482b38ea2b51bf88298048285b86bc7c8262
--- /dev/null
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_i_data.pkt
@@ -0,0 +1,25 @@
++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 setsockopt(3, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, [2], 4) = 0
++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_INTERLEAVING_SUPPORTED, {assoc_value=1}, 8) = 0
++0.0 < sctp: INIT[flgs=0, tag=1, a_rwnd=1500, os=2, is=2, tsn=1,
+                  SUPPORTED_EXTENSIONS[types=[I-DATA, PAD]]]
++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
++0.1 send(4, ..., 100, 0) = 100
++0.0 > sctp: I-DATA[flgs=BE, len=120, tsn=1, sid=0, mid=0, ppid=0]
++0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]]
+// Insert a I-DATA chunk
++0.0 < sctp: I-DATA[flgs=BE, len=24, tsn=1, sid=1, mid=0, ppid=1234]
++0.0 > sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=..., gaps=[], dups=[]]
++0.0 recv(4, ..., 100, 0) = 4
+// Tear down the association
++1.0 < sctp: SHUTDOWN[flgs=0, cum_tsn=1]
++0.0 > sctp: SHUTDOWN_ACK[flgs=0]
++0.0 < sctp: SHUTDOWN_COMPLETE[flgs=0]
++0.0 close(4) = 0
++0.0 close(3) = 0