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