tests: astlpc: MTU renegotiation with populated Tx queue

Capture the behaviour that lead to a complete stall now that we've fixed
the bug.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Change-Id: I9883a4f4040a282de417cf0e4293ecd1ad45419a
diff --git a/tests/test_astlpc.c b/tests/test_astlpc.c
index 2b7a477..91f6507 100644
--- a/tests/test_astlpc.c
+++ b/tests/test_astlpc.c
@@ -1149,6 +1149,115 @@
 	free(lpc_mem);
 }
 
+static void astlpc_test_negotiate_mtu_high_low(void)
+{
+	uint8_t msg[3 * MCTP_BTU] = { 0 };
+	struct astlpc_test ctx = { 0 };
+	uint32_t bmtu, hmtu;
+	uint8_t tag = 0;
+	int rc;
+
+	/* Configure message */
+	memset(&msg[0], 0xa5, sizeof(msg));
+
+	/* Test harness initialisation */
+	ctx.lpc_mem = calloc(1, 1 * 1024 * 1024);
+	assert(ctx.lpc_mem);
+
+	/* BMC initialisation */
+	bmtu = 3 * MCTP_BTU;
+	rc = endpoint_init(&ctx.bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, bmtu,
+			   &ctx.kcs, ctx.lpc_mem);
+	assert(!rc);
+
+	/* Host initialisation with low MTU */
+	hmtu = 3 * MCTP_BTU;
+	rc = endpoint_init(&ctx.host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, hmtu,
+			   &ctx.kcs, ctx.lpc_mem);
+	assert(!rc);
+
+	/* Configure host message handler */
+	ctx.msg = &msg[0];
+	ctx.count = 0;
+	mctp_set_rx_all(ctx.host.mctp, astlpc_test_rx_message, &ctx);
+
+	/* Startup BMC and host interfaces */
+	rc = mctp_astlpc_poll(ctx.bmc.astlpc);
+	assert(rc == 0);
+	rc = mctp_astlpc_poll(ctx.host.astlpc);
+	assert(rc == 0);
+
+	/*
+	 * Transmit a message to place a packet on the interface. This releases the buffer and
+	 * disables the binding, plugging the binding's transmit queue while the host hasn't polled
+	 * to pull the packet off.
+	 */
+	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_DST, tag, msg,
+			     sizeof(msg));
+
+	/* Leave the packet in place on the interface by not polling the host binding */
+
+	/*
+	 * Transmit another message to force packetisation at the current MTU while the binding is
+	 * disabled, leaving the packet(s) in the binding's transmit queue
+	 */
+	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_DST, tag, msg,
+			     sizeof(msg));
+
+	/* Tear-down the host so we can bring up a new one */
+	endpoint_destroy(&ctx.host);
+
+	/* Bring up a new host endpoint with a lower MTU than we previously negotiated */
+	hmtu = 2 * MCTP_BTU;
+	rc = endpoint_init(&ctx.host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, hmtu,
+			   &ctx.kcs, ctx.lpc_mem);
+	assert(!rc);
+
+	/* Configure host message handler again after reinitialisation */
+	ctx.msg = &msg[0];
+	ctx.count = 0;
+	mctp_set_rx_all(ctx.host.mctp, astlpc_test_rx_message, &ctx);
+
+	/* Process low MTU proposal */
+	rc = mctp_astlpc_poll(ctx.bmc.astlpc);
+	assert(rc == 0);
+
+	/* Accept low MTU proposal */
+	rc = mctp_astlpc_poll(ctx.host.astlpc);
+	assert(rc == 0);
+
+	/*
+	 * Check that there are no outstanding messages to be received by the host. The message
+	 * packetised on the BMC at the larger MTU must be dropped as its now no longer possible to
+	 * transmit those packets
+	 */
+	rc = mctp_astlpc_poll(ctx.host.astlpc);
+	assert(rc == 0);
+	assert(ctx.count == 0);
+
+	/* Transmit another message from the BMC to the host, packetised using the new MTU */
+	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_DST, tag, msg,
+			     hmtu);
+
+	/* Check that the most recent BMC transmission is received by the host */
+	rc = mctp_astlpc_poll(ctx.host.astlpc);
+	assert(rc == 0);
+	assert(ctx.count == 1);
+
+	/* Ensure buffer ownership is returned to the BMC and the BMC Tx queue is processed */
+	rc = mctp_astlpc_poll(ctx.bmc.astlpc);
+	assert(rc == 0);
+
+	/* Check that no further messages are propagated to the host */
+	rc = mctp_astlpc_poll(ctx.host.astlpc);
+	assert(rc == 0);
+	assert(ctx.count == 1);
+
+	endpoint_destroy(&ctx.host);
+	endpoint_destroy(&ctx.bmc);
+	free(ctx.lpc_mem);
+}
+
 static void astlpc_test_tx_before_channel_init(void)
 {
 	struct astlpc_endpoint *bmc;
@@ -1397,6 +1506,7 @@
 	TEST_CASE(astlpc_test_buffers_bad_host_init),
 	TEST_CASE(astlpc_test_negotiate_increased_mtu),
 	TEST_CASE(astlpc_test_negotiate_mtu_low_high),
+	TEST_CASE(astlpc_test_negotiate_mtu_high_low),
 	TEST_CASE(astlpc_test_send_large_packet),
 	TEST_CASE(astlpc_test_tx_before_channel_init),
 	TEST_CASE(astlpc_test_corrupt_host_tx),