blob: be3516c9ae57378f12371d0485ef5dcb5eb6b0da [file] [log] [blame]
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <zephyr/net/buf.h>
#include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
#include <zephyr/mgmt/mcumgr/transport/smp_dummy.h>
#include <zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h>
#include <zcbor_common.h>
#include <zcbor_decode.h>
#include <zcbor_encode.h>
#include <mgmt/mcumgr/util/zcbor_bulk.h>
#include <string.h>
#include <smp_internal.h>
#include "smp_test_util.h"
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(mcumgr_fs_grp, 4);
enum {
LEGACY_VERSION = 0,
CURRENT_VERSION,
FUTURE_VERSION,
};
#define SMP_RESPONSE_WAIT_TIME 3
#define QUERY_BUFFER_SIZE 16
#define ZCBOR_BUFFER_SIZE 256
#define OUTPUT_BUFFER_SIZE 256
#define ZCBOR_HISTORY_ARRAY_SIZE 4
#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
/* Response to legacy packet */
static const uint8_t response_old[] = {
0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x07,
0xbf, 0x62, 0x72, 0x63, 0x03, 0xff
};
#else
/* Response if a legacy packet is sent and server does not support it */
static const uint8_t response_old[] = {
0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x07,
0xbf, 0x62, 0x72, 0x63, 0x0c, 0xff
};
#endif
/* Response to current packet */
static const uint8_t response_current[] = {
0x09, 0x00, 0x00, 0x13, 0x00, 0x00, 0x01, 0x07,
0xbf, 0x63, 0x72, 0x65, 0x74, 0xbf, 0x65, 0x67,
0x72, 0x6f, 0x75, 0x70, 0x00, 0x62, 0x72, 0x63,
0x02, 0xff, 0xff
};
/* Response if an invalid (too high) version packet is sent and server does not support it */
static const uint8_t response_new[] = {
0x09, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x07,
0xbf, 0x62, 0x72, 0x63, 0x0d, 0xff
};
static struct net_buf *nb;
const uint8_t query_fake[] = "8";
struct group_error {
uint16_t group;
uint16_t rc;
bool found;
};
static bool mcumgr_ret_decode(zcbor_state_t *state, struct group_error *result)
{
bool ok;
size_t decoded;
uint32_t tmp_group;
uint32_t tmp_rc;
struct zcbor_map_decode_key_val output_decode[] = {
ZCBOR_MAP_DECODE_KEY_DECODER("group", zcbor_uint32_decode, &tmp_group),
ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_uint32_decode, &tmp_rc),
};
result->found = false;
ok = zcbor_map_decode_bulk(state, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
if (ok &&
zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), "group") &&
zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), "rc")) {
result->group = (uint16_t)tmp_group;
result->rc = (uint16_t)tmp_rc;
result->found = true;
}
return ok;
}
ZTEST(smp_version, test_legacy_command)
{
uint8_t buffer[ZCBOR_BUFFER_SIZE];
uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
bool ok;
uint16_t buffer_size;
zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
bool received;
struct zcbor_string output = { 0 };
size_t decoded = 0;
struct smp_hdr *smp_header;
int32_t rc;
struct group_error group_error;
struct zcbor_map_decode_key_val output_decode[] = {
ZCBOR_MAP_DECODE_KEY_DECODER("output", zcbor_tstr_decode, &output),
ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc),
ZCBOR_MAP_DECODE_KEY_DECODER("ret", mcumgr_ret_decode, &group_error),
};
memset(buffer, 0, sizeof(buffer));
memset(buffer_out, 0, sizeof(buffer_out));
buffer_size = 0;
memset(zse, 0, sizeof(zse));
memset(zsd, 0, sizeof(zsd));
zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0);
ok = create_mcumgr_format_packet(zse, query_fake, buffer, buffer_out, &buffer_size,
LEGACY_VERSION);
zassert_true(ok, "Expected packet creation to be successful");
/* Enable dummy SMP backend and ready for usage */
smp_dummy_enable();
smp_dummy_clear_state();
/* Send query command to dummy SMP backend */
(void)smp_dummy_tx_pkt(buffer_out, buffer_size);
smp_dummy_add_data();
/* For a short duration to see if response has been received */
received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
zassert_true(received, "Expected to receive data but timed out");
/* Retrieve response buffer and ensure validity */
nb = smp_dummy_get_outgoing();
smp_dummy_disable();
/* Check that the received response matches the expected response */
zassert_equal(sizeof(response_old), nb->len, "Expected received data length mismatch");
zassert_mem_equal(response_old, nb->data, nb->len, "Expected received data mismatch");
/* Process received data by removing header */
smp_header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
zassert_equal(smp_header->nh_version, LEGACY_VERSION,
"Expected response header version mismatch");
zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1);
ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
zassert_true(ok, "Expected decode to be successful");
zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element");
zassert_equal(
zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
"output"), 0,
"Did not expect to get output in response");
zassert_equal(
zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
"rc"), 1,
"Expected to get rc in response");
zassert_equal(
zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
"ret"), 0,
"Did not expect to get ret in response");
#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
zassert_equal(rc, MGMT_ERR_EINVAL, "Expected to get MGMT_ERR_EINVAL error");
#else
zassert_equal(rc, MGMT_ERR_UNSUPPORTED_TOO_OLD,
"Expected to get MGMT_ERR_UNSUPPORTED_TOO_OLD error");
#endif
}
ZTEST(smp_version, test_current_command)
{
uint8_t buffer[ZCBOR_BUFFER_SIZE];
uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
bool ok;
uint16_t buffer_size;
zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
bool received;
struct zcbor_string output = { 0 };
size_t decoded = 0;
struct smp_hdr *smp_header;
int32_t rc;
struct group_error group_error;
struct zcbor_map_decode_key_val output_decode[] = {
ZCBOR_MAP_DECODE_KEY_DECODER("output", zcbor_tstr_decode, &output),
ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc),
ZCBOR_MAP_DECODE_KEY_DECODER("ret", mcumgr_ret_decode, &group_error),
};
memset(buffer, 0, sizeof(buffer));
memset(buffer_out, 0, sizeof(buffer_out));
buffer_size = 0;
memset(zse, 0, sizeof(zse));
memset(zsd, 0, sizeof(zsd));
zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0);
ok = create_mcumgr_format_packet(zse, query_fake, buffer, buffer_out, &buffer_size,
CURRENT_VERSION);
zassert_true(ok, "Expected packet creation to be successful");
/* Enable dummy SMP backend and ready for usage */
smp_dummy_enable();
smp_dummy_clear_state();
/* Send query command to dummy SMP backend */
(void)smp_dummy_tx_pkt(buffer_out, buffer_size);
smp_dummy_add_data();
/* For a short duration to see if response has been received */
received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
zassert_true(received, "Expected to receive data but timed out");
/* Retrieve response buffer and ensure validity */
nb = smp_dummy_get_outgoing();
smp_dummy_disable();
/* Check that the received response matches the expected response */
zassert_equal(sizeof(response_current), nb->len, "Expected received data length mismatch");
zassert_mem_equal(response_current, nb->data, nb->len, "Expected received data mismatch");
/* Process received data by removing header */
smp_header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
zassert_equal(smp_header->nh_version, CURRENT_VERSION,
"Expected response header version mismatch");
zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1);
ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
zassert_true(ok, "Expected decode to be successful");
zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element");
zassert_equal(
zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
"output"), 0,
"Did not expect to get output in response");
zassert_equal(
zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
"rc"), 0,
"Did not expect to get rc in response");
zassert_equal(
zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
"ret"), 1,
"Expected to get ret in response");
zassert_true(group_error.found, "Expected both group and rc in ret to be found");
zassert_equal(group_error.group, MGMT_GROUP_ID_OS,
"Expected to get MGMT_GROUP_ID_OS for ret group");
zassert_equal(group_error.rc, OS_MGMT_RET_RC_INVALID_FORMAT,
"Expected to get OS_MGMT_RET_RC_INVALID_FORMAT for ret rc");
}
ZTEST(smp_version, test_new_command)
{
uint8_t buffer[ZCBOR_BUFFER_SIZE];
uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
bool ok;
uint16_t buffer_size;
zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
bool received;
struct zcbor_string output = { 0 };
size_t decoded = 0;
struct smp_hdr *smp_header;
int32_t rc;
struct group_error group_error;
struct zcbor_map_decode_key_val output_decode[] = {
ZCBOR_MAP_DECODE_KEY_DECODER("output", zcbor_tstr_decode, &output),
ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc),
ZCBOR_MAP_DECODE_KEY_DECODER("ret", mcumgr_ret_decode, &group_error),
};
memset(buffer, 0, sizeof(buffer));
memset(buffer_out, 0, sizeof(buffer_out));
buffer_size = 0;
memset(zse, 0, sizeof(zse));
memset(zsd, 0, sizeof(zsd));
zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0);
ok = create_mcumgr_format_packet(zse, query_fake, buffer, buffer_out, &buffer_size,
FUTURE_VERSION);
zassert_true(ok, "Expected packet creation to be successful");
/* Enable dummy SMP backend and ready for usage */
smp_dummy_enable();
smp_dummy_clear_state();
/* Send query command to dummy SMP backend */
(void)smp_dummy_tx_pkt(buffer_out, buffer_size);
smp_dummy_add_data();
/* For a short duration to see if response has been received */
received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
zassert_true(received, "Expected to receive data but timed out");
/* Retrieve response buffer and ensure validity */
nb = smp_dummy_get_outgoing();
smp_dummy_disable();
/* Check that the received response matches the expected response */
zassert_equal(sizeof(response_new), nb->len, "Expected received data length mismatch");
zassert_mem_equal(response_new, nb->data, nb->len, "Expected received data mismatch");
/* Process received data by removing header */
smp_header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
zassert_equal(smp_header->nh_version, CURRENT_VERSION,
"Expected response header version mismatch");
zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1);
ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
zassert_true(ok, "Expected decode to be successful");
zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element");
zassert_equal(
zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
"output"), 0,
"Did not expect to get output in response");
zassert_equal(
zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
"rc"), 1,
"Expected to get rc in response");
zassert_equal(
zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
"ret"), 0,
"Did not expect to get ret in response");
zassert_equal(rc, MGMT_ERR_UNSUPPORTED_TOO_NEW,
"Expected to get MGMT_ERR_UNSUPPORTED_TOO_NEW error");
}
static void cleanup_test(void *p)
{
if (nb != NULL) {
net_buf_unref(nb);
nb = NULL;
}
}
/* Main test set */
ZTEST_SUITE(smp_version, NULL, NULL, NULL, cleanup_test, NULL);