xref: /openbmc/libmctp/tests/test_core.c (revision a68185c4)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 
3 #define _GNU_SOURCE
4 
5 #ifdef NDEBUG
6 #undef NDEBUG
7 #endif
8 
9 #if HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12 
13 #include <assert.h>
14 #include <fcntl.h>
15 #include <stdbool.h>
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 
22 #include "compiler.h"
23 #include "libmctp-alloc.h"
24 #include "libmctp-log.h"
25 #include "range.h"
26 #include "test-utils.h"
27 
28 #define TEST_DEST_EID 9
29 #define TEST_SRC_EID  10
30 
31 #ifndef ARRAY_SIZE
32 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
33 #endif
34 
35 #define MAX_PAYLOAD_SIZE 50000
36 
37 struct pktbuf {
38 	struct mctp_hdr hdr;
39 	uint8_t *payload;
40 };
41 
42 struct test_params {
43 	bool seen;
44 	size_t message_size;
45 	uint8_t msg_tag;
46 	bool tag_owner;
47 };
48 
49 static void rx_message(uint8_t eid __unused, bool tag_owner, uint8_t msg_tag,
50 		       void *data, void *msg __unused, size_t len)
51 {
52 	struct test_params *param = (struct test_params *)data;
53 
54 	mctp_prdebug("MCTP message received: len %zd, tag %u", len, msg_tag);
55 
56 	param->seen = true;
57 	param->message_size = len;
58 	param->msg_tag = msg_tag;
59 	param->tag_owner = tag_owner;
60 }
61 
62 static uint8_t get_sequence()
63 {
64 	static uint8_t pkt_seq = 0;
65 
66 	return (pkt_seq++ % 4);
67 }
68 
69 static uint8_t get_tag()
70 {
71 	static uint8_t tag = 0;
72 
73 	return (tag++ % 8);
74 }
75 
76 /*
77  * receive_pktbuf bypasses all bindings and directly invokes mctp_bus_rx.
78  * This is necessary in order invoke test cases on the core functionality.
79  * The memory allocated for the mctp packet is capped at MCTP_BTU
80  * size, however, the mimiced rx pkt still retains the len parameter.
81  * This allows to mimic packets larger than a sane memory allocator can
82  * provide.
83  */
84 static void receive_ptkbuf(struct mctp_binding_test *binding,
85 			   const struct pktbuf *pktbuf, size_t len)
86 {
87 	size_t alloc_size = MIN((size_t)MCTP_BTU, len);
88 	struct mctp_pktbuf *rx_pkt;
89 
90 	rx_pkt = __mctp_alloc(sizeof(*rx_pkt) + MCTP_PACKET_SIZE(alloc_size));
91 	assert(rx_pkt);
92 
93 	/* Preserve passed len parameter */
94 	rx_pkt->size = MCTP_PACKET_SIZE(len);
95 	rx_pkt->start = 0;
96 	rx_pkt->end = MCTP_PACKET_SIZE(len);
97 	rx_pkt->mctp_hdr_off = 0;
98 	rx_pkt->next = NULL;
99 	memcpy(rx_pkt->data, &pktbuf->hdr, sizeof(pktbuf->hdr));
100 	memcpy(rx_pkt->data + sizeof(pktbuf->hdr), pktbuf->payload, alloc_size);
101 
102 	mctp_bus_rx((struct mctp_binding *)binding, rx_pkt);
103 }
104 
105 static void receive_one_fragment(struct mctp_binding_test *binding,
106 				 uint8_t *payload, size_t fragment_size,
107 				 uint8_t flags_seq_tag, struct pktbuf *pktbuf)
108 {
109 	pktbuf->hdr.flags_seq_tag = flags_seq_tag;
110 	pktbuf->payload = payload;
111 	receive_ptkbuf(binding, pktbuf, fragment_size);
112 }
113 
114 static void receive_two_fragment_message(struct mctp_binding_test *binding,
115 					 uint8_t *payload,
116 					 size_t fragment1_size,
117 					 size_t fragment2_size,
118 					 struct pktbuf *pktbuf)
119 {
120 	uint8_t tag = MCTP_HDR_FLAG_TO | get_tag();
121 	uint8_t flags_seq_tag;
122 
123 	flags_seq_tag = MCTP_HDR_FLAG_SOM |
124 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
125 	receive_one_fragment(binding, payload, fragment1_size, flags_seq_tag,
126 			     pktbuf);
127 
128 	flags_seq_tag = MCTP_HDR_FLAG_EOM |
129 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
130 	receive_one_fragment(binding, payload + fragment1_size, fragment2_size,
131 			     flags_seq_tag, pktbuf);
132 }
133 
134 static void mctp_core_test_simple_rx()
135 {
136 	struct mctp *mctp = NULL;
137 	struct mctp_binding_test *binding = NULL;
138 	struct test_params test_param;
139 	uint8_t test_payload[2 * MCTP_BTU];
140 	struct pktbuf pktbuf;
141 
142 	memset(test_payload, 0, sizeof(test_payload));
143 	test_param.seen = false;
144 	test_param.message_size = 0;
145 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
146 	mctp_set_rx_all(mctp, rx_message, &test_param);
147 	memset(&pktbuf, 0, sizeof(pktbuf));
148 	pktbuf.hdr.dest = TEST_DEST_EID;
149 	pktbuf.hdr.src = TEST_SRC_EID;
150 
151 	/* Receive 2 fragments of equal size */
152 	receive_two_fragment_message(binding, test_payload, MCTP_BTU, MCTP_BTU,
153 				     &pktbuf);
154 
155 	assert(test_param.seen);
156 	assert(test_param.message_size == 2 * MCTP_BTU);
157 
158 	mctp_binding_test_destroy(binding);
159 	mctp_destroy(mctp);
160 }
161 
162 static void mctp_core_test_receive_equal_length_fragments()
163 {
164 	struct mctp *mctp = NULL;
165 	struct mctp_binding_test *binding = NULL;
166 	struct test_params test_param;
167 	static uint8_t test_payload[MAX_PAYLOAD_SIZE];
168 	uint8_t tag = MCTP_HDR_FLAG_TO | get_tag();
169 	struct pktbuf pktbuf;
170 	uint8_t flags_seq_tag;
171 
172 	memset(test_payload, 0, sizeof(test_payload));
173 	test_param.seen = false;
174 	test_param.message_size = 0;
175 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
176 	mctp_set_rx_all(mctp, rx_message, &test_param);
177 	memset(&pktbuf, 0, sizeof(pktbuf));
178 	pktbuf.hdr.dest = TEST_DEST_EID;
179 	pktbuf.hdr.src = TEST_SRC_EID;
180 
181 	/* Receive 3 fragments, each of size MCTP_BTU */
182 	flags_seq_tag = MCTP_HDR_FLAG_SOM |
183 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
184 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
185 			     &pktbuf);
186 
187 	flags_seq_tag = (get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
188 	receive_one_fragment(binding, test_payload + MCTP_BTU, MCTP_BTU,
189 			     flags_seq_tag, &pktbuf);
190 
191 	flags_seq_tag = MCTP_HDR_FLAG_EOM |
192 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
193 	receive_one_fragment(binding, test_payload + (2 * MCTP_BTU), MCTP_BTU,
194 			     flags_seq_tag, &pktbuf);
195 
196 	assert(test_param.seen);
197 	assert(test_param.message_size == 3 * MCTP_BTU);
198 
199 	mctp_binding_test_destroy(binding);
200 	mctp_destroy(mctp);
201 }
202 
203 static void mctp_core_test_receive_unexpected_smaller_middle_fragment()
204 {
205 	struct mctp *mctp = NULL;
206 	struct mctp_binding_test *binding = NULL;
207 	struct test_params test_param;
208 	static uint8_t test_payload[MAX_PAYLOAD_SIZE];
209 	uint8_t tag = MCTP_HDR_FLAG_TO | get_tag();
210 	struct pktbuf pktbuf;
211 	uint8_t flags_seq_tag;
212 
213 	memset(test_payload, 0, sizeof(test_payload));
214 	test_param.seen = false;
215 	test_param.message_size = 0;
216 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
217 	mctp_set_rx_all(mctp, rx_message, &test_param);
218 	memset(&pktbuf, 0, sizeof(pktbuf));
219 	pktbuf.hdr.dest = TEST_DEST_EID;
220 	pktbuf.hdr.src = TEST_SRC_EID;
221 
222 	/* Middle fragment with size MCTP_BTU - 1 */
223 	flags_seq_tag = MCTP_HDR_FLAG_SOM |
224 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
225 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
226 			     &pktbuf);
227 
228 	flags_seq_tag = (get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
229 	receive_one_fragment(binding, test_payload + MCTP_BTU, MCTP_BTU - 1,
230 			     flags_seq_tag, &pktbuf);
231 
232 	flags_seq_tag = MCTP_HDR_FLAG_EOM |
233 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
234 	receive_one_fragment(binding, test_payload + (2 * MCTP_BTU), MCTP_BTU,
235 			     flags_seq_tag, &pktbuf);
236 
237 	assert(!test_param.seen);
238 
239 	mctp_binding_test_destroy(binding);
240 	mctp_destroy(mctp);
241 }
242 
243 static void mctp_core_test_receive_unexpected_bigger_middle_fragment()
244 {
245 	struct mctp *mctp = NULL;
246 	struct mctp_binding_test *binding = NULL;
247 	struct test_params test_param;
248 	static uint8_t test_payload[MAX_PAYLOAD_SIZE];
249 	uint8_t tag = MCTP_HDR_FLAG_TO | get_tag();
250 	struct pktbuf pktbuf;
251 	uint8_t flags_seq_tag;
252 
253 	memset(test_payload, 0, sizeof(test_payload));
254 	test_param.seen = false;
255 	test_param.message_size = 0;
256 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
257 	mctp_set_rx_all(mctp, rx_message, &test_param);
258 	memset(&pktbuf, 0, sizeof(pktbuf));
259 	pktbuf.hdr.dest = TEST_DEST_EID;
260 	pktbuf.hdr.src = TEST_SRC_EID;
261 
262 	/* Middle fragment with size MCTP_BTU + 1 */
263 	flags_seq_tag = MCTP_HDR_FLAG_SOM |
264 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
265 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
266 			     &pktbuf);
267 
268 	flags_seq_tag = (get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
269 	receive_one_fragment(binding, test_payload + MCTP_BTU, MCTP_BTU + 1,
270 			     flags_seq_tag, &pktbuf);
271 
272 	flags_seq_tag = MCTP_HDR_FLAG_EOM |
273 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
274 	receive_one_fragment(binding, test_payload + (2 * MCTP_BTU), MCTP_BTU,
275 			     flags_seq_tag, &pktbuf);
276 
277 	assert(!test_param.seen);
278 
279 	mctp_binding_test_destroy(binding);
280 	mctp_destroy(mctp);
281 }
282 
283 static void mctp_core_test_receive_smaller_end_fragment()
284 {
285 	struct mctp *mctp = NULL;
286 	struct mctp_binding_test *binding = NULL;
287 	struct test_params test_param;
288 	static uint8_t test_payload[MAX_PAYLOAD_SIZE];
289 	uint8_t tag = MCTP_HDR_FLAG_TO | get_tag();
290 	uint8_t end_frag_size = MCTP_BTU - 10;
291 	struct pktbuf pktbuf;
292 	uint8_t flags_seq_tag;
293 
294 	memset(test_payload, 0, sizeof(test_payload));
295 	test_param.seen = false;
296 	test_param.message_size = 0;
297 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
298 	mctp_set_rx_all(mctp, rx_message, &test_param);
299 	memset(&pktbuf, 0, sizeof(pktbuf));
300 	pktbuf.hdr.dest = TEST_DEST_EID;
301 	pktbuf.hdr.src = TEST_SRC_EID;
302 
303 	flags_seq_tag = MCTP_HDR_FLAG_SOM |
304 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
305 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
306 			     &pktbuf);
307 
308 	flags_seq_tag = (get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
309 	receive_one_fragment(binding, test_payload + MCTP_BTU, MCTP_BTU,
310 			     flags_seq_tag, &pktbuf);
311 
312 	flags_seq_tag = MCTP_HDR_FLAG_EOM |
313 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
314 	receive_one_fragment(binding, test_payload + (2 * MCTP_BTU),
315 			     end_frag_size, flags_seq_tag, &pktbuf);
316 
317 	assert(test_param.seen);
318 	assert(test_param.message_size ==
319 	       (size_t)(2 * MCTP_BTU + end_frag_size));
320 
321 	mctp_binding_test_destroy(binding);
322 	mctp_destroy(mctp);
323 }
324 
325 static void mctp_core_test_receive_bigger_end_fragment()
326 {
327 	struct mctp *mctp = NULL;
328 	struct mctp_binding_test *binding = NULL;
329 	struct test_params test_param;
330 	static uint8_t test_payload[MAX_PAYLOAD_SIZE];
331 	uint8_t tag = MCTP_HDR_FLAG_TO | get_tag();
332 	uint8_t end_frag_size = MCTP_BTU + 10;
333 	struct pktbuf pktbuf;
334 	uint8_t flags_seq_tag;
335 
336 	memset(test_payload, 0, sizeof(test_payload));
337 	test_param.seen = false;
338 	test_param.message_size = 0;
339 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
340 	mctp_set_rx_all(mctp, rx_message, &test_param);
341 	memset(&pktbuf, 0, sizeof(pktbuf));
342 	pktbuf.hdr.dest = TEST_DEST_EID;
343 	pktbuf.hdr.src = TEST_SRC_EID;
344 
345 	flags_seq_tag = MCTP_HDR_FLAG_SOM |
346 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
347 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
348 			     &pktbuf);
349 
350 	flags_seq_tag = (get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
351 	receive_one_fragment(binding, test_payload + MCTP_BTU, MCTP_BTU,
352 			     flags_seq_tag, &pktbuf);
353 
354 	flags_seq_tag = MCTP_HDR_FLAG_EOM |
355 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
356 	receive_one_fragment(binding, test_payload + (2 * MCTP_BTU),
357 			     end_frag_size, flags_seq_tag, &pktbuf);
358 
359 	assert(!test_param.seen);
360 
361 	mctp_binding_test_destroy(binding);
362 	mctp_destroy(mctp);
363 }
364 
365 static void mctp_core_test_drop_large_fragments()
366 {
367 	struct mctp *mctp = NULL;
368 	struct mctp_binding_test *binding = NULL;
369 	struct test_params test_param;
370 	static uint8_t test_payload[MAX_PAYLOAD_SIZE];
371 	struct pktbuf pktbuf;
372 
373 	memset(test_payload, 0, sizeof(test_payload));
374 	test_param.seen = false;
375 	test_param.message_size = 0;
376 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
377 	mctp_set_rx_all(mctp, rx_message, &test_param);
378 	memset(&pktbuf, 0, sizeof(pktbuf));
379 	pktbuf.hdr.dest = TEST_DEST_EID;
380 	pktbuf.hdr.src = TEST_SRC_EID;
381 
382 	/* Receive a large payload - first fragment with MCTP_BTU bytes,
383 	* 2nd fragment of SIZE_MAX */
384 
385 	receive_two_fragment_message(binding, test_payload, MCTP_BTU,
386 				     SIZE_MAX - sizeof(struct mctp_hdr),
387 				     &pktbuf);
388 
389 	assert(!test_param.seen);
390 
391 	mctp_binding_test_destroy(binding);
392 	mctp_destroy(mctp);
393 }
394 
395 static void mctp_core_test_exhaust_context_buffers()
396 {
397 	struct mctp *mctp = NULL;
398 	struct mctp_binding_test *binding = NULL;
399 	struct test_params test_param;
400 	static uint8_t test_payload[MAX_PAYLOAD_SIZE];
401 	uint8_t tag = MCTP_HDR_FLAG_TO | get_tag();
402 	uint8_t i = 0;
403 	const uint8_t max_context_buffers = 16;
404 	struct pktbuf pktbuf;
405 	uint8_t flags_seq_tag;
406 
407 	memset(test_payload, 0, sizeof(test_payload));
408 	test_param.seen = false;
409 	test_param.message_size = 0;
410 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
411 	mctp_set_rx_all(mctp, rx_message, &test_param);
412 	memset(&pktbuf, 0, sizeof(pktbuf));
413 	pktbuf.hdr.dest = TEST_DEST_EID;
414 	pktbuf.hdr.src = TEST_SRC_EID;
415 
416 	/* Exhaust all 16 context buffers*/
417 	for (i = 0; i < max_context_buffers; i++) {
418 		flags_seq_tag = MCTP_HDR_FLAG_SOM |
419 				(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
420 		receive_one_fragment(binding, test_payload, MCTP_BTU,
421 				     flags_seq_tag, &pktbuf);
422 
423 		/* Change source EID so that different contexts are created */
424 		pktbuf.hdr.src++;
425 	}
426 
427 	/* Send a full message from a different EID */
428 	pktbuf.hdr.src++;
429 	receive_two_fragment_message(binding, test_payload, MCTP_BTU, MCTP_BTU,
430 				     &pktbuf);
431 
432 	/* Message assembly should fail */
433 	assert(!test_param.seen);
434 
435 	/* Complete message assembly for one of the messages */
436 	pktbuf.hdr.src -= max_context_buffers;
437 	flags_seq_tag = MCTP_HDR_FLAG_EOM |
438 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
439 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
440 			     &pktbuf);
441 
442 	assert(test_param.seen);
443 	assert(test_param.message_size == (2 * MCTP_BTU));
444 
445 	mctp_binding_test_destroy(binding);
446 	mctp_destroy(mctp);
447 }
448 
449 static void mctp_core_test_rx_with_tag()
450 {
451 	struct mctp *mctp = NULL;
452 	struct mctp_binding_test *binding = NULL;
453 	struct test_params test_param;
454 	static uint8_t test_payload[MCTP_BTU];
455 	uint8_t tag = get_tag();
456 	struct pktbuf pktbuf;
457 	uint8_t flags_seq_tag;
458 
459 	memset(test_payload, 0, sizeof(test_payload));
460 	test_param.seen = false;
461 	test_param.message_size = 0;
462 	test_param.msg_tag = 0;
463 	test_param.tag_owner = false;
464 
465 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
466 	mctp_set_rx_all(mctp, rx_message, &test_param);
467 	memset(&pktbuf, 0, sizeof(pktbuf));
468 	pktbuf.hdr.dest = TEST_DEST_EID;
469 	pktbuf.hdr.src = TEST_SRC_EID;
470 
471 	/* Set tag and tag owner fields for a recieve packet */
472 	flags_seq_tag = MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM |
473 			(1 << MCTP_HDR_TO_SHIFT) | tag;
474 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
475 			     &pktbuf);
476 
477 	assert(test_param.seen);
478 	assert(test_param.message_size == (MCTP_BTU));
479 	assert(test_param.msg_tag == tag);
480 	assert(test_param.tag_owner);
481 
482 	mctp_binding_test_destroy(binding);
483 	mctp_destroy(mctp);
484 }
485 
486 static void mctp_core_test_rx_with_tag_multifragment()
487 {
488 	struct mctp *mctp = NULL;
489 	struct mctp_binding_test *binding = NULL;
490 	struct test_params test_param;
491 	static uint8_t test_payload[MCTP_BTU];
492 	uint8_t tag = get_tag();
493 	struct pktbuf pktbuf;
494 	uint8_t flags_seq_tag;
495 
496 	memset(test_payload, 0, sizeof(test_payload));
497 	test_param.seen = false;
498 	test_param.message_size = 0;
499 	test_param.msg_tag = 0;
500 	test_param.tag_owner = false;
501 
502 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
503 	mctp_set_rx_all(mctp, rx_message, &test_param);
504 	memset(&pktbuf, 0, sizeof(pktbuf));
505 	pktbuf.hdr.dest = TEST_DEST_EID;
506 	pktbuf.hdr.src = TEST_SRC_EID;
507 
508 	/* Set tag and tag owner fields for a 3 fragment packet */
509 	flags_seq_tag = MCTP_HDR_FLAG_SOM |
510 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) |
511 			(1 << MCTP_HDR_TO_SHIFT) | tag;
512 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
513 			     &pktbuf);
514 
515 	flags_seq_tag = (get_sequence() << MCTP_HDR_SEQ_SHIFT) |
516 			(1 << MCTP_HDR_TO_SHIFT) | tag;
517 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
518 			     &pktbuf);
519 
520 	flags_seq_tag = MCTP_HDR_FLAG_EOM |
521 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) |
522 			(1 << MCTP_HDR_TO_SHIFT) | tag;
523 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
524 			     &pktbuf);
525 
526 	assert(test_param.seen);
527 	assert(test_param.message_size == (3 * MCTP_BTU));
528 	assert(test_param.msg_tag == tag);
529 	assert(test_param.tag_owner);
530 
531 	mctp_binding_test_destroy(binding);
532 	mctp_destroy(mctp);
533 }
534 
535 /* clang-format off */
536 #define TEST_CASE(test) { #test, test }
537 static const struct {
538 	const char *name;
539 	void (*test)(void);
540 } mctp_core_tests[] = {
541 	TEST_CASE(mctp_core_test_simple_rx),
542 	TEST_CASE(mctp_core_test_receive_equal_length_fragments),
543 	TEST_CASE(mctp_core_test_receive_unexpected_smaller_middle_fragment),
544 	TEST_CASE(mctp_core_test_receive_unexpected_bigger_middle_fragment),
545 	TEST_CASE(mctp_core_test_receive_smaller_end_fragment),
546 	TEST_CASE(mctp_core_test_receive_bigger_end_fragment),
547 	TEST_CASE(mctp_core_test_drop_large_fragments),
548 	TEST_CASE(mctp_core_test_exhaust_context_buffers),
549 	TEST_CASE(mctp_core_test_rx_with_tag),
550 	TEST_CASE(mctp_core_test_rx_with_tag_multifragment),
551 };
552 /* clang-format on */
553 
554 #ifndef BUILD_ASSERT
555 #define BUILD_ASSERT(x)                                                        \
556 	do {                                                                   \
557 		(void)sizeof(char[0 - (!(x))]);                                \
558 	} while (0)
559 #endif
560 
561 int main(void)
562 {
563 	uint8_t i;
564 
565 	mctp_set_log_stdio(MCTP_LOG_DEBUG);
566 
567 	BUILD_ASSERT(ARRAY_SIZE(mctp_core_tests) < SIZE_MAX);
568 	for (i = 0; i < ARRAY_SIZE(mctp_core_tests); i++) {
569 		mctp_prlog(MCTP_LOG_DEBUG, "begin: %s",
570 			   mctp_core_tests[i].name);
571 		mctp_core_tests[i].test();
572 		mctp_prlog(MCTP_LOG_DEBUG, "end: %s\n",
573 			   mctp_core_tests[i].name);
574 	}
575 
576 	return 0;
577 }
578