From af421ceab33380c20fb0884ff79792538035a150 Mon Sep 17 00:00:00 2001 From: Michael Tuexen <tuexen@fh-muenster.de> Date: Sat, 23 May 2015 20:45:42 +0200 Subject: [PATCH] Add support for RFC 4820 (Padding chunk and parameter) This patch add support for the PAD chunk and PAD parameter defined in https://tools.ietf.org/html/rfc4820 This fixes https://github.com/nplab/packetdrill/issues/16 --- gtests/net/packetdrill/lexer.l | 1 + .../net/packetdrill/packet_to_string_test.c | 86 +++++++++++------- gtests/net/packetdrill/parser.y | 26 +++++- gtests/net/packetdrill/run_packet.c | 13 +++ gtests/net/packetdrill/sctp.h | 15 ++++ gtests/net/packetdrill/sctp_chunk_to_string.c | 41 ++++++++- gtests/net/packetdrill/sctp_packet.c | 89 ++++++++++++++++++- gtests/net/packetdrill/sctp_packet.h | 6 ++ .../tests/bsd/sctp/sctp_active.pkt | 2 +- .../tests/bsd/sctp/sctp_passive.pkt | 4 +- 10 files changed, 243 insertions(+), 40 deletions(-) diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index d5fb23b8..e462478e 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -227,6 +227,7 @@ COOKIE_ACK return COOKIE_ACK; ECNE return ECNE; CWR return CWR; SHUTDOWN_COMPLETE return SHUTDOWN_COMPLETE; +PAD return PAD; flgs return FLAGS; len return LEN; tag return TAG; diff --git a/gtests/net/packetdrill/packet_to_string_test.c b/gtests/net/packetdrill/packet_to_string_test.c index b81befab..ae497533 100644 --- a/gtests/net/packetdrill/packet_to_string_test.c +++ b/gtests/net/packetdrill/packet_to_string_test.c @@ -102,7 +102,7 @@ static void test_sctp_ipv6_packet_to_string(void) /* An IPv6/SCTP packet. */ u8 data[] = { /* IPv6 Base Header: */ - 0x60, 0x00, 0x00, 0x00, 0x01, 0x80, 0x84, 0xff, + 0x60, 0x00, 0x00, 0x00, 0x01, 0xa0, 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, - 0x22, 0x3e, 0x3f, 0x1c, + 0x6e, 0xfc, 0x47, 0x17, /* SCTP DATA Chunk */ 0x00, 0x0f, 0x00, 0x13, 0x01, 0x02, 0x03, 0x04, @@ -118,7 +118,7 @@ static void test_sctp_ipv6_packet_to_string(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, /* SCTP INIT Chunk */ - 0x01, 0x00, 0x00, 0x50, + 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, @@ -138,6 +138,10 @@ static void test_sctp_ipv6_packet_to_string(void) 0x00, 0x05, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, + 0x80, 0x05, 0x00, 0x10, + 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, /* SCTP INIT_ACK Chunk */ 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, @@ -219,7 +223,12 @@ static void test_sctp_ipv6_packet_to_string(void) 0x0d, 0x00, 0x00, 0x08, 0x01, 0x02, 0x03, 0x04, /* SCTP SHUTDOWN_COMPLETE Chunk */ - 0x0e, 0x01, 0x00, 0x04 + 0x0e, 0x01, 0x00, 0x04, + /* SCTP PAD Chunk */ + 0x84, 0x00, 0x00, 0x10, + 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50 }; struct packet *packet = packet_new(sizeof(data)); @@ -249,7 +258,8 @@ static void test_sctp_ipv6_packet_to_string(void) "COOKIE_PRESERVATIVE[incr=65536], " "HOSTNAME[addr=\"@A\"], " "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], " - "ECN_CAPABLE[]]; " + "ECN_CAPABLE[], " + "PAD[len=16, val=...]]; " "INIT_ACK[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " "STATE_COOKIE[len=7, val=...], " "UNRECOGNIZED_PARAMETER[params=[" @@ -265,7 +275,7 @@ static void test_sctp_ipv6_packet_to_string(void) "OUT_OF_RESOURCES[], " "UNRESOLVABLE_ADDRESS[HOSTNAME[addr=\"@A\"]], " "UNRECOGNIZED_CHUNK[" - "CHUNK[type=0xfe, flags=0x05, value=[0x01]]], " + "CHUNK[type=0xfe, flgs=0x05, value=[0x01]]], " "INVALID_MANDATORY_PARAMETER[], " "UNRECOGNIZED_PARAMETERS[" "PARAMETER[type=0x800a, value=[]], " @@ -283,7 +293,8 @@ static void test_sctp_ipv6_packet_to_string(void) "COOKIE_ACK[flgs=0x00]; " "ECNE[flgs=0x00, tsn=16909060]; " "CWR[flgs=0x00, tsn=16909060]; " - "SHUTDOWN_COMPLETE[flgs=T]"; + "SHUTDOWN_COMPLETE[flgs=T]; " + "PAD[flgs=0x00, len=16, val=...]"; assert(strcmp(dump, expected) == 0); free(dump); @@ -302,7 +313,8 @@ static void test_sctp_ipv6_packet_to_string(void) "COOKIE_PRESERVATIVE[incr=65536], " "HOSTNAME[addr=\"@A\"], " "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], " - "ECN_CAPABLE[]]; " + "ECN_CAPABLE[], " + "PAD[len=16, val=...]]; " "INIT_ACK[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " "STATE_COOKIE[len=7, val=...], " "UNRECOGNIZED_PARAMETER[params=[" @@ -318,7 +330,7 @@ static void test_sctp_ipv6_packet_to_string(void) "OUT_OF_RESOURCES[], " "UNRESOLVABLE_ADDRESS[HOSTNAME[addr=\"@A\"]], " "UNRECOGNIZED_CHUNK[" - "CHUNK[type=0xfe, flags=0x05, value=[0x01]]], " + "CHUNK[type=0xfe, flgs=0x05, value=[0x01]]], " "INVALID_MANDATORY_PARAMETER[], " "UNRECOGNIZED_PARAMETERS[" "PARAMETER[type=0x800a, value=[]], " @@ -336,7 +348,8 @@ static void test_sctp_ipv6_packet_to_string(void) "COOKIE_ACK[flgs=0x00]; " "ECNE[flgs=0x00, tsn=16909060]; " "CWR[flgs=0x00, tsn=16909060]; " - "SHUTDOWN_COMPLETE[flgs=T]"; + "SHUTDOWN_COMPLETE[flgs=T]; " + "PAD[flgs=0x00, len=16, val=...]"; assert(strcmp(dump, expected) == 0); free(dump); @@ -355,7 +368,8 @@ static void test_sctp_ipv6_packet_to_string(void) "COOKIE_PRESERVATIVE[incr=65536], " "HOSTNAME[addr=\"@A\"], " "SUPPORTED_ADDRESS_TYPES[types=[IPv4, IPv6, HOSTNAME]], " - "ECN_CAPABLE[]]; " + "ECN_CAPABLE[], " + "PAD[len=16, val=...]]; " "INIT_ACK[flgs=0x00, tag=1, a_rwnd=65536, os=15, is=15, tsn=16909060, " "STATE_COOKIE[len=7, val=...], " "UNRECOGNIZED_PARAMETER[params=[" @@ -371,7 +385,7 @@ static void test_sctp_ipv6_packet_to_string(void) "OUT_OF_RESOURCES[], " "UNRESOLVABLE_ADDRESS[HOSTNAME[addr=\"@A\"]], " "UNRECOGNIZED_CHUNK[" - "CHUNK[type=0xfe, flags=0x05, value=[0x01]]], " + "CHUNK[type=0xfe, flgs=0x05, value=[0x01]]], " "INVALID_MANDATORY_PARAMETER[], " "UNRECOGNIZED_PARAMETERS[" "PARAMETER[type=0x800a, value=[]], " @@ -389,35 +403,39 @@ static void test_sctp_ipv6_packet_to_string(void) "COOKIE_ACK[flgs=0x00]; " "ECNE[flgs=0x00, tsn=16909060]; " "CWR[flgs=0x00, tsn=16909060]; " - "SHUTDOWN_COMPLETE[flgs=T]" + "SHUTDOWN_COMPLETE[flgs=T]; " + "PAD[flgs=0x00, len=16, val=...]" "\n" - "0x0000: 60 00 00 00 01 80 84 ff 00 02 00 00 00 00 00 00 " "\n" + "0x0000: 60 00 00 00 01 a0 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: 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" + "0x0030: 6e fc 47 17 00 0f 00 13 01 02 03 04 00 ff 01 00 " "\n" + "0x0040: 00 00 00 00 00 01 02 00 01 00 00 60 00 00 00 01 " "\n" "0x0050: 00 01 00 00 00 0f 00 0f 01 02 03 04 00 05 00 08 " "\n" "0x0060: 01 02 03 04 00 06 00 14 00 00 00 00 00 00 00 00 " "\n" "0x0070: 00 00 00 00 00 00 00 01 00 09 00 08 00 01 00 00 " "\n" "0x0080: 00 0b 00 06 40 41 00 00 00 0c 00 0a 00 05 00 06 " "\n" - "0x0090: 00 0b 00 00 80 00 00 04 02 00 00 24 00 00 00 01 " "\n" - "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 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"; + "0x0090: 00 0b 00 00 80 00 00 04 80 05 00 10 50 50 50 50 " "\n" + "0x00a0: 50 50 50 50 50 50 50 50 02 00 00 24 00 00 00 01 " "\n" + "0x00b0: 00 01 00 00 00 0f 00 0f 01 02 03 04 00 07 00 07 " "\n" + "0x00c0: 01 02 03 00 00 08 00 08 80 01 00 04 03 00 00 20 " "\n" + "0x00d0: 01 02 03 04 00 01 00 00 00 03 00 01 00 01 00 03 " "\n" + "0x00e0: 00 05 00 0f 10 00 10 14 01 02 03 04 04 00 00 0a " "\n" + "0x00f0: 00 01 00 06 01 02 00 00 05 00 00 0a 00 01 00 06 " "\n" + "0x0100: 01 02 00 00 06 01 00 04 06 00 00 80 00 01 00 08 " "\n" + "0x0110: 00 ff 00 00 00 02 00 0a 00 00 00 01 00 07 00 00 " "\n" + "0x0120: 00 03 00 08 00 01 00 00 00 04 00 04 00 05 00 0c " "\n" + "0x0130: 00 0b 00 06 40 41 00 00 00 06 00 0c fe 05 00 05 " "\n" + "0x0140: 01 00 00 00 00 07 00 04 00 08 00 10 80 0a 00 04 " "\n" + "0x0150: 80 0b 00 05 01 00 00 00 00 09 00 08 01 02 03 04 " "\n" + "0x0160: 00 0a 00 04 00 0b 00 14 00 05 00 08 01 02 03 04 " "\n" + "0x0170: 00 05 00 08 02 03 04 05 00 0c 00 07 42 59 45 00 " "\n" + "0x0180: 00 0d 00 06 40 40 00 00 07 00 00 08 01 02 03 04 " "\n" + "0x0190: 08 00 00 04 09 00 00 04 0a 00 00 05 45 00 00 00 " "\n" + "0x01a0: 0b 00 00 04 0c 00 00 08 01 02 03 04 0d 00 00 08 " "\n" + "0x01b0: 01 02 03 04 0e 01 00 04 84 00 00 10 50 50 50 50 " "\n" + "0x01c0: 50 50 50 50 50 50 50 50 " "\n"; + printf("expected = '%s'\n", expected); 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 2e1d93f1..593603fa 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -503,7 +503,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %token <reserved> SACK_DELAY SACK_FREQ %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> SHUTDOWN_COMPLETE PAD %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 @@ -561,6 +561,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <chunk_list_item> sctp_cookie_echo_chunk_spec sctp_cookie_ack_chunk_spec %type <chunk_list_item> sctp_ecne_chunk_spec sctp_cwr_chunk_spec %type <chunk_list_item> sctp_shutdown_complete_chunk_spec +%type <chunk_list_item> sctp_pad_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 @@ -572,6 +573,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <parameter_list_item> sctp_hostname_address_parameter_spec %type <parameter_list_item> sctp_supported_address_types_parameter_spec %type <parameter_list_item> sctp_ecn_capable_parameter_spec +%type <parameter_list_item> sctp_pad_parameter_spec %type <integer> opt_flags opt_data_flags opt_abort_flags %type <integer> opt_shutdown_complete_flags opt_chunk_len @@ -787,6 +789,7 @@ sctp_chunk_spec | sctp_ecne_chunk_spec { $$ = $1; } | sctp_cwr_chunk_spec { $$ = $1; } | sctp_shutdown_complete_chunk_spec { $$ = $1; } +| sctp_pad_chunk_spec { $$ = $1; } ; opt_chunk_len @@ -1175,6 +1178,11 @@ sctp_shutdown_complete_chunk_spec $$ = sctp_shutdown_complete_chunk_new($3); } +sctp_pad_chunk_spec +: PAD '[' opt_flags ',' opt_chunk_len ',' VAL '=' ELLIPSIS ']' { + $$ = sctp_pad_chunk_new($3, $5, NULL); +} + opt_parameter_list_spec : ',' ELLIPSIS { $$ = NULL; } | { $$ = sctp_parameter_list_new(); } @@ -1198,6 +1206,7 @@ sctp_parameter_spec | sctp_hostname_address_parameter_spec { $$ = $1; } | sctp_supported_address_types_parameter_spec { $$ = $1; } | sctp_ecn_capable_parameter_spec { $$ = $1; } +| sctp_pad_parameter_spec { $$ = $1; } ; sctp_heartbeat_information_parameter_spec @@ -1315,6 +1324,21 @@ sctp_ecn_capable_parameter_spec $$ = sctp_ecn_capable_parameter_new(); } +sctp_pad_parameter_spec +: PAD '[' ELLIPSIS ']' { + $$ = sctp_pad_parameter_new(-1, NULL); +} +| PAD '[' LEN '=' ELLIPSIS ',' VAL '=' ELLIPSIS ']' { + $$ = sctp_pad_parameter_new(-1, NULL); +} +| PAD '[' LEN '=' INTEGER ',' VAL '=' ELLIPSIS ']' { + if (($5 < sizeof(struct sctp_pad_parameter)) || + !is_valid_u32($5)) { + semantic_error("len value out of range"); + } + $$ = sctp_pad_parameter_new($5, NULL); +} + tcp_packet_spec : packet_prefix opt_ip_info flags seq opt_ack opt_window opt_tcp_options { char *error = NULL; diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c index 3eea2703..bf23e161 100644 --- a/gtests/net/packetdrill/run_packet.c +++ b/gtests/net/packetdrill/run_packet.c @@ -1426,6 +1426,14 @@ static int verify_shutdown_complete_chunk(struct sctp_shutdown_complete_chunk *a return STATUS_OK; } +static int verify_pad_chunk(struct sctp_pad_chunk *actual_chunk, + struct sctp_pad_chunk *script_chunk, + u32 flags, char **error) +{ + /* Nothing to check */ + return STATUS_OK; +} + /* Verify that required actual SCTP packet fields are as the script expected. */ static int verify_sctp( const struct packet *actual_packet, @@ -1559,6 +1567,11 @@ static int verify_sctp( (struct sctp_shutdown_complete_chunk *)script_chunk, flags, error); break; + case SCTP_PAD_CHUNK_TYPE: + result = verify_pad_chunk((struct sctp_pad_chunk *)actual_chunk, + (struct sctp_pad_chunk *)script_chunk, + flags, error); + break; default: result = STATUS_ERR; assert(!"unsupported SCTP chunk type"); diff --git a/gtests/net/packetdrill/sctp.h b/gtests/net/packetdrill/sctp.h index 74ce79aa..b4e36e24 100644 --- a/gtests/net/packetdrill/sctp.h +++ b/gtests/net/packetdrill/sctp.h @@ -52,6 +52,7 @@ struct sctp_common_header { #define SCTP_ECNE_CHUNK_TYPE 0x0c #define SCTP_CWR_CHUNK_TYPE 0x0d #define SCTP_SHUTDOWN_COMPLETE_CHUNK_TYPE 0x0e +#define SCTP_PAD_CHUNK_TYPE 0x84 #define MAX_SCTP_CHUNK_BYTES 0xffff @@ -204,6 +205,13 @@ struct sctp_shutdown_complete_chunk { __be16 length; } __packed; +struct sctp_pad_chunk { + __u8 type; + __u8 flags; + __be16 length; + __u8 padding_data[]; +} __packed; + #define SCTP_HEARTBEAT_INFORMATION_PARAMETER_TYPE 0x0001 #define SCTP_IPV4_ADDRESS_PARAMETER_TYPE 0x0005 #define SCTP_IPV6_ADDRESS_PARAMETER_TYPE 0x0006 @@ -213,6 +221,7 @@ struct sctp_shutdown_complete_chunk { #define SCTP_HOSTNAME_ADDRESS_PARAMETER_TYPE 0x000b #define SCTP_SUPPORTED_ADDRESS_TYPES_PARAMETER_TYPE 0x000c #define SCTP_ECN_CAPABLE_PARAMETER_TYPE 0x8000 +#define SCTP_PAD_PARAMETER_TYPE 0x8005 #define MAX_SCTP_PARAMETER_BYTES 0xffff @@ -275,6 +284,12 @@ struct sctp_ecn_capable_parameter { __be16 length; } __packed; +struct sctp_pad_parameter { + __be16 type; + __be16 length; + __be16 padding_data[]; +} __packed; + #define SCTP_INVALID_STREAM_IDENTIFIER_CAUSE_CODE 0x0001 #define SCTP_MISSING_MADATORY_PARAMETER_CAUSE_CODE 0x0002 #define SCTP_STALE_COOKIE_ERROR_CAUSE_CODE 0x0003 diff --git a/gtests/net/packetdrill/sctp_chunk_to_string.c b/gtests/net/packetdrill/sctp_chunk_to_string.c index c365e7c3..e909bfc0 100644 --- a/gtests/net/packetdrill/sctp_chunk_to_string.c +++ b/gtests/net/packetdrill/sctp_chunk_to_string.c @@ -219,6 +219,20 @@ static int sctp_ecn_capable_parameter_to_string( return STATUS_OK; } +static int sctp_pad_parameter_to_string( + FILE *s, + struct sctp_pad_parameter *parameter, + char **error) +{ + u16 length; + + length = ntohs(parameter->length); + fputs("PAD[", s); + fprintf(s, "len=%u, ", length); + fputs("val=...]", s); + return STATUS_OK; +} + static int sctp_unknown_parameter_to_string( FILE *s, struct sctp_parameter *parameter, @@ -291,6 +305,10 @@ static int sctp_parameter_to_string(FILE *s, result = sctp_ecn_capable_parameter_to_string(s, (struct sctp_ecn_capable_parameter *)parameter, error); break; + case SCTP_PAD_PARAMETER_TYPE: + result = sctp_pad_parameter_to_string(s, + (struct sctp_pad_parameter *)parameter, error); + break; default: result = sctp_unknown_parameter_to_string(s, parameter, error); break; @@ -1212,6 +1230,23 @@ static int sctp_shutdown_complete_chunk_to_string( return STATUS_OK; } +static int sctp_pad_chunk_to_string( + FILE *s, + struct sctp_pad_chunk *chunk, + char **error) +{ + u8 flags; + u16 length; + + flags = chunk->flags; + length = ntohs(chunk->length); + fputs("PAD[", s); + fprintf(s, "flgs=0x%02x, ", chunk->flags); + fprintf(s, "len=%u, ", length); + fputs("val=...]", s); + return STATUS_OK; +} + static int sctp_unknown_chunk_to_string(FILE *s, struct sctp_chunk *chunk, char **error) @@ -1221,7 +1256,7 @@ static int sctp_unknown_chunk_to_string(FILE *s, length = ntohs(chunk->length); fputs("CHUNK[", s); fprintf(s, "type=0x%02x, ", chunk->type); - fprintf(s, "flags=0x%02x, ", chunk->flags); + fprintf(s, "flgs=0x%02x, ", chunk->flags); fputs("value=[", s); for (i = 0; i < length - sizeof(struct sctp_chunk); i++) fprintf(s, "%s0x%02x", @@ -1296,6 +1331,10 @@ int sctp_chunk_to_string(FILE *s, struct sctp_chunk *chunk, char **error) result = sctp_shutdown_complete_chunk_to_string(s, (struct sctp_shutdown_complete_chunk *)chunk, error); break; + case SCTP_PAD_CHUNK_TYPE: + result = sctp_pad_chunk_to_string(s, + (struct sctp_pad_chunk *)chunk, error); + break; default: result = sctp_unknown_chunk_to_string(s, chunk, error); break; diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c index 886a921c..b1610938 100644 --- a/gtests/net/packetdrill/sctp_packet.c +++ b/gtests/net/packetdrill/sctp_packet.c @@ -808,6 +808,51 @@ sctp_shutdown_complete_chunk_new(s64 flgs) flags, sctp_parameter_list_new()); } +struct sctp_chunk_list_item * +sctp_pad_chunk_new(s64 flgs, s64 len, u8* padding) +{ + struct sctp_pad_chunk *chunk; + u32 flags; + u16 chunk_length, padding_length, chunk_padding_length; + + assert((len == -1) || is_valid_u16(len)); + assert((len != -1) || (padding == NULL)); + flags = 0; + if (len == -1) { + padding_length = 0; + flags |= FLAG_CHUNK_LENGTH_NOCHECK; + } else { + assert(len <= MAX_SCTP_CHUNK_BYTES - sizeof(struct sctp_pad_chunk)); + padding_length = len - sizeof(struct sctp_pad_chunk); + } + chunk_length = padding_length + sizeof(struct sctp_pad_chunk); + 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_PAD_CHUNK_TYPE; + if (flgs == -1) { + chunk->flags = 0; + flags |= FLAG_CHUNK_FLAGS_NOCHECK; + } else { + chunk->flags = (u8)flgs; + } + chunk->length = htons(chunk_length); + if (padding != NULL) { + memcpy(chunk->padding_data, padding, padding_length); + } else { + flags |= FLAG_CHUNK_VALUE_NOCHECK; + memset(chunk->padding_data, 'P', padding_length); + } + /* Clear the padding */ + memset(chunk->padding_data + padding_length, 0, chunk_padding_length); + return sctp_chunk_list_item_new((struct sctp_chunk *)chunk, + chunk_length + chunk_padding_length, + flags, sctp_parameter_list_new()); +} + struct sctp_chunk_list * sctp_chunk_list_new(void) { @@ -1139,8 +1184,43 @@ sctp_supported_address_types_parameter_new(struct sctp_address_type_list *list) parameter_length, flags); } +struct sctp_parameter_list_item * +sctp_pad_parameter_new(s64 len, u8 *padding) +{ + struct sctp_pad_parameter *parameter; + u32 flags; + u16 parameter_length, padding_length, parameter_padding_length; -/* SCTP_SUPPORTED_ADDRESS_TYPES_PARAMETER_TYPE */ + assert((len == -1) || is_valid_u16(len)); + assert((len != -1) || (padding == NULL)); + flags = 0; + if (len == -1) { + padding_length = 0; + flags |= FLAG_PARAMETER_LENGTH_NOCHECK; + } else { + assert(len <= MAX_SCTP_PARAMETER_BYTES - sizeof(struct sctp_pad_parameter)); + padding_length = len - sizeof(struct sctp_pad_parameter); + } + parameter_length = padding_length + sizeof(struct sctp_pad_parameter); + parameter_padding_length = parameter_length % 4; + if (parameter_padding_length > 0) { + parameter_padding_length = 4 - parameter_padding_length; + } + parameter = malloc(parameter_length + parameter_padding_length); + assert(parameter != NULL); + parameter->type = htons(SCTP_PAD_PARAMETER_TYPE); + parameter->length = htons(parameter_length); + if (padding != NULL) { + memcpy(parameter->padding_data, padding, padding_length); + } else { + /* flags |= FLAG_PARAMETER_VALUE_NOCHECK; */ + memset(parameter->padding_data, 'P', padding_length); + } + /* Clear the padding */ + memset(parameter->padding_data + padding_length, 0, parameter_padding_length); + return sctp_parameter_list_item_new((struct sctp_parameter *)parameter, + parameter_length, flags); +} struct sctp_parameter_list_item * sctp_ecn_capable_parameter_new(void) @@ -1410,6 +1490,13 @@ new_sctp_packet(int address_family, break; case SCTP_SHUTDOWN_COMPLETE_CHUNK_TYPE: break; + case SCTP_PAD_CHUNK_TYPE: + if (chunk_item->flags & FLAG_CHUNK_LENGTH_NOCHECK) { + asprintf(error, + "chunk length must be specified for inbound packets"); + return NULL; + } + break; default: asprintf(error, "Unknown chunk type 0x%02x", chunk_item->chunk->type); return NULL; diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h index eacbe555..36df5f54 100644 --- a/gtests/net/packetdrill/sctp_packet.h +++ b/gtests/net/packetdrill/sctp_packet.h @@ -197,6 +197,9 @@ 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_item * +sctp_pad_chunk_new(s64 flgs, s64 len, u8* padding); + struct sctp_chunk_list * sctp_chunk_list_new(void); @@ -242,6 +245,9 @@ 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_item * +sctp_pad_parameter_new(s64 len, u8 *padding); + struct sctp_parameter_list * sctp_parameter_list_new(void); diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_active.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_active.pkt index 87c7266d..c0c7d0c0 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_active.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_active.pkt @@ -16,7 +16,7 @@ +0.1 < sctp: COOKIE_ACK[flgs=0] +0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 // Send some data -+0.5 < sctp: HEARTBEAT[flgs=0, HEARTBEAT_INFORMATION[len=9, val=...]] ++0.5 < sctp: HEARTBEAT[flgs=0, HEARTBEAT_INFORMATION[len=9, val=...]]; PAD[flgs=0, len=1300, val=...] +0.0 > sctp: HEARTBEAT_ACK[flgs=0, HEARTBEAT_INFORMATION[len=9, val=...]] +1.0 write(3, ..., 1000) = 1000 +0.0 > sctp: DATA[flgs=BE, len=1016, tsn=0, sid=0, ssn=0, ppid=0] diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt index e8b517f5..5accc93c 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_passive.pkt @@ -9,9 +9,9 @@ // Check the handshake with en empty(!) cookie +0.0 bind(3, ..., ...) = 0 +0.0 listen(3, 1) = 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[flgs=0, tag=1, a_rwnd=1500, os=1, is=1, tsn=0, ECN_CAPABLE[], COOKIE_PRESERVATIVE[incr=12345], SUPPORTED_ADDRESS_TYPES[types=[IPv4]], PAD[len=500, val=...], PAD[len=500, val=...]] +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.1 < sctp: COOKIE_ECHO[flgs=0, len=..., val=...]; PAD[flgs=0, len=10, 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 -- GitLab