/* * Copyright (c) 2022 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include "mgmt/mcumgr/transport/smp_reassembly.h" #include "mgmt/mcumgr/transport/smp_internal.h" #define TRANSPORT_NETBUF_SIZE CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE static struct smp_transport smpt; static uint8_t buff[TRANSPORT_NETBUF_SIZE]; #define TEST_FRAME_SIZE 256 static struct net_buf *backup; /* The function is called by smp_reassembly_complete to pass a completed packet * for further processing; since there is nothing to process, this stub will only backup * buffer the pointer to allow a test case to free it with use of the mcumgr net_buf * management. */ void smp_rx_req(struct smp_transport *transport, struct net_buf *nb) { backup = nb; } ZTEST(smp_reassembly, test_first) { smp_reassembly_init(&smpt); struct smp_hdr *mh = (struct smp_hdr *)buff; int frag_used; int ret; int expected; /** First fragment errors **/ /* Len longer than netbuf error */ zassert_equal(-ENOSR, smp_reassembly_collect(&smpt, buff, TRANSPORT_NETBUF_SIZE + 1), "Expected -ENOSR error"); /* Len not enough to read expected size from header */ zassert_equal(-ENODATA, smp_reassembly_collect(&smpt, buff, sizeof(struct smp_hdr) - 1), "Expected -ENODATA error"); /* Length extracted from header, plus size of header, is bigger than buffer */ mh->nh_len = sys_cpu_to_be16(TRANSPORT_NETBUF_SIZE - sizeof(struct smp_hdr) + 1); zassert_equal(-ENOSR, smp_reassembly_collect(&smpt, buff, sizeof(struct smp_hdr) + 1), "Expected -ENOSR error"); /* Successfully alloc buffer */ mh->nh_len = sys_cpu_to_be16(TEST_FRAME_SIZE - sizeof(struct smp_hdr)); frag_used = 40; expected = TEST_FRAME_SIZE - frag_used; ret = smp_reassembly_collect(&smpt, buff, frag_used); zassert_equal(expected, ret, "Expected is %d should be %d\n", ret, expected); /* Force complete it, expected returned number of bytes missing */ ret = smp_reassembly_complete(&smpt, true); zassert_equal(expected, ret, "Forced completion ret %d, but expected was %d\n", ret, expected); /* Check fail due to lack of buffers: there is only one buffer and it already got passed * for processing by complete */ ret = smp_reassembly_collect(&smpt, buff, frag_used); zassert_equal(-ENOMEM, ret, "Expected -ENOMEM, got %d\n", ret); /* This will normally be done by packet processing and should not be done by hand: * release the buffer to the pool */ smp_packet_free(backup); } ZTEST(smp_reassembly, test_drops) { struct smp_hdr *mh = (struct smp_hdr *)buff; int frag_used; int ret; int expected; /* Collect one buffer and drop it */ mh->nh_len = sys_cpu_to_be16(TEST_FRAME_SIZE - sizeof(struct smp_hdr)); frag_used = 40; expected = TEST_FRAME_SIZE - frag_used; ret = smp_reassembly_collect(&smpt, buff, frag_used); zassert_equal(expected, ret, "Expected is %d should be %d\n", ret, expected); ret = smp_reassembly_drop(&smpt); zassert_equal(0, ret, "Expected %d from drop, got %d", ret, expected); } ZTEST(smp_reassembly, test_collection) { struct smp_hdr *mh = (struct smp_hdr *)buff; int pkt_used; int ret; int expected; int frag; void *p; for (int i = 0; i < ARRAY_SIZE(buff); i++) { buff[i] = (i % 255) + 1; } /** Collect fragments **/ /* First fragment with header */ mh->nh_len = sys_cpu_to_be16(TEST_FRAME_SIZE - sizeof(struct smp_hdr)); frag = 40; ret = smp_reassembly_collect(&smpt, buff, frag); expected = TEST_FRAME_SIZE - frag; zassert_equal(expected, ret, "Expected is %d should be %d\n", ret, expected); pkt_used = frag; /* Next fragment */ frag = 40; ret = smp_reassembly_collect(&smpt, &buff[pkt_used], frag); pkt_used += frag; expected = TEST_FRAME_SIZE - pkt_used; zassert_equal(expected, ret, "Expected is %d should be %d\n", ret, expected); /* Try to complete incomplete, no force */ ret = smp_reassembly_complete(&smpt, false); zassert_equal(-ENODATA, ret, "Expected -ENODATA when completing incomplete buffer"); /* Last fragment */ ret = smp_reassembly_collect(&smpt, &buff[pkt_used], expected); zassert_equal(0, ret, "Expected 0, got %d\n", ret); /* And overflow */ ret = smp_reassembly_collect(&smpt, buff, 1); zassert_equal(-EOVERFLOW, ret, "Expected -EOVERFLOW, got %d\n", ret); /* Complete successfully complete buffer */ ret = smp_reassembly_complete(&smpt, false); zassert_equal(0, ret, "Expected 0 from complete, got %d\n", ret); p = net_buf_pull_mem(backup, TEST_FRAME_SIZE); ret = memcmp(p, buff, TEST_FRAME_SIZE); zassert_equal(ret, 0, "Failed to assemble packet"); /* This will normally be done by packet processing and should not be done by hand: * release the buffer to the pool */ smp_packet_free(backup); } ZTEST(smp_reassembly, test_no_packet_started) { int ret; /** Complete on non-started packet **/ ret = smp_reassembly_complete(&smpt, false); zassert_equal(-EINVAL, ret, "Expected -EINVAL from complete, got %d", ret); ret = smp_reassembly_complete(&smpt, true); zassert_equal(-EINVAL, ret, "Expected -EINVAL from complete, got %d", ret); /* Try to drop packet when there is none yet */ ret = smp_reassembly_drop(&smpt); zassert_equal(-EINVAL, ret, "Expected -EINVAL, there is no packet started yet"); } ZTEST(smp_reassembly, test_ud) { struct smp_hdr *mh = (struct smp_hdr *)buff; int frag_used; int ret; int expected; void *p; /* No packet started yet */ p = smp_reassembly_get_ud(&smpt); zassert_equal(p, NULL, "Expect NULL ud poiner"); /* After collecting first fragment */ mh->nh_len = sys_cpu_to_be16(TEST_FRAME_SIZE); frag_used = 40; expected = TEST_FRAME_SIZE - frag_used + sizeof(struct smp_hdr); ret = smp_reassembly_collect(&smpt, buff, frag_used); zassert_equal(expected, ret, "Expected is %d should be %d\n", ret, expected); p = smp_reassembly_get_ud(&smpt); zassert_not_equal(p, NULL, "Expect non-NULL ud poiner"); smp_reassembly_drop(&smpt); } ZTEST_SUITE(smp_reassembly, NULL, NULL, NULL, NULL, NULL);