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