blob: 76f57259e93ccddc91a5657528b7c1d1af29d548 [file] [log] [blame]
#include "base_disc_state_machine.hpp"
#include "libpldm/base.h"
#include "libpldm/pldm.h"
#include "interface/pldm_interface.hpp"
#include <stdplus/print.hpp>
#include <util/common.hpp>
BaseDiscoveryStateMachine::BaseDiscoveryStateMachine(
int fd, const std::string& deviceName, int netId) :
fd(fd),
deviceName(deviceName), netId(netId)
{
stdplus::print(stderr, "Initializing base discovery state machine...\n");
this->initialized = true;
this->requesterStatus = StateMachineStatus::NoPendingAction;
this->eid = DEST_EID;
this->instanceId = INSTANCE_ID; // TODO(@harshtya): Make this dynamic
}
OperationStatus BaseDiscoveryStateMachine::run()
{
stdplus::print(stderr, "Triggering PLDM Base discovery for device {}...\n",
this->deviceName);
if (!this->initialized &&
this->requesterStatus != StateMachineStatus::NoPendingAction)
{
return OperationStatus::StateMachineInitializationError;
}
// Setting up the initial command set
this->nextCommand = PLDM_GET_TID;
this->requesterStatus = StateMachineStatus::ReadyToPickNextRequest;
for (int processCounter = 0; processCounter < BASE_REQUEST_RETRIES;
processCounter++)
{
if (this->requesterStatus == StateMachineStatus::NoPendingAction)
{
stdplus::print(stderr, "Base discovery successfully completed\n");
break;
}
OperationStatus status = triggerNextCommand();
if (status != OperationStatus::Success)
{
stdplus::print(stderr,
"Base discovery failed at command {} with "
"status: {}\n",
std::to_string(this->nextCommand),
static_cast<int>(status));
return status;
}
if (processCounter == (BASE_REQUEST_RETRIES - 1))
{
stdplus::print(stderr, "Base discovery failed due infinite loop\n");
return OperationStatus::OperationFailure;
}
}
return OperationStatus::Success;
}
OperationStatus BaseDiscoveryStateMachine::triggerNextCommand()
{
switch (this->nextCommand)
{
case PLDM_GET_TID:
return processGetTidRequest();
case PLDM_GET_PLDM_TYPES:
return processGetPldmTypesRequest();
case PLDM_GET_PLDM_VERSION:
return processGetPldmVersionRequest();
case PLDM_GET_PLDM_COMMANDS:
return processGetPldmCommandsRequest();
default:
return OperationStatus::NoNextCommandFound;
}
return OperationStatus::Success;
}
OperationStatus BaseDiscoveryStateMachine::processGetTidRequest()
{
std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
baseCommandRequestSize.at(PLDM_GET_TID));
auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
int rc = encode_get_tid_req(this->instanceId, request);
if (rc)
{
stdplus::print(
stderr,
"Encoding TID request failed in base discovery with rc: {} for "
"device {}\n",
rc, this->deviceName);
return OperationStatus::EncodingRequestFailure;
}
if (pldmSendAtNetwork(this->eid, this->netId, this->fd, requestMsg.data(),
requestMsg.size()))
{
this->requesterStatus = StateMachineStatus::RequestFailed;
return OperationStatus::PldmSendFailure;
}
std::vector<uint8_t> response(
sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES, 0);
uint8_t* responseMsg = response.data();
size_t responseMsgSize = sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES;
auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
if (pldmRecvAtNetwork(this->eid, this->netId, this->fd, this->instanceId,
&responseMsg, &responseMsgSize))
{
this->requesterStatus = StateMachineStatus::RequestFailed;
return OperationStatus::PldmRecvFailure;
}
stdplus::print(stderr, "Pushing response for GET_TID for device {}\n",
this->deviceName);
OperationStatus status = pushCommandResponse(responsePtr, responseMsgSize);
if (status != OperationStatus::Success)
{
stdplus::print(stderr,
"Failed to push response for Get TID in base "
"discovery with status: {} for device: {}\n",
static_cast<int>(status), this->deviceName);
}
return status;
}
OperationStatus BaseDiscoveryStateMachine::processGetPldmTypesRequest()
{
std::vector<uint8_t> requestMsg(
sizeof(pldm_msg_hdr) + baseCommandRequestSize.at(PLDM_GET_PLDM_TYPES));
auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
int rc = encode_get_types_req(this->instanceId, request);
if (rc)
{
stdplus::print(
stderr,
"Encoding PLDM Types request failed in base discovery with rc: {} "
"for device {}\n",
rc, this->deviceName);
return OperationStatus::EncodingRequestFailure;
}
if (pldmSendAtNetwork(this->eid, this->netId, this->fd, requestMsg.data(),
requestMsg.size()))
{
this->requesterStatus = StateMachineStatus::RequestFailed;
return OperationStatus::PldmSendFailure;
}
std::vector<uint8_t> response(
sizeof(pldm_msg_hdr) + PLDM_GET_TYPES_RESP_BYTES, 0);
uint8_t* responseMsg = response.data();
size_t responseMsgSize = response.size();
auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
if (pldmRecvAtNetwork(this->eid, this->netId, this->fd, this->instanceId,
&responseMsg, &responseMsgSize))
{
this->requesterStatus = StateMachineStatus::RequestFailed;
return OperationStatus::PldmRecvFailure;
}
stdplus::print(stderr,
"Pushing response for GET_PLDM_TYPES for device: "
"{}\n",
this->deviceName);
OperationStatus status = pushCommandResponse(responsePtr, responseMsgSize);
if (status != OperationStatus::Success)
{
stdplus::print(stderr,
"Failed to push response for Get PLDM TYPES in base "
"discovery with status: {} for device: {}\n",
static_cast<int>(status), this->deviceName);
}
return status;
}
OperationStatus BaseDiscoveryStateMachine::processGetPldmVersionRequest()
{
std::vector<uint8_t> requestMsg(
sizeof(pldm_msg_hdr) +
baseCommandRequestSize.at(PLDM_GET_PLDM_VERSION));
auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
int rc = encode_get_version_req(this->instanceId, /*transfer_handle=*/0,
PLDM_GET_FIRSTPART, this->commandPldmType,
request);
if (rc)
{
stdplus::print(
stderr,
"Encoding PLDM Version request failed in base discovery with rc: "
"{} for device {} and pldmType: {}\n",
rc, this->deviceName, std::to_string(this->commandPldmType));
return OperationStatus::EncodingRequestFailure;
}
if (pldmSendAtNetwork(this->eid, this->netId, this->fd, requestMsg.data(),
requestMsg.size()))
{
this->requesterStatus = StateMachineStatus::RequestFailed;
return OperationStatus::PldmSendFailure;
}
std::vector<uint8_t> response(
sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, 0);
uint8_t* responseMsg = response.data();
size_t responseMsgSize = response.size();
auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
if (pldmRecvAtNetwork(this->eid, this->netId, this->fd, this->instanceId,
&responseMsg, &responseMsgSize))
{
this->requesterStatus = StateMachineStatus::RequestFailed;
return OperationStatus::PldmRecvFailure;
}
stdplus::print(stderr,
"Pushing response for GET_PLDM_VERSION for device: "
"{} with pldmType: {}\n",
this->deviceName, std::to_string(this->commandPldmType));
OperationStatus status = pushCommandResponse(responsePtr, responseMsgSize);
if (status != OperationStatus::Success)
{
stdplus::print(stderr,
"Failed to push response for Get PLDM Version in base "
"discovery with status: {} for device: {} for pldm Type:"
" {}\n",
static_cast<int>(status), this->deviceName,
std::to_string(this->commandPldmType));
}
return status;
}
OperationStatus BaseDiscoveryStateMachine::processGetPldmCommandsRequest()
{
std::vector<uint8_t> requestMsg(
sizeof(pldm_msg_hdr) +
baseCommandRequestSize.at(PLDM_GET_PLDM_COMMANDS));
auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
int rc = encode_get_commands_req(this->instanceId, this->commandPldmType,
this->pldmVersions[this->commandPldmType],
request);
if (rc)
{
stdplus::print(
stderr,
"Encoding PLDM Commands request failed in base discovery with rc: "
"{} for device {} and pldmType: {}\n",
rc, this->deviceName, std::to_string(this->commandPldmType));
return OperationStatus::EncodingRequestFailure;
}
if (pldmSendAtNetwork(this->eid, this->netId, this->fd, requestMsg.data(),
requestMsg.size()))
{
this->requesterStatus = StateMachineStatus::RequestFailed;
return OperationStatus::PldmSendFailure;
}
std::vector<uint8_t> response(
sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_RESP_BYTES, 0);
uint8_t* responseMsg = response.data();
size_t responseMsgSize = response.size();
auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
if (pldmRecvAtNetwork(this->eid, this->netId, this->fd, this->instanceId,
&responseMsg, &responseMsgSize))
{
this->requesterStatus = StateMachineStatus::RequestFailed;
return OperationStatus::PldmRecvFailure;
}
stdplus::print(stderr,
"Pushing response for GET_PLDM_COMMANDS for device: "
"{} with pldmType: {}\n",
this->deviceName, std::to_string(this->commandPldmType));
OperationStatus status = pushCommandResponse(responsePtr, responseMsgSize);
if (status != OperationStatus::Success)
{
stdplus::print(stderr,
"Failed to push response for Get PLDM Command in base "
"discovery with status: {} for device: {} for pldm Type:"
" {}\n",
static_cast<int>(status), this->deviceName,
std::to_string(this->commandPldmType));
}
return status;
}
OperationStatus BaseDiscoveryStateMachine::pushCommandResponse(
const struct pldm_msg* respMsg, size_t respSize)
{
switch (this->nextCommand)
{
case PLDM_GET_TID:
{
uint8_t completionCode = DEFAULT_INITIAL_VAL;
uint8_t tid = DEFAULT_INITIAL_VAL;
int rc = decode_get_tid_resp(respMsg,
respSize - sizeof(struct pldm_msg_hdr),
&completionCode, &tid);
if (rc || completionCode)
{
this->requesterStatus = StateMachineStatus::RequestFailed;
stdplus::print(stderr,
"Get TID response decode failed with rc:"
" {} and completion code: {}\n",
rc, std::to_string(completionCode));
return OperationStatus::IncorrectResponseMsg;
}
this->tid = tid;
this->nextCommand = PLDM_GET_PLDM_TYPES;
this->requesterStatus = StateMachineStatus::ReadyToPickNextRequest;
return OperationStatus::Success;
}
case PLDM_GET_PLDM_TYPES:
{
uint8_t completionCode = DEFAULT_INITIAL_VAL;
int rc = decode_get_types_resp(
respMsg, respSize - sizeof(struct pldm_msg_hdr),
&completionCode, this->pldmTypes.data());
if (rc || completionCode)
{
this->requesterStatus = StateMachineStatus::RequestFailed;
stdplus::print(
stderr,
"Get PLDM Type response decoded for "
"pldm GetTypes failed with rc: {} and completion code: {}\n",
rc, std::to_string(completionCode));
return OperationStatus::IncorrectResponseMsg;
}
// Setting the initial pldm_type as PLDM_BASE
this->commandPldmType = PLDM_BASE;
this->nextCommand = PLDM_GET_PLDM_VERSION;
this->requesterStatus = StateMachineStatus::ReadyToPickNextRequest;
return OperationStatus::Success;
}
case PLDM_GET_PLDM_VERSION:
{
ver32_t versionOut;
uint8_t completionCode = DEFAULT_INITIAL_VAL;
uint8_t retFlag = DEFAULT_INITIAL_VAL;
uint32_t retTransferHandle = DEFAULT_INITIAL_VAL;
int rc = decode_get_version_resp(
respMsg, respSize - sizeof(struct pldm_msg_hdr),
&completionCode, &retTransferHandle, &retFlag, &versionOut);
if (rc || completionCode)
{
this->requesterStatus = StateMachineStatus::RequestFailed;
stdplus::print(
stderr,
"Get PLDM Versions response decoded for "
"pldm get versions failed on pldm type: {} with rc: {} and "
"completion code: {}\n",
std::to_string(this->commandPldmType), rc,
std::to_string(completionCode));
return OperationStatus::IncorrectResponseMsg;
}
uint8_t currentPldmType = this->commandPldmType;
this->pldmVersions[currentPldmType] = versionOut;
std::optional<uint8_t> nextPldmType =
getNextPldmTypeToBeProcessed(currentPldmType);
if (nextPldmType.has_value())
{
// get the version for the next pldm type
this->commandPldmType = nextPldmType.value();
this->nextCommand = PLDM_GET_PLDM_VERSION;
this->requesterStatus =
StateMachineStatus::ReadyToPickNextRequest;
}
else
{
// All available pldm types processed
this->nextCommand = PLDM_GET_PLDM_COMMANDS;
this->requesterStatus =
StateMachineStatus::ReadyToPickNextRequest;
this->commandPldmType = PLDM_BASE;
}
return OperationStatus::Success;
}
case PLDM_GET_PLDM_COMMANDS:
{
uint8_t completionCode = DEFAULT_INITIAL_VAL;
bitfield8_t pldmCmds[PLDM_MAX_CMDS_PER_TYPE / 8];
int rc = decode_get_commands_resp(
respMsg, respSize - sizeof(struct pldm_msg_hdr),
&completionCode, pldmCmds);
if (rc || completionCode)
{
this->requesterStatus = StateMachineStatus::RequestFailed;
stdplus::print(
stderr,
"Get PLDM Cmds response decoded for "
"pldm get cmds failed on pldm type: {} with rc: {} and "
"completion code: {}\n",
std::to_string(this->commandPldmType), rc,
std::to_string(completionCode));
return OperationStatus::IncorrectResponseMsg;
}
uint8_t currentPldmType = this->commandPldmType;
for (int i = 0; i < (PLDM_MAX_CMDS_PER_TYPE / 8); i++)
{
this->pldmCommands[currentPldmType][i] = pldmCmds[i].byte;
}
std::optional<uint8_t> nextPldmType =
getNextPldmTypeToBeProcessed(currentPldmType);
if (nextPldmType.has_value())
{
this->commandPldmType = nextPldmType.value();
this->nextCommand = PLDM_GET_PLDM_COMMANDS;
this->requesterStatus =
StateMachineStatus::ReadyToPickNextRequest;
}
else
{
// All available pldm types processed
this->nextCommand =
static_cast<int>(OperationStatus::NoNextCommandFound);
this->requesterStatus = StateMachineStatus::NoPendingAction;
// Setting base PLDM type the PLDM Commands - default
this->commandPldmType = PLDM_BASE;
}
return OperationStatus::Success;
}
default:
return OperationStatus::OperationFailure;
}
}
std::optional<uint8_t>
BaseDiscoveryStateMachine::getNextPldmTypeToBeProcessed(uint8_t currentType)
{
// Each bit in a byte returned in pldm type response represents a pldm type
// Hence we process each bit to get the corresponding versions and commands
// for that bit
int byte = currentType / 8;
int bit = currentType % 8;
bool isBitSet = false;
while (byte < 8 && !isBitSet)
{
uint8_t currentByte = this->pldmTypes[byte].byte;
int index = bit + 1;
// Skip already traversed bits of the current byte
currentByte = currentByte >> (bit + 1);
while (currentByte)
{
if (currentByte & 1)
{
isBitSet = true;
bit = index;
break;
}
index++;
currentByte = currentByte >> 1;
}
if (!isBitSet)
{
byte++;
bit = -1; // We need to start from 0th bit of
// the next byte
}
}
if (byte == 8 && !isBitSet)
{
return std::nullopt;
}
return (bit + byte * 8);
}
void BaseDiscoveryStateMachine::printState()
{
// TODO(@harshtya): Implement state print for debug
}