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 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 = 100 recv(socketFd(), nullptr, 0, 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 = 144 pldm::utils::DBusHandler().getService(pldmObjPath, 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(method); 149 reply.read(instanceId); 150 } 151 catch (const std::exception& e) 152 { 153 std::cerr << "GetInstanceId D-Bus call failed, MCTP id = " 154 << (unsigned)mctp_eid << ", error = " << e.what() << "\n"; 155 return; 156 } 157 auto [rc, requestMsg] = createRequestMsg(); 158 if (rc != PLDM_SUCCESS) 159 { 160 std::cerr << "Failed to encode request message for " << pldmType << ":" 161 << commandName << " rc = " << rc << "\n"; 162 return; 163 } 164 165 std::vector<uint8_t> responseMsg; 166 rc = pldmSendRecv(requestMsg, responseMsg); 167 168 if (rc != PLDM_SUCCESS) 169 { 170 std::cerr << "pldmSendRecv: Failed to receive RC = " << rc << "\n"; 171 return; 172 } 173 174 auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg.data()); 175 parseResponseMsg(responsePtr, responseMsg.size() - sizeof(pldm_msg_hdr)); 176 } 177 178 int CommandInterface::pldmSendRecv(std::vector<uint8_t>& requestMsg, 179 std::vector<uint8_t>& responseMsg) 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 if (pldmVerbose) 195 { 196 std::cout << "pldmtool: "; 197 printBuffer(Tx, requestMsg); 198 } 199 200 if (mctp_eid != PLDM_ENTITY_ID) 201 { 202 int fd = pldm_open(); 203 if (-1 == fd) 204 { 205 std::cerr << "failed to init mctp " 206 << "\n"; 207 return -1; 208 } 209 uint8_t* responseMessage = nullptr; 210 size_t responseMessageSize{}; 211 pldm_send_recv(mctp_eid, fd, requestMsg.data() + 2, 212 requestMsg.size() - 2, &responseMessage, 213 &responseMessageSize); 214 215 responseMsg.resize(responseMessageSize); 216 memcpy(responseMsg.data(), responseMessage, responseMsg.size()); 217 218 free(responseMessage); 219 if (pldmVerbose) 220 { 221 std::cout << "pldmtool: "; 222 printBuffer(Rx, responseMsg); 223 } 224 } 225 else 226 { 227 mctpSockSendRecv(requestMsg, responseMsg, mctpVerbose); 228 if (pldmVerbose) 229 { 230 std::cout << "pldmtool: "; 231 printBuffer(Rx, responseMsg); 232 } 233 responseMsg.erase(responseMsg.begin(), 234 responseMsg.begin() + 2 /* skip the mctp header */); 235 } 236 return PLDM_SUCCESS; 237 } 238 } // namespace helper 239 } // namespace pldmtool 240