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