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