blob: 82cf63c711cb608a43108d6db089bbf29c185c31 [file] [log] [blame] [edit]
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION &
* AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "device-capability-discovery.h"
#include "base.h"
#include "firmware-utils.h"
#include <endian.h>
#include <stdio.h>
#include <string.h>
static int encode_nsm_get_event_source_req(uint8_t command, uint8_t instance_id,
uint8_t nvidia_message_type,
struct nsm_msg *msg)
{
if (msg == NULL) {
return NSM_SW_ERROR_NULL;
}
struct nsm_header_info header = {NSM_REQUEST, instance_id,
NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY};
uint8_t rc = pack_nsm_header(&header, &msg->hdr);
if (rc != NSM_SUCCESS) {
return rc;
}
struct nsm_get_event_source_req *request =
(struct nsm_get_event_source_req *)msg->payload;
request->hdr.command = command;
request->hdr.data_size = NSM_GET_EVENT_SOURCES_REQ_DATA_SIZE;
request->nvidia_message_type = nvidia_message_type;
return NSM_SW_SUCCESS;
}
int encode_nsm_get_supported_event_source_req(uint8_t instance_id,
uint8_t nvidia_message_type,
struct nsm_msg *msg)
{
return encode_nsm_get_event_source_req(NSM_GET_SUPPORTED_EVENT_SOURCES,
instance_id, nvidia_message_type,
msg);
}
int encode_nsm_get_current_event_source_req(uint8_t instance_id,
uint8_t nvidia_message_type,
struct nsm_msg *msg)
{
return encode_nsm_get_event_source_req(NSM_GET_CURRENT_EVENT_SOURCES,
instance_id, nvidia_message_type,
msg);
}
int decode_nsm_get_event_source_req(const struct nsm_msg *msg, size_t msg_len,
uint8_t *nvidia_message_type)
{
if (msg == NULL || nvidia_message_type == NULL) {
return NSM_SW_ERROR_NULL;
}
struct nsm_header_info header = {0};
uint8_t rc = unpack_nsm_header(&msg->hdr, &header);
if (rc != NSM_SW_SUCCESS) {
return rc;
}
if (msg_len < sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_get_event_source_req)) {
return NSM_SW_ERROR_LENGTH;
}
struct nsm_get_event_source_req *request =
(struct nsm_get_event_source_req *)msg->payload;
*nvidia_message_type = request->nvidia_message_type;
return NSM_SW_SUCCESS;
}
static int encode_nsm_get_event_source_resp(
uint8_t command, uint8_t instance_id, uint8_t cc, uint16_t reason_code,
const bitfield8_t event_sources[EVENT_SOURCES_LENGTH], struct nsm_msg *msg)
{
if (msg == NULL || event_sources == NULL) {
return NSM_SW_ERROR_NULL;
}
struct nsm_header_info header = {NSM_RESPONSE, instance_id,
NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY};
uint8_t rc = pack_nsm_header(&header, &msg->hdr);
if (rc != NSM_SUCCESS) {
return rc;
}
if (cc != NSM_SUCCESS) {
return encode_reason_code(cc, reason_code, command, msg);
}
struct nsm_get_event_source_resp *response =
(struct nsm_get_event_source_resp *)msg->payload;
response->hdr.command = command;
response->hdr.completion_code = cc;
response->hdr.data_size = EVENT_SOURCES_LENGTH;
memcpy(response->event_sources, event_sources, EVENT_SOURCES_LENGTH);
return NSM_SW_SUCCESS;
}
int encode_nsm_get_supported_event_source_resp(
uint8_t instance_id, uint8_t cc, uint16_t reason_code,
const bitfield8_t event_sources[EVENT_SOURCES_LENGTH], struct nsm_msg *msg)
{
return encode_nsm_get_event_source_resp(NSM_GET_SUPPORTED_EVENT_SOURCES,
instance_id, cc, reason_code,
event_sources, msg);
}
int encode_nsm_get_current_event_source_resp(
uint8_t instance_id, uint8_t cc, uint16_t reason_code,
const bitfield8_t event_sources[EVENT_SOURCES_LENGTH], struct nsm_msg *msg)
{
return encode_nsm_get_event_source_resp(NSM_GET_CURRENT_EVENT_SOURCES,
instance_id, cc, reason_code,
event_sources, msg);
}
int decode_nsm_get_event_source_resp(
const struct nsm_msg *msg, size_t msg_len, uint8_t *cc,
uint16_t *reason_code, bitfield8_t event_sources[EVENT_SOURCES_LENGTH])
{
if (msg == NULL || cc == NULL || reason_code == NULL ||
event_sources == NULL) {
return NSM_SW_ERROR_NULL;
}
int rc = decode_reason_code_and_cc(msg, msg_len, cc, reason_code);
if (rc != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) {
return rc;
}
if (msg_len < sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_get_event_source_resp)) {
return NSM_SW_ERROR_LENGTH;
}
struct nsm_get_event_source_resp *response =
(struct nsm_get_event_source_resp *)msg->payload;
memcpy(event_sources, response->event_sources, EVENT_SOURCES_LENGTH);
return NSM_SW_SUCCESS;
}
int encode_nsm_get_event_subscription_req(uint8_t instance_id,
struct nsm_msg *msg)
{
return encode_common_req(instance_id,
NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY,
NSM_GET_EVENT_SUBSCRIPTION, msg);
}
int decode_nsm_get_event_subscription_req(const struct nsm_msg *msg,
size_t msg_len)
{
return decode_common_req(msg, msg_len);
}
int encode_nsm_get_event_subscription_resp(uint8_t instance_id, uint8_t cc,
uint16_t reason_code,
uint8_t receiver_eid,
struct nsm_msg *msg)
{
if (msg == NULL) {
return NSM_SW_ERROR_NULL;
}
struct nsm_header_info header = {NSM_RESPONSE, instance_id,
NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY};
uint8_t rc = pack_nsm_header(&header, &msg->hdr);
if (rc != NSM_SUCCESS) {
return rc;
}
if (cc != NSM_SUCCESS) {
return encode_reason_code(cc, reason_code,
NSM_GET_EVENT_SUBSCRIPTION, msg);
}
struct nsm_get_event_subscription_resp *response =
(struct nsm_get_event_subscription_resp *)msg->payload;
response->hdr.command = NSM_GET_EVENT_SUBSCRIPTION;
response->hdr.completion_code = cc;
response->hdr.data_size = htole16(1);
response->receiver_endpoint_id = receiver_eid;
return NSM_SUCCESS;
}
int decode_nsm_get_event_subscription_resp(const struct nsm_msg *msg,
size_t msg_len, uint8_t *cc,
uint16_t *reason_code,
uint8_t *receiver_eid)
{
if (msg == NULL || receiver_eid == NULL) {
return NSM_SW_ERROR_NULL;
}
struct nsm_header_info header = {0};
uint8_t rc = unpack_nsm_header(&msg->hdr, &header);
if (rc != NSM_SW_SUCCESS) {
return rc;
}
rc = decode_reason_code_and_cc(msg, msg_len, cc, reason_code);
if (rc != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) {
return rc;
}
if (msg_len != sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_get_event_subscription_resp)) {
return NSM_SW_ERROR_LENGTH;
}
struct nsm_get_event_subscription_resp *response =
(struct nsm_get_event_subscription_resp *)msg->payload;
response->hdr.data_size = le16toh(response->hdr.data_size);
if (response->hdr.data_size != 1) {
return NSM_SW_ERROR_LENGTH;
}
*receiver_eid = response->receiver_endpoint_id;
return NSM_SUCCESS;
}
int encode_nsm_set_event_subscription_req(uint8_t instance_id,
uint8_t global_setting,
uint8_t receiver_eid,
struct nsm_msg *msg)
{
if (msg == NULL) {
return NSM_ERR_INVALID_DATA;
}
struct nsm_header_info header = {0};
header.nsm_msg_type = NSM_REQUEST;
header.instance_id = instance_id & 0x1f;
header.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY;
uint8_t rc = pack_nsm_header(&header, &msg->hdr);
if (rc != NSM_SUCCESS) {
return rc;
}
struct nsm_set_event_subscription_req *request =
(struct nsm_set_event_subscription_req *)msg->payload;
request->hdr.command = NSM_SET_EVENT_SUBSCRIPTION;
request->hdr.data_size = NSM_SET_EVENT_SUBSCRIPTION_REQ_DATA_SIZE;
request->global_event_generation_setting = global_setting;
request->receiver_endpoint_id = receiver_eid;
return NSM_SUCCESS;
}
int decode_nsm_set_event_subscription_req(const struct nsm_msg *msg,
size_t msg_len,
uint8_t *global_setting,
uint8_t *receiver_eid)
{
if (msg == NULL || global_setting == NULL || receiver_eid == NULL) {
return NSM_ERR_INVALID_DATA;
}
if (msg_len < sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_set_event_subscription_req)) {
return NSM_ERR_INVALID_DATA_LENGTH;
}
struct nsm_set_event_subscription_req *request =
(struct nsm_set_event_subscription_req *)msg->payload;
if (request->hdr.data_size < NSM_SET_EVENT_SUBSCRIPTION_REQ_DATA_SIZE) {
return NSM_ERR_INVALID_DATA_LENGTH;
}
*global_setting = request->global_event_generation_setting;
*receiver_eid = request->receiver_endpoint_id;
return NSM_SUCCESS;
}
int decode_nsm_set_event_subscription_resp(const struct nsm_msg *msg,
size_t msg_len, uint8_t *cc)
{
if (msg == NULL || cc == NULL) {
return NSM_ERR_INVALID_DATA;
}
if (msg_len < sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_set_event_subscription_resp)) {
return NSM_ERR_INVALID_DATA;
}
struct nsm_set_event_subscription_resp *response =
(struct nsm_set_event_subscription_resp *)msg->payload;
*cc = response->hdr.completion_code;
return NSM_SUCCESS;
}
int encode_nsm_configure_event_acknowledgement_req(
uint8_t instance_id, uint8_t nvidia_message_type,
bitfield8_t *current_event_sources_acknowledgement_mask,
struct nsm_msg *msg)
{
if (msg == NULL) {
return NSM_ERR_INVALID_DATA;
}
struct nsm_header_info header = {0};
header.nsm_msg_type = NSM_REQUEST;
header.instance_id = instance_id & 0x1f;
header.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY;
uint8_t rc = pack_nsm_header(&header, &msg->hdr);
if (rc != NSM_SUCCESS) {
return rc;
}
struct nsm_configure_event_acknowledgement_req *request =
(struct nsm_configure_event_acknowledgement_req *)msg->payload;
request->hdr.command = NSM_CONFIGURE_EVENT_ACKNOWLEDGEMENT;
request->hdr.data_size =
NSM_CONFIGURE_EVENT_ACKNOWLEDGEMENT_REQ_DATA_SIZE;
request->nvidia_message_type = nvidia_message_type;
memcpy(request->current_event_sources_acknowledgement_mask,
current_event_sources_acknowledgement_mask,
EVENT_ACKNOWLEDGEMENT_MASK_LENGTH);
return NSM_SUCCESS;
}
int decode_nsm_configure_event_acknowledgement_req(
const struct nsm_msg *msg, size_t msg_len, uint8_t *nvidia_message_type,
bitfield8_t **current_event_sources_acknowledgement_mask)
{
if (msg == NULL || nvidia_message_type == NULL ||
current_event_sources_acknowledgement_mask == NULL) {
return NSM_ERR_INVALID_DATA;
}
if (msg_len <
sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_configure_event_acknowledgement_req)) {
return NSM_ERR_INVALID_DATA_LENGTH;
}
struct nsm_configure_event_acknowledgement_req *request =
(struct nsm_configure_event_acknowledgement_req *)msg->payload;
if (request->hdr.data_size <
NSM_CONFIGURE_EVENT_ACKNOWLEDGEMENT_REQ_DATA_SIZE) {
return NSM_ERR_INVALID_DATA_LENGTH;
}
*nvidia_message_type = request->nvidia_message_type;
*current_event_sources_acknowledgement_mask =
request->current_event_sources_acknowledgement_mask;
return NSM_SUCCESS;
}
int encode_nsm_configure_event_acknowledgement_resp(
uint8_t instance_id, uint8_t cc,
bitfield8_t *new_event_sources_acknowledgement_mask, struct nsm_msg *msg)
{
if (new_event_sources_acknowledgement_mask == NULL || msg == NULL) {
return NSM_ERR_INVALID_DATA;
}
struct nsm_header_info header = {0};
header.nsm_msg_type = NSM_RESPONSE;
header.instance_id = instance_id & 0x1f;
header.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY;
uint8_t rc = pack_nsm_header(&header, &msg->hdr);
if (rc != NSM_SUCCESS) {
return rc;
}
struct nsm_configure_event_acknowledgement_resp *response =
(struct nsm_configure_event_acknowledgement_resp *)msg->payload;
response->hdr.command = NSM_CONFIGURE_EVENT_ACKNOWLEDGEMENT;
response->hdr.completion_code = cc;
response->hdr.reserved = 0;
response->hdr.data_size = htole16(EVENT_ACKNOWLEDGEMENT_MASK_LENGTH);
memcpy(response->new_event_sources_acknowledgement_mask,
new_event_sources_acknowledgement_mask,
EVENT_ACKNOWLEDGEMENT_MASK_LENGTH);
return NSM_SUCCESS;
}
int decode_nsm_configure_event_acknowledgement_resp(
const struct nsm_msg *msg, size_t msg_len, uint8_t *cc,
bitfield8_t **new_event_sources_acknowledgement_mask)
{
if (msg == NULL || cc == NULL) {
return NSM_ERR_INVALID_DATA;
}
if (msg_len <
sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_configure_event_acknowledgement_resp)) {
return NSM_ERR_INVALID_DATA_LENGTH;
}
struct nsm_configure_event_acknowledgement_resp *response =
(struct nsm_configure_event_acknowledgement_resp *)msg->payload;
*cc = response->hdr.completion_code;
*new_event_sources_acknowledgement_mask =
response->new_event_sources_acknowledgement_mask;
return NSM_SUCCESS;
}
int encode_nsm_set_current_event_sources_req(
uint8_t instance_id, uint8_t nvidia_message_type,
bitfield8_t event_sources[EVENT_SOURCES_LENGTH], struct nsm_msg *msg)
{
if (event_sources == NULL || msg == NULL) {
return NSM_SW_ERROR_NULL;
}
struct nsm_header_info header = {0};
header.nsm_msg_type = NSM_REQUEST;
header.instance_id = instance_id & 0x1f;
header.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY;
uint8_t rc = pack_nsm_header(&header, &msg->hdr);
if (rc != NSM_SUCCESS) {
return rc;
}
struct nsm_set_current_event_source_req *request =
(struct nsm_set_current_event_source_req *)msg->payload;
request->hdr.command = NSM_SET_CURRENT_EVENT_SOURCES;
request->hdr.data_size = NSM_SET_CURRENT_EVENT_SOURCES_REQ_DATA_SIZE;
request->nvidia_message_type = nvidia_message_type;
memcpy(request->event_sources, event_sources, EVENT_SOURCES_LENGTH);
return NSM_SUCCESS;
}
int decode_nsm_set_current_event_sources_req(
const struct nsm_msg *msg, size_t msg_len, uint8_t *nvidia_message_type,
bitfield8_t event_sources[EVENT_SOURCES_LENGTH])
{
if (msg == NULL || nvidia_message_type == NULL ||
event_sources == NULL) {
return NSM_SW_ERROR_NULL;
}
if (msg_len < sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_set_current_event_source_req)) {
return NSM_SW_ERROR_LENGTH;
}
struct nsm_set_current_event_source_req *request =
(struct nsm_set_current_event_source_req *)msg->payload;
if (request->hdr.data_size !=
NSM_SET_CURRENT_EVENT_SOURCES_REQ_DATA_SIZE) {
return NSM_SW_ERROR_LENGTH;
}
*nvidia_message_type = request->nvidia_message_type;
memcpy(event_sources, request->event_sources, EVENT_SOURCES_LENGTH);
return NSM_SUCCESS;
}
int decode_nsm_set_current_event_sources_resp(const struct nsm_msg *msg,
size_t msg_len, uint8_t *cc)
{
if (msg == NULL || cc == NULL) {
return NSM_ERR_INVALID_DATA;
}
if (msg_len < sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_set_current_event_source_resp)) {
return NSM_ERR_INVALID_DATA_LENGTH;
}
struct nsm_set_current_event_source_resp *response =
(struct nsm_set_current_event_source_resp *)msg->payload;
*cc = response->hdr.completion_code;
return NSM_SUCCESS;
}
int encode_nsm_get_event_log_record_req(uint8_t instance_id,
uint8_t selector_type,
uint32_t selector, struct nsm_msg *msg)
{
if (msg == NULL) {
return NSM_ERR_INVALID_DATA;
}
struct nsm_header_info header = {0};
header.nsm_msg_type = NSM_REQUEST;
header.instance_id = instance_id & 0x1f;
header.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY;
uint8_t rc = pack_nsm_header(&header, &msg->hdr);
if (rc != NSM_SUCCESS) {
return rc;
}
struct nsm_get_event_log_record_req *request =
(struct nsm_get_event_log_record_req *)msg->payload;
request->hdr.command = NSM_GET_EVENT_LOG_RECORD;
request->hdr.data_size = 5;
request->selector_type = selector_type;
request->selector = htole32(selector);
return NSM_SUCCESS;
}
int decode_nsm_get_event_log_record_resp(
const struct nsm_msg *msg, size_t msg_len, uint8_t *cc,
uint8_t *nvidia_message_type, uint8_t *event_id, uint32_t *event_handle,
uint64_t *timestamp, uint8_t **payload, uint16_t *payload_len)
{
if (msg == NULL || cc == NULL) {
return NSM_ERR_INVALID_DATA;
}
if (msg_len < sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_get_event_log_record_resp) - 1) {
return NSM_ERR_INVALID_DATA_LENGTH;
}
struct nsm_get_event_log_record_resp *response =
(struct nsm_get_event_log_record_resp *)msg->payload;
*cc = response->hdr.completion_code;
*nvidia_message_type = response->nvidia_message_type;
*event_id = response->event_id;
*event_handle = le32toh(response->event_handle);
*timestamp = le64toh(response->timestamp);
uint16_t data_size = le16toh(response->hdr.data_size);
if (data_size > NSM_GET_EVENT_LOG_RECORD_RESP_MIN_DATA_SIZE) {
*payload = response->payload;
*payload_len =
data_size - NSM_GET_EVENT_LOG_RECORD_RESP_MIN_DATA_SIZE;
}
return NSM_SUCCESS;
}
int encode_nsm_rediscovery_event(uint8_t instance_id, bool ackr,
struct nsm_msg *msg)
{
return encode_nsm_event(instance_id,
NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY, ackr,
NSM_EVENT_VERSION, NSM_REDISCOVERY_EVENT,
NSM_GENERAL_EVENT_CLASS, 0, 0, NULL, msg);
}
int decode_nsm_rediscovery_event(const struct nsm_msg *msg, size_t msg_len,
uint8_t *event_class, uint16_t *event_state)
{
if (msg == NULL || event_class == NULL || event_state == NULL) {
return NSM_ERR_INVALID_DATA;
}
if (msg_len < sizeof(struct nsm_msg_hdr) + NSM_EVENT_MIN_LEN) {
return NSM_ERR_INVALID_DATA_LENGTH;
}
struct nsm_event *event = (struct nsm_event *)msg->payload;
if (event->data_size > 0) {
return NSM_ERR_INVALID_DATA_LENGTH;
}
*event_class = event->event_class;
*event_state = le16toh(event->event_state);
return NSM_SUCCESS;
}
int encode_nsm_get_device_capabilities_v2_req(uint8_t instance_id,
struct nsm_msg *msg)
{
if (msg == NULL) {
return NSM_SW_ERROR_NULL;
}
struct nsm_header_info header = {0};
header.nsm_msg_type = NSM_REQUEST;
header.instance_id = instance_id & 0x1f;
header.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY;
uint8_t rc = pack_nsm_header(&header, &msg->hdr);
if (rc != NSM_SW_SUCCESS) {
return rc;
}
struct nsm_get_device_capabilities_v2_req *request =
(struct nsm_get_device_capabilities_v2_req *)msg->payload;
request->hdr.command = NSM_GET_DEVICE_CAPABILITIES_V2;
request->hdr.data_size = 0;
return NSM_SW_SUCCESS;
}
int decode_nsm_get_device_capabilities_v2_req(const struct nsm_msg *msg,
size_t msg_len)
{
if (msg == NULL) {
return NSM_SW_ERROR_NULL;
}
if (msg_len < sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_get_device_capabilities_v2_req)) {
return NSM_SW_ERROR_LENGTH;
}
return NSM_SW_SUCCESS;
}
int encode_nsm_get_device_capabilities_v2_resp(
uint8_t instance_id, uint8_t cc, uint16_t reason_code,
uint8_t timestamp_generation, uint32_t maximum_input_buffer_size,
struct nsm_msg *msg)
{
if (msg == NULL) {
return NSM_SW_ERROR_NULL;
}
struct nsm_header_info header = {0};
header.nsm_msg_type = NSM_RESPONSE;
header.instance_id = instance_id & 0x1f;
header.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY;
uint8_t rc = pack_nsm_header(&header, &msg->hdr);
if (rc != NSM_SW_SUCCESS) {
return rc;
}
if (cc != NSM_SUCCESS) {
return encode_reason_code(cc, reason_code,
NSM_GET_DEVICE_CAPABILITIES_V2, msg);
}
struct nsm_get_device_capabilities_v2_resp *response =
(struct nsm_get_device_capabilities_v2_resp *)msg->payload;
response->hdr.command = NSM_GET_DEVICE_CAPABILITIES_V2;
response->hdr.completion_code = cc;
uint16_t telemetry_count = 0;
uint16_t msg_size = sizeof(struct nsm_common_telemetry_resp);
uint8_t *data = &(response->payload[0]);
encode_nsm_firmware_aggregate_tag_uint8(
&data, NSM_TAG_TIMESTAMP_GENERATION, timestamp_generation,
&msg_size);
++telemetry_count;
encode_nsm_firmware_aggregate_tag_uint32(
&data, NSM_TAG_MAXIMUM_INPUT_BUFFER_SIZE, maximum_input_buffer_size,
&msg_size);
++telemetry_count;
response->hdr.telemetry_count = htole16(telemetry_count);
return NSM_SW_SUCCESS;
}
int decode_nsm_get_device_capabilities_v2_resp(
const struct nsm_msg *msg, size_t msg_len, uint8_t *cc,
uint16_t *reason_code, uint8_t *timestamp_generation,
uint32_t *maximum_input_buffer_size)
{
if (msg == NULL || cc == NULL || reason_code == NULL ||
timestamp_generation == NULL || maximum_input_buffer_size == NULL) {
return NSM_SW_ERROR_NULL;
}
if (msg_len < sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_firmware_aggregate_tag)) {
return NSM_SW_ERROR_LENGTH;
}
int rc = decode_reason_code_and_cc(msg, msg_len, cc, reason_code);
if (rc != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) {
return rc;
}
struct nsm_get_device_capabilities_v2_resp *response =
(struct nsm_get_device_capabilities_v2_resp *)msg->payload;
if (response->hdr.telemetry_count < 2) {
return NSM_SW_ERROR_LENGTH;
}
uint16_t telemetry_count = le16toh(response->hdr.telemetry_count);
uint8_t *data = &(response->payload[0]);
uint16_t data_len = (uint16_t)msg_len - sizeof(struct nsm_msg_hdr) -
sizeof(struct nsm_common_telemetry_resp);
uint8_t tag = 0;
uint8_t valid = 0;
bool rc_ok = false;
while ((data_len >= sizeof(struct nsm_firmware_aggregate_tag)) &&
(telemetry_count > 0)) {
struct nsm_firmware_aggregate_tag *field =
(struct nsm_firmware_aggregate_tag *)data;
tag = field->tag;
if (tag == NSM_TAG_TIMESTAMP_GENERATION) {
uint8_t value8 = 0;
rc_ok = decode_nsm_firmware_aggregate_tag_uint8(
&data, &tag, &valid, &value8, &data_len);
if (rc_ok) {
--telemetry_count;
*timestamp_generation = value8;
}
} else if (tag == NSM_TAG_MAXIMUM_INPUT_BUFFER_SIZE) {
uint32_t value32 = 0;
rc_ok = decode_nsm_firmware_aggregate_tag_uint32(
&data, &tag, &valid, &value32, &data_len);
if (rc_ok) {
--telemetry_count;
*maximum_input_buffer_size = value32;
}
} else {
rc_ok = decode_nsm_firmware_aggregate_tag_skip(
&data, &data_len);
if (rc_ok) {
--telemetry_count;
}
}
if (!rc_ok || !valid) {
return NSM_SW_ERROR_DATA;
}
}
return NSM_SW_SUCCESS;
}