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 * print the input buffer if pldm verbosity is enabled. 21 * 22 */ 23 void printBuffer(const std::vector<uint8_t>& buffer, bool pldmVerbose) 24 { 25 if (pldmVerbose && !buffer.empty()) 26 { 27 std::ostringstream tempStream; 28 for (int byte : buffer) 29 { 30 tempStream << std::setfill('0') << std::setw(2) << std::hex << byte 31 << " "; 32 } 33 std::cout << tempStream.str() << std::endl; 34 } 35 } 36 /* 37 * Initialize the socket, send pldm command & recieve response from socket 38 * 39 */ 40 int mctpSockSendRecv(const std::vector<uint8_t>& requestMsg, 41 std::vector<uint8_t>& responseMsg, bool pldmVerbose) 42 { 43 44 const char devPath[] = "\0mctp-mux"; 45 int returnCode = 0; 46 47 int sockFd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 48 if (-1 == sockFd) 49 { 50 returnCode = -errno; 51 std::cerr << "Failed to create the socket : RC = " << sockFd << "\n"; 52 return returnCode; 53 } 54 Logger(pldmVerbose, "Success in creating the socket : RC = ", sockFd); 55 56 struct sockaddr_un addr 57 {}; 58 addr.sun_family = AF_UNIX; 59 60 memcpy(addr.sun_path, devPath, sizeof(devPath) - 1); 61 62 CustomFD socketFd(sockFd); 63 int result = connect(socketFd(), reinterpret_cast<struct sockaddr*>(&addr), 64 sizeof(devPath) + sizeof(addr.sun_family) - 1); 65 if (-1 == result) 66 { 67 returnCode = -errno; 68 std::cerr << "Failed to connect to socket : RC = " << returnCode 69 << "\n"; 70 return returnCode; 71 } 72 Logger(pldmVerbose, "Success in connecting to socket : RC = ", returnCode); 73 74 auto pldmType = MCTP_MSG_TYPE_PLDM; 75 result = write(socketFd(), &pldmType, sizeof(pldmType)); 76 if (-1 == result) 77 { 78 returnCode = -errno; 79 std::cerr << "Failed to send message type as pldm to mctp : RC = " 80 << returnCode << "\n"; 81 return returnCode; 82 } 83 Logger( 84 pldmVerbose, 85 "Success in sending message type as pldm to mctp : RC = ", returnCode); 86 87 result = send(socketFd(), requestMsg.data(), requestMsg.size(), 0); 88 if (-1 == result) 89 { 90 returnCode = -errno; 91 std::cerr << "Write to socket failure : RC = " << returnCode << "\n"; 92 return returnCode; 93 } 94 Logger(pldmVerbose, "Write to socket successful : RC = ", result); 95 96 // Read the response from socket 97 ssize_t peekedLength = recv(socketFd(), nullptr, 0, MSG_TRUNC | MSG_PEEK); 98 if (0 == peekedLength) 99 { 100 std::cerr << "Socket is closed : peekedLength = " << peekedLength 101 << "\n"; 102 return returnCode; 103 } 104 else if (peekedLength <= -1) 105 { 106 returnCode = -errno; 107 std::cerr << "recv() system call failed : RC = " << returnCode << "\n"; 108 return returnCode; 109 } 110 else 111 { 112 auto reqhdr = reinterpret_cast<const pldm_msg_hdr*>(&requestMsg[2]); 113 do 114 { 115 ssize_t peekedLength = 116 recv(socketFd(), nullptr, 0, MSG_PEEK | MSG_TRUNC); 117 responseMsg.resize(peekedLength); 118 auto recvDataLength = 119 recv(socketFd(), reinterpret_cast<void*>(responseMsg.data()), 120 peekedLength, 0); 121 auto resphdr = 122 reinterpret_cast<const pldm_msg_hdr*>(&responseMsg[2]); 123 if (recvDataLength == peekedLength && 124 resphdr->instance_id == reqhdr->instance_id && 125 resphdr->request != PLDM_REQUEST) 126 { 127 Logger(pldmVerbose, "Total length:", recvDataLength); 128 break; 129 } 130 else if (recvDataLength != peekedLength) 131 { 132 std::cerr << "Failure to read response length packet: length = " 133 << recvDataLength << "\n"; 134 return returnCode; 135 } 136 } while (1); 137 } 138 139 returnCode = shutdown(socketFd(), SHUT_RDWR); 140 if (-1 == returnCode) 141 { 142 returnCode = -errno; 143 std::cerr << "Failed to shutdown the socket : RC = " << returnCode 144 << "\n"; 145 return returnCode; 146 } 147 148 Logger(pldmVerbose, "Shutdown Socket successful : RC = ", returnCode); 149 return PLDM_SUCCESS; 150 } 151 152 void CommandInterface::exec() 153 { 154 static constexpr auto pldmObjPath = "/xyz/openbmc_project/pldm"; 155 static constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester"; 156 auto& bus = pldm::utils::DBusHandler::getBus(); 157 try 158 { 159 auto service = 160 pldm::utils::DBusHandler().getService(pldmObjPath, pldmRequester); 161 auto method = bus.new_method_call(service.c_str(), pldmObjPath, 162 pldmRequester, "GetInstanceId"); 163 method.append(mctp_eid); 164 auto reply = bus.call(method); 165 reply.read(instanceId); 166 } 167 catch (const std::exception& e) 168 { 169 std::cerr << "GetInstanceId D-Bus call failed, MCTP id = " << mctp_eid 170 << ", error = " << e.what() << "\n"; 171 return; 172 } 173 auto [rc, requestMsg] = createRequestMsg(); 174 if (rc != PLDM_SUCCESS) 175 { 176 std::cerr << "Failed to encode request message for " << pldmType << ":" 177 << commandName << " rc = " << rc << "\n"; 178 return; 179 } 180 181 std::vector<uint8_t> responseMsg; 182 rc = pldmSendRecv(requestMsg, responseMsg); 183 184 if (rc != PLDM_SUCCESS) 185 { 186 std::cerr << "pldmSendRecv: Failed to receive RC = " << rc << "\n"; 187 return; 188 } 189 190 auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg.data()); 191 parseResponseMsg(responsePtr, responseMsg.size() - sizeof(pldm_msg_hdr)); 192 } 193 194 int CommandInterface::pldmSendRecv(std::vector<uint8_t>& requestMsg, 195 std::vector<uint8_t>& responseMsg) 196 { 197 198 // Insert the PLDM message type and EID at the beginning of the 199 // msg. 200 requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM); 201 requestMsg.insert(requestMsg.begin(), mctp_eid); 202 203 bool mctpVerbose = pldmVerbose; 204 205 // By default enable request/response msgs for pldmtool raw commands. 206 if (CommandInterface::pldmType == "raw") 207 { 208 pldmVerbose = true; 209 } 210 211 Logger(pldmVerbose, "Request Message:", ""); 212 printBuffer(requestMsg, pldmVerbose); 213 214 if (mctp_eid != PLDM_ENTITY_ID) 215 { 216 int fd = pldm_open(); 217 if (-1 == fd) 218 { 219 std::cerr << "failed to init mctp " 220 << "\n"; 221 return -1; 222 } 223 uint8_t* responseMessage = nullptr; 224 size_t responseMessageSize{}; 225 pldm_send_recv(mctp_eid, fd, requestMsg.data() + 2, 226 requestMsg.size() - 2, &responseMessage, 227 &responseMessageSize); 228 229 Logger(pldmVerbose, "Response Message:", ""); 230 responseMsg.resize(responseMessageSize); 231 memcpy(responseMsg.data(), responseMessage, responseMsg.size()); 232 233 free(responseMessage); 234 printBuffer(responseMsg, pldmVerbose); 235 } 236 else 237 { 238 mctpSockSendRecv(requestMsg, responseMsg, mctpVerbose); 239 Logger(pldmVerbose, "Response Message:", ""); 240 printBuffer(responseMsg, pldmVerbose); 241 responseMsg.erase(responseMsg.begin(), 242 responseMsg.begin() + 2 /* skip the mctp header */); 243 } 244 return PLDM_SUCCESS; 245 } 246 } // namespace helper 247 } // namespace pldmtool 248