1 /**
2  * Copyright © 2019 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "pldm_oem_cmds.hpp"
17 
18 #include "dump_utils.hpp"
19 #include "pldm_utils.hpp"
20 #include "xyz/openbmc_project/Common/error.hpp"
21 
22 #include <libpldm/base.h>
23 #include <libpldm/file_io.h>
24 #include <libpldm/platform.h>
25 #include <unistd.h>
26 
27 #include <fstream>
28 #include <phosphor-logging/elog-errors.hpp>
29 #include <phosphor-logging/log.hpp>
30 #include <sdbusplus/bus.hpp>
31 
32 namespace phosphor
33 {
34 namespace dump
35 {
36 namespace host
37 {
38 /**
39  * @brief Initiate offload of the dump with provided id
40  *
41  * @param[in] id - The Dump Source ID.
42  *
43  */
44 void requestOffload(uint32_t id)
45 {
46     pldm::requestOffload(id);
47 }
48 
49 void requestDelete(uint32_t id, uint32_t dumpType)
50 {
51     pldm::requestDelete(id, dumpType);
52 }
53 } // namespace host
54 
55 namespace pldm
56 {
57 
58 using namespace phosphor::logging;
59 
60 constexpr auto eidPath = "/usr/share/pldm/host_eid";
61 constexpr mctp_eid_t defaultEIDValue = 9;
62 
63 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
64 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
65 
66 mctp_eid_t readEID()
67 {
68     mctp_eid_t eid = defaultEIDValue;
69 
70     std::ifstream eidFile{eidPath};
71     if (!eidFile.good())
72     {
73         log<level::ERR>("Could not open host EID file");
74         elog<NotAllowed>(Reason("Required host dump action via pldm is not "
75                                 "allowed due to mctp end point read failed"));
76     }
77     else
78     {
79         std::string eid;
80         eidFile >> eid;
81         if (!eid.empty())
82         {
83             eid = strtol(eid.c_str(), nullptr, 10);
84         }
85         else
86         {
87             log<level::ERR>("EID file was empty");
88             elog<NotAllowed>(
89                 Reason("Required host dump action via pldm is not "
90                        "allowed due to mctp end point read failed"));
91         }
92     }
93 
94     return eid;
95 }
96 
97 void requestOffload(uint32_t id)
98 {
99     uint16_t effecterId = 0x05; // TODO PhyP temporary Hardcoded value.
100 
101     std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(id) +
102                             sizeof(uint8_t)>
103         requestMsg{};
104     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
105 
106     std::array<uint8_t, sizeof(id)> effecterValue{};
107 
108     memcpy(effecterValue.data(), &id, sizeof(id));
109 
110     mctp_eid_t eid = readEID();
111 
112     auto instanceID = getPLDMInstanceID(eid);
113 
114     auto rc = encode_set_numeric_effecter_value_req(
115         instanceID, effecterId, PLDM_EFFECTER_DATA_SIZE_UINT32,
116         effecterValue.data(), request,
117         requestMsg.size() - sizeof(pldm_msg_hdr));
118 
119     if (rc != PLDM_SUCCESS)
120     {
121         log<level::ERR>("Message encode failure. ", entry("RC=%d", rc));
122         elog<NotAllowed>(Reason("Host dump offload via pldm is not "
123                                 "allowed due to encode failed"));
124     }
125 
126     uint8_t* responseMsg = nullptr;
127     size_t responseMsgSize{};
128 
129     CustomFd fd(openPLDM());
130 
131     rc = pldm_send_recv(eid, fd(), requestMsg.data(), requestMsg.size(),
132                         &responseMsg, &responseMsgSize);
133     if (rc < 0)
134     {
135         auto e = errno;
136         log<level::ERR>("pldm_send failed", entry("RC=%d", rc),
137                         entry("ERRNO=%d", e));
138         elog<NotAllowed>(Reason("Host dump offload via pldm is not "
139                                 "allowed due to fileack send failed"));
140     }
141     pldm_msg* response = reinterpret_cast<pldm_msg*>(responseMsg);
142     log<level::INFO>(
143         "Done. PLDM message",
144         entry("RC=%d", static_cast<uint16_t>(response->payload[0])));
145 }
146 
147 void requestDelete(uint32_t dumpId, uint32_t dumpType)
148 {
149     pldm_fileio_file_type pldmDumpType;
150     switch (dumpType)
151     {
152         case PLDM_FILE_TYPE_DUMP:
153             pldmDumpType = PLDM_FILE_TYPE_DUMP;
154             break;
155         case PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS:
156             pldmDumpType = PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS;
157             break;
158         default:
159             throw std::runtime_error("Unknown pldm dump file-io type to delete "
160                                      "host dump");
161     }
162     const size_t pldmMsgHdrSize = sizeof(pldm_msg_hdr);
163     std::array<uint8_t, pldmMsgHdrSize + PLDM_FILE_ACK_REQ_BYTES> fileAckReqMsg;
164 
165     mctp_eid_t mctpEndPointId = readEID();
166 
167     auto pldmInstanceId = getPLDMInstanceID(mctpEndPointId);
168 
169     // - PLDM_SUCCESS - To indicate dump was readed (offloaded) or user decided,
170     //   no longer host dump is not required so, initiate deletion from
171     //   host memory
172     int retCode =
173         encode_file_ack_req(pldmInstanceId, pldmDumpType, dumpId, PLDM_SUCCESS,
174                             reinterpret_cast<pldm_msg*>(fileAckReqMsg.data()));
175 
176     if (retCode != PLDM_SUCCESS)
177     {
178         log<level::ERR>("Failed to encode pldm FileAck to delete host dump",
179                         entry("SRC_DUMP_ID=%d", dumpId),
180                         entry("PLDM_FILE_IO_TYPE=%d", pldmDumpType),
181                         entry("PLDM_RETURN_CODE=%d", retCode));
182         elog<NotAllowed>(Reason("Host dump deletion via pldm is not "
183                                 "allowed due to encode fileack failed"));
184     }
185 
186     uint8_t* pldmRespMsg = nullptr;
187     size_t pldmRespMsgSize;
188 
189     CustomFd pldmFd(openPLDM());
190 
191     retCode =
192         pldm_send_recv(mctpEndPointId, pldmFd(), fileAckReqMsg.data(),
193                        fileAckReqMsg.size(), &pldmRespMsg, &pldmRespMsgSize);
194 
195     std::unique_ptr<uint8_t, decltype(std::free)*> pldmRespMsgPtr{pldmRespMsg,
196                                                                   std::free};
197     if (retCode != PLDM_REQUESTER_SUCCESS)
198     {
199         auto errorNumber = errno;
200         log<level::ERR>("Failed to send pldm FileAck to delete host dump",
201                         entry("SRC_DUMP_ID=%d", dumpId),
202                         entry("PLDM_FILE_IO_TYPE=%d", pldmDumpType),
203                         entry("PLDM_RETURN_CODE=%d", retCode),
204                         entry("ERRNO=%d", errorNumber),
205                         entry("ERRMSG=%s", strerror(errorNumber)));
206         elog<NotAllowed>(Reason("Host dump deletion via pldm is not "
207                                 "allowed due to fileack send failed"));
208     }
209 
210     uint8_t completionCode;
211 
212     retCode =
213         decode_file_ack_resp(reinterpret_cast<pldm_msg*>(pldmRespMsgPtr.get()),
214                              pldmRespMsgSize - pldmMsgHdrSize, &completionCode);
215 
216     if (retCode || completionCode)
217     {
218         log<level::ERR>("Failed to delete host dump",
219                         entry("SRC_DUMP_ID=%d", dumpId),
220                         entry("PLDM_FILE_IO_TYPE=%d", pldmDumpType),
221                         entry("PLDM_RETURN_CODE=%d", retCode),
222                         entry("PLDM_COMPLETION_CODE=%d", completionCode));
223         elog<NotAllowed>(Reason("Host dump deletion via pldm is "
224                                 "failed"));
225     }
226 
227     log<level::INFO>("Deleted host dump", entry("SRC_DUMP_ID=%d", dumpId));
228 }
229 } // namespace pldm
230 } // namespace dump
231 } // namespace phosphor
232