blob: 74180673c4d0d74f0a3accb9117e793cd169422d [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.
*/
// NSM: Nvidia Message type
// - Diagnostics [Type 4]
#include "nsm_diag_cmd.hpp"
#include "base.h"
#include "debug-token.h"
#include "debug-token/error.h"
#include "debug-token/tlv.h"
#include "debug-token/types.h"
#include "diagnostics.h"
#include "platform-environmental.h"
#include "cmd_helper.hpp"
#include "nsm_base.hpp"
#include "utils.hpp"
#include <CLI/CLI.hpp>
#include <ctime>
namespace nsmtool
{
namespace diag
{
namespace
{
using namespace nsmtool::helper;
std::vector<std::unique_ptr<CommandInterface>> commands;
} // namespace
class GetDeviceDiagnostics : public CommandInterface
{
public:
GetDeviceDiagnostics() = delete;
GetDeviceDiagnostics(const GetDeviceDiagnostics&) = delete;
GetDeviceDiagnostics(GetDeviceDiagnostics&&) = default;
GetDeviceDiagnostics& operator=(const GetDeviceDiagnostics&) = delete;
GetDeviceDiagnostics& operator=(GetDeviceDiagnostics&&) = default;
using CommandInterface::CommandInterface;
explicit GetDeviceDiagnostics(const char* type, const char* name,
CLI::App* app) :
CommandInterface(type, name, app)
{
app->add_option("-s, --segmentId", segment_id, "Segment Id")
->required();
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_get_device_diagnostics_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_get_device_diagnostics_req(instanceId, segment_id,
request);
return {rc, requestMsg};
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_ERROR;
std::vector<uint8_t> seg_data(65535, 0);
uint16_t seg_data_size;
uint8_t next_segment_id;
uint16_t reason_code;
auto rc = decode_get_device_diagnostics_resp(
responsePtr, payloadLength, &cc, &reason_code, seg_data.data(),
&seg_data_size, &next_segment_id);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reason_code << "\n"
<< payloadLength << "...."
<< (sizeof(struct nsm_msg_hdr) +
sizeof(struct nsm_get_device_diagnostics_resp));
}
ordered_json result;
result["Completion Code"] = cc;
result["Segment Data Size"] = seg_data_size;
result["Next Segment Id"] = next_segment_id;
result["Segment Data"] = std::string(
std::bit_cast<const char*>(seg_data.data()), seg_data_size);
nsmtool::helper::DisplayInJson(result);
}
private:
uint8_t segment_id;
};
class QueryTokenParameters : public CommandInterface
{
public:
~QueryTokenParameters() = default;
QueryTokenParameters() = delete;
QueryTokenParameters(const QueryTokenParameters&) = delete;
QueryTokenParameters(QueryTokenParameters&&) = default;
QueryTokenParameters& operator=(const QueryTokenParameters&) = delete;
QueryTokenParameters& operator=(QueryTokenParameters&&) = default;
using CommandInterface::CommandInterface;
explicit QueryTokenParameters(const char* type, const char* name,
CLI::App* app) :
CommandInterface(type, name, app)
{
auto ccOptionGroup = app->add_option_group(
"Required",
"Query token parameters for the specified token opcode");
ccOptionGroup->add_option(
"-o,--opcode", tokenOpcode,
"query token parameters for the specified token opcode");
ccOptionGroup->require_option(1);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_query_token_parameters_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_nsm_query_token_parameters_req(
instanceId, static_cast<nsm_debug_token_opcode>(tokenOpcode),
request);
return std::make_pair(rc, requestMsg);
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reason_code = ERR_NULL;
struct nsm_debug_token_request token_request;
auto rc = decode_nsm_query_token_parameters_resp(
responsePtr, payloadLength, &cc, &reason_code, &token_request);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reason_code << "\n";
return;
}
nlohmann::ordered_json result;
result["Completion code"] = cc;
result["Reason code"] = reason_code;
result["Token request version"] =
static_cast<uint32_t>(token_request.token_request_version);
result["Token request size"] =
static_cast<uint32_t>(token_request.token_request_size);
result["Device UUID"] = bytesToHexString(token_request.device_uuid, 8);
switch (token_request.device_type)
{
case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_EROT:
result["Device type"] = "ERoT";
break;
case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_GPU:
result["Device type"] = "GPU";
break;
case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_NVSWITCH:
result["Device type"] = "NVSwitch";
break;
case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_CX7:
result["Device type"] = "CX7";
break;
case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_MCU:
result["Device type"] = "MCU";
break;
case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_CX8:
result["Device type"] = "CX8";
break;
default:
result["Device type"] =
"Invalid value: " +
std::to_string(token_request.device_type);
break;
}
result["Device index"] =
static_cast<uint32_t>(token_request.device_index);
switch (token_request.status)
{
case NSM_DEBUG_TOKEN_CHALLENGE_QUERY_STATUS_OK:
result["Status"] = "OK";
break;
case NSM_DEBUG_TOKEN_CHALLENGE_QUERY_STATUS_TOKEN_ALREADY_APPLIED:
result["Status"] = "Token already applied";
break;
case NSM_DEBUG_TOKEN_CHALLENGE_QUERY_STATUS_TOKEN_NOT_SUPPORTED:
result["Status"] = "Token not supported";
break;
case NSM_DEBUG_TOKEN_CHALLENGE_QUERY_STATUS_NO_KEY_CONFIGURED:
result["Status"] = "No key configured";
break;
case NSM_DEBUG_TOKEN_CHALLENGE_QUERY_STATUS_INTERFACE_NOT_ALLOWED:
result["Status"] = "Interface not allowed";
break;
default:
result["Status"] = "Invalid value: " +
std::to_string(token_request.status);
break;
}
switch (token_request.token_opcode)
{
case NSM_DEBUG_TOKEN_OPCODE_RMCS:
result["Token opcode"] = "RMCS";
break;
case NSM_DEBUG_TOKEN_OPCODE_RMDT:
result["Token opcode"] = "RMDT";
break;
case NSM_DEBUG_TOKEN_OPCODE_CRCS:
result["Token opcode"] = "CRCS";
break;
case NSM_DEBUG_TOKEN_OPCODE_CRDT:
result["Token opcode"] = "CRDT";
break;
case NSM_DEBUG_TOKEN_OPCODE_LINKX_FRC:
result["Token opcode"] = "LINKX_FRC";
break;
default:
result["Token opcode"] =
"Invalid value: " +
std::to_string(token_request.token_opcode);
break;
}
result["Keypair UUID"] = bytesToHexString(token_request.keypair_uuid,
16);
result["Base MAC"] = bytesToHexString(token_request.base_mac, 8);
result["PSID"] = bytesToHexString(token_request.psid, 16);
result["FW version"] = std::to_string(token_request.fw_version[0]) +
"." +
std::to_string(token_request.fw_version[1] << 8 |
token_request.fw_version[2]) +
"." +
std::to_string(token_request.fw_version[3] << 8 |
token_request.fw_version[4]);
result["Source address"] =
bytesToHexString(token_request.source_address, 16);
result["Session ID"] = static_cast<uint32_t>(token_request.session_id);
result["Challenge version"] = token_request.challenge_version;
result["Challenge"] = bytesToHexString(token_request.challenge, 32);
DisplayInJson(result);
}
private:
uint8_t tokenOpcode;
};
/** @class QueryResetStatistics
* @brief Command to query reset statistics.
*/
class QueryResetStatistics : public CommandInterface
{
public:
~QueryResetStatistics() = default;
QueryResetStatistics() = delete;
QueryResetStatistics(const QueryResetStatistics&) = delete;
QueryResetStatistics(QueryResetStatistics&&) = default;
QueryResetStatistics& operator=(const QueryResetStatistics&) = delete;
QueryResetStatistics& operator=(QueryResetStatistics&&) = default;
using CommandInterface::CommandInterface;
private:
class QueryResetMetricsAggregateResponseParser :
public AggregateResponseParser
{
private:
int handleSampleData(uint8_t tag, const uint8_t* data, size_t data_len,
ordered_json& sample_json) final
{
// Static member initialization
const std::unordered_map<uint8_t, std::string> tagToPropertyMap = {
{0, "PF_FLR_ResetEntryCount"},
{1, "PF_FLR_ResetExitCount"},
{2, "ConventionalResetEntryCount"},
{3, "ConventionalResetExitCount"},
{4, "FundamentalResetEntryCount"},
{5, "FundamentalResetExitCount"},
{6, "IRoTResetExitCount"},
{7, "LastResetType"},
{8, "BootReason"}};
auto it = tagToPropertyMap.find(tag);
if (it == tagToPropertyMap.end())
{
// Unknown tag; skip processing
return NSM_SW_ERROR_DATA;
}
const std::string& property = it->second;
// Handle LastResetType (enum8)
if (property == "LastResetType")
{
uint8_t resetType;
if (decode_reset_enum_data(data, data_len, &resetType) !=
NSM_SW_SUCCESS)
{
return NSM_SW_ERROR_LENGTH;
}
// Include the tag in the JSON
sample_json["Tag"] = static_cast<int>(tag);
sample_json["Property"] = property;
sample_json["Value"] = resetType;
}
else if (property == "BootReason")
{
// Handle boot reason counter (uint64_t)
std::array<uint64_t, 4> counterVal;
if (decode_reset_count_256data(
data, data_len, counterVal.data(), counterVal.size()) !=
NSM_SW_SUCCESS)
{
return NSM_SW_ERROR_LENGTH;
}
// Include the tag in the JSON
sample_json["Tag"] = static_cast<int>(tag);
sample_json["Property"] = property;
sample_json["Value0to63"] = counterVal[0];
sample_json["Value64to127"] = counterVal[1];
sample_json["Value128to191"] = counterVal[2];
sample_json["Value192to255"] = counterVal[3];
}
else
{
// Handle reset count (uint16_t)
uint16_t count;
if (decode_reset_count_data(data, data_len, &count) !=
NSM_SW_SUCCESS)
{
return NSM_SW_ERROR_LENGTH;
}
// Include the tag in the JSON
sample_json["Tag"] = static_cast<int>(tag);
sample_json["Property"] = property;
sample_json["Value"] = count;
}
return NSM_SW_SUCCESS;
}
};
public:
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_req));
auto requestPtr = reinterpret_cast<nsm_msg*>(requestMsg.data());
// Encode the request message
auto rc = encode_get_device_reset_statistics_req(instanceId,
requestPtr);
return {rc, requestMsg};
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
QueryResetMetricsAggregateResponseParser{}.parseAggregateResponse(
responsePtr, payloadLength);
}
};
class ProvideToken : public CommandInterface
{
public:
~ProvideToken() = default;
ProvideToken() = delete;
ProvideToken(const ProvideToken&) = delete;
ProvideToken(ProvideToken&&) = default;
ProvideToken& operator=(const ProvideToken&) = delete;
ProvideToken& operator=(ProvideToken&&) = default;
using CommandInterface::CommandInterface;
explicit ProvideToken(const char* type, const char* name, CLI::App* app) :
CommandInterface(type, name, app)
{
auto ccOptionGroup =
app->add_option_group("Required", "Install specified token data");
ccOptionGroup->add_option(
"-t,--token", tokenHexstring,
"hexadecimal string containing token data to be installed");
ccOptionGroup->require_option(1);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_req_v2) +
tokenHexstring.size() / 2);
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
std::vector<uint8_t> token;
for (size_t i = 0; i < tokenHexstring.length(); i += 2)
{
std::string byteString = tokenHexstring.substr(i, 2);
uint8_t byte = (uint8_t)strtoul(byteString.c_str(), NULL, 16);
token.push_back(byte);
}
auto rc = encode_nsm_provide_token_req(instanceId, token.data(),
token.size(), request);
return std::make_pair(rc, requestMsg);
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reason_code = ERR_NULL;
auto rc = decode_nsm_provide_token_resp(responsePtr, payloadLength, &cc,
&reason_code);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reason_code << "\n";
return;
}
nlohmann::ordered_json result;
result["Completion code"] = cc;
result["Reason code"] = reason_code;
DisplayInJson(result);
}
private:
std::string tokenHexstring;
};
class DisableTokens : public CommandInterface
{
public:
~DisableTokens() = default;
DisableTokens() = delete;
DisableTokens(const DisableTokens&) = delete;
DisableTokens(DisableTokens&&) = default;
DisableTokens& operator=(const DisableTokens&) = delete;
DisableTokens& operator=(DisableTokens&&) = default;
using CommandInterface::CommandInterface;
explicit DisableTokens(const char* type, const char* name, CLI::App* app) :
CommandInterface(type, name, app)
{}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_disable_tokens_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_nsm_disable_tokens_req(instanceId, request);
return std::make_pair(rc, requestMsg);
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reason_code = ERR_NULL;
auto rc = decode_nsm_disable_tokens_resp(responsePtr, payloadLength,
&cc, &reason_code);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reason_code << "\n";
return;
}
nlohmann::ordered_json result;
result["Completion code"] = cc;
result["Reason code"] = reason_code;
DisplayInJson(result);
}
};
class QueryTokenStatus : public CommandInterface
{
public:
~QueryTokenStatus() = default;
QueryTokenStatus() = delete;
QueryTokenStatus(const QueryTokenStatus&) = delete;
QueryTokenStatus(QueryTokenStatus&&) = default;
QueryTokenStatus& operator=(const QueryTokenStatus&) = delete;
QueryTokenStatus& operator=(QueryTokenStatus&&) = default;
using CommandInterface::CommandInterface;
explicit QueryTokenStatus(const char* type, const char* name,
CLI::App* app) : CommandInterface(type, name, app)
{
auto ccOptionGroup = app->add_option_group(
"Required", "Query token status for the specified token type");
ccOptionGroup->add_option(
"-t,--type", tokenType,
"query token status for the specified token type");
ccOptionGroup->require_option(1);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_query_token_status_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_nsm_query_token_status_req(
instanceId, static_cast<nsm_debug_token_type>(tokenType), request);
return std::make_pair(rc, requestMsg);
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reason_code = ERR_NULL;
nsm_debug_token_status status;
nsm_debug_token_status_additional_info additionalInfo;
nsm_debug_token_type tokenType;
uint32_t timeLeft;
auto rc = decode_nsm_query_token_status_resp(
responsePtr, payloadLength, &cc, &reason_code, &status,
&additionalInfo, &tokenType, &timeLeft);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reason_code << "\n";
return;
}
nlohmann::ordered_json result;
result["Completion code"] = cc;
result["Reason code"] = reason_code;
switch (status)
{
case NSM_DEBUG_TOKEN_STATUS_DEBUG_SESSION_ENDED:
result["Status"] = "Debug session ended";
break;
case NSM_DEBUG_TOKEN_STATUS_OPERATION_FAILURE:
result["Status"] = "Operation failure";
break;
case NSM_DEBUG_TOKEN_STATUS_DEBUG_SESSION_ACTIVE:
result["Status"] = "Debug session active";
break;
case NSM_DEBUG_TOKEN_STATUS_NO_TOKEN_APPLIED:
result["Status"] = "No token applied";
break;
case NSM_DEBUG_TOKEN_STATUS_CHALLENGE_PROVIDED:
result["Status"] = "Challenge provided";
break;
case NSM_DEBUG_TOKEN_STATUS_INSTALLATION_TIMEOUT:
result["Status"] = "Installation timeout";
break;
case NSM_DEBUG_TOKEN_STATUS_TOKEN_TIMEOUT:
result["Status"] = "Token timeout";
break;
default:
result["Status"] = "Invalid value: " + std::to_string(status);
break;
}
switch (additionalInfo)
{
case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_NONE:
result["Additional info"] = "None";
break;
case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_NO_DEBUG_SESSION:
result["Additional info"] = "No debug session";
break;
case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_FIRMWARE_NOT_SECURED:
result["Additional info"] = "Firmware not secured";
break;
case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_DEBUG_SESSION_END_REQUEST_NOT_ACCEPTED:
result["Additional info"] =
"Debug session end request not accepted";
break;
case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_DEBUG_SESSION_QUERY_DISALLOWED:
result["Additional info"] = "Debug session query disallowed";
break;
case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_DEBUG_SESSION_ACTIVE:
result["Additional info"] = "Debug session active";
break;
default:
result["Additional info"] = "Invalid value: " +
std::to_string(additionalInfo);
break;
}
switch (tokenType)
{
case NSM_DEBUG_TOKEN_TYPE_FRC:
result["Token type"] = "FRC";
break;
case NSM_DEBUG_TOKEN_TYPE_CRCS:
result["Token type"] = "CRCS";
break;
case NSM_DEBUG_TOKEN_TYPE_CRDT:
result["Token type"] = "CRDT";
break;
case NSM_DEBUG_TOKEN_TYPE_DEBUG_FIRMWARE:
result["Token type"] = "Debug firmware";
break;
default:
result["Token type"] = "Invalid value: " +
std::to_string(tokenType);
break;
}
result["Time left"] = timeLeft;
DisplayInJson(result);
}
private:
uint8_t tokenType;
};
class QueryDeviceIds : public CommandInterface
{
public:
~QueryDeviceIds() = default;
QueryDeviceIds() = delete;
QueryDeviceIds(const QueryDeviceIds&) = delete;
QueryDeviceIds(QueryDeviceIds&&) = default;
QueryDeviceIds& operator=(const QueryDeviceIds&) = delete;
QueryDeviceIds& operator=(QueryDeviceIds&&) = default;
using CommandInterface::CommandInterface;
explicit QueryDeviceIds(const char* type, const char* name, CLI::App* app) :
CommandInterface(type, name, app)
{}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_query_device_ids_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_nsm_query_device_ids_req(instanceId, request);
return std::make_pair(rc, requestMsg);
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reason_code = ERR_NULL;
size_t device_id_len;
auto rc = decode_nsm_query_device_ids_resp(responsePtr, payloadLength,
&cc, &reason_code, nullptr,
&device_id_len);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reason_code << "\n";
return;
}
std::vector<uint8_t> device_id(device_id_len);
rc = decode_nsm_query_device_ids_resp(responsePtr, payloadLength, &cc,
&reason_code, device_id.data(),
&device_id_len);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reason_code << "\n";
return;
}
nlohmann::ordered_json result;
result["Completion code"] = cc;
result["Reason code"] = reason_code;
result["Device ID"] = bytesToHexString(device_id.data(), device_id_len);
DisplayInJson(result);
}
};
class EnableDisableWriteProtected : public CommandInterface
{
public:
~EnableDisableWriteProtected() = default;
EnableDisableWriteProtected() = delete;
EnableDisableWriteProtected(const EnableDisableWriteProtected&) = delete;
EnableDisableWriteProtected(EnableDisableWriteProtected&&) = default;
EnableDisableWriteProtected&
operator=(const EnableDisableWriteProtected&) = delete;
EnableDisableWriteProtected&
operator=(EnableDisableWriteProtected&&) = default;
using CommandInterface::CommandInterface;
explicit EnableDisableWriteProtected(const char* type, const char* name,
CLI::App* app) :
CommandInterface(type, name, app)
{
auto writeProtectedGroup = app->add_option_group(
"Required",
"Data Index and Value for which write protected will be set.");
dataId = 0;
writeProtectedGroup->add_option(
"-d, --dataId", dataId,
"Data Index of write protected:\n"
"128: Retimer EEPROM\n"
"129: Baseboard FRU EEPROM\n"
"130: PEX SW EEPROM\n"
"131: NvSWs EEPROM\n"
"133: NvSW EEPROM 1\n"
"134: NvSW EEPROM 2\n"
"160: GPUs 1-4 SPI Flash\n"
"161: GPUs 5-8 SPI Flash\n"
"162-169: Individual GPU SPI flash 1-8\n"
"170: GPUs SPI Flash\n"
"176: HMC SPI Flash\n"
"183: CX8s SPI Flash\n"
"192-199: Retimer EEPROM 1-8\n"
"224-231: CPU SPI Flash 1-8\n"
"232: CX7 FRU EEPROM\n"
"233: HMC FRU EEPROM\n");
value = 0;
writeProtectedGroup->add_option("-V, --value", value,
"Disable - 0 / Enable - 1");
writeProtectedGroup->require_option(2);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_enable_disable_wp_req));
int rc = NSM_SW_ERROR;
switch ((diagnostics_enable_disable_wp_data_index)dataId)
{
case RETIMER_EEPROM:
case BASEBOARD_FRU_EEPROM:
case PEX_SW_EEPROM:
case NVSW_EEPROM_BOTH:
case NVSW_EEPROM_1:
case NVSW_EEPROM_2:
case GPU_1_4_SPI_FLASH:
case GPU_5_8_SPI_FLASH:
case GPU_SPI_FLASH_1:
case GPU_SPI_FLASH_2:
case GPU_SPI_FLASH_3:
case GPU_SPI_FLASH_4:
case GPU_SPI_FLASH_5:
case GPU_SPI_FLASH_6:
case GPU_SPI_FLASH_7:
case GPU_SPI_FLASH_8:
case GPU_SPI_FLASH:
case HMC_SPI_FLASH:
case CX8_SPI_FLASH:
case RETIMER_EEPROM_1:
case RETIMER_EEPROM_2:
case RETIMER_EEPROM_3:
case RETIMER_EEPROM_4:
case RETIMER_EEPROM_5:
case RETIMER_EEPROM_6:
case RETIMER_EEPROM_7:
case RETIMER_EEPROM_8:
case CPU_SPI_FLASH_1:
case CPU_SPI_FLASH_2:
case CPU_SPI_FLASH_3:
case CPU_SPI_FLASH_4:
case CPU_SPI_FLASH_5:
case CPU_SPI_FLASH_6:
case CPU_SPI_FLASH_7:
case CPU_SPI_FLASH_8:
case CX7_FRU_EEPROM:
case HMC_FRU_EEPROM:
{
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
rc = encode_enable_disable_wp_req(
instanceId,
(diagnostics_enable_disable_wp_data_index)dataId, value,
request);
}
break;
default:
std::cerr << "Invalid Data Id \n";
break;
}
return {rc, requestMsg};
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_ERROR;
uint16_t reason_code = ERR_NULL;
auto rc = decode_enable_disable_wp_resp(responsePtr, payloadLength, &cc,
&reason_code);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reason_code << "\n"
<< payloadLength << "...."
<< (sizeof(nsm_msg_hdr) + sizeof(nsm_common_resp));
return;
}
ordered_json result;
result["Completion Code"] = cc;
nsmtool::helper::DisplayInJson(result);
}
private:
uint8_t dataId;
uint8_t value;
};
class ResetNetworkDevice : public CommandInterface
{
public:
~ResetNetworkDevice() = default;
ResetNetworkDevice() = delete;
ResetNetworkDevice(const ResetNetworkDevice&) = delete;
ResetNetworkDevice(ResetNetworkDevice&&) = default;
ResetNetworkDevice& operator=(const ResetNetworkDevice&) = delete;
ResetNetworkDevice& operator=(ResetNetworkDevice&&) = default;
using CommandInterface::CommandInterface;
explicit ResetNetworkDevice(const char* type, const char* name,
CLI::App* app) :
CommandInterface(type, name, app)
{
auto resetNDOptionGroup = app->add_option_group(
"Required", "Mode for reseting the network device.");
mode = 0;
resetNDOptionGroup->add_option(
"-M, --mode", mode, "set mode while resetting network device");
resetNDOptionGroup->require_option(1);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_reset_network_device_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_reset_network_device_req(instanceId, mode, request);
return {rc, requestMsg};
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reason_code = ERR_NULL;
auto rc = decode_reset_network_device_resp(responsePtr, payloadLength,
&cc, &reason_code);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reason_code << "\n";
return;
}
ordered_json result;
result["Completion Code"] = cc;
nsmtool::helper::DisplayInJson(result);
}
private:
uint8_t mode;
};
class GetNetworkDeviceDebugInfo : public CommandInterface
{
public:
~GetNetworkDeviceDebugInfo() = default;
GetNetworkDeviceDebugInfo() = delete;
GetNetworkDeviceDebugInfo(const GetNetworkDeviceDebugInfo&) = delete;
GetNetworkDeviceDebugInfo(GetNetworkDeviceDebugInfo&&) = default;
GetNetworkDeviceDebugInfo&
operator=(const GetNetworkDeviceDebugInfo&) = delete;
GetNetworkDeviceDebugInfo& operator=(GetNetworkDeviceDebugInfo&&) = default;
using CommandInterface::CommandInterface;
explicit GetNetworkDeviceDebugInfo(const char* type, const char* name,
CLI::App* app) :
CommandInterface(type, name, app)
{
auto getNetworkDeviceDebugInfoOptionGroup = app->add_option_group(
"Required", "Get network device debug information options.");
debugInfoType = 0;
recordHandle = 0;
getNetworkDeviceDebugInfoOptionGroup->add_option(
"-t, --debugInfoType", debugInfoType,
"Debug information type [0-Device info, 1-FW runtime data, 2-FW saved dump info and 3-Device dump]");
getNetworkDeviceDebugInfoOptionGroup->add_option(
"-r, --recordHandle", recordHandle,
"Record handle for fetching the debug info chunk.");
getNetworkDeviceDebugInfoOptionGroup->require_option(2);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(
sizeof(nsm_msg_hdr) +
sizeof(nsm_get_network_device_debug_info_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_get_network_device_debug_info_req(
instanceId, debugInfoType, recordHandle, request);
return {rc, requestMsg};
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reasonCode = ERR_NULL;
uint16_t segDataSize = 0;
uint32_t nextHandle = 0;
std::vector<uint8_t> segData(65535, 0);
auto rc = decode_get_network_device_debug_info_resp(
responsePtr, payloadLength, &cc, &reasonCode, &segDataSize,
segData.data(), &nextHandle);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reasonCode << "\n";
return;
}
ordered_json result;
result["Completion code"] = cc;
result["Segment Data Length"] = static_cast<uint16_t>(segDataSize);
result["Next Record Handle"] = static_cast<uint32_t>(nextHandle);
if (segDataSize != 0)
result["Segment Data"] = "Data received";
else
result["Segment Data"] = "No data received";
nsmtool::helper::DisplayInJson(result);
}
private:
uint8_t debugInfoType;
uint32_t recordHandle;
};
class EraseTrace : public CommandInterface
{
public:
~EraseTrace() = default;
EraseTrace() = delete;
EraseTrace(const EraseTrace&) = delete;
EraseTrace(EraseTrace&&) = default;
EraseTrace& operator=(const EraseTrace&) = delete;
EraseTrace& operator=(EraseTrace&&) = default;
using CommandInterface::CommandInterface;
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_erase_trace_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_erase_trace_req(instanceId, request);
return {rc, requestMsg};
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reasonCode = ERR_NULL;
uint8_t resStatus = 0;
auto rc = decode_erase_trace_resp(responsePtr, payloadLength, &cc,
&reasonCode, &resStatus);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reasonCode << "\n";
return;
}
ordered_json result;
result["Completion code"] = cc;
switch (resStatus)
{
case ERASE_TRACE_NO_DATA_ERASED:
result["Result status"] =
"0: No data was erased, FLASH storage is empty.";
break;
case ERASE_TRACE_DATA_ERASED:
result["Result status"] = "1: Flash storage is erased.";
break;
case ERASE_TRACE_DATA_ERASE_INPROGRESS:
result["Result status"] =
"2: Flash storage erase is in progress.";
break;
default:
result["Result status"] = "Unknown value";
break;
}
nsmtool::helper::DisplayInJson(result);
}
};
class GetNetworkDeviceLogInfo : public CommandInterface
{
public:
~GetNetworkDeviceLogInfo() = default;
GetNetworkDeviceLogInfo() = delete;
GetNetworkDeviceLogInfo(const GetNetworkDeviceLogInfo&) = delete;
GetNetworkDeviceLogInfo(GetNetworkDeviceLogInfo&&) = default;
GetNetworkDeviceLogInfo& operator=(const GetNetworkDeviceLogInfo&) = delete;
GetNetworkDeviceLogInfo& operator=(GetNetworkDeviceLogInfo&&) = default;
using CommandInterface::CommandInterface;
explicit GetNetworkDeviceLogInfo(const char* type, const char* name,
CLI::App* app) :
CommandInterface(type, name, app)
{
auto getNetworkDeviceDebugInfoOptionGroup = app->add_option_group(
"Required", "Get network device log information options.");
recordHandle = 0;
getNetworkDeviceDebugInfoOptionGroup->add_option(
"-r, --recordHandle", recordHandle,
"Record handle for fetching the log info chunk.");
getNetworkDeviceDebugInfoOptionGroup->require_option(1);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(
sizeof(nsm_msg_hdr) + sizeof(nsm_get_network_device_log_info_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_get_network_device_log_info_req(instanceId,
recordHandle, request);
return {rc, requestMsg};
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reasonCode = ERR_NULL;
uint32_t nextHandle = 0;
uint16_t logInfoSize = 0;
struct nsm_device_log_info_breakdown logInfo;
std::vector<uint8_t> logData(65535, 0);
auto rc = decode_get_network_device_log_info_resp(
responsePtr, payloadLength, &cc, &reasonCode, &nextHandle, &logInfo,
logData.data(), &logInfoSize);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reasonCode << "\n";
return;
}
ordered_json result;
result["Completion code"] = cc;
result["Next Record Handle"] = static_cast<uint32_t>(nextHandle);
result["Lost Events"] = static_cast<uint16_t>(logInfo.lost_events);
auto syncedTime = static_cast<uint8_t>(logInfo.synced_time);
if (syncedTime == 0)
result["Synced Time"] = "Boot - Time measured since bootup";
else if (syncedTime == 1)
result["Synced Time"] = "Synced - Time was synced by the host";
else
result["Synced Time"] = "Unknown";
result["Time High"] = static_cast<uint32_t>(logInfo.time_high);
result["Time low"] = static_cast<uint32_t>(logInfo.time_low);
result["Log Entry Prefix"] =
static_cast<uint32_t>(logInfo.entry_prefix);
result["Log Entry Suffix"] =
static_cast<uint32_t>(logInfo.entry_suffix);
result["Number of Dwords in log entry"] =
static_cast<uint8_t>(logInfo.length);
if (logInfoSize != 0)
result["Log Information"] = "Data received";
else
result["Log Information"] = "No Data received";
nsmtool::helper::DisplayInJson(result);
}
private:
uint32_t recordHandle;
};
class EraseDebugInfo : public CommandInterface
{
public:
~EraseDebugInfo() = default;
EraseDebugInfo() = delete;
EraseDebugInfo(const EraseDebugInfo&) = delete;
EraseDebugInfo(EraseDebugInfo&&) = default;
EraseDebugInfo& operator=(const EraseDebugInfo&) = delete;
EraseDebugInfo& operator=(EraseDebugInfo&&) = default;
using CommandInterface::CommandInterface;
explicit EraseDebugInfo(const char* type, const char* name, CLI::App* app) :
CommandInterface(type, name, app)
{
auto eraseDebugInfoOptionGroup =
app->add_option_group("Required", "Erase debug info options.");
infoType = 0;
eraseDebugInfoOptionGroup->add_option(
"-t, --infoType", infoType,
"Debug information type [0-FW saved debug info]");
eraseDebugInfoOptionGroup->require_option(1);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_erase_debug_info_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_erase_debug_info_req(instanceId, infoType, request);
return {rc, requestMsg};
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reasonCode = ERR_NULL;
uint8_t resStatus = 0;
auto rc = decode_erase_debug_info_resp(responsePtr, payloadLength, &cc,
&reasonCode, &resStatus);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reasonCode << "\n";
return;
}
ordered_json result;
result["Completion code"] = cc;
switch (resStatus)
{
case ERASE_TRACE_NO_DATA_ERASED:
result["Result status"] =
"0: No data was erased, FLASH storage is empty.";
break;
case ERASE_TRACE_DATA_ERASED:
result["Result status"] = "1: Flash storage is erased.";
break;
case ERASE_TRACE_DATA_ERASE_INPROGRESS:
result["Result status"] =
"2: Flash storage erase is in progress.";
break;
default:
result["Result status"] = "Unknown value";
break;
}
nsmtool::helper::DisplayInJson(result);
}
private:
uint8_t infoType;
};
class GetDeviceDebugParameters : public CommandInterface
{
public:
~GetDeviceDebugParameters() = default;
GetDeviceDebugParameters() = delete;
GetDeviceDebugParameters(const GetDeviceDebugParameters&) = delete;
GetDeviceDebugParameters(GetDeviceDebugParameters&&) = default;
GetDeviceDebugParameters&
operator=(const GetDeviceDebugParameters&) = delete;
GetDeviceDebugParameters& operator=(GetDeviceDebugParameters&&) = default;
using CommandInterface::CommandInterface;
explicit GetDeviceDebugParameters(const char* type, const char* name,
CLI::App* app) :
CommandInterface(type, name, app)
{
auto getDeviceDebugParametersOptionGroup = app->add_option_group(
"Required", "Get device debug parameters options.");
debugConfigurationType = 0;
portNumber = 0;
parameterIndex = 0;
parameterSubIndex = 0;
getDeviceDebugParametersOptionGroup->add_option(
"-t, --configType", debugConfigurationType,
"Debug configuration type [0-Network interface mode]");
getDeviceDebugParametersOptionGroup->add_option(
"-p, --portNumber", portNumber, "Port number");
getDeviceDebugParametersOptionGroup->add_option(
"-i, --parameterIndex", parameterIndex, "Parameter index (ID)");
getDeviceDebugParametersOptionGroup->add_option(
"-s, --parameterSubId", parameterSubIndex, "Parameter sub ID");
getDeviceDebugParametersOptionGroup->require_option(4);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(
sizeof(nsm_msg_hdr) + sizeof(nsm_get_device_debug_parameters_req));
struct nsm_debug_parameter_id parameterId;
nsm_debug_parameter_sub_id_bitfield parameterSubId;
parameterId.port_number = portNumber;
parameterId.index = parameterIndex;
parameterSubId.value = parameterSubIndex;
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_get_device_debug_parameters_req(
instanceId, debugConfigurationType, parameterId, parameterSubId,
request);
return std::make_pair(rc, requestMsg);
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t dataSize = 0;
std::vector<uint8_t> data(65535, 0);
auto rc = decode_get_device_debug_parameters_resp(
responsePtr, payloadLength, &cc, &dataSize, data.data());
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc << "\n";
return;
}
ordered_json result;
result["Completion code"] = cc;
result["Data size"] = static_cast<uint16_t>(dataSize);
result["Debug Data"] = nsmtool::helper::bytesToHexString(data.data(),
dataSize);
nsmtool::helper::DisplayInJson(result);
}
private:
uint8_t debugConfigurationType;
uint16_t portNumber;
uint8_t parameterIndex;
uint32_t parameterSubIndex;
};
class SetDeviceDebugParameters : public CommandInterface
{
public:
~SetDeviceDebugParameters() = default;
SetDeviceDebugParameters() = delete;
SetDeviceDebugParameters(const SetDeviceDebugParameters&) = delete;
SetDeviceDebugParameters(SetDeviceDebugParameters&&) = default;
SetDeviceDebugParameters&
operator=(const SetDeviceDebugParameters&) = delete;
SetDeviceDebugParameters& operator=(SetDeviceDebugParameters&&) = default;
using CommandInterface::CommandInterface;
explicit SetDeviceDebugParameters(const char* type, const char* name,
CLI::App* app) :
CommandInterface(type, name, app)
{
auto setDeviceDebugParametersOptionGroup = app->add_option_group(
"Required", "Set device debug parameters options.");
debugConfigurationType = 0;
portNumber = 0;
parameterIndex = 0;
parameterSubIndex = 0;
dataSize = 0;
data = {};
setDeviceDebugParametersOptionGroup->add_option(
"-t, --configType", debugConfigurationType,
"Debug configuration type [0-Network interface mode]");
setDeviceDebugParametersOptionGroup->add_option(
"-p, --portNumber", portNumber, "Port number");
setDeviceDebugParametersOptionGroup->add_option(
"-i, --parameterIndex", parameterIndex, "Parameter index (ID)");
setDeviceDebugParametersOptionGroup->add_option(
"-s, --parameterSubId", parameterSubIndex, "Parameter sub ID");
setDeviceDebugParametersOptionGroup->add_option("-d, --data", data,
"Data");
setDeviceDebugParametersOptionGroup->require_option(5);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(
sizeof(nsm_msg_hdr) + sizeof(nsm_set_device_debug_parameters_req) +
data.size() - sizeof(uint8_t));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
struct nsm_debug_parameter_id parameterId;
nsm_debug_parameter_sub_id_bitfield parameterSubId;
parameterId.port_number = portNumber;
parameterId.index = parameterIndex;
parameterSubId.value = parameterSubIndex;
dataSize = data.size();
auto rc = encode_set_device_debug_parameters_req(
instanceId, debugConfigurationType, parameterId, parameterSubId,
dataSize, data.data(), request);
return std::make_pair(rc, requestMsg);
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
auto rc = decode_set_device_debug_parameters_resp(responsePtr,
payloadLength, &cc);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc << "\n";
return;
}
ordered_json result;
result["Completion code"] = cc;
nsmtool::helper::DisplayInJson(result);
}
private:
uint8_t debugConfigurationType;
uint16_t portNumber;
uint8_t parameterIndex;
uint32_t parameterSubIndex;
uint8_t dataSize;
std::vector<uint8_t> data;
};
class InstallToken : public CommandInterface
{
public:
InstallToken() = delete;
InstallToken(const InstallToken&) = delete;
InstallToken(InstallToken&&) = default;
InstallToken& operator=(const InstallToken&) = delete;
InstallToken& operator=(InstallToken&&) = default;
using CommandInterface::CommandInterface;
explicit InstallToken(const char* type, const char* name, CLI::App* app) :
CommandInterface(type, name, app)
{
auto ccOptionGroup =
app->add_option_group("Required", "Install specified token chunk");
ccOptionGroup->add_option("-b,--bufferSize", bufferSize,
"buffer size of the target device");
ccOptionGroup->add_option("-f,--file", filePath,
"path to the token file");
ccOptionGroup->require_option(2);
}
~InstallToken()
{
if (fd >= 0)
{
close(fd);
}
}
std::vector<uint8_t> createChunk()
{
size_t toRead = std::min(chunkSize, remaining);
std::vector<uint8_t> data(toRead);
auto bytesRead = read(fd, data.data(), toRead);
if (bytesRead < 0)
{
close(fd);
fd = -1;
throw std::runtime_error("Failed to read token file: " +
std::string(strerror(errno)));
}
data.resize(bytesRead);
return data;
}
std::pair<int, std::vector<uint8_t>> createChunkRequestMsg()
{
std::vector<uint8_t> data = createChunk();
if (data.empty())
{
return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>());
}
sentChunkSize = data.size();
remaining -= data.size();
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_install_token_req) - 1 +
data.size());
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_nsm_install_token_req(instanceId, offset, data.size(),
remaining, data.data(), request);
offset += data.size();
return std::make_pair(rc, requestMsg);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
if (bufferSize == 0)
{
std::cerr << "Buffer size is 0" << std::endl;
return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>());
}
if (bufferSize > std::numeric_limits<uint16_t>::max())
{
std::cerr << "Buffer size is too large (max is "
<< std::numeric_limits<uint16_t>::max()
<< "): " << bufferSize << std::endl;
return std::make_pair(NSM_SW_ERROR_LENGTH, std::vector<uint8_t>());
}
fd = open(filePath.c_str(), O_RDONLY);
if (fd < 0)
{
std::cerr << "open error: " << strerror(errno) << std::endl;
return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>());
}
int rc = lseek(fd, 0, SEEK_SET);
if (rc < 0)
{
std::cerr << "lseek error: " << rc << std::endl;
return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>());
}
struct stat fileStat;
rc = fstat(fd, &fileStat);
if (rc < 0)
{
std::cerr << "fstat error: " << strerror(errno) << std::endl;
return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>());
}
if (fileStat.st_size < 0)
{
std::cerr << "Invalid file size in fd" << std::endl;
return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>());
}
// Read and parse the 16-byte file header
constexpr size_t HEADER_SIZE = 16;
if (fileStat.st_size < static_cast<off_t>(HEADER_SIZE))
{
std::cerr << "File too small to contain header (size: "
<< fileStat.st_size << ", expected at least "
<< HEADER_SIZE << " bytes)" << std::endl;
return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>());
}
std::array<uint8_t, HEADER_SIZE> header;
ssize_t bytesRead = read(fd, header.data(), HEADER_SIZE);
if (bytesRead != static_cast<ssize_t>(HEADER_SIZE))
{
std::cerr << "Failed to read file header: " << strerror(errno)
<< std::endl;
return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>());
}
remaining = fileStat.st_size - HEADER_SIZE;
chunkSize = NSM_DEBUG_TOKEN_INSTALL_CHUNK_SIZE(bufferSize);
return createChunkRequestMsg();
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reasonCode = ERR_NULL;
auto rc = decode_nsm_install_token_resp(responsePtr, payloadLength, &cc,
&reasonCode);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reasonCode << ", error="
<< debug_token::Error(reasonCode).to_string()
<< std::endl;
return;
}
nlohmann::ordered_json result;
result["Completion code"] = cc;
result["Reason code"] = reasonCode;
result["Chunk size"] = sentChunkSize;
result["Remaining"] = remaining;
nsmtool::helper::DisplayInJson(result);
if (remaining > 0)
{
auto [rc, requestMsg] = createChunkRequestMsg();
if (rc != NSM_SW_SUCCESS)
{
return;
}
requestQueue.push_back(std::move(requestMsg));
}
}
private:
std::string filePath;
int fd{-1};
uint32_t bufferSize{0};
uint32_t chunkSize{0};
uint32_t offset{0};
uint32_t remaining{0};
uint32_t sentChunkSize{0};
};
class EraseToken : public CommandInterface
{
public:
~EraseToken() = default;
EraseToken() = delete;
EraseToken(const EraseToken&) = delete;
EraseToken(EraseToken&&) = default;
EraseToken& operator=(const EraseToken&) = delete;
EraseToken& operator=(EraseToken&&) = default;
using CommandInterface::CommandInterface;
explicit EraseToken(const char* type, const char* name, CLI::App* app) :
CommandInterface(type, name, app)
{
auto eraseTokenOptionGroup =
app->add_option_group("Required", "Erase specified token");
eraseTokenOptionGroup->add_option("-t,--type", tokenType, "token type");
eraseTokenOptionGroup->require_option(1);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_erase_token_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_nsm_erase_token_req(instanceId, tokenType, request);
return std::make_pair(rc, requestMsg);
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reasonCode = ERR_NULL;
auto rc = decode_nsm_erase_token_resp(responsePtr, payloadLength, &cc,
&reasonCode);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reasonCode << ", error="
<< debug_token::Error(reasonCode).to_string()
<< std::endl;
return;
}
nlohmann::ordered_json result;
result["Completion code"] = cc;
result["Reason code"] = reasonCode;
nsmtool::helper::DisplayInJson(result);
}
private:
uint32_t tokenType;
};
class QueryToken : public CommandInterface
{
public:
~QueryToken() = default;
QueryToken() = delete;
QueryToken(const QueryToken&) = delete;
QueryToken(QueryToken&&) = default;
QueryToken& operator=(const QueryToken&) = delete;
QueryToken& operator=(QueryToken&&) = default;
using CommandInterface::CommandInterface;
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_query_token_req));
auto request = reinterpret_cast<nsm_msg*>(requestMsg.data());
auto rc = encode_nsm_query_token_req(instanceId, request);
return std::make_pair(rc, requestMsg);
}
void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override
{
uint8_t cc = NSM_SUCCESS;
uint16_t reasonCode = ERR_NULL;
std::vector<uint8_t> payload;
size_t payloadSize = 0;
auto rc = decode_nsm_query_token_resp(responsePtr, payloadLength, &cc,
&reasonCode, nullptr,
&payloadSize);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reasonCode << ", error="
<< debug_token::Error(reasonCode).to_string()
<< std::endl;
return;
}
if (payloadSize > 0)
{
payload.resize(payloadSize);
rc = decode_nsm_query_token_resp(responsePtr, payloadLength, &cc,
&reasonCode, payload.data(),
&payloadSize);
if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS)
{
std::cerr << "Response message error: "
<< "rc=" << rc << ", cc=" << (int)cc
<< ", reasonCode=" << (int)reasonCode << ", error="
<< debug_token::Error(reasonCode).to_string()
<< std::endl;
return;
}
}
ordered_json result;
result["Completion code"] = cc;
result["Reason code"] = reasonCode;
result["Data size"] = payloadSize;
if (payloadSize == 0)
{
nsmtool::helper::DisplayInJson(result);
return;
}
result["Raw data"] = bytesToHexString(payload.data(), payloadSize);
auto tlv = debug_token::tlv_decoder::Structure(payload);
auto types = tlv.getTypes();
for (const auto& type : types)
{
if (type == debug_token::types::Common::InstallationStatus)
{
auto value = tlv.get(type).getValue<uint8_t>();
result[debug_token::tlv_decoder::Item::getTypeName(type)] =
static_cast<bool>(value);
}
else if (type == debug_token::types::Common::ProcessingStatus)
{
auto value = tlv.get(type).getValue<uint8_t>();
result[debug_token::tlv_decoder::Item::getTypeName(type)] =
static_cast<bool>(value);
}
else if (type == debug_token::types::Common::TokenTypeSubtypeList)
{
auto value = tlv.get(type).getValue<std::vector<uint32_t>>();
if (value.size() % 2 != 0)
{
std::cerr << "Token type subtype list size is not even"
<< std::endl;
auto value = tlv.get(type).getRawValue();
result[debug_token::tlv_decoder::Item::getTypeName(type)] =
bytesToHexString(value.data(), value.size());
}
else
{
ordered_json array;
for (size_t i = 0; i < value.size(); i += 2)
{
ordered_json pair;
pair.push_back(value[i]);
pair.push_back(value[i + 1]);
array.push_back(pair);
}
result[debug_token::tlv_decoder::Item::getTypeName(type)] =
array;
}
}
else
{
auto value = tlv.get(type).getRawValue();
result[debug_token::tlv_decoder::Item::getTypeName(type)] =
bytesToHexString(value.data(), value.size());
}
}
nsmtool::helper::DisplayInJson(result);
}
};
void registerCommand(CLI::App& app)
{
auto diag = app.add_subcommand("diag", "Diagnostics type command");
diag->require_subcommand(1);
auto queryTokenParameters = diag->add_subcommand("QueryTokenParameters",
"Query token parameters");
commands.push_back(std::make_unique<QueryTokenParameters>(
"diag", "QueryTokenParameters", queryTokenParameters));
auto provideToken = diag->add_subcommand("ProvideToken", "Provide token");
commands.push_back(
std::make_unique<ProvideToken>("diag", "ProvideToken", provideToken));
auto disableTokens = diag->add_subcommand("DisableTokens",
"Disable tokens");
commands.push_back(std::make_unique<DisableTokens>("diag", "DisableTokens",
disableTokens));
auto queryTokenStatus = diag->add_subcommand("QueryTokenStatus",
"Query token status");
commands.push_back(std::make_unique<QueryTokenStatus>(
"diag", "QueryTokenStatus", queryTokenStatus));
auto queryDeviceIds = diag->add_subcommand("QueryDeviceIds",
"Query device IDs");
commands.push_back(std::make_unique<QueryDeviceIds>(
"diag", "QueryDeviceIds", queryDeviceIds));
auto enableDisableWriteProtected = diag->add_subcommand(
"EnableDisableWriteProtected", "Enable/Disable WriteProtected");
commands.push_back(std::make_unique<EnableDisableWriteProtected>(
"diag", "EnableDisableWriteProtected", enableDisableWriteProtected));
auto resetNetworkDevice = diag->add_subcommand("ResetNetworkDevice",
"Reset Network Device");
commands.push_back(std::make_unique<ResetNetworkDevice>(
"diag", "ResetNetworkDevice", resetNetworkDevice));
auto getNetworkDeviceDebugInfo = diag->add_subcommand(
"GetNetworkDeviceDebugInfo", "Get Network Device Debug Info");
commands.push_back(std::make_unique<GetNetworkDeviceDebugInfo>(
"diag", "GetNetworkDeviceDebugInfo", getNetworkDeviceDebugInfo));
auto eraseTrace = diag->add_subcommand("EraseTrace", "Erase Trace");
commands.push_back(
std::make_unique<EraseTrace>("diag", "EraseTrace", eraseTrace));
auto getNetworkDeviceLogInfo = diag->add_subcommand(
"GetNetworkDeviceLogInfo", "Get Network Device Log Info");
commands.push_back(std::make_unique<GetNetworkDeviceLogInfo>(
"diag", "GetNetworkDeviceLogInfo", getNetworkDeviceLogInfo));
auto eraseDebugInfo = diag->add_subcommand("EraseDebugInfo",
"Erase Debug Info");
commands.push_back(std::make_unique<EraseDebugInfo>(
"diag", "EraseDebugInfo", eraseDebugInfo));
auto resetMetricsInfo = diag->add_subcommand("GetResetMetrcs",
"Get Reset MEtrics Info");
commands.push_back(std::make_unique<QueryResetStatistics>(
"diag", "GetResetMetrcs", resetMetricsInfo));
auto getDeviceDiagnostics = diag->add_subcommand("GetDeviceDiagnostics",
"Get Device Diagnostics");
commands.push_back(std::make_unique<GetDeviceDiagnostics>(
"diag", "GetDeviceDiagnostics", getDeviceDiagnostics));
auto getDeviceDebugParameters = diag->add_subcommand(
"GetDeviceDebugParameters", "Get Device Debug Parameters");
commands.push_back(std::make_unique<GetDeviceDebugParameters>(
"diag", "GetDeviceDebugParameters", getDeviceDebugParameters));
auto setDeviceDebugParameters = diag->add_subcommand(
"SetDeviceDebugParameters", "Set Device Debug Parameters");
commands.push_back(std::make_unique<SetDeviceDebugParameters>(
"diag", "SetDeviceDebugParameters", setDeviceDebugParameters));
auto installToken = diag->add_subcommand("InstallToken", "Install token");
commands.push_back(
std::make_unique<InstallToken>("diag", "InstallToken", installToken));
auto eraseToken = diag->add_subcommand("EraseToken", "Erase token");
commands.push_back(
std::make_unique<EraseToken>("diag", "EraseToken", eraseToken));
auto queryToken = diag->add_subcommand("QueryToken", "Query token");
commands.push_back(
std::make_unique<QueryToken>("diag", "QueryToken", queryToken));
}
} // namespace diag
} // namespace nsmtool