diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index d452e25dc515b249501508be61899e7d4613ca56..0fa52409cf7d383407124cc5ef743cb4f4d0d0e9 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -557,6 +557,7 @@ I-DATA return I_DATA; PAD return PAD; RECONFIG return RECONFIG; FORWARD_TSN return FORWARD_TSN; +I_FORWARD_TSN return I_FORWARD_TSN; type return TYPE; flgs return FLAGS; len return LEN; diff --git a/gtests/net/packetdrill/packet_to_string_test.c b/gtests/net/packetdrill/packet_to_string_test.c index 136a075272bdb4413bd6c340c8178727dbfd72f9..a63249721c7fcb66a6d32c659bacd4763446928e 100644 --- a/gtests/net/packetdrill/packet_to_string_test.c +++ b/gtests/net/packetdrill/packet_to_string_test.c @@ -103,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, 0x02, 0x0c, 0x84, 0xff, + 0x60, 0x00, 0x00, 0x00, 0x02, 0x1c, 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, @@ -111,7 +111,7 @@ static void test_sctp_ipv6_packet_to_string(void) /* SCTP Common Header: */ 0x04, 0xd2, 0x1f, 0x90, 0x01, 0x02, 0x03, 0x04, - 0xd8, 0x6a, 0x11, 0x71, + 0xc9, 0xc7, 0x27, 0x40, /* SCTP DATA Chunk */ 0x00, 0x0f, 0x00, 0x13, 0x01, 0x02, 0x03, 0x04, @@ -242,6 +242,11 @@ static void test_sctp_ipv6_packet_to_string(void) 0xb5, 0xaa, 0xaf, 0x0f, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + /* I_FORWARD_TSN Chunk*/ + 0xc2, 0x00, 0x00, 0x10, + 0xb5, 0xaa, 0xaf, 0x0f, + 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x01, 0x00, /* SCTP I-DATA Chunk */ 0x40, 0x0f, 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, @@ -341,6 +346,7 @@ static void test_sctp_ipv6_packet_to_string(void) "CWR[flgs=0x00, tsn=16909060]; " "SHUTDOWN_COMPLETE[flgs=T]; " "FORWARD_TSN[flgs=0x00, len=16, cum_tsn=3047862031, ids=[{1,2},{3,4}]]; " + "I_FORWARD_TSN[flgs=0x00, len=16, cum_tsn=3047862031, ids=[{U,1,256}]]; " "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=...]"; @@ -403,6 +409,7 @@ static void test_sctp_ipv6_packet_to_string(void) "CWR[flgs=0x00, tsn=16909060]; " "SHUTDOWN_COMPLETE[flgs=T]; " "FORWARD_TSN[flgs=0x00, len=16, cum_tsn=3047862031, ids=[{1,2},{3,4}]]; " + "I_FORWARD_TSN[flgs=0x00, len=16, cum_tsn=3047862031, ids=[{U,1,256}]]; " "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=...]"; @@ -465,14 +472,15 @@ static void test_sctp_ipv6_packet_to_string(void) "CWR[flgs=0x00, tsn=16909060]; " "SHUTDOWN_COMPLETE[flgs=T]; " "FORWARD_TSN[flgs=0x00, len=16, cum_tsn=3047862031, ids=[{1,2},{3,4}]]; " + "I_FORWARD_TSN[flgs=0x00, len=16, cum_tsn=3047862031, ids=[{U,1,256}]]; " "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 02 0c 84 ff 00 02 00 00 00 00 00 00 " "\n" + "0x0000: 60 00 00 00 02 1c 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: d8 6a 11 71 00 0f 00 13 01 02 03 04 00 ff 01 00 " "\n" + "0x0030: c9 c7 27 40 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" @@ -500,11 +508,13 @@ static void test_sctp_ipv6_packet_to_string(void) "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 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"; + "0x01f0: 00 03 00 04 c2 00 00 10 b5 aa af 0f 00 01 00 01 " "\n" + "0x0200: 00 00 01 00 40 0f 00 17 00 00 00 04 00 ff 00 00 " "\n" + "0x0210: 00 00 00 01 00 00 00 00 00 01 02 00 40 0d 00 17 " "\n" + "0x0220: 00 00 00 04 00 ff 00 00 00 00 00 02 00 00 00 01 " "\n" + "0x0230: 00 01 02 00 84 00 00 10 50 50 50 50 50 50 50 50 " "\n" + "0x0240: 50 50 50 50 " "\n"; + printf("expected = '%s'\n", expected); assert(strcmp(dump, expected) == 0); free(dump); diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index e35640e39c6d3b637d446bd47499d79df4ad4ea5..a2ad7f21ee42567118631a647c35241d4a50f9ef 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -1632,14 +1632,14 @@ i_forward_tsn_ids_list i_forward_tsn_id : '{' WORD ',' INTEGER ',' INTEGER '}' { char *c = $2; - if (*c != 'O' || *c != 'U') { + if (*c != 'O' && *c != 'U') { semantic_error("either O for ordered or U for unordered must be specified"); } if (!is_valid_u16($4)) { semantic_error("stream identifier out of range"); } - if (!is_valid_u16($6)) { - semantic_error("stream sequence number out of range"); + if (!is_valid_u32($6)) { + semantic_error("message identifier number out of range"); } $$ = sctp_i_forward_tsn_ids_list_item_new(*c, $4, $6); } diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c index 65f2cc7fa920898d13eaf364ab48fe5ad5d54468..a1459d72f9cb0bc2c7c18b960b0452e5e62204b3 100644 --- a/gtests/net/packetdrill/run_packet.c +++ b/gtests/net/packetdrill/run_packet.c @@ -655,6 +655,7 @@ static int map_inbound_sctp_packet( struct sctp_i_data_chunk *i_data; struct sctp_reconfig_chunk *reconfig; struct sctp_forward_tsn_chunk *forward_tsn; + struct sctp_i_forward_tsn_chunk *i_forward_tsn; u32 local_diff, remote_diff; u32 v_tag; @@ -761,6 +762,10 @@ static int map_inbound_sctp_packet( forward_tsn = (struct sctp_forward_tsn_chunk *) chunk; forward_tsn->cum_tsn = htonl(ntohl(forward_tsn->cum_tsn) + local_diff); break; + case SCTP_I_FORWARD_TSN_CHUNK_TYPE: + i_forward_tsn = (struct sctp_i_forward_tsn_chunk *) chunk; + i_forward_tsn->cum_tsn = htonl(ntohl(i_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) { @@ -973,6 +978,7 @@ static int map_outbound_live_sctp_packet( struct sctp_i_data_chunk *i_data; struct sctp_reconfig_chunk *reconfig; struct sctp_forward_tsn_chunk *forward_tsn; + struct sctp_i_forward_tsn_chunk *i_forward_tsn; u32 local_diff, remote_diff; u16 nr_gap_blocks, nr_dup_tsns, number_of_nr_gap_blocks, i; @@ -1048,6 +1054,10 @@ static int map_outbound_live_sctp_packet( forward_tsn = (struct sctp_forward_tsn_chunk *) chunk; forward_tsn->cum_tsn = htonl(ntohl(forward_tsn->cum_tsn) + local_diff); break; + case SCTP_I_FORWARD_TSN_CHUNK_TYPE: + i_forward_tsn = (struct sctp_i_forward_tsn_chunk *) chunk; + i_forward_tsn->cum_tsn = htonl(ntohl(i_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)) { @@ -2214,6 +2224,58 @@ static int verify_forward_tsn_chunk(struct sctp_forward_tsn_chunk *actual_chunk, return STATUS_OK; } +static u16 get_num_id_blocks_for_i_forward_tsn (u16 packet_length) { + return (packet_length - sizeof(struct sctp_i_forward_tsn_chunk)) / sizeof(struct sctp_i_forward_tsn_identifier_block); +} + +static int verify_i_forward_tsn_chunk(struct sctp_i_forward_tsn_chunk *actual_chunk, + struct sctp_i_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_for_i_forward_tsn(actual_packet_length); + u16 script_nr_id_blocks = get_num_id_blocks_for_i_forward_tsn(script_packet_length); + u16 i; + + if ((flags & FLAG_I_FORWARD_TSN_CHUNK_CUM_TSN_NOCHECK) == 0) { + if (check_field("sctp_i_forward_tsn_cum_tsn", + ntohl(script_chunk->cum_tsn), + ntohl(actual_chunk->cum_tsn), + error) == STATUS_ERR) { + return STATUS_ERR; + } + } + + if ((flags & FLAG_I_FORWARD_TSN_CHUNK_IDS_NOCHECK) == 0) { + if (check_field("nr_id_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_i_forward_tsn_stream_identifier", + ntohs(script_chunk->stream_identifier_blocks[i].stream_identifier), + ntohs(actual_chunk->stream_identifier_blocks[i].stream_identifier), + error) == STATUS_ERR || + check_field("sctp_i_forward_tsn_u_bit", + ntohs(script_chunk->stream_identifier_blocks[i].reserved), + ntohs(actual_chunk->stream_identifier_blocks[i].reserved), + error) == STATUS_ERR || + check_field("sctp_i_forward_tsn_message_identifier", + ntohs(script_chunk->stream_identifier_blocks[i].message_identifier), + ntohs(actual_chunk->stream_identifier_blocks[i].message_identifier), + 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, @@ -2369,6 +2431,11 @@ static int verify_sctp( (struct sctp_forward_tsn_chunk *)script_chunk, flags, error); break; + case SCTP_I_FORWARD_TSN_CHUNK_TYPE: + result = verify_i_forward_tsn_chunk((struct sctp_i_forward_tsn_chunk *)actual_chunk, + (struct sctp_i_forward_tsn_chunk *)script_chunk, + flags, error); + break; default: result = STATUS_ERR; assert(!"unsupported SCTP chunk type"); diff --git a/gtests/net/packetdrill/sctp_chunk_to_string.c b/gtests/net/packetdrill/sctp_chunk_to_string.c index 386cab745171ad3cdfeb011dcb8fd398d074da59..6f3c6cd3eb99c75fb0f24bea7b6844b20b9c0daf 100644 --- a/gtests/net/packetdrill/sctp_chunk_to_string.c +++ b/gtests/net/packetdrill/sctp_chunk_to_string.c @@ -1742,6 +1742,46 @@ static int sctp_forward_tsn_chunk_to_string( return STATUS_OK; } +static u16 get_num_id_blocks_for_i_forward_tsn (u16 packet_length) { + return (packet_length - sizeof(struct sctp_i_forward_tsn_chunk)) / sizeof(struct sctp_i_forward_tsn_identifier_block); +} + +static int sctp_i_forward_tsn_chunk_to_string( + FILE *s, + struct sctp_i_forward_tsn_chunk *chunk, + char **error) +{ + u16 length, i; + length = ntohs(chunk->length); + u16 num_id_blocks = get_num_id_blocks_for_i_forward_tsn(length); + + if (length < sizeof(struct sctp_i_forward_tsn_chunk)) { + asprintf(error, "I_FORWARD_TSN chunk too short (length=%u)", length); + return STATUS_ERR; + } + + fputs("I_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, "{%s,%u,%u}", + (ntohs(chunk->stream_identifier_blocks[i].reserved) & 1) ? "U" : "O", + ntohs(chunk->stream_identifier_blocks[i].stream_identifier), + ntohl(chunk->stream_identifier_blocks[i].message_identifier)); + 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) @@ -1846,6 +1886,10 @@ int sctp_chunk_to_string(FILE *s, struct sctp_chunk *chunk, char **error) result = sctp_forward_tsn_chunk_to_string(s, (struct sctp_forward_tsn_chunk *)chunk, error); break; + case SCTP_I_FORWARD_TSN_CHUNK_TYPE: + result = sctp_i_forward_tsn_chunk_to_string(s, + (struct sctp_i_forward_tsn_chunk *)chunk, error); + break; default: result = sctp_unknown_chunk_to_string(s, chunk, error); break;