diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index e7f0c7b2caded90867f8249285a1b3ec94537b5d..95cb894ce1fd22bbf9a4d5e5d8afccc97bc9b866 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -268,6 +268,25 @@ params				return PARAMS;
 IPv4				return IPV4_TYPE;
 IPv6				return IPV6_TYPE;
 HOSTNAME			return HOSTNAME_TYPE;
+CAUSE				return CAUSE;
+INVALID_STREAM_IDENTIFIER	return INVALID_STREAM_IDENTIFIER;
+MISSING_MANDATORY_PARAMETER	return MISSING_MANDATORY_PARAMETER;
+STALE_COOKIE_ERROR		return STALE_COOKIE_ERROR;
+OUT_OF_RESOURCE			return OUT_OF_RESOURCE;
+UNRESOLVABLE_ADDRESS		return UNRESOLVABLE_ADDRESS;
+UNRECOGNIZED_CHUNK_TYPE		return UNRECOGNIZED_CHUNK_TYPE;
+INVALID_MANDATORY_PARAMETER	return INVALID_MANDATORY_PARAMETER;
+UNRECOGNIZED_PARAMETERS		return UNRECOGNIZED_PARAMETERS;
+NO_USER_DATA			return NO_USER_DATA;
+COOKIE_RECEIVED_WHILE_SHUTDOWN  return COOKIE_RECEIVED_WHILE_SHUTDOWN;
+RESTART_WITH_NEW_ADDRESSES	return RESTART_WITH_NEW_ADDRESSES;
+USER_INITIATED_ABORT		return USER_INITIATED_ABORT;
+PROTOCOL_VIOLATION		return PROTOCOL_VIOLATION;
+code				return CAUSE_CODE;
+info				return CAUSE_INFO;
+staleness			return STALENESS;
+param				return PARAM;
+chk				return CHK;
 --[a-zA-Z0-9_]+			yylval.string	= option(yytext); return OPTION;
 [-]?[0-9]*[.][0-9]+		yylval.floating	= atof(yytext);   return FLOAT;
 [-]?[0-9]+			yylval.integer	= atoll(yytext);  return INTEGER;
diff --git a/gtests/net/packetdrill/packet.c b/gtests/net/packetdrill/packet.c
index 97331617438eba5a62bb0702633a713ac186f470..a5edfebe07eeca5d3ea2f53ae8078265c620e4b2 100644
--- a/gtests/net/packetdrill/packet.c
+++ b/gtests/net/packetdrill/packet.c
@@ -153,6 +153,9 @@ static struct packet *packet_copy_with_headroom(struct packet *old_packet,
 	struct sctp_parameter_list_item *old_parameter_item, *new_parameter_item;
 	struct sctp_parameter *new_parameter;
 	struct sctp_parameter_list *new_parameter_list;
+	struct sctp_cause_list_item *old_cause_item, *new_cause_item;
+	struct sctp_cause *new_cause;
+	struct sctp_cause_list *new_cause_list;
 
 	memcpy(new_base, old_base, bytes_used);
 
@@ -191,11 +194,24 @@ static struct packet *packet_copy_with_headroom(struct packet *old_packet,
 			                                                  old_parameter_item->flags);
 			sctp_parameter_list_append(new_parameter_list, new_parameter_item);
 		}
+		new_cause_list = sctp_cause_list_new();
+		for (old_cause_item = old_chunk_item->cause_list->first;
+		     old_cause_item != NULL;
+		     old_cause_item = old_cause_item->next) {
+			new_cause = offset_ptr(old_base,
+			                       new_base,
+			                       old_cause_item->cause);
+			new_cause_item = sctp_cause_list_item_new(new_cause,
+			                                          old_cause_item->length,
+			                                          old_cause_item->flags);
+			sctp_cause_list_append(new_cause_list, new_cause_item);
+		}
 		new_chunk = offset_ptr(old_base, new_base, old_chunk_item->chunk);
 		new_chunk_item = sctp_chunk_list_item_new(new_chunk,
 		                                          old_chunk_item->length,
 		                                          old_chunk_item->flags,
-		                                          new_parameter_list);
+		                                          new_parameter_list,
+		                                          new_cause_list);
 		sctp_chunk_list_append(packet->chunk_list, new_chunk_item);
 	}
 
diff --git a/gtests/net/packetdrill/packet_to_string_test.c b/gtests/net/packetdrill/packet_to_string_test.c
index ae497533a78ae8c0feadd58c94bdda0edeea7fea..899ef4b743168cce1d774174c076d44aa3cfac8c 100644
--- a/gtests/net/packetdrill/packet_to_string_test.c
+++ b/gtests/net/packetdrill/packet_to_string_test.c
@@ -256,7 +256,7 @@ static void test_sctp_ipv6_packet_to_string(void)
 		     "IPV4_ADDRESS[addr=1.2.3.4], "
 		     "IPV6_ADDRESS[addr=::1], "
 		     "COOKIE_PRESERVATIVE[incr=65536], "
-		     "HOSTNAME[addr=\"@A\"], "
+		     "HOSTNAME_ADDRESS[addr=\"@A\"], "
 		     "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], "
 		     "ECN_CAPABLE[], "
 		     "PAD[len=16, val=...]]; "
@@ -270,11 +270,11 @@ static void test_sctp_ipv6_packet_to_string(void)
 		"HEARTBEAT_ACK[flgs=0x00, HEARTBEAT_INFORMATION[len=6, val=...]]; "
 		"ABORT[flgs=T]; "
 		"ABORT[flgs=0x00, INVALID_STREAM_IDENTIFIER[sid=255], "
-		      "MISSING_MANDATORY_PARAMETER[STATE_COOKIE], "
+		      "MISSING_MANDATORY_PARAMETER[types=[STATE_COOKIE]], "
 		      "STALE_COOKIE_ERROR[staleness=65536], "
 		      "OUT_OF_RESOURCES[], "
-		      "UNRESOLVABLE_ADDRESS[HOSTNAME[addr=\"@A\"]], "
-		      "UNRECOGNIZED_CHUNK["
+		      "UNRESOLVABLE_ADDRESS[param=HOSTNAME_ADDRESS[addr=\"@A\"]], "
+		      "UNRECOGNIZED_CHUNK[chk="
 			"CHUNK[type=0xfe, flgs=0x05, value=[0x01]]], "
 		      "INVALID_MANDATORY_PARAMETER[], "
 		      "UNRECOGNIZED_PARAMETERS["
@@ -284,8 +284,8 @@ static void test_sctp_ipv6_packet_to_string(void)
 		      "COOKIE_RECEIVED_WHILE_SHUTDOWN[], "
 		      "RESTART_WITH_NEW_ADDRESSES[IPV4_ADDRESS[addr=1.2.3.4], "
 						 "IPV4_ADDRESS[addr=2.3.4.5]], "
-		      "USER_INITIATED_ABORT[BYE], "
-		      "PROTOCOL_VIOLATION[@@]]; "
+		      "USER_INITIATED_ABORT[info=\"BYE\"], "
+		      "PROTOCOL_VIOLATION[info=\"@@\"]]; "
 		"SHUTDOWN[flgs=0x00, cum_tsn=16909060]; "
 		"SHUTDOWN_ACK[flgs=0x00]; "
 		"ERROR[flgs=0x00]; "
@@ -311,7 +311,7 @@ static void test_sctp_ipv6_packet_to_string(void)
 		     "IPV4_ADDRESS[addr=1.2.3.4], "
 		     "IPV6_ADDRESS[addr=::1], "
 		     "COOKIE_PRESERVATIVE[incr=65536], "
-		     "HOSTNAME[addr=\"@A\"], "
+		     "HOSTNAME_ADDRESS[addr=\"@A\"], "
 		     "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], "
 		     "ECN_CAPABLE[], "
 		     "PAD[len=16, val=...]]; "
@@ -325,11 +325,11 @@ static void test_sctp_ipv6_packet_to_string(void)
 		"HEARTBEAT_ACK[flgs=0x00, HEARTBEAT_INFORMATION[len=6, val=...]]; "
 		"ABORT[flgs=T]; "
 		"ABORT[flgs=0x00, INVALID_STREAM_IDENTIFIER[sid=255], "
-		      "MISSING_MANDATORY_PARAMETER[STATE_COOKIE], "
+		      "MISSING_MANDATORY_PARAMETER[types=[STATE_COOKIE]], "
 		      "STALE_COOKIE_ERROR[staleness=65536], "
 		      "OUT_OF_RESOURCES[], "
-		      "UNRESOLVABLE_ADDRESS[HOSTNAME[addr=\"@A\"]], "
-		      "UNRECOGNIZED_CHUNK["
+		      "UNRESOLVABLE_ADDRESS[param=HOSTNAME_ADDRESS[addr=\"@A\"]], "
+		      "UNRECOGNIZED_CHUNK[chk="
 			"CHUNK[type=0xfe, flgs=0x05, value=[0x01]]], "
 		      "INVALID_MANDATORY_PARAMETER[], "
 		      "UNRECOGNIZED_PARAMETERS["
@@ -339,8 +339,8 @@ static void test_sctp_ipv6_packet_to_string(void)
 		      "COOKIE_RECEIVED_WHILE_SHUTDOWN[], "
 		      "RESTART_WITH_NEW_ADDRESSES[IPV4_ADDRESS[addr=1.2.3.4], "
 						 "IPV4_ADDRESS[addr=2.3.4.5]], "
-		      "USER_INITIATED_ABORT[BYE], "
-		      "PROTOCOL_VIOLATION[@@]]; "
+		      "USER_INITIATED_ABORT[info=\"BYE\"], "
+		      "PROTOCOL_VIOLATION[info=\"@@\"]]; "
 		"SHUTDOWN[flgs=0x00, cum_tsn=16909060]; "
 		"SHUTDOWN_ACK[flgs=0x00]; "
 		"ERROR[flgs=0x00]; "
@@ -366,7 +366,7 @@ static void test_sctp_ipv6_packet_to_string(void)
 		     "IPV4_ADDRESS[addr=1.2.3.4], "
 		     "IPV6_ADDRESS[addr=::1], "
 		     "COOKIE_PRESERVATIVE[incr=65536], "
-		     "HOSTNAME[addr=\"@A\"], "
+		     "HOSTNAME_ADDRESS[addr=\"@A\"], "
 		     "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], "
 		     "ECN_CAPABLE[], "
 		     "PAD[len=16, val=...]]; "
@@ -380,11 +380,11 @@ static void test_sctp_ipv6_packet_to_string(void)
 		"HEARTBEAT_ACK[flgs=0x00, HEARTBEAT_INFORMATION[len=6, val=...]]; "
 		"ABORT[flgs=T]; "
 		"ABORT[flgs=0x00, INVALID_STREAM_IDENTIFIER[sid=255], "
-		      "MISSING_MANDATORY_PARAMETER[STATE_COOKIE], "
+		      "MISSING_MANDATORY_PARAMETER[types=[STATE_COOKIE]], "
 		      "STALE_COOKIE_ERROR[staleness=65536], "
 		      "OUT_OF_RESOURCES[], "
-		      "UNRESOLVABLE_ADDRESS[HOSTNAME[addr=\"@A\"]], "
-		      "UNRECOGNIZED_CHUNK["
+		      "UNRESOLVABLE_ADDRESS[param=HOSTNAME_ADDRESS[addr=\"@A\"]], "
+		      "UNRECOGNIZED_CHUNK[chk="
 			"CHUNK[type=0xfe, flgs=0x05, value=[0x01]]], "
 		      "INVALID_MANDATORY_PARAMETER[], "
 		      "UNRECOGNIZED_PARAMETERS["
@@ -394,8 +394,8 @@ static void test_sctp_ipv6_packet_to_string(void)
 		      "COOKIE_RECEIVED_WHILE_SHUTDOWN[], "
 		      "RESTART_WITH_NEW_ADDRESSES[IPV4_ADDRESS[addr=1.2.3.4], "
 						 "IPV4_ADDRESS[addr=2.3.4.5]], "
-		      "USER_INITIATED_ABORT[BYE], "
-		      "PROTOCOL_VIOLATION[@@]]; "
+		      "USER_INITIATED_ABORT[info=\"BYE\"], "
+		      "PROTOCOL_VIOLATION[info=\"@@\"]]; "
 		"SHUTDOWN[flgs=0x00, cum_tsn=16909060]; "
 		"SHUTDOWN_ACK[flgs=0x00]; "
 		"ERROR[flgs=0x00]; "
diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index 69a8430922c752e81a73b28dfd5c5517966b8dce..950f92a6759c56c0b2e727103ea44ded83cbd48f 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -472,8 +472,12 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 	struct sctp_sack_block_list *sack_block_list;
 	struct sctp_address_type_list_item *address_type_list_item;
 	struct sctp_address_type_list *address_type_list;
+	struct sctp_parameter_type_list_item *parameter_type_list_item;
+	struct sctp_parameter_type_list *parameter_type_list;
 	struct sctp_parameter_list_item *parameter_list_item;
 	struct sctp_parameter_list *parameter_list;
+	struct sctp_cause_list_item *cause_list_item;
+	struct sctp_cause_list *cause_list;
 	struct syscall_spec *syscall;
 	struct command_spec *command;
 	struct code_spec *code;
@@ -516,6 +520,15 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %token <reserved> HOSTNAME_ADDRESS SUPPORTED_ADDRESS_TYPES ECN_CAPABLE
 %token <reserved> ADDR INCR TYPES PARAMS
 %token <reserved> IPV4_TYPE IPV6_TYPE HOSTNAME_TYPE
+%token <reserved> CAUSE
+%token <reserved> CAUSE_CODE CAUSE_INFO
+%token <reserved> INVALID_STREAM_IDENTIFIER MISSING_MANDATORY_PARAMETER
+%token <reserved> STALE_COOKIE_ERROR OUT_OF_RESOURCE
+%token <reserved> UNRESOLVABLE_ADDRESS UNRECOGNIZED_CHUNK_TYPE
+%token <reserved> INVALID_MANDATORY_PARAMETER NO_USER_DATA
+%token <reserved> COOKIE_RECEIVED_WHILE_SHUTDOWN RESTART_WITH_NEW_ADDRESSES
+%token <reserved> USER_INITIATED_ABORT PROTOCOL_VIOLATION
+%token <reserved> STALENESS CHK PARAM UNRECOGNIZED_PARAMETERS
 %token <floating> FLOAT
 %token <integer> INTEGER HEX_INTEGER
 %token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR
@@ -583,17 +596,35 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <parameter_list_item> sctp_supported_address_types_parameter_spec
 %type <parameter_list_item> sctp_ecn_capable_parameter_spec
 %type <parameter_list_item> sctp_pad_parameter_spec
-%type <integer> opt_chunk_type opt_parameter_type
+%type <cause_list> opt_cause_list_spec sctp_cause_list_spec
+%type <cause_list_item> sctp_cause_spec
+%type <cause_list_item> sctp_generic_cause_spec
+%type <cause_list_item> sctp_invalid_stream_identifier_cause_spec
+%type <cause_list_item> sctp_missing_mandatory_parameter_cause_spec
+%type <cause_list_item> sctp_stale_cookie_error_cause_spec
+%type <cause_list_item> sctp_out_of_resources_cause_spec
+%type <cause_list_item> sctp_unresolvable_address_cause_spec
+%type <cause_list_item> sctp_unrecognized_chunk_type_cause_spec
+%type <cause_list_item> sctp_invalid_mandatory_parameter_cause_spec
+%type <cause_list_item> sctp_unrecognized_parameters_cause_spec
+%type <cause_list_item> sctp_no_user_data_cause_spec
+%type <cause_list_item> sctp_cookie_received_while_shutdown_cause_spec
+%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> opt_flags opt_data_flags opt_abort_flags
 %type <integer> opt_shutdown_complete_flags opt_len
 %type <integer> opt_tag opt_a_rwnd opt_os opt_is opt_tsn opt_sid opt_ssn
 %type <integer> opt_cum_tsn opt_ppid
-%type <byte_list> opt_val byte_list
+%type <byte_list> opt_val opt_info byte_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
 %type <address_type_list> address_types_list
 %type <address_type_list_item> address_type
+%type <parameter_type_list> parameter_types_list
+%type <parameter_type_list_item> parameter_type
 
 %%  /* The grammar follows. */
 
@@ -852,6 +883,12 @@ opt_val
 | VAL '=' '[' byte_list ']' { $$ = $4; }
 ;
 
+opt_info
+: CAUSE_INFO '=' ELLIPSIS          { $$ = NULL; }
+| CAUSE_INFO '=' '[' ELLIPSIS ']'  { $$ = NULL; }
+| CAUSE_INFO '=' '[' byte_list ']' { $$ = $4; }
+;
+
 byte_list
 :                    { $$ = sctp_byte_list_new(); }
 | byte               { $$ = sctp_byte_list_new();
@@ -1195,11 +1232,8 @@ sctp_heartbeat_ack_chunk_spec
 }
 
 sctp_abort_chunk_spec
-: ABORT '[' opt_abort_flags ']' {
-	$$ = sctp_abort_chunk_new($3);
-}
-| ABORT '[' opt_abort_flags ',' ELLIPSIS ']' {
-	$$ = sctp_abort_chunk_new($3);
+: ABORT '[' opt_abort_flags opt_cause_list_spec ']' {
+	$$ = sctp_abort_chunk_new($3, $4);
 }
 
 sctp_shutdown_chunk_spec
@@ -1213,11 +1247,8 @@ sctp_shutdown_ack_chunk_spec
 }
 
 sctp_error_chunk_spec
-: ERROR '[' opt_flags ']' {
-	$$ = sctp_error_chunk_new($3);
-}
-| ERROR '[' opt_flags ',' ELLIPSIS ']' {
-	$$ = sctp_error_chunk_new($3);
+: ERROR '[' opt_flags opt_cause_list_spec ']' {
+	$$ = sctp_error_chunk_new($3, $4);
 }
 
 sctp_cookie_echo_chunk_spec
@@ -1282,13 +1313,13 @@ opt_parameter_type
 | TYPE '=' HEX_INTEGER {
 	if (!is_valid_u16($3)) {
 		semantic_error("type value out of range");
-        }
+	}
 	$$ = $3;
 }
 | TYPE '=' INTEGER     {
 	if (!is_valid_u16($3)) {
 		semantic_error("type value out of range");
-        }
+	}
 	$$ = $3;
 }
 ;
@@ -1402,8 +1433,8 @@ address_types_list
 address_type
 : INTEGER       { if (!is_valid_u16($1)) {
                   semantic_error("address type value out of range");
-	          }
-	          $$ = sctp_address_type_list_item_new($1); }
+                  }
+                  $$ = sctp_address_type_list_item_new($1); }
 | IPV4_TYPE     { $$ = sctp_address_type_list_item_new(SCTP_IPV4_ADDRESS_PARAMETER_TYPE); }
 | IPV6_TYPE     { $$ = sctp_address_type_list_item_new(SCTP_IPV6_ADDRESS_PARAMETER_TYPE); }
 | HOSTNAME_TYPE { $$ = sctp_address_type_list_item_new(SCTP_HOSTNAME_ADDRESS_PARAMETER_TYPE); }
@@ -1438,6 +1469,186 @@ sctp_pad_parameter_spec
 	$$ = sctp_pad_parameter_new($5, NULL);
 }
 
+opt_cause_list_spec
+: ',' ELLIPSIS             { $$ = NULL; }
+|                          { $$ = sctp_cause_list_new(); }
+| ',' sctp_cause_list_spec { $$ = $2; }
+;
+
+sctp_cause_list_spec
+: sctp_cause_spec                          { $$ = sctp_cause_list_new();
+                                             sctp_cause_list_append($$, $1); }
+| sctp_cause_list_spec ',' sctp_cause_spec { $$ = $1;
+                                             sctp_cause_list_append($1, $3); }
+;
+
+sctp_cause_spec
+: sctp_generic_cause_spec                        { $$ = $1; }
+| sctp_invalid_stream_identifier_cause_spec      { $$ = $1; }
+| sctp_missing_mandatory_parameter_cause_spec    { $$ = $1; }
+| sctp_stale_cookie_error_cause_spec             { $$ = $1; }
+| sctp_out_of_resources_cause_spec               { $$ = $1; }
+| sctp_unresolvable_address_cause_spec           { $$ = $1; }
+| sctp_unrecognized_chunk_type_cause_spec        { $$ = $1; }
+| sctp_invalid_mandatory_parameter_cause_spec    { $$ = $1; }
+| sctp_unrecognized_parameters_cause_spec        { $$ = $1; }
+| sctp_no_user_data_cause_spec                   { $$ = $1; }
+| sctp_cookie_received_while_shutdown_cause_spec { $$ = $1; }
+| sctp_restart_with_new_addresses_cause_spec     { $$ = $1; }
+| sctp_user_initiated_abort_cause_spec           { $$ = $1; }
+| sctp_protocol_violation_cause_spec             { $$ = $1; }
+;
+
+opt_cause_code
+: CAUSE_CODE '=' ELLIPSIS    { $$ = -1; }
+| CAUSE_CODE '=' HEX_INTEGER {
+	if (!is_valid_u16($3)) {
+		semantic_error("cause value out of range");
+	}
+	$$ = $3;
+}
+| CAUSE_CODE '=' INTEGER     {
+	if (!is_valid_u16($3)) {
+		semantic_error("cause value out of range");
+	}
+	$$ = $3;
+}
+;
+
+sctp_generic_cause_spec
+: CAUSE '[' opt_cause_code ',' opt_len ',' opt_info ']' {
+	if (($5 != -1) && ($5 < sizeof(struct sctp_cause))) {
+		semantic_error("length value out of range");
+	}
+	if (($5 != -1) && ($7 != NULL) &&
+	    ($5 != sizeof(struct sctp_cause) + $7->nr_entries)) {
+		semantic_error("length value incompatible with val");
+	}
+	if (($5 == -1) && ($7 != NULL)) {
+		semantic_error("length needs to be specified");
+	}
+	$$ = sctp_generic_cause_new($3, $5, $7);
+}
+
+sctp_invalid_stream_identifier_cause_spec
+: INVALID_STREAM_IDENTIFIER '[' SID '=' INTEGER ']' {
+	if (!is_valid_u16($5)) {
+		semantic_error("stream identifier out of range");
+	}
+	$$ = sctp_invalid_stream_identifier_cause_new($5);
+}
+| INVALID_STREAM_IDENTIFIER '[' SID '=' ELLIPSIS ']' {
+	$$ = sctp_invalid_stream_identifier_cause_new(-1);
+}
+
+parameter_types_list
+:                                         { $$ = sctp_parameter_type_list_new(); }
+| parameter_type                          { $$ = sctp_parameter_type_list_new();
+                                            sctp_parameter_type_list_append($$, $1); }
+| parameter_types_list ',' parameter_type { $$ = $1;
+                                            sctp_parameter_type_list_append($1, $3); }
+;
+
+parameter_type
+: INTEGER       { if (!is_valid_u16($1)) {
+                  semantic_error("parameter type value out of range");
+                  }
+                  $$ = sctp_parameter_type_list_item_new($1); }
+;
+
+sctp_missing_mandatory_parameter_cause_spec
+: MISSING_MANDATORY_PARAMETER '[' TYPES '=' ELLIPSIS ']' {
+	$$ = sctp_missing_mandatory_parameter_cause_new(NULL);
+}
+| MISSING_MANDATORY_PARAMETER '[' TYPES '=' '[' parameter_types_list ']' ']' {
+	$$ = sctp_missing_mandatory_parameter_cause_new($6);
+}
+
+sctp_stale_cookie_error_cause_spec
+: STALE_COOKIE_ERROR '[' STALENESS '=' INTEGER ']' {
+	if (!is_valid_u32($5)) {
+		semantic_error("staleness out of range");
+	}
+	$$ = sctp_stale_cookie_error_cause_new($5);
+}
+| STALE_COOKIE_ERROR '[' STALENESS '=' ELLIPSIS ']' {
+	$$ = sctp_stale_cookie_error_cause_new(-1);
+}
+
+sctp_out_of_resources_cause_spec
+: OUT_OF_RESOURCE '[' ']' {
+	$$ = sctp_out_of_resources_cause_new();
+}
+
+sctp_unresolvable_address_cause_spec
+: UNRESOLVABLE_ADDRESS '[' PARAM '=' sctp_parameter_spec ']' {
+	$$ = sctp_unresolvable_address_cause_new($5);
+}
+| UNRESOLVABLE_ADDRESS '[' PARAM '=' ELLIPSIS ']' {
+	$$ = sctp_unresolvable_address_cause_new(NULL);
+}
+
+sctp_unrecognized_chunk_type_cause_spec
+: UNRECOGNIZED_CHUNK_TYPE '[' CHK '=' sctp_chunk_spec ']' {
+	$$ = sctp_unrecognized_chunk_type_cause_new($5);
+}
+| UNRECOGNIZED_CHUNK_TYPE '[' CHK '=' ELLIPSIS ']' {
+	$$ = sctp_unrecognized_chunk_type_cause_new(NULL);
+}
+
+sctp_invalid_mandatory_parameter_cause_spec
+: INVALID_MANDATORY_PARAMETER '[' ']' {
+	$$ = sctp_invalid_mandatory_parameter_cause_new();
+}
+
+sctp_unrecognized_parameters_cause_spec
+: UNRECOGNIZED_PARAMETERS '[' PARAMS '=' '[' sctp_parameter_list_spec ']' ']' {
+	$$ = sctp_unrecognized_parameters_cause_new($6);
+}
+| UNRECOGNIZED_PARAMETERS '[' PARAMS '=' ELLIPSIS ']' {
+	$$ = sctp_unrecognized_parameters_cause_new(NULL);
+}
+
+sctp_no_user_data_cause_spec
+: NO_USER_DATA '[' TSN '=' INTEGER ']' {
+	if (!is_valid_u32($5)) {
+		semantic_error("tsn out of range");
+	}
+	$$ = sctp_no_user_data_cause_new($5);
+}
+| NO_USER_DATA '[' TSN '=' ELLIPSIS ']' {
+	$$ = sctp_no_user_data_cause_new(-1);
+}
+
+sctp_cookie_received_while_shutdown_cause_spec
+: COOKIE_RECEIVED_WHILE_SHUTDOWN '[' ']' {
+	$$ = sctp_cookie_received_while_shutdown_cause_new();
+}
+
+sctp_restart_with_new_addresses_cause_spec
+: RESTART_WITH_NEW_ADDRESSES '[' PARAMS '=' '[' sctp_parameter_list_spec ']' ']' {
+	$$ = sctp_restart_with_new_addresses_cause_new($6);
+}
+| RESTART_WITH_NEW_ADDRESSES '[' PARAMS '=' ELLIPSIS ']' {
+	$$ = sctp_restart_with_new_addresses_cause_new(NULL);
+}
+
+sctp_user_initiated_abort_cause_spec
+: USER_INITIATED_ABORT '[' CAUSE_INFO '=' STRING ']' {
+	$$ = sctp_user_initiated_abort_cause_new($5);
+}
+| USER_INITIATED_ABORT '[' CAUSE_INFO '=' ELLIPSIS ']' {
+	$$ = sctp_user_initiated_abort_cause_new(NULL);
+}
+
+sctp_protocol_violation_cause_spec
+: PROTOCOL_VIOLATION '[' CAUSE_INFO '=' STRING ']' {
+	$$ = sctp_protocol_violation_cause_new($5);
+}
+| PROTOCOL_VIOLATION '[' CAUSE_INFO '=' ELLIPSIS ']' {
+	$$ = sctp_protocol_violation_cause_new(NULL);
+}
+
 tcp_packet_spec
 : packet_prefix opt_ip_info flags seq opt_ack opt_window opt_tcp_options {
 	char *error = NULL;
diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c
index 78222d6643d23dc000e3b30de441a5c0ff52025b..5284d7db234a242c262392a0e44bde542e540101 100644
--- a/gtests/net/packetdrill/run_packet.c
+++ b/gtests/net/packetdrill/run_packet.c
@@ -149,12 +149,12 @@ static struct socket *find_socket_for_live_packet(
 {
 	struct socket *socket = state->socket_under_test;	/* shortcut */
 
+	DEBUGP("find_connect_for_live_packet\n");
 	if (socket == NULL)
 		return NULL;
 
 	struct tuple packet_tuple, live_outbound, live_inbound;
 	get_packet_tuple(packet, &packet_tuple);
-
 	/* Is packet inbound to the socket under test? */
 	socket_get_inbound(&socket->live, &live_inbound);
 	if (is_equal_tuple(&packet_tuple, &live_inbound)) {
@@ -1083,7 +1083,7 @@ static int verify_sctp_parameters(u8 *begin, u16 length,
 		                    ntohs(actual_parameter->type),
 		                    error)) ||
 		    (flags & FLAG_PARAMETER_LENGTH_NOCHECK ? STATUS_OK :
-		        check_field("sctp_chunk_length",
+		        check_field("sctp_parameter_length",
 		                    ntohs(script_parameter->length),
 		                    ntohs(actual_parameter->length),
 		                    error))) {
@@ -1113,6 +1113,71 @@ static int verify_sctp_parameters(u8 *begin, u16 length,
 	return STATUS_OK;
 }
 
+static int verify_sctp_causes(struct sctp_chunk *chunk, u16 offset,
+                              struct sctp_chunk_list_item *script_chunk_item,
+                              char **error)
+{
+	struct sctp_causes_iterator iter;
+	struct sctp_cause *actual_cause;
+	struct sctp_cause *script_cause;
+	struct sctp_cause_list_item *script_cause_item;
+	u32 flags;
+
+	for (actual_cause = sctp_causes_begin(chunk, offset, &iter, error),
+	     script_cause_item = script_chunk_item->cause_list->first;
+	     actual_cause != NULL && script_cause_item != NULL;
+	     actual_cause = sctp_causes_next(&iter, error),
+	     script_cause_item = script_cause_item->next) {
+		if (*error != NULL) {
+			DEBUGP("Error during iteration\n");
+			return STATUS_ERR;
+		}
+		script_cause = script_cause_item->cause;
+		flags = script_cause_item->flags;
+		assert(script_cause != NULL);
+		DEBUGP("script cause: code 0x%04x, length %05d\n",
+		       ntohs(script_cause->code),
+		       ntohs(script_cause->length));
+		DEBUGP("actual cause: code 0x%04x, length %05d\n",
+		       ntohs(actual_cause->code),
+		       ntohs(actual_cause->length));
+		DEBUGP("flags: %08x\n", flags);
+		if ((flags & FLAG_CAUSE_CODE_NOCHECK ? STATUS_OK :
+		        check_field("sctp_cause_code",
+		                    ntohs(script_cause->code),
+		                    ntohs(actual_cause->code),
+		                    error)) ||
+		    (flags & FLAG_CAUSE_LENGTH_NOCHECK ? STATUS_OK :
+		        check_field("sctp_cause_length",
+		                    ntohs(script_cause->length),
+		                    ntohs(actual_cause->length),
+		                    error))) {
+			return STATUS_ERR;
+		}
+		if ((flags & FLAG_CAUSE_INFORMATION_NOCHECK) == 0) {
+			assert((flags & FLAG_CAUSE_LENGTH_NOCHECK) == 0);
+			if (memcmp(script_cause->information,
+			           actual_cause->information,
+			           ntohs(actual_cause->length) - sizeof(struct sctp_cause))) {
+				asprintf(error, "live packet cause information not as expected");
+				return STATUS_ERR;
+			}
+		}
+	}
+	if (actual_cause != NULL) {
+		DEBUGP("actual chunk contains more causes than script chunk\n");
+	}
+	if (script_cause_item != NULL) {
+		DEBUGP("script chunk contains more causes than actual chunk\n");
+	}
+	if ((actual_cause != NULL) || (script_cause_item != NULL)) {
+		asprintf(error,
+		         "live chunk and expected chunk have not the same number of causes");
+		return STATUS_ERR;
+	}
+	return STATUS_OK;
+}
+
 static int verify_data_chunk(struct sctp_data_chunk *actual_chunk,
                              struct sctp_data_chunk *script_chunk,
                              u32 flags, char **error)
@@ -1349,11 +1414,17 @@ static int verify_heartbeat_ack_chunk(struct sctp_heartbeat_ack_chunk *actual_ch
 }
 
 static int verify_abort_chunk(struct sctp_abort_chunk *actual_chunk,
-                              struct sctp_abort_chunk *script_chunk,
-                              u32 flags, char **error)
+                              struct sctp_chunk_list_item *script_chunk_item,
+                              char **error)
 {
-	/* FIXME: Validate causes */
-	return STATUS_OK;
+	u32 flags;
+
+	assert(ntohs(actual_chunk->length) >= sizeof(struct sctp_abort_chunk));
+	flags = script_chunk_item->flags;
+	return (flags & FLAG_ABORT_CHUNK_OPT_CAUSES_NOCHECK ? STATUS_OK :
+	    verify_sctp_causes((struct sctp_chunk *)actual_chunk,
+	                       sizeof(struct sctp_error_chunk),
+		               script_chunk_item, error));
 }
 
 static int verify_shutdown_chunk(struct sctp_shutdown_chunk *actual_chunk,
@@ -1376,11 +1447,17 @@ static int verify_shutdown_ack_chunk(struct sctp_shutdown_ack_chunk *actual_chun
 }
 
 static int verify_error_chunk(struct sctp_error_chunk *actual_chunk,
-                              struct sctp_error_chunk *script_chunk,
-                              u32 flags, char **error)
+                              struct sctp_chunk_list_item *script_chunk_item,
+                              char **error)
 {
-	/* FIXME: Validate causes */
-	return STATUS_OK;
+	u32 flags;
+
+	assert(ntohs(actual_chunk->length) >= sizeof(struct sctp_error_chunk));
+	flags = script_chunk_item->flags;
+	return (flags & FLAG_ERROR_CHUNK_OPT_CAUSES_NOCHECK ? STATUS_OK :
+	    verify_sctp_causes((struct sctp_chunk *)actual_chunk,
+	                       sizeof(struct sctp_error_chunk),
+		               script_chunk_item, error));
 }
 
 static int verify_cookie_echo_chunk(struct sctp_cookie_echo_chunk *actual_chunk,
@@ -1540,8 +1617,7 @@ static int verify_sctp(
 			break;
 		case SCTP_ABORT_CHUNK_TYPE:
 			result = verify_abort_chunk((struct sctp_abort_chunk *)actual_chunk,
-			                            (struct sctp_abort_chunk *)script_chunk,
-			                            flags, error);
+			                            script_chunk_item, error);
 			break;
 		case SCTP_SHUTDOWN_CHUNK_TYPE:
 			result = verify_shutdown_chunk((struct sctp_shutdown_chunk *)actual_chunk,
@@ -1555,8 +1631,7 @@ static int verify_sctp(
 			break;
 		case SCTP_ERROR_CHUNK_TYPE:
 			result = verify_error_chunk((struct sctp_error_chunk *)actual_chunk,
-			                            (struct sctp_error_chunk *)script_chunk,
-			                            flags, error);
+			                            script_chunk_item, error);
 			break;
 		case SCTP_COOKIE_ECHO_CHUNK_TYPE:
 			result = verify_cookie_echo_chunk((struct sctp_cookie_echo_chunk *)actual_chunk,
@@ -2546,6 +2621,7 @@ int abort_association(struct state *state, struct socket *socket)
 	struct sctp_chunk_list *chunk_list;
 	struct tuple live_inbound;
 	int result = STATUS_OK;
+	s64 flgs;
 
 	if ((socket->live.local_initiate_tag == 0) &&
 	    (socket->live.remote_initiate_tag == 0)) {
@@ -2553,10 +2629,12 @@ int abort_association(struct state *state, struct socket *socket)
 	}
 	chunk_list = sctp_chunk_list_new();
 	if (socket->live.local_initiate_tag != 0) {
-		sctp_chunk_list_append(chunk_list, sctp_abort_chunk_new(0));
+		flgs = 0;
 	} else {
-		sctp_chunk_list_append(chunk_list, sctp_abort_chunk_new(SCTP_ABORT_CHUNK_T_BIT));
+		flgs = SCTP_ABORT_CHUNK_T_BIT;
 	}
+	/* XXX Provide an error cause */
+	sctp_chunk_list_append(chunk_list, sctp_abort_chunk_new(flgs, sctp_cause_list_new()));
 	packet = new_sctp_packet(socket->address_family,
 				 DIRECTION_INBOUND, ECN_NONE,
 				 chunk_list, &error);
diff --git a/gtests/net/packetdrill/sctp.h b/gtests/net/packetdrill/sctp.h
index b4e36e2438ad441da4886aaa8685cf0959e9cf88..177735b2dccaecdc834d1a816d03ceddafe209a9 100644
--- a/gtests/net/packetdrill/sctp.h
+++ b/gtests/net/packetdrill/sctp.h
@@ -291,12 +291,12 @@ struct sctp_pad_parameter {
 } __packed;
 
 #define SCTP_INVALID_STREAM_IDENTIFIER_CAUSE_CODE	0x0001
-#define SCTP_MISSING_MADATORY_PARAMETER_CAUSE_CODE	0x0002
+#define SCTP_MISSING_MANDATORY_PARAMETER_CAUSE_CODE	0x0002
 #define SCTP_STALE_COOKIE_ERROR_CAUSE_CODE		0x0003
 #define SCTP_OUT_OF_RESOURCES_CAUSE_CODE		0x0004
 #define SCTP_UNRESOLVABLE_ADDRESS_CAUSE_CODE		0x0005
 #define SCTP_UNRECOGNIZED_CHUNK_TYPE_CAUSE_CODE		0x0006
-#define SCTP_INVALID_MADATORY_PARAMETER_CAUSE_CODE	0x0007
+#define SCTP_INVALID_MANDATORY_PARAMETER_CAUSE_CODE	0x0007
 #define SCTP_UNRECOGNIZED_PARAMETERS_CAUSE_CODE		0x0008
 #define SCTP_NO_USER_DATA_CAUSE_CODE			0x0009
 #define SCTP_COOKIE_RECEIVED_WHILE_SHUTDOWN_CAUSE_CODE	0x000a
@@ -304,6 +304,8 @@ struct sctp_pad_parameter {
 #define SCTP_USER_INITIATED_ABORT_CAUSE_CODE		0x000c
 #define SCTP_PROTOCOL_VIOLATION_CAUSE_CODE		0x000d
 
+#define MAX_SCTP_CAUSE_BYTES	0xffff
+
 struct sctp_cause {
 	__be16 code;
 	__be16 length;
diff --git a/gtests/net/packetdrill/sctp_chunk_to_string.c b/gtests/net/packetdrill/sctp_chunk_to_string.c
index 993bb94d46a485031d7b7759ff07df04834e34c9..59c246a06ed35800c8c189222b11c4446b2f0a56 100644
--- a/gtests/net/packetdrill/sctp_chunk_to_string.c
+++ b/gtests/net/packetdrill/sctp_chunk_to_string.c
@@ -151,11 +151,11 @@ static int sctp_hostname_parameter_to_string(
 
 	length = ntohs(parameter->length);
 	if (length < sizeof(struct sctp_hostname_address_parameter)) {
-		asprintf(error, "HOSTNAME parameter illegal (length=%u)",
+		asprintf(error, "HOSTNAME_ADDRESS parameter illegal (length=%u)",
 			 length);
 		return STATUS_ERR;
 	}
-	fprintf(s, "HOSTNAME[addr=\"%.*s\"]",
+	fprintf(s, "HOSTNAME_ADDRESS[addr=\"%.*s\"]",
 		(int)(length - sizeof(struct sctp_hostname_address_parameter)),
 		(char *)parameter->hostname);
 	return STATUS_OK;
@@ -355,7 +355,7 @@ static int sctp_missing_mandatory_parameter_cause_to_string(
 		asprintf(error, "MISSING_MANDATORY_PARAMETER inconsistent");
 		return STATUS_ERR;
 	}
-	fputs("MISSING_MANDATORY_PARAMETER[", s);
+	fputs("MISSING_MANDATORY_PARAMETER[types=[", s);
 	for (i = 0; i < nr_parameters; i++) {
 		if (i > 0)
 			fputs(", ", s);
@@ -389,7 +389,7 @@ static int sctp_missing_mandatory_parameter_cause_to_string(
 			break;
 		}
 	}
-	fputc(']', s);
+	fputs("]]", s);
 	return STATUS_OK;
 }
 
@@ -456,7 +456,7 @@ static int sctp_unresolvable_address_cause_to_string(
 		asprintf(error, "UNRESOLVABLE_ADDRESS cause inconsistent");
 		return STATUS_ERR;
 	}
-	fputs("UNRESOLVABLE_ADDRESS[", s);
+	fputs("UNRESOLVABLE_ADDRESS[param=", s);
 	result = sctp_parameter_to_string(s, parameter, error);
 	fputc(']', s);
 	return result;
@@ -492,7 +492,7 @@ static int sctp_unrecognized_chunk_type_cause_to_string(
 		asprintf(error, "UNRECOGNIZED_CHUNK cause inconsistent");
 		return STATUS_ERR;
 	}
-	fputs("UNRECOGNIZED_CHUNK[", s);
+	fputs("UNRECOGNIZED_CHUNK[chk=", s);
 	result = sctp_chunk_to_string(s, chunk, error);
 	fputc(']', s);
 	return result;
@@ -644,7 +644,7 @@ static int sctp_user_initiated_abort_cause_to_string(
 			 length);
 		return STATUS_ERR;
 	}
-	fprintf(s, "USER_INITIATED_ABORT[%.*s]",
+	fprintf(s, "USER_INITIATED_ABORT[info=\"%.*s\"]",
 		(int)(length - sizeof(struct sctp_user_initiated_abort_cause)),
 		(char *)cause->information);
 	return STATUS_OK;
@@ -663,7 +663,7 @@ static int sctp_protocol_violation_cause_to_string(
 			 length);
 		return STATUS_ERR;
 	}
-	fprintf(s, "PROTOCOL_VIOLATION[%.*s]",
+	fprintf(s, "PROTOCOL_VIOLATION[info=\"%.*s\"]",
 		(int)(length - sizeof(struct sctp_protocol_violation_cause)),
 		(char *)cause->information);
 	return STATUS_OK;
@@ -703,7 +703,7 @@ static int sctp_cause_to_string(FILE *s, struct sctp_cause *cause, char **error)
 			(struct sctp_invalid_stream_identifier_cause *)cause,
 			error);
 		break;
-	case SCTP_MISSING_MADATORY_PARAMETER_CAUSE_CODE:
+	case SCTP_MISSING_MANDATORY_PARAMETER_CAUSE_CODE:
 		result = sctp_missing_mandatory_parameter_cause_to_string(s,
 			(struct sctp_missing_mandatory_parameter_cause *)cause,
 			error);
@@ -725,7 +725,7 @@ static int sctp_cause_to_string(FILE *s, struct sctp_cause *cause, char **error)
 			(struct sctp_unrecognized_chunk_type_cause *)cause,
 			error);
 		break;
-	case SCTP_INVALID_MADATORY_PARAMETER_CAUSE_CODE:
+	case SCTP_INVALID_MANDATORY_PARAMETER_CAUSE_CODE:
 		result = sctp_invalid_mandatory_parameter_cause_to_string(s,
 			(struct sctp_invalid_mandatory_parameter_cause *)cause,
 			error);
diff --git a/gtests/net/packetdrill/sctp_iterator.c b/gtests/net/packetdrill/sctp_iterator.c
index b4df6d5c735f7384edf2aa1aae8d3d021bd75ac1..059f244574c9740412519fc9643010fe07ab844b 100644
--- a/gtests/net/packetdrill/sctp_iterator.c
+++ b/gtests/net/packetdrill/sctp_iterator.c
@@ -72,6 +72,7 @@ struct sctp_chunk *sctp_chunks_next(struct sctp_chunks_iterator *iter,
 	u16 chunk_length, padding_length;
 	struct sctp_chunk *current_chunk;
 
+	if (*error) printf("!!!%s!!!\n", *error);
 	assert(*error == NULL);
 	current_chunk = (struct sctp_chunk *)iter->current_chunk;
 	chunk_length = ntohs(current_chunk->length);
diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c
index f123d542788dfdbbf9cfa9d0aa0a1ee4fd12ea55..8f8b3407181a3b2fb869862ea87c95d6d0864889 100644
--- a/gtests/net/packetdrill/sctp_packet.c
+++ b/gtests/net/packetdrill/sctp_packet.c
@@ -234,9 +234,73 @@ sctp_address_type_list_item_new(u16 address_type)
 	return item;
 }
 
+struct sctp_parameter_type_list *
+sctp_parameter_type_list_new(void)
+{
+	struct sctp_parameter_type_list *list;
+
+	list = malloc(sizeof(struct sctp_parameter_type_list));
+	assert(list != NULL);
+	list->first = NULL;
+	list->last = NULL;
+	list->nr_entries = 0;
+	return list;
+}
+
+void
+sctp_parameter_type_list_append(struct sctp_parameter_type_list *list,
+			        struct sctp_parameter_type_list_item *item)
+{
+	assert(item->next == NULL);
+	if (list->last == NULL) {
+		assert(list->first == NULL);
+		assert(list->nr_entries == 0);
+		list->first = item;
+	} else {
+		assert(list->first != NULL);
+		list->last->next = item;
+	}
+	list->last = item;
+	list->nr_entries++;
+}
+
+void
+sctp_parameter_type_list_free(struct sctp_parameter_type_list *list)
+{
+	struct sctp_parameter_type_list_item *current_item, *next_item;
+
+	if (list == NULL) {
+		return;
+	}
+	current_item = list->first;
+	while (current_item != NULL) {
+		assert(list->nr_entries > 0);
+		next_item = current_item->next;
+		assert(next_item != NULL || current_item == list->last);
+		free(current_item);
+		current_item = next_item;
+		list->nr_entries--;
+	}
+	assert(list->nr_entries == 0);
+	free(list);
+}
+
+struct sctp_parameter_type_list_item *
+sctp_parameter_type_list_item_new(u16 parameter_type)
+{
+	struct sctp_parameter_type_list_item *item;
+
+	item = malloc(sizeof(struct sctp_parameter_type_list_item));
+	assert(item != NULL);
+	item->next = NULL;
+	item->parameter_type = parameter_type;
+	return item;
+}
+
 struct sctp_chunk_list_item *
 sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags,
-                         struct sctp_parameter_list *list)
+                         struct sctp_parameter_list *parameter_list,
+                         struct sctp_cause_list *cause_list)
 {
 	struct sctp_chunk_list_item *item;
 
@@ -244,7 +308,8 @@ sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags,
 	assert(item != NULL);
 	item->next = NULL;
 	item->chunk = chunk;
-	item->parameter_list = list;
+	item->parameter_list = parameter_list;
+	item->cause_list = cause_list;
 	item->length = length;
 	item->flags = flags;
 	return item;
@@ -301,7 +366,9 @@ sctp_generic_chunk_new(s64 type, s64 flgs, s64 len,
 	       0, padding_length);
 	return sctp_chunk_list_item_new(chunk,
 	                                length + padding_length,
-	                                flags, sctp_parameter_list_new());
+	                                flags,
+	                                sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -363,7 +430,8 @@ sctp_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 ssn, s64 ppid)
 	       length + padding_length - sizeof(struct sctp_data_chunk));
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                length, flags,
-	                                sctp_parameter_list_new());
+	                                sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -446,7 +514,7 @@ sctp_init_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn,
 	}
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                chunk_length + chunk_padding_length,
-	                                flags, list);
+	                                flags, list, sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -529,7 +597,7 @@ sctp_init_ack_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn,
 	}
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                chunk_length + chunk_padding_length,
-	                                flags, list);
+	                                flags, list, sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -607,7 +675,8 @@ sctp_sack_chunk_new(s64 flgs, s64 cum_tsn, s64 a_rwnd,
 	}
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                length, flags,
-	                                sctp_parameter_list_new());
+	                                sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -653,7 +722,8 @@ sctp_heartbeat_chunk_new(s64 flgs, struct sctp_parameter_list_item *info)
 	free(info);
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                chunk_length + padding_length,
-	                                flags, sctp_parameter_list_new());
+	                                flags, sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -699,17 +769,32 @@ sctp_heartbeat_ack_chunk_new(s64 flgs, struct sctp_parameter_list_item *info)
 	free(info);
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                chunk_length + padding_length,
-	                                flags, sctp_parameter_list_new());
+	                                flags, sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
-sctp_abort_chunk_new(s64 flgs)
+sctp_abort_chunk_new(s64 flgs, struct sctp_cause_list *list)
 {
 	struct sctp_abort_chunk *chunk;
+	struct sctp_cause_list_item *item;
 	u32 flags;
+	u16 offset, chunk_length, chunk_padding_length, cause_padding_length;
 
-	flags = FLAG_CHUNK_LENGTH_NOCHECK | FLAG_CHUNK_VALUE_NOCHECK;
-	chunk = malloc(sizeof(struct sctp_abort_chunk));
+	flags = 0;
+	chunk_length = sizeof(struct sctp_abort_chunk);
+	if (list != NULL) {
+		chunk_length += list->length;
+	} else {
+		flags |= FLAG_CHUNK_LENGTH_NOCHECK;
+		flags |= FLAG_ERROR_CHUNK_OPT_CAUSES_NOCHECK;
+		list = sctp_cause_list_new();
+	}
+	chunk_padding_length = chunk_length % 4;
+	if (chunk_padding_length > 0) {
+		chunk_padding_length = 4 - chunk_padding_length;
+	}
+	chunk = malloc(chunk_length + chunk_padding_length);
 	assert(chunk != NULL);
 	chunk->type = SCTP_ABORT_CHUNK_TYPE;
 	if (flgs == -1) {
@@ -718,10 +803,30 @@ sctp_abort_chunk_new(s64 flgs)
 	} else {
 		chunk->flags = (u8)flgs;
 	}
-	chunk->length = htons(sizeof(struct sctp_abort_chunk));
+	chunk->length = htons(chunk_length);
+	offset = 0;
+	for (item = list->first; item != NULL; item = item->next) {
+		cause_padding_length = item->length % 4;
+		if (cause_padding_length > 0) {
+			cause_padding_length = 4 - cause_padding_length;
+		}
+		memcpy(chunk->cause + offset,
+		       item->cause,
+		       item->length + cause_padding_length);
+		free(item->cause);
+		item->cause = (struct sctp_cause *)(chunk->cause + offset);
+		if ((item->flags & FLAG_CAUSE_CODE_NOCHECK) ||
+		    (item->flags & FLAG_CAUSE_INFORMATION_NOCHECK)) {
+			flags |= FLAG_CHUNK_VALUE_NOCHECK;
+		}
+		if (item->flags & FLAG_CAUSE_LENGTH_NOCHECK) {
+			flags |= FLAG_CHUNK_LENGTH_NOCHECK;
+		}
+		offset += item->length + cause_padding_length;
+	}
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
-	                                (u32)sizeof(struct sctp_abort_chunk),
-	                                flags, sctp_parameter_list_new());
+	                                chunk_length + chunk_padding_length,
+	                                flags, sctp_parameter_list_new(), list);
 }
 
 struct sctp_chunk_list_item *
@@ -750,7 +855,8 @@ sctp_shutdown_chunk_new(s64 flgs, s64 cum_tsn)
 
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                (u32)sizeof(struct sctp_shutdown_chunk),
-	                                flags, sctp_parameter_list_new());
+	                                flags, sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -772,17 +878,32 @@ sctp_shutdown_ack_chunk_new(s64 flgs)
 	chunk->length = htons(sizeof(struct sctp_shutdown_ack_chunk));
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                (u32)sizeof(struct sctp_shutdown_ack_chunk),
-	                                flags, sctp_parameter_list_new());
+	                                flags, sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
-sctp_error_chunk_new(s64 flgs)
+sctp_error_chunk_new(s64 flgs, struct sctp_cause_list *list)
 {
 	struct sctp_error_chunk *chunk;
+	struct sctp_cause_list_item *item;
 	u32 flags;
+	u16 offset, chunk_length, chunk_padding_length, cause_padding_length;
 
-	flags = FLAG_CHUNK_LENGTH_NOCHECK | FLAG_CHUNK_VALUE_NOCHECK;
-	chunk = malloc(sizeof(struct sctp_error_chunk));
+	flags = 0;
+	chunk_length = sizeof(struct sctp_error_chunk);
+	if (list != NULL) {
+		chunk_length += list->length;
+	} else {
+		flags |= FLAG_CHUNK_LENGTH_NOCHECK;
+		flags |= FLAG_ERROR_CHUNK_OPT_CAUSES_NOCHECK;
+		list = sctp_cause_list_new();
+	}
+	chunk_padding_length = chunk_length % 4;
+	if (chunk_padding_length > 0) {
+		chunk_padding_length = 4 - chunk_padding_length;
+	}
+	chunk = malloc(chunk_length + chunk_padding_length);
 	assert(chunk != NULL);
 	chunk->type = SCTP_ERROR_CHUNK_TYPE;
 	if (flgs == -1) {
@@ -791,10 +912,30 @@ sctp_error_chunk_new(s64 flgs)
 	} else {
 		chunk->flags = (u8)flgs;
 	}
-	chunk->length = htons(sizeof(struct sctp_error_chunk));
+	chunk->length = htons(chunk_length);
+	offset = 0;
+	for (item = list->first; item != NULL; item = item->next) {
+		cause_padding_length = item->length % 4;
+		if (cause_padding_length > 0) {
+			cause_padding_length = 4 - cause_padding_length;
+		}
+		memcpy(chunk->cause + offset,
+		       item->cause,
+		       item->length + cause_padding_length);
+		free(item->cause);
+		item->cause = (struct sctp_cause *)(chunk->cause + offset);
+		if ((item->flags & FLAG_CAUSE_CODE_NOCHECK) ||
+		    (item->flags & FLAG_CAUSE_INFORMATION_NOCHECK)) {
+			flags |= FLAG_CHUNK_VALUE_NOCHECK;
+		}
+		if (item->flags & FLAG_CAUSE_LENGTH_NOCHECK) {
+			flags |= FLAG_CHUNK_LENGTH_NOCHECK;
+		}
+		offset += item->length + cause_padding_length;
+	}
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
-	                                (u32)sizeof(struct sctp_error_chunk),
-	                                flags, sctp_parameter_list_new());
+	                                chunk_length + chunk_padding_length,
+	                                flags, sctp_parameter_list_new(), list);
 }
 
 struct sctp_chunk_list_item *
@@ -839,7 +980,8 @@ sctp_cookie_echo_chunk_new(s64 flgs, s64 len, u8* cookie)
 	memset(chunk->cookie + cookie_length, 0, padding_length);
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                chunk_length + padding_length,
-	                                flags, sctp_parameter_list_new());
+	                                flags, sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -861,7 +1003,8 @@ sctp_cookie_ack_chunk_new(s64 flgs)
 	chunk->length = htons(sizeof(struct sctp_cookie_ack_chunk));
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                (u32)sizeof(struct sctp_cookie_ack_chunk),
-	                                flags, sctp_parameter_list_new());
+	                                flags, sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -890,7 +1033,8 @@ sctp_ecne_chunk_new(s64 flgs, s64 lowest_tsn)
 
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                (u32)sizeof(struct sctp_ecne_chunk),
-	                                flags, sctp_parameter_list_new());
+	                                flags, sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -919,7 +1063,8 @@ sctp_cwr_chunk_new(s64 flgs, s64 lowest_tsn)
 
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                (u32)sizeof(struct sctp_cwr_chunk),
-	                                flags, sctp_parameter_list_new());
+	                                flags, sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -941,7 +1086,8 @@ sctp_shutdown_complete_chunk_new(s64 flgs)
 	chunk->length = htons(sizeof(struct sctp_shutdown_complete_chunk));
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                (u32)sizeof(struct sctp_shutdown_complete_chunk),
-	                                flags, sctp_parameter_list_new());
+	                                flags, sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list_item *
@@ -986,7 +1132,8 @@ sctp_pad_chunk_new(s64 flgs, s64 len, u8* padding)
 	memset(chunk->padding_data + padding_length, 0, chunk_padding_length);
 	return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
 	                                chunk_length + chunk_padding_length,
-	                                flags, sctp_parameter_list_new());
+	                                flags, sctp_parameter_list_new(),
+	                                sctp_cause_list_new());
 }
 
 struct sctp_chunk_list *
@@ -1031,6 +1178,8 @@ sctp_chunk_list_free(struct sctp_chunk_list *list)
 		assert(next_item != NULL || current_item == list->last);
 		assert(current_item->parameter_list);
 		sctp_parameter_list_free(current_item->parameter_list);
+		assert(current_item->cause_list);
+		sctp_cause_list_free(current_item->cause_list);
 		free(current_item);
 		current_item = next_item;
 	}
@@ -1064,7 +1213,7 @@ sctp_generic_parameter_new(s64 type, s64 len, struct sctp_byte_list *bytes)
 		flags |= FLAG_PARAMETER_VALUE_NOCHECK;
 	}
 	if (len == -1) {
-		parameter_length = (u16)sizeof(struct sctp_chunk);
+		parameter_length = (u16)sizeof(struct sctp_parameter);
 		flags |= FLAG_PARAMETER_LENGTH_NOCHECK;
 	} else {
 		parameter_length = (u16)len;
@@ -1474,6 +1623,528 @@ sctp_parameter_list_free(struct sctp_parameter_list *list)
 	free(list);
 }
 
+struct sctp_cause_list_item *
+sctp_cause_list_item_new(struct sctp_cause *cause, u32 length, u32 flags)
+{
+	struct sctp_cause_list_item *item;
+
+	item = malloc(sizeof(struct sctp_cause_list_item));
+	assert(item != NULL);
+	item->next = NULL;
+	item->cause = cause;
+	item->length = length;
+	item->flags = flags;
+	return item;
+}
+
+struct sctp_cause_list_item *
+sctp_generic_cause_new(s64 code, s64 len, struct sctp_byte_list *bytes)
+{
+	struct sctp_cause *cause;
+	struct sctp_byte_list_item *item;
+	u32 flags;
+	u16 cause_length, information_length, padding_length, i;
+
+	flags = 0;
+	if (bytes == NULL) {
+		flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+	}
+	if (len == -1) {
+		cause_length = (u16)sizeof(struct sctp_cause);
+		flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+	} else {
+		cause_length = (u16)len;
+	}
+	information_length = cause_length - sizeof(struct sctp_cause);
+	padding_length = cause_length % 4;
+	if (padding_length > 0) {
+		padding_length = 4 - padding_length;
+	}
+	cause = malloc(cause_length + padding_length);
+	assert(cause != NULL);
+	if (code == -1) {
+		cause->code = 0;
+		flags |= FLAG_CAUSE_CODE_NOCHECK;
+	} else {
+		cause->code = htons((u16)code);
+	}
+	cause->length = htons(cause_length);
+	if (bytes != NULL) {
+		for (i = 0, item = bytes->first;
+		     item != NULL;
+		     i++, item = item->next) {
+			cause->information[i] = item->byte;
+		}
+	} else {
+		memset(cause->information, 0, information_length);
+	}
+	/* Clear the padding */
+	memset(cause->information + information_length, 0, padding_length);
+	return sctp_cause_list_item_new(cause, cause_length, flags);
+}
+
+struct sctp_cause_list_item *
+sctp_invalid_stream_identifier_cause_new(s64 sid)
+{
+	struct sctp_invalid_stream_identifier_cause *cause;
+	u32 flags;
+
+	flags = 0;
+	cause = malloc(sizeof(struct sctp_invalid_stream_identifier_cause));
+	assert(cause != NULL);
+	cause->code = htons(SCTP_INVALID_STREAM_IDENTIFIER_CAUSE_CODE);
+	cause->length = htons(sizeof(struct sctp_invalid_stream_identifier_cause));
+	if (sid == -1) {
+		cause->sid = htonl(0);
+		flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+	} else {
+		assert(is_valid_u16(sid));
+		cause->sid = htons((u16)sid);
+	}
+	cause->reserved = htons(0);
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                sizeof(struct sctp_invalid_stream_identifier_cause),
+	                                flags);
+}
+
+struct sctp_cause_list_item *
+sctp_missing_mandatory_parameter_cause_new(struct sctp_parameter_type_list *list)
+{
+	struct sctp_missing_mandatory_parameter_cause *cause;
+
+	u32 flags;
+	u16 i, cause_length, padding_length;
+	struct sctp_parameter_type_list_item *item;
+
+	flags = 0;
+	cause_length = sizeof(struct sctp_missing_mandatory_parameter_cause);
+	if (list == NULL) {
+		flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+		flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+	} else {
+		assert(list->nr_entries <=
+		       (MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_missing_mandatory_parameter_cause)) / sizeof(u16));
+		cause_length += list->nr_entries * sizeof(u16);
+	}
+	padding_length = cause_length % 4;
+	if (padding_length > 0) {
+		padding_length = 4 - padding_length;
+	}
+	assert(padding_length == 0 || padding_length == 2);
+	cause = malloc(cause_length + padding_length);
+	assert(cause != NULL);
+	cause->code = htons(SCTP_MISSING_MANDATORY_PARAMETER_CAUSE_CODE);
+	cause->length = htons(cause_length);
+	cause->nr_parameters = htonl(list->nr_entries);
+	if (list != NULL) {
+		for (i = 0, item = list->first;
+		     (i < list->nr_entries) && (item != NULL);
+		     i++, item = item->next) {
+			cause->parameter_type[i] = htons(item->parameter_type);
+		}
+		assert((i == list->nr_entries) && (item == NULL));
+	}
+	if (padding_length == 2) {
+		cause->parameter_type[list->nr_entries] = htons(0);
+	}
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                cause_length, flags);
+}
+
+struct sctp_cause_list_item *
+sctp_stale_cookie_error_cause_new(s64 staleness)
+{
+	struct sctp_stale_cookie_error_cause *cause;
+	u32 flags;
+
+	flags = 0;
+	cause = malloc(sizeof(struct sctp_stale_cookie_error_cause));
+	assert(cause != NULL);
+	cause->code = htons(SCTP_STALE_COOKIE_ERROR_CAUSE_CODE);
+	cause->length = htons(sizeof(struct sctp_stale_cookie_error_cause));
+	if (staleness == -1) {
+		cause->staleness = htonl(0);
+		flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+	} else {
+		assert(is_valid_u32(staleness));
+		cause->staleness = htonl((u32)staleness);
+	}
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                sizeof(struct sctp_stale_cookie_error_cause),
+	                                flags);
+}
+
+struct sctp_cause_list_item *
+sctp_out_of_resources_cause_new(void)
+{
+	struct sctp_out_of_resources_cause *cause;
+
+	cause = malloc(sizeof(struct sctp_out_of_resources_cause));
+	assert(cause != NULL);
+	cause->code = htons(SCTP_OUT_OF_RESOURCES_CAUSE_CODE);
+	cause->length = htons(sizeof(struct sctp_out_of_resources_cause));
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                sizeof(struct sctp_out_of_resources_cause),
+	                                0);
+}
+
+struct sctp_cause_list_item *
+sctp_unresolvable_address_cause_new(struct sctp_parameter_list_item *item)
+{
+	struct sctp_unresolvable_address_cause *cause;
+	u32 flags;
+	u16 length, padding_length;
+
+	assert(item == NULL ||
+	       (item->length <=
+	        MAX_SCTP_CAUSE_BYTES - sizeof(struct sctp_unresolvable_address_cause)));
+	flags = 0;
+	length = sizeof(struct sctp_unresolvable_address_cause);
+	if (item != NULL) {
+		length += item->length;
+	}
+	padding_length = length % 4;
+	if (padding_length > 0) {
+		padding_length = 4 - padding_length;
+	}
+	cause = malloc(length + padding_length);
+	assert(cause != NULL);
+	cause->code = htons(SCTP_UNRESOLVABLE_ADDRESS_CAUSE_CODE);
+	cause->length = htons(length);
+	if (item == NULL) {
+		flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+		flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+	} else {
+		if ((item->flags & FLAG_PARAMETER_TYPE_NOCHECK) ||
+		    (item->flags & FLAG_PARAMETER_VALUE_NOCHECK)) {
+			flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+		}
+		if (item->flags & FLAG_PARAMETER_LENGTH_NOCHECK) {
+			flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+		}
+		memcpy(cause->parameter, item->parameter, item->length);
+	}
+	memset(cause->parameter + item->length, 0, padding_length);
+	free(item);
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                length, flags);
+}
+
+struct sctp_cause_list_item *
+sctp_unrecognized_chunk_type_cause_new(struct sctp_chunk_list_item *item)
+{
+	struct sctp_unrecognized_chunk_type_cause *cause;
+	u32 flags;
+	u16 length, padding_length;
+
+	assert(item == NULL ||
+	       (item->length <=
+	        MAX_SCTP_CAUSE_BYTES - sizeof(struct sctp_unrecognized_chunk_type_cause)));
+	flags = 0;
+	length = sizeof(struct sctp_unrecognized_chunk_type_cause);
+	if (item != NULL) {
+		length += item->length;
+	}
+	padding_length = length % 4;
+	if (padding_length > 0) {
+		padding_length = 4 - padding_length;
+	}
+	cause = malloc(length + padding_length);
+	assert(cause != NULL);
+	cause->code = htons(SCTP_UNRECOGNIZED_CHUNK_TYPE_CAUSE_CODE);
+	cause->length = htons(length);
+	if (item == NULL) {
+		flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+		flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+	} else {
+		if ((item->flags & FLAG_CHUNK_TYPE_NOCHECK) ||
+		    (item->flags & FLAG_CHUNK_FLAGS_NOCHECK) ||
+		    (item->flags & FLAG_CHUNK_VALUE_NOCHECK)) {
+			flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+		}
+		if (item->flags & FLAG_CHUNK_LENGTH_NOCHECK) {
+			flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+		}
+		memcpy(cause->chunk, item->chunk, item->length);
+	}
+	memset(cause->chunk + item->length, 0, padding_length);
+	free(item);
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                length, flags);
+}
+
+struct sctp_cause_list_item *
+sctp_invalid_mandatory_parameter_cause_new(void)
+{
+	struct sctp_invalid_mandatory_parameter_cause *cause;
+
+	cause = malloc(sizeof(struct sctp_invalid_mandatory_parameter_cause));
+	assert(cause != NULL);
+	cause->code = htons(SCTP_INVALID_MANDATORY_PARAMETER_CAUSE_CODE);
+	cause->length = htons(sizeof(struct sctp_invalid_mandatory_parameter_cause));
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                sizeof(struct sctp_invalid_mandatory_parameter_cause),
+	                                0);
+}
+
+struct sctp_cause_list_item *
+sctp_unrecognized_parameters_cause_new(struct sctp_parameter_list *list)
+{
+	struct sctp_unrecognized_parameters_cause *cause;
+	struct sctp_parameter_list_item *item;
+	u32 flags;
+	u16 cause_length, padding_length, offset;
+
+	assert(list == NULL ||
+	       (list->length <
+	        MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_unrecognized_parameters_cause)));
+	flags = 0;
+	cause_length = sizeof(struct sctp_unrecognized_parameters_cause);
+	if (list != NULL) {
+		cause_length += list->length;
+	} else {
+		flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+		flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+	}
+	padding_length = cause_length % 4;
+	if (padding_length > 0) {
+		padding_length = 4 - padding_length;
+	}
+	cause = malloc(cause_length + padding_length);
+	assert(cause != NULL);
+	cause->code = htons(SCTP_UNRECOGNIZED_PARAMETERS_CAUSE_CODE);
+	cause->length = htons(cause_length);
+	if (list != NULL) {
+		offset = 0;
+		for (item = list->first; item != NULL; item = item->next) {
+			padding_length = item->length % 4;
+			if (padding_length > 0) {
+				padding_length = 4 - padding_length;
+			}
+			memcpy(cause->parameters + offset, item->parameter, item->length + padding_length);
+			if (item->flags & FLAG_PARAMETER_LENGTH_NOCHECK) {
+				flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+			}
+			if (item->flags & FLAG_PARAMETER_VALUE_NOCHECK) {
+				flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+			}
+			offset += item->length + padding_length;
+		}
+	}
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                cause_length, flags);
+}
+
+struct sctp_cause_list_item *
+sctp_no_user_data_cause_new(s64 tsn)
+{
+	struct sctp_no_user_data_cause *cause;
+	u32 flags;
+
+	flags = 0;
+	cause = malloc(sizeof(struct sctp_no_user_data_cause));
+	assert(cause != NULL);
+	cause->code = htons(SCTP_NO_USER_DATA_CAUSE_CODE);
+	cause->length = htons(sizeof(struct sctp_no_user_data_cause));
+	if (tsn == -1) {
+		cause->tsn = htonl(0);
+		flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+	} else {
+		assert(is_valid_u32(tsn));
+		cause->tsn = htonl((u32)tsn);
+	}
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                sizeof(struct sctp_no_user_data_cause),
+	                                flags);
+}
+
+struct sctp_cause_list_item *
+sctp_cookie_received_while_shutdown_cause_new(void)
+{
+	struct sctp_cookie_received_while_shutdown_cause *cause;
+
+	cause = malloc(sizeof(struct sctp_cookie_received_while_shutdown_cause));
+	assert(cause != NULL);
+	cause->code = htons(SCTP_COOKIE_RECEIVED_WHILE_SHUTDOWN_CAUSE_CODE);
+	cause->length = htons(sizeof(struct sctp_cookie_received_while_shutdown_cause));
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                sizeof(struct sctp_cookie_received_while_shutdown_cause),
+	                                0);
+}
+
+struct sctp_cause_list_item *
+sctp_restart_with_new_addresses_cause_new(struct sctp_parameter_list *list)
+{
+	struct sctp_restart_with_new_addresses_cause *cause;
+	struct sctp_parameter_list_item *item;
+	u32 flags;
+	u16 cause_length, padding_length, offset;
+
+	assert(list == NULL ||
+	       (list->length <
+	        MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_restart_with_new_addresses_cause)));
+	flags = 0;
+	cause_length = sizeof(struct sctp_restart_with_new_addresses_cause);
+	if (list != NULL) {
+		cause_length += list->length;
+	} else {
+		flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+		flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+	}
+	padding_length = cause_length % 4;
+	if (padding_length > 0) {
+		padding_length = 4 - padding_length;
+	}
+	cause = malloc(cause_length + padding_length);
+	assert(cause != NULL);
+	cause->code = htons(SCTP_RESTART_WITH_NEW_ADDRESSES_CAUSE_CODE);
+	cause->length = htons(cause_length);
+	if (list != NULL) {
+		offset = 0;
+		for (item = list->first; item != NULL; item = item->next) {
+			padding_length = item->length % 4;
+			if (padding_length > 0) {
+				padding_length = 4 - padding_length;
+			}
+			memcpy(cause->addresses + offset, item->parameter, item->length + padding_length);
+			if (item->flags & FLAG_PARAMETER_LENGTH_NOCHECK) {
+				flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+			}
+			if (item->flags & FLAG_PARAMETER_VALUE_NOCHECK) {
+				flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+			}
+			offset += item->length + padding_length;
+		}
+	}
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                cause_length, flags);
+}
+
+struct sctp_cause_list_item *
+sctp_user_initiated_abort_cause_new(char *info)
+{
+	struct sctp_user_initiated_abort_cause *cause;
+	u32 flags;
+	u16 length, info_length, padding_length;
+
+	assert(info == NULL ||
+	       (strlen(info) <=
+	        MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_user_initiated_abort_cause)));
+	flags = 0;
+	if (info == NULL) {
+		info_length = 0;
+	} else {
+		info_length = strlen(info);
+	}
+	length = info_length + sizeof(struct sctp_user_initiated_abort_cause);
+	padding_length = length % 4;
+	if (padding_length > 0) {
+		padding_length = 4 - padding_length;
+	}
+	cause = malloc(length + padding_length);
+	assert(cause != NULL);
+	cause->code = htons(SCTP_USER_INITIATED_ABORT_CAUSE_CODE);
+	cause->length = htons(length);
+	if (info == NULL) {
+		flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+		flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+	} else {
+		memcpy(cause->information, info, info_length);
+	}
+	memset(cause->information + info_length, 0, padding_length);
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                length, flags);
+}
+
+struct sctp_cause_list_item *
+sctp_protocol_violation_cause_new(char *info)
+{
+	struct sctp_protocol_violation_cause *cause;
+	u32 flags;
+	u16 length, info_length, padding_length;
+
+	assert(info == NULL ||
+	       (strlen(info) <=
+	        MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_protocol_violation_cause)));
+	flags = 0;
+	if (info == NULL) {
+		info_length = 0;
+	} else {
+		info_length = strlen(info);
+	}
+	length = info_length + sizeof(struct sctp_protocol_violation_cause);
+	padding_length = length % 4;
+	if (padding_length > 0) {
+		padding_length = 4 - padding_length;
+	}
+	cause = malloc(length + padding_length);
+	assert(cause != NULL);
+	cause->code = htons(SCTP_PROTOCOL_VIOLATION_CAUSE_CODE);
+	cause->length = htons(length);
+	if (info == NULL) {
+		flags |= FLAG_CAUSE_LENGTH_NOCHECK;
+		flags |= FLAG_CAUSE_INFORMATION_NOCHECK;
+	} else {
+		memcpy(cause->information, info, info_length);
+	}
+	memset(cause->information + info_length, 0, padding_length);
+	return sctp_cause_list_item_new((struct sctp_cause *)cause,
+	                                length, flags);
+}
+
+struct sctp_cause_list *
+sctp_cause_list_new(void)
+{
+	struct sctp_cause_list *list;
+
+	list = malloc(sizeof(struct sctp_cause_list));
+	assert(list != NULL);
+	list->first = NULL;
+	list->last = NULL;
+	list->length = 0;
+	return list;
+}
+
+void
+sctp_cause_list_append(struct sctp_cause_list *list,
+                       struct sctp_cause_list_item *item)
+{
+	u16 padding_length;
+
+	assert(item->next == NULL);
+	padding_length = list->length % 4;
+	if (padding_length > 0) {
+		padding_length = 4 - padding_length;
+	}
+	list->length += padding_length;
+	if (list->last == NULL) {
+		assert(list->first == NULL);
+		assert(list->length == 0);
+		list->first = item;
+	} else {
+		assert(list->first != NULL);
+		list->last->next = item;
+	}
+	list->last = item;
+	list->length += item->length;
+}
+
+void
+sctp_cause_list_free(struct sctp_cause_list *list)
+{
+	struct sctp_cause_list_item *current_item, *next_item;
+
+	assert(list != NULL);
+	current_item = list->first;
+	while (current_item != NULL) {
+		next_item = current_item->next;
+		assert(next_item != NULL || current_item == list->last);
+		free(current_item);
+		current_item = next_item;
+	}
+	free(list);
+}
+
 struct packet *
 new_sctp_packet(int address_family,
                 enum direction_t direction,
@@ -1485,6 +2156,7 @@ new_sctp_packet(int address_family,
 	struct header *sctp_header;  /* the SCTP header info */
 	struct sctp_chunk_list_item *chunk_item;
 	struct sctp_parameter_list_item *parameter_item;
+	struct sctp_cause_list_item *cause_item;
 	/* 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) +
@@ -1531,6 +2203,20 @@ new_sctp_packet(int address_family,
 					return NULL;
 				}
 			}
+			for (cause_item = chunk_item->cause_list->first;
+			     cause_item != NULL;
+			     cause_item = cause_item->next) {
+				if (cause_item->flags & FLAG_CAUSE_LENGTH_NOCHECK) {
+					asprintf(error,
+						 "cause length must be specified for inbound packets");
+					return NULL;
+				}
+				if (cause_item->flags & FLAG_CAUSE_INFORMATION_NOCHECK) {
+					asprintf(error,
+						 "cause information must be specified for inbound packets");
+					return NULL;
+				}
+			}
 			switch (chunk_item->chunk->type) {
 			case SCTP_DATA_CHUNK_TYPE:
 				if (chunk_item->flags & FLAG_CHUNK_FLAGS_NOCHECK) {
@@ -1646,13 +2332,11 @@ new_sctp_packet(int address_family,
 				overbook = true;
 				break;
 			case SCTP_ABORT_CHUNK_TYPE:
-#if 0
 				if (chunk_item->flags & FLAG_CHUNK_LENGTH_NOCHECK) {
 					asprintf(error,
 						 "error causes must be specified for inbound packets");
 					return NULL;
 				}
-#endif
 				break;
 			case SCTP_SHUTDOWN_CHUNK_TYPE:
 				if (chunk_item->flags & FLAG_SHUTDOWN_CHUNK_CUM_TSN_NOCHECK) {
@@ -1664,13 +2348,11 @@ new_sctp_packet(int address_family,
 			case SCTP_SHUTDOWN_ACK_CHUNK_TYPE:
 				break;
 			case SCTP_ERROR_CHUNK_TYPE:
-#if 0
 				if (chunk_item->flags & FLAG_CHUNK_LENGTH_NOCHECK) {
 					asprintf(error,
 						 "error causes must be specified for inbound packets");
 					return NULL;
 				}
-#endif
 				break;
 			case SCTP_COOKIE_ECHO_CHUNK_TYPE:
 				overbook = true;
@@ -1758,6 +2440,14 @@ new_sctp_packet(int address_family,
 			                              ((u8 *)parameter_item->parameter -
 			                               (u8 *)chunk_item->chunk));
 		}
+		for (cause_item = chunk_item->cause_list->first;
+		     cause_item != NULL;
+		     cause_item = cause_item->next) {
+			cause_item->cause =
+			    (struct sctp_cause *)(sctp_chunk_start +
+			                         ((u8 *)cause_item->cause -
+			                          (u8 *)chunk_item->chunk));
+		}
 		free(chunk_item->chunk);
 		chunk_item->chunk = (struct sctp_chunk *)sctp_chunk_start;
 		sctp_chunk_start += chunk_item->length;
diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h
index 85a3ea626240b93893f9b897fb132ff19a2504bf..4207111139aaa9dd03eafc0a98cb913215a651f2 100644
--- a/gtests/net/packetdrill/sctp_packet.h
+++ b/gtests/net/packetdrill/sctp_packet.h
@@ -104,6 +104,30 @@ sctp_address_type_list_free(struct sctp_address_type_list *list);
 struct sctp_address_type_list_item *
 sctp_address_type_list_item_new(u16 address_type);
 
+struct sctp_parameter_type_list_item {
+	struct sctp_parameter_type_list_item *next;
+	u16 parameter_type;
+};
+
+struct sctp_parameter_type_list {
+	struct sctp_parameter_type_list_item *first;
+	struct sctp_parameter_type_list_item *last;
+	u16 nr_entries;
+};
+
+struct sctp_parameter_type_list *
+sctp_parameter_type_list_new(void);
+
+void
+sctp_parameter_type_list_append(struct sctp_parameter_type_list *list,
+			        struct sctp_parameter_type_list_item *item);
+
+void
+sctp_parameter_type_list_free(struct sctp_parameter_type_list *list);
+
+struct sctp_parameter_type_list_item *
+sctp_parameter_type_list_item_new(u16 parameter_type);
+
 struct sctp_parameter_list_item {
 	struct sctp_parameter_list_item *next;
 	struct sctp_parameter *parameter;
@@ -120,10 +144,27 @@ struct sctp_parameter_list {
 	u32 length;
 };
 
+struct sctp_cause_list_item {
+	struct sctp_cause_list_item *next;
+	struct sctp_cause *cause;
+	/* total length in bytes */
+	u32 length;
+	/* metadata */
+	u32 flags;
+};
+
+struct sctp_cause_list {
+	struct sctp_cause_list_item *first;
+	struct sctp_cause_list_item *last;
+	/* length in bytes excluding the padding of the last cause*/
+	u32 length;
+};
+
 struct sctp_chunk_list_item {
 	struct sctp_chunk_list_item *next;
 	struct sctp_chunk *chunk;
 	struct sctp_parameter_list *parameter_list;
+	struct sctp_cause_list *cause_list;
 	/* total length in bytes */
 	u32 length;
 	/* metadata */
@@ -139,7 +180,8 @@ struct sctp_chunk_list {
 
 struct sctp_chunk_list_item *
 sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags,
-                         struct sctp_parameter_list *list);
+                         struct sctp_parameter_list *parameter_list,
+                         struct sctp_cause_list *cause_list);
 
 #define FLAG_CHUNK_TYPE_NOCHECK                 0x00000001
 #define FLAG_CHUNK_FLAGS_NOCHECK                0x00000002
@@ -196,8 +238,10 @@ sctp_heartbeat_chunk_new(s64 flgs, struct sctp_parameter_list_item *info);
 struct sctp_chunk_list_item *
 sctp_heartbeat_ack_chunk_new(s64 flgs, struct sctp_parameter_list_item *info);
 
+#define FLAG_ABORT_CHUNK_OPT_CAUSES_NOCHECK     0x00000100
+
 struct sctp_chunk_list_item *
-sctp_abort_chunk_new(s64 flgs);
+sctp_abort_chunk_new(s64 flgs, struct sctp_cause_list *causes);
 
 #define FLAG_SHUTDOWN_CHUNK_CUM_TSN_NOCHECK     0x00000100
 
@@ -207,8 +251,10 @@ sctp_shutdown_chunk_new(s64 flgs, s64 cum_tsn);
 struct sctp_chunk_list_item *
 sctp_shutdown_ack_chunk_new(s64 flgs);
 
+#define FLAG_ERROR_CHUNK_OPT_CAUSES_NOCHECK     0x00000100
+
 struct sctp_chunk_list_item *
-sctp_error_chunk_new(s64 flgs);
+sctp_error_chunk_new(s64 flgs, struct sctp_cause_list *causes);
 
 struct sctp_chunk_list_item *
 sctp_cookie_echo_chunk_new(s64 flgs, s64 len, u8* cookie);
@@ -293,6 +339,65 @@ sctp_parameter_list_append(struct sctp_parameter_list *list,
 void
 sctp_parameter_list_free(struct sctp_parameter_list *list);
 
+struct sctp_cause_list_item *
+sctp_cause_list_item_new(struct sctp_cause *cause,
+                         u32 length, u32 flags);
+
+#define FLAG_CAUSE_CODE_NOCHECK					0x00000001
+#define FLAG_CAUSE_LENGTH_NOCHECK				0x00000002
+#define FLAG_CAUSE_INFORMATION_NOCHECK				0x00000004
+
+struct sctp_cause_list_item *
+sctp_generic_cause_new(s64 code, s64 len, struct sctp_byte_list *bytes);
+
+struct sctp_cause_list_item *
+sctp_invalid_stream_identifier_cause_new(s64 sid);
+
+struct sctp_cause_list_item *
+sctp_missing_mandatory_parameter_cause_new(struct sctp_parameter_type_list *list);
+
+struct sctp_cause_list_item *
+sctp_stale_cookie_error_cause_new(s64 staleness);
+
+struct sctp_cause_list_item *
+sctp_out_of_resources_cause_new(void);
+
+struct sctp_cause_list_item *
+sctp_unresolvable_address_cause_new(struct sctp_parameter_list_item *item);
+
+struct sctp_cause_list_item *
+sctp_unrecognized_chunk_type_cause_new(struct sctp_chunk_list_item *item);
+
+struct sctp_cause_list_item *
+sctp_invalid_mandatory_parameter_cause_new(void);
+
+struct sctp_cause_list_item *
+sctp_unrecognized_parameters_cause_new(struct sctp_parameter_list *list);
+
+struct sctp_cause_list_item *
+sctp_no_user_data_cause_new(s64 tsn);
+
+struct sctp_cause_list_item *
+sctp_cookie_received_while_shutdown_cause_new(void);
+
+struct sctp_cause_list_item *
+sctp_restart_with_new_addresses_cause_new(struct sctp_parameter_list *list);
+
+struct sctp_cause_list_item *
+sctp_user_initiated_abort_cause_new(char *info);
+
+struct sctp_cause_list_item *
+sctp_protocol_violation_cause_new(char *info);
+
+struct sctp_cause_list *
+sctp_cause_list_new(void);
+
+void
+sctp_cause_list_append(struct sctp_cause_list *list,
+                       struct sctp_cause_list_item *item);
+
+void
+sctp_cause_list_free(struct sctp_cause_list *list);
 
 /* Create and initialize a new struct packet containing a SCTP packet.
  * On success, returns a newly-allocated packet. On failure, returns NULL
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_error_causes_active.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_error_causes_active.pkt
new file mode 100644
index 0000000000000000000000000000000000000000..685453e4c6aefa538b9d65e69df37b92b4dfbf3a
--- /dev/null
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_error_causes_active.pkt
@@ -0,0 +1,39 @@
++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
++0.1 < sctp: ERROR[flgs=0]
++0.1 < sctp: ERROR[flgs=0, CAUSE[code=0x0004, len=4, info=[]]]
++0.1 < sctp: ERROR[flgs=0, CAUSE[code=0x0001, len=8, info=[0x00, 0x01, 0x00, 0x00]],
+                          CAUSE[code=0x0001, len=8, info=[0x00, 0x02, 0x00, 0x00]]]
++0.1 < sctp: ERROR[flgs=0, INVALID_STREAM_IDENTIFIER[sid=65535]]
++0.1 < sctp: ERROR[flgs=0, MISSING_MANDATORY_PARAMETER[types=[123, 234]]]
++0.1 < sctp: ERROR[flgs=0, STALE_COOKIE_ERROR[staleness=12345678]]
++0.1 < sctp: ERROR[flgs=0, OUT_OF_RESOURCE[]]
++0.1 < sctp: ERROR[flgs=0, UNRESOLVABLE_ADDRESS[param=HOSTNAME_ADDRESS[addr="@A"]]]
++0.1 < sctp: ERROR[flgs=0, UNRECOGNIZED_CHUNK_TYPE[chk=CHUNK[type=0xCF, flgs=0, len=7, val=[0x01, 0x02, 0x03]]]]
++0.1 < sctp: ERROR[flgs=0, INVALID_MANDATORY_PARAMETER[]]
++0.1 < sctp: ERROR[flgs=0, UNRECOGNIZED_PARAMETERS[params=[PARAMETER[type=0x1234, len=4, val=[]]]]]
++0.1 < sctp: ERROR[flgs=0, NO_USER_DATA[tsn=12345678]]
++0.1 < sctp: ERROR[flgs=0, COOKIE_RECEIVED_WHILE_SHUTDOWN[]]
++0.1 < sctp: ERROR[flgs=0, RESTART_WITH_NEW_ADDRESSES[params=[IPV4_ADDRESS[addr=1.2.3.4],
+                                                              IPV4_ADDRESS[addr=2.3.4.5]]]]
++0.1 < sctp: ERROR[flgs=0, USER_INITIATED_ABORT[info="Testing"]]
++0.1 < sctp: ERROR[flgs=0, PROTOCOL_VIOLATION[info="Testing"]]
+//+0.1 < sctp: DATA[flgs=IBE, len=16, tsn=1, sid=0, ssn=0, ppid=0]
+//+0.0 > sctp: ABORT[flgs=0, NO_USER_DATA[tsn=1]]
+//+0.0 > sctp: ABORT[flgs=0, ...]
++1.0 < sctp: DATA[flgs=IBE, len=1016, tsn=1, sid=65535, ssn=0, ppid=0]
++0.0 > sctp: ERROR[flgs=0, CAUSE[code=0x0001, len=8, info=[0xff, 0xff, 0x00, 0x00]]];
+             SACK[flgs=0, cum_tsn=1, a_rwnd=..., gaps=[], dups=[]] // cum_tsn?
+// Tear down the association
++0.0 close(3) = 0
++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=1]
++0.1 < sctp: SHUTDOWN_ACK[flgs=0]
++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0]