1 
2 #include "platform.hpp"
3 
4 #include "pdr_state_effecter.hpp"
5 #include "utils.hpp"
6 
7 namespace pldm
8 {
9 namespace responder
10 {
11 namespace platform
12 {
13 
14 using InternalFailure =
15     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
16 
17 static const Json empty{};
18 
19 void Handler::addDbusObjMaps(
20     uint16_t effecterId,
21     std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj)
22 {
23     dbusObjMaps.emplace(effecterId, dbusObj);
24 }
25 
26 const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>&
27     Handler::getDbusObjMaps(uint16_t effecterId) const
28 {
29     return dbusObjMaps.at(effecterId);
30 }
31 
32 void Handler::generate(const std::string& dir, Repo& repo)
33 {
34     // A map of PDR type to a lambda that handles creation of that PDR type.
35     // The lambda essentially would parse the platform specific PDR JSONs to
36     // generate the PDR structures. This function iterates through the map to
37     // invoke all lambdas, so that all PDR types can be created.
38 
39     const std::map<Type, generatePDR> generateHandlers = {
40         {PLDM_STATE_EFFECTER_PDR,
41          [this](const auto& json, RepoInterface& repo) {
42              pdr_state_effecter::generateStateEffecterPDR<Handler>(json, *this,
43                                                                    repo);
44          }}};
45 
46     Type pdrType{};
47     for (const auto& dirEntry : fs::directory_iterator(dir))
48     {
49         try
50         {
51             auto json = readJson(dirEntry.path().string());
52             if (!json.empty())
53             {
54                 auto effecterPDRs = json.value("effecterPDRs", empty);
55                 for (const auto& effecter : effecterPDRs)
56                 {
57                     pdrType = effecter.value("pdrType", 0);
58                     generateHandlers.at(pdrType)(effecter, repo);
59                 }
60             }
61         }
62         catch (const InternalFailure& e)
63         {
64             std::cerr << "PDR config directory does not exist or empty, TYPE= "
65                       << pdrType << "PATH= " << dirEntry
66                       << " ERROR=" << e.what() << "\n";
67         }
68         catch (const Json::exception& e)
69         {
70             std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType
71                       << " ERROR=" << e.what() << "\n";
72             pldm::utils::reportError(
73                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
74         }
75         catch (const std::exception& e)
76         {
77             std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType
78                       << " ERROR=" << e.what() << "\n";
79             pldm::utils::reportError(
80                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
81         }
82     }
83 }
84 
85 Response Handler::getPDR(const pldm_msg* request, size_t payloadLength)
86 {
87     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0);
88     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
89 
90     if (payloadLength != PLDM_GET_PDR_REQ_BYTES)
91     {
92         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
93     }
94 
95     uint32_t recordHandle{};
96     uint32_t dataTransferHandle{};
97     uint8_t transferOpFlag{};
98     uint16_t reqSizeBytes{};
99     uint16_t recordChangeNum{};
100 
101     auto rc = decode_get_pdr_req(request, payloadLength, &recordHandle,
102                                  &dataTransferHandle, &transferOpFlag,
103                                  &reqSizeBytes, &recordChangeNum);
104     if (rc != PLDM_SUCCESS)
105     {
106         return CmdHandler::ccOnlyResponse(request, rc);
107     }
108 
109     uint16_t respSizeBytes{};
110     uint8_t* recordData = nullptr;
111     try
112     {
113         pdr_utils::PdrEntry e;
114         auto record = pdr::getRecordByHandle(pdrRepo, recordHandle, e);
115         if (record == NULL)
116         {
117             return CmdHandler::ccOnlyResponse(
118                 request, PLDM_PLATFORM_INVALID_RECORD_HANDLE);
119         }
120 
121         if (reqSizeBytes)
122         {
123             respSizeBytes = e.size;
124             if (respSizeBytes > reqSizeBytes)
125             {
126                 respSizeBytes = reqSizeBytes;
127             }
128             recordData = e.data;
129         }
130         response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES +
131                             respSizeBytes,
132                         0);
133         responsePtr = reinterpret_cast<pldm_msg*>(response.data());
134         rc = encode_get_pdr_resp(
135             request->hdr.instance_id, PLDM_SUCCESS, e.handle.nextRecordHandle,
136             0, PLDM_START_AND_END, respSizeBytes, recordData, 0, responsePtr);
137         if (rc != PLDM_SUCCESS)
138         {
139             return ccOnlyResponse(request, rc);
140         }
141     }
142     catch (const std::exception& e)
143     {
144         std::cerr << "Error accessing PDR, HANDLE=" << recordHandle
145                   << " ERROR=" << e.what() << "\n";
146         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR);
147     }
148     return response;
149 }
150 
151 Response Handler::setStateEffecterStates(const pldm_msg* request,
152                                          size_t payloadLength)
153 {
154     Response response(
155         sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0);
156     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
157     uint16_t effecterId;
158     uint8_t compEffecterCnt;
159     constexpr auto maxCompositeEffecterCnt = 8;
160     std::vector<set_effecter_state_field> stateField(maxCompositeEffecterCnt,
161                                                      {0, 0});
162 
163     if ((payloadLength > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) ||
164         (payloadLength < sizeof(effecterId) + sizeof(compEffecterCnt) +
165                              sizeof(set_effecter_state_field)))
166     {
167         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
168     }
169 
170     int rc = decode_set_state_effecter_states_req(request, payloadLength,
171                                                   &effecterId, &compEffecterCnt,
172                                                   stateField.data());
173 
174     if (rc != PLDM_SUCCESS)
175     {
176         return CmdHandler::ccOnlyResponse(request, rc);
177     }
178 
179     stateField.resize(compEffecterCnt);
180     const pldm::utils::DBusHandler dBusIntf;
181     rc = setStateEffecterStatesHandler<pldm::utils::DBusHandler>(
182         dBusIntf, effecterId, stateField);
183     if (rc != PLDM_SUCCESS)
184     {
185         return CmdHandler::ccOnlyResponse(request, rc);
186     }
187 
188     rc = encode_set_state_effecter_states_resp(request->hdr.instance_id, rc,
189                                                responsePtr);
190     if (rc != PLDM_SUCCESS)
191     {
192         return ccOnlyResponse(request, rc);
193     }
194 
195     return response;
196 }
197 
198 Response Handler::platformEventMessage(const pldm_msg* request,
199                                        size_t payloadLength)
200 {
201     uint8_t formatVersion{};
202     uint8_t tid{};
203     uint8_t eventClass{};
204     size_t offset{};
205 
206     auto rc = decode_platform_event_message_req(
207         request, payloadLength, &formatVersion, &tid, &eventClass, &offset);
208     if (rc != PLDM_SUCCESS)
209     {
210         return CmdHandler::ccOnlyResponse(request, rc);
211     }
212 
213     try
214     {
215         const auto& handlers = eventHandlers.at(eventClass);
216         for (const auto& handler : handlers)
217         {
218             auto rc =
219                 handler(request, payloadLength, formatVersion, tid, offset);
220             if (rc != PLDM_SUCCESS)
221             {
222                 return CmdHandler::ccOnlyResponse(request, rc);
223             }
224         }
225     }
226     catch (const std::out_of_range& e)
227     {
228         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_DATA);
229     }
230 
231     Response response(
232         sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES, 0);
233     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
234 
235     rc = encode_platform_event_message_resp(request->hdr.instance_id, rc,
236                                             PLDM_EVENT_NO_LOGGING, responsePtr);
237     if (rc != PLDM_SUCCESS)
238     {
239         return ccOnlyResponse(request, rc);
240     }
241 
242     return response;
243 }
244 
245 int Handler::sensorEvent(const pldm_msg* request, size_t payloadLength,
246                          uint8_t /*formatVersion*/, uint8_t /*tid*/,
247                          size_t eventDataOffset)
248 {
249     uint16_t sensorId{};
250     uint8_t eventClass{};
251     size_t eventClassDataOffset{};
252     auto eventData =
253         reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset;
254     auto eventDataSize = payloadLength - eventDataOffset;
255 
256     auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId,
257                                        &eventClass, &eventClassDataOffset);
258     if (rc != PLDM_SUCCESS)
259     {
260         return rc;
261     }
262 
263     if (eventClass == PLDM_STATE_SENSOR_STATE)
264     {
265         uint8_t sensorOffset{};
266         uint8_t eventState{};
267         uint8_t previousEventState{};
268 
269         rc = decode_state_sensor_data(&eventClass, eventClassDataOffset,
270                                       &sensorOffset, &eventState,
271                                       &previousEventState);
272     }
273     else
274     {
275         return PLDM_ERROR_INVALID_DATA;
276     }
277 
278     return PLDM_SUCCESS;
279 }
280 
281 } // namespace platform
282 } // namespace responder
283 } // namespace pldm
284