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