1 
2 #include "platform.hpp"
3 
4 #include "common/utils.hpp"
5 #include "event_parser.hpp"
6 #include "pdr_numeric_effecter.hpp"
7 #include "pdr_state_effecter.hpp"
8 #include "platform_numeric_effecter.hpp"
9 #include "platform_state_effecter.hpp"
10 
11 namespace pldm
12 {
13 namespace responder
14 {
15 namespace platform
16 {
17 
18 using InternalFailure =
19     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
20 
21 static const Json empty{};
22 
23 using EventEntryMap = std::map<EventEntry, DBusInfo>;
24 
25 const EventEntryMap eventEntryMap = {
26     {
27         0x01010007, // SensorID for VMI Port 0 ipv4 = 7, SensorOffset for the
28                     // State Set ID 15 = 1 & PLDM State Set Enumeration List = 1
29                     // (Valid Configuration)
30         {"/xyz/openbmc_project/network/vmi/intf0/ipv4/addr0",
31          "xyz.openbmc_project.Object.Enable", "Enabled", "bool", true},
32     },
33     {
34         0x02010007, // SensorID for VMI Port 0 ipv4 = 7, SensorOffset for the
35                     // State Set ID 15 = 1 & PLDM State Set Enumeration List = 2
36                     // (Invalid Configuration)
37         {"/xyz/openbmc_project/network/vmi/intf0/ipv4/addr0",
38          "xyz.openbmc_project.Object.Enable", "Enabled", "bool", false},
39     },
40     {
41         0x01010008, // SensorID for VMI Port 1 ipv4 = 8, SensorOffset for the
42                     // State Set ID 15 = 1 & PLDM State Set Enumeration List = 1
43                     // (Valid Configuration)
44         {"/xyz/openbmc_project/network/vmi/intf1/ipv4/addr0",
45          "xyz.openbmc_project.Object.Enable", "Enabled", "bool", true},
46     },
47     {
48         0x02010008, // SensorID for VMI Port 1 ipv4 = 8, SensorOffset for the
49                     // State Set ID 15 = 1 & PLDM State Set Enumeration List = 2
50                     // (Invalid Configuration)
51         {"/xyz/openbmc_project/network/vmi/intf1/ipv4/addr0",
52          "xyz.openbmc_project.Object.Enable", "Enabled", "bool", false},
53     }};
54 
55 void Handler::addDbusObjMaps(
56     uint16_t effecterId,
57     std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj)
58 {
59     dbusObjMaps.emplace(effecterId, dbusObj);
60 }
61 
62 const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>&
63     Handler::getDbusObjMaps(uint16_t effecterId) const
64 {
65     return dbusObjMaps.at(effecterId);
66 }
67 
68 void Handler::generate(const std::string& dir, Repo& repo)
69 {
70     // A map of PDR type to a lambda that handles creation of that PDR type.
71     // The lambda essentially would parse the platform specific PDR JSONs to
72     // generate the PDR structures. This function iterates through the map to
73     // invoke all lambdas, so that all PDR types can be created.
74 
75     const std::map<Type, generatePDR> generateHandlers = {
76         {PLDM_STATE_EFFECTER_PDR,
77          [this](const auto& json, RepoInterface& repo) {
78              pdr_state_effecter::generateStateEffecterPDR<Handler>(json, *this,
79                                                                    repo);
80          }},
81         {PLDM_NUMERIC_EFFECTER_PDR,
82          [this](const auto& json, RepoInterface& repo) {
83              pdr_numeric_effecter::generateNumericEffecterPDR<Handler>(
84                  json, *this, repo);
85          }}};
86 
87     Type pdrType{};
88     for (const auto& dirEntry : fs::directory_iterator(dir))
89     {
90         try
91         {
92             auto json = readJson(dirEntry.path().string());
93             if (!json.empty())
94             {
95                 auto effecterPDRs = json.value("effecterPDRs", empty);
96                 for (const auto& effecter : effecterPDRs)
97                 {
98                     pdrType = effecter.value("pdrType", 0);
99                     generateHandlers.at(pdrType)(effecter, repo);
100                 }
101             }
102         }
103         catch (const InternalFailure& e)
104         {
105             std::cerr << "PDR config directory does not exist or empty, TYPE= "
106                       << pdrType << "PATH= " << dirEntry
107                       << " ERROR=" << e.what() << "\n";
108         }
109         catch (const Json::exception& e)
110         {
111             std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType
112                       << " ERROR=" << e.what() << "\n";
113             pldm::utils::reportError(
114                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
115         }
116         catch (const std::exception& e)
117         {
118             std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType
119                       << " ERROR=" << e.what() << "\n";
120             pldm::utils::reportError(
121                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
122         }
123     }
124 }
125 
126 Response Handler::getPDR(const pldm_msg* request, size_t payloadLength)
127 {
128     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0);
129     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
130 
131     if (payloadLength != PLDM_GET_PDR_REQ_BYTES)
132     {
133         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
134     }
135 
136     uint32_t recordHandle{};
137     uint32_t dataTransferHandle{};
138     uint8_t transferOpFlag{};
139     uint16_t reqSizeBytes{};
140     uint16_t recordChangeNum{};
141 
142     auto rc = decode_get_pdr_req(request, payloadLength, &recordHandle,
143                                  &dataTransferHandle, &transferOpFlag,
144                                  &reqSizeBytes, &recordChangeNum);
145     if (rc != PLDM_SUCCESS)
146     {
147         return CmdHandler::ccOnlyResponse(request, rc);
148     }
149 
150     uint16_t respSizeBytes{};
151     uint8_t* recordData = nullptr;
152     try
153     {
154         pdr_utils::PdrEntry e;
155         auto record = pdr::getRecordByHandle(pdrRepo, recordHandle, e);
156         if (record == NULL)
157         {
158             return CmdHandler::ccOnlyResponse(
159                 request, PLDM_PLATFORM_INVALID_RECORD_HANDLE);
160         }
161 
162         if (reqSizeBytes)
163         {
164             respSizeBytes = e.size;
165             if (respSizeBytes > reqSizeBytes)
166             {
167                 respSizeBytes = reqSizeBytes;
168             }
169             recordData = e.data;
170         }
171         response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES +
172                             respSizeBytes,
173                         0);
174         responsePtr = reinterpret_cast<pldm_msg*>(response.data());
175         rc = encode_get_pdr_resp(
176             request->hdr.instance_id, PLDM_SUCCESS, e.handle.nextRecordHandle,
177             0, PLDM_START_AND_END, respSizeBytes, recordData, 0, responsePtr);
178         if (rc != PLDM_SUCCESS)
179         {
180             return ccOnlyResponse(request, rc);
181         }
182     }
183     catch (const std::exception& e)
184     {
185         std::cerr << "Error accessing PDR, HANDLE=" << recordHandle
186                   << " ERROR=" << e.what() << "\n";
187         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR);
188     }
189     return response;
190 }
191 
192 Response Handler::setStateEffecterStates(const pldm_msg* request,
193                                          size_t payloadLength)
194 {
195     Response response(
196         sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0);
197     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
198     uint16_t effecterId;
199     uint8_t compEffecterCnt;
200     constexpr auto maxCompositeEffecterCnt = 8;
201     std::vector<set_effecter_state_field> stateField(maxCompositeEffecterCnt,
202                                                      {0, 0});
203 
204     if ((payloadLength > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) ||
205         (payloadLength < sizeof(effecterId) + sizeof(compEffecterCnt) +
206                              sizeof(set_effecter_state_field)))
207     {
208         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
209     }
210 
211     int rc = decode_set_state_effecter_states_req(request, payloadLength,
212                                                   &effecterId, &compEffecterCnt,
213                                                   stateField.data());
214 
215     if (rc != PLDM_SUCCESS)
216     {
217         return CmdHandler::ccOnlyResponse(request, rc);
218     }
219 
220     stateField.resize(compEffecterCnt);
221     const pldm::utils::DBusHandler dBusIntf;
222     rc = platform_state_effecter::setStateEffecterStatesHandler<
223         pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId,
224                                            stateField);
225     if (rc != PLDM_SUCCESS)
226     {
227         return CmdHandler::ccOnlyResponse(request, rc);
228     }
229 
230     rc = encode_set_state_effecter_states_resp(request->hdr.instance_id, rc,
231                                                responsePtr);
232     if (rc != PLDM_SUCCESS)
233     {
234         return ccOnlyResponse(request, rc);
235     }
236 
237     return response;
238 }
239 
240 Response Handler::platformEventMessage(const pldm_msg* request,
241                                        size_t payloadLength)
242 {
243     uint8_t formatVersion{};
244     uint8_t tid{};
245     uint8_t eventClass{};
246     size_t offset{};
247 
248     auto rc = decode_platform_event_message_req(
249         request, payloadLength, &formatVersion, &tid, &eventClass, &offset);
250     if (rc != PLDM_SUCCESS)
251     {
252         return CmdHandler::ccOnlyResponse(request, rc);
253     }
254 
255     try
256     {
257         const auto& handlers = eventHandlers.at(eventClass);
258         for (const auto& handler : handlers)
259         {
260             auto rc =
261                 handler(request, payloadLength, formatVersion, tid, offset);
262             if (rc != PLDM_SUCCESS)
263             {
264                 return CmdHandler::ccOnlyResponse(request, rc);
265             }
266         }
267     }
268     catch (const std::out_of_range& e)
269     {
270         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_DATA);
271     }
272 
273     Response response(
274         sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES, 0);
275     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
276 
277     rc = encode_platform_event_message_resp(request->hdr.instance_id, rc,
278                                             PLDM_EVENT_NO_LOGGING, responsePtr);
279     if (rc != PLDM_SUCCESS)
280     {
281         return ccOnlyResponse(request, rc);
282     }
283 
284     return response;
285 }
286 
287 int Handler::sensorEvent(const pldm_msg* request, size_t payloadLength,
288                          uint8_t /*formatVersion*/, uint8_t tid,
289                          size_t eventDataOffset)
290 {
291     uint16_t sensorId{};
292     uint8_t eventClass{};
293     size_t eventClassDataOffset{};
294     auto eventData =
295         reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset;
296     auto eventDataSize = payloadLength - eventDataOffset;
297 
298     auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId,
299                                        &eventClass, &eventClassDataOffset);
300     if (rc != PLDM_SUCCESS)
301     {
302         return rc;
303     }
304 
305     auto eventClassData = reinterpret_cast<const uint8_t*>(request->payload) +
306                           eventDataOffset + eventClassDataOffset;
307     auto eventClassDataSize =
308         payloadLength - eventDataOffset - eventClassDataOffset;
309 
310     if (eventClass == PLDM_STATE_SENSOR_STATE)
311     {
312         uint8_t sensorOffset{};
313         uint8_t eventState{};
314         uint8_t previousEventState{};
315 
316         rc = decode_state_sensor_data(eventClassData, eventClassDataSize,
317                                       &sensorOffset, &eventState,
318                                       &previousEventState);
319         if (rc != PLDM_SUCCESS)
320         {
321             return PLDM_ERROR;
322         }
323 
324         // Handle PLDM events for which PDR is not available, setSensorEventData
325         // will return PLDM_ERROR_INVALID_DATA if the sensorID is not found in
326         // the hardcoded sensor list.
327         rc = setSensorEventData(sensorId, sensorOffset, eventState);
328         if (rc != PLDM_ERROR_INVALID_DATA)
329         {
330             return rc;
331         }
332 
333         // If there are no HOST PDR's, there is no further action
334         if (hostPDRHandler == NULL)
335         {
336             return PLDM_SUCCESS;
337         }
338 
339         // Handle PLDM events for which PDR is available
340         SensorEntry sensorEntry{tid, sensorId};
341         try
342         {
343             const auto& [entityInfo, compositeSensorStates] =
344                 hostPDRHandler->lookupSensorInfo(sensorEntry);
345             if (sensorOffset >= compositeSensorStates.size())
346             {
347                 return PLDM_ERROR_INVALID_DATA;
348             }
349 
350             const auto& possibleStates = compositeSensorStates[sensorOffset];
351             if (possibleStates.find(eventState) == possibleStates.end())
352             {
353                 return PLDM_ERROR_INVALID_DATA;
354             }
355 
356             const auto& [containerId, entityType, entityInstance] = entityInfo;
357             events::StateSensorEntry stateSensorEntry{
358                 containerId, entityType, entityInstance, sensorOffset};
359             return stateSensorHandler.eventAction(stateSensorEntry, eventState);
360         }
361         // If there is no mapping for events return PLDM_SUCCESS
362         catch (const std::out_of_range& e)
363         {
364             return PLDM_SUCCESS;
365         }
366     }
367     else
368     {
369         return PLDM_ERROR_INVALID_DATA;
370     }
371 
372     return PLDM_SUCCESS;
373 }
374 
375 int Handler::setSensorEventData(uint16_t sensorId, uint8_t sensorOffset,
376                                 uint8_t eventState)
377 {
378     EventEntry eventEntry = ((static_cast<uint32_t>(eventState)) << 24) +
379                             ((static_cast<uint32_t>(sensorOffset)) << 16) +
380                             sensorId;
381     auto iter = eventEntryMap.find(eventEntry);
382     if (iter == eventEntryMap.end())
383     {
384         return PLDM_ERROR_INVALID_DATA;
385     }
386 
387     const auto& dBusInfo = iter->second;
388     try
389     {
390         pldm::utils::DBusMapping dbusMapping{
391             dBusInfo.dBusValues.objectPath, dBusInfo.dBusValues.interface,
392             dBusInfo.dBusValues.propertyName, dBusInfo.dBusValues.propertyType};
393         pldm::utils::DBusHandler().setDbusProperty(dbusMapping,
394                                                    dBusInfo.dBusPropertyValue);
395     }
396     catch (std::exception& e)
397     {
398         std::cerr
399             << "Error Setting dbus property,SensorID=" << eventEntry
400             << "DBusInfo=" << dBusInfo.dBusValues.objectPath
401             << dBusInfo.dBusValues.interface << dBusInfo.dBusValues.propertyName
402             << "ERROR=" << e.what() << "\n";
403         return PLDM_ERROR;
404     }
405     return PLDM_SUCCESS;
406 }
407 
408 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request,
409                                        size_t payloadLength,
410                                        uint8_t /*formatVersion*/,
411                                        uint8_t /*tid*/, size_t eventDataOffset)
412 {
413     uint8_t eventDataFormat{};
414     uint8_t numberOfChangeRecords{};
415     size_t dataOffset{};
416 
417     auto eventData =
418         reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset;
419     auto eventDataSize = payloadLength - eventDataOffset;
420 
421     auto rc = decode_pldm_pdr_repository_chg_event_data(
422         eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords,
423         &dataOffset);
424     if (rc != PLDM_SUCCESS)
425     {
426         return rc;
427     }
428 
429     PDRRecordHandles pdrRecordHandles;
430     if (eventDataFormat == FORMAT_IS_PDR_HANDLES)
431     {
432         uint8_t eventDataOperation{};
433         uint8_t numberOfChangeEntries{};
434 
435         auto changeRecordData = eventData + dataOffset;
436         auto changeRecordDataSize = eventDataSize - dataOffset;
437 
438         while (changeRecordDataSize)
439         {
440             rc = decode_pldm_pdr_repository_change_record_data(
441                 changeRecordData, changeRecordDataSize, &eventDataOperation,
442                 &numberOfChangeEntries, &dataOffset);
443 
444             if (rc != PLDM_SUCCESS)
445             {
446                 return rc;
447             }
448 
449             if (eventDataOperation == PLDM_RECORDS_ADDED)
450             {
451                 rc = getPDRRecordHandles(
452                     reinterpret_cast<const ChangeEntry*>(changeRecordData +
453                                                          dataOffset),
454                     changeRecordDataSize - dataOffset,
455                     static_cast<size_t>(numberOfChangeEntries),
456                     pdrRecordHandles);
457 
458                 if (rc != PLDM_SUCCESS)
459                 {
460                     return rc;
461                 }
462             }
463 
464             changeRecordData +=
465                 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry));
466             changeRecordDataSize -=
467                 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry));
468         }
469 
470         if (hostPDRHandler && !pdrRecordHandles.empty())
471         {
472             hostPDRHandler->fetchPDR(std::move(pdrRecordHandles));
473         }
474     }
475     else
476     {
477         return PLDM_ERROR_INVALID_DATA;
478     }
479 
480     return PLDM_SUCCESS;
481 }
482 
483 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData,
484                                  size_t changeEntryDataSize,
485                                  size_t numberOfChangeEntries,
486                                  PDRRecordHandles& pdrRecordHandles)
487 {
488     if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry)))
489     {
490         return PLDM_ERROR_INVALID_DATA;
491     }
492     for (size_t i = 0; i < numberOfChangeEntries; i++)
493     {
494         pdrRecordHandles.push_back(changeEntryData[i]);
495     }
496     return PLDM_SUCCESS;
497 }
498 
499 Response Handler::setNumericEffecterValue(const pldm_msg* request,
500                                           size_t payloadLength)
501 {
502     Response response(sizeof(pldm_msg_hdr) +
503                       PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES);
504     uint16_t effecterId{};
505     uint8_t effecterDataSize{};
506     uint8_t effecterValue[4] = {};
507 
508     if ((payloadLength > sizeof(effecterId) + sizeof(effecterDataSize) +
509                              sizeof(union_effecter_data_size)) ||
510         (payloadLength < sizeof(effecterId) + sizeof(effecterDataSize) + 1))
511     {
512         return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
513     }
514 
515     int rc = decode_set_numeric_effecter_value_req(
516         request, payloadLength, &effecterId, &effecterDataSize,
517         reinterpret_cast<uint8_t*>(&effecterValue));
518 
519     if (rc == PLDM_SUCCESS)
520     {
521         const pldm::utils::DBusHandler dBusIntf;
522         rc = platform_numeric_effecter::setNumericEffecterValueHandler<
523             pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId,
524                                                effecterDataSize, effecterValue,
525                                                sizeof(effecterValue));
526     }
527 
528     return ccOnlyResponse(request, rc);
529 }
530 
531 } // namespace platform
532 } // namespace responder
533 } // namespace pldm
534