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