diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index 36fa98fd3991fba1dc7426388cbfc21483e1a65a..d5fb23b8e82c1c0caccc758a0a02d92f95d8053b 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -237,8 +237,25 @@ tsn return TSN; sid return SID; ssn return SSN; ppid return PPID; +cum_tsn return CUM_TSN; gaps return GAPS; dups return DUPS; +HEARTBEAT_INFORMATION return HEARTBEAT_INFORMATION; +IPV4_ADDRESS return IPV4_ADDRESS; +IPV6_ADDRESS return IPV6_ADDRESS; +STATE_COOKIE return STATE_COOKIE; +UNRECOGNIZED_PARAMETER return UNRECOGNIZED_PARAMETER; +COOKIE_PRESERVATIVE return COOKIE_PRESERVATIVE; +HOSTNAME_ADDRESS return HOSTNAME_ADDRESS; +SUPPORTED_ADDRESS_TYPES return SUPPORTED_ADDRESS_TYPES; +ECN_CAPABLE return ECN_CAPABLE; +addr return ADDR; +incr return INCR; +types return TYPES; +params return PARAMS; +IPv4 return IPV4_TYPE; +IPv6 return IPV6_TYPE; +HOSTNAME return HOSTNAME_TYPE; --[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 19b9e6a7b048239443f4c6178ee15ceaa5c9bca0..97331617438eba5a62bb0702633a713ac186f470 100644 --- a/gtests/net/packetdrill/packet.c +++ b/gtests/net/packetdrill/packet.c @@ -148,8 +148,11 @@ static struct packet *packet_copy_with_headroom(struct packet *old_packet, struct packet *packet = packet_new(max(bytes_headroom + bytes_used, old_packet->buffer_bytes)); u8 *old_base = old_packet->buffer; u8 *new_base = packet->buffer + bytes_headroom; - struct sctp_chunk_list_item *old_item, *new_item; + struct sctp_chunk_list_item *old_chunk_item, *new_chunk_item; struct sctp_chunk *new_chunk; + struct sctp_parameter_list_item *old_parameter_item, *new_parameter_item; + struct sctp_parameter *new_parameter; + struct sctp_parameter_list *new_parameter_list; memcpy(new_base, old_base, bytes_used); @@ -172,14 +175,28 @@ static struct packet *packet_copy_with_headroom(struct packet *old_packet, packet->icmpv4 = offset_ptr(old_base, new_base, old_packet->icmpv4); packet->icmpv6 = offset_ptr(old_base, new_base, old_packet->icmpv6); - for (old_item = old_packet->chunk_list->first; - old_item != NULL; - old_item = old_item->next) { - new_chunk = offset_ptr(old_base, new_base, old_item->chunk); - new_item = sctp_chunk_list_item_new(new_chunk, - old_item->length, - old_item->flags); - sctp_chunk_list_append(packet->chunk_list, new_item); + /* Go through the SCTP specific lists */ + for (old_chunk_item = old_packet->chunk_list->first; + old_chunk_item != NULL; + old_chunk_item = old_chunk_item->next) { + new_parameter_list = sctp_parameter_list_new(); + for (old_parameter_item = old_chunk_item->parameter_list->first; + old_parameter_item != NULL; + old_parameter_item = old_parameter_item->next) { + new_parameter = offset_ptr(old_base, + new_base, + old_parameter_item->parameter); + new_parameter_item = sctp_parameter_list_item_new(new_parameter, + old_parameter_item->length, + old_parameter_item->flags); + sctp_parameter_list_append(new_parameter_list, new_parameter_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); + sctp_chunk_list_append(packet->chunk_list, new_chunk_item); } packet->tcp_ts_val = offset_ptr(old_base, new_base, diff --git a/gtests/net/packetdrill/packet_to_string_test.c b/gtests/net/packetdrill/packet_to_string_test.c index 0e0f0788a7a13b56d0ccc5426086fa9af0e828d1..b81befabba85096a9d04ec6b8525183529549db5 100644 --- a/gtests/net/packetdrill/packet_to_string_test.c +++ b/gtests/net/packetdrill/packet_to_string_test.c @@ -64,7 +64,7 @@ static void test_sctp_ipv4_packet_to_string(void) assert(error == NULL); printf("dump = '%s'\n", dump); expected = - "sctp: ABORT[flags=T]"; + "sctp: ABORT[flgs=T]"; assert(strcmp(dump, expected) == 0); free(dump); @@ -75,7 +75,7 @@ static void test_sctp_ipv4_packet_to_string(void) printf("dump = '%s'\n", dump); expected = "2.2.2.2:1234 > 1.1.1.1:8080 " - "sctp: ABORT[flags=T]"; + "sctp: ABORT[flgs=T]"; assert(strcmp(dump, expected) == 0); free(dump); @@ -86,7 +86,7 @@ static void test_sctp_ipv4_packet_to_string(void) printf("dump = '%s'\n", dump); expected = "2.2.2.2:1234 > 1.1.1.1:8080 " - "sctp: ABORT[flags=T]" + "sctp: ABORT[flgs=T]" "\n" "0x0000: 45 00 00 24 00 00 00 00 ff 84 b5 50 02 02 02 02 " "\n" "0x0010: 01 01 01 01 04 d2 1f 90 01 02 03 04 3d 99 bf e3 " "\n" @@ -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, 0x78, 0x84, 0xff, + 0x60, 0x00, 0x00, 0x00, 0x01, 0x80, 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, - 0x1b, 0x68, 0x75, 0x8e, + 0x22, 0x3e, 0x3f, 0x1c, /* SCTP DATA Chunk */ 0x00, 0x0f, 0x00, 0x13, 0x01, 0x02, 0x03, 0x04, @@ -158,10 +158,12 @@ static void test_sctp_ipv6_packet_to_string(void) 0x10, 0x00, 0x10, 0x14, 0x01, 0x02, 0x03, 0x04, /* SCTP HEARTBEAT Chunk */ - 0x04, 0x00, 0x00, 0x06, + 0x04, 0x00, 0x00, 0x0a, + 0x00, 0x01, 0x00, 0x06, 0x01, 0x02, 0x00, 0x00, /* SCTP HEARTBEAT-ACK Chunk */ - 0x05, 0x00, 0x00, 0x06, + 0x05, 0x00, 0x00, 0x0a, + 0x00, 0x01, 0x00, 0x06, 0x01, 0x02, 0x00, 0x00, /* SCTP ABORT Chunk: */ 0x06, 0x01, 0x00, 0x04, @@ -240,29 +242,28 @@ static void test_sctp_ipv6_packet_to_string(void) printf("dump = '%s'\n", dump); expected = "sctp: " - "DATA[flags=IUBE, tsn=16909060, sid=255, ssn=256, ppid=0, " - "payload_len=3]; " - "INIT[tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " - "IPV4_ADDRESS[1.2.3.4], " - "IPV6_ADDRESS[::1], " - "COOKIE_PRESERVATIVE[65536], " - "HOSTNAME[@A], " - "SUPPORTED_ADDRESS_TYPES[IPV4, IPV6, HOSTNAME], " + "DATA[flgs=IUBE, len=19, tsn=16909060, sid=255, ssn=256, ppid=0]; " + "INIT[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " + "IPV4_ADDRESS[addr=1.2.3.4], " + "IPV6_ADDRESS[addr=::1], " + "COOKIE_PRESERVATIVE[incr=65536], " + "HOSTNAME[addr=\"@A\"], " + "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], " "ECN_CAPABLE[]]; " - "INIT_ACK[tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " - "STATE_COOKIE[cookie_len=3], " - "UNRECOGNIZED_PARAMETER[" - "PARAMETER[type=0x8001, value=[]]]]; " - "SACK[cum_tsn=16909060, a_rwnd=65536, " - "gaps=[1-3, 5-15, 4096-4116], dups=[16909060]]; " - "HEARTBEAT[info_len=2]; " - "HEARTBEAT_ACK[info_len=2]; " - "ABORT[flags=T]; " - "ABORT[INVALID_STREAM_IDENTIFIER[sid=255], " + "INIT_ACK[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " + "STATE_COOKIE[len=7, val=...], " + "UNRECOGNIZED_PARAMETER[params=[" + "PARAMETER[type=0x8001, value=[]]]]]; " + "SACK[flgs=0x00, cum_tsn=16909060, a_rwnd=65536, " + "gaps=[1:3, 5:15, 4096:4116], dups=[16909060]]; " + "HEARTBEAT[flgs=0x00, HEARTBEAT_INFORMATION[len=6, val=...]]; " + "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], " "STALE_COOKIE_ERROR[staleness=65536], " "OUT_OF_RESOURCES[], " - "UNRESOLVABLE_ADDRESS[HOSTNAME[@A]], " + "UNRESOLVABLE_ADDRESS[HOSTNAME[addr=\"@A\"]], " "UNRECOGNIZED_CHUNK[" "CHUNK[type=0xfe, flags=0x05, value=[0x01]]], " "INVALID_MANDATORY_PARAMETER[], " @@ -271,18 +272,18 @@ static void test_sctp_ipv6_packet_to_string(void) "PARAMETER[type=0x800b, value=[0x01]]], " "NO_USER_DATA[tsn=16909060], " "COOKIE_RECEIVED_WHILE_SHUTDOWN[], " - "RESTART_WITH_NEW_ADDRESSES[IPV4_ADDRESS[1.2.3.4], " - "IPV4_ADDRESS[2.3.4.5]], " + "RESTART_WITH_NEW_ADDRESSES[IPV4_ADDRESS[addr=1.2.3.4], " + "IPV4_ADDRESS[addr=2.3.4.5]], " "USER_INITIATED_ABORT[BYE], " "PROTOCOL_VIOLATION[@@]]; " - "SHUTDOWN[tsn=16909060]; " - "SHUTDOWN_ACK[]; " - "ERROR[]; " - "COOKIE_ECHO[cookie_len=1]; " - "COOKIE_ACK[]; " - "ECNE[tsn=16909060]; " - "CWR[tsn=16909060]; " - "SHUTDOWN_COMPLETE[flags=T]"; + "SHUTDOWN[flgs=0x00, cum_tsn=16909060]; " + "SHUTDOWN_ACK[flgs=0x00]; " + "ERROR[flgs=0x00]; " + "COOKIE_ECHO[flgs=0x00, len=5]; " + "COOKIE_ACK[flgs=0x00]; " + "ECNE[flgs=0x00, tsn=16909060]; " + "CWR[flgs=0x00, tsn=16909060]; " + "SHUTDOWN_COMPLETE[flgs=T]"; assert(strcmp(dump, expected) == 0); free(dump); @@ -294,29 +295,28 @@ static void test_sctp_ipv6_packet_to_string(void) expected = "2::2222:1234 > 1::1111:8080 " "sctp: " - "DATA[flags=IUBE, tsn=16909060, sid=255, ssn=256, ppid=0, " - "payload_len=3]; " - "INIT[tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " - "IPV4_ADDRESS[1.2.3.4], " - "IPV6_ADDRESS[::1], " - "COOKIE_PRESERVATIVE[65536], " - "HOSTNAME[@A], " - "SUPPORTED_ADDRESS_TYPES[IPV4, IPV6, HOSTNAME], " + "DATA[flgs=IUBE, len=19, tsn=16909060, sid=255, ssn=256, ppid=0]; " + "INIT[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " + "IPV4_ADDRESS[addr=1.2.3.4], " + "IPV6_ADDRESS[addr=::1], " + "COOKIE_PRESERVATIVE[incr=65536], " + "HOSTNAME[addr=\"@A\"], " + "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], " "ECN_CAPABLE[]]; " - "INIT_ACK[tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " - "STATE_COOKIE[cookie_len=3], " - "UNRECOGNIZED_PARAMETER[" - "PARAMETER[type=0x8001, value=[]]]]; " - "SACK[cum_tsn=16909060, a_rwnd=65536, " - "gaps=[1-3, 5-15, 4096-4116], dups=[16909060]]; " - "HEARTBEAT[info_len=2]; " - "HEARTBEAT_ACK[info_len=2]; " - "ABORT[flags=T]; " - "ABORT[INVALID_STREAM_IDENTIFIER[sid=255], " + "INIT_ACK[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " + "STATE_COOKIE[len=7, val=...], " + "UNRECOGNIZED_PARAMETER[params=[" + "PARAMETER[type=0x8001, value=[]]]]]; " + "SACK[flgs=0x00, cum_tsn=16909060, a_rwnd=65536, " + "gaps=[1:3, 5:15, 4096:4116], dups=[16909060]]; " + "HEARTBEAT[flgs=0x00, HEARTBEAT_INFORMATION[len=6, val=...]]; " + "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], " "STALE_COOKIE_ERROR[staleness=65536], " "OUT_OF_RESOURCES[], " - "UNRESOLVABLE_ADDRESS[HOSTNAME[@A]], " + "UNRESOLVABLE_ADDRESS[HOSTNAME[addr=\"@A\"]], " "UNRECOGNIZED_CHUNK[" "CHUNK[type=0xfe, flags=0x05, value=[0x01]]], " "INVALID_MANDATORY_PARAMETER[], " @@ -325,18 +325,18 @@ static void test_sctp_ipv6_packet_to_string(void) "PARAMETER[type=0x800b, value=[0x01]]], " "NO_USER_DATA[tsn=16909060], " "COOKIE_RECEIVED_WHILE_SHUTDOWN[], " - "RESTART_WITH_NEW_ADDRESSES[IPV4_ADDRESS[1.2.3.4], " - "IPV4_ADDRESS[2.3.4.5]], " + "RESTART_WITH_NEW_ADDRESSES[IPV4_ADDRESS[addr=1.2.3.4], " + "IPV4_ADDRESS[addr=2.3.4.5]], " "USER_INITIATED_ABORT[BYE], " "PROTOCOL_VIOLATION[@@]]; " - "SHUTDOWN[tsn=16909060]; " - "SHUTDOWN_ACK[]; " - "ERROR[]; " - "COOKIE_ECHO[cookie_len=1]; " - "COOKIE_ACK[]; " - "ECNE[tsn=16909060]; " - "CWR[tsn=16909060]; " - "SHUTDOWN_COMPLETE[flags=T]"; + "SHUTDOWN[flgs=0x00, cum_tsn=16909060]; " + "SHUTDOWN_ACK[flgs=0x00]; " + "ERROR[flgs=0x00]; " + "COOKIE_ECHO[flgs=0x00, len=5]; " + "COOKIE_ACK[flgs=0x00]; " + "ECNE[flgs=0x00, tsn=16909060]; " + "CWR[flgs=0x00, tsn=16909060]; " + "SHUTDOWN_COMPLETE[flgs=T]"; assert(strcmp(dump, expected) == 0); free(dump); @@ -348,29 +348,28 @@ static void test_sctp_ipv6_packet_to_string(void) expected = "2::2222:1234 > 1::1111:8080 " "sctp: " - "DATA[flags=IUBE, tsn=16909060, sid=255, ssn=256, ppid=0, " - "payload_len=3]; " - "INIT[tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " - "IPV4_ADDRESS[1.2.3.4], " - "IPV6_ADDRESS[::1], " - "COOKIE_PRESERVATIVE[65536], " - "HOSTNAME[@A], " - "SUPPORTED_ADDRESS_TYPES[IPV4, IPV6, HOSTNAME], " + "DATA[flgs=IUBE, len=19, tsn=16909060, sid=255, ssn=256, ppid=0]; " + "INIT[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " + "IPV4_ADDRESS[addr=1.2.3.4], " + "IPV6_ADDRESS[addr=::1], " + "COOKIE_PRESERVATIVE[incr=65536], " + "HOSTNAME[addr=\"@A\"], " + "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], " "ECN_CAPABLE[]]; " - "INIT_ACK[tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " - "STATE_COOKIE[cookie_len=3], " - "UNRECOGNIZED_PARAMETER[" - "PARAMETER[type=0x8001, value=[]]]]; " - "SACK[cum_tsn=16909060, a_rwnd=65536, " - "gaps=[1-3, 5-15, 4096-4116], dups=[16909060]]; " - "HEARTBEAT[info_len=2]; " - "HEARTBEAT_ACK[info_len=2]; " - "ABORT[flags=T]; " - "ABORT[INVALID_STREAM_IDENTIFIER[sid=255], " + "INIT_ACK[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " + "STATE_COOKIE[len=7, val=...], " + "UNRECOGNIZED_PARAMETER[params=[" + "PARAMETER[type=0x8001, value=[]]]]]; " + "SACK[flgs=0x00, cum_tsn=16909060, a_rwnd=65536, " + "gaps=[1:3, 5:15, 4096:4116], dups=[16909060]]; " + "HEARTBEAT[flgs=0x00, HEARTBEAT_INFORMATION[len=6, val=...]]; " + "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], " "STALE_COOKIE_ERROR[staleness=65536], " "OUT_OF_RESOURCES[], " - "UNRESOLVABLE_ADDRESS[HOSTNAME[@A]], " + "UNRESOLVABLE_ADDRESS[HOSTNAME[addr=\"@A\"]], " "UNRECOGNIZED_CHUNK[" "CHUNK[type=0xfe, flags=0x05, value=[0x01]]], " "INVALID_MANDATORY_PARAMETER[], " @@ -379,23 +378,23 @@ static void test_sctp_ipv6_packet_to_string(void) "PARAMETER[type=0x800b, value=[0x01]]], " "NO_USER_DATA[tsn=16909060], " "COOKIE_RECEIVED_WHILE_SHUTDOWN[], " - "RESTART_WITH_NEW_ADDRESSES[IPV4_ADDRESS[1.2.3.4], " - "IPV4_ADDRESS[2.3.4.5]], " + "RESTART_WITH_NEW_ADDRESSES[IPV4_ADDRESS[addr=1.2.3.4], " + "IPV4_ADDRESS[addr=2.3.4.5]], " "USER_INITIATED_ABORT[BYE], " "PROTOCOL_VIOLATION[@@]]; " - "SHUTDOWN[tsn=16909060]; " - "SHUTDOWN_ACK[]; " - "ERROR[]; " - "COOKIE_ECHO[cookie_len=1]; " - "COOKIE_ACK[]; " - "ECNE[tsn=16909060]; " - "CWR[tsn=16909060]; " - "SHUTDOWN_COMPLETE[flags=T]" + "SHUTDOWN[flgs=0x00, cum_tsn=16909060]; " + "SHUTDOWN_ACK[flgs=0x00]; " + "ERROR[flgs=0x00]; " + "COOKIE_ECHO[flgs=0x00, len=5]; " + "COOKIE_ACK[flgs=0x00]; " + "ECNE[flgs=0x00, tsn=16909060]; " + "CWR[flgs=0x00, tsn=16909060]; " + "SHUTDOWN_COMPLETE[flgs=T]" "\n" - "0x0000: 60 00 00 00 01 78 84 ff 00 02 00 00 00 00 00 00 " "\n" + "0x0000: 60 00 00 00 01 80 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: 1b 68 75 8e 00 0f 00 13 01 02 03 04 00 ff 01 00 " "\n" + "0x0030: 22 3e 3f 1c 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 50 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" @@ -405,19 +404,20 @@ static void test_sctp_ipv6_packet_to_string(void) "0x00a0: 00 01 00 00 00 0f 00 0f 01 02 03 04 00 07 00 07 " "\n" "0x00b0: 01 02 03 00 00 08 00 08 80 01 00 04 03 00 00 20 " "\n" "0x00c0: 01 02 03 04 00 01 00 00 00 03 00 01 00 01 00 03 " "\n" - "0x00d0: 00 05 00 0f 10 00 10 14 01 02 03 04 04 00 00 06 " "\n" - "0x00e0: 01 02 00 00 05 00 00 06 01 02 00 00 06 01 00 04 " "\n" - "0x00f0: 06 00 00 80 00 01 00 08 00 ff 00 00 00 02 00 0a " "\n" - "0x0100: 00 00 00 01 00 07 00 00 00 03 00 08 00 01 00 00 " "\n" - "0x0110: 00 04 00 04 00 05 00 0c 00 0b 00 06 40 41 00 00 " "\n" - "0x0120: 00 06 00 0c fe 05 00 05 01 00 00 00 00 07 00 04 " "\n" - "0x0130: 00 08 00 10 80 0a 00 04 80 0b 00 05 01 00 00 00 " "\n" - "0x0140: 00 09 00 08 01 02 03 04 00 0a 00 04 00 0b 00 14 " "\n" - "0x0150: 00 05 00 08 01 02 03 04 00 05 00 08 02 03 04 05 " "\n" - "0x0160: 00 0c 00 07 42 59 45 00 00 0d 00 06 40 40 00 00 " "\n" - "0x0170: 07 00 00 08 01 02 03 04 08 00 00 04 09 00 00 04 " "\n" - "0x0180: 0a 00 00 05 45 00 00 00 0b 00 00 04 0c 00 00 08 " "\n" - "0x0190: 01 02 03 04 0d 00 00 08 01 02 03 04 0e 01 00 04 " "\n"; + "0x00d0: 00 05 00 0f 10 00 10 14 01 02 03 04 04 00 00 0a " "\n" + "0x00e0: 00 01 00 06 01 02 00 00 05 00 00 0a 00 01 00 06 " "\n" + "0x00f0: 01 02 00 00 06 01 00 04 06 00 00 80 00 01 00 08 " "\n" + "0x0100: 00 ff 00 00 00 02 00 0a 00 00 00 01 00 07 00 00 " "\n" + "0x0110: 00 03 00 08 00 01 00 00 00 04 00 04 00 05 00 0c " "\n" + "0x0120: 00 0b 00 06 40 41 00 00 00 06 00 0c fe 05 00 05 " "\n" + "0x0130: 01 00 00 00 00 07 00 04 00 08 00 10 80 0a 00 04 " "\n" + "0x0140: 80 0b 00 05 01 00 00 00 00 09 00 08 01 02 03 04 " "\n" + "0x0150: 00 0a 00 04 00 0b 00 14 00 05 00 08 01 02 03 04 " "\n" + "0x0160: 00 05 00 08 02 03 04 05 00 0c 00 07 42 59 45 00 " "\n" + "0x0170: 00 0d 00 06 40 40 00 00 07 00 00 08 01 02 03 04 " "\n" + "0x0180: 08 00 00 04 09 00 00 04 0a 00 00 05 45 00 00 00 " "\n" + "0x0190: 0b 00 00 04 0c 00 00 08 01 02 03 04 0d 00 00 08 " "\n" + "0x01a0: 01 02 03 04 0e 01 00 04 " "\n"; assert(strcmp(dump, expected) == 0); free(dump); packet_free(packet); diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index ec0443458324c848d317c5427193d515f8f2fd11..2e1d93f153c5e12f8232e3dddb28041d43930ecf 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -468,6 +468,10 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, struct sctp_chunk_list *chunk_list; struct sctp_sack_block_list_item *sack_block_list_item; 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_list_item *parameter_list_item; + struct sctp_parameter_list *parameter_list; struct syscall_spec *syscall; struct command_spec *command; struct code_spec *code; @@ -500,7 +504,12 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %token <reserved> DATA INIT INIT_ACK HEARTBEAT HEARTBEAT_ACK ABORT %token <reserved> SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECNE CWR %token <reserved> SHUTDOWN_COMPLETE -%token <reserved> FLAGS LEN TAG A_RWND OS IS TSN SID SSN PPID GAPS DUPS +%token <reserved> FLAGS LEN TAG A_RWND OS IS TSN SID SSN PPID CUM_TSN GAPS DUPS +%token <reserved> HEARTBEAT_INFORMATION IPV4_ADDRESS IPV6_ADDRESS STATE_COOKIE +%token <reserved> UNRECOGNIZED_PARAMETER COOKIE_PRESERVATIVE HOSTNAME_ADDRESS +%token <reserved> SUPPORTED_ADDRESS_TYPES ECN_CAPABLE +%token <reserved> ADDR INCR TYPES PARAMS +%token <reserved> IPV4_TYPE IPV6_TYPE HOSTNAME_TYPE %token <floating> FLOAT %token <integer> INTEGER HEX_INTEGER %token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR @@ -552,11 +561,26 @@ 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 <parameter_list> opt_parameter_list_spec sctp_parameter_list_spec +%type <parameter_list_item> sctp_parameter_spec +%type <parameter_list_item> sctp_heartbeat_information_parameter_spec +%type <parameter_list_item> sctp_ipv4_address_parameter_spec +%type <parameter_list_item> sctp_ipv6_address_parameter_spec +%type <parameter_list_item> sctp_state_cookie_parameter_spec +%type <parameter_list_item> sctp_unrecognized_parameter_parameter_spec +%type <parameter_list_item> sctp_cookie_preservative_parameter_spec +%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 <integer> opt_flags opt_data_flags opt_abort_flags -%type <integer> opt_shutdown_complete_flags opt_data_chunk_len -%type <integer> opt_a_rwnd opt_os opt_is opt_tsn opt_sid opt_ssn opt_ppid +%type <integer> opt_shutdown_complete_flags opt_chunk_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 <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 %% /* The grammar follows. */ @@ -765,33 +789,46 @@ sctp_chunk_spec | sctp_shutdown_complete_chunk_spec { $$ = $1; } ; -opt_data_chunk_len -: { $$ = -1; } -| LEN '=' INTEGER {if (!is_valid_u16($3) || - $3 < sizeof(struct sctp_data_chunk)) { - semantic_error("length value out of range"); - } - $$ = $3; +opt_chunk_len +: LEN '=' ELLIPSIS { $$ = -1; } +| LEN '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("length value out of range"); + } + $$ = $3; } +; opt_flags -: { $$ = -1; } -| FLAGS '=' HEX_INTEGER {if (!is_valid_u8($3)) { - semantic_error("flags value out of range"); - } - $$ = $3; +: 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; +} +; opt_data_flags -: { - $$ = -1; -} +: 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; @@ -801,28 +838,28 @@ opt_data_flags switch (*c) { case 'I': if (flags & SCTP_DATA_CHUNK_I_BIT) { - semantic_error("Specifying the I-bit multiple times"); + semantic_error("I-bit specified multiple times"); } else { flags |= SCTP_DATA_CHUNK_I_BIT; } break; case 'U': if (flags & SCTP_DATA_CHUNK_U_BIT) { - semantic_error("Specifying the U-bit multiple times"); + semantic_error("U-bit specified multiple times"); } else { flags |= SCTP_DATA_CHUNK_U_BIT; } break; case 'B': if (flags & SCTP_DATA_CHUNK_B_BIT) { - semantic_error("Specifying the B-bit multiple times"); + semantic_error("B-bit specified multiple times"); } else { flags |= SCTP_DATA_CHUNK_B_BIT; } break; case 'E': if (flags & SCTP_DATA_CHUNK_E_BIT) { - semantic_error("Specifying the E-bit multiple times"); + semantic_error("E-bit specified multiple times"); } else { flags |= SCTP_DATA_CHUNK_E_BIT; } @@ -834,17 +871,22 @@ opt_data_flags } $$ = flags; } +; opt_abort_flags -: { - $$ = -1; -} +: 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; @@ -854,7 +896,7 @@ opt_abort_flags switch (*c) { case 'T': if (flags & SCTP_ABORT_CHUNK_T_BIT) { - semantic_error("Specifying the T-bit multiple times"); + semantic_error("T-bit specified multiple times"); } else { flags |= SCTP_ABORT_CHUNK_T_BIT; } @@ -866,17 +908,22 @@ opt_abort_flags } $$ = flags; } +; opt_shutdown_complete_flags -: { - $$ = -1; -} +: 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; @@ -886,7 +933,7 @@ opt_shutdown_complete_flags switch (*c) { case 'T': if (flags & SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) { - semantic_error("Specifying the T-bit multiple times"); + semantic_error("T-bit specified multiple times"); } else { flags |= SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT; } @@ -898,72 +945,100 @@ opt_shutdown_complete_flags } $$ = flags; } +; + +opt_tag +: TAG '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("tag value out of range"); + } + $$ = $3; +} +; opt_a_rwnd -: { $$ = -1; } -| A_RWND '=' INTEGER { +: A_RWND '=' ELLIPSIS { $$ = -1; } +| A_RWND '=' INTEGER { if (!is_valid_u32($3)) { semantic_error("a_rwnd value out of range"); } $$ = $3; } +; opt_os -: { $$ = -1; } -| OS '=' INTEGER { +: OS '=' ELLIPSIS { $$ = -1; } +| OS '=' INTEGER { if (!is_valid_u16($3)) { semantic_error("os value out of range"); } $$ = $3; } +; opt_is -: { $$ = -1; } -| IS '=' INTEGER { +: IS '=' ELLIPSIS { $$ = -1; } +| IS '=' INTEGER { if (!is_valid_u16($3)) { semantic_error("is value out of range"); } $$ = $3; } +; opt_tsn -: { $$ = -1; } -| TSN '=' INTEGER { +: TSN '=' ELLIPSIS { $$ = -1; } +| TSN '=' INTEGER { if (!is_valid_u32($3)) { semantic_error("tsn value out of range"); } $$ = $3; } +; opt_sid -: { $$ = -1; } -| SID '=' INTEGER { +: SID '=' ELLIPSIS { $$ = -1; } +| SID '=' INTEGER { if (!is_valid_u16($3)) { semantic_error("sid value out of range"); } $$ = $3; } +; opt_ssn -: { $$ = -1; } -| SSN '=' INTEGER { +: SSN '=' ELLIPSIS { $$ = -1; } +| SSN '=' INTEGER { if (!is_valid_u16($3)) { semantic_error("ssn value out of range"); } $$ = $3; } +; opt_ppid -: { $$ = -1; } -| PPID '=' INTEGER { +: PPID '=' ELLIPSIS { $$ = -1; } +| PPID '=' INTEGER { if (!is_valid_u32($3)) { semantic_error("ppid value out of range"); } $$ = $3; } +; + +opt_cum_tsn +: CUM_TSN '=' ELLIPSIS { $$ = -1; } +| CUM_TSN '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("cum_tsn value out of range"); + } + $$ = $3; +} +; opt_gaps -: { $$ = NULL; } +: GAPS '=' ELLIPSIS { $$ = NULL; } +| GAPS '=' '[' ELLIPSIS ']' { $$ = NULL; } | GAPS '=' '[' gap_list ']' { $$ = $4; } ; @@ -976,17 +1051,20 @@ gap_list ; gap -: INTEGER ':' INTEGER { if (!is_valid_u32($1)) { - semantic_error("start value out of range"); - } - if (!is_valid_u32($3)) { - semantic_error("end value out of range"); - } - $$ = sctp_sack_block_list_item_gap_new($1, $3); } +: INTEGER ':' INTEGER { + if (!is_valid_u16($1)) { + semantic_error("start value out of range"); + } + if (!is_valid_u16($3)) { + semantic_error("end value out of range"); + } + $$ = sctp_sack_block_list_item_gap_new($1, $3); +} ; opt_dups -: { $$ = NULL; } +: DUPS '=' ELLIPSIS { $$ = NULL; } +| DUPS '=' '[' ELLIPSIS ']' { $$ = NULL; } | DUPS '=' '[' dup_list ']' { $$ = $4; } ; @@ -999,52 +1077,57 @@ dup_list ; dup -: INTEGER { if (!is_valid_u32($1)) { - semantic_error("tsn value out of range"); - } - $$ = sctp_sack_block_list_item_dup_new($1); } +: INTEGER { + if (!is_valid_u32($1)) { + semantic_error("tsn value out of range"); + } + $$ = sctp_sack_block_list_item_dup_new($1); +} ; sctp_data_chunk_spec -: DATA '[' opt_data_flags opt_data_chunk_len opt_tsn opt_sid opt_ssn opt_ppid ']' { - $$ = sctp_data_chunk_new($3, $4, $5, $6, $7, $8); +: DATA '[' opt_data_flags ',' opt_chunk_len ',' opt_tsn ',' opt_sid ',' opt_ssn ',' opt_ppid ']' { + if (($5 != -1) && ($5 < sizeof(struct sctp_data_chunk))) { + semantic_error("length value out of range"); + } + $$ = sctp_data_chunk_new($3, $5, $7, $9, $11, $13); } sctp_init_chunk_spec -: INIT '[' opt_flags TAG '=' INTEGER opt_a_rwnd opt_os opt_is TSN '=' INTEGER ']' { - if (!is_valid_u32($6)) { - semantic_error("tag value out of range"); +: INIT '[' opt_flags ',' opt_tag ',' opt_a_rwnd ',' opt_os ',' opt_is ',' opt_tsn opt_parameter_list_spec ']' { + if ($5 == -1) { + semantic_error("tag value must be specified"); } - if (!is_valid_u32($12)) { - semantic_error("tsn value out of range"); + if ($13 == -1) { + semantic_error("tsn value must be specified"); } - $$ = sctp_init_chunk_new($3, $6, $7, $8, $9, $12); + $$ = sctp_init_chunk_new($3, $5, $7, $9, $11, $13, $14); } sctp_init_ack_chunk_spec -: INIT_ACK '[' opt_flags TAG '=' INTEGER opt_a_rwnd opt_os opt_is TSN '=' INTEGER ']' { - if (!is_valid_u32($6)) { - semantic_error("tag value out of range"); +: INIT_ACK '[' opt_flags ',' opt_tag ',' opt_a_rwnd ',' opt_os ',' opt_is ',' opt_tsn opt_parameter_list_spec ']' { + if ($5 == -1) { + semantic_error("tag value must be specified"); } - if (!is_valid_u32($12)) { - semantic_error("tsn value out of range"); + if ($13 == -1) { + semantic_error("tsn value must be specified"); } - $$ = sctp_init_ack_chunk_new($3, $6, $7, $8, $9, $12); + $$ = sctp_init_ack_chunk_new($3, $5, $7, $9, $11, $13, $14); } sctp_sack_chunk_spec -: SACK '[' opt_flags opt_tsn opt_a_rwnd opt_gaps opt_dups']' { - $$ = sctp_sack_chunk_new($3, $4, $5, $6, $7); +: SACK '[' opt_flags ',' opt_cum_tsn ',' opt_a_rwnd ',' opt_gaps ',' opt_dups']' { + $$ = sctp_sack_chunk_new($3, $5, $7, $9, $11); } sctp_heartbeat_chunk_spec -: HEARTBEAT '[' opt_flags ']' { - $$ = sctp_heartbeat_chunk_new($3); +: HEARTBEAT '[' opt_flags ',' sctp_heartbeat_information_parameter_spec ']' { + $$ = sctp_heartbeat_chunk_new($3, $5); } sctp_heartbeat_ack_chunk_spec -: HEARTBEAT_ACK '[' opt_flags ']' { - $$ = sctp_heartbeat_ack_chunk_new($3); +: HEARTBEAT_ACK '[' opt_flags ',' sctp_heartbeat_information_parameter_spec ']' { + $$ = sctp_heartbeat_ack_chunk_new($3, $5); } sctp_abort_chunk_spec @@ -1053,8 +1136,8 @@ sctp_abort_chunk_spec } sctp_shutdown_chunk_spec -: SHUTDOWN '[' opt_flags opt_tsn ']' { - $$ = sctp_shutdown_chunk_new($3, $4); +: SHUTDOWN '[' opt_flags ',' opt_cum_tsn ']' { + $$ = sctp_shutdown_chunk_new($3, $5); } sctp_shutdown_ack_chunk_spec @@ -1068,8 +1151,8 @@ sctp_error_chunk_spec } sctp_cookie_echo_chunk_spec -: COOKIE_ECHO '[' opt_flags ']' { - $$ = sctp_cookie_echo_chunk_new($3); +: COOKIE_ECHO '[' opt_flags ',' opt_chunk_len ',' VAL '=' ELLIPSIS ']' { + $$ = sctp_cookie_echo_chunk_new($3, $5, NULL); } sctp_cookie_ack_chunk_spec @@ -1092,6 +1175,146 @@ sctp_shutdown_complete_chunk_spec $$ = sctp_shutdown_complete_chunk_new($3); } +opt_parameter_list_spec +: ',' ELLIPSIS { $$ = NULL; } +| { $$ = sctp_parameter_list_new(); } +| ',' sctp_parameter_list_spec { $$ = $2; } +; + +sctp_parameter_list_spec +: sctp_parameter_spec { $$ = sctp_parameter_list_new(); + sctp_parameter_list_append($$, $1); } +| sctp_parameter_list_spec ',' sctp_parameter_spec { $$ = $1; + sctp_parameter_list_append($1, $3); } +; + +sctp_parameter_spec +: sctp_heartbeat_information_parameter_spec { $$ = $1; } +| sctp_ipv4_address_parameter_spec { $$ = $1; } +| sctp_ipv6_address_parameter_spec { $$ = $1; } +| sctp_state_cookie_parameter_spec { $$ = $1; } +| sctp_unrecognized_parameter_parameter_spec { $$ = $1; } +| sctp_cookie_preservative_parameter_spec { $$ = $1; } +| sctp_hostname_address_parameter_spec { $$ = $1; } +| sctp_supported_address_types_parameter_spec { $$ = $1; } +| sctp_ecn_capable_parameter_spec { $$ = $1; } +; + +sctp_heartbeat_information_parameter_spec +: HEARTBEAT_INFORMATION '[' ELLIPSIS ']' { + $$ = sctp_heartbeat_information_parameter_new(-1, NULL); +} +| HEARTBEAT_INFORMATION '[' LEN '=' ELLIPSIS ',' VAL '=' ELLIPSIS ']' { + $$ = sctp_heartbeat_information_parameter_new(-1, NULL); +} +| HEARTBEAT_INFORMATION '[' LEN '=' INTEGER ',' VAL '=' ELLIPSIS ']' { + if (($5 < sizeof(struct sctp_heartbeat_information_parameter)) || + !is_valid_u16($5)) { + semantic_error("len value out of range"); + } + $$ = sctp_heartbeat_information_parameter_new($5, NULL); +} + +sctp_ipv4_address_parameter_spec +: IPV4_ADDRESS '[' ADDR '=' IPV4_ADDR ']' { + struct in_addr addr; + + if (inet_pton(AF_INET, $5, &addr) != 1) { + semantic_error("Invalid address"); + } + $$ = sctp_ipv4_address_parameter_new(&addr); +} +| IPV4_ADDRESS '[' ADDR '=' ELLIPSIS ']' { + $$ = sctp_ipv4_address_parameter_new(NULL); +} + +sctp_ipv6_address_parameter_spec +: IPV6_ADDRESS '[' ADDR '=' IPV6_ADDR ']' { + struct in6_addr addr; + + if (inet_pton(AF_INET6, $5, &addr) != 1) { + semantic_error("Invalid address"); + } + $$ = sctp_ipv6_address_parameter_new(&addr); +} +| IPV6_ADDRESS '[' ADDR '=' ELLIPSIS ']' { + $$ = sctp_ipv6_address_parameter_new(NULL); +} + +sctp_state_cookie_parameter_spec +: STATE_COOKIE '[' ELLIPSIS ']' { + $$ = sctp_state_cookie_parameter_new(-1, NULL); +} +| STATE_COOKIE '[' LEN '=' ELLIPSIS ',' VAL '=' ELLIPSIS ']' { + $$ = sctp_state_cookie_parameter_new(-1, NULL); +} +| STATE_COOKIE '[' LEN '=' INTEGER ',' VAL '=' ELLIPSIS ']' { + if (($5 < sizeof(struct sctp_state_cookie_parameter)) || + !is_valid_u32($5)) { + semantic_error("len value out of range"); + } + $$ = sctp_state_cookie_parameter_new($5, NULL); +} + +sctp_unrecognized_parameter_parameter_spec +: UNRECOGNIZED_PARAMETER '[' PARAMS '=' ELLIPSIS ']' { + $$ = sctp_unrecognized_parameters_parameter_new(NULL); +} +| UNRECOGNIZED_PARAMETER '[' PARAMS '=' '[' sctp_parameter_list_spec ']' ']' { + $$ = sctp_unrecognized_parameters_parameter_new($6); +} + +sctp_cookie_preservative_parameter_spec +: COOKIE_PRESERVATIVE '[' INCR '=' INTEGER ']' { + if (!is_valid_u32($5)) { + semantic_error("increment value out of range"); + } + $$ = sctp_cookie_preservative_parameter_new($5); +} +| COOKIE_PRESERVATIVE '[' INCR '=' ELLIPSIS ']' { + $$ = sctp_cookie_preservative_parameter_new(-1); +} + +sctp_hostname_address_parameter_spec +: HOSTNAME_ADDRESS '[' ADDR '=' STRING ']' { + $$ = sctp_hostname_address_parameter_new($5); +} +| HOSTNAME_ADDRESS '[' ADDR '=' ELLIPSIS ']' { + $$ = sctp_hostname_address_parameter_new(NULL); +} + +address_types_list +: { $$ = sctp_address_type_list_new(); } +| address_type { $$ = sctp_address_type_list_new(); + sctp_address_type_list_append($$, $1); } +| address_types_list ',' address_type { $$ = $1; + sctp_address_type_list_append($1, $3); } +; + +address_type +: INTEGER { if (!is_valid_u16($1)) { + semantic_error("address type value out of range"); + } + $$ = 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); } +; + +sctp_supported_address_types_parameter_spec +: SUPPORTED_ADDRESS_TYPES '[' TYPES '=' ELLIPSIS ']' { + $$ = sctp_supported_address_types_parameter_new(NULL); +} +| SUPPORTED_ADDRESS_TYPES '[' TYPES '=' '[' address_types_list ']' ']' { + $$ = sctp_supported_address_types_parameter_new($6); +} + + +sctp_ecn_capable_parameter_spec +: ECN_CAPABLE '[' ']' { + $$ = sctp_ecn_capable_parameter_new(); +} + 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 331903c5b94cf54b84d51962c422c7d2122821d0..3eea270325520200845bdf87786fc212fdf7c1be 100644 --- a/gtests/net/packetdrill/run_packet.c +++ b/gtests/net/packetdrill/run_packet.c @@ -1047,6 +1047,70 @@ static int verify_ipv6( return STATUS_OK; } +static int verify_sctp_parameters(u8 *begin, u16 length, + struct sctp_chunk_list_item *script_chunk_item, + char **error) +{ + struct sctp_parameters_iterator iter; + struct sctp_parameter *actual_parameter; + struct sctp_parameter *script_parameter; + struct sctp_parameter_list_item *script_parameter_item; + u32 flags; + + for (actual_parameter = sctp_parameters_begin(begin, length, &iter, error), + script_parameter_item = script_chunk_item->parameter_list->first; + actual_parameter != NULL && script_parameter_item != NULL; + actual_parameter = sctp_parameters_next(&iter, error), + script_parameter_item = script_parameter_item->next) { + if (*error != NULL) { + DEBUGP("Error during iteration\n"); + return STATUS_ERR; + } + script_parameter = script_parameter_item->parameter; + flags = script_parameter_item->flags; + assert(script_parameter != NULL); + DEBUGP("script parameter: type %04d, length %04d\n", + ntohs(script_parameter->type), + ntohs(script_parameter->length)); + DEBUGP("actual parameter: type %04d, length %04d\n", + ntohs(actual_parameter->type), + ntohs(actual_parameter->length)); + if ((flags & FLAG_PARAMETER_TYPE_NOCHECK ? STATUS_OK : + check_field("sctp_parameter_type", + ntohs(script_parameter->type), + ntohs(actual_parameter->type), + error)) || + (flags & FLAG_PARAMETER_LENGTH_NOCHECK ? STATUS_OK : + check_field("sctp_chunk_length", + ntohs(script_parameter->length), + ntohs(actual_parameter->length), + error))) { + return STATUS_ERR; + } + if ((flags & FLAG_PARAMETER_VALUE_NOCHECK) == 0) { + assert((flags & FLAG_PARAMETER_LENGTH_NOCHECK) == 0); + if (memcmp(script_parameter->value, + actual_parameter->value, + ntohs(actual_parameter->length) - sizeof(struct sctp_parameter))) { + asprintf(error, "live packet parameter value not as expected"); + return STATUS_ERR; + } + } + } + if (actual_parameter != NULL) { + DEBUGP("actual chunk contains more parameters than script chunk\n"); + } + if (script_parameter_item != NULL) { + DEBUGP("script chunk contains more parameters than actual chunk\n"); + } + if ((actual_parameter != NULL) || (script_parameter_item != NULL)) { + asprintf(error, + "live chunk and expected chunk have not the same number of parameters"); + 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) @@ -1076,9 +1140,18 @@ static int verify_data_chunk(struct sctp_data_chunk *actual_chunk, } static int verify_init_chunk(struct sctp_init_chunk *actual_chunk, - struct sctp_init_chunk *script_chunk, - u32 flags, char **error) + struct sctp_chunk_list_item *script_chunk_item, + char **error) { + struct sctp_init_chunk *script_chunk; + u32 flags; + + script_chunk = (struct sctp_init_chunk *)script_chunk_item->chunk; + flags = script_chunk_item->flags; + u16 parameters_length; + + assert(ntohs(actual_chunk->length) >= sizeof(struct sctp_init_chunk)); + parameters_length = ntohs(actual_chunk->length) - sizeof(struct sctp_init_chunk); if (check_field("sctp_init_chunk_tag", ntohl(script_chunk->initiate_tag), ntohl(actual_chunk->initiate_tag), @@ -1101,10 +1174,14 @@ static int verify_init_chunk(struct sctp_init_chunk *actual_chunk, check_field("sctp_init_chunk_tsn", ntohl(script_chunk->initial_tsn), ntohl(actual_chunk->initial_tsn), - error)) { + error) || + (flags & FLAG_INIT_CHUNK_OPT_PARAM_NOCHECK? STATUS_OK : + verify_sctp_parameters(actual_chunk->parameter, + parameters_length, + script_chunk_item, + error))) { return STATUS_ERR; } - /* FIXME: Validate parameters */ return STATUS_OK; } @@ -1415,8 +1492,7 @@ static int verify_sctp( break; case SCTP_INIT_CHUNK_TYPE: result = verify_init_chunk((struct sctp_init_chunk *)actual_chunk, - (struct sctp_init_chunk *)script_chunk, - flags, error); + script_chunk_item, error); break; case SCTP_INIT_ACK_CHUNK_TYPE: result = verify_init_ack_chunk((struct sctp_init_ack_chunk *)actual_chunk, diff --git a/gtests/net/packetdrill/sctp_chunk_to_string.c b/gtests/net/packetdrill/sctp_chunk_to_string.c index 842978bf0f0ffd3dfb9e4db256a4cb21019ad891..c365e7c37c231026a369a7b1e866785bd890d286 100644 --- a/gtests/net/packetdrill/sctp_chunk_to_string.c +++ b/gtests/net/packetdrill/sctp_chunk_to_string.c @@ -27,6 +27,23 @@ static int sctp_parameter_to_string(FILE *, struct sctp_parameter *, char **); +static int sctp_heartbeat_information_parameter_to_string( + FILE *s, + struct sctp_heartbeat_information_parameter *parameter, + char **error) +{ + u16 length; + + length = ntohs(parameter->length); + if (length < sizeof(struct sctp_heartbeat_information_parameter)) { + asprintf(error, "HEARTBEAT_INFORMATION parameter illegal (length=%u)", + length); + return STATUS_ERR; + } + fprintf(s, "HEARTBEAT_INFORMATION[len=%u, val=...]", length); + return STATUS_OK; +} + static int sctp_ipv4_address_parameter_to_string( FILE *s, struct sctp_ipv4_address_parameter *parameter, @@ -42,7 +59,7 @@ static int sctp_ipv4_address_parameter_to_string( return STATUS_ERR; } inet_ntop(AF_INET, ¶meter->addr, buffer, INET_ADDRSTRLEN); - fprintf(s, "IPV4_ADDRESS[%s]", buffer); + fprintf(s, "IPV4_ADDRESS[addr=%s]", buffer); return STATUS_OK; } @@ -61,7 +78,7 @@ static int sctp_ipv6_address_parameter_to_string( return STATUS_ERR; } inet_ntop(AF_INET6, ¶meter->addr, buffer, INET6_ADDRSTRLEN); - fprintf(s, "IPV6_ADDRESS[%s]", buffer); + fprintf(s, "IPV6_ADDRESS[addr=%s]", buffer); return STATUS_OK; } @@ -70,7 +87,7 @@ static int sctp_state_cookie_parameter_to_string( struct sctp_state_cookie_parameter *parameter, char **error) { - u16 length, cookie_length; + u16 length; length = ntohs(parameter->length); if (length < sizeof(struct sctp_state_cookie_parameter)) { @@ -78,8 +95,7 @@ static int sctp_state_cookie_parameter_to_string( length); return STATUS_ERR; } - cookie_length = length - sizeof(struct sctp_state_cookie_parameter); - fprintf(s, "STATE_COOKIE[cookie_len=%d]", cookie_length); + fprintf(s, "STATE_COOKIE[len=%d, val=...]", length); return STATUS_OK; } @@ -99,10 +115,10 @@ static int sctp_unrecognized_parameter_parameter_to_string( length); return STATUS_ERR; } - fputs("UNRECOGNIZED_PARAMETER[", s); + fputs("UNRECOGNIZED_PARAMETER[params=[", s); result = sctp_parameter_to_string(s, (struct sctp_parameter *)parameter->value, error); - fputc(']', s); + fputs("]]", s); return result; } @@ -120,7 +136,7 @@ static int sctp_cookie_preservative_parameter_to_string( length); return STATUS_ERR; } - fputs("COOKIE_PRESERVATIVE[", s); + fputs("COOKIE_PRESERVATIVE[incr=", s); fprintf(s, "%u", ntohl(parameter->increment)); fputc(']', s); return STATUS_OK; @@ -139,7 +155,7 @@ static int sctp_hostname_parameter_to_string( length); return STATUS_ERR; } - fprintf(s, "HOSTNAME[%.*s]", + fprintf(s, "HOSTNAME[addr=\"%.*s\"]", (int)(length - sizeof(struct sctp_hostname_address_parameter)), (char *)parameter->hostname); return STATUS_OK; @@ -163,16 +179,16 @@ static int sctp_supported_address_types_parameter_to_string( nr_address_types = (length - sizeof(struct sctp_supported_address_types_parameter)) / sizeof(u16); - fputs("SUPPORTED_ADDRESS_TYPES[", s); + fputs("SUPPORTED_ADDRESS_TYPES[types=[", s); for (i = 0; i < nr_address_types; i++) { if (i > 0) fputs(", ", s); switch (ntohs(parameter->address_type[i])) { case SCTP_IPV4_ADDRESS_PARAMETER_TYPE: - fputs("IPV4", s); + fputs("IPv4", s); break; case SCTP_IPV6_ADDRESS_PARAMETER_TYPE: - fputs("IPV6", s); + fputs("IPv6", s); break; case SCTP_HOSTNAME_ADDRESS_PARAMETER_TYPE: fputs("HOSTNAME", s); @@ -182,7 +198,7 @@ static int sctp_supported_address_types_parameter_to_string( break; } } - fputs("]", s); + fputs("]]", s); return STATUS_OK; } @@ -235,6 +251,10 @@ static int sctp_parameter_to_string(FILE *s, int result; switch (ntohs(parameter->type)) { + case SCTP_HEARTBEAT_INFORMATION_PARAMETER_TYPE: + result = sctp_heartbeat_information_parameter_to_string(s, + (struct sctp_heartbeat_information_parameter *)parameter, error); + break; case SCTP_IPV4_ADDRESS_PARAMETER_TYPE: result = sctp_ipv4_address_parameter_to_string(s, (struct sctp_ipv4_address_parameter *)parameter, error); @@ -740,31 +760,28 @@ static int sctp_data_chunk_to_string(FILE *s, return STATUS_ERR; } fputs("DATA[", s); - if (flags != 0x00) { - fputs("flags=", s); - if (flags & ~(SCTP_DATA_CHUNK_I_BIT | - SCTP_DATA_CHUNK_U_BIT | - SCTP_DATA_CHUNK_B_BIT | - SCTP_DATA_CHUNK_E_BIT)) - fprintf(s, "0x%02x", chunk->flags); - else { - if (flags & SCTP_DATA_CHUNK_I_BIT) - fputc('I', s); - if (flags & SCTP_DATA_CHUNK_U_BIT) - fputc('U', s); - if (flags & SCTP_DATA_CHUNK_B_BIT) - fputc('B', s); - if (flags & SCTP_DATA_CHUNK_E_BIT) - fputc('E', s); - } - fputs(", ", s); + fputs("flgs=", s); + if (flags & ~(SCTP_DATA_CHUNK_I_BIT | + SCTP_DATA_CHUNK_U_BIT | + SCTP_DATA_CHUNK_B_BIT | + SCTP_DATA_CHUNK_E_BIT)) + fprintf(s, "0x%02x", chunk->flags); + else { + if (flags & SCTP_DATA_CHUNK_I_BIT) + fputc('I', s); + if (flags & SCTP_DATA_CHUNK_U_BIT) + fputc('U', s); + if (flags & SCTP_DATA_CHUNK_B_BIT) + fputc('B', s); + if (flags & SCTP_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, "ssn=%u, ", ntohs(chunk->ssn)); - fprintf(s, "ppid=%u, ", ntohl(chunk->ppid)); - fprintf(s, "payload_len=%u]", - length - (u16)sizeof(struct sctp_data_chunk)); + fprintf(s, "ppid=%u]", ntohl(chunk->ppid)); return STATUS_OK; } @@ -787,8 +804,7 @@ static int sctp_init_chunk_to_string(FILE *s, } parameters_length = length - sizeof(struct sctp_init_chunk); fputs("INIT[", s); - if (flags != 0x00) - fprintf(s, "flags=0x%02x, ", chunk->flags); + fprintf(s, "flgs=0x%02x, ", chunk->flags); fprintf(s, "tag=%u, ", ntohl(chunk->initiate_tag)); fprintf(s, "a_rwnd=%d, ", ntohl(chunk->a_rwnd)); fprintf(s, "os=%u, ", ntohs(chunk->os)); @@ -831,8 +847,7 @@ static int sctp_init_ack_chunk_to_string(FILE *s, } parameters_length = length - sizeof(struct sctp_init_ack_chunk); fputs("INIT_ACK[", s); - if (flags != 0x00) - fprintf(s, "flags=0x%02x, ", chunk->flags); + fprintf(s, "flgs=0x%02x, ", chunk->flags); fprintf(s, "tag=%u, ", ntohl(chunk->initiate_tag)); fprintf(s, "a_rwnd=%d, ", ntohl(chunk->a_rwnd)); fprintf(s, "os=%u, ", ntohs(chunk->os)); @@ -879,13 +894,12 @@ static int sctp_sack_chunk_to_string(FILE *s, return STATUS_ERR; } fputs("SACK[", s); - if (flags != 0) - fprintf(s, "flags=0x%02x, ", flags); + fprintf(s, "flgs=0x%02x, ", flags); fprintf(s, "cum_tsn=%u, ", ntohl(chunk->cum_tsn)); fprintf(s, "a_rwnd=%u, ", ntohl(chunk->a_rwnd)); fputs("gaps=[", s); for (i = 0; i < nr_gaps; i++) - fprintf(s, "%s%u-%u", + fprintf(s, "%s%u:%u", i > 0 ? ", " : "", ntohs(chunk->block[i].gap.start), ntohs(chunk->block[i].gap.end)); @@ -902,18 +916,37 @@ static int sctp_heartbeat_chunk_to_string(FILE *s, struct sctp_heartbeat_chunk *chunk, char **error) { - u16 length; + u16 chunk_length, parameter_length, chunk_padding, parameter_padding; + struct sctp_parameter *parameter; + int result; u8 flags; flags = chunk->flags; - length = ntohs(chunk->length); + chunk_length = ntohs(chunk->length); + if (chunk_length < sizeof(struct sctp_heartbeat_chunk) + + sizeof(struct sctp_heartbeat_information_parameter)) { + asprintf(error, "HEARTBEAT chunk too short"); + return STATUS_ERR; + } + chunk_padding = chunk_length & 0x0003; + if (chunk_padding != 0) + chunk_padding = 4 - chunk_padding; + parameter = (struct sctp_parameter *)chunk->value; + parameter_length = ntohs(parameter->length); + parameter_padding = parameter_length & 0x0003; + if (parameter_padding != 0) + parameter_padding = 4 - parameter_padding; + if (chunk_length + chunk_padding != + sizeof(struct sctp_heartbeat_chunk) + + parameter_length + parameter_padding) { + asprintf(error, "HEARTBEAT chunk inconsistent"); + return STATUS_ERR; + } fputs("HEARTBEAT[", s); - if (flags != 0x00) - fprintf(s, "flags=0x%02x, ", flags); - fprintf(s, "info_len=%u", - length - (u16)sizeof(struct sctp_heartbeat_chunk)); + fprintf(s, "flgs=0x%02x, ", flags); + result = sctp_parameter_to_string(s, parameter, error); fputc(']', s); - return STATUS_OK; + return result; } static int sctp_heartbeat_ack_chunk_to_string( @@ -921,18 +954,37 @@ static int sctp_heartbeat_ack_chunk_to_string( struct sctp_heartbeat_ack_chunk *chunk, char **error) { - u16 length; + u16 chunk_length, parameter_length, chunk_padding, parameter_padding; + struct sctp_parameter *parameter; + int result; u8 flags; flags = chunk->flags; - length = ntohs(chunk->length); + chunk_length = ntohs(chunk->length); + if (chunk_length < sizeof(struct sctp_heartbeat_ack_chunk) + + sizeof(struct sctp_heartbeat_information_parameter)) { + asprintf(error, "HEARTBEAT_ACK chunk too short"); + return STATUS_ERR; + } + chunk_padding = chunk_length & 0x0003; + if (chunk_padding != 0) + chunk_padding = 4 - chunk_padding; + parameter = (struct sctp_parameter *)chunk->value; + parameter_length = ntohs(parameter->length); + parameter_padding = parameter_length & 0x0003; + if (parameter_padding != 0) + parameter_padding = 4 - parameter_padding; + if (chunk_length + chunk_padding != + sizeof(struct sctp_heartbeat_chunk) + + parameter_length + parameter_padding) { + asprintf(error, "HEARTBEAT_ACK chunk inconsistent"); + return STATUS_ERR; + } fputs("HEARTBEAT_ACK[", s); - if (flags != 0x00) - fprintf(s, "flags=0x%02x, ", flags); - fprintf(s, "info_len=%u", - length - (u16)sizeof(struct sctp_heartbeat_chunk)); + fprintf(s, "flgs=0x%02x, ", flags); + result = sctp_parameter_to_string(s, parameter, error); fputc(']', s); - return STATUS_OK; + return result; } static int sctp_abort_chunk_to_string(FILE *s, @@ -952,22 +1004,19 @@ static int sctp_abort_chunk_to_string(FILE *s, return STATUS_ERR; } fputs("ABORT[", s); - if (flags != 0x00) { - fputs("flags=", s); - if (flags & ~SCTP_ABORT_CHUNK_T_BIT) - fprintf(s, "0x%02x", chunk->flags); - else - if (flags & SCTP_ABORT_CHUNK_T_BIT) - fputc('T', s); - } + fputs("flgs=", s); + if ((flags & ~SCTP_ABORT_CHUNK_T_BIT) || (flags == 0x00)) + fprintf(s, "0x%02x", flags); + else + if (flags & SCTP_ABORT_CHUNK_T_BIT) + fputc('T', s); index = 0; for (cause = sctp_causes_begin((struct sctp_chunk *)chunk, SCTP_ABORT_CHUNK_CAUSE_OFFSET, &iter, error); cause != NULL; cause = sctp_causes_next(&iter, error)) { - if (((index == 0) && (flags != 0x00)) || (index > 0)) - fputs(", ", s); + fputs(", ", s); if (*error != NULL) break; result = sctp_cause_to_string(s, cause, error); @@ -995,9 +1044,8 @@ static int sctp_shutdown_chunk_to_string(FILE *s, return STATUS_ERR; } fputs("SHUTDOWN[", s); - if (flags != 0x00) - fprintf(s, "flags=0x%02x, ", chunk->flags); - fprintf(s, "tsn=%u", ntohl(chunk->cum_tsn)); + fprintf(s, "flgs=0x%02x, ", chunk->flags); + fprintf(s, "cum_tsn=%u", ntohl(chunk->cum_tsn)); fputc(']', s); return STATUS_OK; } @@ -1018,8 +1066,7 @@ static int sctp_shutdown_ack_chunk_to_string( return STATUS_ERR; } fputs("SHUTDOWN_ACK[", s); - if (flags != 0x00) - fprintf(s, "flags=0x%02x, ", chunk->flags); + fprintf(s, "flgs=0x%02x", chunk->flags); fputc(']', s); return STATUS_OK; } @@ -1041,16 +1088,14 @@ static int sctp_error_chunk_to_string(FILE *s, return STATUS_ERR; } fputs("ERROR[", s); - if (flags != 0x00) - fprintf(s, "flags=0x%02x", chunk->flags); + fprintf(s, "flgs=0x%02x", chunk->flags); index = 0; for (cause = sctp_causes_begin((struct sctp_chunk *)chunk, SCTP_ERROR_CHUNK_CAUSE_OFFSET, &iter, error); cause != NULL; cause = sctp_causes_next(&iter, error)) { - if (((index == 0) && (flags != 0x00)) || (index > 0)) - fputs(", ", s); + fputs(", ", s); if (*error != NULL) break; result = sctp_cause_to_string(s, cause, error); @@ -1075,10 +1120,8 @@ static int sctp_cookie_echo_chunk_to_string( flags = chunk->flags; length = ntohs(chunk->length); fputs("COOKIE_ECHO[", s); - if (flags != 0x00) - fprintf(s, "flags=0x%02x, ", flags); - fprintf(s, "cookie_len=%u", - length - (u16)sizeof(struct sctp_cookie_echo_chunk)); + fprintf(s, "flgs=0x%02x, ", flags); + fprintf(s, "len=%u", length); fputc(']', s); return STATUS_OK; } @@ -1098,8 +1141,7 @@ static int sctp_cookie_ack_chunk_to_string(FILE *s, return STATUS_ERR; } fputs("COOKIE_ACK[", s); - if (flags != 0x00) - fprintf(s, "flags=0x%02x", chunk->flags); + fprintf(s, "flgs=0x%02x", chunk->flags); fputc(']', s); return STATUS_OK; } @@ -1118,8 +1160,7 @@ static int sctp_ecne_chunk_to_string(FILE *s, return STATUS_ERR; } fputs("ECNE[", s); - if (flags != 0x00) - fprintf(s, "flags=0x%02x, ", chunk->flags); + fprintf(s, "flgs=0x%02x, ", chunk->flags); fprintf(s, "tsn=%u", ntohl(chunk->lowest_tsn)); fputc(']', s); return STATUS_OK; @@ -1139,8 +1180,7 @@ static int sctp_cwr_chunk_to_string(FILE *s, return STATUS_ERR; } fputs("CWR[", s); - if (flags != 0x00) - fprintf(s, "flags=0x%02x, ", chunk->flags); + fprintf(s, "flgs=0x%02x, ", chunk->flags); fprintf(s, "tsn=%u", ntohl(chunk->lowest_tsn)); fputc(']', s); return STATUS_OK; @@ -1162,14 +1202,12 @@ static int sctp_shutdown_complete_chunk_to_string( return STATUS_ERR; } fputs("SHUTDOWN_COMPLETE[", s); - if (flags != 0x00) { - fputs("flags=", s); - if (flags & ~SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) - fprintf(s, "0x%02x", chunk->flags); - else - if (flags & SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) - fputc('T', s); - } + fputs("flgs=", s); + if ((flags & ~SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) || (flags == 0x00)) + fprintf(s, "0x%02x", flags); + else + if (flags & SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) + fputc('T', s); fputc(']', s); return STATUS_OK; } diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c index 21cbcfc8c9910fc8ce342e33a86b74a45d70b3df..886a921ca935dd9ed55004141e6c43d77a8b44d3 100644 --- a/gtests/net/packetdrill/sctp_packet.c +++ b/gtests/net/packetdrill/sctp_packet.c @@ -29,8 +29,6 @@ /* * ToDo: - * - Add support for chunk flags (fix hard coded flags for DATA chunk) - * - Add support for user data length in DATA chunks (fix hard coded payload) * - Add support for parameters (fix hard coded state cookie in INIT-ACK) * - Add support for error causes */ @@ -66,7 +64,7 @@ sctp_sack_block_list_append(struct sctp_sack_block_list *list, } void -sctp_sctp_sack_block_list_free(struct sctp_sack_block_list *list) +sctp_sack_block_list_free(struct sctp_sack_block_list *list) { struct sctp_sack_block_list_item *current_item, *next_item; @@ -111,8 +109,72 @@ sctp_sack_block_list_item_dup_new(u32 tsn) return item; } +struct sctp_address_type_list * +sctp_address_type_list_new(void) +{ + struct sctp_address_type_list *list; + + list = malloc(sizeof(struct sctp_address_type_list)); + assert(list != NULL); + list->first = NULL; + list->last = NULL; + list->nr_entries = 0; + return list; +} + +void +sctp_address_type_list_append(struct sctp_address_type_list *list, + struct sctp_address_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_address_type_list_free(struct sctp_address_type_list *list) +{ + struct sctp_address_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_address_type_list_item * +sctp_address_type_list_item_new(u16 address_type) +{ + struct sctp_address_type_list_item *item; + + item = malloc(sizeof(struct sctp_address_type_list_item)); + assert(item != NULL); + item->next = NULL; + item->address_type = address_type; + return item; +} + struct sctp_chunk_list_item * -sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags) +sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags, + struct sctp_parameter_list *list) { struct sctp_chunk_list_item *item; @@ -120,6 +182,7 @@ 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->length = length; item->flags = flags; return item; @@ -183,17 +246,33 @@ sctp_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 ssn, s64 ppid) memset(chunk->data, 0, length + padding_length - sizeof(struct sctp_data_chunk)); return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, - length, flags); + length, flags, + sctp_parameter_list_new()); } struct sctp_chunk_list_item * -sctp_init_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn) +sctp_init_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn, + struct sctp_parameter_list *list) { struct sctp_init_chunk *chunk; + struct sctp_parameter_list_item *item; u32 flags; + u16 offset, chunk_length, chunk_padding_length, parameter_padding_length; flags = 0; - chunk = malloc(sizeof(struct sctp_init_chunk)); + chunk_length = sizeof(struct sctp_init_chunk); + if (list != NULL) { + chunk_length += list->length; + } else { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + flags |= FLAG_INIT_CHUNK_OPT_PARAM_NOCHECK; + list = sctp_parameter_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_INIT_CHUNK_TYPE; if (flgs == -1) { @@ -202,9 +281,7 @@ sctp_init_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn) } else { chunk->flags = (u8)flgs; } - /* FIXME */ - flags |= FLAG_CHUNK_LENGTH_NOCHECK; - chunk->length = htons(sizeof(struct sctp_init_chunk)); + chunk->length = htons(chunk_length); chunk->initiate_tag = htonl((u32)tag); if (a_rwnd == -1) { chunk->a_rwnd = htonl(0); @@ -225,21 +302,50 @@ sctp_init_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn) chunk->is = htons((u16)is); } chunk->initial_tsn = htonl((u32)tsn); + offset = 0; + for (item = list->first; item != NULL; item = item->next) { + parameter_padding_length = item->length % 4; + if (parameter_padding_length > 0) { + parameter_padding_length = 4 - parameter_padding_length; + } + memcpy(chunk->parameter + offset, + item->parameter, + item->length + parameter_padding_length); + free(item->parameter); + item->parameter = (struct sctp_parameter *)(chunk->parameter + offset); + if (item->flags == FLAG_PARAMETER_LENGTH_NOCHECK) { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + } + offset += item->length + parameter_padding_length; + } return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, - (u32)sizeof(struct sctp_init_chunk), - flags); + chunk_length + chunk_padding_length, + flags, list); } -/* FIXME: Don't fake the cookie that way... */ struct sctp_chunk_list_item * -sctp_init_ack_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn) +sctp_init_ack_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn, + struct sctp_parameter_list *list) { struct sctp_init_ack_chunk *chunk; - struct sctp_state_cookie_parameter state_cookie_parameter; + struct sctp_parameter_list_item *item; u32 flags; + u16 offset, chunk_length, chunk_padding_length, parameter_padding_length; flags = 0; - chunk = malloc(sizeof(struct sctp_init_ack_chunk) + sizeof(struct sctp_state_cookie_parameter)); + chunk_length = sizeof(struct sctp_init_ack_chunk); + if (list != NULL) { + chunk_length += list->length; + } else { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + flags |= FLAG_INIT_ACK_CHUNK_OPT_PARAM_NOCHECK; + list = sctp_parameter_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_INIT_ACK_CHUNK_TYPE; if (flgs == -1) { @@ -248,9 +354,7 @@ sctp_init_ack_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn) } else { chunk->flags = (u8)flgs; } - /* FIXME */ - flags |= FLAG_CHUNK_LENGTH_NOCHECK; - chunk->length = htons(sizeof(struct sctp_init_ack_chunk) + sizeof(struct sctp_state_cookie_parameter)); + chunk->length = htons(chunk_length); chunk->initiate_tag = htonl((u32)tag); if (a_rwnd == -1) { chunk->a_rwnd = htonl(0); @@ -271,12 +375,25 @@ sctp_init_ack_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn) chunk->is = htons((u16)is); } chunk->initial_tsn = htonl((u32)tsn); - state_cookie_parameter.type = htons(SCTP_STATE_COOKIE_PARAMETER_TYPE); - state_cookie_parameter.length = htons(sizeof(struct sctp_state_cookie_parameter)); - memcpy(chunk->parameter, &state_cookie_parameter, sizeof(struct sctp_state_cookie_parameter)); + offset = 0; + for (item = list->first; item != NULL; item = item->next) { + parameter_padding_length = item->length % 4; + if (parameter_padding_length > 0) { + parameter_padding_length = 4 - parameter_padding_length; + } + memcpy(chunk->parameter + offset, + item->parameter, + item->length + parameter_padding_length); + free(item->parameter); + item->parameter = (struct sctp_parameter *)(chunk->parameter + offset); + if (item->flags == FLAG_PARAMETER_LENGTH_NOCHECK) { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + } + offset += item->length + parameter_padding_length; + } return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, - (u32)sizeof(struct sctp_init_ack_chunk) + sizeof(struct sctp_state_cookie_parameter), - flags); + chunk_length + chunk_padding_length, + flags, list); } struct sctp_chunk_list_item * @@ -353,17 +470,38 @@ sctp_sack_chunk_new(s64 flgs, s64 cum_tsn, s64 a_rwnd, assert((i == nr_dups) && (item == NULL)); } return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, - length, flags); + length, flags, + sctp_parameter_list_new()); } struct sctp_chunk_list_item * -sctp_heartbeat_chunk_new(s64 flgs) +sctp_heartbeat_chunk_new(s64 flgs, struct sctp_parameter_list_item *info) { struct sctp_heartbeat_chunk *chunk; u32 flags; + u16 chunk_length, padding_length; - flags = FLAG_CHUNK_LENGTH_NOCHECK | FLAG_CHUNK_VALUE_NOCHECK; - chunk = malloc(sizeof(struct sctp_heartbeat_chunk)); + flags = 0; + assert(info == NULL || + info->length + sizeof(struct sctp_heartbeat_chunk) <= MAX_SCTP_CHUNK_BYTES); + chunk_length = sizeof(struct sctp_heartbeat_chunk); + if (info != NULL) { + chunk_length += info->length; + if (info->flags & FLAG_PARAMETER_LENGTH_NOCHECK) { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + } + if (info->flags & FLAG_PARAMETER_VALUE_NOCHECK) { + flags |= FLAG_CHUNK_VALUE_NOCHECK; + } + } else { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + flags |= FLAG_CHUNK_VALUE_NOCHECK; + } + padding_length = chunk_length % 4; + if (padding_length > 0) { + padding_length = 4 - padding_length; + } + chunk = malloc(chunk_length + padding_length); assert(chunk != NULL); chunk->type = SCTP_HEARTBEAT_CHUNK_TYPE; if (flgs == -1) { @@ -372,20 +510,44 @@ sctp_heartbeat_chunk_new(s64 flgs) } else { chunk->flags = (u8)flgs; } - chunk->length = htons(sizeof(struct sctp_heartbeat_chunk)); + chunk->length = htons(chunk_length); + memcpy(chunk->value, info->parameter, info->length); + memset(chunk->value + info->length, 0, padding_length); + free(info->parameter); + free(info); return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, - (u32)sizeof(struct sctp_heartbeat_chunk), - flags); + chunk_length + padding_length, + flags, sctp_parameter_list_new()); } struct sctp_chunk_list_item * -sctp_heartbeat_ack_chunk_new(s64 flgs) +sctp_heartbeat_ack_chunk_new(s64 flgs, struct sctp_parameter_list_item *info) { struct sctp_heartbeat_ack_chunk *chunk; u32 flags; + u16 chunk_length, padding_length; - flags = FLAG_CHUNK_LENGTH_NOCHECK | FLAG_CHUNK_VALUE_NOCHECK; - chunk = malloc(sizeof(struct sctp_heartbeat_ack_chunk)); + flags = 0; + assert(info == NULL || + info->length + sizeof(struct sctp_heartbeat_ack_chunk) <= MAX_SCTP_CHUNK_BYTES); + chunk_length = sizeof(struct sctp_heartbeat_ack_chunk); + if (info != NULL) { + chunk_length += info->length; + if (info->flags & FLAG_PARAMETER_LENGTH_NOCHECK) { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + } + if (info->flags & FLAG_PARAMETER_VALUE_NOCHECK) { + flags |= FLAG_CHUNK_VALUE_NOCHECK; + } + } else { + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + flags |= FLAG_CHUNK_VALUE_NOCHECK; + } + padding_length = chunk_length % 4; + if (padding_length > 0) { + padding_length = 4 - padding_length; + } + chunk = malloc(chunk_length + padding_length); assert(chunk != NULL); chunk->type = SCTP_HEARTBEAT_ACK_CHUNK_TYPE; if (flgs == -1) { @@ -394,10 +556,14 @@ sctp_heartbeat_ack_chunk_new(s64 flgs) } else { chunk->flags = (u8)flgs; } - chunk->length = htons(sizeof(struct sctp_heartbeat_ack_chunk)); + chunk->length = htons(chunk_length); + memcpy(chunk->value, info->parameter, info->length); + memset(chunk->value + info->length, 0, padding_length); + free(info->parameter); + free(info); return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, - (u32)sizeof(struct sctp_heartbeat_ack_chunk), - flags); + chunk_length + padding_length, + flags, sctp_parameter_list_new()); } struct sctp_chunk_list_item * @@ -418,8 +584,8 @@ sctp_abort_chunk_new(s64 flgs) } chunk->length = htons(sizeof(struct sctp_abort_chunk)); return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, - (u32)sizeof(struct sctp_abort_chunk), - flags); + (u32)sizeof(struct sctp_abort_chunk), + flags, sctp_parameter_list_new()); } struct sctp_chunk_list_item * @@ -447,8 +613,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); + (u32)sizeof(struct sctp_shutdown_chunk), + flags, sctp_parameter_list_new()); } struct sctp_chunk_list_item * @@ -469,8 +635,8 @@ 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); + (u32)sizeof(struct sctp_shutdown_ack_chunk), + flags, sctp_parameter_list_new()); } struct sctp_chunk_list_item * @@ -491,18 +657,33 @@ sctp_error_chunk_new(s64 flgs) } chunk->length = htons(sizeof(struct sctp_error_chunk)); return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, - (u32)sizeof(struct sctp_error_chunk), - flags); + (u32)sizeof(struct sctp_error_chunk), + flags, sctp_parameter_list_new()); } struct sctp_chunk_list_item * -sctp_cookie_echo_chunk_new(s64 flgs) +sctp_cookie_echo_chunk_new(s64 flgs, s64 len, u8* cookie) { struct sctp_cookie_echo_chunk *chunk; u32 flags; + u16 chunk_length, cookie_length, padding_length; - flags = FLAG_CHUNK_LENGTH_NOCHECK | FLAG_CHUNK_VALUE_NOCHECK; - chunk = malloc(sizeof(struct sctp_cookie_echo_chunk)); + assert((len == -1) || is_valid_u16(len)); + assert((len != -1) || (cookie == NULL)); + flags = 0; + if (len == -1) { + cookie_length = 0; + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + } else { + assert(len <= MAX_SCTP_CHUNK_BYTES - sizeof(struct sctp_cookie_echo_chunk)); + cookie_length = len - sizeof(struct sctp_cookie_echo_chunk); + } + chunk_length = cookie_length + sizeof(struct sctp_cookie_echo_chunk); + padding_length = chunk_length % 4; + if (padding_length > 0) { + padding_length = 4 - padding_length; + } + chunk = malloc(chunk_length + padding_length); assert(chunk != NULL); chunk->type = SCTP_COOKIE_ECHO_CHUNK_TYPE; if (flgs == -1) { @@ -511,10 +692,18 @@ sctp_cookie_echo_chunk_new(s64 flgs) } else { chunk->flags = (u8)flgs; } - chunk->length = htons(sizeof(struct sctp_cookie_echo_chunk)); + chunk->length = htons(chunk_length); + if (cookie != NULL) { + memcpy(chunk->cookie, cookie, cookie_length); + } else { + flags |= FLAG_CHUNK_VALUE_NOCHECK; + memset(chunk->cookie, 'A', cookie_length); + } + /* Clear the padding */ + memset(chunk->cookie + cookie_length, 0, padding_length); return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, - (u32)sizeof(struct sctp_cookie_echo_chunk), - flags); + chunk_length + padding_length, + flags, sctp_parameter_list_new()); } struct sctp_chunk_list_item * @@ -535,8 +724,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); + (u32)sizeof(struct sctp_cookie_ack_chunk), + flags, sctp_parameter_list_new()); } struct sctp_chunk_list_item * @@ -564,8 +753,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); + (u32)sizeof(struct sctp_ecne_chunk), + flags, sctp_parameter_list_new()); } struct sctp_chunk_list_item * @@ -593,8 +782,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); + (u32)sizeof(struct sctp_cwr_chunk), + flags, sctp_parameter_list_new()); } struct sctp_chunk_list_item * @@ -615,8 +804,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); + (u32)sizeof(struct sctp_shutdown_complete_chunk), + flags, sctp_parameter_list_new()); } struct sctp_chunk_list * @@ -659,7 +848,361 @@ sctp_chunk_list_free(struct sctp_chunk_list *list) while (current_item != NULL) { next_item = current_item->next; assert(next_item != NULL || current_item == list->last); - assert(current_item->chunk != NULL); + assert(current_item->parameter_list); + sctp_parameter_list_free(current_item->parameter_list); + free(current_item); + current_item = next_item; + } + free(list); +} + +struct sctp_parameter_list_item * +sctp_parameter_list_item_new(struct sctp_parameter *parameter, u32 length, u32 flags) +{ + struct sctp_parameter_list_item *item; + + item = malloc(sizeof(struct sctp_parameter_list_item)); + assert(item != NULL); + item->next = NULL; + item->parameter = parameter; + item->length = length; + item->flags = flags; + return item; +} + +struct sctp_parameter_list_item * +sctp_heartbeat_information_parameter_new(s64 len, u8 *information) +{ + struct sctp_heartbeat_information_parameter *parameter; + u32 flags; + u16 parameter_length, information_length, padding_length; + + assert((len == -1) || is_valid_u16(len)); + assert((len != -1) || (information == NULL)); + flags = 0; + if (len == -1) { + information_length = 0; + flags |= FLAG_PARAMETER_LENGTH_NOCHECK; + } else { + assert(len <= MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_heartbeat_information_parameter)); + information_length = len - sizeof(struct sctp_heartbeat_information_parameter); + } + parameter_length = information_length + sizeof(struct sctp_heartbeat_information_parameter); + padding_length = parameter_length % 4; + if (padding_length > 0) { + padding_length = 4 - padding_length; + } + parameter = malloc(parameter_length + padding_length); + assert(parameter != NULL); + parameter->type = htons(SCTP_HEARTBEAT_INFORMATION_PARAMETER_TYPE); + parameter->length = htons(parameter_length); + if (information != NULL) { + memcpy(parameter->information, information, information_length); + } else { + flags |= FLAG_PARAMETER_VALUE_NOCHECK; + memset(parameter->information, 'A', information_length); + } + /* Clear the padding */ + memset(parameter->information + information_length, 0, padding_length); + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + parameter_length, flags); +} + +struct sctp_parameter_list_item * +sctp_ipv4_address_parameter_new(struct in_addr *addr) +{ + struct sctp_ipv4_address_parameter *parameter; + u32 flags; + + flags = 0; + parameter = malloc(sizeof(struct sctp_ipv4_address_parameter)); + assert(parameter != NULL); + parameter->type = htons(SCTP_IPV4_ADDRESS_PARAMETER_TYPE); + parameter->length = htons(sizeof(struct sctp_ipv4_address_parameter)); + if (addr == NULL) { + parameter->addr.s_addr = htonl(INADDR_ANY); + flags |= FLAG_PARAMETER_VALUE_NOCHECK; + } else { + parameter->addr = *addr; + } + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + sizeof(struct sctp_ipv4_address_parameter), + flags); +} + +struct sctp_parameter_list_item * +sctp_ipv6_address_parameter_new(struct in6_addr *addr) +{ + struct sctp_ipv6_address_parameter *parameter; + u32 flags; + + flags = 0; + parameter = malloc(sizeof(struct sctp_ipv6_address_parameter)); + assert(parameter != NULL); + parameter->type = htons(SCTP_IPV6_ADDRESS_PARAMETER_TYPE); + parameter->length = htons(sizeof(struct sctp_ipv6_address_parameter)); + if (addr == NULL) { + parameter->addr = in6addr_any; + flags |= FLAG_PARAMETER_VALUE_NOCHECK; + } else { + parameter->addr = *addr; + } + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + sizeof(struct sctp_ipv6_address_parameter), + flags); +} + +struct sctp_parameter_list_item * +sctp_state_cookie_parameter_new(s64 len, u8 *cookie) +{ + struct sctp_state_cookie_parameter *parameter; + u32 flags; + u16 parameter_length, cookie_length, padding_length; + + assert((len == -1) || is_valid_u16(len)); + assert((len != -1) || (cookie == NULL)); + flags = 0; + if (len == -1) { + cookie_length = 0; + flags |= FLAG_PARAMETER_LENGTH_NOCHECK; + } else { + assert(len <= MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_state_cookie_parameter)); + cookie_length = len - sizeof(struct sctp_state_cookie_parameter); + } + parameter_length = cookie_length + sizeof(struct sctp_state_cookie_parameter); + padding_length = parameter_length % 4; + if (padding_length > 0) { + padding_length = 4 - padding_length; + } + parameter = malloc(parameter_length + padding_length); + assert(parameter != NULL); + parameter->type = htons(SCTP_STATE_COOKIE_PARAMETER_TYPE); + parameter->length = htons(parameter_length); + if (cookie != NULL) { + memcpy(parameter->cookie, cookie, cookie_length); + } else { + /* flags |= FLAG_PARAMETER_VALUE_NOCHECK; */ + memset(parameter->cookie, 'A', cookie_length); + } + /* Clear the padding */ + memset(parameter->cookie + cookie_length, 0, padding_length); + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + parameter_length, flags); +} + +struct sctp_parameter_list_item * +sctp_unrecognized_parameters_parameter_new(struct sctp_parameter_list *list) +{ + struct sctp_unrecognized_parameter_parameter *parameter; + struct sctp_parameter_list_item *item; + u32 flags; + u16 parameter_length, padding_length, offset; + + assert(list == NULL || + (list->length < + MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_unrecognized_parameter_parameter))); + flags = 0; + parameter_length = sizeof(struct sctp_unrecognized_parameter_parameter); + if (list != NULL) { + parameter_length += list->length; + } else { + flags |= FLAG_PARAMETER_LENGTH_NOCHECK; + flags |= FLAG_PARAMETER_VALUE_NOCHECK; + } + padding_length = parameter_length % 4; + if (padding_length > 0) { + padding_length = 4 - padding_length; + } + parameter = malloc(parameter_length + padding_length); + assert(parameter != NULL); + parameter->type = htons(SCTP_UNRECOGNIZED_PARAMETER_PARAMETER_TYPE); + parameter->length = htons(parameter_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(parameter->value + offset, item->parameter, item->length + padding_length); + if (item->flags & FLAG_PARAMETER_LENGTH_NOCHECK) { + flags |= FLAG_PARAMETER_LENGTH_NOCHECK; + } + if (item->flags & FLAG_PARAMETER_VALUE_NOCHECK) { + flags |= FLAG_PARAMETER_VALUE_NOCHECK; + } + offset += item->length + padding_length; + } + } + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + parameter_length, flags); +} + +struct sctp_parameter_list_item * +sctp_cookie_preservative_parameter_new(s64 increment) +{ + struct sctp_cookie_preservative_parameter *parameter; + u32 flags; + + flags = 0; + parameter = malloc(sizeof(struct sctp_cookie_preservative_parameter)); + assert(parameter != NULL); + parameter->type = htons(SCTP_COOKIE_PRESERVATIVE_PARAMETER_TYPE); + parameter->length = htons(sizeof(struct sctp_cookie_preservative_parameter)); + if (increment == -1) { + parameter->increment = htonl(0); + flags |= FLAG_PARAMETER_VALUE_NOCHECK; + } else { + assert(is_valid_u32(increment)); + parameter->increment = htonl((u32)increment); + } + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + sizeof(struct sctp_cookie_preservative_parameter), + flags); +} + +struct sctp_parameter_list_item * +sctp_hostname_address_parameter_new(char *hostname) +{ + struct sctp_hostname_address_parameter *parameter; + u32 flags; + u16 length, name_length, padding_length; + + /* RFC 4960 requires that the hostname is NUL terminated */ + assert(hostname == NULL || + (strlen(hostname) + 1 <= + MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_hostname_address_parameter))); + flags = 0; + if (hostname == NULL) { + name_length = 1; + } else { + name_length = strlen(hostname) + 1; + } + length = name_length + sizeof(struct sctp_hostname_address_parameter); + padding_length = length % 4; + if (padding_length > 0) { + padding_length = 4 - padding_length; + } + parameter = malloc(length + padding_length); + assert(parameter != NULL); + parameter->type = htons(SCTP_HOSTNAME_ADDRESS_PARAMETER_TYPE); + parameter->length = htons(length); + if (hostname == NULL) { + parameter->hostname[0] = '\0'; + flags |= FLAG_PARAMETER_LENGTH_NOCHECK; + flags |= FLAG_PARAMETER_VALUE_NOCHECK; + } else { + strcpy(parameter->hostname, hostname); + } + memset(parameter->hostname + name_length, 0, padding_length); + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + length, flags); +} + +struct sctp_parameter_list_item * +sctp_supported_address_types_parameter_new(struct sctp_address_type_list *list) +{ + struct sctp_supported_address_types_parameter *parameter; + + u32 flags; + u16 i, parameter_length, padding_length; + struct sctp_address_type_list_item *item; + + flags = 0; + parameter_length = sizeof(struct sctp_supported_address_types_parameter); + if (list != NULL) { + assert(list->nr_entries <= + (MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_supported_address_types_parameter)) / sizeof(u16)); + parameter_length += list->nr_entries * sizeof(u16); + } + padding_length = parameter_length % 4; + if (padding_length > 0) { + padding_length = 4 - padding_length; + } + assert(padding_length == 0 || padding_length == 2); + parameter = malloc(parameter_length + padding_length); + assert(parameter != NULL); + parameter->type = htons(SCTP_SUPPORTED_ADDRESS_TYPES_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->address_type[i] = htons(item->address_type); + } + assert((i == list->nr_entries) && (item == NULL)); + } + if (padding_length == 2) { + parameter->address_type[list->nr_entries] = htons(0); + } + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + parameter_length, flags); +} + + +/* SCTP_SUPPORTED_ADDRESS_TYPES_PARAMETER_TYPE */ + +struct sctp_parameter_list_item * +sctp_ecn_capable_parameter_new(void) +{ + struct sctp_ecn_capable_parameter *parameter; + + parameter = malloc(sizeof(struct sctp_ecn_capable_parameter)); + assert(parameter != NULL); + parameter->type = htons(SCTP_ECN_CAPABLE_PARAMETER_TYPE); + parameter->length = htons(sizeof(struct sctp_ecn_capable_parameter)); + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + sizeof(struct sctp_ecn_capable_parameter), + 0); +} + +struct sctp_parameter_list * +sctp_parameter_list_new(void) +{ + struct sctp_parameter_list *list; + + list = malloc(sizeof(struct sctp_parameter_list)); + assert(list != NULL); + list->first = NULL; + list->last = NULL; + list->length = 0; + return list; +} + +void +sctp_parameter_list_append(struct sctp_parameter_list *list, + struct sctp_parameter_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_parameter_list_free(struct sctp_parameter_list *list) +{ + struct sctp_parameter_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; } @@ -675,7 +1218,8 @@ new_sctp_packet(int address_family, { struct packet *packet; /* the newly-allocated result packet */ struct header *sctp_header; /* the SCTP header info */ - struct sctp_chunk_list_item *item; + struct sctp_chunk_list_item *chunk_item; + struct sctp_parameter_list_item *parameter_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) + @@ -701,91 +1245,117 @@ new_sctp_packet(int address_family, } if (direction == DIRECTION_INBOUND) { - for (item = list->first; item != NULL; item = item->next) { - switch (item->chunk->type) { + for (chunk_item = list->first; + chunk_item != NULL; + chunk_item = chunk_item->next) { + for (parameter_item = chunk_item->parameter_list->first; + parameter_item != NULL; + parameter_item = parameter_item->next) { + if (parameter_item->flags & FLAG_PARAMETER_LENGTH_NOCHECK) { + asprintf(error, + "parameter length must be specified for inbound packets"); + return NULL; + } + if (parameter_item->flags & FLAG_PARAMETER_VALUE_NOCHECK) { + asprintf(error, + "parameter value must be specified for inbound packets"); + return NULL; + } + } + switch (chunk_item->chunk->type) { case SCTP_DATA_CHUNK_TYPE: - if (item->flags & FLAG_CHUNK_FLAGS_NOCHECK) { + if (chunk_item->flags & FLAG_CHUNK_FLAGS_NOCHECK) { asprintf(error, "chunk flags must be specified for inbound packets"); return NULL; } - if (item->flags & FLAG_CHUNK_LENGTH_NOCHECK) { + if (chunk_item->flags & FLAG_CHUNK_LENGTH_NOCHECK) { asprintf(error, "chunk length must be specified for inbound packets"); return NULL; - } - if (item->flags & FLAG_DATA_CHUNK_TSN_NOCHECK) { + } + if (chunk_item->flags & FLAG_DATA_CHUNK_TSN_NOCHECK) { asprintf(error, "TSN must be specified for inbound packets"); return NULL; } - if (item->flags & FLAG_DATA_CHUNK_SID_NOCHECK) { + if (chunk_item->flags & FLAG_DATA_CHUNK_SID_NOCHECK) { asprintf(error, "SID must be specified for inbound packets"); return NULL; } - if (item->flags & FLAG_DATA_CHUNK_SSN_NOCHECK) { + if (chunk_item->flags & FLAG_DATA_CHUNK_SSN_NOCHECK) { asprintf(error, "SSN must be specified for inbound packets"); return NULL; } - if (item->flags & FLAG_DATA_CHUNK_PPID_NOCHECK) { + if (chunk_item->flags & FLAG_DATA_CHUNK_PPID_NOCHECK) { asprintf(error, "PPID must be specified for inbound packets"); return NULL; - } + } break; case SCTP_INIT_CHUNK_TYPE: - if (item->flags & FLAG_INIT_CHUNK_A_RWND_NOCHECK) { + if (chunk_item->flags & FLAG_INIT_CHUNK_A_RWND_NOCHECK) { asprintf(error, "A_RWND must be specified for inbound packets"); return NULL; } - if (item->flags & FLAG_INIT_CHUNK_OS_NOCHECK) { + if (chunk_item->flags & FLAG_INIT_CHUNK_OS_NOCHECK) { asprintf(error, "OS must be specified for inbound packets"); return NULL; } - if (item->flags & FLAG_INIT_CHUNK_IS_NOCHECK) { + if (chunk_item->flags & FLAG_INIT_CHUNK_IS_NOCHECK) { asprintf(error, "IS must be specified for inbound packets"); return NULL; } + if (chunk_item->flags & FLAG_INIT_CHUNK_OPT_PARAM_NOCHECK) { + asprintf(error, + "list of optional parameters must be specified for inbound packets"); + return NULL; + } break; case SCTP_INIT_ACK_CHUNK_TYPE: - if (item->flags & FLAG_INIT_ACK_CHUNK_A_RWND_NOCHECK) { + if (chunk_item->flags & FLAG_INIT_ACK_CHUNK_A_RWND_NOCHECK) { asprintf(error, "A_RWND must be specified for inbound packets"); return NULL; } - if (item->flags & FLAG_INIT_ACK_CHUNK_OS_NOCHECK) { + if (chunk_item->flags & FLAG_INIT_ACK_CHUNK_OS_NOCHECK) { asprintf(error, "OS must be specified for inbound packets"); return NULL; } - if (item->flags & FLAG_INIT_ACK_CHUNK_IS_NOCHECK) { + if (chunk_item->flags & FLAG_INIT_ACK_CHUNK_IS_NOCHECK) { asprintf(error, "IS must be specified for inbound packets"); return NULL; } + if (chunk_item->flags & FLAG_INIT_ACK_CHUNK_OPT_PARAM_NOCHECK) { + asprintf(error, + "list of optional parameters must be specified for inbound packets"); + return NULL; + } break; case SCTP_SACK_CHUNK_TYPE: - if (item->flags & FLAG_SACK_CHUNK_CUM_TSN_NOCHECK) { + if (chunk_item->flags & FLAG_SACK_CHUNK_CUM_TSN_NOCHECK) { asprintf(error, "CUM_TSN must be specified for inbound packets"); return NULL; } - if (item->flags & FLAG_SACK_CHUNK_A_RWND_NOCHECK) { + if (chunk_item->flags & FLAG_SACK_CHUNK_A_RWND_NOCHECK) { asprintf(error, "A_RWND must be specified for inbound packets"); return NULL; - } - if (item->flags & FLAG_SACK_CHUNK_GAP_BLOCKS_NOCHECK) { + } + if (chunk_item->flags & FLAG_SACK_CHUNK_GAP_BLOCKS_NOCHECK) { asprintf(error, "GAP_BLOCKS must be specified for inbound packets"); return NULL; } - if (item->flags & FLAG_SACK_CHUNK_DUP_TSNS_NOCHECK) { + if (chunk_item->flags & FLAG_SACK_CHUNK_DUP_TSNS_NOCHECK) { asprintf(error, "DUP_TSNS must be specified for inbound packets"); return NULL; @@ -797,14 +1367,14 @@ new_sctp_packet(int address_family, overbook = true; break; case SCTP_ABORT_CHUNK_TYPE: - if (item->flags & FLAG_CHUNK_LENGTH_NOCHECK) { + if (chunk_item->flags & FLAG_CHUNK_LENGTH_NOCHECK) { asprintf(error, "error causes must be specified for inbound packets"); return NULL; - } + } break; case SCTP_SHUTDOWN_CHUNK_TYPE: - if (item->flags & FLAG_SHUTDOWN_CHUNK_CUM_TSN_NOCHECK) { + if (chunk_item->flags & FLAG_SHUTDOWN_CHUNK_CUM_TSN_NOCHECK) { asprintf(error, "TSN must be specified for inbound packets"); return NULL; @@ -813,11 +1383,11 @@ new_sctp_packet(int address_family, case SCTP_SHUTDOWN_ACK_CHUNK_TYPE: break; case SCTP_ERROR_CHUNK_TYPE: - if (item->flags & FLAG_CHUNK_LENGTH_NOCHECK) { + if (chunk_item->flags & FLAG_CHUNK_LENGTH_NOCHECK) { asprintf(error, "error causes must be specified for inbound packets"); return NULL; - } + } break; case SCTP_COOKIE_ECHO_CHUNK_TYPE: overbook = true; @@ -825,14 +1395,14 @@ new_sctp_packet(int address_family, case SCTP_COOKIE_ACK_CHUNK_TYPE: break; case SCTP_ECNE_CHUNK_TYPE: - if (item->flags & FLAG_ECNE_CHUNK_LOWEST_TSN_NOCHECK) { + if (chunk_item->flags & FLAG_ECNE_CHUNK_LOWEST_TSN_NOCHECK) { asprintf(error, "LOWEST_TSN must be specified for inbound packets"); return NULL; } break; case SCTP_CWR_CHUNK_TYPE: - if (item->flags & FLAG_CWR_CHUNK_LOWEST_TSN_NOCHECK) { + if (chunk_item->flags & FLAG_CWR_CHUNK_LOWEST_TSN_NOCHECK) { asprintf(error, "LOWEST_TSN must be specified for inbound packets"); return NULL; @@ -841,12 +1411,12 @@ new_sctp_packet(int address_family, case SCTP_SHUTDOWN_COMPLETE_CHUNK_TYPE: break; default: - asprintf(error, "Unknown chunk type 0x%02x", item->chunk->type); + asprintf(error, "Unknown chunk type 0x%02x", chunk_item->chunk->type); return NULL; } } } - + /* Allocate and zero out a packet object of the desired size */ packet = packet_new(overbook ? MAX_SCTP_DATAGRAM_BYTES : ip_bytes); memset(packet->buffer, 0, overbook ? MAX_SCTP_DATAGRAM_BYTES : ip_bytes); @@ -872,14 +1442,21 @@ new_sctp_packet(int address_family, packet->sctp->v_tag = htonl(0); packet->sctp->crc32c = htonl(0); - for (item = list->first; item != NULL; item = item->next) { - DEBUGP("Copy in a chunk of length %d\n", item->length); - memcpy(sctp_chunk_start, item->chunk, item->length); - DEBUGP("Old location: %p\n", (void *)item->chunk); - free(item->chunk); - item->chunk = (struct sctp_chunk *)sctp_chunk_start; - DEBUGP("New location: %p\n", (void *)item->chunk); - sctp_chunk_start += item->length; + for (chunk_item = list->first; + chunk_item != NULL; + chunk_item = chunk_item->next) { + memcpy(sctp_chunk_start, chunk_item->chunk, chunk_item->length); + for (parameter_item = chunk_item->parameter_list->first; + parameter_item != NULL; + parameter_item = parameter_item->next) { + parameter_item->parameter = + (struct sctp_parameter *)(sctp_chunk_start + + ((u8 *)parameter_item->parameter - + (u8 *)chunk_item->chunk)); + } + free(chunk_item->chunk); + chunk_item->chunk = (struct sctp_chunk *)sctp_chunk_start; + sctp_chunk_start += chunk_item->length; } free(packet->chunk_list); packet->chunk_list = list; diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h index 6ac35603d36b5fb834fbb36b8865984ce96020bb..eacbe555a8a228b1bb1f7f08639a09b7d83b3daf 100644 --- a/gtests/net/packetdrill/sctp_packet.h +++ b/gtests/net/packetdrill/sctp_packet.h @@ -48,7 +48,7 @@ sctp_sack_block_list_append(struct sctp_sack_block_list *list, struct sctp_sack_block_list_item *item); void -sctp_sctp_sack_block_list_free(struct sctp_sack_block_list *list); +sctp_sack_block_list_free(struct sctp_sack_block_list *list); struct sctp_sack_block_list_item * sctp_sack_block_list_item_gap_new(u16 start, u16 end); @@ -56,9 +56,50 @@ sctp_sack_block_list_item_gap_new(u16 start, u16 end); struct sctp_sack_block_list_item * sctp_sack_block_list_item_dup_new(u32 tsn); +struct sctp_address_type_list_item { + struct sctp_address_type_list_item *next; + u16 address_type; +}; + +struct sctp_address_type_list { + struct sctp_address_type_list_item *first; + struct sctp_address_type_list_item *last; + u16 nr_entries; +}; + +struct sctp_address_type_list * +sctp_address_type_list_new(void); + +void +sctp_address_type_list_append(struct sctp_address_type_list *list, + struct sctp_address_type_list_item *item); + +void +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_list_item { + struct sctp_parameter_list_item *next; + struct sctp_parameter *parameter; + /* total length in bytes */ + u32 length; + /* metadata */ + u32 flags; +}; + +struct sctp_parameter_list { + struct sctp_parameter_list_item *first; + struct sctp_parameter_list_item *last; + /* length in bytes excluding the padding of the last parameter*/ + u32 length; +}; + struct sctp_chunk_list_item { struct sctp_chunk_list_item *next; struct sctp_chunk *chunk; + struct sctp_parameter_list *parameter_list; /* total length in bytes */ u32 length; /* metadata */ @@ -78,7 +119,8 @@ struct sctp_chunk_list { #define FLAG_CHUNK_VALUE_NOCHECK 0x00000008 struct sctp_chunk_list_item * -sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags); +sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags, + struct sctp_parameter_list *list); #define FLAG_DATA_CHUNK_TSN_NOCHECK 0x00000100 #define FLAG_DATA_CHUNK_SID_NOCHECK 0x00000200 @@ -91,16 +133,20 @@ sctp_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 ssn, s64 ppid); #define FLAG_INIT_CHUNK_A_RWND_NOCHECK 0x00000100 #define FLAG_INIT_CHUNK_OS_NOCHECK 0x00000200 #define FLAG_INIT_CHUNK_IS_NOCHECK 0x00000400 +#define FLAG_INIT_CHUNK_OPT_PARAM_NOCHECK 0x00000800 struct sctp_chunk_list_item * -sctp_init_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn); +sctp_init_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn, + struct sctp_parameter_list *parameters); #define FLAG_INIT_ACK_CHUNK_A_RWND_NOCHECK 0x00000100 #define FLAG_INIT_ACK_CHUNK_OS_NOCHECK 0x00000200 #define FLAG_INIT_ACK_CHUNK_IS_NOCHECK 0x00000400 +#define FLAG_INIT_ACK_CHUNK_OPT_PARAM_NOCHECK 0x00000800 struct sctp_chunk_list_item * -sctp_init_ack_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn); +sctp_init_ack_chunk_new(s64 flgs, s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn, + struct sctp_parameter_list *parameters); #define FLAG_SACK_CHUNK_CUM_TSN_NOCHECK 0x00000100 #define FLAG_SACK_CHUNK_A_RWND_NOCHECK 0x00000200 @@ -113,10 +159,10 @@ sctp_sack_chunk_new(s64 flgs, s64 cum_tsn, s64 a_rwnd, struct sctp_sack_block_list *dups); struct sctp_chunk_list_item * -sctp_heartbeat_chunk_new(s64 flgs); +sctp_heartbeat_chunk_new(s64 flgs, struct sctp_parameter_list_item *info); struct sctp_chunk_list_item * -sctp_heartbeat_ack_chunk_new(s64 flgs); +sctp_heartbeat_ack_chunk_new(s64 flgs, struct sctp_parameter_list_item *info); struct sctp_chunk_list_item * sctp_abort_chunk_new(s64 flgs); @@ -133,7 +179,7 @@ struct sctp_chunk_list_item * sctp_error_chunk_new(s64 flgs); struct sctp_chunk_list_item * -sctp_cookie_echo_chunk_new(s64 flgs); +sctp_cookie_echo_chunk_new(s64 flgs, s64 len, u8* cookie); struct sctp_chunk_list_item * sctp_cookie_ack_chunk_new(s64 flgs); @@ -151,12 +197,61 @@ sctp_cwr_chunk_new(s64 flgs, s64 lowest_tsn); struct sctp_chunk_list_item * sctp_shutdown_complete_chunk_new(s64 flgs); -struct sctp_chunk_list *sctp_chunk_list_new(void); +struct sctp_chunk_list * +sctp_chunk_list_new(void); -void sctp_chunk_list_append(struct sctp_chunk_list *list, - struct sctp_chunk_list_item *item); +void +sctp_chunk_list_append(struct sctp_chunk_list *list, + struct sctp_chunk_list_item *item); + +void +sctp_chunk_list_free(struct sctp_chunk_list *list); + +#define FLAG_PARAMETER_TYPE_NOCHECK 0x00000001 +#define FLAG_PARAMETER_LENGTH_NOCHECK 0x00000002 +#define FLAG_PARAMETER_VALUE_NOCHECK 0x00000004 + +struct sctp_parameter_list_item * +sctp_parameter_list_item_new(struct sctp_parameter *parameter, + u32 length, u32 flags); + +struct sctp_parameter_list_item * +sctp_heartbeat_information_parameter_new(s64 len, u8 *information); + +struct sctp_parameter_list_item * +sctp_ipv4_address_parameter_new(struct in_addr *addr); + +struct sctp_parameter_list_item * +sctp_ipv6_address_parameter_new(struct in6_addr *addr); + +struct sctp_parameter_list_item * +sctp_state_cookie_parameter_new(s64 len, u8 *cookie); + +struct sctp_parameter_list_item * +sctp_unrecognized_parameters_parameter_new(struct sctp_parameter_list *list); + +struct sctp_parameter_list_item * +sctp_cookie_preservative_parameter_new(s64 increment); + +struct sctp_parameter_list_item * +sctp_hostname_address_parameter_new(char *hostname); + +struct sctp_parameter_list_item * +sctp_supported_address_types_parameter_new(struct sctp_address_type_list *list); + +struct sctp_parameter_list_item * +sctp_ecn_capable_parameter_new(void); + +struct sctp_parameter_list * +sctp_parameter_list_new(void); + +void +sctp_parameter_list_append(struct sctp_parameter_list *list, + struct sctp_parameter_list_item *item); + +void +sctp_parameter_list_free(struct sctp_parameter_list *list); -void sctp_chunk_list_free(struct sctp_chunk_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_active.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_active.pkt index 64a442fc3dd18117aae85dfed7c4df93e366f0f0..87c7266d8f3fe52275e1be8edbadee69cea3e549 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_active.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_active.pkt @@ -1,27 +1,36 @@ + 0.0 `sysctl -w net.inet.sctp.ecn_enable=1` ++0.0 `sysctl -w net.inet.sctp.pr_enable=0` ++0.0 `sysctl -w net.inet.sctp.asconf_enable=0` ++0.0 `sysctl -w net.inet.sctp.auth_enable=0` ++0.0 `sysctl -w net.inet.sctp.reconfig_enable=0` ++0.0 `sysctl -w net.inet.sctp.nrsack_enable=0` ++0.0 `sysctl -w net.inet.sctp.pktdrop_enable=0` +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 en empty(!) cookie +// Check the handshake with an empty(!) cookie +0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) -+0.0 > sctp: INIT[tag=1 tsn=0] -+0.1 < sctp: INIT_ACK[tag=2 a_rwnd=1500 os=1 is =1 tsn=3] // faked cookie -+0.0 > sctp: COOKIE_ECHO[] // syntax not clear -+0.1 < sctp: COOKIE_ACK[] ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ECN_CAPABLE[], SUPPORTED_ADDRESS_TYPES[types=[IPv4]]] ++0.1 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=3, STATE_COOKIE[len=4, val=...], SUPPORTED_ADDRESS_TYPES[types=[IPv4]]] ++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 -// Send some data. +// Send some data ++0.5 < sctp: HEARTBEAT[flgs=0, HEARTBEAT_INFORMATION[len=9, val=...]] ++0.0 > sctp: HEARTBEAT_ACK[flgs=0, HEARTBEAT_INFORMATION[len=9, val=...]] +1.0 write(3, ..., 1000) = 1000 -+0.0 > sctp: DATA[tsn=0 sid=0 ssn=0 ppid=0] -+0.1 < sctp: SACK[tsn=0 a_rwnd=1500 gaps=[] dups=[]] ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=0, sid=0, ssn=0, ppid=0] ++0.1 < sctp: SACK[flgs=0, cum_tsn=0, a_rwnd=1500, gaps=[], dups=[]] // Receive some data -+1.0 < sctp: DATA[flgs=BE len=1016 tsn=3 sid=0 ssn=0 ppid=0] ++1.0 < sctp: DATA[flgs=BE, len=1016, tsn=3, sid=0, ssn=0, ppid=0] +0.0 read(3, ..., 2000) = 1000 -+0.0 > sctp: SACK[tsn=3] -// Receive more data, observe delayed SACK -+1.0 < sctp: DATA[flgs=IBE len=1016 tsn=4 sid=0 ssn=1 ppid=0] ++0.0 > sctp: SACK[flgs=..., cum_tsn=3, a_rwnd=..., gaps=..., dups=...] +// Receive more data, observe a non-delayed SACK ++1.0 < sctp: DATA[flgs=IBE, len=1016, tsn=4, sid=0, ssn=1, ppid=0] +0.0 read(3, ..., 2000) = 1000 -+0.0 > sctp: SACK[tsn=4] ++0.0 > sctp: SACK[flgs=0, cum_tsn=4, a_rwnd=..., gaps=..., dups=...] // Tear down the association +0.0 close(3) = 0 -+0.0 > sctp: SHUTDOWN[tsn=4] -+0.1 < sctp: SHUTDOWN_ACK[] -+0.0 > sctp: SHUTDOWN_COMPLETE[] ++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=4] ++0.1 < sctp: SHUTDOWN_ACK[flgs=0] ++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0] diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_handle_init.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_handle_init.pkt index eafcaf511913f7ad930b38a0c0e6f22ff19d09d1..389c938f9c98b29eef11d5362b52e79f31f2305a 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_handle_init.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_handle_init.pkt @@ -2,6 +2,6 @@ +0.0 bind(3, ..., ...) = 0 +0.0 listen(3, 1) = 0 // The initiate tag in the INIT chunk MUST NOT be zero. -+0.1 < sctp: INIT[tag=0, a_rwnd=1500, is=1, os=1, tsn=0] -+0.0 > sctp: ABORT[INVALID_MANDATORY_PARAMETER[]] ++0.1 < sctp: INIT[flgs=0, tag=0, a_rwnd=1500, os=1, is=1, tsn=0] ++0.0 > sctp: ABORT[flgs=T] +0.0 close(3) = 0 diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_hb.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_hb.pkt index 0869034e21a5ede4a42d0f56a138f61156d0ebd1..d7278191e3a6a00553a113bdb747fc72d8da8f7b 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_hb.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_hb.pkt @@ -4,18 +4,18 @@ +0.0 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) +0.0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 +0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) -+0.0 > sctp: INIT[tag=1 tsn=1] // FIXME -+0.0 < sctp: INIT_ACK[tag=2 a_rwnd=1500 os=1 is =1 tsn=1] // FIXME -+0.0 > sctp: COOKIE_ECHO[] // FIXME -+0.0 < sctp: COOKIE_ACK[] ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...] ++0.0 < 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.0 < sctp: COOKIE_ACK[flgs=0] +0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 // then respond to two HEARTBEATs - * > sctp: HEARTBEAT[] -+0.0 < sctp: HEARTBEAT_ACK[] - * > sctp: HEARTBEAT[] -+0.0 < sctp: HEARTBEAT_ACK[] + * > sctp: HEARTBEAT[flgs=0, HEARTBEAT_INFORMATION[len=..., val=...]] ++0.0 < sctp: HEARTBEAT_ACK[flgs=0, HEARTBEAT_INFORMATION[len=..., val=...]] + * > sctp: HEARTBEAT[flgs=0, HEARTBEAT_INFORMATION[len=..., val=...]] ++0.0 < sctp: HEARTBEAT_ACK[flgs=0, HEARTBEAT_INFORMATION[len=..., val=...]] // and finally perform a graceful shutdown +0.0 close(3) = 0 -+0.0 > sctp: SHUTDOWN[tsn=0] -+0.0 < sctp: SHUTDOWN_ACK[] -+0.0 > sctp: SHUTDOWN_COMPLETE[] ++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=0] ++0.0 < sctp: SHUTDOWN_ACK[flgs=0] ++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0] diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_icmp_active.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_icmp_active.pkt index c02a9e0898471f1f5a204caf750c01f2d5f31fa8..5aa6a0ee4d172c4f21430a113a15065063050ee8 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_icmp_active.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_icmp_active.pkt @@ -4,20 +4,20 @@ +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[tag=1 tsn=0] -+0.1 < sctp: INIT_ACK[tag=2 a_rwnd=4500 os=1 is =1 tsn=3] // faked cookie -+0.0 > sctp: COOKIE_ECHO[] // faked cookie -+0.1 < sctp: COOKIE_ACK[] ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] ++0.1 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=4500, os=1, is =1, tsn=3, 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 // Reduce the PMTU. +0.5 < [sctp(2)] icmp unreachable frag_needed mtu 1500 // Send some data and get it acknowledged. +0.5 write(3, ..., 2000) = 2000 -+0.0 > sctp: DATA[flgs=B len=1468 tsn=0 sid=0 ssn=0 ppid=0] -+0.0 > sctp: DATA[flgs=E len=564 tsn=1 sid=0 ssn=0 ppid=0] -+0.1 < sctp: SACK[tsn=1 a_rwnd=1500 gaps=[] dups=[]] ++0.0 > sctp: DATA[flgs=B, len=1468, tsn=0, sid=0, ssn=0, ppid=0] ++0.0 > sctp: DATA[flgs=E, len=564, tsn=1, sid=0, ssn=0, ppid=0] ++0.1 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]] // Tear down the association +0.0 close(3) = 0 -+0.0 > sctp: SHUTDOWN[tsn=2] -+0.1 < sctp: SHUTDOWN_ACK[] -+0.0 > sctp: SHUTDOWN_COMPLETE[] ++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=2] ++0.1 < sctp: SHUTDOWN_ACK[flgs=0] ++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0] diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_icmp_passive.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_icmp_passive.pkt index eb801515eba3609c7801ae284048b42700cfe8ed..82460960f70072d748c936f7ca48e61e2ac42c9a 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_icmp_passive.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_icmp_passive.pkt @@ -2,21 +2,21 @@ // Check the handshake with en empty(!) cookie +0.0 bind(3, ..., ...) = 0 +0.0 listen(3, 1) = 0 -+0.0 < sctp: INIT[tag=1 a_rwnd=4500 os=1 is=1 tsn=1] -+0.0 > sctp: INIT_ACK[tag=2 tsn=0] // faked cookie -+0.1 < sctp: COOKIE_ECHO[] -+0.0 > sctp: COOKIE_ACK[] ++0.0 < sctp: INIT[flgs=0, tag=1, a_rwnd=4500, os=1, is=1, tsn=1] ++0.0 > sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=..., os=..., is=..., tsn=0, STATE_COOKIE[len=..., val=...]] ++0.1 < sctp: COOKIE_ECHO[flgs=0, len=..., val=...] ++0.0 > sctp: COOKIE_ACK[flgs=0] +0.0 accept(3, ..., ...) = 4 +0.0 close(3) = 0 // Reduce the PMTU. +0.5 < [sctp(1)] icmp unreachable frag_needed mtu 1500 // Send some data and get it acknowledged. +0.5 write(4, ..., 2000) = 2000 -+0.0 > sctp: DATA[flgs=B len=1468 tsn=0 sid=0 ssn=0 ppid=0] -+0.0 > sctp: DATA[flgs=E len=564 tsn=1 sid=0 ssn=0 ppid=0] -+0.1 < sctp: SACK[tsn=1 a_rwnd=4500 gaps=[] dups=[]] ++0.0 > sctp: DATA[flgs=B, len=1468, tsn=0, sid=0, ssn=0, ppid=0] ++0.0 > sctp: DATA[flgs=E, len=564, tsn=1, sid=0, ssn=0, ppid=0] ++0.1 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=4500, gaps=[], dups=[]] // Tear down the association +0.0 close(4) = 0 -+0.0 > sctp: SHUTDOWN[tsn=0] -+0.1 < sctp: SHUTDOWN_ACK[] -+0.0 > sctp: SHUTDOWN_COMPLETE[] ++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=0] ++0.1 < sctp: SHUTDOWN_ACK[flgs=0] ++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0] diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_init_rtx.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_init_rtx.pkt index 2254235e731b1dfe92447ee4507bf53b99d4f7cf..64b992533a5b723d22c17cba1fdabca0de3e0c8e 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_init_rtx.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_init_rtx.pkt @@ -1,26 +1,18 @@ - 0.0 `sysctl -w net.inet.sctp.ecn_enable=0` -+0.0 `sysctl -w net.inet.sctp.pr_enable=0` -+0.0 `sysctl -w net.inet.sctp.asconf_enable=0` -+0.0 `sysctl -w net.inet.sctp.auth_enable=0` -+0.0 `sysctl -w net.inet.sctp.reconfig_enable=0` -+0.0 `sysctl -w net.inet.sctp.nrsack_enable=0` -+0.0 `sysctl -w net.inet.sctp.pktdrop_enable=0` +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 +0.0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=800, srto_min=100}, 16) = 0 +0.0 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) // Check the number and the timing of the restransmissions -+0.0 > sctp: INIT[tag=..., a_rwnd=..., is=10, os=2048, tsn=0, ...] -+0.1 > sctp: INIT[tag=..., a_rwnd=..., is=10, os=2048, tsn=0, ...] -+0.2 > sctp: INIT[tag=..., a_rwnd=..., is=10, os=2048, tsn=0, ...] -+0.4 > sctp: INIT[tag=..., a_rwnd=..., is=10, os=2048, tsn=0, ...] -+0.8 > sctp: INIT[tag=..., a_rwnd=..., is=10, os=2048, tsn=0, ...] -+0.8 > sctp: INIT[tag=..., a_rwnd=..., is=10, os=2048, tsn=0, ...] -+0.8 > sctp: INIT[tag=..., a_rwnd=..., is=10, os=2048, tsn=0, ...] -+0.8 > sctp: INIT[tag=..., a_rwnd=..., is=10, os=2048, tsn=0, ...] -+0.8 > sctp: INIT[tag=..., a_rwnd=..., is=10, os=2048, tsn=0, ...] -// Look as if we don't send a final ABORT. Shouldn't we? -// +1.0 > sctp: ABORT[] ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] ++0.1 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] ++0.2 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] ++0.4 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] ++0.8 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] ++0.8 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] ++0.8 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] ++0.8 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] ++0.8 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] ++0.8 > sctp: ABORT[flgs=T] +1.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [ETIMEDOUT], [4]) = 0 +0.0 close(3) = 0 diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt index 3ca6b026b4e2005dac3befa621a27d483e6cf946..e8b517f568f34a74db70bd4fff7f235ec510dcfc 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt @@ -1,28 +1,35 @@ + 0.0 `sysctl -w net.inet.sctp.ecn_enable=1` ++0.0 `sysctl -w net.inet.sctp.pr_enable=0` ++0.0 `sysctl -w net.inet.sctp.asconf_enable=0` ++0.0 `sysctl -w net.inet.sctp.auth_enable=0` ++0.0 `sysctl -w net.inet.sctp.reconfig_enable=0` ++0.0 `sysctl -w net.inet.sctp.nrsack_enable=0` ++0.0 `sysctl -w net.inet.sctp.pktdrop_enable=0` +0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 // Check the handshake with en empty(!) cookie +0.0 bind(3, ..., ...) = 0 +0.0 listen(3, 1) = 0 -+0.0 < sctp: INIT[tag=1 a_rwnd=1500 os=1 is=1 tsn=0] -+0.0 > sctp: INIT_ACK[tag=2 tsn=10] // faked cookie -+0.1 < sctp: COOKIE_ECHO[]; DATA[flgs=0x03 len=1016 tsn=0 sid=0 ssn=0 ppid=0]// syntax not clear -+0.0 > sctp: COOKIE_ACK[]; SACK[tsn=0] ++0.0 < sctp: INIT[flgs=0, tag=1, a_rwnd=1500, os=1, is=1, tsn=0, ECN_CAPABLE[], COOKIE_PRESERVATIVE[incr=12345], SUPPORTED_ADDRESS_TYPES[types=[IPv4]]] ++0.0 > sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=..., os=..., is=..., tsn=10, STATE_COOKIE[len=..., val=...]] ++0.1 < sctp: COOKIE_ECHO[flgs=0, len=..., val=...]; DATA[flgs=BE, len=1016, tsn=0, sid=0, ssn=0, ppid=0] ++0.0 > sctp: COOKIE_ACK[flgs=0]; SACK[flgs=0, cum_tsn=0, a_rwnd=..., gaps=..., dups=...] +0.0 accept(3, ..., ...) = 4 +0.0 read(4, ..., 1000) = 1000 // Send some data. +1.0 write(4, ..., 1000) = 1000 -+0.0 > sctp: DATA[tsn=10 sid=0 ssn=0 ppid=0] -+0.1 < sctp: SACK[tsn=10 a_rwnd=1500 gaps=[] dups=[]] ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=10, sid=0, ssn=0, ppid=0] ++0.1 < sctp: SACK[flgs=0, cum_tsn=10, a_rwnd=1500, gaps=[], dups=[]] // Receive some data -+1.0 < sctp: DATA[flgs=BE len=1016 tsn=1 sid=0 ssn=1 ppid=0] ++1.0 < sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=1, ppid=0] +0.0 read(4, ..., 2000) = 1000 -+0.2 > sctp: SACK[tsn=1] ++0.2 > sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=..., gaps=[], dups=[]] // Receive more data, observe delayed SACKi -+1.0 < sctp: DATA[flgs=BE len=1016 tsn=2 sid=0 ssn=2 ppid=0] ++1.0 < sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=2, ppid=0] +0.0 read(4, ..., 2000) = 1000 -+0.2 > sctp: SACK[tsn=2] ++0.2 > sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=..., gaps=[], dups=[]] // Tear down the association -+1.0 < sctp: SHUTDOWN[tsn=10] -+0.0 > sctp: SHUTDOWN_ACK[] -+0.0 < sctp: SHUTDOWN_COMPLETE[] ++1.0 < sctp: SHUTDOWN[flgs=0, cum_tsn=10] ++0.0 > sctp: SHUTDOWN_ACK[flgs=0] ++0.0 < sctp: SHUTDOWN_COMPLETE[flgs=0] +0.0 close(4) = 0 +0.0 close(3) = 0