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