xref: /openbmc/pldm/pldmtool/pldm_cmd_helper.cpp (revision f7f5da97)
1 #include "pldm_cmd_helper.hpp"
2 
3 #include "libpldm/requester/pldm.h"
4 
5 #include "xyz/openbmc_project/Common/error.hpp"
6 
7 #include <systemd/sd-bus.h>
8 
9 #include <sdbusplus/server.hpp>
10 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
11 
12 #include <exception>
13 
14 namespace pldmtool
15 {
16 
17 namespace helper
18 {
19 /*
20  * print the input buffer if pldm verbosity is enabled.
21  *
22  */
23 void printBuffer(const std::vector<uint8_t>& buffer, bool pldmVerbose)
24 {
25     if (pldmVerbose && !buffer.empty())
26     {
27         std::ostringstream tempStream;
28         for (int byte : buffer)
29         {
30             tempStream << std::setfill('0') << std::setw(2) << std::hex << byte
31                        << " ";
32         }
33         std::cout << tempStream.str() << std::endl;
34     }
35 }
36 /*
37  * Initialize the socket, send pldm command & recieve response from socket
38  *
39  */
40 int mctpSockSendRecv(const std::vector<uint8_t>& requestMsg,
41                      std::vector<uint8_t>& responseMsg, bool pldmVerbose)
42 {
43 
44     const char devPath[] = "\0mctp-mux";
45     int returnCode = 0;
46 
47     int sockFd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
48     if (-1 == sockFd)
49     {
50         returnCode = -errno;
51         std::cerr << "Failed to create the socket : RC = " << sockFd << "\n";
52         return returnCode;
53     }
54     Logger(pldmVerbose, "Success in creating the socket : RC = ", sockFd);
55 
56     struct sockaddr_un addr
57     {};
58     addr.sun_family = AF_UNIX;
59 
60     memcpy(addr.sun_path, devPath, sizeof(devPath) - 1);
61 
62     CustomFD socketFd(sockFd);
63     int result = connect(socketFd(), reinterpret_cast<struct sockaddr*>(&addr),
64                          sizeof(devPath) + sizeof(addr.sun_family) - 1);
65     if (-1 == result)
66     {
67         returnCode = -errno;
68         std::cerr << "Failed to connect to socket : RC = " << returnCode
69                   << "\n";
70         return returnCode;
71     }
72     Logger(pldmVerbose, "Success in connecting to socket : RC = ", returnCode);
73 
74     auto pldmType = MCTP_MSG_TYPE_PLDM;
75     result = write(socketFd(), &pldmType, sizeof(pldmType));
76     if (-1 == result)
77     {
78         returnCode = -errno;
79         std::cerr << "Failed to send message type as pldm to mctp : RC = "
80                   << returnCode << "\n";
81         return returnCode;
82     }
83     Logger(
84         pldmVerbose,
85         "Success in sending message type as pldm to mctp : RC = ", returnCode);
86 
87     result = send(socketFd(), requestMsg.data(), requestMsg.size(), 0);
88     if (-1 == result)
89     {
90         returnCode = -errno;
91         std::cerr << "Write to socket failure : RC = " << returnCode << "\n";
92         return returnCode;
93     }
94     Logger(pldmVerbose, "Write to socket successful : RC = ", result);
95 
96     // Read the response from socket
97     ssize_t peekedLength = recv(socketFd(), nullptr, 0, MSG_TRUNC | MSG_PEEK);
98     if (0 == peekedLength)
99     {
100         std::cerr << "Socket is closed : peekedLength = " << peekedLength
101                   << "\n";
102         return returnCode;
103     }
104     else if (peekedLength <= -1)
105     {
106         returnCode = -errno;
107         std::cerr << "recv() system call failed : RC = " << returnCode << "\n";
108         return returnCode;
109     }
110     else
111     {
112         auto reqhdr = reinterpret_cast<const pldm_msg_hdr*>(&requestMsg[2]);
113         do
114         {
115             ssize_t peekedLength =
116                 recv(socketFd(), nullptr, 0, MSG_PEEK | MSG_TRUNC);
117             responseMsg.resize(peekedLength);
118             auto recvDataLength =
119                 recv(socketFd(), reinterpret_cast<void*>(responseMsg.data()),
120                      peekedLength, 0);
121             auto resphdr =
122                 reinterpret_cast<const pldm_msg_hdr*>(&responseMsg[2]);
123             if (recvDataLength == peekedLength &&
124                 resphdr->instance_id == reqhdr->instance_id &&
125                 resphdr->request != PLDM_REQUEST)
126             {
127                 Logger(pldmVerbose, "Total length:", recvDataLength);
128                 break;
129             }
130             else if (recvDataLength != peekedLength)
131             {
132                 std::cerr << "Failure to read response length packet: length = "
133                           << recvDataLength << "\n";
134                 return returnCode;
135             }
136         } while (1);
137     }
138 
139     returnCode = shutdown(socketFd(), SHUT_RDWR);
140     if (-1 == returnCode)
141     {
142         returnCode = -errno;
143         std::cerr << "Failed to shutdown the socket : RC = " << returnCode
144                   << "\n";
145         return returnCode;
146     }
147 
148     Logger(pldmVerbose, "Shutdown Socket successful :  RC = ", returnCode);
149     return PLDM_SUCCESS;
150 }
151 
152 void CommandInterface::exec()
153 {
154     static constexpr auto pldmObjPath = "/xyz/openbmc_project/pldm";
155     static constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
156     auto& bus = pldm::utils::DBusHandler::getBus();
157     try
158     {
159         auto service =
160             pldm::utils::DBusHandler().getService(pldmObjPath, pldmRequester);
161         auto method = bus.new_method_call(service.c_str(), pldmObjPath,
162                                           pldmRequester, "GetInstanceId");
163         method.append(mctp_eid);
164         auto reply = bus.call(method);
165         reply.read(instanceId);
166     }
167     catch (const std::exception& e)
168     {
169         std::cerr << "GetInstanceId D-Bus call failed, MCTP id = " << mctp_eid
170                   << ", error = " << e.what() << "\n";
171         return;
172     }
173     auto [rc, requestMsg] = createRequestMsg();
174     if (rc != PLDM_SUCCESS)
175     {
176         std::cerr << "Failed to encode request message for " << pldmType << ":"
177                   << commandName << " rc = " << rc << "\n";
178         return;
179     }
180 
181     std::vector<uint8_t> responseMsg;
182     rc = pldmSendRecv(requestMsg, responseMsg);
183 
184     if (rc != PLDM_SUCCESS)
185     {
186         std::cerr << "pldmSendRecv: Failed to receive RC = " << rc << "\n";
187         return;
188     }
189 
190     auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg.data());
191     parseResponseMsg(responsePtr, responseMsg.size() - sizeof(pldm_msg_hdr));
192 }
193 
194 int CommandInterface::pldmSendRecv(std::vector<uint8_t>& requestMsg,
195                                    std::vector<uint8_t>& responseMsg)
196 {
197 
198     // Insert the PLDM message type and EID at the beginning of the
199     // msg.
200     requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
201     requestMsg.insert(requestMsg.begin(), mctp_eid);
202 
203     bool mctpVerbose = pldmVerbose;
204 
205     // By default enable request/response msgs for pldmtool raw commands.
206     if (CommandInterface::pldmType == "raw")
207     {
208         pldmVerbose = true;
209     }
210 
211     Logger(pldmVerbose, "Request Message:", "");
212     printBuffer(requestMsg, pldmVerbose);
213 
214     if (mctp_eid != PLDM_ENTITY_ID)
215     {
216         int fd = pldm_open();
217         if (-1 == fd)
218         {
219             std::cerr << "failed to init mctp "
220                       << "\n";
221             return -1;
222         }
223         uint8_t* responseMessage = nullptr;
224         size_t responseMessageSize{};
225         pldm_send_recv(mctp_eid, fd, requestMsg.data() + 2,
226                        requestMsg.size() - 2, &responseMessage,
227                        &responseMessageSize);
228 
229         Logger(pldmVerbose, "Response Message:", "");
230         responseMsg.resize(responseMessageSize);
231         memcpy(responseMsg.data(), responseMessage, responseMsg.size());
232 
233         free(responseMessage);
234         printBuffer(responseMsg, pldmVerbose);
235     }
236     else
237     {
238         mctpSockSendRecv(requestMsg, responseMsg, mctpVerbose);
239         Logger(pldmVerbose, "Response Message:", "");
240         printBuffer(responseMsg, pldmVerbose);
241         responseMsg.erase(responseMsg.begin(),
242                           responseMsg.begin() + 2 /* skip the mctp header */);
243     }
244     return PLDM_SUCCESS;
245 }
246 } // namespace helper
247 } // namespace pldmtool
248