xref: /openbmc/pldm/pldmtool/pldm_cmd_helper.cpp (revision a7dbca53)
1 #include "config.h"
2 
3 #include "pldm_cmd_helper.hpp"
4 
5 #include "xyz/openbmc_project/Common/error.hpp"
6 
7 #include <libpldm/pldm.h>
8 #include <systemd/sd-bus.h>
9 
10 #include <sdbusplus/server.hpp>
11 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
12 
13 #include <exception>
14 
15 using namespace pldm::utils;
16 
17 namespace pldmtool
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 = recv(socketFd(), nullptr, 0,
100                                         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 = pldm::utils::DBusHandler().getService(pldmObjPath,
144                                                              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(
149             method,
150             std::chrono::duration_cast<microsec>(sec(DBUS_TIMEOUT)).count());
151         reply.read(instanceId);
152     }
153     catch (const std::exception& e)
154     {
155         std::cerr << "GetInstanceId D-Bus call failed, MCTP id = "
156                   << (unsigned)mctp_eid << ", error = " << e.what() << "\n";
157         return;
158     }
159     auto [rc, requestMsg] = createRequestMsg();
160     if (rc != PLDM_SUCCESS)
161     {
162         std::cerr << "Failed to encode request message for " << pldmType << ":"
163                   << commandName << " rc = " << rc << "\n";
164         return;
165     }
166 
167     std::vector<uint8_t> responseMsg;
168     rc = pldmSendRecv(requestMsg, responseMsg);
169 
170     if (rc != PLDM_SUCCESS)
171     {
172         std::cerr << "pldmSendRecv: Failed to receive RC = " << rc << "\n";
173         return;
174     }
175 
176     auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg.data());
177     parseResponseMsg(responsePtr, responseMsg.size() - sizeof(pldm_msg_hdr));
178 }
179 
180 int CommandInterface::pldmSendRecv(std::vector<uint8_t>& requestMsg,
181                                    std::vector<uint8_t>& responseMsg)
182 {
183     // Insert the PLDM message type and EID at the beginning of the
184     // msg.
185     requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
186     requestMsg.insert(requestMsg.begin(), mctp_eid);
187 
188     bool mctpVerbose = pldmVerbose;
189 
190     // By default enable request/response msgs for pldmtool raw commands.
191     if (CommandInterface::pldmType == "raw")
192     {
193         pldmVerbose = true;
194     }
195 
196     if (pldmVerbose)
197     {
198         std::cout << "pldmtool: ";
199         printBuffer(Tx, requestMsg);
200     }
201 
202     if (mctp_eid != PLDM_ENTITY_ID)
203     {
204         int fd = pldm_open();
205         if (-1 == fd)
206         {
207             std::cerr << "failed to init mctp "
208                       << "\n";
209             return -1;
210         }
211         uint8_t* responseMessage = nullptr;
212         size_t responseMessageSize{};
213         pldm_send_recv(mctp_eid, fd, requestMsg.data() + 2,
214                        requestMsg.size() - 2, &responseMessage,
215                        &responseMessageSize);
216 
217         responseMsg.resize(responseMessageSize);
218         memcpy(responseMsg.data(), responseMessage, responseMsg.size());
219 
220         shutdown(fd, SHUT_RDWR);
221         free(responseMessage);
222 
223         if (pldmVerbose)
224         {
225             std::cout << "pldmtool: ";
226             printBuffer(Rx, responseMsg);
227         }
228     }
229     else
230     {
231         mctpSockSendRecv(requestMsg, responseMsg, mctpVerbose);
232         if (pldmVerbose)
233         {
234             std::cout << "pldmtool: ";
235             printBuffer(Rx, responseMsg);
236         }
237         responseMsg.erase(responseMsg.begin(),
238                           responseMsg.begin() + 2 /* skip the mctp header */);
239     }
240     return PLDM_SUCCESS;
241 }
242 } // namespace helper
243 } // namespace pldmtool
244