core: Add TX/RX API that exposes message tag and tag owner

MCTP received packets can carry a message tag and tag owner bit
which is set by a remote MCTP endpoint. This can be used by the
remote MCTP endpoint to track the responses. Thus, libmctp should
provide a mechanism for the upper layer MCTP applications to
respond with the same message tag.

This patchset extends TX and RX API with message tag and
tag owner bits.

Signed-off-by: Sumanth Bhat <sumanth.bhat@linux.intel.com>
Change-Id: I6d07eafa86c653abdd4313ab7cc77e5a93124477
diff --git a/tests/test_astlpc.c b/tests/test_astlpc.c
index 054eda1..f781fa5 100644
--- a/tests/test_astlpc.c
+++ b/tests/test_astlpc.c
@@ -150,7 +150,8 @@
 	.lpc_write = mctp_astlpc_mmio_lpc_write,
 };
 
-static void rx_message(uint8_t eid __unused, void *data __unused, void *msg,
+static void rx_message(uint8_t eid __unused, bool tag_owner __unused,
+		       uint8_t msg_tag __unused, void *data __unused, void *msg,
 		       size_t len)
 {
 	struct astlpc_test *test = data;
@@ -257,7 +258,8 @@
 	mctp_set_rx_all(ctx.host.mctp, rx_message, &ctx);
 
 	/* BMC sends a message */
-	rc = mctp_message_tx(ctx.bmc.mctp, 9, msg, sizeof(msg));
+	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_SRC, 0, msg,
+			     sizeof(msg));
 	assert(rc == 0);
 
 	/* Host receives the first packet */
@@ -284,6 +286,7 @@
 {
 	struct astlpc_test ctx = { 0 };
 	uint8_t msg[MCTP_BTU];
+	uint8_t tag = 0;
 	int rc;
 
 	/* Test harness initialisation */
@@ -297,7 +300,8 @@
 	mctp_set_rx_all(ctx.bmc.mctp, rx_message, &ctx);
 
 	/* Host sends the single-packet message */
-	rc = mctp_message_tx(ctx.host.mctp, 8, msg, sizeof(msg));
+	rc = mctp_message_tx(ctx.host.mctp, 8, MCTP_MESSAGE_TO_DST, tag, msg,
+			     sizeof(msg));
 	assert(rc == 0);
 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF);
 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01);
@@ -324,6 +328,7 @@
 {
 	struct astlpc_test ctx = { 0 };
 	uint8_t msg[MCTP_BTU];
+	uint8_t tag = 0;
 	int rc;
 
 	/* Test harness initialisation */
@@ -337,7 +342,8 @@
 	mctp_set_rx_all(ctx.host.mctp, rx_message, &ctx);
 
 	/* BMC sends the single-packet message */
-	rc = mctp_message_tx(ctx.bmc.mctp, 9, msg, sizeof(msg));
+	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_SRC, tag, msg,
+			     sizeof(msg));
 	assert(rc == 0);
 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF);
 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01);
@@ -549,6 +555,7 @@
 	struct astlpc_test ctx = { 0 };
 	uint8_t kcs[2] = { 0 };
 	uint8_t msg[MCTP_BTU];
+	uint8_t tag = 0;
 	int rc;
 
 	ctx.lpc_mem = calloc(1, LPC_WIN_SIZE);
@@ -594,7 +601,8 @@
 	mctp_set_rx_all(ctx.host.mctp, rx_message, &ctx);
 
 	/* BMC sends the single-packet message */
-	rc = mctp_message_tx(ctx.bmc.mctp, 9, msg, sizeof(msg));
+	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_SRC, tag, msg,
+			     sizeof(msg));
 	assert(rc == 0);
 
 	/* Host receives the single-packet message */
@@ -615,6 +623,7 @@
 	struct astlpc_test ctx = { 0 };
 	uint8_t unwritten[MCTP_BTU];
 	uint8_t msg[MCTP_BTU];
+	uint8_t tag = 0;
 	int rc;
 
 	/* Test harness initialisation */
@@ -634,7 +643,8 @@
 	mctp_astlpc_poll(ctx.host.astlpc);
 
 	/* Host attempts to send the single-packet message, but is prevented */
-	rc = mctp_message_tx(ctx.host.mctp, 8, msg, sizeof(msg));
+	rc = mctp_message_tx(ctx.host.mctp, 8, MCTP_MESSAGE_TO_DST, tag, msg,
+			     sizeof(msg));
 	assert(rc == 0);
 	assert(!(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF));
 	astlpc_assert_tx_packet(&ctx.host, &unwritten[0], MCTP_BTU);
@@ -1083,6 +1093,7 @@
 	struct astlpc_endpoint *bmc, *host;
 	struct astlpc_test ctx;
 	uint8_t kcs[2] = { 0 };
+	uint8_t tag = 0;
 	void *lpc_mem;
 	int rc;
 
@@ -1117,7 +1128,8 @@
 
 	memset(ctx.msg, 0x5a, 2 * MCTP_BODY_SIZE(8192));
 
-	rc = mctp_message_tx(host->mctp, 8, ctx.msg, 2 * MCTP_BODY_SIZE(8192));
+	rc = mctp_message_tx(host->mctp, 8, MCTP_MESSAGE_TO_DST, tag, ctx.msg,
+			     2 * MCTP_BODY_SIZE(8192));
 	assert(rc == 0);
 	rc = mctp_astlpc_poll(bmc->astlpc);
 	assert(rc == 0);
@@ -1142,6 +1154,7 @@
 	struct astlpc_test ctx;
 	uint8_t kcs[2] = { 0 };
 	uint8_t msg[MCTP_BTU];
+	uint8_t tag = 0;
 	void *lpc_mem;
 	int rc;
 
@@ -1165,7 +1178,8 @@
 	 * terminating after a period long enough to packetise the message.
 	 */
 	alarm(1);
-	mctp_message_tx(bmc->mctp, 9, msg, sizeof(msg));
+	mctp_message_tx(bmc->mctp, 9, MCTP_MESSAGE_TO_SRC, tag, msg,
+			sizeof(msg));
 	alarm(0);
 
 	endpoint_destroy(bmc);
@@ -1178,6 +1192,7 @@
 	struct mctp_lpcmap_hdr *hdr;
 	uint8_t msg[MCTP_BTU];
 	uint32_t offset;
+	uint8_t tag = 0;
 	uint32_t code;
 	uint8_t *tlr;
 	int rc;
@@ -1193,7 +1208,8 @@
 	mctp_set_rx_all(ctx.bmc.mctp, rx_message, &ctx);
 
 	/* Host sends the single-packet message */
-	rc = mctp_message_tx(ctx.host.mctp, 8, msg, sizeof(msg));
+	rc = mctp_message_tx(ctx.host.mctp, 8, MCTP_MESSAGE_TO_DST, tag, msg,
+			     sizeof(msg));
 	assert(rc == 0);
 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF);
 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01);
@@ -1230,6 +1246,7 @@
 	struct mctp_lpcmap_hdr *hdr;
 	uint8_t msg[MCTP_BTU];
 	uint32_t offset;
+	uint8_t tag = 0;
 	uint32_t code;
 	uint8_t *tlr;
 	int rc;
@@ -1245,7 +1262,8 @@
 	mctp_set_rx_all(ctx.host.mctp, rx_message, &ctx);
 
 	/* BMC sends the single-packet message */
-	rc = mctp_message_tx(ctx.bmc.mctp, 9, msg, sizeof(msg));
+	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_SRC, tag, msg,
+			     sizeof(msg));
 	assert(rc == 0);
 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF);
 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01);
diff --git a/tests/test_cmds.c b/tests/test_cmds.c
index 1b7536a..ca5e838 100644
--- a/tests/test_cmds.c
+++ b/tests/test_cmds.c
@@ -32,6 +32,8 @@
 };
 
 static void control_message_transport_callback(mctp_eid_t src __unused,
+					       bool tag_owner __unused,
+					       uint8_t msg_tag __unused,
 					       void *data, void *buf,
 					       size_t len __unused)
 {
diff --git a/tests/test_core.c b/tests/test_core.c
index dacf197..744fe96 100644
--- a/tests/test_core.c
+++ b/tests/test_core.c
@@ -42,17 +42,21 @@
 struct test_params {
 	bool seen;
 	size_t message_size;
+	uint8_t msg_tag;
+	bool tag_owner;
 };
 
-static void rx_message(uint8_t eid __unused, void *data, void *msg __unused,
-		       size_t len)
+static void rx_message(uint8_t eid __unused, bool tag_owner, uint8_t msg_tag,
+		       void *data, void *msg __unused, size_t len)
 {
 	struct test_params *param = (struct test_params *)data;
 
-	mctp_prdebug("MCTP message received: len %zd", len);
+	mctp_prdebug("MCTP message received: len %zd, tag %u", len, msg_tag);
 
 	param->seen = true;
 	param->message_size = len;
+	param->msg_tag = msg_tag;
+	param->tag_owner = tag_owner;
 }
 
 static uint8_t get_sequence()
@@ -441,6 +445,92 @@
 	mctp_destroy(mctp);
 }
 
+static void mctp_core_test_rx_with_tag()
+{
+	struct mctp *mctp = NULL;
+	struct mctp_binding_test *binding = NULL;
+	struct test_params test_param;
+	static uint8_t test_payload[MCTP_BTU];
+	uint8_t tag = get_tag();
+	struct pktbuf pktbuf;
+	uint8_t flags_seq_tag;
+
+	memset(test_payload, 0, sizeof(test_payload));
+	test_param.seen = false;
+	test_param.message_size = 0;
+	test_param.msg_tag = 0;
+	test_param.tag_owner = false;
+
+	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
+	mctp_set_rx_all(mctp, rx_message, &test_param);
+	memset(&pktbuf, 0, sizeof(pktbuf));
+	pktbuf.hdr.dest = TEST_DEST_EID;
+	pktbuf.hdr.src = TEST_SRC_EID;
+
+	/* Set tag and tag owner fields for a recieve packet */
+	flags_seq_tag = MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM |
+			(1 << MCTP_HDR_TO_SHIFT) | tag;
+	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
+			     &pktbuf);
+
+	assert(test_param.seen);
+	assert(test_param.message_size == (MCTP_BTU));
+	assert(test_param.msg_tag == tag);
+	assert(test_param.tag_owner);
+
+	mctp_binding_test_destroy(binding);
+	mctp_destroy(mctp);
+}
+
+static void mctp_core_test_rx_with_tag_multifragment()
+{
+	struct mctp *mctp = NULL;
+	struct mctp_binding_test *binding = NULL;
+	struct test_params test_param;
+	static uint8_t test_payload[MCTP_BTU];
+	uint8_t tag = get_tag();
+	struct pktbuf pktbuf;
+	uint8_t flags_seq_tag;
+
+	memset(test_payload, 0, sizeof(test_payload));
+	test_param.seen = false;
+	test_param.message_size = 0;
+	test_param.msg_tag = 0;
+	test_param.tag_owner = false;
+
+	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
+	mctp_set_rx_all(mctp, rx_message, &test_param);
+	memset(&pktbuf, 0, sizeof(pktbuf));
+	pktbuf.hdr.dest = TEST_DEST_EID;
+	pktbuf.hdr.src = TEST_SRC_EID;
+
+	/* Set tag and tag owner fields for a 3 fragment packet */
+	flags_seq_tag = MCTP_HDR_FLAG_SOM |
+			(get_sequence() << MCTP_HDR_SEQ_SHIFT) |
+			(1 << MCTP_HDR_TO_SHIFT) | tag;
+	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
+			     &pktbuf);
+
+	flags_seq_tag = (get_sequence() << MCTP_HDR_SEQ_SHIFT) |
+			(1 << MCTP_HDR_TO_SHIFT) | tag;
+	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
+			     &pktbuf);
+
+	flags_seq_tag = MCTP_HDR_FLAG_EOM |
+			(get_sequence() << MCTP_HDR_SEQ_SHIFT) |
+			(1 << MCTP_HDR_TO_SHIFT) | tag;
+	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
+			     &pktbuf);
+
+	assert(test_param.seen);
+	assert(test_param.message_size == (3 * MCTP_BTU));
+	assert(test_param.msg_tag == tag);
+	assert(test_param.tag_owner);
+
+	mctp_binding_test_destroy(binding);
+	mctp_destroy(mctp);
+}
+
 /* clang-format off */
 #define TEST_CASE(test) { #test, test }
 static const struct {
@@ -455,6 +545,8 @@
 	TEST_CASE(mctp_core_test_receive_bigger_end_fragment),
 	TEST_CASE(mctp_core_test_drop_large_fragments),
 	TEST_CASE(mctp_core_test_exhaust_context_buffers),
+	TEST_CASE(mctp_core_test_rx_with_tag),
+	TEST_CASE(mctp_core_test_rx_with_tag_multifragment),
 };
 /* clang-format on */
 
diff --git a/tests/test_eid.c b/tests/test_eid.c
index 031d044..5c089ad 100644
--- a/tests/test_eid.c
+++ b/tests/test_eid.c
@@ -16,7 +16,9 @@
 	mctp_eid_t			src_eid;
 };
 
-static void test_rx(uint8_t eid, void *data, void *msg, size_t len)
+static void
+test_rx(uint8_t eid, bool tag_owner __unused, uint8_t msg_tag __unused,
+	void *data, void *msg __unused, size_t len __unused)
 {
 	struct test_ctx *ctx = data;
 
diff --git a/tests/test_seq.c b/tests/test_seq.c
index 8838acb..e5a8954 100644
--- a/tests/test_seq.c
+++ b/tests/test_seq.c
@@ -19,12 +19,12 @@
 	size_t				rx_len;
 };
 
-static void test_rx(uint8_t eid, void *data, void *msg, size_t len)
+static void
+test_rx(uint8_t eid __unused, bool tag_owner __unused,
+	uint8_t msg_tag __unused, void *data, void *msg, size_t len)
 {
 	struct test_ctx *ctx = data;
 
-	(void)eid;
-
 	ctx->rx_count++;
 
 	/* append incoming message data to the existing rx_data */
diff --git a/tests/test_serial.c b/tests/test_serial.c
index 3c6d147..aa282c9 100644
--- a/tests/test_serial.c
+++ b/tests/test_serial.c
@@ -43,20 +43,25 @@
 uint8_t mctp_msg_src[2 * MCTP_BTU];
 
 static bool seen;
+static bool received_tag_owner;
+static uint8_t received_msg_tag;
 
-static void rx_message(uint8_t eid __unused, void *data __unused, void *msg,
-		       size_t len)
+static void rx_message(uint8_t eid __unused, bool tag_owner, uint8_t msg_tag,
+		       void *data __unused, void *msg, size_t len)
 {
 	uint8_t type;
 
 	type = *(uint8_t *)msg;
 
-	mctp_prdebug("MCTP message received: len %zd, type %d", len, type);
+	mctp_prdebug("MCTP message received: len %zd, type %d, tag %d", len,
+		     type, msg_tag);
 
 	assert(sizeof(mctp_msg_src) == len);
 	assert(!memcmp(mctp_msg_src, msg, len));
 
 	seen = true;
+	received_msg_tag = msg_tag;
+	received_tag_owner = tag_owner;
 }
 
 struct serial_test {
@@ -70,6 +75,8 @@
 
 	struct mctp_binding_serial_pipe *a;
 	struct mctp_binding_serial_pipe *b;
+	uint8_t msg_tag = 2;
+	bool tag_owner = false;
 	int p[2][2];
 	int rc;
 
@@ -109,14 +116,19 @@
 	mctp_serial_set_tx_fn(b->serial, mctp_binding_serial_pipe_tx, a);
 	mctp_register_bus(scenario[1].mctp, mctp_binding_serial_core(b->serial), 9);
 
-	/* Transmit a message from A to B */
-	rc = mctp_message_tx(scenario[0].mctp, 9, mctp_msg_src, sizeof(mctp_msg_src));
+	/* Transmit a message from A to B, with message tag */
+	rc = mctp_message_tx(scenario[0].mctp, 9, tag_owner, msg_tag,
+			     mctp_msg_src, sizeof(mctp_msg_src));
 	assert(rc == 0);
 
 	/* Read the message at B from A */
 	seen = false;
+	received_tag_owner = true;
+	received_msg_tag = 0;
 	mctp_serial_read(b->serial);
 	assert(seen);
+	assert(received_tag_owner == tag_owner);
+	assert(received_msg_tag == msg_tag);
 
 	mctp_serial_destroy(scenario[1].binding.serial);
 	mctp_destroy(scenario[1].mctp);