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

Add support for a generic chunk.

parent 84b6555c
No related branches found
No related tags found
No related merge requests found
......@@ -212,6 +212,7 @@ sinit_num_ostreams return SINIT_NUM_OSTREAMS;
sinit_max_instreams return SINIT_MAX_INSTREAMS;
sinit_max_attempts return SINIT_MAX_ATTEMPTS;
sinit_max_init_timeo return SINIT_MAX_INIT_TIMEO;
CHUNK return CHUNK;
DATA return DATA;
INIT return INIT;
INIT_ACK return INIT_ACK;
......@@ -228,6 +229,7 @@ ECNE return ECNE;
CWR return CWR;
SHUTDOWN_COMPLETE return SHUTDOWN_COMPLETE;
PAD return PAD;
type return TYPE;
flgs return FLAGS;
len return LEN;
tag return TAG;
......
......@@ -466,6 +466,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_byte_list_item *byte_list_item;
struct sctp_byte_list *byte_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;
......@@ -501,10 +503,11 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
%token <reserved> SINIT_MAX_INIT_TIMEO
%token <reserved> ASSOC_VALUE
%token <reserved> SACK_DELAY SACK_FREQ
%token <reserved> DATA INIT INIT_ACK HEARTBEAT HEARTBEAT_ACK ABORT
%token <reserved> CHUNK DATA INIT INIT_ACK HEARTBEAT HEARTBEAT_ACK ABORT
%token <reserved> SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECNE CWR
%token <reserved> SHUTDOWN_COMPLETE PAD
%token <reserved> FLAGS LEN TAG A_RWND OS IS TSN SID SSN PPID CUM_TSN GAPS DUPS
%token <reserved> TYPE FLAGS LEN
%token <reserved> 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
......@@ -550,6 +553,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
%type <errno_info> opt_errno
%type <chunk_list> sctp_chunk_list_spec
%type <chunk_list_item> sctp_chunk_spec
%type <chunk_list_item> sctp_generic_chunk_spec
%type <chunk_list_item> sctp_data_chunk_spec
%type <chunk_list_item> sctp_init_chunk_spec sctp_init_ack_chunk_spec
%type <chunk_list_item> sctp_sack_chunk_spec
......@@ -574,11 +578,12 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
%type <parameter_list_item> sctp_supported_address_types_parameter_spec
%type <parameter_list_item> sctp_ecn_capable_parameter_spec
%type <parameter_list_item> sctp_pad_parameter_spec
%type <integer> opt_flags opt_data_flags opt_abort_flags
%type <integer> opt_chunk_type opt_flags opt_data_flags opt_abort_flags
%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 <byte_list> opt_val byte_list
%type <byte_list_item> byte
%type <sack_block_list> opt_gaps gap_list opt_dups dup_list
%type <sack_block_list_item> gap dup
%type <address_type_list> address_types_list
......@@ -774,7 +779,8 @@ sctp_chunk_list_spec
;
sctp_chunk_spec
: sctp_data_chunk_spec { $$ = $1; }
: sctp_generic_chunk_spec { $$ = $1; }
| sctp_data_chunk_spec { $$ = $1; }
| sctp_init_chunk_spec { $$ = $1; }
| sctp_init_ack_chunk_spec { $$ = $1; }
| sctp_sack_chunk_spec { $$ = $1; }
......@@ -792,13 +798,19 @@ sctp_chunk_spec
| sctp_pad_chunk_spec { $$ = $1; }
;
opt_chunk_len
: LEN '=' ELLIPSIS { $$ = -1; }
| LEN '=' INTEGER {
if (!is_valid_u16($3)) {
semantic_error("length value out of range");
opt_chunk_type
: TYPE '=' ELLIPSIS { $$ = -1; }
| TYPE '=' HEX_INTEGER {
if (!is_valid_u8($3)) {
semantic_error("type value out of range");
}
$$ = $3;
$$ = $3;
}
| TYPE '=' INTEGER {
if (!is_valid_u8($3)) {
semantic_error("type value out of range");
}
$$ = $3;
}
;
......@@ -818,6 +830,45 @@ opt_flags
}
;
opt_chunk_len
: LEN '=' ELLIPSIS { $$ = -1; }
| LEN '=' INTEGER {
if (!is_valid_u16($3)) {
semantic_error("length value out of range");
}
$$ = $3;
}
;
opt_val
: VAL '=' ELLIPSIS { $$ = NULL; }
| VAL '=' '[' ELLIPSIS ']' { $$ = NULL; }
| VAL '=' '[' byte_list ']' { $$ = $4; }
;
byte_list
: { $$ = sctp_byte_list_new(); }
| byte { $$ = sctp_byte_list_new();
sctp_byte_list_append($$, $1); }
| byte_list ',' byte { $$ = $1;
sctp_byte_list_append($1, $3); }
;
byte
: HEX_INTEGER {
if (!is_valid_u8($1)) {
semantic_error("byte value out of range");
}
$$ = sctp_byte_list_item_new($1);
}
| INTEGER {
if (!is_valid_u8($1)) {
semantic_error("byte value out of range");
}
$$ = sctp_byte_list_item_new($1);
}
;
opt_data_flags
: FLAGS '=' ELLIPSIS { $$ = -1; }
| FLAGS '=' HEX_INTEGER {
......@@ -924,7 +975,7 @@ opt_shutdown_complete_flags
| FLAGS '=' INTEGER {
if (!is_valid_u8($3)) {
semantic_error("flags value out of range");
}
}
$$ = $3;
}
| FLAGS '=' WORD {
......@@ -1089,6 +1140,21 @@ dup
}
;
sctp_generic_chunk_spec
: CHUNK '[' opt_chunk_type ',' opt_flags ',' opt_chunk_len ',' opt_val ']' {
if (($7 != -1) && ($7 < sizeof(struct sctp_chunk))) {
semantic_error("length value out of range");
}
if (($7 != -1) && ($9 != NULL) &&
($7 != sizeof(struct sctp_chunk) + $9->nr_entries)) {
semantic_error("length value incompatible with val");
}
if (($7 == -1) && ($9 != NULL)) {
semantic_error("length needs to be specified");
}
$$ = sctp_generic_chunk_new($3, $5, $7, $9);
}
sctp_data_chunk_spec
: DATA '[' opt_data_flags ',' opt_chunk_len ',' opt_tsn ',' opt_sid ',' opt_ssn ',' opt_ppid ']' {
if (($5 != -1) && ($5 < sizeof(struct sctp_data_chunk))) {
......
......@@ -29,10 +29,72 @@
/*
* ToDo:
* - Add support for parameters (fix hard coded state cookie in INIT-ACK)
* - Add support for error causes
*/
struct sctp_byte_list *
sctp_byte_list_new(void)
{
struct sctp_byte_list *list;
list = malloc(sizeof(struct sctp_byte_list));
assert(list != NULL);
list->first = NULL;
list->last = NULL;
list->nr_entries = 0;
return list;
}
void
sctp_byte_list_append(struct sctp_byte_list *list,
struct sctp_byte_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_byte_list_free(struct sctp_byte_list *list)
{
struct sctp_byte_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_byte_list_item *
sctp_byte_list_item_new(u8 byte)
{
struct sctp_byte_list_item *item;
item = malloc(sizeof(struct sctp_byte_list_item));
assert(item != NULL);
item->next = NULL;
item->byte = byte;
return item;
}
struct sctp_sack_block_list *
sctp_sack_block_list_new(void)
{
......@@ -188,6 +250,64 @@ sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags,
return item;
}
struct sctp_chunk_list_item *
sctp_generic_chunk_new(s64 type, s64 flgs, s64 len,
struct sctp_byte_list *bytes)
{
struct sctp_chunk *chunk;
struct sctp_byte_list_item *item;
u32 flags;
u16 length, padding_length, i;
flags = 0;
if (bytes == NULL) {
flags |= FLAG_CHUNK_LENGTH_NOCHECK;
flags |= FLAG_CHUNK_VALUE_NOCHECK;
}
if (len == -1) {
length = (u16)sizeof(struct sctp_chunk);
} else {
length = (u16)len;
}
padding_length = length % 4;
if (padding_length > 0) {
padding_length = 4 - padding_length;
}
chunk = malloc(length + padding_length);
assert(chunk != NULL);
if (type == -1) {
chunk->type = 0;
flags |= FLAG_CHUNK_TYPE_NOCHECK;
} else {
chunk->type = (u8)type;
}
if (flgs == -1) {
chunk->flags = 0;
flags |= FLAG_CHUNK_FLAGS_NOCHECK;
} else {
chunk->flags = (u8)flgs;
}
chunk->length = htons(length);
if (len == -1) {
flags |= FLAG_CHUNK_LENGTH_NOCHECK;
flags |= FLAG_CHUNK_VALUE_NOCHECK;
}
if (bytes != NULL) {
for (i = 0, item = bytes->first;
item != NULL;
i++, item = item->next) {
chunk->value[i] = item->byte;
}
} else {
memset(chunk->value, 0, length - sizeof(struct sctp_chunk));
}
memset(chunk->value + (length - sizeof(struct sctp_chunk)),
0, padding_length);
return sctp_chunk_list_item_new(chunk,
length + padding_length,
flags, sctp_parameter_list_new());
}
struct sctp_chunk_list_item *
sctp_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 ssn, s64 ppid)
{
......@@ -1535,8 +1655,22 @@ new_sctp_packet(int address_family,
}
break;
default:
asprintf(error, "Unknown chunk type 0x%02x", chunk_item->chunk->type);
return NULL;
if (chunk_item->flags & FLAG_CHUNK_TYPE_NOCHECK) {
asprintf(error,
"chunk type must be specified for inbound packets");
return NULL;
}
if (chunk_item->flags & FLAG_CHUNK_FLAGS_NOCHECK) {
asprintf(error,
"chunk flags must be specified for inbound packets");
return NULL;
}
if (chunk_item->flags & FLAG_CHUNK_LENGTH_NOCHECK) {
asprintf(error,
"chunk length must be specified for inbound packets");
return NULL;
}
break;
}
}
}
......
......@@ -29,6 +29,30 @@
#include "packet.h"
#include "sctp.h"
struct sctp_byte_list_item {
struct sctp_byte_list_item *next;
u8 byte;
};
struct sctp_byte_list {
struct sctp_byte_list_item *first;
struct sctp_byte_list_item *last;
u16 nr_entries;
};
struct sctp_byte_list *
sctp_byte_list_new(void);
void
sctp_byte_list_append(struct sctp_byte_list *list,
struct sctp_byte_list_item *item);
void
sctp_byte_list_free(struct sctp_byte_list *list);
struct sctp_byte_list_item *
sctp_byte_list_item_new(u8 byte);
struct sctp_sack_block_list_item {
struct sctp_sack_block_list_item *next;
union sctp_sack_block block;
......@@ -113,14 +137,18 @@ struct sctp_chunk_list {
u32 length;
};
struct sctp_chunk_list_item *
sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags,
struct sctp_parameter_list *list);
#define FLAG_CHUNK_TYPE_NOCHECK 0x00000001
#define FLAG_CHUNK_FLAGS_NOCHECK 0x00000002
#define FLAG_CHUNK_LENGTH_NOCHECK 0x00000004
#define FLAG_CHUNK_VALUE_NOCHECK 0x00000008
struct sctp_chunk_list_item *
sctp_chunk_list_item_new(struct sctp_chunk *chunk, u32 length, u32 flags,
struct sctp_parameter_list *list);
sctp_generic_chunk_new(s64 type, s64 flgs, s64 len,
struct sctp_byte_list *bytes);
#define FLAG_DATA_CHUNK_TSN_NOCHECK 0x00000100
#define FLAG_DATA_CHUNK_SID_NOCHECK 0x00000200
......
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