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