1 #include "config.h" 2 3 #include "pldm_cmd_helper.hpp" 4 5 #include "xyz/openbmc_project/Common/error.hpp" 6 7 #include <libpldm/pldm.h> 8 #include <systemd/sd-bus.h> 9 10 #include <sdbusplus/server.hpp> 11 #include <xyz/openbmc_project/Logging/Entry/server.hpp> 12 13 #include <exception> 14 15 using namespace pldm::utils; 16 17 namespace pldmtool 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 = recv(socketFd(), nullptr, 0, 100 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 = pldm::utils::DBusHandler().getService(pldmObjPath, 144 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( 149 method, 150 std::chrono::duration_cast<microsec>(sec(DBUS_TIMEOUT)).count()); 151 reply.read(instanceId); 152 } 153 catch (const std::exception& e) 154 { 155 std::cerr << "GetInstanceId D-Bus call failed, MCTP id = " 156 << (unsigned)mctp_eid << ", error = " << e.what() << "\n"; 157 return; 158 } 159 auto [rc, requestMsg] = createRequestMsg(); 160 if (rc != PLDM_SUCCESS) 161 { 162 std::cerr << "Failed to encode request message for " << pldmType << ":" 163 << commandName << " rc = " << rc << "\n"; 164 return; 165 } 166 167 std::vector<uint8_t> responseMsg; 168 rc = pldmSendRecv(requestMsg, responseMsg); 169 170 if (rc != PLDM_SUCCESS) 171 { 172 std::cerr << "pldmSendRecv: Failed to receive RC = " << rc << "\n"; 173 return; 174 } 175 176 auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg.data()); 177 parseResponseMsg(responsePtr, responseMsg.size() - sizeof(pldm_msg_hdr)); 178 } 179 180 int CommandInterface::pldmSendRecv(std::vector<uint8_t>& requestMsg, 181 std::vector<uint8_t>& responseMsg) 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 shutdown(fd, SHUT_RDWR); 221 free(responseMessage); 222 223 if (pldmVerbose) 224 { 225 std::cout << "pldmtool: "; 226 printBuffer(Rx, responseMsg); 227 } 228 } 229 else 230 { 231 mctpSockSendRecv(requestMsg, responseMsg, mctpVerbose); 232 if (pldmVerbose) 233 { 234 std::cout << "pldmtool: "; 235 printBuffer(Rx, responseMsg); 236 } 237 responseMsg.erase(responseMsg.begin(), 238 responseMsg.begin() + 2 /* skip the mctp header */); 239 } 240 return PLDM_SUCCESS; 241 } 242 } // namespace helper 243 } // namespace pldmtool 244