xref: /openbmc/pldm/common/utils.cpp (revision 7ad45b401134e3b3a05a75200dbba00afd5aee46)
1 #include "utils.hpp"
2 
3 #include <libpldm/pdr.h>
4 #include <libpldm/pldm_types.h>
5 #include <linux/mctp.h>
6 
7 #include <xyz/openbmc_project/Common/error.hpp>
8 #include <xyz/openbmc_project/Logging/Create/client.hpp>
9 #include <xyz/openbmc_project/ObjectMapper/client.hpp>
10 
11 #include <algorithm>
12 #include <array>
13 #include <cctype>
14 #include <ctime>
15 #include <fstream>
16 #include <iostream>
17 #include <map>
18 #include <stdexcept>
19 #include <string>
20 #include <vector>
21 
22 PHOSPHOR_LOG2_USING;
23 
24 namespace pldm
25 {
26 namespace utils
27 {
28 
29 using ObjectMapper = sdbusplus::client::xyz::openbmc_project::ObjectMapper<>;
30 
31 constexpr const char* MCTP_INTERFACE_CC = "au.com.codeconstruct.MCTP.Endpoint1";
32 constexpr const char* MCTP_ENDPOINT_RECOVER_METHOD = "Recover";
33 
findStateEffecterPDR(uint8_t,uint16_t entityID,uint16_t stateSetId,const pldm_pdr * repo)34 std::vector<std::vector<uint8_t>> findStateEffecterPDR(
35     uint8_t /*tid*/, uint16_t entityID, uint16_t stateSetId,
36     const pldm_pdr* repo)
37 {
38     uint8_t* outData = nullptr;
39     uint32_t size{};
40     const pldm_pdr_record* record{};
41     std::vector<std::vector<uint8_t>> pdrs;
42     try
43     {
44         do
45         {
46             record = pldm_pdr_find_record_by_type(repo, PLDM_STATE_EFFECTER_PDR,
47                                                   record, &outData, &size);
48             if (record)
49             {
50                 auto pdr = new (outData) pldm_state_effecter_pdr;
51                 auto compositeEffecterCount = pdr->composite_effecter_count;
52                 auto possible_states_start = pdr->possible_states;
53 
54                 for (auto effecters = 0x00; effecters < compositeEffecterCount;
55                      effecters++)
56                 {
57                     auto possibleStates = new (possible_states_start)
58                         state_effecter_possible_states;
59                     auto setId = possibleStates->state_set_id;
60                     auto possibleStateSize =
61                         possibleStates->possible_states_size;
62 
63                     if (pdr->entity_type == entityID && setId == stateSetId)
64                     {
65                         std::vector<uint8_t> effecter_pdr(&outData[0],
66                                                           &outData[size]);
67                         pdrs.emplace_back(std::move(effecter_pdr));
68                         break;
69                     }
70                     possible_states_start += possibleStateSize + sizeof(setId) +
71                                              sizeof(possibleStateSize);
72                 }
73             }
74 
75         } while (record);
76     }
77     catch (const std::exception& e)
78     {
79         error("Failed to obtain a record, error - {ERROR}", "ERROR", e);
80     }
81 
82     return pdrs;
83 }
84 
findStateSensorPDR(uint8_t,uint16_t entityID,uint16_t stateSetId,const pldm_pdr * repo)85 std::vector<std::vector<uint8_t>> findStateSensorPDR(
86     uint8_t /*tid*/, uint16_t entityID, 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 = new (outData) pldm_state_sensor_pdr;
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 = new (possible_states_start)
109                         state_sensor_possible_states;
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         error(
131             "Failed to obtain a record with entity ID '{ENTITYID}', error - {ERROR}",
132             "ENTITYID", entityID, "ERROR", e);
133     }
134 
135     return pdrs;
136 }
137 
readHostEID()138 uint8_t readHostEID()
139 {
140     uint8_t eid{};
141     std::ifstream eidFile{HOST_EID_PATH};
142     if (!eidFile.good())
143     {
144         error("Failed to open remote terminus EID file at path '{PATH}'",
145               "PATH", static_cast<std::string>(HOST_EID_PATH));
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             error("Remote terminus EID file was empty");
158         }
159     }
160 
161     return eid;
162 }
163 
isValidEID(eid mctpEid)164 bool isValidEID(eid mctpEid)
165 {
166     if (mctpEid == MCTP_ADDR_NULL || mctpEid < MCTP_START_VALID_EID ||
167         mctpEid == MCTP_ADDR_ANY)
168     {
169         return false;
170     }
171 
172     return true;
173 }
174 
getNumPadBytes(uint32_t data)175 uint8_t getNumPadBytes(uint32_t data)
176 {
177     uint8_t pad;
178     pad = ((data % 4) ? (4 - data % 4) : 0);
179     return pad;
180 } // end getNumPadBytes
181 
uintToDate(uint64_t data,uint16_t * year,uint8_t * month,uint8_t * day,uint8_t * hour,uint8_t * min,uint8_t * sec)182 bool uintToDate(uint64_t data, uint16_t* year, uint8_t* month, uint8_t* day,
183                 uint8_t* hour, uint8_t* min, uint8_t* sec)
184 {
185     constexpr uint64_t max_data = 29991231115959;
186     constexpr uint64_t min_data = 19700101000000;
187     if (data < min_data || data > max_data)
188     {
189         return false;
190     }
191 
192     *year = data / 10000000000;
193     data = data % 10000000000;
194     *month = data / 100000000;
195     data = data % 100000000;
196     *day = data / 1000000;
197     data = data % 1000000;
198     *hour = data / 10000;
199     data = data % 10000;
200     *min = data / 100;
201     *sec = data % 100;
202 
203     return true;
204 }
205 
parseEffecterData(const std::vector<uint8_t> & effecterData,uint8_t effecterCount)206 std::optional<std::vector<set_effecter_state_field>> parseEffecterData(
207     const std::vector<uint8_t>& effecterData, uint8_t effecterCount)
208 {
209     std::vector<set_effecter_state_field> stateField;
210 
211     if (effecterData.size() != effecterCount * 2)
212     {
213         return std::nullopt;
214     }
215 
216     for (uint8_t i = 0; i < effecterCount; ++i)
217     {
218         uint8_t set_request = effecterData[i * 2] == PLDM_REQUEST_SET
219                                   ? PLDM_REQUEST_SET
220                                   : PLDM_NO_CHANGE;
221         set_effecter_state_field filed{set_request, effecterData[i * 2 + 1]};
222         stateField.emplace_back(std::move(filed));
223     }
224 
225     return std::make_optional(std::move(stateField));
226 }
227 
getService(const char * path,const char * interface) const228 std::string DBusHandler::getService(const char* path,
229                                     const char* interface) const
230 {
231     using DbusInterfaceList = std::vector<std::string>;
232     std::map<std::string, std::vector<std::string>> mapperResponse;
233     auto& bus = DBusHandler::getBus();
234 
235     auto mapper = bus.new_method_call(ObjectMapper::default_service,
236                                       ObjectMapper::instance_path,
237                                       ObjectMapper::interface, "GetObject");
238 
239     if (interface)
240     {
241         mapper.append(path, DbusInterfaceList({interface}));
242     }
243     else
244     {
245         mapper.append(path, DbusInterfaceList({}));
246     }
247 
248     auto mapperResponseMsg = bus.call(mapper, dbusTimeout);
249     mapperResponseMsg.read(mapperResponse);
250     return mapperResponse.begin()->first;
251 }
252 
getSubtree(const std::string & searchPath,int depth,const std::vector<std::string> & ifaceList) const253 GetSubTreeResponse DBusHandler::getSubtree(
254     const std::string& searchPath, int depth,
255     const std::vector<std::string>& ifaceList) const
256 {
257     auto& bus = pldm::utils::DBusHandler::getBus();
258     auto method = bus.new_method_call(ObjectMapper::default_service,
259                                       ObjectMapper::instance_path,
260                                       ObjectMapper::interface, "GetSubTree");
261     method.append(searchPath, depth, ifaceList);
262     auto reply = bus.call(method, dbusTimeout);
263     GetSubTreeResponse response;
264     reply.read(response);
265     return response;
266 }
267 
getSubTreePaths(const std::string & objectPath,int depth,const std::vector<std::string> & ifaceList) const268 GetSubTreePathsResponse DBusHandler::getSubTreePaths(
269     const std::string& objectPath, int depth,
270     const std::vector<std::string>& ifaceList) const
271 {
272     std::vector<std::string> paths;
273     auto& bus = pldm::utils::DBusHandler::getBus();
274     auto method = bus.new_method_call(
275         ObjectMapper::default_service, ObjectMapper::instance_path,
276         ObjectMapper::interface, "GetSubTreePaths");
277     method.append(objectPath, depth, ifaceList);
278     auto reply = bus.call(method, dbusTimeout);
279 
280     reply.read(paths);
281     return paths;
282 }
283 
getAncestors(const std::string & path,const std::vector<std::string> & ifaceList) const284 GetAncestorsResponse DBusHandler::getAncestors(
285     const std::string& path, const std::vector<std::string>& ifaceList) const
286 {
287     auto& bus = pldm::utils::DBusHandler::getBus();
288     auto method = bus.new_method_call(ObjectMapper::default_service,
289                                       ObjectMapper::instance_path,
290                                       ObjectMapper::interface, "GetAncestors");
291     method.append(path, ifaceList);
292     auto reply = bus.call(method, dbusTimeout);
293     GetAncestorsResponse response;
294     reply.read(response);
295     return response;
296 }
297 
reportError(const char * errorMsg)298 void reportError(const char* errorMsg)
299 {
300     auto& bus = pldm::utils::DBusHandler::getBus();
301     using LoggingCreate =
302         sdbusplus::client::xyz::openbmc_project::logging::Create<>;
303     try
304     {
305         using namespace sdbusplus::xyz::openbmc_project::Logging::server;
306         auto severity =
307             sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
308                 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
309                     Error);
310         auto method = bus.new_method_call(LoggingCreate::default_service,
311                                           LoggingCreate::instance_path,
312                                           LoggingCreate::interface, "Create");
313 
314         std::map<std::string, std::string> addlData{};
315         method.append(errorMsg, severity, addlData);
316         bus.call_noreply(method, dbusTimeout);
317     }
318     catch (const std::exception& e)
319     {
320         error(
321             "Failed to do dbus call for creating error log for '{ERRMSG}' at path '{PATH}' and interface '{INTERFACE}', error - {ERROR}",
322             "ERRMSG", errorMsg, "PATH", LoggingCreate::instance_path,
323             "INTERFACE", LoggingCreate::interface, "ERROR", e);
324     }
325 }
326 
setDbusProperty(const DBusMapping & dBusMap,const PropertyValue & value) const327 void DBusHandler::setDbusProperty(const DBusMapping& dBusMap,
328                                   const PropertyValue& value) const
329 {
330     auto setDbusValue = [&dBusMap, this](const auto& variant) {
331         auto& bus = getBus();
332         auto service =
333             getService(dBusMap.objectPath.c_str(), dBusMap.interface.c_str());
334         auto method = bus.new_method_call(
335             service.c_str(), dBusMap.objectPath.c_str(), dbusProperties, "Set");
336         method.append(dBusMap.interface.c_str(), dBusMap.propertyName.c_str(),
337                       variant);
338         bus.call_noreply(method, dbusTimeout);
339     };
340 
341     if (dBusMap.propertyType == "uint8_t")
342     {
343         std::variant<uint8_t> v = std::get<uint8_t>(value);
344         setDbusValue(v);
345     }
346     else if (dBusMap.propertyType == "bool")
347     {
348         std::variant<bool> v = std::get<bool>(value);
349         setDbusValue(v);
350     }
351     else if (dBusMap.propertyType == "int16_t")
352     {
353         std::variant<int16_t> v = std::get<int16_t>(value);
354         setDbusValue(v);
355     }
356     else if (dBusMap.propertyType == "uint16_t")
357     {
358         std::variant<uint16_t> v = std::get<uint16_t>(value);
359         setDbusValue(v);
360     }
361     else if (dBusMap.propertyType == "int32_t")
362     {
363         std::variant<int32_t> v = std::get<int32_t>(value);
364         setDbusValue(v);
365     }
366     else if (dBusMap.propertyType == "uint32_t")
367     {
368         std::variant<uint32_t> v = std::get<uint32_t>(value);
369         setDbusValue(v);
370     }
371     else if (dBusMap.propertyType == "int64_t")
372     {
373         std::variant<int64_t> v = std::get<int64_t>(value);
374         setDbusValue(v);
375     }
376     else if (dBusMap.propertyType == "uint64_t")
377     {
378         std::variant<uint64_t> v = std::get<uint64_t>(value);
379         setDbusValue(v);
380     }
381     else if (dBusMap.propertyType == "double")
382     {
383         std::variant<double> v = std::get<double>(value);
384         setDbusValue(v);
385     }
386     else if (dBusMap.propertyType == "string")
387     {
388         std::variant<std::string> v = std::get<std::string>(value);
389         setDbusValue(v);
390     }
391     else if (dBusMap.propertyType == "array[string]")
392     {
393         std::variant<std::vector<std::string>> v =
394             std::get<std::vector<std::string>>(value);
395         setDbusValue(v);
396     }
397     else
398     {
399         error("Unsupported property type '{TYPE}'", "TYPE",
400               dBusMap.propertyType);
401         throw std::invalid_argument("UnSupported Dbus Type");
402     }
403 }
404 
getDbusPropertyVariant(const char * objPath,const char * dbusProp,const char * dbusInterface) const405 PropertyValue DBusHandler::getDbusPropertyVariant(
406     const char* objPath, const char* dbusProp, const char* dbusInterface) const
407 {
408     auto& bus = DBusHandler::getBus();
409     auto service = getService(objPath, dbusInterface);
410     auto method =
411         bus.new_method_call(service.c_str(), objPath, dbusProperties, "Get");
412     method.append(dbusInterface, dbusProp);
413     return bus.call(method, dbusTimeout).unpack<PropertyValue>();
414 }
415 
getAssociatedSubTree(const sdbusplus::message::object_path & objectPath,const sdbusplus::message::object_path & subtree,int depth,const std::vector<std::string> & ifaceList) const416 GetAssociatedSubTreeResponse DBusHandler::getAssociatedSubTree(
417     const sdbusplus::message::object_path& objectPath,
418     const sdbusplus::message::object_path& subtree, int depth,
419     const std::vector<std::string>& ifaceList) const
420 {
421     auto& bus = DBusHandler::getBus();
422     auto method = bus.new_method_call(
423         ObjectMapper::default_service, ObjectMapper::instance_path,
424         ObjectMapper::interface, "GetAssociatedSubTree");
425     method.append(objectPath, subtree, depth, ifaceList);
426     auto reply = bus.call(method, dbusTimeout);
427     GetAssociatedSubTreeResponse response;
428     reply.read(response);
429     return response;
430 }
431 
getManagedObj(const char * service,const char * rootPath)432 ObjectValueTree DBusHandler::getManagedObj(const char* service,
433                                            const char* rootPath)
434 {
435     auto& bus = DBusHandler::getBus();
436     auto method = bus.new_method_call(service, rootPath,
437                                       "org.freedesktop.DBus.ObjectManager",
438                                       "GetManagedObjects");
439     return bus.call(method).unpack<ObjectValueTree>();
440 }
441 
getDbusPropertiesVariant(const char * serviceName,const char * objPath,const char * dbusInterface) const442 PropertyMap DBusHandler::getDbusPropertiesVariant(
443     const char* serviceName, const char* objPath,
444     const char* dbusInterface) const
445 {
446     auto& bus = DBusHandler::getBus();
447     auto method =
448         bus.new_method_call(serviceName, objPath, dbusProperties, "GetAll");
449     method.append(dbusInterface);
450     return bus.call(method, dbusTimeout).unpack<PropertyMap>();
451 }
452 
jsonEntryToDbusVal(std::string_view type,const nlohmann::json & value)453 PropertyValue jsonEntryToDbusVal(std::string_view type,
454                                  const nlohmann::json& value)
455 {
456     PropertyValue propValue{};
457     if (type == "uint8_t")
458     {
459         propValue = static_cast<uint8_t>(value);
460     }
461     else if (type == "uint16_t")
462     {
463         propValue = static_cast<uint16_t>(value);
464     }
465     else if (type == "uint32_t")
466     {
467         propValue = static_cast<uint32_t>(value);
468     }
469     else if (type == "uint64_t")
470     {
471         propValue = static_cast<uint64_t>(value);
472     }
473     else if (type == "int16_t")
474     {
475         propValue = static_cast<int16_t>(value);
476     }
477     else if (type == "int32_t")
478     {
479         propValue = static_cast<int32_t>(value);
480     }
481     else if (type == "int64_t")
482     {
483         propValue = static_cast<int64_t>(value);
484     }
485     else if (type == "bool")
486     {
487         propValue = static_cast<bool>(value);
488     }
489     else if (type == "double")
490     {
491         propValue = static_cast<double>(value);
492     }
493     else if (type == "string")
494     {
495         propValue = static_cast<std::string>(value);
496     }
497     else
498     {
499         error("Unknown D-Bus property type '{TYPE}'", "TYPE", type);
500     }
501 
502     return propValue;
503 }
504 
findStateEffecterId(const pldm_pdr * pdrRepo,uint16_t entityType,uint16_t entityInstance,uint16_t containerId,uint16_t stateSetId,bool localOrRemote)505 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType,
506                              uint16_t entityInstance, uint16_t containerId,
507                              uint16_t stateSetId, bool localOrRemote)
508 {
509     uint8_t* pdrData = nullptr;
510     uint32_t pdrSize{};
511     const pldm_pdr_record* record{};
512     do
513     {
514         record = pldm_pdr_find_record_by_type(pdrRepo, PLDM_STATE_EFFECTER_PDR,
515                                               record, &pdrData, &pdrSize);
516         if (record && (localOrRemote ^ pldm_pdr_record_is_remote(record)))
517         {
518             auto pdr = new (pdrData) pldm_state_effecter_pdr;
519             auto compositeEffecterCount = pdr->composite_effecter_count;
520             auto possible_states_start = pdr->possible_states;
521 
522             for (auto effecters = 0x00; effecters < compositeEffecterCount;
523                  effecters++)
524             {
525                 auto possibleStates = new (possible_states_start)
526                     state_effecter_possible_states;
527                 auto setId = possibleStates->state_set_id;
528                 auto possibleStateSize = possibleStates->possible_states_size;
529 
530                 if (entityType == pdr->entity_type &&
531                     entityInstance == pdr->entity_instance &&
532                     containerId == pdr->container_id && stateSetId == setId)
533                 {
534                     return pdr->effecter_id;
535                 }
536                 possible_states_start += possibleStateSize + sizeof(setId) +
537                                          sizeof(possibleStateSize);
538             }
539         }
540     } while (record);
541 
542     return PLDM_INVALID_EFFECTER_ID;
543 }
544 
emitStateSensorEventSignal(uint8_t tid,uint16_t sensorId,uint8_t sensorOffset,uint8_t eventState,uint8_t previousEventState)545 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId,
546                                uint8_t sensorOffset, uint8_t eventState,
547                                uint8_t previousEventState)
548 {
549     try
550     {
551         auto& bus = DBusHandler::getBus();
552         auto msg = bus.new_signal("/xyz/openbmc_project/pldm",
553                                   "xyz.openbmc_project.PLDM.Event",
554                                   "StateSensorEvent");
555         msg.append(tid, sensorId, sensorOffset, eventState, previousEventState);
556 
557         msg.signal_send();
558     }
559     catch (const std::exception& e)
560     {
561         error("Failed to emit pldm event signal, error - {ERROR}", "ERROR", e);
562         return PLDM_ERROR;
563     }
564 
565     return PLDM_SUCCESS;
566 }
567 
recoverMctpEndpoint(const std::string & endpointObjPath)568 void recoverMctpEndpoint(const std::string& endpointObjPath)
569 {
570     auto& bus = DBusHandler::getBus();
571     try
572     {
573         std::string service = DBusHandler().getService(endpointObjPath.c_str(),
574                                                        MCTP_INTERFACE_CC);
575 
576         auto method = bus.new_method_call(
577             service.c_str(), endpointObjPath.c_str(), MCTP_INTERFACE_CC,
578             MCTP_ENDPOINT_RECOVER_METHOD);
579         bus.call_noreply(method, dbusTimeout);
580     }
581     catch (const std::exception& e)
582     {
583         error(
584             "failed to make a D-Bus call to recover MCTP Endpoint, ERROR {ERR_EXCEP}",
585             "ERR_EXCEP", e);
586     }
587 }
588 
findStateSensorId(const pldm_pdr * pdrRepo,uint8_t tid,uint16_t entityType,uint16_t entityInstance,uint16_t containerId,uint16_t stateSetId)589 uint16_t findStateSensorId(const pldm_pdr* pdrRepo, uint8_t tid,
590                            uint16_t entityType, uint16_t entityInstance,
591                            uint16_t containerId, uint16_t stateSetId)
592 {
593     auto pdrs = findStateSensorPDR(tid, entityType, stateSetId, pdrRepo);
594     for (auto pdr : pdrs)
595     {
596         auto sensorPdr = new (pdr.data()) pldm_state_sensor_pdr;
597         auto compositeSensorCount = sensorPdr->composite_sensor_count;
598         auto possible_states_start = sensorPdr->possible_states;
599 
600         for (auto sensors = 0x00; sensors < compositeSensorCount; sensors++)
601         {
602             auto possibleStates = new (possible_states_start)
603                 state_sensor_possible_states;
604             auto setId = possibleStates->state_set_id;
605             auto possibleStateSize = possibleStates->possible_states_size;
606             if (entityType == sensorPdr->entity_type &&
607                 entityInstance == sensorPdr->entity_instance &&
608                 stateSetId == setId && containerId == sensorPdr->container_id)
609             {
610                 return sensorPdr->sensor_id;
611             }
612             possible_states_start +=
613                 possibleStateSize + sizeof(setId) + sizeof(possibleStateSize);
614         }
615     }
616     return PLDM_INVALID_EFFECTER_ID;
617 }
618 
printBuffer(bool isTx,const std::vector<uint8_t> & buffer)619 void printBuffer(bool isTx, const std::vector<uint8_t>& buffer)
620 {
621     if (buffer.empty())
622     {
623         return;
624     }
625 
626     std::cout << (isTx ? "Tx: " : "Rx: ");
627 
628     std::ranges::for_each(buffer, [](uint8_t byte) {
629         std::cout << std::format("{:02x} ", byte);
630     });
631 
632     std::cout << std::endl;
633 }
634 
toString(const struct variable_field & var)635 std::string toString(const struct variable_field& var)
636 {
637     if (var.ptr == nullptr || !var.length)
638     {
639         return "";
640     }
641 
642     std::string str(reinterpret_cast<const char*>(var.ptr), var.length);
643     std::replace_if(
644         str.begin(), str.end(), [](const char& c) { return !isprint(c); }, ' ');
645     return str;
646 }
647 
split(std::string_view srcStr,std::string_view delim,std::string_view trimStr)648 std::vector<std::string> split(std::string_view srcStr, std::string_view delim,
649                                std::string_view trimStr)
650 {
651     std::vector<std::string> out;
652     size_t start = 0;
653     size_t end = 0;
654 
655     while ((start = srcStr.find_first_not_of(delim, end)) != std::string::npos)
656     {
657         end = srcStr.find(delim, start);
658         std::string_view dstStr = srcStr.substr(start, end - start);
659         if (!trimStr.empty())
660         {
661             dstStr.remove_prefix(dstStr.find_first_not_of(trimStr));
662             dstStr.remove_suffix(
663                 dstStr.size() - 1 - dstStr.find_last_not_of(trimStr));
664         }
665 
666         if (!dstStr.empty())
667         {
668             out.emplace_back(dstStr);
669         }
670     }
671 
672     return out;
673 }
674 
getCurrentSystemTime()675 std::string getCurrentSystemTime()
676 {
677     const auto zonedTime{std::chrono::zoned_time{
678         std::chrono::current_zone(), std::chrono::system_clock::now()}};
679     return std::format("{:%F %Z %T}", zonedTime);
680 }
681 
checkForFruPresence(const std::string & objPath)682 bool checkForFruPresence(const std::string& objPath)
683 {
684     bool isPresent = false;
685     static constexpr auto presentInterface =
686         "xyz.openbmc_project.Inventory.Item";
687     static constexpr auto presentProperty = "Present";
688     try
689     {
690         auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant(
691             objPath.c_str(), presentProperty, presentInterface);
692         isPresent = std::get<bool>(propVal);
693     }
694     catch (const sdbusplus::exception::SdBusError& e)
695     {
696         error("Failed to check for FRU presence at {PATH}, error - {ERROR}",
697               "PATH", objPath, "ERROR", e);
698     }
699     return isPresent;
700 }
701 
checkIfLogicalBitSet(const uint16_t & containerId)702 bool checkIfLogicalBitSet(const uint16_t& containerId)
703 {
704     return !(containerId & 0x8000);
705 }
706 
setFruPresence(const std::string & fruObjPath,bool present)707 void setFruPresence(const std::string& fruObjPath, bool present)
708 {
709     pldm::utils::PropertyValue value{present};
710     pldm::utils::DBusMapping dbusMapping;
711     dbusMapping.objectPath = fruObjPath;
712     dbusMapping.interface = "xyz.openbmc_project.Inventory.Item";
713     dbusMapping.propertyName = "Present";
714     dbusMapping.propertyType = "bool";
715     try
716     {
717         pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
718     }
719     catch (const std::exception& e)
720     {
721         error(
722             "Failed to set the present property on path '{PATH}', error - {ERROR}.",
723             "PATH", fruObjPath, "ERROR", e);
724     }
725 }
726 
trimNameForDbus(std::string & name)727 std::string_view trimNameForDbus(std::string& name)
728 {
729     std::replace(name.begin(), name.end(), ' ', '_');
730     auto nullTerminatorPos = name.find('\0');
731     if (nullTerminatorPos != std::string::npos)
732     {
733         name.erase(nullTerminatorPos);
734     }
735     return name;
736 }
737 
dbusPropValuesToDouble(const std::string_view & type,const pldm::utils::PropertyValue & value,double * doubleValue)738 bool dbusPropValuesToDouble(const std::string_view& type,
739                             const pldm::utils::PropertyValue& value,
740                             double* doubleValue)
741 {
742     if (!dbusValueNumericTypeNames.contains(type))
743     {
744         return false;
745     }
746 
747     if (!doubleValue)
748     {
749         return false;
750     }
751 
752     try
753     {
754         if (type == "uint8_t")
755         {
756             *doubleValue = static_cast<double>(std::get<uint8_t>(value));
757         }
758         else if (type == "int16_t")
759         {
760             *doubleValue = static_cast<double>(std::get<int16_t>(value));
761         }
762         else if (type == "uint16_t")
763         {
764             *doubleValue = static_cast<double>(std::get<uint16_t>(value));
765         }
766         else if (type == "int32_t")
767         {
768             *doubleValue = static_cast<double>(std::get<int32_t>(value));
769         }
770         else if (type == "uint32_t")
771         {
772             *doubleValue = static_cast<double>(std::get<uint32_t>(value));
773         }
774         else if (type == "int64_t")
775         {
776             *doubleValue = static_cast<double>(std::get<int64_t>(value));
777         }
778         else if (type == "uint64_t")
779         {
780             *doubleValue = static_cast<double>(std::get<uint64_t>(value));
781         }
782         else if (type == "double")
783         {
784             *doubleValue = static_cast<double>(std::get<double>(value));
785         }
786         else
787         {
788             return false;
789         }
790     }
791     catch (const std::exception& e)
792     {
793         return false;
794     }
795 
796     return true;
797 }
798 
fruFieldValuestring(const uint8_t * value,const uint8_t & length)799 std::optional<std::string> fruFieldValuestring(const uint8_t* value,
800                                                const uint8_t& length)
801 {
802     if (!value || !length)
803     {
804         return std::nullopt;
805     }
806 
807     return std::string(reinterpret_cast<const char*>(value), length);
808 }
809 
fruFieldParserU32(const uint8_t * value,const uint8_t & length)810 std::optional<uint32_t> fruFieldParserU32(const uint8_t* value,
811                                           const uint8_t& length)
812 {
813     if (!value || length != sizeof(uint32_t))
814     {
815         lg2::error("Fru data to u32 invalid data.");
816         return std::nullopt;
817     }
818 
819     uint32_t ret;
820     std::memcpy(&ret, value, length);
821     return ret;
822 }
823 
getStateSensorPDRsByType(uint16_t entityType,const pldm_pdr * repo)824 SensorPDRs getStateSensorPDRsByType(uint16_t entityType, const pldm_pdr* repo)
825 {
826     uint8_t* outData = nullptr;
827     uint32_t size{};
828     const pldm_pdr_record* record = nullptr;
829     SensorPDRs pdrs;
830 
831     if (repo)
832     {
833         while ((record = pldm_pdr_find_record_by_type(
834                     repo, PLDM_STATE_SENSOR_PDR, record, &outData, &size)))
835         {
836             auto pdr = new (outData) pldm_state_sensor_pdr;
837             if (pdr && pdr->entity_type == entityType)
838             {
839                 pdrs.emplace_back(outData, outData + size);
840             }
841         }
842     }
843 
844     return pdrs;
845 }
846 
findSensorIds(const pldm_pdr * pdrRepo,uint16_t entityType,uint16_t entityInstance,uint16_t containerId)847 std::vector<pldm::pdr::SensorID> findSensorIds(
848     const pldm_pdr* pdrRepo, uint16_t entityType, uint16_t entityInstance,
849     uint16_t containerId)
850 {
851     std::vector<uint16_t> sensorIDs;
852     auto pdrs = getStateSensorPDRsByType(entityType, pdrRepo);
853 
854     for (const auto& pdr : pdrs)
855     {
856         auto sensorPdr =
857             reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
858 
859         if (sensorPdr && sensorPdr->entity_type == entityType &&
860             sensorPdr->entity_instance == entityInstance &&
861             sensorPdr->container_id == containerId)
862         {
863             sensorIDs.emplace_back(sensorPdr->sensor_id);
864         }
865     }
866 
867     return sensorIDs;
868 }
869 
getStateEffecterPDRsByType(uint16_t entityType,const pldm_pdr * repo)870 EffecterPDRs getStateEffecterPDRsByType(uint16_t entityType,
871                                         const pldm_pdr* repo)
872 {
873     uint8_t* outData = nullptr;
874     uint32_t size{};
875     const pldm_pdr_record* record = nullptr;
876     EffecterPDRs pdrs;
877     if (repo)
878     {
879         while ((record = pldm_pdr_find_record_by_type(
880                     repo, PLDM_STATE_EFFECTER_PDR, record, &outData, &size)))
881         {
882             auto pdr = new (outData) pldm_state_effecter_pdr;
883             if (pdr && pdr->entity_type == entityType)
884             {
885                 pdrs.emplace_back(outData, outData + size);
886             }
887         }
888     }
889     return pdrs;
890 }
891 
findEffecterIds(const pldm_pdr * pdrRepo,uint16_t entityType,uint16_t entityInstance,uint16_t containerId)892 std::vector<pldm::pdr::EffecterID> findEffecterIds(
893     const pldm_pdr* pdrRepo, uint16_t entityType, uint16_t entityInstance,
894     uint16_t containerId)
895 {
896     std::vector<uint16_t> effecterIDs;
897     auto pdrs = getStateEffecterPDRsByType(entityType, pdrRepo);
898     for (const auto& pdr : pdrs)
899     {
900         auto effecterPdr =
901             reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
902         if (effecterPdr && effecterPdr->entity_type == entityType &&
903             effecterPdr->entity_instance == entityInstance &&
904             effecterPdr->container_id == containerId)
905         {
906             effecterIDs.emplace_back(effecterPdr->effecter_id);
907         }
908     }
909     return effecterIDs;
910 }
911 
setBiosAttr(const PendingAttributesList & biosAttrList)912 void setBiosAttr(const PendingAttributesList& biosAttrList)
913 {
914     static constexpr auto SYSTEMD_PROPERTY_INTERFACE =
915         "org.freedesktop.DBus.Properties";
916     constexpr auto biosConfigPath = "/xyz/openbmc_project/bios_config/manager";
917     constexpr auto biosConfigIntf = "xyz.openbmc_project.BIOSConfig.Manager";
918 
919     for (const auto& [attrName, biosAttrDetails] : biosAttrList)
920     {
921         auto& bus = DBusHandler::getBus();
922         try
923         {
924             auto service = pldm::utils::DBusHandler().getService(
925                 biosConfigPath, biosConfigIntf);
926             auto method =
927                 bus.new_method_call(service.c_str(), biosConfigPath,
928                                     SYSTEMD_PROPERTY_INTERFACE, "Set");
929             method.append(biosConfigIntf, "PendingAttributes",
930                           std::variant<PendingAttributesList>(biosAttrList));
931             bus.call_noreply(method, dbusTimeout);
932         }
933         catch (const sdbusplus::exception::SdBusError& e)
934         {
935             AttributeType attrType;
936             AttributeValue attrValue;
937             std::tie(attrType, attrValue) = biosAttrDetails;
938             if (attrType ==
939                 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer")
940             {
941                 info(
942                     "Error setting the value {VALUE} to bios attribute {BIOS_ATTR}: {ERR_EXCEP}",
943                     "VALUE", std::get<int64_t>(attrValue), "BIOS_ATTR",
944                     attrName, "ERR_EXCEP", e);
945             }
946             else
947             {
948                 info(
949                     "Error setting the value {VALUE} to bios attribute {BIOS_ATTR}: {ERR_EXCEP}",
950                     "VALUE", std::get<std::string>(attrValue), "BIOS_ATTR",
951                     attrName, "ERR_EXCEP", e);
952             }
953         }
954     }
955 }
956 
generateSwId()957 long int generateSwId()
958 {
959     return random() % 10000;
960 }
961 
962 } // namespace utils
963 } // namespace pldm
964