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