xref: /openbmc/libmctp/tests/test_astlpc.c (revision 7f7fdc1d)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6 
7 #define ASTLPC_VER_CUR 3
8 #include "astlpc.c"
9 
10 #ifdef pr_fmt
11 #undef pr_fmt
12 #define pr_fmt(x) "test: " x
13 #endif
14 
15 #include "compiler.h"
16 #include "container_of.h"
17 #include "libmctp-astlpc.h"
18 #include "libmctp-log.h"
19 
20 #ifdef NDEBUG
21 #undef NDEBUG
22 #endif
23 
24 #include <assert.h>
25 #include <limits.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/random.h>
31 #include <unistd.h>
32 
33 #ifndef ARRAY_SIZE
34 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
35 #endif
36 
37 struct mctp_binding_astlpc_mmio {
38 	struct mctp_binding_astlpc astlpc;
39 	bool bmc;
40 
41 	uint8_t (*kcs)[2];
42 
43 	size_t lpc_size;
44 	uint8_t *lpc;
45 };
46 
47 struct astlpc_endpoint {
48 	struct mctp_binding_astlpc_mmio mmio;
49 	struct mctp_binding_astlpc *astlpc;
50 	struct mctp *mctp;
51 };
52 
53 struct astlpc_test {
54 	struct astlpc_endpoint bmc;
55 	struct astlpc_endpoint host;
56 	uint8_t kcs[2];
57 	uint8_t *lpc_mem;
58 
59 	void *msg;
60 	uint8_t count;
61 };
62 
63 #define binding_to_mmio(b)                                                     \
64 	container_of(b, struct mctp_binding_astlpc_mmio, astlpc)
65 
mctp_astlpc_mmio_kcs_read(void * data,enum mctp_binding_astlpc_kcs_reg reg,uint8_t * val)66 static int mctp_astlpc_mmio_kcs_read(void *data,
67 				     enum mctp_binding_astlpc_kcs_reg reg,
68 				     uint8_t *val)
69 {
70 	struct mctp_binding_astlpc_mmio *mmio = binding_to_mmio(data);
71 
72 	*val = (*mmio->kcs)[reg];
73 
74 	mctp_prdebug("%s: 0x%hhx from %s", __func__, *val,
75 		     reg ? "status" : "data");
76 
77 	if (reg == MCTP_ASTLPC_KCS_REG_DATA) {
78 		uint8_t flag = mmio->bmc ? KCS_STATUS_IBF : KCS_STATUS_OBF;
79 		(*mmio->kcs)[MCTP_ASTLPC_KCS_REG_STATUS] &= ~flag;
80 	}
81 
82 	return 0;
83 }
84 
mctp_astlpc_mmio_kcs_write(void * data,enum mctp_binding_astlpc_kcs_reg reg,uint8_t val)85 static int mctp_astlpc_mmio_kcs_write(void *data,
86 				      enum mctp_binding_astlpc_kcs_reg reg,
87 				      uint8_t val)
88 {
89 	struct mctp_binding_astlpc_mmio *mmio = binding_to_mmio(data);
90 	uint8_t *regp;
91 
92 	assert(reg == MCTP_ASTLPC_KCS_REG_DATA ||
93 	       reg == MCTP_ASTLPC_KCS_REG_STATUS);
94 
95 	if (reg == MCTP_ASTLPC_KCS_REG_DATA) {
96 		uint8_t flag = mmio->bmc ? KCS_STATUS_OBF : KCS_STATUS_IBF;
97 		(*mmio->kcs)[MCTP_ASTLPC_KCS_REG_STATUS] |= flag;
98 	}
99 
100 	regp = &(*mmio->kcs)[reg];
101 	if (reg == MCTP_ASTLPC_KCS_REG_STATUS)
102 		*regp = (val & ~0xbU) | (val & *regp & 1);
103 	else
104 		*regp = val;
105 
106 	mctp_prdebug("%s: 0x%hhx to %s", __func__, val,
107 		     reg ? "status" : "data");
108 
109 	return 0;
110 }
111 
112 static const struct mctp_binding_astlpc_ops astlpc_direct_mmio_ops = {
113 	.kcs_read = mctp_astlpc_mmio_kcs_read,
114 	.kcs_write = mctp_astlpc_mmio_kcs_write,
115 };
116 
mctp_astlpc_mmio_lpc_read(void * data,void * buf,long offset,size_t len)117 int mctp_astlpc_mmio_lpc_read(void *data, void *buf, long offset, size_t len)
118 {
119 	struct mctp_binding_astlpc_mmio *mmio = binding_to_mmio(data);
120 
121 	mctp_prdebug("%s: %zu bytes from 0x%lx", __func__, len, offset);
122 
123 	assert(offset >= 0L);
124 	assert(offset + len < mmio->lpc_size);
125 
126 	memcpy(buf, mmio->lpc + offset, len);
127 
128 	return 0;
129 }
130 
mctp_astlpc_mmio_lpc_write(void * data,const void * buf,long offset,size_t len)131 int mctp_astlpc_mmio_lpc_write(void *data, const void *buf, long offset,
132 			       size_t len)
133 {
134 	struct mctp_binding_astlpc_mmio *mmio = binding_to_mmio(data);
135 
136 	mctp_prdebug("%s: %zu bytes to 0x%lx", __func__, len, offset);
137 
138 	assert(offset >= 0L);
139 	assert(offset + len < mmio->lpc_size);
140 
141 	memcpy(mmio->lpc + offset, buf, len);
142 
143 	return 0;
144 }
145 
146 static const struct mctp_binding_astlpc_ops astlpc_indirect_mmio_ops = {
147 	.kcs_read = mctp_astlpc_mmio_kcs_read,
148 	.kcs_write = mctp_astlpc_mmio_kcs_write,
149 	.lpc_read = mctp_astlpc_mmio_lpc_read,
150 	.lpc_write = mctp_astlpc_mmio_lpc_write,
151 };
152 
astlpc_test_rx_message(uint8_t eid __unused,bool tag_owner __unused,uint8_t msg_tag __unused,void * data __unused,void * msg,size_t len)153 static void astlpc_test_rx_message(uint8_t eid __unused,
154 				   bool tag_owner __unused,
155 				   uint8_t msg_tag __unused,
156 				   void *data __unused, void *msg, size_t len)
157 {
158 	struct astlpc_test *test = data;
159 
160 	mctp_prdebug("MCTP message received: msg: %p, len %zd", msg, len);
161 
162 	assert(len > 0);
163 	assert(msg);
164 	assert(test);
165 	assert(test->msg);
166 	assert(!memcmp(test->msg, msg, len));
167 
168 	test->count++;
169 }
170 
endpoint_init(struct astlpc_endpoint * ep,mctp_eid_t eid,uint8_t mode,uint32_t mtu,uint8_t (* kcs)[2],void * lpc_mem)171 static int endpoint_init(struct astlpc_endpoint *ep, mctp_eid_t eid,
172 			 uint8_t mode, uint32_t mtu, uint8_t (*kcs)[2],
173 			 void *lpc_mem)
174 {
175 	/*
176 	 * Configure the direction of the KCS interface so we know whether to
177 	 * set or clear IBF or OBF on writes or reads.
178 	 */
179 	ep->mmio.bmc = (mode == MCTP_BINDING_ASTLPC_MODE_BMC);
180 
181 	ep->mctp = mctp_init();
182 	assert(ep->mctp);
183 
184 	/* Inject KCS registers */
185 	ep->mmio.kcs = kcs;
186 
187 	/* Initialise the binding */
188 	ep->astlpc = mctp_astlpc_init(mode, mtu, lpc_mem,
189 				      &astlpc_direct_mmio_ops, &ep->mmio);
190 	assert(ep->astlpc);
191 
192 	return mctp_register_bus(ep->mctp, &ep->astlpc->binding, eid);
193 }
194 
endpoint_destroy(struct astlpc_endpoint * ep)195 static void endpoint_destroy(struct astlpc_endpoint *ep)
196 {
197 	mctp_astlpc_destroy(ep->astlpc);
198 	mctp_destroy(ep->mctp);
199 }
200 
network_init(struct astlpc_test * ctx)201 static void network_init(struct astlpc_test *ctx)
202 {
203 	int rc;
204 
205 	ctx->lpc_mem = calloc(1, 1 * 1024 * 1024);
206 	assert(ctx->lpc_mem);
207 
208 	/* BMC initialisation */
209 	rc = endpoint_init(&ctx->bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU,
210 			   &ctx->kcs, ctx->lpc_mem);
211 	assert(!rc);
212 	assert(ctx->kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_BMC_READY);
213 
214 	/* Host initialisation */
215 	rc = endpoint_init(&ctx->host, 9, MCTP_BINDING_ASTLPC_MODE_HOST,
216 			   MCTP_BTU, &ctx->kcs, ctx->lpc_mem);
217 	assert(!rc);
218 
219 	/* BMC processes host channel init request, alerts host */
220 	mctp_astlpc_poll(ctx->bmc.astlpc);
221 	assert(ctx->kcs[MCTP_ASTLPC_KCS_REG_STATUS] &
222 	       KCS_STATUS_CHANNEL_ACTIVE);
223 	assert(ctx->kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0xff);
224 
225 	/* Host dequeues channel init result */
226 	mctp_astlpc_poll(ctx->host.astlpc);
227 }
228 
network_destroy(struct astlpc_test * ctx)229 static void network_destroy(struct astlpc_test *ctx)
230 {
231 	endpoint_destroy(&ctx->bmc);
232 	endpoint_destroy(&ctx->host);
233 	free(ctx->lpc_mem);
234 }
235 
astlpc_assert_tx_packet(struct astlpc_endpoint * src,const void * expected,size_t len)236 static void astlpc_assert_tx_packet(struct astlpc_endpoint *src,
237 				    const void *expected, size_t len)
238 {
239 	const size_t tx_body = src->astlpc->layout.tx.offset + 4 + 4;
240 	const void *test = ((char *)src->astlpc->lpc_map) + tx_body;
241 	assert(!memcmp(test, expected, len));
242 }
243 
astlpc_test_packetised_message_bmc_to_host(void)244 static void astlpc_test_packetised_message_bmc_to_host(void)
245 {
246 	struct astlpc_test ctx = { 0 };
247 	uint8_t msg[2 * MCTP_BTU];
248 	int rc;
249 
250 	/* Test harness initialisation */
251 
252 	network_init(&ctx);
253 
254 	memset(&msg[0], 0x5a, MCTP_BTU);
255 	memset(&msg[MCTP_BTU], 0xa5, MCTP_BTU);
256 
257 	ctx.msg = &msg[0];
258 	ctx.count = 0;
259 	mctp_set_rx_all(ctx.host.mctp, astlpc_test_rx_message, &ctx);
260 
261 	/* BMC sends a message */
262 	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_SRC, 0, msg,
263 			     sizeof(msg));
264 	assert(rc == 0);
265 
266 	/* Host receives the first packet */
267 	mctp_astlpc_poll(ctx.host.astlpc);
268 
269 	/* BMC dequeues ownership hand-over and sends the queued packet */
270 	rc = mctp_astlpc_poll(ctx.bmc.astlpc);
271 	assert(rc == 0);
272 
273 	/* Host receives the next packet */
274 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF);
275 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01);
276 
277 	astlpc_assert_tx_packet(&ctx.bmc, &msg[MCTP_BTU], MCTP_BTU);
278 
279 	/* Host receives final packet */
280 	mctp_astlpc_poll(ctx.host.astlpc);
281 	assert(ctx.count == 1);
282 
283 	network_destroy(&ctx);
284 }
285 
astlpc_test_simple_message_host_to_bmc(void)286 static void astlpc_test_simple_message_host_to_bmc(void)
287 {
288 	struct astlpc_test ctx = { 0 };
289 	uint8_t msg[MCTP_BTU];
290 	uint8_t tag = 0;
291 	int rc;
292 
293 	/* Test harness initialisation */
294 
295 	network_init(&ctx);
296 
297 	memset(&msg[0], 0xa5, MCTP_BTU);
298 
299 	ctx.msg = &msg[0];
300 	ctx.count = 0;
301 	mctp_set_rx_all(ctx.bmc.mctp, astlpc_test_rx_message, &ctx);
302 
303 	/* Host sends the single-packet message */
304 	rc = mctp_message_tx(ctx.host.mctp, 8, MCTP_MESSAGE_TO_DST, tag, msg,
305 			     sizeof(msg));
306 	assert(rc == 0);
307 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF);
308 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01);
309 
310 	astlpc_assert_tx_packet(&ctx.host, &msg[0], MCTP_BTU);
311 
312 	/* BMC receives the single-packet message */
313 	mctp_astlpc_poll(ctx.bmc.astlpc);
314 	assert(ctx.count == 1);
315 
316 	/* BMC returns Tx area ownership to Host */
317 	assert(!(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF));
318 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x02);
319 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF);
320 
321 	/* Host dequeues ownership hand-over and sends the queued packet */
322 	rc = mctp_astlpc_poll(ctx.host.astlpc);
323 	assert(rc == 0);
324 
325 	network_destroy(&ctx);
326 }
327 
astlpc_test_simple_message_bmc_to_host(void)328 static void astlpc_test_simple_message_bmc_to_host(void)
329 {
330 	struct astlpc_test ctx = { 0 };
331 	uint8_t msg[MCTP_BTU];
332 	uint8_t tag = 0;
333 	int rc;
334 
335 	/* Test harness initialisation */
336 
337 	network_init(&ctx);
338 
339 	memset(&msg[0], 0x5a, MCTP_BTU);
340 
341 	ctx.msg = &msg[0];
342 	ctx.count = 0;
343 	mctp_set_rx_all(ctx.host.mctp, astlpc_test_rx_message, &ctx);
344 
345 	/* BMC sends the single-packet message */
346 	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_SRC, tag, msg,
347 			     sizeof(msg));
348 	assert(rc == 0);
349 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF);
350 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01);
351 
352 	astlpc_assert_tx_packet(&ctx.bmc, &msg[0], MCTP_BTU);
353 
354 	/* Host receives the single-packet message */
355 	mctp_astlpc_poll(ctx.host.astlpc);
356 	assert(ctx.count == 1);
357 
358 	/* Host returns Rx area ownership to BMC */
359 	assert(!(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF));
360 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x02);
361 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF);
362 
363 	/* BMC dequeues ownership hand-over and sends the queued packet */
364 	rc = mctp_astlpc_poll(ctx.bmc.astlpc);
365 	assert(rc == 0);
366 
367 	network_destroy(&ctx);
368 }
369 
astlpc_test_host_before_bmc(void)370 static void astlpc_test_host_before_bmc(void)
371 {
372 	struct mctp_binding_astlpc_mmio mmio = { 0 };
373 	struct mctp_binding_astlpc *astlpc;
374 	uint8_t kcs[2] = { 0 };
375 	struct mctp *mctp;
376 	int rc;
377 
378 	mctp = mctp_init();
379 	assert(mctp);
380 
381 	/* Inject KCS registers */
382 	mmio.kcs = &kcs;
383 
384 	/* Initialise the binding */
385 	astlpc = mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU, NULL,
386 				  &astlpc_direct_mmio_ops, &mmio);
387 
388 	/* Register the binding to trigger the start-up sequence */
389 	rc = mctp_register_bus(mctp, &astlpc->binding, 8);
390 
391 	/* Start-up should fail as we haven't initialised the BMC */
392 	assert(rc < 0);
393 
394 	mctp_astlpc_destroy(astlpc);
395 	mctp_destroy(mctp);
396 }
397 
astlpc_test_bad_version(void)398 static void astlpc_test_bad_version(void)
399 {
400 	assert(0 ==
401 	       mctp_astlpc_negotiate_version(ASTLPC_VER_BAD, ASTLPC_VER_CUR,
402 					     ASTLPC_VER_MIN, ASTLPC_VER_CUR));
403 	assert(0 ==
404 	       mctp_astlpc_negotiate_version(ASTLPC_VER_MIN, ASTLPC_VER_BAD,
405 					     ASTLPC_VER_MIN, ASTLPC_VER_CUR));
406 	assert(0 ==
407 	       mctp_astlpc_negotiate_version(ASTLPC_VER_MIN, ASTLPC_VER_CUR,
408 					     ASTLPC_VER_BAD, ASTLPC_VER_CUR));
409 	assert(0 ==
410 	       mctp_astlpc_negotiate_version(ASTLPC_VER_MIN, ASTLPC_VER_CUR,
411 					     ASTLPC_VER_MIN, ASTLPC_VER_BAD));
412 	assert(0 == mctp_astlpc_negotiate_version(
413 			    ASTLPC_VER_CUR + 1, ASTLPC_VER_CUR, ASTLPC_VER_MIN,
414 			    ASTLPC_VER_CUR + 1));
415 	assert(0 == mctp_astlpc_negotiate_version(
416 			    ASTLPC_VER_MIN, ASTLPC_VER_CUR + 1,
417 			    ASTLPC_VER_CUR + 1, ASTLPC_VER_CUR));
418 }
419 
astlpc_test_incompatible_versions(void)420 static void astlpc_test_incompatible_versions(void)
421 {
422 	assert(0 == mctp_astlpc_negotiate_version(
423 			    ASTLPC_VER_CUR, ASTLPC_VER_CUR, ASTLPC_VER_CUR + 1,
424 			    ASTLPC_VER_CUR + 1));
425 	assert(0 == mctp_astlpc_negotiate_version(
426 			    ASTLPC_VER_CUR + 1, ASTLPC_VER_CUR + 1,
427 			    ASTLPC_VER_CUR, ASTLPC_VER_CUR));
428 }
429 
astlpc_test_choose_bmc_ver_cur(void)430 static void astlpc_test_choose_bmc_ver_cur(void)
431 {
432 	assert(2 == mctp_astlpc_negotiate_version(1, 2, 2, 3));
433 }
434 
astlpc_test_choose_host_ver_cur(void)435 static void astlpc_test_choose_host_ver_cur(void)
436 {
437 	assert(2 == mctp_astlpc_negotiate_version(2, 3, 1, 2));
438 }
439 
astlpc_test_version_host_fails_negotiation(void)440 static void astlpc_test_version_host_fails_negotiation(void)
441 {
442 	struct astlpc_endpoint bmc, host;
443 	struct mctp_lpcmap_hdr *hdr;
444 	uint8_t kcs[2] = { 0 };
445 	void *lpc_mem;
446 	int rc;
447 
448 	/* Test harness initialisation */
449 	lpc_mem = calloc(1, 1 * 1024 * 1024);
450 	assert(lpc_mem);
451 
452 	/* BMC initialisation */
453 	rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU,
454 			   &kcs, lpc_mem);
455 	assert(!rc);
456 
457 	/* Now the BMC is initialised, break its version announcement */
458 	hdr = lpc_mem;
459 	hdr->bmc_ver_cur = ASTLPC_VER_BAD;
460 
461 	/* Host initialisation */
462 	rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU,
463 			   &kcs, lpc_mem);
464 	assert(rc < 0);
465 
466 	endpoint_destroy(&bmc);
467 	endpoint_destroy(&host);
468 	free(lpc_mem);
469 }
470 
astlpc_test_version_bmc_fails_negotiation(void)471 static void astlpc_test_version_bmc_fails_negotiation(void)
472 {
473 	struct astlpc_endpoint bmc, host;
474 	struct mctp_lpcmap_hdr *hdr;
475 	uint8_t kcs[2] = { 0 };
476 	void *lpc_mem;
477 	int rc;
478 
479 	/* Test harness initialisation */
480 	lpc_mem = calloc(1, 1 * 1024 * 1024);
481 	assert(lpc_mem);
482 
483 	/* BMC initialisation */
484 	rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU,
485 			   &kcs, lpc_mem);
486 	assert(!rc);
487 
488 	/* Host initialisation */
489 	rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU,
490 			   &kcs, lpc_mem);
491 	assert(!rc);
492 
493 	/* Now the host is initialised, break its version announcement */
494 	hdr = lpc_mem;
495 	hdr->host_ver_cur = ASTLPC_VER_BAD;
496 
497 	/* Poll the BMC to detect the broken host version */
498 	mctp_astlpc_poll(bmc.astlpc);
499 	assert(!(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_CHANNEL_ACTIVE));
500 
501 	/* Poll the host so it detects failed negotiation */
502 	rc = mctp_astlpc_poll(host.astlpc);
503 	assert(rc < 0);
504 
505 	endpoint_destroy(&bmc);
506 	endpoint_destroy(&host);
507 	free(lpc_mem);
508 }
509 
astlpc_test_simple_init(void)510 static void astlpc_test_simple_init(void)
511 {
512 	struct astlpc_endpoint bmc, host;
513 	uint8_t kcs[2] = { 0 };
514 	void *lpc_mem;
515 	int rc;
516 
517 	/* Test harness initialisation */
518 	lpc_mem = calloc(1, 1 * 1024 * 1024);
519 	assert(lpc_mem);
520 
521 	/* BMC initialisation */
522 	rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU,
523 			   &kcs, lpc_mem);
524 	assert(!rc);
525 
526 	/* Verify the BMC binding was initialised */
527 	assert(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_BMC_READY);
528 
529 	/* Host initialisation */
530 	rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU,
531 			   &kcs, lpc_mem);
532 	assert(!rc);
533 
534 	/* Host sends channel init command */
535 	assert(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF);
536 	assert(kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x00);
537 
538 	/* BMC receives host channel init request */
539 	mctp_astlpc_poll(bmc.astlpc);
540 
541 	/* BMC sends init response */
542 	assert(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF);
543 	assert(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_CHANNEL_ACTIVE);
544 	assert(kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0xff);
545 
546 	/* Host dequeues data */
547 	mctp_astlpc_poll(host.astlpc);
548 
549 	endpoint_destroy(&bmc);
550 	endpoint_destroy(&host);
551 	free(lpc_mem);
552 }
553 
astlpc_test_simple_indirect_message_bmc_to_host(void)554 static void astlpc_test_simple_indirect_message_bmc_to_host(void)
555 {
556 	struct astlpc_test ctx = { 0 };
557 	uint8_t kcs[2] = { 0 };
558 	uint8_t msg[MCTP_BTU];
559 	uint8_t tag = 0;
560 	int rc;
561 
562 	ctx.lpc_mem = calloc(1, LPC_WIN_SIZE);
563 	assert(ctx.lpc_mem);
564 
565 	/* Test message data */
566 	memset(&msg[0], 0x5a, MCTP_BTU);
567 
568 	/* Manually set up the network so we can inject the indirect ops */
569 
570 	/* BMC initialisation */
571 	ctx.bmc.mmio.bmc = true;
572 	ctx.bmc.mctp = mctp_init();
573 	assert(ctx.bmc.mctp);
574 	ctx.bmc.mmio.kcs = &kcs;
575 	ctx.bmc.mmio.lpc = ctx.lpc_mem;
576 	ctx.bmc.mmio.lpc_size = LPC_WIN_SIZE;
577 	ctx.bmc.astlpc =
578 		mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, NULL,
579 				 &astlpc_indirect_mmio_ops, &ctx.bmc.mmio);
580 	mctp_register_bus(ctx.bmc.mctp, &ctx.bmc.astlpc->binding, 8);
581 
582 	/* Host initialisation */
583 	ctx.host.mmio.bmc = false;
584 	ctx.host.mctp = mctp_init();
585 	assert(ctx.host.mctp);
586 	ctx.host.mmio.kcs = &kcs;
587 	ctx.host.mmio.lpc = ctx.lpc_mem;
588 	ctx.host.mmio.lpc_size = LPC_WIN_SIZE;
589 	ctx.host.astlpc =
590 		mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU, NULL,
591 				 &astlpc_indirect_mmio_ops, &ctx.host.mmio);
592 	mctp_register_bus(ctx.host.mctp, &ctx.host.astlpc->binding, 9);
593 
594 	/* BMC processes host channel init request, alerts host */
595 	mctp_astlpc_poll(ctx.bmc.astlpc);
596 
597 	/* Host dequeues channel init result */
598 	mctp_astlpc_poll(ctx.host.astlpc);
599 
600 	ctx.msg = &msg[0];
601 	ctx.count = 0;
602 	mctp_set_rx_all(ctx.host.mctp, astlpc_test_rx_message, &ctx);
603 
604 	/* BMC sends the single-packet message */
605 	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_SRC, tag, msg,
606 			     sizeof(msg));
607 	assert(rc == 0);
608 
609 	/* Host receives the single-packet message */
610 	rc = mctp_astlpc_poll(ctx.host.astlpc);
611 	assert(rc == 0);
612 	assert(ctx.count == 1);
613 
614 	/* BMC dequeues ownership hand-over and sends the queued packet */
615 	rc = mctp_astlpc_poll(ctx.bmc.astlpc);
616 	assert(rc == 0);
617 
618 	/* Can still tear-down the network in the normal fashion */
619 	network_destroy(&ctx);
620 }
621 
astlpc_test_host_tx_bmc_gone(void)622 static void astlpc_test_host_tx_bmc_gone(void)
623 {
624 	struct astlpc_test ctx = { 0 };
625 	uint8_t unwritten[MCTP_BTU];
626 	uint8_t msg[MCTP_BTU];
627 	uint8_t tag = 0;
628 	int rc;
629 
630 	/* Test harness initialisation */
631 
632 	network_init(&ctx);
633 
634 	memset(&msg[0], 0x5a, sizeof(msg));
635 	memset(&unwritten[0], 0, sizeof(unwritten));
636 
637 	ctx.msg = &msg[0];
638 	ctx.count = 0;
639 
640 	/* Clear bmc-ready */
641 	endpoint_destroy(&ctx.bmc);
642 
643 	/* Host detects that the BMC is disabled */
644 	mctp_astlpc_poll(ctx.host.astlpc);
645 
646 	/* Host attempts to send the single-packet message, but is prevented */
647 	rc = mctp_message_tx(ctx.host.mctp, 8, MCTP_MESSAGE_TO_DST, tag, msg,
648 			     sizeof(msg));
649 	assert(rc == 0);
650 	assert(!(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF));
651 	astlpc_assert_tx_packet(&ctx.host, &unwritten[0], MCTP_BTU);
652 
653 	/* BMC comes back */
654 	rc = endpoint_init(&ctx.bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU,
655 			   &ctx.kcs, ctx.lpc_mem);
656 	assert(!rc);
657 	mctp_set_rx_all(ctx.bmc.mctp, astlpc_test_rx_message, &ctx);
658 
659 	/* Host triggers channel init */
660 	mctp_astlpc_poll(ctx.host.astlpc);
661 
662 	/* BMC handles channel init */
663 	mctp_astlpc_poll(ctx.bmc.astlpc);
664 
665 	/* Host completes channel init, flushing the Tx queue */
666 	mctp_astlpc_poll(ctx.host.astlpc);
667 
668 	/* BMC receives the single-packet message */
669 	mctp_astlpc_poll(ctx.bmc.astlpc);
670 	assert(ctx.count == 1);
671 
672 	network_destroy(&ctx);
673 }
674 
astlpc_test_poll_not_ready(void)675 static void astlpc_test_poll_not_ready(void)
676 {
677 	struct astlpc_endpoint bmc;
678 	uint8_t kcs[2] = { 0 };
679 	void *lpc_mem;
680 	int rc;
681 
682 	/* Test harness initialisation */
683 	lpc_mem = calloc(1, 1 * 1024 * 1024);
684 	assert(lpc_mem);
685 
686 	/* BMC initialisation */
687 	rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU,
688 			   &kcs, lpc_mem);
689 	assert(!rc);
690 
691 	/* Check for a command despite none present */
692 	rc = mctp_astlpc_poll(bmc.astlpc);
693 
694 	/* Make sure it doesn't fail */
695 	assert(rc == 0);
696 
697 	endpoint_destroy(&bmc);
698 	free(lpc_mem);
699 }
700 
astlpc_test_undefined_command(void)701 static void astlpc_test_undefined_command(void)
702 {
703 	struct astlpc_endpoint bmc;
704 	uint8_t kcs[2] = { 0 };
705 	void *lpc_mem;
706 	int rc;
707 
708 	/* Test harness initialisation */
709 	lpc_mem = calloc(1, 1 * 1024 * 1024);
710 	assert(lpc_mem);
711 
712 	/* BMC initialisation */
713 	rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU,
714 			   &kcs, lpc_mem);
715 	assert(!rc);
716 
717 	/* 0x5a isn't legal in v1 or v2 */
718 	kcs[MCTP_ASTLPC_KCS_REG_DATA] = 0x5a;
719 	kcs[MCTP_ASTLPC_KCS_REG_STATUS] |= KCS_STATUS_IBF;
720 
721 	/* Check for a command despite none present */
722 	rc = mctp_astlpc_poll(bmc.astlpc);
723 
724 	/* Make sure it doesn't fail, bad command should be discarded */
725 	assert(rc == 0);
726 
727 	endpoint_destroy(&bmc);
728 	free(lpc_mem);
729 }
730 
731 #define BUFFER_MIN (MCTP_PACKET_SIZE(MCTP_BTU) + 4 + 4)
732 static const struct mctp_binding_astlpc astlpc_layout_ctx = {
733 	.proto = &astlpc_protocol_version[3],
734 };
735 
astlpc_test_buffers_rx_offset_overflow(void)736 static void astlpc_test_buffers_rx_offset_overflow(void)
737 {
738 	struct mctp_astlpc_layout l = {
739 		.rx = { UINT32_MAX, BUFFER_MIN },
740 		.tx = { control_size, BUFFER_MIN },
741 	};
742 
743 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
744 }
745 
astlpc_test_buffers_tx_offset_overflow(void)746 static void astlpc_test_buffers_tx_offset_overflow(void)
747 {
748 	struct mctp_astlpc_layout l = {
749 		.rx = { control_size, BUFFER_MIN },
750 		.tx = { UINT32_MAX, BUFFER_MIN },
751 	};
752 
753 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
754 }
755 
astlpc_test_buffers_rx_size_overflow(void)756 static void astlpc_test_buffers_rx_size_overflow(void)
757 {
758 	struct mctp_astlpc_layout l = {
759 		.rx = { control_size + BUFFER_MIN, UINT32_MAX },
760 		.tx = { control_size, BUFFER_MIN },
761 	};
762 
763 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
764 }
765 
astlpc_test_buffers_tx_size_overflow(void)766 static void astlpc_test_buffers_tx_size_overflow(void)
767 {
768 	struct mctp_astlpc_layout l = {
769 		.rx = { control_size, BUFFER_MIN },
770 		.tx = { control_size + BUFFER_MIN, UINT32_MAX },
771 	};
772 
773 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
774 }
775 
astlpc_test_buffers_rx_window_violation(void)776 static void astlpc_test_buffers_rx_window_violation(void)
777 {
778 	struct mctp_astlpc_layout l = {
779 		.rx = { LPC_WIN_SIZE - BUFFER_MIN + 1, BUFFER_MIN },
780 		.tx = { control_size, BUFFER_MIN },
781 	};
782 
783 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
784 }
785 
astlpc_test_buffers_tx_window_violation(void)786 static void astlpc_test_buffers_tx_window_violation(void)
787 {
788 	struct mctp_astlpc_layout l = {
789 		.rx = { control_size, BUFFER_MIN },
790 		.tx = { LPC_WIN_SIZE - BUFFER_MIN + 1, BUFFER_MIN },
791 	};
792 
793 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
794 }
795 
astlpc_test_buffers_rx_size_fails_btu(void)796 static void astlpc_test_buffers_rx_size_fails_btu(void)
797 {
798 	struct mctp_astlpc_layout l = {
799 		.rx = { control_size, BUFFER_MIN - 1 },
800 		.tx = { control_size + BUFFER_MIN, BUFFER_MIN },
801 	};
802 
803 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
804 }
805 
astlpc_test_buffers_tx_size_fails_btu(void)806 static void astlpc_test_buffers_tx_size_fails_btu(void)
807 {
808 	struct mctp_astlpc_layout l = {
809 		.rx = { control_size, BUFFER_MIN },
810 		.tx = { control_size + BUFFER_MIN, BUFFER_MIN - 1 },
811 	};
812 
813 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
814 }
815 
astlpc_test_buffers_overlap_rx_low(void)816 static void astlpc_test_buffers_overlap_rx_low(void)
817 {
818 	struct mctp_astlpc_layout l = {
819 		.rx = { control_size, 2 * BUFFER_MIN },
820 		.tx = { control_size + BUFFER_MIN, 2 * BUFFER_MIN },
821 	};
822 
823 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
824 }
825 
astlpc_test_buffers_overlap_tx_low(void)826 static void astlpc_test_buffers_overlap_tx_low(void)
827 {
828 	struct mctp_astlpc_layout l = {
829 		.rx = { control_size + BUFFER_MIN, 2 * BUFFER_MIN },
830 		.tx = { control_size, 2 * BUFFER_MIN },
831 	};
832 
833 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
834 }
835 
astlpc_test_buffers_overlap_exact(void)836 static void astlpc_test_buffers_overlap_exact(void)
837 {
838 	struct mctp_astlpc_layout l = {
839 		.rx = { control_size, 2 * BUFFER_MIN },
840 		.tx = { control_size, 2 * BUFFER_MIN },
841 	};
842 
843 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
844 }
845 
astlpc_test_buffers_overlap_control(void)846 static void astlpc_test_buffers_overlap_control(void)
847 {
848 	struct mctp_astlpc_layout l = {
849 		.rx = { 0, BUFFER_MIN },
850 		.tx = { control_size + BUFFER_MIN, BUFFER_MIN },
851 	};
852 
853 	assert(!mctp_astlpc_layout_validate(&astlpc_layout_ctx, &l));
854 }
855 
astlpc_test_buffers_bad_host_proposal(void)856 static void astlpc_test_buffers_bad_host_proposal(void)
857 {
858 	struct astlpc_endpoint bmc, host;
859 	struct mctp_lpcmap_hdr *hdr;
860 	uint8_t kcs[2] = { 0 };
861 	void *lpc_mem;
862 	int rc;
863 
864 	/* Test harness initialisation */
865 	lpc_mem = calloc(1, 1 * 1024 * 1024);
866 	assert(lpc_mem);
867 
868 	/* BMC initialisation */
869 	rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU,
870 			   &kcs, lpc_mem);
871 	assert(!rc);
872 
873 	/* Host initialisation */
874 	rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU,
875 			   &kcs, lpc_mem);
876 	assert(!rc);
877 
878 	/*
879 	 * Now that the host has initialised the control area, break
880 	 * something before polling the BMC
881 	 */
882 	hdr = lpc_mem;
883 	hdr->layout.rx_size = 0;
884 
885 	mctp_astlpc_poll(bmc.astlpc);
886 
887 	/* Make sure the BMC has not set the channel to active */
888 	assert(!(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_CHANNEL_ACTIVE));
889 
890 	endpoint_destroy(&host);
891 	endpoint_destroy(&bmc);
892 	free(lpc_mem);
893 }
894 
astlpc_test_buffers_bad_bmc_proposal(void)895 static void astlpc_test_buffers_bad_bmc_proposal(void)
896 {
897 	struct astlpc_endpoint bmc, host;
898 	struct mctp_lpcmap_hdr *hdr;
899 	uint8_t kcs[2] = { 0 };
900 	void *lpc_mem;
901 	int rc;
902 
903 	/* Test harness initialisation */
904 	lpc_mem = calloc(1, 1 * 1024 * 1024);
905 	assert(lpc_mem);
906 
907 	/* BMC initialisation */
908 	rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU,
909 			   &kcs, lpc_mem);
910 	assert(!rc);
911 
912 	/*
913 	 * Now that the BMC has initialised the control area, break something
914 	 * before initialising the host
915 	 */
916 	hdr = lpc_mem;
917 	hdr->layout.rx_size = 0;
918 
919 	/* Host initialisation: Fails due to bad layout */
920 	rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU,
921 			   &kcs, lpc_mem);
922 	assert(rc < 0);
923 
924 	endpoint_destroy(&host);
925 	endpoint_destroy(&bmc);
926 	free(lpc_mem);
927 }
928 
astlpc_test_buffers_bad_bmc_negotiation(void)929 static void astlpc_test_buffers_bad_bmc_negotiation(void)
930 {
931 	struct astlpc_endpoint bmc, host;
932 	struct mctp_lpcmap_hdr *hdr;
933 	uint8_t kcs[2] = { 0 };
934 	void *lpc_mem;
935 	int rc;
936 
937 	/* Test harness initialisation */
938 	lpc_mem = calloc(1, 1 * 1024 * 1024);
939 	assert(lpc_mem);
940 
941 	/* BMC initialisation */
942 	rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU,
943 			   &kcs, lpc_mem);
944 	assert(!rc);
945 
946 	/* Host initialisation */
947 	rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU,
948 			   &kcs, lpc_mem);
949 	assert(!rc);
950 
951 	mctp_astlpc_poll(bmc.astlpc);
952 
953 	/*
954 	 * Now that the BMC has initialised the control area, break something
955 	 * before polling the host
956 	 */
957 	hdr = lpc_mem;
958 	hdr->layout.rx_size = 0;
959 
960 	rc = mctp_astlpc_poll(host.astlpc);
961 	assert(rc < 0);
962 
963 	endpoint_destroy(&host);
964 	endpoint_destroy(&bmc);
965 	free(lpc_mem);
966 }
967 
astlpc_test_buffers_bad_host_init(void)968 static void astlpc_test_buffers_bad_host_init(void)
969 {
970 	struct astlpc_endpoint host;
971 	uint8_t kcs[2] = { 0 };
972 	void *lpc_mem;
973 	int rc;
974 
975 	/* Test harness initialisation */
976 	lpc_mem = calloc(1, 1 * 1024 * 1024);
977 	assert(lpc_mem);
978 
979 	host.mctp = mctp_init();
980 	assert(host.mctp);
981 	host.mmio.kcs = &kcs;
982 	host.mmio.bmc = false;
983 
984 	/* Set the MTU to 0 to provoke a failure */
985 	host.astlpc = mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_HOST, 0,
986 				       lpc_mem, &astlpc_direct_mmio_ops,
987 				       &host.mmio);
988 
989 	rc = mctp_register_bus(host.mctp, &host.astlpc->binding, 8);
990 	assert(rc < 0);
991 
992 	mctp_astlpc_destroy(host.astlpc);
993 	mctp_destroy(host.mctp);
994 	free(lpc_mem);
995 }
996 
astlpc_test_negotiate_increased_mtu(void)997 static void astlpc_test_negotiate_increased_mtu(void)
998 {
999 	struct astlpc_endpoint bmc, host;
1000 	uint8_t kcs[2] = { 0 };
1001 	void *lpc_mem;
1002 	int rc;
1003 
1004 	/* Test harness initialisation */
1005 	lpc_mem = calloc(1, 1 * 1024 * 1024);
1006 	assert(lpc_mem);
1007 
1008 	/* BMC initialisation */
1009 	rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, 3 * MCTP_BTU,
1010 			   &kcs, lpc_mem);
1011 	assert(!rc);
1012 
1013 	/* Host initialisation */
1014 	rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST,
1015 			   2 * MCTP_BTU, &kcs, lpc_mem);
1016 	assert(!rc);
1017 
1018 	rc = mctp_astlpc_poll(bmc.astlpc);
1019 	assert(rc == 0);
1020 
1021 	rc = mctp_astlpc_poll(host.astlpc);
1022 	assert(rc == 0);
1023 
1024 	endpoint_destroy(&host);
1025 	endpoint_destroy(&bmc);
1026 	free(lpc_mem);
1027 }
1028 
astlpc_test_negotiate_mtu_low_high(void)1029 static void astlpc_test_negotiate_mtu_low_high(void)
1030 {
1031 	struct astlpc_endpoint bmc, host;
1032 	uint8_t kcs[2] = { 0 };
1033 	uint32_t bmtu, hmtu;
1034 	void *lpc_mem;
1035 	int rc;
1036 
1037 	/* Test harness initialisation */
1038 	lpc_mem = calloc(1, 1 * 1024 * 1024);
1039 	assert(lpc_mem);
1040 
1041 	/* BMC initialisation */
1042 	bmtu = 3 * MCTP_BTU;
1043 	rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, bmtu, &kcs,
1044 			   lpc_mem);
1045 	assert(!rc);
1046 
1047 	/* Host initialisation with low MTU */
1048 	hmtu = 2 * MCTP_BTU;
1049 	rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, hmtu, &kcs,
1050 			   lpc_mem);
1051 	assert(!rc);
1052 
1053 	/* Process low MTU proposal */
1054 	rc = mctp_astlpc_poll(bmc.astlpc);
1055 	assert(rc == 0);
1056 
1057 	/* Accept low MTU proposal */
1058 	rc = mctp_astlpc_poll(host.astlpc);
1059 	assert(rc == 0);
1060 
1061 	assert(host.astlpc->layout.rx.size ==
1062 	       astlpc_layout_ctx.proto->packet_size(MCTP_PACKET_SIZE(hmtu)));
1063 
1064 	/* Tear-down the host so we can bring up a new one */
1065 	endpoint_destroy(&host);
1066 
1067 	/*
1068 	 * Bring up a new host endpoint with a higher MTU than we previously
1069 	 * negotiated
1070 	 */
1071 	hmtu = 3 * MCTP_BTU;
1072 	rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, hmtu, &kcs,
1073 			   lpc_mem);
1074 	assert(!rc);
1075 
1076 	/* Process high MTU proposal */
1077 	rc = mctp_astlpc_poll(bmc.astlpc);
1078 	assert(rc == 0);
1079 
1080 	/* Accept high MTU proposal */
1081 	rc = mctp_astlpc_poll(host.astlpc);
1082 	assert(rc == 0);
1083 
1084 	assert(host.astlpc->layout.rx.size ==
1085 	       astlpc_layout_ctx.proto->packet_size(MCTP_PACKET_SIZE(bmtu)));
1086 
1087 	endpoint_destroy(&host);
1088 	endpoint_destroy(&bmc);
1089 	free(lpc_mem);
1090 }
1091 
astlpc_test_send_large_packet(void)1092 static void astlpc_test_send_large_packet(void)
1093 {
1094 	struct astlpc_endpoint *bmc, *host;
1095 	struct astlpc_test ctx;
1096 	uint8_t kcs[2] = { 0 };
1097 	uint8_t tag = 0;
1098 	void *lpc_mem;
1099 	int rc;
1100 
1101 	host = &ctx.host;
1102 	bmc = &ctx.bmc;
1103 
1104 	/* Test harness initialisation */
1105 	lpc_mem = calloc(1, 1 * 1024 * 1024);
1106 	assert(lpc_mem);
1107 
1108 	/* BMC initialisation */
1109 	rc = endpoint_init(bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, 8192, &kcs,
1110 			   lpc_mem);
1111 	assert(!rc);
1112 
1113 	/* Host initialisation */
1114 	rc = endpoint_init(host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, 8192, &kcs,
1115 			   lpc_mem);
1116 	assert(!rc);
1117 
1118 	ctx.count = 0;
1119 	mctp_set_rx_all(bmc->mctp, astlpc_test_rx_message, &ctx);
1120 
1121 	rc = mctp_astlpc_poll(bmc->astlpc);
1122 	assert(rc == 0);
1123 
1124 	rc = mctp_astlpc_poll(host->astlpc);
1125 	assert(rc == 0);
1126 
1127 	ctx.msg = malloc(2 * MCTP_BODY_SIZE(8192));
1128 	assert(ctx.msg);
1129 
1130 	memset(ctx.msg, 0x5a, 2 * MCTP_BODY_SIZE(8192));
1131 
1132 	rc = mctp_message_tx(host->mctp, 8, MCTP_MESSAGE_TO_DST, tag, ctx.msg,
1133 			     2 * MCTP_BODY_SIZE(8192));
1134 	assert(rc == 0);
1135 	rc = mctp_astlpc_poll(bmc->astlpc);
1136 	assert(rc == 0);
1137 	rc = mctp_astlpc_poll(host->astlpc);
1138 	assert(rc == 0);
1139 	rc = mctp_astlpc_poll(bmc->astlpc);
1140 	assert(rc == 0);
1141 	rc = mctp_astlpc_poll(host->astlpc);
1142 	assert(rc == 0);
1143 
1144 	assert(ctx.count == 1);
1145 
1146 	free(ctx.msg);
1147 	endpoint_destroy(host);
1148 	endpoint_destroy(bmc);
1149 	free(lpc_mem);
1150 }
1151 
astlpc_test_negotiate_mtu_high_low(void)1152 static void astlpc_test_negotiate_mtu_high_low(void)
1153 {
1154 	uint8_t msg[3 * MCTP_BTU] = { 0 };
1155 	struct astlpc_test ctx = { 0 };
1156 	uint32_t bmtu, hmtu;
1157 	uint8_t tag = 0;
1158 	int rc;
1159 
1160 	/* Configure message */
1161 	memset(&msg[0], 0xa5, sizeof(msg));
1162 
1163 	/* Test harness initialisation */
1164 	ctx.lpc_mem = calloc(1, 1 * 1024 * 1024);
1165 	assert(ctx.lpc_mem);
1166 
1167 	/* BMC initialisation */
1168 	bmtu = 3 * MCTP_BTU;
1169 	rc = endpoint_init(&ctx.bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, bmtu,
1170 			   &ctx.kcs, ctx.lpc_mem);
1171 	assert(!rc);
1172 
1173 	/* Host initialisation with low MTU */
1174 	hmtu = 3 * MCTP_BTU;
1175 	rc = endpoint_init(&ctx.host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, hmtu,
1176 			   &ctx.kcs, ctx.lpc_mem);
1177 	assert(!rc);
1178 
1179 	/* Configure host message handler */
1180 	ctx.msg = &msg[0];
1181 	ctx.count = 0;
1182 	mctp_set_rx_all(ctx.host.mctp, astlpc_test_rx_message, &ctx);
1183 
1184 	/* Startup BMC and host interfaces */
1185 	rc = mctp_astlpc_poll(ctx.bmc.astlpc);
1186 	assert(rc == 0);
1187 	rc = mctp_astlpc_poll(ctx.host.astlpc);
1188 	assert(rc == 0);
1189 
1190 	/*
1191 	 * Transmit a message to place a packet on the interface. This releases the buffer and
1192 	 * disables the binding, plugging the binding's transmit queue while the host hasn't polled
1193 	 * to pull the packet off.
1194 	 */
1195 	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_DST, tag, msg,
1196 			     sizeof(msg));
1197 
1198 	/* Leave the packet in place on the interface by not polling the host binding */
1199 
1200 	/*
1201 	 * Transmit another message to force packetisation at the current MTU while the binding is
1202 	 * disabled, leaving the packet(s) in the binding's transmit queue
1203 	 */
1204 	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_DST, tag, msg,
1205 			     sizeof(msg));
1206 
1207 	/* Tear-down the host so we can bring up a new one */
1208 	endpoint_destroy(&ctx.host);
1209 
1210 	/* Bring up a new host endpoint with a lower MTU than we previously negotiated */
1211 	hmtu = 2 * MCTP_BTU;
1212 	rc = endpoint_init(&ctx.host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, hmtu,
1213 			   &ctx.kcs, ctx.lpc_mem);
1214 	assert(!rc);
1215 
1216 	/* Configure host message handler again after reinitialisation */
1217 	ctx.msg = &msg[0];
1218 	ctx.count = 0;
1219 	mctp_set_rx_all(ctx.host.mctp, astlpc_test_rx_message, &ctx);
1220 
1221 	/* Process low MTU proposal */
1222 	rc = mctp_astlpc_poll(ctx.bmc.astlpc);
1223 	assert(rc == 0);
1224 
1225 	/* Accept low MTU proposal */
1226 	rc = mctp_astlpc_poll(ctx.host.astlpc);
1227 	assert(rc == 0);
1228 
1229 	/*
1230 	 * Check that there are no outstanding messages to be received by the host. The message
1231 	 * packetised on the BMC at the larger MTU must be dropped as its now no longer possible to
1232 	 * transmit those packets
1233 	 */
1234 	rc = mctp_astlpc_poll(ctx.host.astlpc);
1235 	assert(rc == 0);
1236 	assert(ctx.count == 0);
1237 
1238 	/* Transmit another message from the BMC to the host, packetised using the new MTU */
1239 	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_DST, tag, msg,
1240 			     hmtu);
1241 
1242 	/* Check that the most recent BMC transmission is received by the host */
1243 	rc = mctp_astlpc_poll(ctx.host.astlpc);
1244 	assert(rc == 0);
1245 	assert(ctx.count == 1);
1246 
1247 	/* Ensure buffer ownership is returned to the BMC and the BMC Tx queue is processed */
1248 	rc = mctp_astlpc_poll(ctx.bmc.astlpc);
1249 	assert(rc == 0);
1250 
1251 	/* Check that no further messages are propagated to the host */
1252 	rc = mctp_astlpc_poll(ctx.host.astlpc);
1253 	assert(rc == 0);
1254 	assert(ctx.count == 1);
1255 
1256 	endpoint_destroy(&ctx.host);
1257 	endpoint_destroy(&ctx.bmc);
1258 	free(ctx.lpc_mem);
1259 }
1260 
astlpc_test_tx_before_channel_init(void)1261 static void astlpc_test_tx_before_channel_init(void)
1262 {
1263 	struct astlpc_endpoint *bmc;
1264 	struct astlpc_test ctx;
1265 	uint8_t kcs[2] = { 0 };
1266 	uint8_t msg[MCTP_BTU];
1267 	uint8_t tag = 0;
1268 	void *lpc_mem;
1269 	int rc;
1270 
1271 	bmc = &ctx.bmc;
1272 
1273 	/* Test harness initialisation */
1274 	lpc_mem = calloc(1, 1 * 1024 * 1024);
1275 	assert(lpc_mem);
1276 
1277 	/* BMC initialisation */
1278 	rc = endpoint_init(bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, 0, &kcs,
1279 			   lpc_mem);
1280 	assert(!rc);
1281 
1282 	memset(msg, '\0', sizeof(msg));
1283 
1284 	/*
1285 	 * There was once a bug where the calculated MTU was 0 and the
1286 	 * packetisation loop in mctp_message_tx_on_bus() allocated all the
1287 	 * memory. Catch the bug and avoid OOMing the test machine by
1288 	 * terminating after a period long enough to packetise the message.
1289 	 */
1290 	alarm(1);
1291 	mctp_message_tx(bmc->mctp, 9, MCTP_MESSAGE_TO_SRC, tag, msg,
1292 			sizeof(msg));
1293 	alarm(0);
1294 
1295 	endpoint_destroy(bmc);
1296 	free(lpc_mem);
1297 }
1298 
astlpc_test_corrupt_host_tx(void)1299 static void astlpc_test_corrupt_host_tx(void)
1300 {
1301 	struct astlpc_test ctx = { 0 };
1302 	struct mctp_lpcmap_hdr *hdr;
1303 	uint8_t msg[MCTP_BTU];
1304 	uint32_t offset;
1305 	uint8_t tag = 0;
1306 	uint32_t code;
1307 	uint8_t *tlr;
1308 	int rc;
1309 
1310 	/* Test harness initialisation */
1311 
1312 	network_init(&ctx);
1313 
1314 	memset(&msg[0], 0xa5, MCTP_BTU);
1315 
1316 	ctx.msg = &msg[0];
1317 	ctx.count = 0;
1318 	mctp_set_rx_all(ctx.bmc.mctp, astlpc_test_rx_message, &ctx);
1319 
1320 	/* Host sends the single-packet message */
1321 	rc = mctp_message_tx(ctx.host.mctp, 8, MCTP_MESSAGE_TO_DST, tag, msg,
1322 			     sizeof(msg));
1323 	assert(rc == 0);
1324 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF);
1325 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01);
1326 
1327 	astlpc_assert_tx_packet(&ctx.host, &msg[0], MCTP_BTU);
1328 
1329 	/* Corrupt the CRC-32 in the message trailer */
1330 	hdr = (struct mctp_lpcmap_hdr *)ctx.lpc_mem;
1331 	offset = be32toh(hdr->layout.tx_offset);
1332 	tlr = (uint8_t *)&ctx.lpc_mem[offset] + 4 + sizeof(msg);
1333 	memcpy(&code, tlr, sizeof(code));
1334 	code = ~code;
1335 	memcpy(tlr, &code, sizeof(code));
1336 
1337 	/* BMC receives the single-packet message */
1338 	mctp_astlpc_poll(ctx.bmc.astlpc);
1339 	assert(ctx.count == 0);
1340 
1341 	/* BMC returns Tx area ownership to Host */
1342 	assert(!(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF));
1343 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x02);
1344 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF);
1345 
1346 	/* Host dequeues ownership hand-over */
1347 	rc = mctp_astlpc_poll(ctx.host.astlpc);
1348 	assert(rc == 0);
1349 
1350 	network_destroy(&ctx);
1351 }
1352 
astlpc_test_corrupt_bmc_tx(void)1353 static void astlpc_test_corrupt_bmc_tx(void)
1354 {
1355 	struct astlpc_test ctx = { 0 };
1356 	struct mctp_lpcmap_hdr *hdr;
1357 	uint8_t msg[MCTP_BTU];
1358 	uint32_t offset;
1359 	uint8_t tag = 0;
1360 	uint32_t code;
1361 	uint8_t *tlr;
1362 	int rc;
1363 
1364 	/* Test harness initialisation */
1365 
1366 	network_init(&ctx);
1367 
1368 	memset(&msg[0], 0x5a, MCTP_BTU);
1369 
1370 	ctx.msg = &msg[0];
1371 	ctx.count = 0;
1372 	mctp_set_rx_all(ctx.host.mctp, astlpc_test_rx_message, &ctx);
1373 
1374 	/* BMC sends the single-packet message */
1375 	rc = mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_SRC, tag, msg,
1376 			     sizeof(msg));
1377 	assert(rc == 0);
1378 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF);
1379 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01);
1380 
1381 	/* Check that the BMC sent a fully-formed packet */
1382 	astlpc_assert_tx_packet(&ctx.bmc, &msg[0], MCTP_BTU);
1383 
1384 	/* Corrupt the CRC-32 in the message trailer */
1385 	hdr = (struct mctp_lpcmap_hdr *)ctx.lpc_mem;
1386 	offset = be32toh(hdr->layout.rx_offset);
1387 	tlr = (uint8_t *)&ctx.lpc_mem[offset] + 4 + sizeof(msg);
1388 	memcpy(&code, tlr, sizeof(code));
1389 	code = ~code;
1390 	memcpy(tlr, &code, sizeof(code));
1391 
1392 	/* Host drops the single-packet message */
1393 	mctp_astlpc_poll(ctx.host.astlpc);
1394 	assert(ctx.count == 0);
1395 
1396 	/* Host returns Rx area ownership to BMC */
1397 	assert(!(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF));
1398 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x02);
1399 	assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF);
1400 
1401 	/* BMC dequeues ownership hand-over */
1402 	rc = mctp_astlpc_poll(ctx.bmc.astlpc);
1403 	assert(rc == 0);
1404 
1405 	network_destroy(&ctx);
1406 }
1407 
astlpc_test_async_exchange(void)1408 static void astlpc_test_async_exchange(void)
1409 {
1410 	struct astlpc_test ctx = { 0 };
1411 	uint8_t msg[MCTP_BTU];
1412 	struct pollfd pollfd;
1413 	uint8_t tag = 0;
1414 
1415 	network_init(&ctx);
1416 
1417 	memset(&msg[0], 0x5a, MCTP_BTU);
1418 
1419 	/* (1)
1420 	 * Fill the KCS transmit buffer by sending a message from the BMC to the host without
1421 	 * dequeuing it on the host side
1422 	 */
1423 	mctp_message_tx(ctx.bmc.mctp, 9, MCTP_MESSAGE_TO_SRC, tag, msg,
1424 			sizeof(msg));
1425 
1426 	/* (2)
1427 	 * Assert that we're still listening for in-bound messages on the BMC
1428 	 */
1429 	mctp_astlpc_init_pollfd(ctx.bmc.astlpc, &pollfd);
1430 	assert(pollfd.events & POLLIN);
1431 	assert(!(pollfd.events & POLLOUT));
1432 
1433 	/* (3)
1434 	 * Send a message from the host to the BMC and dequeue the message on the BMC, triggering a
1435 	 * buffer ownership transfer command back to the host
1436 	 */
1437 	mctp_message_tx(ctx.host.mctp, 8, MCTP_MESSAGE_TO_SRC, tag, msg,
1438 			sizeof(msg));
1439 	mctp_astlpc_poll(ctx.bmc.astlpc);
1440 
1441 	/* (4)
1442 	 * Assert that the BMC has to wait for the host to dequeue the ownership transfer command
1443 	 * from (1) before further transfers take place.
1444 	 */
1445 	mctp_astlpc_init_pollfd(ctx.bmc.astlpc, &pollfd);
1446 	assert(!(pollfd.events & POLLIN));
1447 	assert(pollfd.events & POLLOUT);
1448 
1449 	/* (5)
1450 	 * Dequeue the message from (1) on the host side, allowing transmisson of the outstanding
1451 	 * ownership transfer command from (3)
1452 	 */
1453 	mctp_astlpc_poll(ctx.host.astlpc);
1454 
1455 	/* (6)
1456 	 * Emulate a POLLOUT event on the BMC side
1457 	 */
1458 	mctp_astlpc_poll(ctx.bmc.astlpc);
1459 
1460 	/* (7)
1461 	 * Assert that we're again listening for in-bound messages on the BMC.
1462 	 */
1463 	mctp_astlpc_init_pollfd(ctx.bmc.astlpc, &pollfd);
1464 	assert(pollfd.events & POLLIN);
1465 	assert(!(pollfd.events & POLLOUT));
1466 
1467 	network_destroy(&ctx);
1468 }
1469 
1470 /* clang-format off */
1471 #define TEST_CASE(test) { #test, test }
1472 static const struct {
1473 	const char *name;
1474 	void (*test)(void);
1475 } astlpc_tests[] = {
1476 	TEST_CASE(astlpc_test_simple_init),
1477 	TEST_CASE(astlpc_test_bad_version),
1478 	TEST_CASE(astlpc_test_incompatible_versions),
1479 	TEST_CASE(astlpc_test_choose_bmc_ver_cur),
1480 	TEST_CASE(astlpc_test_choose_host_ver_cur),
1481 	TEST_CASE(astlpc_test_version_host_fails_negotiation),
1482 	TEST_CASE(astlpc_test_version_bmc_fails_negotiation),
1483 	TEST_CASE(astlpc_test_host_before_bmc),
1484 	TEST_CASE(astlpc_test_simple_message_bmc_to_host),
1485 	TEST_CASE(astlpc_test_simple_message_host_to_bmc),
1486 	TEST_CASE(astlpc_test_packetised_message_bmc_to_host),
1487 	TEST_CASE(astlpc_test_simple_indirect_message_bmc_to_host),
1488 	TEST_CASE(astlpc_test_host_tx_bmc_gone),
1489 	TEST_CASE(astlpc_test_poll_not_ready),
1490 	TEST_CASE(astlpc_test_undefined_command),
1491 	TEST_CASE(astlpc_test_buffers_rx_offset_overflow),
1492 	TEST_CASE(astlpc_test_buffers_tx_offset_overflow),
1493 	TEST_CASE(astlpc_test_buffers_rx_size_overflow),
1494 	TEST_CASE(astlpc_test_buffers_tx_size_overflow),
1495 	TEST_CASE(astlpc_test_buffers_rx_window_violation),
1496 	TEST_CASE(astlpc_test_buffers_tx_window_violation),
1497 	TEST_CASE(astlpc_test_buffers_rx_size_fails_btu),
1498 	TEST_CASE(astlpc_test_buffers_tx_size_fails_btu),
1499 	TEST_CASE(astlpc_test_buffers_overlap_rx_low),
1500 	TEST_CASE(astlpc_test_buffers_overlap_tx_low),
1501 	TEST_CASE(astlpc_test_buffers_bad_host_proposal),
1502 	TEST_CASE(astlpc_test_buffers_bad_bmc_proposal),
1503 	TEST_CASE(astlpc_test_buffers_bad_bmc_negotiation),
1504 	TEST_CASE(astlpc_test_buffers_overlap_exact),
1505 	TEST_CASE(astlpc_test_buffers_overlap_control),
1506 	TEST_CASE(astlpc_test_buffers_bad_host_init),
1507 	TEST_CASE(astlpc_test_negotiate_increased_mtu),
1508 	TEST_CASE(astlpc_test_negotiate_mtu_low_high),
1509 	TEST_CASE(astlpc_test_negotiate_mtu_high_low),
1510 	TEST_CASE(astlpc_test_send_large_packet),
1511 	TEST_CASE(astlpc_test_tx_before_channel_init),
1512 	TEST_CASE(astlpc_test_corrupt_host_tx),
1513 	TEST_CASE(astlpc_test_corrupt_bmc_tx),
1514 	TEST_CASE(astlpc_test_async_exchange),
1515 };
1516 /* clang-format on */
1517 
1518 #ifndef BUILD_ASSERT
1519 #define BUILD_ASSERT(x)                                                        \
1520 	do {                                                                   \
1521 		(void)sizeof(char[0 - (!(x))]);                                \
1522 	} while (0)
1523 #endif
1524 
main(void)1525 int main(void)
1526 {
1527 	size_t i;
1528 
1529 	mctp_set_log_stdio(MCTP_LOG_DEBUG);
1530 
1531 	BUILD_ASSERT(ARRAY_SIZE(astlpc_tests) < SIZE_MAX);
1532 	for (i = 0; i < ARRAY_SIZE(astlpc_tests); i++) {
1533 		mctp_prlog(MCTP_LOG_DEBUG, "begin: %s", astlpc_tests[i].name);
1534 		astlpc_tests[i].test();
1535 		mctp_prlog(MCTP_LOG_DEBUG, "end: %s\n", astlpc_tests[i].name);
1536 	}
1537 
1538 	return 0;
1539 }
1540