From b9adce2cbb749e2d5e2d6f0e4c57db92bed3285e Mon Sep 17 00:00:00 2001
From: Julian Cordes <julian.cordes@gmail.com>
Date: Fri, 22 Jul 2016 18:51:15 +0200
Subject: [PATCH] more adjustments regarding i_forward_tsn_chunk

---
 gtests/net/packetdrill/lexer.l                |  1 +
 .../net/packetdrill/packet_to_string_test.c   | 28 +++++---
 gtests/net/packetdrill/parser.y               |  6 +-
 gtests/net/packetdrill/run_packet.c           | 67 +++++++++++++++++++
 gtests/net/packetdrill/sctp_chunk_to_string.c | 44 ++++++++++++
 5 files changed, 134 insertions(+), 12 deletions(-)

diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index d452e25d..0fa52409 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 136a0752..a6324972 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 e35640e3..a2ad7f21 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 65f2cc7f..a1459d72 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 386cab74..6f3c6cd3 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;
-- 
GitLab