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