xref: /openbmc/pldm/pldmtool/pldm_cmd_helper.cpp (revision 96a3a048)
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  * Initialize the socket, send pldm command & recieve response from socket
21  *
22  */
23 int mctpSockSendRecv(const std::vector<uint8_t>& requestMsg,
24                      std::vector<uint8_t>& responseMsg, bool pldmVerbose)
25 {
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 = " << mctp_eid
153                   << ", 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 
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     Logger(pldmVerbose, "Request Message:", "");
195     printBuffer(requestMsg, pldmVerbose);
196 
197     if (mctp_eid != PLDM_ENTITY_ID)
198     {
199         int fd = pldm_open();
200         if (-1 == fd)
201         {
202             std::cerr << "failed to init mctp "
203                       << "\n";
204             return -1;
205         }
206         uint8_t* responseMessage = nullptr;
207         size_t responseMessageSize{};
208         pldm_send_recv(mctp_eid, fd, requestMsg.data() + 2,
209                        requestMsg.size() - 2, &responseMessage,
210                        &responseMessageSize);
211 
212         Logger(pldmVerbose, "Response Message:", "");
213         responseMsg.resize(responseMessageSize);
214         memcpy(responseMsg.data(), responseMessage, responseMsg.size());
215 
216         free(responseMessage);
217         printBuffer(responseMsg, pldmVerbose);
218     }
219     else
220     {
221         mctpSockSendRecv(requestMsg, responseMsg, mctpVerbose);
222         Logger(pldmVerbose, "Response Message:", "");
223         printBuffer(responseMsg, pldmVerbose);
224         responseMsg.erase(responseMsg.begin(),
225                           responseMsg.begin() + 2 /* skip the mctp header */);
226     }
227     return PLDM_SUCCESS;
228 }
229 } // namespace helper
230 } // namespace pldmtool
231