Add zero-copy SNMP parser and host tests

This commit is contained in:
CinderSocket
2026-03-09 10:23:11 -07:00
parent 6149d190f2
commit 088aef1f2f
13 changed files with 1356 additions and 0 deletions
+6
View File
@@ -18,12 +18,18 @@ test-host:
lib/host_tests/test_ccid_logic.c \
lib/host_tests/test_t1_existing.c \
lib/host_tests/test_t1_protocol.c \
lib/host_tests/test_snmp.c \
lib/host_tests/t1_test_stubs.c \
lib/host_tests/bit_buffer_mock.c \
lrc.c \
ccid_logic.c \
t_1_logic.c \
t_1.c \
snmp_ber_view.c \
snmp_codec.c \
snmp_response_view.c \
uhf_tag_config_view.c \
uhf_snmp_probe.c \
-o build/host_tests/seader_tests
./build/host_tests/seader_tests
+2
View File
@@ -4,6 +4,7 @@ extern MunitSuite test_lrc_suite;
extern MunitSuite test_ccid_logic_suite;
extern MunitSuite test_t1_existing_suite;
extern MunitSuite test_t1_protocol_suite;
extern MunitSuite test_snmp_suite;
int main(int argc, char* argv[]) {
MunitSuite child_suites[] = {
@@ -11,6 +12,7 @@ int main(int argc, char* argv[]) {
{"/t1", test_t1_existing_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
{"/t1", test_t1_protocol_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
{"/ccid", test_ccid_logic_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
{"/snmp", test_snmp_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
{NULL, NULL, NULL, 0, 0},
};
MunitSuite main_suite = {
+255
View File
@@ -0,0 +1,255 @@
#include <ctype.h>
#include <string.h>
#include "munit.h"
#include "snmp_codec.h"
#include "uhf_snmp_probe.h"
#include "snmp_response_view.h"
#include "uhf_tag_config_view.h"
static const char* snmp_discovery_request_hex =
"3038020103300E020100020202F4040104020201010410300E0400020100020100040004000400301104000400A00B0201000201000201003000";
static const char* snmp_discovery_response_hex =
"308200A80201033082000E02010002010004020000020201010482003A30820036041B2B0601040181E438010103050F8C9088CDA2A8D885C0B298D7FF7F020105020101040D2B0601040181E438010104080F0400040030820051041B2B0601040181E438010103050F8C9088CDA2A8D885C0B298D7FF7F040D2B0601040181E438010104080FA08200210201000201000201003082001430820010060A2B060106030F0101040002020141";
static const char* snmp_ice_response_hex =
"308200A80201033082000E02010002010004020000020201010482003A30820036041B2B0601040181E438010103050F8C9088CDA2A8D885C0B298D7FF7F020105020102040D2B0601040181E438010104080F0400040030820051041B2B0601040181E438010103050F8C9088CDA2A8D885C0B298D7FF7F040D2B0601040181E438010104080FA2820021020100020100020100308200143082001006050301070138040749434531383033";
static const char* snmp_uhf_config_response_hex =
"308200F40201033082000E02010002010004020000020201010482003A30820036041B2B0601040181E438010103050F8C9088CDA2A8D885C0B298D7FF7F020105020103040D2B0601040181E438010104080F040004003082009D041B2B0601040181E438010103050F8C9088CDA2A8D885C0B298D7FF7F040D2B0601040181E438010104080FA282006D020100020100020100308200603082005C0606030107030B00045204E2003412112B0601040181E438010102012201010101112B0601040181E43801010201220101020104E2801105112B0601040181E438010102011E01010101112B0601040181E438010102011E01010201";
static const char* snmp_ice_request_hex =
"307A020103300E020100020202F40401040202010104383036041B2B0601040181E438010103050F8C9088CDA2A8D885C0B298D7FF7F020105020101040D2B0601040181E438010104080F04000400302B04000400A025020100020100020100301A30180604030003060410300E0605030107013802010002020100";
static const char* snmp_monza_request_hex =
"308186020103300E020100020202F40401040202010104383036041B2B0601040181E438010103050F8C9088CDA2A8D885C0B298D7FF7F020105020101040D2B0601040181E438010104080F04000400303704000400A03102010002010002010030263024060403000306041C301A06112B0601040181E438010102011E0101010102010002020100";
static const char* snmp_higgs_request_hex =
"308186020103300E020100020202F40401040202010104383036041B2B0601040181E438010103050F8C9088CDA2A8D885C0B298D7FF7F020105020101040D2B0601040181E438010104080F04000400303704000400A03102010002010002010030263024060403000306041C301A06112B0601040181E43801010201220101010102010002020100";
static const uint8_t oid_elite_ice[] = {0x03, 0x01, 0x07, 0x01, 0x38};
static const uint8_t oid_uhf_tags_config[] = {0x03, 0x01, 0x07, 0x03, 0x0B, 0x00};
static const uint8_t oid_monza4qt_access_key[] = {
0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x01, 0x1E, 0x01, 0x01, 0x01, 0x01};
static const uint8_t oid_higgs3_access_key[] = {
0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x01, 0x22, 0x01, 0x01, 0x01, 0x01};
static const uint8_t live_engine_id[] = {
0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x03,
0x05, 0x0F, 0x8C, 0x90, 0x88, 0xCD, 0xA2, 0xA8, 0xD8, 0x85, 0xC0,
0xB2, 0x98, 0xD7, 0xFF, 0x7F};
static const uint8_t live_username[] = {
0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x04, 0x08, 0x0F};
static size_t test_hex_to_bytes(const char* hex, uint8_t* out, size_t out_size) {
size_t len = 0U;
int high_nibble = -1;
for(const char* p = hex; *p; ++p) {
int value = -1;
if(*p >= '0' && *p <= '9') value = *p - '0';
else if(*p >= 'A' && *p <= 'F') value = *p - 'A' + 10;
else if(*p >= 'a' && *p <= 'f') value = *p - 'a' + 10;
else if(isspace((unsigned char)*p)) continue;
else munit_error("invalid hex character");
if(high_nibble < 0) {
high_nibble = value;
} else {
if(len >= out_size) munit_error("hex output buffer too small");
out[len++] = (uint8_t)((high_nibble << 4) | value);
high_nibble = -1;
}
}
if(high_nibble >= 0) munit_error("odd-length hex string");
return len;
}
static MunitResult test_build_discovery_request_matches_live_vector(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
uint8_t message[512] = {0};
uint8_t scratch[512] = {0};
uint8_t expected[512] = {0};
size_t message_len = 0U;
size_t expected_len = test_hex_to_bytes(snmp_discovery_request_hex, expected, sizeof(expected));
munit_assert_true(seader_snmp_build_discovery_request(
scratch, sizeof(scratch), message, sizeof(message), &message_len));
munit_assert_size(message_len, ==, expected_len);
munit_assert_memory_equal(expected_len, message, expected);
return MUNIT_OK;
}
static MunitResult test_build_get_data_requests_match_live_vectors(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
uint8_t message[512] = {0};
uint8_t scratch[512] = {0};
uint8_t expected[512] = {0};
size_t message_len = 0U;
size_t expected_len = test_hex_to_bytes(snmp_ice_request_hex, expected, sizeof(expected));
munit_assert_true(seader_snmp_build_get_data_request(
live_engine_id, sizeof(live_engine_id), live_username, sizeof(live_username), 5U, 1U,
oid_elite_ice, sizeof(oid_elite_ice), scratch, sizeof(scratch), message, sizeof(message), &message_len));
munit_assert_size(message_len, ==, expected_len);
munit_assert_memory_equal(expected_len, message, expected);
expected_len = test_hex_to_bytes(snmp_monza_request_hex, expected, sizeof(expected));
munit_assert_true(seader_snmp_build_get_data_request(
live_engine_id, sizeof(live_engine_id), live_username, sizeof(live_username), 5U, 1U,
oid_monza4qt_access_key, sizeof(oid_monza4qt_access_key), scratch, sizeof(scratch), message, sizeof(message), &message_len));
munit_assert_size(message_len, ==, expected_len);
munit_assert_memory_equal(expected_len, message, expected);
expected_len = test_hex_to_bytes(snmp_higgs_request_hex, expected, sizeof(expected));
munit_assert_true(seader_snmp_build_get_data_request(
live_engine_id, sizeof(live_engine_id), live_username, sizeof(live_username), 5U, 1U,
oid_higgs3_access_key, sizeof(oid_higgs3_access_key), scratch, sizeof(scratch), message, sizeof(message), &message_len));
munit_assert_size(message_len, ==, expected_len);
munit_assert_memory_equal(expected_len, message, expected);
return MUNIT_OK;
}
static MunitResult test_parse_response_and_zero_copy_views(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
uint8_t response[256] = {0};
size_t response_len = test_hex_to_bytes(snmp_discovery_response_hex, response, sizeof(response));
SeaderSnmpResponseView view = {0};
munit_assert_true(seader_snmp_parse_response_view(response, response_len, &view));
munit_assert_uint32(view.error_status, ==, 0U);
munit_assert_uint32(view.error_index, ==, 0U);
munit_assert_uint32(view.usm_engine_boots, ==, 5U);
munit_assert_uint32(view.usm_engine_time, ==, 1U);
munit_assert_memory_equal(sizeof(live_engine_id), view.context_engine_id.ptr, live_engine_id);
munit_assert_memory_equal(sizeof(live_engine_id), view.usm_engine_id.ptr, live_engine_id);
munit_assert_memory_equal(sizeof(live_username), view.usm_username.ptr, live_username);
munit_assert_true(view.context_engine_id.ptr >= response);
munit_assert_true(view.context_engine_id.ptr < response + response_len);
return MUNIT_OK;
}
static MunitResult test_parse_ice_and_tag_config_values(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
uint8_t response[512] = {0};
size_t response_len = test_hex_to_bytes(snmp_ice_response_hex, response, sizeof(response));
SeaderSnmpResponseView view = {0};
SeaderBytesView value = {0};
munit_assert_true(seader_snmp_parse_response_view(response, response_len, &view));
munit_assert_true(seader_snmp_find_varbind_octet_value(
view.varbind_sequence, (SeaderBytesView){oid_elite_ice, sizeof(oid_elite_ice)}, &value));
munit_assert_size(value.len, ==, 7);
munit_assert_memory_equal(7, value.ptr, "ICE1803");
response_len = test_hex_to_bytes(snmp_uhf_config_response_hex, response, sizeof(response));
munit_assert_true(seader_snmp_parse_response_view(response, response_len, &view));
munit_assert_true(seader_snmp_find_varbind_octet_value(
view.varbind_sequence, (SeaderBytesView){oid_uhf_tags_config, sizeof(oid_uhf_tags_config)}, &value));
munit_assert_size(value.len, >, 80);
munit_assert_true(value.ptr >= response);
munit_assert_true(value.ptr < response + response_len);
return MUNIT_OK;
}
static MunitResult test_probe_stages(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
uint8_t response[512] = {0};
size_t response_len = test_hex_to_bytes(snmp_discovery_response_hex, response, sizeof(response));
SeaderUhfSnmpProbe probe = {0};
uint8_t message[512] = {0};
uint8_t scratch[512] = {0};
size_t message_len = 0U;
seader_uhf_snmp_probe_init(&probe);
munit_assert_int(probe.stage, ==, SeaderUhfSnmpProbeStageDiscovery);
munit_assert_true(seader_uhf_snmp_probe_build_next_request(
&probe, scratch, sizeof(scratch), message, sizeof(message), &message_len));
munit_assert_size(message_len, >, 0);
munit_assert_true(seader_uhf_snmp_probe_consume_response(&probe, response, response_len));
munit_assert_int(probe.stage, ==, SeaderUhfSnmpProbeStageReadIce);
memset(response, 0xA5, response_len);
munit_assert_true(seader_uhf_snmp_probe_build_next_request(
&probe, scratch, sizeof(scratch), message, sizeof(message), &message_len));
response_len = test_hex_to_bytes(snmp_ice_response_hex, response, sizeof(response));
munit_assert_true(seader_uhf_snmp_probe_consume_response(&probe, response, response_len));
munit_assert_int(probe.stage, ==, SeaderUhfSnmpProbeStageReadTagConfig);
munit_assert_size(probe.ice_value_len, ==, 7);
munit_assert_memory_equal(7, probe.ice_value_storage, "ICE1803");
response_len = test_hex_to_bytes(snmp_uhf_config_response_hex, response, sizeof(response));
munit_assert_true(seader_uhf_snmp_probe_consume_response(&probe, response, response_len));
munit_assert_true(probe.has_monza4qt);
munit_assert_true(probe.has_higgs3);
munit_assert_int(probe.stage, ==, SeaderUhfSnmpProbeStageReadMonza4QtKey);
munit_assert_size(probe.tag_config_value.len, >, 80);
munit_assert_true(seader_uhf_snmp_probe_consume_error(
&probe, 0x06U, (const uint8_t*)"\x69\x82", 2U));
munit_assert_true(probe.monza4qt_key_present);
munit_assert_int(probe.stage, ==, SeaderUhfSnmpProbeStageReadHiggs3Key);
munit_assert_true(seader_uhf_snmp_probe_consume_error(
&probe, 0x06U, (const uint8_t*)"\x69\x82", 2U));
munit_assert_true(probe.higgs3_key_present);
munit_assert_int(probe.stage, ==, SeaderUhfSnmpProbeStageDone);
return MUNIT_OK;
}
static MunitResult test_tag_config_view_extracts_known_entries(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
uint8_t response[512] = {0};
size_t response_len = test_hex_to_bytes(snmp_uhf_config_response_hex, response, sizeof(response));
SeaderSnmpResponseView snmp = {0};
SeaderBytesView config_payload = {0};
SeaderUhfTagConfigView view = {0};
SeaderUhfTagConfigEntryView entry = {0};
munit_assert_true(seader_snmp_parse_response_view(response, response_len, &snmp));
munit_assert_true(seader_snmp_find_varbind_octet_value(
snmp.varbind_sequence, (SeaderBytesView){oid_uhf_tags_config, sizeof(oid_uhf_tags_config)}, &config_payload));
munit_assert_true(seader_uhf_tag_config_parse(config_payload, &view));
munit_assert_true(view.has_higgs3);
munit_assert_true(view.has_monza4qt);
munit_assert_size(view.entry_count, ==, 4);
munit_assert_true(seader_uhf_tag_config_get_entry(&view, 0U, &entry));
munit_assert_int(entry.kind, ==, SeaderUhfTagConfigEntryHiggs3Access);
munit_assert_size(entry.oid.len, ==, 17U);
munit_assert_true(seader_uhf_tag_config_get_entry(&view, 2U, &entry));
munit_assert_int(entry.kind, ==, SeaderUhfTagConfigEntryMonza4QtAccess);
return MUNIT_OK;
}
static MunitResult test_response_rejects_truncated_length(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
const uint8_t malformed[] = {0x30, 0x82, 0x01};
SeaderSnmpResponseView view = {0};
munit_assert_false(seader_snmp_parse_response_view(malformed, sizeof(malformed), &view));
return MUNIT_OK;
}
static MunitTest test_snmp_cases[] = {
{(char*)"/build-discovery", test_build_discovery_request_matches_live_vector, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
{(char*)"/build-get-data", test_build_get_data_requests_match_live_vectors, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
{(char*)"/parse-response", test_parse_response_and_zero_copy_views, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
{(char*)"/parse-values", test_parse_ice_and_tag_config_values, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
{(char*)"/probe", test_probe_stages, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
{(char*)"/tag-config", test_tag_config_view_extracts_known_entries, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
{(char*)"/malformed-length", test_response_rejects_truncated_length, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
{NULL, NULL, NULL, NULL, 0, NULL},
};
MunitSuite test_snmp_suite = {
"",
test_snmp_cases,
NULL,
1,
MUNIT_SUITE_OPTION_NONE,
};
+63
View File
@@ -0,0 +1,63 @@
#include "snmp_ber_view.h"
void seader_ber_cursor_init(SeaderBerCursor* cursor, const uint8_t* buffer, size_t len) {
if(!cursor) return;
cursor->buffer = buffer;
cursor->len = len;
cursor->offset = 0U;
}
static bool seader_ber_read_length(SeaderBerCursor* cursor, size_t* value_len) {
if(!cursor || !value_len || cursor->offset >= cursor->len) return false;
uint8_t descriptor = cursor->buffer[cursor->offset++];
if((descriptor & 0x80U) == 0U) {
*value_len = descriptor;
return true;
}
size_t length_len = descriptor & 0x7FU;
if(length_len == 0U || length_len > sizeof(size_t)) return false;
if(cursor->offset + length_len > cursor->len) return false;
size_t parsed = 0U;
for(size_t i = 0U; i < length_len; i++) {
parsed = (parsed << 8U) | cursor->buffer[cursor->offset++];
}
*value_len = parsed;
return true;
}
bool seader_ber_next_tlv(SeaderBerCursor* cursor, SeaderBerTlvView* tlv) {
if(!cursor || !tlv || !cursor->buffer) return false;
if(cursor->offset + 2U > cursor->len) return false;
tlv->tag = cursor->buffer[cursor->offset++];
size_t value_len = 0U;
if(!seader_ber_read_length(cursor, &value_len)) return false;
if(cursor->offset + value_len > cursor->len) return false;
tlv->value.ptr = cursor->buffer + cursor->offset;
tlv->value.len = value_len;
cursor->offset += value_len;
return true;
}
bool seader_ber_parse_uint32(SeaderBytesView value, uint32_t* out) {
if(!value.ptr || value.len == 0U || !out) return false;
if(value.len > 1U && value.ptr[0] == 0x00U) {
value.ptr++;
value.len--;
}
if(value.len == 0U || value.len > 4U) return false;
uint32_t parsed = 0U;
for(size_t i = 0U; i < value.len; i++) {
parsed = (parsed << 8U) | value.ptr[i];
}
*out = parsed;
return true;
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef struct {
const uint8_t* ptr;
size_t len;
} SeaderBytesView;
typedef struct {
uint8_t tag;
SeaderBytesView value;
} SeaderBerTlvView;
typedef struct {
const uint8_t* buffer;
size_t len;
size_t offset;
} SeaderBerCursor;
void seader_ber_cursor_init(SeaderBerCursor* cursor, const uint8_t* buffer, size_t len);
bool seader_ber_next_tlv(SeaderBerCursor* cursor, SeaderBerTlvView* tlv);
bool seader_ber_parse_uint32(SeaderBytesView value, uint32_t* out);
+321
View File
@@ -0,0 +1,321 @@
#include "snmp_codec.h"
#include <string.h>
static bool
seader_snmp_append_length(uint8_t* dst, size_t dst_size, size_t* offset, size_t value_len) {
if(!dst || !offset) return false;
if(value_len < 0x80U) {
if(*offset + 1U > dst_size) return false;
dst[(*offset)++] = (uint8_t)value_len;
return true;
}
if(value_len <= 0xFFU) {
if(*offset + 2U > dst_size) return false;
dst[(*offset)++] = 0x81U;
dst[(*offset)++] = (uint8_t)value_len;
return true;
}
if(value_len <= 0xFFFFU) {
if(*offset + 3U > dst_size) return false;
dst[(*offset)++] = 0x82U;
dst[(*offset)++] = (uint8_t)(value_len >> 8U);
dst[(*offset)++] = (uint8_t)value_len;
return true;
}
if(value_len <= 0xFFFFFFU) {
if(*offset + 4U > dst_size) return false;
dst[(*offset)++] = 0x83U;
dst[(*offset)++] = (uint8_t)(value_len >> 16U);
dst[(*offset)++] = (uint8_t)(value_len >> 8U);
dst[(*offset)++] = (uint8_t)value_len;
return true;
}
return false;
}
static bool seader_snmp_append_tlv(
uint8_t* dst,
size_t dst_size,
size_t* offset,
uint8_t tag,
const uint8_t* value,
size_t value_len) {
if(!dst || !offset) return false;
if(*offset + 1U > dst_size) return false;
dst[(*offset)++] = tag;
if(!seader_snmp_append_length(dst, dst_size, offset, value_len)) return false;
if(value_len > 0U) {
if(!value || *offset + value_len > dst_size) return false;
memcpy(dst + *offset, value, value_len);
*offset += value_len;
}
return true;
}
static bool
seader_snmp_append_uint32(uint8_t* dst, size_t dst_size, size_t* offset, uint32_t value) {
uint8_t encoded[5] = {0};
size_t encoded_len = 0U;
do {
encoded[4U - encoded_len] = (uint8_t)(value & 0xFFU);
encoded_len++;
value >>= 8U;
} while(value != 0U && encoded_len < 5U);
const uint8_t* integer_value = encoded + (5U - encoded_len);
uint8_t prefixed[6] = {0};
size_t prefixed_len = 0U;
if(integer_value[0] & 0x80U) {
prefixed[prefixed_len++] = 0x00U;
}
memcpy(prefixed + prefixed_len, integer_value, encoded_len);
prefixed_len += encoded_len;
return seader_snmp_append_tlv(dst, dst_size, offset, 0x02U, prefixed, prefixed_len);
}
static bool seader_snmp_wrap_tlv_inplace(
uint8_t* buffer,
size_t buffer_capacity,
size_t value_len,
uint8_t tag,
size_t* encoded_len) {
if(!buffer || !encoded_len) return false;
uint8_t header[5] = {tag};
size_t header_len = 1U;
if(!seader_snmp_append_length(header, sizeof(header), &header_len, value_len)) return false;
if(header_len + value_len > buffer_capacity) return false;
memmove(buffer + header_len, buffer, value_len);
memcpy(buffer, header, header_len);
*encoded_len = header_len + value_len;
return true;
}
static bool seader_snmp_build_get_data_payload(
const uint8_t* target_oid,
size_t target_oid_len,
uint32_t offset_value,
uint32_t max_chunk_len,
uint8_t* payload,
size_t payload_capacity,
size_t* payload_len) {
if(!target_oid || target_oid_len == 0U || !payload || !payload_len) return false;
*payload_len = 0U;
if(!seader_snmp_append_tlv(
payload, payload_capacity, payload_len, 0x06U, target_oid, target_oid_len)) {
return false;
}
if(!seader_snmp_append_uint32(payload, payload_capacity, payload_len, offset_value))
return false;
if(!seader_snmp_append_uint32(payload, payload_capacity, payload_len, max_chunk_len))
return false;
return seader_snmp_wrap_tlv_inplace(
payload, payload_capacity, *payload_len, 0x30U, payload_len);
}
static bool seader_snmp_build_reportable_get_request(
const uint8_t* engine_id,
size_t engine_id_len,
const uint8_t* user_name,
size_t user_name_len,
uint32_t engine_boots,
uint32_t engine_time,
const uint8_t* data_oid,
size_t data_oid_len,
const uint8_t* data,
size_t data_len,
uint8_t* scratch,
size_t scratch_capacity,
uint8_t* message,
size_t message_capacity,
size_t* message_len) {
size_t scratch_len = 0U;
size_t scoped_pdu_len = 0U;
uint8_t global_data_value[16] = {0};
uint8_t global_data[24] = {0};
uint8_t version[8] = {0};
size_t global_data_value_len = 0U;
size_t global_data_len = 0U;
size_t version_len = 0U;
const uint8_t flags[] = {0x04U};
if(!scratch || !message || !message_len) return false;
*message_len = 0U;
if(data_oid && data_oid_len > 0U) {
if(!seader_snmp_append_tlv(
scratch, scratch_capacity, &scratch_len, 0x06U, data_oid, data_oid_len)) {
return false;
}
if(!seader_snmp_append_tlv(
scratch, scratch_capacity, &scratch_len, 0x04U, data, data_len)) {
return false;
}
if(!seader_snmp_wrap_tlv_inplace(
scratch, scratch_capacity, scratch_len, 0x30U, &scratch_len)) {
return false;
}
}
memcpy(message, scratch, scratch_len);
*message_len = scratch_len;
if(!seader_snmp_wrap_tlv_inplace(message, message_capacity, *message_len, 0x30U, message_len)) {
return false;
}
scratch_len = 0U;
if(!seader_snmp_append_uint32(scratch, scratch_capacity, &scratch_len, 0U) ||
!seader_snmp_append_uint32(scratch, scratch_capacity, &scratch_len, 0U) ||
!seader_snmp_append_uint32(scratch, scratch_capacity, &scratch_len, 0U)) {
return false;
}
if(scratch_len + *message_len > scratch_capacity) return false;
memcpy(scratch + scratch_len, message, *message_len);
scratch_len += *message_len;
if(!seader_snmp_wrap_tlv_inplace(scratch, scratch_capacity, scratch_len, 0xA0U, &scratch_len)) {
return false;
}
*message_len = 0U;
if(!seader_snmp_append_tlv(message, message_capacity, message_len, 0x04U, NULL, 0U) ||
!seader_snmp_append_tlv(message, message_capacity, message_len, 0x04U, NULL, 0U)) {
return false;
}
if(*message_len + scratch_len > message_capacity) return false;
memcpy(message + *message_len, scratch, scratch_len);
*message_len += scratch_len;
if(!seader_snmp_wrap_tlv_inplace(
message, message_capacity, *message_len, 0x30U, &scoped_pdu_len)) {
return false;
}
scratch_len = 0U;
if(!seader_snmp_append_tlv(
scratch, scratch_capacity, &scratch_len, 0x04U, engine_id, engine_id_len) ||
!seader_snmp_append_uint32(scratch, scratch_capacity, &scratch_len, engine_boots) ||
!seader_snmp_append_uint32(scratch, scratch_capacity, &scratch_len, engine_time) ||
!seader_snmp_append_tlv(
scratch, scratch_capacity, &scratch_len, 0x04U, user_name, user_name_len) ||
!seader_snmp_append_tlv(scratch, scratch_capacity, &scratch_len, 0x04U, NULL, 0U) ||
!seader_snmp_append_tlv(scratch, scratch_capacity, &scratch_len, 0x04U, NULL, 0U)) {
return false;
}
if(!seader_snmp_wrap_tlv_inplace(scratch, scratch_capacity, scratch_len, 0x30U, &scratch_len) ||
!seader_snmp_wrap_tlv_inplace(scratch, scratch_capacity, scratch_len, 0x04U, &scratch_len)) {
return false;
}
if(!seader_snmp_append_uint32(
global_data_value, sizeof(global_data_value), &global_data_value_len, 0U) ||
!seader_snmp_append_uint32(
global_data_value, sizeof(global_data_value), &global_data_value_len, 756U) ||
!seader_snmp_append_tlv(
global_data_value,
sizeof(global_data_value),
&global_data_value_len,
0x04U,
flags,
sizeof(flags)) ||
!seader_snmp_append_uint32(
global_data_value, sizeof(global_data_value), &global_data_value_len, 0x0101U)) {
return false;
}
if(!seader_snmp_append_tlv(
global_data,
sizeof(global_data),
&global_data_len,
0x30U,
global_data_value,
global_data_value_len)) {
return false;
}
if(!seader_snmp_append_uint32(version, sizeof(version), &version_len, 3U)) return false;
if(version_len + global_data_len + scratch_len + scoped_pdu_len > message_capacity)
return false;
memmove(message + version_len + global_data_len + scratch_len, message, scoped_pdu_len);
memcpy(message, version, version_len);
memcpy(message + version_len, global_data, global_data_len);
memcpy(message + version_len + global_data_len, scratch, scratch_len);
*message_len = version_len + global_data_len + scratch_len + scoped_pdu_len;
return seader_snmp_wrap_tlv_inplace(
message, message_capacity, *message_len, 0x30U, message_len);
}
bool seader_snmp_build_discovery_request(
uint8_t* scratch,
size_t scratch_capacity,
uint8_t* message,
size_t message_capacity,
size_t* message_len) {
return seader_snmp_build_reportable_get_request(
NULL,
0U,
NULL,
0U,
0U,
0U,
NULL,
0U,
NULL,
0U,
scratch,
scratch_capacity,
message,
message_capacity,
message_len);
}
bool seader_snmp_build_get_data_request(
const uint8_t* engine_id,
size_t engine_id_len,
const uint8_t* user_name,
size_t user_name_len,
uint32_t engine_boots,
uint32_t engine_time,
const uint8_t* target_oid,
size_t target_oid_len,
uint8_t* scratch,
size_t scratch_capacity,
uint8_t* message,
size_t message_capacity,
size_t* message_len) {
static const uint8_t oid_get_data[] = {0x03U, 0x00U, 0x03U, 0x06U};
size_t payload_len = 0U;
if(!scratch || !message) return false;
if(!seader_snmp_build_get_data_payload(
target_oid, target_oid_len, 0U, 0x100U, message, message_capacity, &payload_len)) {
return false;
}
return seader_snmp_build_reportable_get_request(
engine_id,
engine_id_len,
user_name,
user_name_len,
engine_boots,
engine_time,
oid_get_data,
sizeof(oid_get_data),
message,
payload_len,
scratch,
scratch_capacity,
message,
message_capacity,
message_len);
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
bool seader_snmp_build_discovery_request(
uint8_t* scratch,
size_t scratch_capacity,
uint8_t* message,
size_t message_capacity,
size_t* message_len);
bool seader_snmp_build_get_data_request(
const uint8_t* engine_id,
size_t engine_id_len,
const uint8_t* user_name,
size_t user_name_len,
uint32_t engine_boots,
uint32_t engine_time,
const uint8_t* target_oid,
size_t target_oid_len,
uint8_t* scratch,
size_t scratch_capacity,
uint8_t* message,
size_t message_capacity,
size_t* message_len);
+122
View File
@@ -0,0 +1,122 @@
#include "snmp_response_view.h"
#include <string.h>
bool seader_snmp_parse_response_view(
const uint8_t* response,
size_t response_len,
SeaderSnmpResponseView* view) {
SeaderBerCursor root_cursor = {0};
SeaderBerTlvView root = {0};
SeaderBerTlvView tlv = {0};
if(!response || response_len == 0U || !view) return false;
memset(view, 0, sizeof(*view));
seader_ber_cursor_init(&root_cursor, response, response_len);
if(!seader_ber_next_tlv(&root_cursor, &root) || root.tag != 0x30U) return false;
SeaderBerCursor message_cursor = {0};
seader_ber_cursor_init(&message_cursor, root.value.ptr, root.value.len);
if(!seader_ber_next_tlv(&message_cursor, &tlv) || tlv.tag != 0x02U) return false;
if(!seader_ber_next_tlv(&message_cursor, &tlv) || tlv.tag != 0x30U) return false;
SeaderBerTlvView security_params_octet = {0};
if(!seader_ber_next_tlv(&message_cursor, &security_params_octet) ||
security_params_octet.tag != 0x04U) {
return false;
}
if(!seader_ber_next_tlv(&message_cursor, &tlv) || tlv.tag != 0x30U) return false;
SeaderBerCursor sec_octet_cursor = {0};
SeaderBerTlvView sec_sequence = {0};
seader_ber_cursor_init(
&sec_octet_cursor, security_params_octet.value.ptr, security_params_octet.value.len);
if(!seader_ber_next_tlv(&sec_octet_cursor, &sec_sequence) || sec_sequence.tag != 0x30U)
return false;
SeaderBerCursor sec_cursor = {0};
SeaderBerTlvView usm_engine_id = {0};
SeaderBerTlvView usm_engine_boots = {0};
SeaderBerTlvView usm_engine_time = {0};
SeaderBerTlvView usm_username = {0};
SeaderBerTlvView ignore = {0};
seader_ber_cursor_init(&sec_cursor, sec_sequence.value.ptr, sec_sequence.value.len);
if(!seader_ber_next_tlv(&sec_cursor, &usm_engine_id) || usm_engine_id.tag != 0x04U)
return false;
if(!seader_ber_next_tlv(&sec_cursor, &usm_engine_boots) || usm_engine_boots.tag != 0x02U)
return false;
if(!seader_ber_next_tlv(&sec_cursor, &usm_engine_time) || usm_engine_time.tag != 0x02U)
return false;
if(!seader_ber_next_tlv(&sec_cursor, &usm_username) || usm_username.tag != 0x04U) return false;
if(!seader_ber_next_tlv(&sec_cursor, &ignore) || ignore.tag != 0x04U) return false;
if(!seader_ber_next_tlv(&sec_cursor, &ignore) || ignore.tag != 0x04U) return false;
SeaderBerCursor scoped_cursor = {0};
SeaderBerTlvView context_engine = {0};
SeaderBerTlvView context_name = {0};
SeaderBerTlvView pdu = {0};
seader_ber_cursor_init(&scoped_cursor, tlv.value.ptr, tlv.value.len);
if(!seader_ber_next_tlv(&scoped_cursor, &context_engine) || context_engine.tag != 0x04U)
return false;
if(!seader_ber_next_tlv(&scoped_cursor, &context_name) || context_name.tag != 0x04U)
return false;
if(!seader_ber_next_tlv(&scoped_cursor, &pdu)) return false;
SeaderBerCursor pdu_cursor = {0};
SeaderBerTlvView request_id = {0};
SeaderBerTlvView error_status = {0};
SeaderBerTlvView error_index = {0};
SeaderBerTlvView varbinds = {0};
seader_ber_cursor_init(&pdu_cursor, pdu.value.ptr, pdu.value.len);
if(!seader_ber_next_tlv(&pdu_cursor, &request_id) || request_id.tag != 0x02U) return false;
if(!seader_ber_next_tlv(&pdu_cursor, &error_status) || error_status.tag != 0x02U) return false;
if(!seader_ber_next_tlv(&pdu_cursor, &error_index) || error_index.tag != 0x02U) return false;
if(!seader_ber_next_tlv(&pdu_cursor, &varbinds) || varbinds.tag != 0x30U) return false;
view->context_engine_id = context_engine.value;
view->usm_engine_id = usm_engine_id.value;
view->usm_username = usm_username.value;
view->varbind_sequence = varbinds.value;
view->pdu_tag = pdu.tag;
if(!seader_ber_parse_uint32(usm_engine_boots.value, &view->usm_engine_boots) ||
!seader_ber_parse_uint32(usm_engine_time.value, &view->usm_engine_time) ||
!seader_ber_parse_uint32(error_status.value, &view->error_status) ||
!seader_ber_parse_uint32(error_index.value, &view->error_index)) {
return false;
}
return true;
}
bool seader_snmp_find_varbind_octet_value(
SeaderBytesView varbind_sequence,
SeaderBytesView expected_oid,
SeaderBytesView* value) {
SeaderBerCursor cursor = {0};
seader_ber_cursor_init(&cursor, varbind_sequence.ptr, varbind_sequence.len);
while(cursor.offset < cursor.len) {
SeaderBerTlvView varbind = {0};
SeaderBerTlvView oid = {0};
SeaderBerTlvView object_value = {0};
SeaderBerCursor inner = {0};
if(!seader_ber_next_tlv(&cursor, &varbind) || varbind.tag != 0x30U) return false;
seader_ber_cursor_init(&inner, varbind.value.ptr, varbind.value.len);
if(!seader_ber_next_tlv(&inner, &oid) || oid.tag != 0x06U) return false;
if(!seader_ber_next_tlv(&inner, &object_value)) return false;
if(oid.value.len == expected_oid.len &&
memcmp(oid.value.ptr, expected_oid.ptr, expected_oid.len) == 0) {
if(object_value.tag != 0x04U) return false;
if(value) *value = object_value.value;
return true;
}
}
return false;
}
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include "snmp_ber_view.h"
typedef struct {
SeaderBytesView context_engine_id;
SeaderBytesView usm_engine_id;
SeaderBytesView usm_username;
SeaderBytesView varbind_sequence;
uint8_t pdu_tag;
uint32_t usm_engine_boots;
uint32_t usm_engine_time;
uint32_t error_status;
uint32_t error_index;
} SeaderSnmpResponseView;
bool seader_snmp_parse_response_view(
const uint8_t* response,
size_t response_len,
SeaderSnmpResponseView* view);
bool seader_snmp_find_varbind_octet_value(
SeaderBytesView varbind_sequence,
SeaderBytesView expected_oid,
SeaderBytesView* value);
+284
View File
@@ -0,0 +1,284 @@
#include "uhf_snmp_probe.h"
#include "snmp_codec.h"
#include <string.h>
static const uint8_t oid_elite_ice[] = {0x03, 0x01, 0x07, 0x01, 0x38};
static const uint8_t oid_uhf_tags_config[] = {0x03, 0x01, 0x07, 0x03, 0x0B, 0x00};
static const uint8_t oid_monza4qt_access_key[] = {
0x2B,
0x06,
0x01,
0x04,
0x01,
0x81,
0xE4,
0x38,
0x01,
0x01,
0x02,
0x01,
0x1E,
0x01,
0x01,
0x01,
0x01};
static const uint8_t oid_higgs3_access_key[] = {
0x2B,
0x06,
0x01,
0x04,
0x01,
0x81,
0xE4,
0x38,
0x01,
0x01,
0x02,
0x01,
0x22,
0x01,
0x01,
0x01,
0x01};
static void seader_uhf_snmp_probe_advance_after_tag_config(SeaderUhfSnmpProbe* probe) {
if(probe->has_monza4qt) {
probe->stage = SeaderUhfSnmpProbeStageReadMonza4QtKey;
} else if(probe->has_higgs3) {
probe->stage = SeaderUhfSnmpProbeStageReadHiggs3Key;
} else {
probe->stage = SeaderUhfSnmpProbeStageDone;
}
}
static void seader_uhf_snmp_probe_advance_after_monza(SeaderUhfSnmpProbe* probe) {
if(probe->has_higgs3) {
probe->stage = SeaderUhfSnmpProbeStageReadHiggs3Key;
} else {
probe->stage = SeaderUhfSnmpProbeStageDone;
}
}
void seader_uhf_snmp_probe_init(SeaderUhfSnmpProbe* probe) {
if(!probe) return;
memset(probe, 0, sizeof(*probe));
probe->stage = SeaderUhfSnmpProbeStageDiscovery;
}
bool seader_uhf_snmp_probe_build_next_request(
const SeaderUhfSnmpProbe* probe,
uint8_t* scratch,
size_t scratch_capacity,
uint8_t* message,
size_t message_capacity,
size_t* message_len) {
if(!probe) return false;
switch(probe->stage) {
case SeaderUhfSnmpProbeStageDiscovery:
return seader_snmp_build_discovery_request(
scratch, scratch_capacity, message, message_capacity, message_len);
case SeaderUhfSnmpProbeStageReadIce:
return seader_snmp_build_get_data_request(
probe->usm_engine_id_storage,
probe->usm_engine_id_len,
probe->usm_username_storage,
probe->usm_username_len,
probe->usm_engine_boots,
probe->usm_engine_time,
oid_elite_ice,
sizeof(oid_elite_ice),
scratch,
scratch_capacity,
message,
message_capacity,
message_len);
case SeaderUhfSnmpProbeStageReadTagConfig:
return seader_snmp_build_get_data_request(
probe->usm_engine_id_storage,
probe->usm_engine_id_len,
probe->usm_username_storage,
probe->usm_username_len,
probe->usm_engine_boots,
probe->usm_engine_time,
oid_uhf_tags_config,
sizeof(oid_uhf_tags_config),
scratch,
scratch_capacity,
message,
message_capacity,
message_len);
case SeaderUhfSnmpProbeStageReadMonza4QtKey:
return seader_snmp_build_get_data_request(
probe->usm_engine_id_storage,
probe->usm_engine_id_len,
probe->usm_username_storage,
probe->usm_username_len,
probe->usm_engine_boots,
probe->usm_engine_time,
oid_monza4qt_access_key,
sizeof(oid_monza4qt_access_key),
scratch,
scratch_capacity,
message,
message_capacity,
message_len);
case SeaderUhfSnmpProbeStageReadHiggs3Key:
return seader_snmp_build_get_data_request(
probe->usm_engine_id_storage,
probe->usm_engine_id_len,
probe->usm_username_storage,
probe->usm_username_len,
probe->usm_engine_boots,
probe->usm_engine_time,
oid_higgs3_access_key,
sizeof(oid_higgs3_access_key),
scratch,
scratch_capacity,
message,
message_capacity,
message_len);
default:
return false;
}
}
bool seader_uhf_snmp_probe_consume_response(
SeaderUhfSnmpProbe* probe,
const uint8_t* response,
size_t response_len) {
SeaderSnmpResponseView view = {0};
SeaderBytesView value = {0};
if(!probe || !seader_snmp_parse_response_view(response, response_len, &view)) {
if(probe) probe->stage = SeaderUhfSnmpProbeStageFailed;
return false;
}
if(view.error_status != 0U) {
probe->stage = SeaderUhfSnmpProbeStageFailed;
return false;
}
switch(probe->stage) {
case SeaderUhfSnmpProbeStageDiscovery:
probe->engine_id = view.context_engine_id;
probe->usm_engine_id_len = view.usm_engine_id.len;
if(probe->usm_engine_id_len > sizeof(probe->usm_engine_id_storage)) {
probe->stage = SeaderUhfSnmpProbeStageFailed;
return false;
}
memcpy(probe->usm_engine_id_storage, view.usm_engine_id.ptr, probe->usm_engine_id_len);
probe->usm_engine_id =
(SeaderBytesView){probe->usm_engine_id_storage, probe->usm_engine_id_len};
probe->usm_username_len = view.usm_username.len;
if(probe->usm_username_len > sizeof(probe->usm_username_storage)) {
probe->stage = SeaderUhfSnmpProbeStageFailed;
return false;
}
memcpy(probe->usm_username_storage, view.usm_username.ptr, probe->usm_username_len);
probe->usm_username =
(SeaderBytesView){probe->usm_username_storage, probe->usm_username_len};
probe->usm_engine_boots = view.usm_engine_boots;
probe->usm_engine_time = view.usm_engine_time;
probe->stage = SeaderUhfSnmpProbeStageReadIce;
return true;
case SeaderUhfSnmpProbeStageReadIce:
if(!seader_snmp_find_varbind_octet_value(
view.varbind_sequence,
(SeaderBytesView){oid_elite_ice, sizeof(oid_elite_ice)},
&value)) {
probe->stage = SeaderUhfSnmpProbeStageFailed;
return false;
}
probe->ice_value_len = value.len;
if(probe->ice_value_len > sizeof(probe->ice_value_storage)) {
probe->stage = SeaderUhfSnmpProbeStageFailed;
return false;
}
memcpy(probe->ice_value_storage, value.ptr, probe->ice_value_len);
probe->ice_value = value;
probe->stage = SeaderUhfSnmpProbeStageReadTagConfig;
return true;
case SeaderUhfSnmpProbeStageReadTagConfig:
if(!seader_snmp_find_varbind_octet_value(
view.varbind_sequence,
(SeaderBytesView){oid_uhf_tags_config, sizeof(oid_uhf_tags_config)},
&value)) {
probe->stage = SeaderUhfSnmpProbeStageFailed;
return false;
}
probe->tag_config_value = value;
{
SeaderUhfTagConfigView tag_config = {0};
if(!seader_uhf_tag_config_parse(value, &tag_config)) {
probe->stage = SeaderUhfSnmpProbeStageFailed;
return false;
}
probe->has_monza4qt = tag_config.has_monza4qt;
probe->has_higgs3 = tag_config.has_higgs3;
}
seader_uhf_snmp_probe_advance_after_tag_config(probe);
return true;
case SeaderUhfSnmpProbeStageReadMonza4QtKey:
probe->monza4qt_key_present =
seader_snmp_find_varbind_octet_value(
view.varbind_sequence,
(SeaderBytesView){oid_monza4qt_access_key, sizeof(oid_monza4qt_access_key)},
&value) &&
value.len > 0U;
seader_uhf_snmp_probe_advance_after_monza(probe);
return true;
case SeaderUhfSnmpProbeStageReadHiggs3Key:
probe->higgs3_key_present =
seader_snmp_find_varbind_octet_value(
view.varbind_sequence,
(SeaderBytesView){oid_higgs3_access_key, sizeof(oid_higgs3_access_key)},
&value) &&
value.len > 0U;
probe->stage = SeaderUhfSnmpProbeStageDone;
return true;
default:
probe->stage = SeaderUhfSnmpProbeStageFailed;
return false;
}
}
bool seader_uhf_snmp_probe_consume_error(
SeaderUhfSnmpProbe* probe,
uint32_t error_code,
const uint8_t* data,
size_t data_len) {
if(!probe) {
return false;
}
if(error_code == 0x06U && data_len >= 2U && data[0] == 0x69U && data[1] == 0x82U) {
if(probe->stage == SeaderUhfSnmpProbeStageReadMonza4QtKey) {
probe->monza4qt_key_present = true;
seader_uhf_snmp_probe_advance_after_monza(probe);
return true;
} else if(probe->stage == SeaderUhfSnmpProbeStageReadHiggs3Key) {
probe->higgs3_key_present = true;
probe->stage = SeaderUhfSnmpProbeStageDone;
return true;
}
}
if(error_code == 0x11U && data_len >= 2U &&
((data[0] == 0x2EU && data[1] == 0x00U) || (data[0] == 0x39U && data[1] == 0x00U))) {
if(probe->stage == SeaderUhfSnmpProbeStageReadMonza4QtKey) {
probe->monza4qt_key_present = false;
seader_uhf_snmp_probe_advance_after_monza(probe);
return true;
} else if(probe->stage == SeaderUhfSnmpProbeStageReadHiggs3Key) {
probe->higgs3_key_present = false;
probe->stage = SeaderUhfSnmpProbeStageDone;
return true;
}
}
probe->stage = SeaderUhfSnmpProbeStageFailed;
return false;
}
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#include "snmp_ber_view.h"
#include "snmp_response_view.h"
#include "uhf_tag_config_view.h"
#define SEADER_UHF_SNMP_MAX_ID_LEN 32U
#define SEADER_UHF_SNMP_MAX_VALUE_LEN 32U
typedef enum {
SeaderUhfSnmpProbeStageIdle = 0,
SeaderUhfSnmpProbeStageDiscovery,
SeaderUhfSnmpProbeStageReadIce,
SeaderUhfSnmpProbeStageReadTagConfig,
SeaderUhfSnmpProbeStageReadMonza4QtKey,
SeaderUhfSnmpProbeStageReadHiggs3Key,
SeaderUhfSnmpProbeStageDone,
SeaderUhfSnmpProbeStageFailed,
} SeaderUhfSnmpProbeStage;
typedef struct {
SeaderUhfSnmpProbeStage stage;
SeaderBytesView engine_id;
SeaderBytesView usm_engine_id;
SeaderBytesView usm_username;
SeaderBytesView ice_value;
SeaderBytesView tag_config_value;
uint32_t usm_engine_boots;
uint32_t usm_engine_time;
bool has_monza4qt;
bool has_higgs3;
bool monza4qt_key_present;
bool higgs3_key_present;
uint8_t usm_engine_id_storage[SEADER_UHF_SNMP_MAX_ID_LEN];
size_t usm_engine_id_len;
uint8_t usm_username_storage[SEADER_UHF_SNMP_MAX_ID_LEN];
size_t usm_username_len;
uint8_t ice_value_storage[SEADER_UHF_SNMP_MAX_VALUE_LEN];
size_t ice_value_len;
} SeaderUhfSnmpProbe;
void seader_uhf_snmp_probe_init(SeaderUhfSnmpProbe* probe);
bool seader_uhf_snmp_probe_build_next_request(
const SeaderUhfSnmpProbe* probe,
uint8_t* scratch,
size_t scratch_capacity,
uint8_t* message,
size_t message_capacity,
size_t* message_len);
bool seader_uhf_snmp_probe_consume_response(
SeaderUhfSnmpProbe* probe,
const uint8_t* response,
size_t response_len);
bool seader_uhf_snmp_probe_consume_error(
SeaderUhfSnmpProbe* probe,
uint32_t error_code,
const uint8_t* data,
size_t data_len);
+130
View File
@@ -0,0 +1,130 @@
#include "uhf_tag_config_view.h"
#include <string.h>
static const uint8_t family_monza4qt[] = {0xE2, 0x80, 0x11, 0x05};
static const uint8_t family_higgs3[] = {0xE2, 0x00, 0x34, 0x12};
static const uint8_t oid_monza4qt_prefix[] =
{0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x01, 0x1EU};
static const uint8_t oid_higgs3_prefix[] =
{0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x01, 0x22U};
static bool seader_uhf_tag_config_match_oid(
const uint8_t* ptr,
size_t len,
const uint8_t* oid,
size_t oid_len) {
return len >= oid_len && memcmp(ptr, oid, oid_len) == 0;
}
static size_t seader_uhf_tag_config_next_entry_offset(SeaderBytesView payload, size_t ordinal) {
size_t offset = 0U;
size_t seen = 0U;
while(offset < payload.len) {
uint8_t tag = payload.ptr[offset++];
size_t value_len = 0U;
if(tag == 0x04U) {
value_len = 4U;
} else if(tag == 0x11U) {
value_len = 17U;
if(seen == ordinal) {
return offset - 1U;
}
seen++;
} else {
return payload.len;
}
if(offset + value_len > payload.len) {
return payload.len;
}
offset += value_len;
}
return payload.len;
}
bool seader_uhf_tag_config_parse(SeaderBytesView payload, SeaderUhfTagConfigView* view) {
size_t offset = 0U;
if(!payload.ptr || payload.len == 0U || !view) return false;
memset(view, 0, sizeof(*view));
view->raw = payload;
view->prefix.ptr = payload.ptr;
while(offset < payload.len) {
uint8_t tag = payload.ptr[offset++];
if(tag == 0x04U) {
if(offset + sizeof(family_monza4qt) > payload.len) {
return false;
}
if(memcmp(payload.ptr + offset, family_monza4qt, sizeof(family_monza4qt)) == 0) {
view->has_monza4qt = true;
view->monza4qt_family_id =
(SeaderBytesView){payload.ptr + offset, sizeof(family_monza4qt)};
} else if(memcmp(payload.ptr + offset, family_higgs3, sizeof(family_higgs3)) == 0) {
view->has_higgs3 = true;
view->higgs3_family_id =
(SeaderBytesView){payload.ptr + offset, sizeof(family_higgs3)};
}
offset += sizeof(family_monza4qt);
} else if(tag == 0x11U) {
if(view->entry_count == 0U) {
view->prefix.len = (offset - 1U) - 0U;
}
if(offset + 17U > payload.len) {
return false;
}
view->entry_count++;
offset += 17U;
} else {
return false;
}
}
if(view->entry_count == 0U) {
view->prefix.len = payload.len;
}
return true;
}
bool seader_uhf_tag_config_get_entry(
const SeaderUhfTagConfigView* view,
size_t index,
SeaderUhfTagConfigEntryView* entry) {
if(!view || !entry || index >= view->entry_count) return false;
memset(entry, 0, sizeof(*entry));
const size_t start = seader_uhf_tag_config_next_entry_offset(view->raw, index);
const size_t next = seader_uhf_tag_config_next_entry_offset(view->raw, index + 1U);
if(start >= view->raw.len) return false;
entry->raw.ptr = view->raw.ptr + start;
entry->raw.len = 18U;
entry->oid.ptr = view->raw.ptr + start + 1U;
entry->oid.len = 17U;
if(next > start + entry->raw.len) {
entry->value.ptr = view->raw.ptr + start + entry->raw.len;
entry->value.len = next - (start + entry->raw.len);
}
if(seader_uhf_tag_config_match_oid(
entry->oid.ptr, entry->oid.len, oid_higgs3_prefix, sizeof(oid_higgs3_prefix))) {
entry->kind = SeaderUhfTagConfigEntryHiggs3Access;
} else if(seader_uhf_tag_config_match_oid(
entry->oid.ptr,
entry->oid.len,
oid_monza4qt_prefix,
sizeof(oid_monza4qt_prefix))) {
entry->kind = SeaderUhfTagConfigEntryMonza4QtAccess;
} else {
entry->kind = SeaderUhfTagConfigEntryUnknown;
}
return true;
}
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include "snmp_ber_view.h"
typedef enum {
SeaderUhfTagConfigEntryUnknown = 0,
SeaderUhfTagConfigEntryHiggs3Access,
SeaderUhfTagConfigEntryMonza4QtAccess,
} SeaderUhfTagConfigEntryKind;
typedef struct {
SeaderBytesView raw;
SeaderBytesView oid;
SeaderBytesView value;
SeaderUhfTagConfigEntryKind kind;
} SeaderUhfTagConfigEntryView;
typedef struct {
SeaderBytesView raw;
SeaderBytesView prefix;
size_t entry_count;
bool has_higgs3;
bool has_monza4qt;
SeaderBytesView higgs3_family_id;
SeaderBytesView monza4qt_family_id;
} SeaderUhfTagConfigView;
bool seader_uhf_tag_config_parse(SeaderBytesView payload, SeaderUhfTagConfigView* view);
bool seader_uhf_tag_config_get_entry(
const SeaderUhfTagConfigView* view,
size_t index,
SeaderUhfTagConfigEntryView* entry);