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