Skip to content
Snippets Groups Projects
Commit ffa4c46f authored by Michael Tüxen's avatar Michael Tüxen Committed by GitHub
Browse files

Merge pull request #125 from TheAomx/forward_tsn_chunk

Forward tsn chunk
parents d8a5a1b9 8ea2ddd8
No related branches found
No related tags found
No related merge requests found
......@@ -556,6 +556,7 @@ SHUTDOWN_COMPLETE return SHUTDOWN_COMPLETE;
I-DATA return I_DATA;
PAD return PAD;
RECONFIG return RECONFIG;
FORWARD_TSN return FORWARD_TSN;
type return TYPE;
flgs return FLAGS;
len return LEN;
......@@ -585,6 +586,7 @@ req_sn return REQ_SN;
resp_sn return RESP_SN;
last_tsn return LAST_TSN;
sids return SIDS;
ids return IDS;
result return RESULT;
sender_next_tsn return SENDER_NEXT_TSN;
receiver_next_tsn return RECEIVER_NEXT_TSN;
......
......@@ -29,6 +29,7 @@
#include <string.h>
#include "ethernet.h"
#include "packet_parser.h"
#include "logging.h"
static void test_sctp_ipv4_packet_to_string(void)
{
......@@ -102,7 +103,7 @@ static void test_sctp_ipv6_packet_to_string(void)
/* An IPv6/SCTP packet. */
u8 data[] = {
/* IPv6 Base Header: */
0x60, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x84, 0xff,
0x60, 0x00, 0x00, 0x00, 0x02, 0x0c, 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 +111,7 @@ static void test_sctp_ipv6_packet_to_string(void)
/* SCTP Common Header: */
0x04, 0xd2, 0x1f, 0x90,
0x01, 0x02, 0x03, 0x04,
0x17, 0x7a, 0xeb, 0xd7,
0xd8, 0x6a, 0x11, 0x71,
/* SCTP DATA Chunk */
0x00, 0x0f, 0x00, 0x13,
0x01, 0x02, 0x03, 0x04,
......@@ -236,6 +237,11 @@ static void test_sctp_ipv6_packet_to_string(void)
0x01, 0x02, 0x03, 0x04,
/* SCTP SHUTDOWN_COMPLETE Chunk */
0x0e, 0x01, 0x00, 0x04,
/* FORWARD_TSN Chunk*/
0xc0, 0x00, 0x00, 0x10,
0xb5, 0xaa, 0xaf, 0x0f,
0x00, 0x01, 0x00, 0x02,
0x00, 0x03, 0x00, 0x04,
/* SCTP I-DATA Chunk */
0x40, 0x0f, 0x00, 0x17,
0x00, 0x00, 0x00, 0x04,
......@@ -264,6 +270,11 @@ static void test_sctp_ipv6_packet_to_string(void)
char *error = NULL;
enum packet_parse_result_t result =
parse_packet(packet, sizeof(data), ETHERTYPE_IPV6, &error);
#if DEBUG_LOGGING == 1
if (result != PACKET_OK) {
printf("error was: %s\n", error);
}
#endif
assert(result == PACKET_OK);
assert(error == NULL);
......@@ -272,6 +283,11 @@ static void test_sctp_ipv6_packet_to_string(void)
/* Test a DUMP_SHORT dump */
status = packet_to_string(packet, DUMP_SHORT, &dump, &error);
#if DEBUG_LOGGING == 1
if (status != STATUS_OK) {
printf("error was: %s\n", error);
}
#endif
assert(status == STATUS_OK);
assert(error == NULL);
printf("dump = '%s'\n", dump);
......@@ -324,6 +340,7 @@ static void test_sctp_ipv6_packet_to_string(void)
"ECNE[flgs=0x00, tsn=16909060]; "
"CWR[flgs=0x00, tsn=16909060]; "
"SHUTDOWN_COMPLETE[flgs=T]; "
"FORWARD_TSN[flgs=0x00, len=16, cum_tsn=3047862031, ids=[{1,2},{3,4}]]; "
"I-DATA[flgs=IUBE, len=23, tsn=4, sid=255, mid=1, ppid=0]; "
"I-DATA[flgs=IUE, len=23, tsn=4, sid=255, mid=2, fsn=1]; "
"PAD[flgs=0x00, len=16, val=...]";
......@@ -385,6 +402,7 @@ static void test_sctp_ipv6_packet_to_string(void)
"ECNE[flgs=0x00, tsn=16909060]; "
"CWR[flgs=0x00, tsn=16909060]; "
"SHUTDOWN_COMPLETE[flgs=T]; "
"FORWARD_TSN[flgs=0x00, len=16, cum_tsn=3047862031, ids=[{1,2},{3,4}]]; "
"I-DATA[flgs=IUBE, len=23, tsn=4, sid=255, mid=1, ppid=0]; "
"I-DATA[flgs=IUE, len=23, tsn=4, sid=255, mid=2, fsn=1]; "
"PAD[flgs=0x00, len=16, val=...]";
......@@ -446,14 +464,15 @@ static void test_sctp_ipv6_packet_to_string(void)
"ECNE[flgs=0x00, tsn=16909060]; "
"CWR[flgs=0x00, tsn=16909060]; "
"SHUTDOWN_COMPLETE[flgs=T]; "
"FORWARD_TSN[flgs=0x00, len=16, cum_tsn=3047862031, ids=[{1,2},{3,4}]]; "
"I-DATA[flgs=IUBE, len=23, tsn=4, sid=255, mid=1, ppid=0]; "
"I-DATA[flgs=IUE, len=23, tsn=4, sid=255, mid=2, fsn=1]; "
"PAD[flgs=0x00, len=16, val=...]"
"\n"
"0x0000: 60 00 00 00 01 fc 84 ff 00 02 00 00 00 00 00 00 " "\n"
"0x0000: 60 00 00 00 02 0c 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: 17 7a eb d7 00 0f 00 13 01 02 03 04 00 ff 01 00 " "\n"
"0x0030: d8 6a 11 71 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 68 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"
......@@ -480,11 +499,12 @@ static void test_sctp_ipv6_packet_to_string(void)
"0x01b0: 40 40 00 00 07 00 00 08 01 02 03 04 08 00 00 04 " "\n"
"0x01c0: 09 00 00 04 0a 00 00 05 45 00 00 00 0b 00 00 04 " "\n"
"0x01d0: 0c 00 00 08 01 02 03 04 0d 00 00 08 01 02 03 04 " "\n"
"0x01e0: 0e 01 00 04 40 0f 00 17 00 00 00 04 00 ff 00 00 " "\n"
"0x01f0: 00 00 00 01 00 00 00 00 00 01 02 00 40 0d 00 17 " "\n"
"0x0200: 00 00 00 04 00 ff 00 00 00 00 00 02 00 00 00 01 " "\n"
"0x0210: 00 01 02 00 84 00 00 10 50 50 50 50 50 50 50 50 " "\n"
"0x0220: 50 50 50 50 " "\n";
"0x01e0: 0e 01 00 04 c0 00 00 10 b5 aa af 0f 00 01 00 02 " "\n"
"0x01f0: 00 03 00 04 40 0f 00 17 00 00 00 04 00 ff 00 00 " "\n"
"0x0200: 00 00 00 01 00 00 00 00 00 01 02 00 40 0d 00 17 " "\n"
"0x0210: 00 00 00 04 00 ff 00 00 00 00 00 02 00 00 00 01 " "\n"
"0x0220: 00 01 02 00 84 00 00 10 50 50 50 50 50 50 50 50 " "\n"
"0x0230: 50 50 50 50 " "\n";
printf("expected = '%s'\n", expected);
assert(strcmp(dump, expected) == 0);
free(dump);
......
......@@ -472,6 +472,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
struct sctp_u16_list_item *u16_item;
struct sctp_sack_block_list_item *sack_block_list_item;
struct sctp_sack_block_list *sack_block_list;
struct sctp_forward_tsn_ids_list *forward_tsn_ids_list;
struct sctp_forward_tsn_ids_list_item *forward_tsn_ids_list_item;
struct sctp_address_type_list_item *address_type_list_item;
struct sctp_address_type_list *address_type_list;
struct sctp_parameter_type_list_item *parameter_type_list_item;
......@@ -519,14 +521,14 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
%token <reserved> SPINFO_MTU GAUTH_ASSOC_ID GAUTH_NUMBER_OF_CHUNKS GAUTH_CHUNKS
%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 I_DATA PAD RECONFIG
%token <reserved> SHUTDOWN_COMPLETE I_DATA PAD RECONFIG FORWARD_TSN
%token <reserved> TYPE FLAGS LEN
%token <reserved> TAG A_RWND OS IS TSN SID SSN MID PPID FSN CUM_TSN GAPS NR_GAPS DUPS
%token <reserved> PARAMETER HEARTBEAT_INFORMATION IPV4_ADDRESS IPV6_ADDRESS
%token <reserved> STATE_COOKIE UNRECOGNIZED_PARAMETER COOKIE_PRESERVATIVE
%token <reserved> HOSTNAME_ADDRESS SUPPORTED_ADDRESS_TYPES ECN_CAPABLE FORWARD_TSN_SUPPORTED
%token <reserved> SUPPORTED_EXTENSIONS ADAPTATION_CODE_POINT ADAPTATION_INDICATION
%token <reserved> OUTGOING_SSN_RESET REQ_SN RESP_SN LAST_TSN SIDS INCOMING_SSN_RESET
%token <reserved> OUTGOING_SSN_RESET REQ_SN RESP_SN LAST_TSN IDS SIDS INCOMING_SSN_RESET
%token <reserved> RECONFIG_RESPONSE RESULT SENDER_NEXT_TSN RECEIVER_NEXT_TSN
%token <reserved> SSN_TSN_RESET ADD_INCOMING_STREAMS NUMBER_OF_NEW_STREAMS
%token <reserved> ADD_OUTGOING_STREAMS RECONFIG_REQUEST_GENERIC
......@@ -675,6 +677,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
%type <chunk_list_item> sctp_shutdown_complete_chunk_spec
%type <chunk_list_item> sctp_i_data_chunk_spec
%type <chunk_list_item> sctp_pad_chunk_spec sctp_reconfig_chunk_spec
%type <chunk_list_item> sctp_forward_tsn_spec
%type <parameter_list> opt_parameter_list_spec sctp_parameter_list_spec
%type <parameter_list_item> sctp_parameter_spec
%type <parameter_list_item> sctp_generic_parameter_spec
......@@ -723,6 +726,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
%type <u16_item> u16_item
%type <sack_block_list> opt_gaps opt_nr_gaps gap_list opt_dups dup_list
%type <sack_block_list_item> gap dup
%type <forward_tsn_ids_list> opt_stream_identifier ids_list
%type <forward_tsn_ids_list_item> id
%type <address_type_list> address_types_list
%type <address_type_list_item> address_type
%type <parameter_type_list> parameter_types_list
......@@ -1055,6 +1060,7 @@ sctp_chunk_spec
| sctp_i_data_chunk_spec { $$ = $1; }
| sctp_pad_chunk_spec { $$ = $1; }
| sctp_reconfig_chunk_spec { $$ = $1; }
| sctp_forward_tsn_spec { $$ = $1; }
;
chunk_type
......@@ -1127,6 +1133,9 @@ chunk_type
| RECONFIG {
$$ = SCTP_RECONFIG_CHUNK_TYPE;
}
| FORWARD_TSN {
$$ = SCTP_FORWARD_TSN_CHUNK_TYPE;
}
;
opt_chunk_type
......@@ -1575,6 +1584,32 @@ dup
}
;
opt_stream_identifier
: IDS '=' ELLIPSIS { $$ = NULL; }
| IDS '=' '[' ELLIPSIS ']' { $$ = NULL; }
| IDS '=' '[' ids_list ']' { $$ = $4; }
;
ids_list
: { $$ = sctp_forward_tsn_ids_list_new(); }
| id { $$ =sctp_forward_tsn_ids_list_new();
sctp_forward_tsn_ids_list_append($$, $1); }
| ids_list ',' id { $$ = $1;
sctp_forward_tsn_ids_list_append($1, $3); }
;
id
: '{' INTEGER ',' INTEGER '}' {
if (!is_valid_u16($2)) {
semantic_error("stream identifier out of range");
}
if (!is_valid_u16($4)) {
semantic_error("stream sequence number out of range");
}
$$ = sctp_forward_tsn_ids_list_item_new($2, $4);
}
;
sctp_generic_chunk_spec
: CHUNK '[' opt_chunk_type ',' opt_flags ',' opt_len ',' opt_val ']' {
if (($7 != -1) &&
......@@ -1712,6 +1747,11 @@ sctp_pad_chunk_spec
$$ = sctp_pad_chunk_new($3, $5, NULL);
}
sctp_forward_tsn_spec
: FORWARD_TSN '[' opt_cum_tsn ',' opt_stream_identifier']' {
$$ = sctp_forward_tsn_chunk_new($3, $5);
}
opt_req_sn
: REQ_SN '=' INTEGER {
if (!is_valid_u32($3)) {
......
......@@ -654,6 +654,8 @@ static int map_inbound_sctp_packet(
struct sctp_shutdown_complete_chunk *shutdown_complete;
struct sctp_i_data_chunk *i_data;
struct sctp_reconfig_chunk *reconfig;
struct sctp_forward_tsn_chunk *forward_tsn;
u32 local_diff, remote_diff;
u32 v_tag;
u16 nr_gap_blocks, number_of_nr_gap_blocks, nr_dup_tsns, i;
......@@ -755,6 +757,10 @@ static int map_inbound_sctp_packet(
i_data = (struct sctp_i_data_chunk *)chunk;
i_data->tsn = htonl(ntohl(i_data->tsn) + remote_diff);
break;
case SCTP_FORWARD_TSN_CHUNK_TYPE:
forward_tsn = (struct sctp_forward_tsn_chunk *) chunk;
forward_tsn->cum_tsn = htonl(ntohl(forward_tsn->cum_tsn) + local_diff);
break;
case SCTP_RECONFIG_CHUNK_TYPE:
reconfig = (struct sctp_reconfig_chunk *)chunk;
if (htons(reconfig->length) >= sizeof(struct sctp_reconfig_chunk) + 4) {
......@@ -966,6 +972,7 @@ static int map_outbound_live_sctp_packet(
struct sctp_cwr_chunk *cwr;
struct sctp_i_data_chunk *i_data;
struct sctp_reconfig_chunk *reconfig;
struct sctp_forward_tsn_chunk *forward_tsn;
u32 local_diff, remote_diff;
u16 nr_gap_blocks, nr_dup_tsns, number_of_nr_gap_blocks, i;
......@@ -1037,6 +1044,10 @@ static int map_outbound_live_sctp_packet(
i_data = (struct sctp_i_data_chunk *)chunk;
i_data->tsn = htonl(ntohl(i_data->tsn) + local_diff);
break;
case SCTP_FORWARD_TSN_CHUNK_TYPE:
forward_tsn = (struct sctp_forward_tsn_chunk *) chunk;
forward_tsn->cum_tsn = htonl(ntohl(forward_tsn->cum_tsn) + local_diff);
break;
case SCTP_RECONFIG_CHUNK_TYPE:
reconfig = (struct sctp_reconfig_chunk *)chunk;
if (reconfig->length > sizeof(struct sctp_reconfig_chunk)) {
......@@ -2156,6 +2167,53 @@ static int verify_reconfig_chunk(struct sctp_reconfig_chunk *actual_chunk,
error);
}
static u16 get_num_id_blocks (u16 packet_length) {
return (packet_length - sizeof(struct sctp_forward_tsn_chunk)) / sizeof(struct sctp_stream_identifier_block);
}
static int verify_forward_tsn_chunk(struct sctp_forward_tsn_chunk *actual_chunk,
struct sctp_forward_tsn_chunk *script_chunk,
u32 flags, char **error) {
u16 actual_packet_length = ntohs(script_chunk->length);
u16 script_packet_length = ntohs(script_chunk->length);
u16 actual_nr_id_blocks = get_num_id_blocks(actual_packet_length);
u16 script_nr_id_blocks = get_num_id_blocks(script_packet_length);
u16 i;
if ((flags & FLAG_FORWARD_TSN_CHUNK_CUM_TSN_NOCHECK) == 0) {
if (check_field("sctp_forward_tsn_cum_tsn",
ntohl(script_chunk->cum_tsn),
ntohl(actual_chunk->cum_tsn),
error) == STATUS_ERR) {
return STATUS_ERR;
}
}
if ((flags & FLAG_FORWARD_TSN_CHUNK_IDS_NOCHECK) == 0) {
if (check_field("nr_sid_blocks",
actual_nr_id_blocks,
script_nr_id_blocks,
error) == STATUS_ERR) {
return STATUS_ERR;
}
for (i = 0; i < script_nr_id_blocks; i++) {
if (check_field("sctp_forward_tsn_stream_identifier",
ntohs(script_chunk->stream_identifier_blocks[i].stream),
ntohs(actual_chunk->stream_identifier_blocks[i].stream),
error) == STATUS_ERR ||
check_field("sctp_forward_tsn_stream_sequence_number",
ntohs(script_chunk->stream_identifier_blocks[i].stream_sequence),
ntohs(actual_chunk->stream_identifier_blocks[i].stream_sequence),
error) == STATUS_ERR) {
return STATUS_ERR;
}
}
}
return STATUS_OK;
}
/* Verify that required actual SCTP packet fields are as the script expected. */
static int verify_sctp(
const struct packet *actual_packet,
......@@ -2306,6 +2364,11 @@ static int verify_sctp(
script_chunk_item,
flags, error);
break;
case SCTP_FORWARD_TSN_CHUNK_TYPE:
result = verify_forward_tsn_chunk((struct sctp_forward_tsn_chunk *)actual_chunk,
(struct sctp_forward_tsn_chunk *)script_chunk,
flags, error);
break;
default:
result = STATUS_ERR;
assert(!"unsupported SCTP chunk type");
......
......@@ -56,6 +56,7 @@ struct sctp_common_header {
#define SCTP_I_DATA_CHUNK_TYPE 0x40
#define SCTP_RECONFIG_CHUNK_TYPE 0x82
#define SCTP_PAD_CHUNK_TYPE 0x84
#define SCTP_FORWARD_TSN_CHUNK_TYPE 0xc0
#define MAX_SCTP_CHUNK_BYTES 0xffff
......@@ -267,6 +268,19 @@ struct sctp_reconfig_chunk {
__u8 parameter[];
} __packed;
struct sctp_stream_identifier_block {
__u16 stream;
__u16 stream_sequence;
} __packed;
struct sctp_forward_tsn_chunk {
__u8 type;
__u8 flags;
__be16 length;
__be32 cum_tsn;
struct sctp_stream_identifier_block stream_identifier_blocks[];
} __packed;
#define SCTP_HEARTBEAT_INFORMATION_PARAMETER_TYPE 0x0001
#define SCTP_IPV4_ADDRESS_PARAMETER_TYPE 0x0005
#define SCTP_IPV6_ADDRESS_PARAMETER_TYPE 0x0006
......
......@@ -1703,6 +1703,45 @@ static int sctp_reconfig_chunk_to_string(
return result;
}
static u16 get_num_id_blocks (u16 packet_length) {
return (packet_length - sizeof(struct sctp_forward_tsn_chunk)) / sizeof(struct sctp_stream_identifier_block);
}
static int sctp_forward_tsn_chunk_to_string(
FILE *s,
struct sctp_forward_tsn_chunk *chunk,
char **error)
{
u16 length, i;
length = ntohs(chunk->length);
u16 num_id_blocks = get_num_id_blocks(length);
if (length < sizeof(struct sctp_forward_tsn_chunk)) {
asprintf(error, "FORWARD_TSN chunk too short (length=%u)", length);
return STATUS_ERR;
}
fputs("FORWARD_TSN[", s);
fprintf(s, "flgs=0x%02x, ", chunk->flags);
fprintf(s, "len=%u, ", length);
fprintf(s, "cum_tsn=%u, ", ntohl(chunk->cum_tsn));
fprintf(s, "ids=[");
for (i = 0; i < num_id_blocks; i++) {
fprintf(s, "{%u,%u}",
ntohs(chunk->stream_identifier_blocks[i].stream),
ntohs(chunk->stream_identifier_blocks[i].stream_sequence));
if (i != num_id_blocks-1) {
fprintf(s, ",");
}
}
fputs("]]", s);
return STATUS_OK;
}
static int sctp_unknown_chunk_to_string(FILE *s,
struct sctp_chunk *chunk,
char **error)
......@@ -1803,6 +1842,10 @@ int sctp_chunk_to_string(FILE *s, struct sctp_chunk *chunk, char **error)
result = sctp_reconfig_chunk_to_string(s,
(struct sctp_reconfig_chunk *)chunk, error);
break;
case SCTP_FORWARD_TSN_CHUNK_TYPE:
result = sctp_forward_tsn_chunk_to_string(s,
(struct sctp_forward_tsn_chunk *)chunk, error);
break;
default:
result = sctp_unknown_chunk_to_string(s, chunk, error);
break;
......
......@@ -234,6 +234,65 @@ sctp_sack_block_list_item_dup_new(u32 tsn)
return item;
}
struct sctp_forward_tsn_ids_list *
sctp_forward_tsn_ids_list_new () {
struct sctp_forward_tsn_ids_list *list;
list = malloc(sizeof(struct sctp_forward_tsn_ids_list));
assert(list != NULL);
list->first = NULL;
list->last = NULL;
list->nr_entries = 0;
return list;
}
void
sctp_forward_tsn_ids_list_append(struct sctp_forward_tsn_ids_list *list,
struct sctp_forward_tsn_ids_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_forward_tsn_ids_list_free (struct sctp_forward_tsn_ids_list *list) {
struct sctp_forward_tsn_ids_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_forward_tsn_ids_list_item *
sctp_forward_tsn_ids_list_item_new(u16 stream_identifier, u16 stream_sequence_number) {
struct sctp_forward_tsn_ids_list_item *item;
item = malloc(sizeof(struct sctp_forward_tsn_ids_list_item));
assert(item != NULL);
item->next = NULL;
item->stream_identifier = stream_identifier;
item->stream_sequence_number= stream_sequence_number;
return item;
}
struct sctp_address_type_list *
sctp_address_type_list_new(void)
{
......@@ -1380,6 +1439,62 @@ sctp_pad_chunk_new(s64 flgs, s64 len, u8* padding)
sctp_cause_list_new());
}
struct sctp_chunk_list_item *
sctp_forward_tsn_chunk_new(u32 cum_tsn, struct sctp_forward_tsn_ids_list *sids) {
struct sctp_forward_tsn_chunk *chunk;
struct sctp_forward_tsn_ids_list_item *item;
DEBUGP("sctp_forward_tsn_chunk_new called with cum_tsn = %d and sids_list = %p", cum_tsn, sids);
u32 flags;
u32 length;
u16 i, nr_sids;
flags = 0;
length = sizeof(struct sctp_forward_tsn_chunk);
if (sids == NULL) {
nr_sids = 0;
flags |= FLAG_CHUNK_LENGTH_NOCHECK;
flags |= FLAG_FORWARD_TSN_CHUNK_IDS_NOCHECK;
} else {
nr_sids = sids->nr_entries;
length += nr_sids * sizeof(struct sctp_stream_identifier_block);
}
assert(is_valid_u16(length));
assert(length % 4 == 0);
chunk = malloc(length);
assert(chunk != NULL);
chunk->type = SCTP_FORWARD_TSN_CHUNK_TYPE;
chunk->flags = 0;
chunk->length = htons(length);
if (cum_tsn == -1) {
chunk->cum_tsn = htonl(0);
flags |= FLAG_FORWARD_TSN_CHUNK_CUM_TSN_NOCHECK;
} else {
chunk->cum_tsn = htonl((u32)cum_tsn);
}
if (nr_sids == 0 || sids == NULL) {
flags |= FLAG_FORWARD_TSN_CHUNK_IDS_NOCHECK;
}
if (sids != NULL) {
for (i = 0, item = sids->first;
(i < nr_sids) && (item != NULL);
i++, item = item->next) {
chunk->stream_identifier_blocks[i].stream= htons(item->stream_identifier);
chunk->stream_identifier_blocks[i].stream_sequence = htons(item->stream_sequence_number);
}
assert((i == nr_sids) && (item == NULL));
}
return sctp_chunk_list_item_new((struct sctp_chunk *)chunk,
length, flags,
sctp_parameter_list_new(),
sctp_cause_list_new());
}
struct sctp_chunk_list_item *
sctp_reconfig_chunk_new(s64 flgs, struct sctp_parameter_list *parameters)
{
......@@ -3104,6 +3219,13 @@ new_sctp_packet(int address_family,
break;
case SCTP_RECONFIG_CHUNK_TYPE:
break;
case SCTP_FORWARD_TSN_CHUNK_TYPE:
if (chunk_item->flags & FLAG_FORWARD_TSN_CHUNK_CUM_TSN_NOCHECK) {
asprintf(error,
"cum tsn must be specified for inbound packets");
return NULL;
}
break;
default:
if (chunk_item->flags & FLAG_CHUNK_TYPE_NOCHECK) {
asprintf(error,
......
......@@ -104,6 +104,32 @@ 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_forward_tsn_ids_list_item {
struct sctp_forward_tsn_ids_list_item *next;
u16 stream_identifier;
u16 stream_sequence_number;
};
struct sctp_forward_tsn_ids_list {
struct sctp_forward_tsn_ids_list_item *first;
struct sctp_forward_tsn_ids_list_item *last;
u16 nr_entries;
};
struct sctp_forward_tsn_ids_list *
sctp_forward_tsn_ids_list_new ();
void
sctp_forward_tsn_ids_list_append(struct sctp_forward_tsn_ids_list *list,
struct sctp_forward_tsn_ids_list_item *item);
// TODO: where to call this freeing method... sctp_sack_block_list_free and sctp_byte_list_free are unused...?
void sctp_forward_tsn_ids_list_free (struct sctp_forward_tsn_ids_list *list);
struct sctp_forward_tsn_ids_list_item *
sctp_forward_tsn_ids_list_item_new(u16 stream_identifier, u16 stream_sequence_number);
struct sctp_address_type_list_item {
struct sctp_address_type_list_item *next;
u16 address_type;
......@@ -325,6 +351,12 @@ sctp_i_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 res, s64 mid,
struct sctp_chunk_list_item *
sctp_pad_chunk_new(s64 flgs, s64 len, u8* padding);
#define FLAG_FORWARD_TSN_CHUNK_CUM_TSN_NOCHECK 0x00000100
#define FLAG_FORWARD_TSN_CHUNK_IDS_NOCHECK 0x00000200
struct sctp_chunk_list_item *
sctp_forward_tsn_chunk_new(u32 cum_tsn, struct sctp_forward_tsn_ids_list *sids_list);
struct sctp_chunk_list_item *
sctp_reconfig_chunk_new(s64 flgs, struct sctp_parameter_list *parameters);
......
#ifdef FreeBSD
// disable all extensions except PR-SCTP on FreeBSD
0.0 `sysctl -w net.inet.sctp.ecn_enable=0`
+0.0 `sysctl -w net.inet.sctp.pr_enable=1`
+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`
#endif
+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 bind(3, ..., ...) = 0
+0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)
+0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...]
+0.1 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=16, is=16, tsn=1, STATE_COOKIE[len=4, val=...], FORWARD_TSN_SUPPORTED[]]
+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
// Turn off the sending of HEARTBEATs.
+0.0 setsockopt(3, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, {spp_address=..., spp_hbinterval=0, spp_pathmaxrxt=0, spp_pathmtu=0, spp_flags=SPP_HB_DISABLE|SPP_PMTUD_DISABLE, spp_ipv6_flowlabel=0, spp_dscp=0}, 152) = 0
//sctp_sendmsg(int sd, const void * msg, size_t len, struct sockaddr *to, socklen_t tolen,
// uint32_t ppid, uint32_t flags, uint16_t stream_no, uint32_t timetolive, uint32_t context);
+0.0 sctp_sendmsg(3, ..., 1000, ..., ..., htonl(1234), 0, 1, 10, 0) = 1000
+0.0 > sctp: DATA[flgs=BE, len=1016, tsn=1, sid=1, ssn=0, ppid=1234]
* > sctp: FORWARD_TSN[cum_tsn=1, ids=[{1,0}]]
+0.1 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]]
+0.0 sctp_sendmsg(3, ..., 1000, ..., ..., htonl(1234), 0, 1, 10, 0) = 1000
+0.0 > sctp: DATA[flgs=BE, len=1016, tsn=2, sid=1, ssn=1, ppid=1234]
* > sctp: FORWARD_TSN[cum_tsn=2, ids=[{1,1}]]
+1.0 < sctp: DATA[flgs=BE, len=1016, tsn=1, sid=1, ssn=0, ppid=1234]
* > sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=..., gaps=[], dups=[]]
+0.0 read(3, ..., 2000) = 1000
+2.0 < sctp: FORWARD_TSN[cum_tsn=1, ids=[{1,0}]]
+0.0 close(3) = 0
+0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=1]
+0.1 < sctp: SHUTDOWN_ACK[flgs=0]
+0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0]
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