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