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