xref: /openbmc/libmctp/tests/test_core.c (revision f39c3857)
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), &pktbuf);
387 
388 	assert(!test_param.seen);
389 
390 	mctp_binding_test_destroy(binding);
391 	mctp_destroy(mctp);
392 }
393 
394 static void mctp_core_test_exhaust_context_buffers()
395 {
396 	struct mctp *mctp = NULL;
397 	struct mctp_binding_test *binding = NULL;
398 	struct test_params test_param;
399 	static uint8_t test_payload[MAX_PAYLOAD_SIZE];
400 	uint8_t tag = MCTP_HDR_FLAG_TO | get_tag();
401 	uint8_t i = 0;
402 	const uint8_t max_context_buffers = 16;
403 	struct pktbuf pktbuf;
404 	uint8_t flags_seq_tag;
405 
406 	memset(test_payload, 0, sizeof(test_payload));
407 	test_param.seen = false;
408 	test_param.message_size = 0;
409 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
410 	mctp_set_rx_all(mctp, rx_message, &test_param);
411 	memset(&pktbuf, 0, sizeof(pktbuf));
412 	pktbuf.hdr.dest = TEST_DEST_EID;
413 	pktbuf.hdr.src = TEST_SRC_EID;
414 
415 	/* Exhaust all 16 context buffers*/
416 	for (i = 0; i < max_context_buffers; i++) {
417 		flags_seq_tag = MCTP_HDR_FLAG_SOM |
418 				(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
419 		receive_one_fragment(binding, test_payload, MCTP_BTU,
420 				flags_seq_tag, &pktbuf);
421 
422 		/* Change source EID so that different contexts are created */
423 		pktbuf.hdr.src++;
424 	}
425 
426 	/* Send a full message from a different EID */
427 	pktbuf.hdr.src++;
428 	receive_two_fragment_message(binding, test_payload, MCTP_BTU, MCTP_BTU,
429 			&pktbuf);
430 
431 	/* Message assembly should fail */
432 	assert(!test_param.seen);
433 
434 	/* Complete message assembly for one of the messages */
435 	pktbuf.hdr.src -= max_context_buffers;
436 	flags_seq_tag = MCTP_HDR_FLAG_EOM |
437 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) | tag;
438 	receive_one_fragment(binding, test_payload, MCTP_BTU,
439 			flags_seq_tag, &pktbuf);
440 
441 	assert(test_param.seen);
442 	assert(test_param.message_size == (2 * MCTP_BTU));
443 
444 	mctp_binding_test_destroy(binding);
445 	mctp_destroy(mctp);
446 }
447 
448 static void mctp_core_test_rx_with_tag()
449 {
450 	struct mctp *mctp = NULL;
451 	struct mctp_binding_test *binding = NULL;
452 	struct test_params test_param;
453 	static uint8_t test_payload[MCTP_BTU];
454 	uint8_t tag = get_tag();
455 	struct pktbuf pktbuf;
456 	uint8_t flags_seq_tag;
457 
458 	memset(test_payload, 0, sizeof(test_payload));
459 	test_param.seen = false;
460 	test_param.message_size = 0;
461 	test_param.msg_tag = 0;
462 	test_param.tag_owner = false;
463 
464 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
465 	mctp_set_rx_all(mctp, rx_message, &test_param);
466 	memset(&pktbuf, 0, sizeof(pktbuf));
467 	pktbuf.hdr.dest = TEST_DEST_EID;
468 	pktbuf.hdr.src = TEST_SRC_EID;
469 
470 	/* Set tag and tag owner fields for a recieve packet */
471 	flags_seq_tag = MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM |
472 			(1 << MCTP_HDR_TO_SHIFT) | tag;
473 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
474 			     &pktbuf);
475 
476 	assert(test_param.seen);
477 	assert(test_param.message_size == (MCTP_BTU));
478 	assert(test_param.msg_tag == tag);
479 	assert(test_param.tag_owner);
480 
481 	mctp_binding_test_destroy(binding);
482 	mctp_destroy(mctp);
483 }
484 
485 static void mctp_core_test_rx_with_tag_multifragment()
486 {
487 	struct mctp *mctp = NULL;
488 	struct mctp_binding_test *binding = NULL;
489 	struct test_params test_param;
490 	static uint8_t test_payload[MCTP_BTU];
491 	uint8_t tag = get_tag();
492 	struct pktbuf pktbuf;
493 	uint8_t flags_seq_tag;
494 
495 	memset(test_payload, 0, sizeof(test_payload));
496 	test_param.seen = false;
497 	test_param.message_size = 0;
498 	test_param.msg_tag = 0;
499 	test_param.tag_owner = false;
500 
501 	mctp_test_stack_init(&mctp, &binding, TEST_DEST_EID);
502 	mctp_set_rx_all(mctp, rx_message, &test_param);
503 	memset(&pktbuf, 0, sizeof(pktbuf));
504 	pktbuf.hdr.dest = TEST_DEST_EID;
505 	pktbuf.hdr.src = TEST_SRC_EID;
506 
507 	/* Set tag and tag owner fields for a 3 fragment packet */
508 	flags_seq_tag = MCTP_HDR_FLAG_SOM |
509 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) |
510 			(1 << MCTP_HDR_TO_SHIFT) | tag;
511 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
512 			     &pktbuf);
513 
514 	flags_seq_tag = (get_sequence() << MCTP_HDR_SEQ_SHIFT) |
515 			(1 << MCTP_HDR_TO_SHIFT) | tag;
516 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
517 			     &pktbuf);
518 
519 	flags_seq_tag = MCTP_HDR_FLAG_EOM |
520 			(get_sequence() << MCTP_HDR_SEQ_SHIFT) |
521 			(1 << MCTP_HDR_TO_SHIFT) | tag;
522 	receive_one_fragment(binding, test_payload, MCTP_BTU, flags_seq_tag,
523 			     &pktbuf);
524 
525 	assert(test_param.seen);
526 	assert(test_param.message_size == (3 * MCTP_BTU));
527 	assert(test_param.msg_tag == tag);
528 	assert(test_param.tag_owner);
529 
530 	mctp_binding_test_destroy(binding);
531 	mctp_destroy(mctp);
532 }
533 
534 /* clang-format off */
535 #define TEST_CASE(test) { #test, test }
536 static const struct {
537 	const char *name;
538 	void (*test)(void);
539 } mctp_core_tests[] = {
540 	TEST_CASE(mctp_core_test_simple_rx),
541 	TEST_CASE(mctp_core_test_receive_equal_length_fragments),
542 	TEST_CASE(mctp_core_test_receive_unexpected_smaller_middle_fragment),
543 	TEST_CASE(mctp_core_test_receive_unexpected_bigger_middle_fragment),
544 	TEST_CASE(mctp_core_test_receive_smaller_end_fragment),
545 	TEST_CASE(mctp_core_test_receive_bigger_end_fragment),
546 	TEST_CASE(mctp_core_test_drop_large_fragments),
547 	TEST_CASE(mctp_core_test_exhaust_context_buffers),
548 	TEST_CASE(mctp_core_test_rx_with_tag),
549 	TEST_CASE(mctp_core_test_rx_with_tag_multifragment),
550 };
551 /* clang-format on */
552 
553 #ifndef BUILD_ASSERT
554 #define BUILD_ASSERT(x)                                                        \
555 	do {                                                                   \
556 		(void)sizeof(char[0 - (!(x))]);                                \
557 	} while (0)
558 #endif
559 
560 int main(void)
561 {
562 	uint8_t i;
563 
564 	mctp_set_log_stdio(MCTP_LOG_DEBUG);
565 
566 	BUILD_ASSERT(ARRAY_SIZE(mctp_core_tests) < SIZE_MAX);
567 	for (i = 0; i < ARRAY_SIZE(mctp_core_tests); i++) {
568 		mctp_prlog(MCTP_LOG_DEBUG, "begin: %s",
569 				mctp_core_tests[i].name);
570 		mctp_core_tests[i].test();
571 		mctp_prlog(MCTP_LOG_DEBUG, "end: %s\n",
572 				mctp_core_tests[i].name);
573 	}
574 
575 	return 0;
576 }
577