diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index 4980fdd81f2f576bbcdf50bc91dda24874571639..5179907b893c25b9cac2f4b4614a5e57207cd101 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -318,6 +318,7 @@ info return CAUSE_INFO; staleness return STALENESS; param return PARAM; chk return CHK; +bad_crc32c return BAD_CRC32C; --[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.h b/gtests/net/packetdrill/packet.h index 6348cc4ea24d69b6b8f999b6441068b031d4e754..832f6125665a1dcdcfd3abeb58d5c1a1a285da64 100644 --- a/gtests/net/packetdrill/packet.h +++ b/gtests/net/packetdrill/packet.h @@ -108,6 +108,7 @@ struct packet { u32 flags; /* various meta-flags */ #define FLAG_WIN_NOCHECK 0x1 /* don't check TCP receive window */ #define FLAG_OPTIONS_NOCHECK 0x2 /* don't check TCP options */ +#define FLAGS_SCTP_BAD_CRC32C 0x4 /* compute bad CRC32C for SCTP packets */ enum ip_ecn_t ecn; /* IPv4/IPv6 ECN treatment for packet */ diff --git a/gtests/net/packetdrill/packet_checksum.c b/gtests/net/packetdrill/packet_checksum.c index 2c5a142f3175c9ae0090f5c59941af0c1b137ddf..a81a3d052ecff8920dc56b658dd2a09b51cc6bdd 100644 --- a/gtests/net/packetdrill/packet_checksum.c +++ b/gtests/net/packetdrill/packet_checksum.c @@ -47,8 +47,11 @@ static void checksum_ipv4_packet(struct packet *packet) /* Fill in IPv4-based layer 4 checksum. */ if (packet->sctp != NULL) { struct sctp_common_header *sctp = packet->sctp; - sctp->crc32c = 0; + sctp->crc32c = htonl(0); sctp->crc32c = sctp_crc32c(sctp, l4_bytes); + if (packet->flags & FLAGS_SCTP_BAD_CRC32C) { + sctp->crc32c = htonl(ntohl(sctp->crc32c) + 1); + } } else if (packet->tcp != NULL) { struct tcp *tcp = packet->tcp; tcp->check = 0; @@ -98,8 +101,11 @@ static void checksum_ipv6_packet(struct packet *packet) /* Fill in IPv6-based layer 4 checksum. */ if (packet->sctp != NULL) { struct sctp_common_header *sctp = packet->sctp; - sctp->crc32c = 0; + sctp->crc32c = htonl(0); sctp->crc32c = sctp_crc32c(sctp, l4_bytes); + if (packet->flags & FLAGS_SCTP_BAD_CRC32C) { + sctp->crc32c = htonl(ntohl(sctp->crc32c) + 1); + } } else if (packet->tcp != NULL) { struct tcp *tcp = packet->tcp; tcp->check = 0; @@ -134,7 +140,7 @@ static void checksum_ipv6_packet(struct packet *packet) &ipv6->dst_ip, IPPROTO_ICMPV6, icmpv6, l4_bytes); } else { - assert(!"not TCP or UDP or UDPLite or ICMP"); + assert(!"not SCTP or TCP or UDP or UDPLite or ICMP"); } } diff --git a/gtests/net/packetdrill/packet_to_string.c b/gtests/net/packetdrill/packet_to_string.c index 08573d39da96c9f2ea18160c4c92d23ffd147009..9b1dd53ef47fcdb9ec27c3ed69783ecb84591507 100644 --- a/gtests/net/packetdrill/packet_to_string.c +++ b/gtests/net/packetdrill/packet_to_string.c @@ -134,7 +134,11 @@ static int sctp_packet_to_string(FILE *s, struct packet *packet, fputc(' ', s); } - fputs("sctp:", s); + fputs("sctp", s); + if (packet->flags & FLAGS_SCTP_BAD_CRC32C) { + fputs("(bad_crc32c)", s); + } + fputc(':', s); index = 0; for (chunk = sctp_chunks_begin(packet, &iter, error); diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index 255215c654cdf1afaa10de300674e0eb77e85df9..90aad78557f3e218dda388eed48ac3d608173d2f 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -535,9 +535,10 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %token <reserved> STALENESS CHK PARAM UNRECOGNIZED_PARAMETERS %token <reserved> SPP_ADDRESS SPP_HBINTERVAL SPP_PATHMAXRXT SPP_PATHMTU %token <reserved> SPP_FLAGS SPP_IPV6_FLOWLABEL_ SPP_DSCP_ -%token <reserved> SASOC_ASOCMAXRXT SASOC_NUMBER_PEER_DESTINATIONS SASOC_PEER_RWND +%token <reserved> SASOC_ASOCMAXRXT SASOC_NUMBER_PEER_DESTINATIONS SASOC_PEER_RWND %token <reserved> SASOC_LOCAL_RWND SASOC_COOKIE_LIFE SE_TYPE SE_ON %token <reserved> SND_SID SND_FLAGS SND_PPID SND_CONTEXT SSB_ADAPTATION_IND +%token <reserved> BAD_CRC32C %token <floating> FLOAT %token <integer> INTEGER HEX_INTEGER %token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR @@ -577,15 +578,15 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <expression> linger l_onoff l_linger %type <expression> sctp_status sstat_state sstat_rwnd sstat_unackdata sstat_penddata %type <expression> sstat_instrms sstat_outstrms sstat_fragmentation_point sstat_primary -%type <expression> sctp_initmsg sinit_num_ostreams sinit_max_instreams sinit_max_attempts -%type <expression> sinit_max_init_timeo sctp_assoc_value sctp_stream_value +%type <expression> sctp_initmsg sinit_num_ostreams sinit_max_instreams sinit_max_attempts +%type <expression> sinit_max_init_timeo sctp_assoc_value sctp_stream_value %type <expression> sctp_sackinfo sack_delay sack_freq %type <expression> sctp_rtoinfo srto_initial srto_max srto_min sctp_paddrinfo %type <expression> sctp_paddrparams spp_address spp_hbinterval spp_pathmtu spp_pathmaxrxt %type <expression> spp_flags spp_ipv6_flowlabel spp_dscp %type <expression> spinfo_address spinfo_state spinfo_cwnd spinfo_srtt spinfo_rto spinfo_mtu -%type <expression> sasoc_asocmaxrxt sasoc_number_peer_destinations sasoc_peer_rwnd -%type <expression> sasoc_local_rwnd sasoc_cookie_life sctp_assocparams +%type <expression> sasoc_asocmaxrxt sasoc_number_peer_destinations sasoc_peer_rwnd +%type <expression> sasoc_local_rwnd sasoc_cookie_life sctp_assocparams %type <expression> sctp_sndinfo snd_sid snd_flags snd_ppid snd_context %type <expression> sctp_event se_type se_on sctp_setadaptation %type <errno_info> opt_errno @@ -819,8 +820,23 @@ sctp_packet_spec struct packet *outer = $1, *inner = NULL; enum direction_t direction = outer->direction; - inner = new_sctp_packet(in_config->wire_protocol, direction, $2, $5, - &error); + inner = new_sctp_packet(in_config->wire_protocol, direction, $2, + false, $5, &error); + if (inner == NULL) { + assert(error != NULL); + semantic_error(error); + free(error); + } + + $$ = packet_encapsulate_and_free(outer, inner); +} +| packet_prefix opt_ip_info SCTP '(' BAD_CRC32C ')' ':' sctp_chunk_list_spec { + char *error = NULL; + struct packet *outer = $1, *inner = NULL; + enum direction_t direction = outer->direction; + + inner = new_sctp_packet(in_config->wire_protocol, direction, $2, + true, $8, &error); if (inner == NULL) { assert(error != NULL); semantic_error(error); @@ -2372,7 +2388,7 @@ expression } | sctp_assocparams { $$ = $1; -} +} | sctp_event { $$ = $1; } @@ -2614,7 +2630,7 @@ sinit_max_init_timeo ; sctp_initmsg -: '{' sinit_num_ostreams ',' sinit_max_instreams ',' sinit_max_attempts ',' sinit_max_init_timeo '}' +: '{' sinit_num_ostreams ',' sinit_max_instreams ',' sinit_max_attempts ',' sinit_max_init_timeo '}' { $$ = new_expression(EXPR_SCTP_INITMSG); $$->value.sctp_paddrinfo = calloc(1, sizeof(struct sctp_initmsg_expr)); @@ -2674,7 +2690,7 @@ sctp_sackinfo $$ = new_expression(EXPR_SCTP_SACKINFO); $$->value.sctp_sack_info = calloc(1, sizeof(struct sctp_sack_info_expr)); $$->value.sctp_sack_info->sack_delay = $2; - $$->value.sctp_sack_info->sack_freq = $4; + $$->value.sctp_sack_info->sack_freq = $4; #else $$ = NULL; #endif @@ -2984,9 +3000,9 @@ se_type } $$ = new_integer_expression($3, "%hu"); } -| SE_TYPE '=' WORD { +| SE_TYPE '=' WORD { $$ = new_expression(EXPR_WORD); - $$->value.string = $3; + $$->value.string = $3; } ; @@ -3013,7 +3029,7 @@ sctp_event } ; -snd_sid +snd_sid : SND_SID '=' INTEGER { if (!is_valid_u16($3)) { semantic_error("snd_sid out of range"); @@ -3023,7 +3039,7 @@ snd_sid | SND_SID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } ; -snd_flags +snd_flags : SND_FLAGS '=' INTEGER { if (!is_valid_u16($3)) { semantic_error("snd_flags out of range"); @@ -3032,12 +3048,12 @@ snd_flags } | SND_FLAGS '=' WORD { $$ = new_expression(EXPR_WORD); - $$->value.string = $3; + $$->value.string = $3; } | SND_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } ; -snd_ppid +snd_ppid : SND_PPID '=' INTEGER { if (!is_valid_u32($3)) { semantic_error("snd_ppid out of range"); diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c index 697feeea88c592b1c69d3db1668b14d4a4405328..45d44a1cc63ff4b83f0db828fb6509fbc00bcffb 100644 --- a/gtests/net/packetdrill/run_packet.c +++ b/gtests/net/packetdrill/run_packet.c @@ -2695,7 +2695,7 @@ int abort_association(struct state *state, struct socket *socket) chunk_list = sctp_chunk_list_new(); sctp_chunk_list_append(chunk_list, sctp_abort_chunk_new(flgs, cause_list)); packet = new_sctp_packet(socket->address_family, - DIRECTION_INBOUND, ECN_NONE, + DIRECTION_INBOUND, ECN_NONE, false, chunk_list, &error); if (packet == NULL) die("%s", error); diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c index 23112204244cf2c4fc15ca35821e0ce182d8b48b..2658b47d4554a868f7cda2cda85c324ce3a627a3 100644 --- a/gtests/net/packetdrill/sctp_packet.c +++ b/gtests/net/packetdrill/sctp_packet.c @@ -2242,6 +2242,7 @@ struct packet * new_sctp_packet(int address_family, enum direction_t direction, enum ip_ecn_t ecn, + bool bad_crc32c, struct sctp_chunk_list *list, char **error) { @@ -2494,6 +2495,12 @@ new_sctp_packet(int address_family, break; } } + } else { + if (bad_crc32c) { + asprintf(error, + "bad CRC32C can only be requested for outbound packets"); + return NULL; + } } /* Allocate and zero out a packet object of the desired size */ @@ -2502,6 +2509,9 @@ new_sctp_packet(int address_family, packet->direction = direction; packet->flags = 0; + if (bad_crc32c) { + packet->flags |= FLAGS_SCTP_BAD_CRC32C; + } packet->ecn = ecn; /* Set IP header fields */ diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h index ba972b395bb1bf338093c6b0ef1d742af2c546cc..ca0256b107fb8a0ffb0e418a7c502f10a616c97d 100644 --- a/gtests/net/packetdrill/sctp_packet.h +++ b/gtests/net/packetdrill/sctp_packet.h @@ -423,6 +423,7 @@ sctp_cause_list_free(struct sctp_cause_list *list); extern struct packet *new_sctp_packet(int address_family, enum direction_t direction, enum ip_ecn_t ecn, + bool bad_crc32c, struct sctp_chunk_list *chunk_list, char **error); #endif /* __SCTP_PACKET_H__ */