1 #include "pldm_cmd_helper.hpp"
2
3 #include "common/transport.hpp"
4 #include "xyz/openbmc_project/Common/error.hpp"
5
6 #include <libpldm/firmware_update.h>
7 #include <libpldm/transport.h>
8 #include <libpldm/transport/af-mctp.h>
9 #include <libpldm/transport/mctp-demux.h>
10 #include <poll.h>
11 #include <systemd/sd-bus.h>
12
13 #include <sdbusplus/server.hpp>
14 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
15
16 #include <exception>
17
18 using namespace pldm::utils;
19
20 namespace pldmtool
21 {
22 namespace helper
23 {
24
25 static const std::map<uint8_t, std::string> genericCompletionCodes{
26 {PLDM_SUCCESS, "SUCCESS"},
27 {PLDM_ERROR, "ERROR"},
28 {PLDM_ERROR_INVALID_DATA, "ERROR_INVALID_DATA"},
29 {PLDM_ERROR_INVALID_LENGTH, "ERROR_INVALID_LENGTH"},
30 {PLDM_ERROR_NOT_READY, "ERROR_NOT_READY"},
31 {PLDM_ERROR_UNSUPPORTED_PLDM_CMD, "ERROR_UNSUPPORTED_PLDM_CMD"},
32 {PLDM_ERROR_INVALID_PLDM_TYPE, "ERROR_INVALID_PLDM_TYPE"},
33 {PLDM_ERROR_UNEXPECTED_TRANSFER_FLAG_OPERATION,
34 "ERROR_UNEXPECTED_TRANSFER_FLAG_OPERATION"}};
35
36 static const std::map<uint8_t, std::string> fwupdateCompletionCodes{
37 {PLDM_FWUP_NOT_IN_UPDATE_MODE, "NOT_IN_UPDATE_MODE"},
38 {PLDM_FWUP_ALREADY_IN_UPDATE_MODE, "ALREADY_IN_UPDATE_MODE"},
39 {PLDM_FWUP_DATA_OUT_OF_RANGE, "DATA_OUT_OF_RANGE"},
40 {PLDM_FWUP_INVALID_TRANSFER_LENGTH, "INVALID_TRANSFER_LENGTH"},
41 {PLDM_FWUP_INVALID_STATE_FOR_COMMAND, "INVALID_STATE_FOR_COMMAND"},
42 {PLDM_FWUP_INCOMPLETE_UPDATE, "INCOMPLETE_UPDATE"},
43 {PLDM_FWUP_BUSY_IN_BACKGROUND, "BUSY_IN_BACKGROUND"},
44 {PLDM_FWUP_CANCEL_PENDING, "CANCEL_PENDING"},
45 {PLDM_FWUP_COMMAND_NOT_EXPECTED, "COMMAND_NOT_EXPECTED"},
46 {PLDM_FWUP_RETRY_REQUEST_FW_DATA, "RETRY_REQUEST_FW_DATA"},
47 {PLDM_FWUP_UNABLE_TO_INITIATE_UPDATE, "UNABLE_TO_INITIATE_UPDATE"},
48 {PLDM_FWUP_ACTIVATION_NOT_REQUIRED, "ACTIVATION_NOT_REQUIRED"},
49 {PLDM_FWUP_SELF_CONTAINED_ACTIVATION_NOT_PERMITTED,
50 "SELF_CONTAINED_ACTIVATION_NOT_PERMITTED"},
51 {PLDM_FWUP_NO_DEVICE_METADATA, "NO_DEVICE_METADATA"},
52 {PLDM_FWUP_RETRY_REQUEST_UPDATE, "RETRY_REQUEST_UPDATE"},
53 {PLDM_FWUP_NO_PACKAGE_DATA, "NO_PACKAGE_DATA"},
54 {PLDM_FWUP_INVALID_TRANSFER_HANDLE, "INVALID_TRANSFER_HANDLE"},
55 {PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG,
56 "INVALID_TRANSFER_OPERATION_FLAG"},
57 {PLDM_FWUP_ACTIVATE_PENDING_IMAGE_NOT_PERMITTED,
58 "ACTIVATE_PENDING_IMAGE_NOT_PERMITTED"},
59 {PLDM_FWUP_PACKAGE_DATA_ERROR, "PACKAGE_DATA_ERROR"}};
60
fillCompletionCode(uint8_t completionCode,ordered_json & data,uint8_t pldmType)61 void fillCompletionCode(uint8_t completionCode, ordered_json& data,
62 uint8_t pldmType)
63 {
64 // Check generic completion codes first for all PLDM types
65 auto it = genericCompletionCodes.find(completionCode);
66 if (it != genericCompletionCodes.end())
67 {
68 data["CompletionCode"] = it->second;
69 return;
70 }
71
72 // If not a generic code, check type-specific codes
73 switch (pldmType)
74 {
75 case PLDM_FWUP:
76 {
77 auto typeIt = fwupdateCompletionCodes.find(completionCode);
78 if (typeIt != fwupdateCompletionCodes.end())
79 {
80 data["CompletionCode"] = typeIt->second;
81 return;
82 }
83 break;
84 }
85 }
86
87 data["CompletionCode"] = "UNKNOWN_COMPLETION_CODE";
88 }
89
exec()90 void CommandInterface::exec()
91 {
92 instanceId = instanceIdDb.next(mctp_eid);
93 auto [rc, requestMsg] = createRequestMsg();
94 if (rc != PLDM_SUCCESS)
95 {
96 instanceIdDb.free(mctp_eid, instanceId);
97 std::cerr << "Failed to encode request message for " << pldmType << ":"
98 << commandName << " rc = " << rc << "\n";
99 return;
100 }
101
102 std::vector<uint8_t> responseMsg;
103 rc = pldmSendRecv(requestMsg, responseMsg);
104
105 if (rc != PLDM_SUCCESS)
106 {
107 instanceIdDb.free(mctp_eid, instanceId);
108 std::cerr << "pldmSendRecv: Failed to receive RC = " << rc << "\n";
109 return;
110 }
111
112 auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg.data());
113 parseResponseMsg(responsePtr, responseMsg.size() - sizeof(pldm_msg_hdr));
114 instanceIdDb.free(mctp_eid, instanceId);
115 }
116
pldmSendRecv(std::vector<uint8_t> & requestMsg,std::vector<uint8_t> & responseMsg)117 int CommandInterface::pldmSendRecv(std::vector<uint8_t>& requestMsg,
118 std::vector<uint8_t>& responseMsg)
119 {
120 // By default enable request/response msgs for pldmtool raw commands.
121 if (CommandInterface::pldmType == "raw")
122 {
123 pldmVerbose = true;
124 }
125
126 if (pldmVerbose)
127 {
128 std::cout << "pldmtool: ";
129 printBuffer(Tx, requestMsg);
130 }
131
132 auto tid = mctp_eid;
133 PldmTransport pldmTransport{};
134 uint8_t retry = 0;
135 int rc = PLDM_ERROR;
136
137 while (PLDM_REQUESTER_SUCCESS != rc && retry <= numRetries)
138 {
139 void* responseMessage = nullptr;
140 size_t responseMessageSize{};
141
142 rc =
143 pldmTransport.sendRecvMsg(tid, requestMsg.data(), requestMsg.size(),
144 responseMessage, responseMessageSize);
145 if (rc)
146 {
147 std::cerr << "[" << unsigned(retry) << "] pldm_send_recv error rc "
148 << rc << std::endl;
149 retry++;
150 continue;
151 }
152
153 responseMsg.resize(responseMessageSize);
154 memcpy(responseMsg.data(), responseMessage, responseMsg.size());
155
156 free(responseMessage);
157
158 if (pldmVerbose)
159 {
160 std::cout << "pldmtool: ";
161 printBuffer(Rx, responseMsg);
162 }
163 }
164
165 if (rc)
166 {
167 std::cerr << "failed to pldm send recv error rc " << rc << std::endl;
168 }
169
170 return rc;
171 }
172 } // namespace helper
173 } // namespace pldmtool
174