Skip to content
Snippets Groups Projects
Commit 2c356609 authored by Michael Tüxen's avatar Michael Tüxen
Browse files

Add support for gaps and dups in SACK using the syntax

SACK[tsn=2 gaps=[4:4, 6:6] dups=[8]]
This fixes https://github.com/nplab/packetdrill/issues/4
parent 83331bb5
No related branches found
No related tags found
No related merge requests found
......@@ -235,6 +235,8 @@ tsn return TSN;
sid return SID;
ssn return SSN;
ppid return PPID;
gaps return GAPS;
dups return DUPS;
--[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;
......
......@@ -465,6 +465,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
struct packet *packet;
struct sctp_chunk_list_item *chunk_list_item;
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 syscall_spec *syscall;
struct command_spec *command;
struct code_spec *code;
......@@ -497,7 +499,7 @@ 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> TAG A_RWND OS IS TSN SID SSN PPID
%token <reserved> TAG A_RWND OS IS TSN SID SSN PPID GAPS DUPS
%token <floating> FLOAT
%token <integer> INTEGER HEX_INTEGER
%token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR
......@@ -550,6 +552,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
%type <chunk_list_item> sctp_ecne_chunk_spec sctp_cwr_chunk_spec
%type <chunk_list_item> sctp_shutdown_complete_chunk_spec
%type <integer> opt_a_rwnd opt_os opt_is opt_tsn opt_sid opt_ssn opt_ppid
%type <sack_block_list> opt_gaps gap_list opt_dups dup_list
%type <sack_block_list_item> gap dup
%% /* The grammar follows. */
......@@ -821,6 +825,49 @@ opt_ppid
$$ = $3;
}
opt_gaps
: { $$ = NULL; }
| GAPS '=' '[' gap_list ']' { $$ = $4; }
;
gap_list
: { $$ = sctp_sack_block_list_new(); }
| gap { $$ = sctp_sack_block_list_new();
sctp_sack_block_list_append($$, $1); }
| gap_list ',' gap { $$ = $1;
sctp_sack_block_list_append($1, $3); }
;
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); }
;
opt_dups
: { $$ = NULL; }
| DUPS '=' '[' dup_list ']' { $$ = $4; }
;
dup_list
: { $$ = sctp_sack_block_list_new(); }
| dup { $$ = sctp_sack_block_list_new();
sctp_sack_block_list_append($$, $1); }
| dup_list ',' dup { $$ = $1;
sctp_sack_block_list_append($1, $3); }
;
dup
: 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_tsn opt_sid opt_ssn opt_ppid ']' {
$$ = sctp_data_chunk_new($3, $4, $5, $6);
......@@ -849,8 +896,8 @@ sctp_init_ack_chunk_spec
}
sctp_sack_chunk_spec
: SACK '[' opt_tsn opt_a_rwnd']' {
$$ = sctp_sack_chunk_new($3, $4);
: SACK '[' opt_tsn opt_a_rwnd opt_gaps opt_dups']' {
$$ = sctp_sack_chunk_new($3, $4, $5, $6);
}
sctp_heartbeat_chunk_spec
......
......@@ -34,7 +34,83 @@
* - Add support for parameters (fix hard coded state cookie in INIT-ACK)
* - Add support for error causes
*/
struct sctp_sack_block_list *
sctp_sack_block_list_new(void)
{
struct sctp_sack_block_list *list;
list = malloc(sizeof(struct sctp_sack_block_list));
assert(list != NULL);
list->first = NULL;
list->last = NULL;
list->nr_entries = 0;
return list;
}
void
sctp_sack_block_list_append(struct sctp_sack_block_list *list,
struct sctp_sack_block_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_sctp_sack_block_list_free(struct sctp_sack_block_list *list)
{
struct sctp_sack_block_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_sack_block_list_item *
sctp_sack_block_list_item_gap_new(u16 start, u16 end)
{
struct sctp_sack_block_list_item *item;
item = malloc(sizeof(struct sctp_sack_block_list_item));
assert(item != NULL);
item->next = NULL;
item->block.gap.start = start;
item->block.gap.end = end;
return item;
}
struct sctp_sack_block_list_item *
sctp_sack_block_list_item_dup_new(u32 tsn)
{
struct sctp_sack_block_list_item *item;
item = malloc(sizeof(struct sctp_sack_block_list_item));
assert(item != NULL);
item->next = NULL;
item->block.tsn = tsn;
return item;
}
struct sctp_chunk_list_item *
sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags)
{
......@@ -182,18 +258,41 @@ sctp_init_ack_chunk_new(s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn)
}
struct sctp_chunk_list_item *
sctp_sack_chunk_new(s64 cum_tsn, s64 a_rwnd)
sctp_sack_chunk_new(s64 cum_tsn, s64 a_rwnd,
struct sctp_sack_block_list *gaps,
struct sctp_sack_block_list *dups)
{
struct sctp_chunk_list_item *item;
struct sctp_sack_chunk *chunk;
struct sctp_sack_block_list_item *item;
u32 flags;
u32 length;
u16 i, nr_gaps, nr_dups;
flags = 0;
chunk = malloc(sizeof(struct sctp_sack_chunk));
length = sizeof(struct sctp_sack_chunk);
if (gaps == NULL) {
nr_gaps = 0;
flags |= FLAG_CHUNK_LENGTH_NOCHECK;
flags |= FLAG_SACK_CHUNK_GAP_BLOCKS_NOCHECK;
} else {
nr_gaps = gaps->nr_entries;
length += nr_gaps * sizeof(union sctp_sack_block);
}
if (dups == NULL) {
nr_dups = 0;
flags |= FLAG_CHUNK_LENGTH_NOCHECK;
flags |= FLAG_SACK_CHUNK_DUP_TSNS_NOCHECK;
} else {
nr_dups = dups->nr_entries;
length += nr_dups * sizeof(union sctp_sack_block);
}
assert(is_valid_u16(length));
assert(length % 4 == 0);
chunk = malloc(length);
assert(chunk != NULL);
chunk->type = SCTP_SACK_CHUNK_TYPE;
chunk->flags = 0;
chunk->length = htons(sizeof(struct sctp_sack_chunk));
chunk->length = htons(length);
if (cum_tsn == -1) {
chunk->cum_tsn = htonl(0);
flags |= FLAG_SACK_CHUNK_CUM_TSN_NOCHECK;
......@@ -206,12 +305,28 @@ sctp_sack_chunk_new(s64 cum_tsn, s64 a_rwnd)
} else {
chunk->a_rwnd = htonl((u32)a_rwnd);
}
chunk->nr_gap_blocks = htons(0);
chunk->nr_dup_tsns = htons(0);
item = sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
(u32)sizeof(struct sctp_sack_chunk),
flags);
return item;
chunk->nr_gap_blocks = htons(nr_gaps);
chunk->nr_dup_tsns = htons(nr_dups);
if (gaps != NULL) {
for (i = 0, item = gaps->first;
(i < nr_gaps) && (item != NULL);
i++, item = item->next) {
chunk->block[i].gap.start = htons(item->block.gap.start);
chunk->block[i].gap.end = htons(item->block.gap.end);
}
assert((i == nr_gaps) && (item == NULL));
}
if (dups != NULL) {
for (i = 0, item = dups->first;
(i < nr_dups) && (item != NULL);
i++, item = item->next) {
chunk->block[i + nr_gaps].tsn= htonl(item->block.tsn);
}
assert((i == nr_dups) && (item == NULL));
}
return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
length, flags);
}
struct sctp_chunk_list_item *
......@@ -428,7 +543,8 @@ sctp_shutdown_complete_chunk_new(u8 flags)
return item;
}
struct sctp_chunk_list *sctp_chunk_list_new(void)
struct sctp_chunk_list *
sctp_chunk_list_new(void)
{
struct sctp_chunk_list *list;
......@@ -440,8 +556,9 @@ struct sctp_chunk_list *sctp_chunk_list_new(void)
return list;
}
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)
{
assert(item->next == NULL);
if (list->last == NULL) {
......@@ -456,7 +573,8 @@ void sctp_chunk_list_append(struct sctp_chunk_list *list,
list->length += item->length;
}
void sctp_chunk_list_free(struct sctp_chunk_list *list)
void
sctp_chunk_list_free(struct sctp_chunk_list *list)
{
struct sctp_chunk_list_item *current_item, *next_item;
......@@ -472,11 +590,12 @@ void sctp_chunk_list_free(struct sctp_chunk_list *list)
free(list);
}
struct packet *new_sctp_packet(int address_family,
enum direction_t direction,
enum ip_ecn_t ecn,
struct sctp_chunk_list *list,
char **error)
struct packet *
new_sctp_packet(int address_family,
enum direction_t direction,
enum ip_ecn_t ecn,
struct sctp_chunk_list *list,
char **error)
{
struct packet *packet; /* the newly-allocated result packet */
struct header *sctp_header; /* the SCTP header info */
......
......@@ -29,6 +29,33 @@
#include "packet.h"
#include "sctp.h"
struct sctp_sack_block_list_item {
struct sctp_sack_block_list_item *next;
union sctp_sack_block block;
};
struct sctp_sack_block_list {
struct sctp_sack_block_list_item *first;
struct sctp_sack_block_list_item *last;
u16 nr_entries;
};
struct sctp_sack_block_list *
sctp_sack_block_list_new(void);
void
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);
struct sctp_sack_block_list_item *
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_chunk_list_item {
struct sctp_chunk_list_item *next;
struct sctp_chunk *chunk;
......@@ -81,7 +108,9 @@ sctp_init_ack_chunk_new(s64 tag, s64 a_rwnd, s64 os, s64 is, s64 tsn);
#define FLAG_SACK_CHUNK_DUP_TSNS_NOCHECK 0x00000800
struct sctp_chunk_list_item *
sctp_sack_chunk_new(s64 cum_tsn, s64 a_rwnd);
sctp_sack_chunk_new(s64 cum_tsn, s64 a_rwnd,
struct sctp_sack_block_list *gaps,
struct sctp_sack_block_list *dups);
struct sctp_chunk_list_item *
sctp_heartbeat_chunk_new(u8 flags);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment