xref: /openbmc/pldm/pldmtool/pldm_cmd_helper.cpp (revision 9285b6b43b88058174f5eecd4c874b130b66da97)
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