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 = recv(socketFd(), nullptr, 0, 99 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 = pldm::utils::DBusHandler().getService(pldmObjPath, 143 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