xref: /openbmc/pldm/common/utils.cpp (revision 03b01ca8)
1 #include "utils.hpp"
2 
3 #include "libpldm/pdr.h"
4 #include "libpldm/pldm_types.h"
5 
6 #include <xyz/openbmc_project/Common/error.hpp>
7 
8 #include <algorithm>
9 #include <array>
10 #include <cctype>
11 #include <ctime>
12 #include <fstream>
13 #include <iostream>
14 #include <map>
15 #include <stdexcept>
16 #include <string>
17 #include <vector>
18 
19 namespace pldm
20 {
21 namespace utils
22 {
23 
24 constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
25 constexpr auto mapperPath = "/xyz/openbmc_project/object_mapper";
26 constexpr auto mapperInterface = "xyz.openbmc_project.ObjectMapper";
27 constexpr auto eidPath = "/usr/share/pldm/host_eid";
28 
29 std::vector<std::vector<uint8_t>> findStateEffecterPDR(uint8_t /*tid*/,
30                                                        uint16_t entityID,
31                                                        uint16_t stateSetId,
32                                                        const pldm_pdr* repo)
33 {
34     uint8_t* outData = nullptr;
35     uint32_t size{};
36     const pldm_pdr_record* record{};
37     std::vector<std::vector<uint8_t>> pdrs;
38     try
39     {
40         do
41         {
42             record = pldm_pdr_find_record_by_type(repo, PLDM_STATE_EFFECTER_PDR,
43                                                   record, &outData, &size);
44             if (record)
45             {
46                 auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(outData);
47                 auto compositeEffecterCount = pdr->composite_effecter_count;
48                 auto possible_states_start = pdr->possible_states;
49 
50                 for (auto effecters = 0x00; effecters < compositeEffecterCount;
51                      effecters++)
52                 {
53                     auto possibleStates =
54                         reinterpret_cast<state_effecter_possible_states*>(
55                             possible_states_start);
56                     auto setId = possibleStates->state_set_id;
57                     auto possibleStateSize =
58                         possibleStates->possible_states_size;
59 
60                     if (pdr->entity_type == entityID && setId == stateSetId)
61                     {
62                         std::vector<uint8_t> effecter_pdr(&outData[0],
63                                                           &outData[size]);
64                         pdrs.emplace_back(std::move(effecter_pdr));
65                         break;
66                     }
67                     possible_states_start += possibleStateSize + sizeof(setId) +
68                                              sizeof(possibleStateSize);
69                 }
70             }
71 
72         } while (record);
73     }
74     catch (const std::exception& e)
75     {
76         std::cerr << " Failed to obtain a record. ERROR =" << e.what()
77                   << std::endl;
78     }
79 
80     return pdrs;
81 }
82 
83 std::vector<std::vector<uint8_t>> findStateSensorPDR(uint8_t /*tid*/,
84                                                      uint16_t entityID,
85                                                      uint16_t stateSetId,
86                                                      const pldm_pdr* repo)
87 {
88     uint8_t* outData = nullptr;
89     uint32_t size{};
90     const pldm_pdr_record* record{};
91     std::vector<std::vector<uint8_t>> pdrs;
92     try
93     {
94         do
95         {
96             record = pldm_pdr_find_record_by_type(repo, PLDM_STATE_SENSOR_PDR,
97                                                   record, &outData, &size);
98             if (record)
99             {
100                 auto pdr = reinterpret_cast<pldm_state_sensor_pdr*>(outData);
101                 auto compositeSensorCount = pdr->composite_sensor_count;
102                 auto possible_states_start = pdr->possible_states;
103 
104                 for (auto sensors = 0x00; sensors < compositeSensorCount;
105                      sensors++)
106                 {
107                     auto possibleStates =
108                         reinterpret_cast<state_sensor_possible_states*>(
109                             possible_states_start);
110                     auto setId = possibleStates->state_set_id;
111                     auto possibleStateSize =
112                         possibleStates->possible_states_size;
113 
114                     if (pdr->entity_type == entityID && setId == stateSetId)
115                     {
116                         std::vector<uint8_t> sensor_pdr(&outData[0],
117                                                         &outData[size]);
118                         pdrs.emplace_back(std::move(sensor_pdr));
119                         break;
120                     }
121                     possible_states_start += possibleStateSize + sizeof(setId) +
122                                              sizeof(possibleStateSize);
123                 }
124             }
125 
126         } while (record);
127     }
128     catch (const std::exception& e)
129     {
130         std::cerr << " Failed to obtain a record. ERROR =" << e.what()
131                   << std::endl;
132     }
133 
134     return pdrs;
135 }
136 
137 uint8_t readHostEID()
138 {
139     uint8_t eid{};
140     std::ifstream eidFile{eidPath};
141     if (!eidFile.good())
142     {
143         std::cerr << "Could not open host EID file"
144                   << "\n";
145     }
146     else
147     {
148         std::string eidStr;
149         eidFile >> eidStr;
150         if (!eidStr.empty())
151         {
152             eid = atoi(eidStr.c_str());
153         }
154         else
155         {
156             std::cerr << "Host EID file was empty"
157                       << "\n";
158         }
159     }
160 
161     return eid;
162 }
163 
164 uint8_t getNumPadBytes(uint32_t data)
165 {
166     uint8_t pad;
167     pad = ((data % 4) ? (4 - data % 4) : 0);
168     return pad;
169 } // end getNumPadBytes
170 
171 bool uintToDate(uint64_t data, uint16_t* year, uint8_t* month, uint8_t* day,
172                 uint8_t* hour, uint8_t* min, uint8_t* sec)
173 {
174     constexpr uint64_t max_data = 29991231115959;
175     constexpr uint64_t min_data = 19700101000000;
176     if (data < min_data || data > max_data)
177     {
178         return false;
179     }
180 
181     *year = data / 10000000000;
182     data = data % 10000000000;
183     *month = data / 100000000;
184     data = data % 100000000;
185     *day = data / 1000000;
186     data = data % 1000000;
187     *hour = data / 10000;
188     data = data % 10000;
189     *min = data / 100;
190     *sec = data % 100;
191 
192     return true;
193 }
194 
195 std::optional<std::vector<set_effecter_state_field>>
196     parseEffecterData(const std::vector<uint8_t>& effecterData,
197                       uint8_t effecterCount)
198 {
199     std::vector<set_effecter_state_field> stateField;
200 
201     if (effecterData.size() != effecterCount * 2)
202     {
203         return std::nullopt;
204     }
205 
206     for (uint8_t i = 0; i < effecterCount; ++i)
207     {
208         uint8_t set_request = effecterData[i * 2] == PLDM_REQUEST_SET
209                                   ? PLDM_REQUEST_SET
210                                   : PLDM_NO_CHANGE;
211         set_effecter_state_field filed{set_request, effecterData[i * 2 + 1]};
212         stateField.emplace_back(std::move(filed));
213     }
214 
215     return std::make_optional(std::move(stateField));
216 }
217 
218 std::string DBusHandler::getService(const char* path,
219                                     const char* interface) const
220 {
221     using DbusInterfaceList = std::vector<std::string>;
222     std::map<std::string, std::vector<std::string>> mapperResponse;
223     auto& bus = DBusHandler::getBus();
224 
225     auto mapper = bus.new_method_call(mapperBusName, mapperPath,
226                                       mapperInterface, "GetObject");
227     mapper.append(path, DbusInterfaceList({interface}));
228 
229     auto mapperResponseMsg = bus.call(mapper);
230     mapperResponseMsg.read(mapperResponse);
231     return mapperResponse.begin()->first;
232 }
233 
234 void reportError(const char* errorMsg)
235 {
236     static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
237     static constexpr auto logInterface = "xyz.openbmc_project.Logging.Create";
238 
239     auto& bus = pldm::utils::DBusHandler::getBus();
240 
241     try
242     {
243         auto service = DBusHandler().getService(logObjPath, logInterface);
244         using namespace sdbusplus::xyz::openbmc_project::Logging::server;
245         auto severity =
246             sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
247                 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
248                     Error);
249         auto method = bus.new_method_call(service.c_str(), logObjPath,
250                                           logInterface, "Create");
251         std::map<std::string, std::string> addlData{};
252         method.append(errorMsg, severity, addlData);
253         bus.call_noreply(method);
254     }
255     catch (const std::exception& e)
256     {
257         std::cerr << "failed to make a d-bus call to create error log, ERROR="
258                   << e.what() << "\n";
259     }
260 }
261 
262 void DBusHandler::setDbusProperty(const DBusMapping& dBusMap,
263                                   const PropertyValue& value) const
264 {
265     auto setDbusValue = [&dBusMap, this](const auto& variant) {
266         auto& bus = getBus();
267         auto service =
268             getService(dBusMap.objectPath.c_str(), dBusMap.interface.c_str());
269         auto method = bus.new_method_call(
270             service.c_str(), dBusMap.objectPath.c_str(), dbusProperties, "Set");
271         method.append(dBusMap.interface.c_str(), dBusMap.propertyName.c_str(),
272                       variant);
273         bus.call_noreply(method);
274     };
275 
276     if (dBusMap.propertyType == "uint8_t")
277     {
278         std::variant<uint8_t> v = std::get<uint8_t>(value);
279         setDbusValue(v);
280     }
281     else if (dBusMap.propertyType == "bool")
282     {
283         std::variant<bool> v = std::get<bool>(value);
284         setDbusValue(v);
285     }
286     else if (dBusMap.propertyType == "int16_t")
287     {
288         std::variant<int16_t> v = std::get<int16_t>(value);
289         setDbusValue(v);
290     }
291     else if (dBusMap.propertyType == "uint16_t")
292     {
293         std::variant<uint16_t> v = std::get<uint16_t>(value);
294         setDbusValue(v);
295     }
296     else if (dBusMap.propertyType == "int32_t")
297     {
298         std::variant<int32_t> v = std::get<int32_t>(value);
299         setDbusValue(v);
300     }
301     else if (dBusMap.propertyType == "uint32_t")
302     {
303         std::variant<uint32_t> v = std::get<uint32_t>(value);
304         setDbusValue(v);
305     }
306     else if (dBusMap.propertyType == "int64_t")
307     {
308         std::variant<int64_t> v = std::get<int64_t>(value);
309         setDbusValue(v);
310     }
311     else if (dBusMap.propertyType == "uint64_t")
312     {
313         std::variant<uint64_t> v = std::get<uint64_t>(value);
314         setDbusValue(v);
315     }
316     else if (dBusMap.propertyType == "double")
317     {
318         std::variant<double> v = std::get<double>(value);
319         setDbusValue(v);
320     }
321     else if (dBusMap.propertyType == "string")
322     {
323         std::variant<std::string> v = std::get<std::string>(value);
324         setDbusValue(v);
325     }
326     else
327     {
328         throw std::invalid_argument("UnSpported Dbus Type");
329     }
330 }
331 
332 PropertyValue DBusHandler::getDbusPropertyVariant(
333     const char* objPath, const char* dbusProp, const char* dbusInterface) const
334 {
335     auto& bus = DBusHandler::getBus();
336     auto service = getService(objPath, dbusInterface);
337     auto method =
338         bus.new_method_call(service.c_str(), objPath, dbusProperties, "Get");
339     method.append(dbusInterface, dbusProp);
340     PropertyValue value{};
341     auto reply = bus.call(method);
342     reply.read(value);
343     return value;
344 }
345 
346 PropertyValue jsonEntryToDbusVal(std::string_view type,
347                                  const nlohmann::json& value)
348 {
349     PropertyValue propValue{};
350     if (type == "uint8_t")
351     {
352         propValue = static_cast<uint8_t>(value);
353     }
354     else if (type == "uint16_t")
355     {
356         propValue = static_cast<uint16_t>(value);
357     }
358     else if (type == "uint32_t")
359     {
360         propValue = static_cast<uint32_t>(value);
361     }
362     else if (type == "uint64_t")
363     {
364         propValue = static_cast<uint64_t>(value);
365     }
366     else if (type == "int16_t")
367     {
368         propValue = static_cast<int16_t>(value);
369     }
370     else if (type == "int32_t")
371     {
372         propValue = static_cast<int32_t>(value);
373     }
374     else if (type == "int64_t")
375     {
376         propValue = static_cast<int64_t>(value);
377     }
378     else if (type == "bool")
379     {
380         propValue = static_cast<bool>(value);
381     }
382     else if (type == "double")
383     {
384         propValue = static_cast<double>(value);
385     }
386     else if (type == "string")
387     {
388         propValue = static_cast<std::string>(value);
389     }
390     else
391     {
392         std::cerr << "Unknown D-Bus property type, TYPE=" << type << "\n";
393     }
394 
395     return propValue;
396 }
397 
398 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType,
399                              uint16_t entityInstance, uint16_t containerId,
400                              uint16_t stateSetId, bool localOrRemote)
401 {
402     uint8_t* pdrData = nullptr;
403     uint32_t pdrSize{};
404     const pldm_pdr_record* record{};
405     do
406     {
407         record = pldm_pdr_find_record_by_type(pdrRepo, PLDM_STATE_EFFECTER_PDR,
408                                               record, &pdrData, &pdrSize);
409         if (record && (localOrRemote ^ pldm_pdr_record_is_remote(record)))
410         {
411             auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrData);
412             auto compositeEffecterCount = pdr->composite_effecter_count;
413             auto possible_states_start = pdr->possible_states;
414 
415             for (auto effecters = 0x00; effecters < compositeEffecterCount;
416                  effecters++)
417             {
418                 auto possibleStates =
419                     reinterpret_cast<state_effecter_possible_states*>(
420                         possible_states_start);
421                 auto setId = possibleStates->state_set_id;
422                 auto possibleStateSize = possibleStates->possible_states_size;
423 
424                 if (entityType == pdr->entity_type &&
425                     entityInstance == pdr->entity_instance &&
426                     containerId == pdr->container_id && stateSetId == setId)
427                 {
428                     return pdr->effecter_id;
429                 }
430                 possible_states_start += possibleStateSize + sizeof(setId) +
431                                          sizeof(possibleStateSize);
432             }
433         }
434     } while (record);
435 
436     return PLDM_INVALID_EFFECTER_ID;
437 }
438 
439 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId,
440                                uint8_t sensorOffset, uint8_t eventState,
441                                uint8_t previousEventState)
442 {
443     try
444     {
445         auto& bus = DBusHandler::getBus();
446         auto msg = bus.new_signal("/xyz/openbmc_project/pldm",
447                                   "xyz.openbmc_project.PLDM.Event",
448                                   "StateSensorEvent");
449         msg.append(tid, sensorId, sensorOffset, eventState, previousEventState);
450 
451         msg.signal_send();
452     }
453     catch (std::exception& e)
454     {
455         std::cerr << "Error emitting pldm event signal:"
456                   << "ERROR=" << e.what() << "\n";
457         return PLDM_ERROR;
458     }
459 
460     return PLDM_SUCCESS;
461 }
462 
463 uint16_t findStateSensorId(const pldm_pdr* pdrRepo, uint8_t tid,
464                            uint16_t entityType, uint16_t entityInstance,
465                            uint16_t containerId, uint16_t stateSetId)
466 {
467     auto pdrs = findStateSensorPDR(tid, entityType, stateSetId, pdrRepo);
468     for (auto pdr : pdrs)
469     {
470         auto sensorPdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data());
471         auto compositeSensorCount = sensorPdr->composite_sensor_count;
472         auto possible_states_start = sensorPdr->possible_states;
473 
474         for (auto sensors = 0x00; sensors < compositeSensorCount; sensors++)
475         {
476             auto possibleStates =
477                 reinterpret_cast<state_sensor_possible_states*>(
478                     possible_states_start);
479             auto setId = possibleStates->state_set_id;
480             auto possibleStateSize = possibleStates->possible_states_size;
481             if (entityType == sensorPdr->entity_type &&
482                 entityInstance == sensorPdr->entity_instance &&
483                 stateSetId == setId && containerId == sensorPdr->container_id)
484             {
485                 return sensorPdr->sensor_id;
486             }
487             possible_states_start +=
488                 possibleStateSize + sizeof(setId) + sizeof(possibleStateSize);
489         }
490     }
491     return PLDM_INVALID_EFFECTER_ID;
492 }
493 
494 void printBuffer(const std::vector<uint8_t>& buffer, bool pldmVerbose)
495 {
496     if (pldmVerbose && !buffer.empty())
497     {
498         std::ostringstream tempStream;
499         for (int byte : buffer)
500         {
501             tempStream << std::setfill('0') << std::setw(2) << std::hex << byte
502                        << " ";
503         }
504         std::cout << tempStream.str() << std::endl;
505     }
506 }
507 
508 std::string toString(const struct variable_field& var)
509 {
510     if (var.ptr == nullptr || !var.length)
511     {
512         return "";
513     }
514 
515     std::string str(reinterpret_cast<const char*>(var.ptr), var.length);
516     std::replace_if(
517         str.begin(), str.end(), [](const char& c) { return !isprint(c); }, ' ');
518     return str;
519 }
520 
521 } // namespace utils
522 } // namespace pldm
523