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