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