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