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