xref: /openbmc/pldm/common/utils.hpp (revision 4e69d252)
1 #pragma once
2 
3 #include "types.hpp"
4 
5 #include <libpldm/base.h>
6 #include <libpldm/bios.h>
7 #include <libpldm/entity.h>
8 #include <libpldm/pdr.h>
9 #include <libpldm/platform.h>
10 #include <libpldm/utils.h>
11 #include <stdint.h>
12 #include <systemd/sd-bus.h>
13 #include <unistd.h>
14 
15 #include <nlohmann/json.hpp>
16 #include <sdbusplus/server.hpp>
17 #include <xyz/openbmc_project/Inventory/Manager/client.hpp>
18 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
19 #include <xyz/openbmc_project/ObjectMapper/client.hpp>
20 
21 #include <deque>
22 #include <exception>
23 #include <filesystem>
24 #include <iostream>
25 #include <map>
26 #include <string>
27 #include <variant>
28 #include <vector>
29 
30 constexpr uint64_t dbusTimeout =
31     std::chrono::duration_cast<std::chrono::microseconds>(
32         std::chrono::seconds(DBUS_TIMEOUT))
33         .count();
34 
35 namespace pldm
36 {
37 namespace utils
38 {
39 namespace fs = std::filesystem;
40 using Json = nlohmann::json;
41 constexpr bool Tx = true;
42 constexpr bool Rx = false;
43 
44 using ObjectMapper = sdbusplus::client::xyz::openbmc_project::ObjectMapper<>;
45 
46 using inventoryManager =
47     sdbusplus::client::xyz::openbmc_project::inventory::Manager<>;
48 
49 constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
50 constexpr auto mapperService = ObjectMapper::default_service;
51 constexpr auto inventoryPath = "/xyz/openbmc_project/inventory";
52 
53 /** @struct CustomFD
54  *
55  *  RAII wrapper for file descriptor.
56  */
57 struct CustomFD
58 {
59     CustomFD(const CustomFD&) = delete;
60     CustomFD& operator=(const CustomFD&) = delete;
61     CustomFD(CustomFD&&) = delete;
62     CustomFD& operator=(CustomFD&&) = delete;
63 
64     CustomFD(int fd) : fd(fd) {}
65 
66     ~CustomFD()
67     {
68         if (fd >= 0)
69         {
70             close(fd);
71         }
72     }
73 
74     int operator()() const
75     {
76         return fd;
77     }
78 
79   private:
80     int fd = -1;
81 };
82 
83 /** @brief Calculate the pad for PLDM data
84  *
85  *  @param[in] data - Length of the data
86  *  @return - uint8_t - number of pad bytes
87  */
88 uint8_t getNumPadBytes(uint32_t data);
89 
90 /** @brief Convert uint64 to date
91  *
92  *  @param[in] data - time date of uint64
93  *  @param[out] year - year number in dec
94  *  @param[out] month - month number in dec
95  *  @param[out] day - day of the month in dec
96  *  @param[out] hour - number of hours in dec
97  *  @param[out] min - number of minutes in dec
98  *  @param[out] sec - number of seconds in dec
99  *  @return true if decode success, false if decode faild
100  */
101 bool uintToDate(uint64_t data, uint16_t* year, uint8_t* month, uint8_t* day,
102                 uint8_t* hour, uint8_t* min, uint8_t* sec);
103 
104 /** @brief Convert effecter data to structure of set_effecter_state_field
105  *
106  *  @param[in] effecterData - the date of effecter
107  *  @param[in] effecterCount - the number of individual sets of effecter
108  *                              information
109  *  @return[out] parse success and get a valid set_effecter_state_field
110  *               structure, return nullopt means parse failed
111  */
112 std::optional<std::vector<set_effecter_state_field>>
113     parseEffecterData(const std::vector<uint8_t>& effecterData,
114                       uint8_t effecterCount);
115 
116 /**
117  *  @brief creates an error log
118  *  @param[in] errorMsg - the error message
119  */
120 void reportError(const char* errorMsg);
121 
122 /** @brief Convert any Decimal number to BCD
123  *
124  *  @tparam[in] decimal - Decimal number
125  *  @return Corresponding BCD number
126  */
127 template <typename T>
128 T decimalToBcd(T decimal)
129 {
130     T bcd = 0;
131     T rem = 0;
132     auto cnt = 0;
133 
134     while (decimal)
135     {
136         rem = decimal % 10;
137         bcd = bcd + (rem << cnt);
138         decimal = decimal / 10;
139         cnt += 4;
140     }
141 
142     return bcd;
143 }
144 
145 struct DBusMapping
146 {
147     std::string objectPath;   //!< D-Bus object path
148     std::string interface;    //!< D-Bus interface
149     std::string propertyName; //!< D-Bus property name
150     std::string propertyType; //!< D-Bus property type
151 };
152 
153 using PropertyValue =
154     std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t,
155                  uint64_t, double, std::string, std::vector<uint8_t>,
156                  std::vector<std::string>>;
157 using DbusProp = std::string;
158 using DbusChangedProps = std::map<DbusProp, PropertyValue>;
159 using DBusInterfaceAdded = std::vector<
160     std::pair<pldm::dbus::Interface,
161               std::vector<std::pair<pldm::dbus::Property,
162                                     std::variant<pldm::dbus::Property>>>>>;
163 using ObjectPath = std::string;
164 using ServiceName = std::string;
165 using Interfaces = std::vector<std::string>;
166 using MapperServiceMap = std::vector<std::pair<ServiceName, Interfaces>>;
167 using GetSubTreeResponse = std::vector<std::pair<ObjectPath, MapperServiceMap>>;
168 using GetSubTreePathsResponse = std::vector<std::string>;
169 using PropertyMap = std::map<std::string, PropertyValue>;
170 using InterfaceMap = std::map<std::string, PropertyMap>;
171 using ObjectValueTree = std::map<sdbusplus::message::object_path, InterfaceMap>;
172 
173 /**
174  * @brief The interface for DBusHandler
175  */
176 class DBusHandlerInterface
177 {
178   public:
179     virtual ~DBusHandlerInterface() = default;
180 
181     virtual std::string getService(const char* path,
182                                    const char* interface) const = 0;
183     virtual GetSubTreeResponse
184         getSubtree(const std::string& path, int depth,
185                    const std::vector<std::string>& ifaceList) const = 0;
186 
187     virtual GetSubTreePathsResponse
188         getSubTreePaths(const std::string& objectPath, int depth,
189                         const std::vector<std::string>& ifaceList) const = 0;
190 
191     virtual void setDbusProperty(const DBusMapping& dBusMap,
192                                  const PropertyValue& value) const = 0;
193 
194     virtual PropertyValue
195         getDbusPropertyVariant(const char* objPath, const char* dbusProp,
196                                const char* dbusInterface) const = 0;
197 
198     virtual PropertyMap
199         getDbusPropertiesVariant(const char* serviceName, const char* objPath,
200                                  const char* dbusInterface) const = 0;
201 };
202 
203 /**
204  *  @class DBusHandler
205  *
206  *  Wrapper class to handle the D-Bus calls
207  *
208  *  This class contains the APIs to handle the D-Bus calls
209  *  to cater the request from pldm requester.
210  *  A class is created to mock the apis in the test cases
211  */
212 class DBusHandler : public DBusHandlerInterface
213 {
214   public:
215     /** @brief Get the bus connection. */
216     static auto& getBus()
217     {
218         static auto bus = sdbusplus::bus::new_default();
219         return bus;
220     }
221 
222     /**
223      *  @brief Get the DBUS Service name for the input dbus path
224      *
225      *  @param[in] path - DBUS object path
226      *  @param[in] interface - DBUS Interface
227      *
228      *  @return std::string - the dbus service name
229      *
230      *  @throw sdbusplus::exception_t when it fails
231      */
232     std::string getService(const char* path,
233                            const char* interface) const override;
234 
235     /**
236      *  @brief Get the Subtree response from the mapper
237      *
238      *  @param[in] path - DBUS object path
239      *  @param[in] depth - Search depth
240      *  @param[in] ifaceList - list of the interface that are being
241      *                         queried from the mapper
242      *
243      *  @return GetSubTreeResponse - the mapper subtree response
244      *
245      *  @throw sdbusplus::exception_t when it fails
246      */
247     GetSubTreeResponse
248         getSubtree(const std::string& path, int depth,
249                    const std::vector<std::string>& ifaceList) const override;
250 
251     /** @brief Get Subtree path response from the mapper
252      *
253      *  @param[in] path - DBUS object path
254      *  @param[in] depth - Search depth
255      *  @param[in] ifaceList - list of the interface that are being
256      *                         queried from the mapper
257      *
258      *  @return std::vector<std::string> vector of subtree paths
259      */
260     GetSubTreePathsResponse getSubTreePaths(
261         const std::string& objectPath, int depth,
262         const std::vector<std::string>& ifaceList) const override;
263 
264     /** @brief Get property(type: variant) from the requested dbus
265      *
266      *  @param[in] objPath - The Dbus object path
267      *  @param[in] dbusProp - The property name to get
268      *  @param[in] dbusInterface - The Dbus interface
269      *
270      *  @return The value of the property(type: variant)
271      *
272      *  @throw sdbusplus::exception_t when it fails
273      */
274     PropertyValue
275         getDbusPropertyVariant(const char* objPath, const char* dbusProp,
276                                const char* dbusInterface) const override;
277 
278     /** @brief Get All properties(type: variant) from the requested dbus
279      *
280      *  @param[in] serviceName - The Dbus service name
281      *  @param[in] objPath - The Dbus object path
282      *  @param[in] dbusInterface - The Dbus interface
283      *
284      *  @return The values of the properties(type: variant)
285      *
286      *  @throw sdbusplus::exception_t when it fails
287      */
288     PropertyMap
289         getDbusPropertiesVariant(const char* serviceName, const char* objPath,
290                                  const char* dbusInterface) const override;
291 
292     /** @brief The template function to get property from the requested dbus
293      *         path
294      *
295      *  @tparam Property - Excepted type of the property on dbus
296      *
297      *  @param[in] objPath - The Dbus object path
298      *  @param[in] dbusProp - The property name to get
299      *  @param[in] dbusInterface - The Dbus interface
300      *
301      *  @return The value of the property
302      *
303      *  @throw sdbusplus::exception_t when dbus request fails
304      *         std::bad_variant_access when \p Property and property on dbus do
305      *         not match
306      */
307     template <typename Property>
308     auto getDbusProperty(const char* objPath, const char* dbusProp,
309                          const char* dbusInterface)
310     {
311         auto VariantValue = getDbusPropertyVariant(objPath, dbusProp,
312                                                    dbusInterface);
313         return std::get<Property>(VariantValue);
314     }
315 
316     /** @brief Set Dbus property
317      *
318      *  @param[in] dBusMap - Object path, property name, interface and property
319      *                       type for the D-Bus object
320      *  @param[in] value - The value to be set
321      *
322      *  @throw sdbusplus::exception_t when it fails
323      */
324     void setDbusProperty(const DBusMapping& dBusMap,
325                          const PropertyValue& value) const override;
326 
327     /** @brief This function retrieves the properties of an object managed
328      *         by the specified D-Bus service located at the given object path.
329      *
330      *  @param[in] service - The D-Bus service providing the managed object
331      *  @param[in] value - The object path of the managed object
332      *
333      *  @return A hierarchical structure representing the properties of the
334      *          managed object.
335      *  @throw sdbusplus::exception_t when it fails
336      */
337     static ObjectValueTree getManagedObj(const char* service, const char* path);
338 
339     /** @brief Retrieve the inventory objects managed by a specified class.
340      *         The retrieved inventory objects are cached statically
341      *         and returned upon subsequent calls to this function.
342      *
343      *  @tparam ClassType - The class type that manages the inventory objects.
344      *
345      *  @return A reference to the cached inventory objects.
346      */
347     template <typename ClassType>
348     static auto& getInventoryObjects()
349     {
350         static ObjectValueTree object = ClassType::getManagedObj(
351             inventoryManager::interface, inventoryPath);
352         return object;
353     }
354 };
355 
356 /** @brief Fetch parent D-Bus object based on pathname
357  *
358  *  @param[in] dbusObj - child D-Bus object
359  *
360  *  @return std::string - the parent D-Bus object path
361  */
362 inline std::string findParent(const std::string& dbusObj)
363 {
364     fs::path p(dbusObj);
365     return p.parent_path().string();
366 }
367 
368 /** @brief Read (static) MCTP EID of host firmware from a file
369  *
370  *  @return uint8_t - MCTP EID
371  */
372 uint8_t readHostEID();
373 
374 /** @brief Convert a value in the JSON to a D-Bus property value
375  *
376  *  @param[in] type - type of the D-Bus property
377  *  @param[in] value - value in the JSON file
378  *
379  *  @return PropertyValue - the D-Bus property value
380  */
381 PropertyValue jsonEntryToDbusVal(std::string_view type,
382                                  const nlohmann::json& value);
383 
384 /** @brief Find State Effecter PDR
385  *  @param[in] tid - PLDM terminus ID.
386  *  @param[in] entityID - entity that can be associated with PLDM State set.
387  *  @param[in] stateSetId - value that identifies PLDM State set.
388  *  @param[in] repo - pointer to BMC's primary PDR repo.
389  *  @return array[array[uint8_t]] - StateEffecterPDRs
390  */
391 std::vector<std::vector<uint8_t>> findStateEffecterPDR(uint8_t tid,
392                                                        uint16_t entityID,
393                                                        uint16_t stateSetId,
394                                                        const pldm_pdr* repo);
395 /** @brief Find State Sensor PDR
396  *  @param[in] tid - PLDM terminus ID.
397  *  @param[in] entityID - entity that can be associated with PLDM State set.
398  *  @param[in] stateSetId - value that identifies PLDM State set.
399  *  @param[in] repo - pointer to BMC's primary PDR repo.
400  *  @return array[array[uint8_t]] - StateSensorPDRs
401  */
402 std::vector<std::vector<uint8_t>> findStateSensorPDR(uint8_t tid,
403                                                      uint16_t entityID,
404                                                      uint16_t stateSetId,
405                                                      const pldm_pdr* repo);
406 
407 /** @brief Find sensor id from a state sensor PDR
408  *
409  *  @param[in] pdrRepo - PDR repository
410  *  @param[in] tid - terminus id
411  *  @param[in] entityType - entity type
412  *  @param[in] entityInstance - entity instance number
413  *  @param[in] containerId - container id
414  *  @param[in] stateSetId - state set id
415  *
416  *  @return uint16_t - the sensor id
417  */
418 uint16_t findStateSensorId(const pldm_pdr* pdrRepo, uint8_t tid,
419                            uint16_t entityType, uint16_t entityInstance,
420                            uint16_t containerId, uint16_t stateSetId);
421 
422 /** @brief Find effecter id from a state effecter pdr
423  *  @param[in] pdrRepo - PDR repository
424  *  @param[in] entityType - entity type
425  *  @param[in] entityInstance - entity instance number
426  *  @param[in] containerId - container id
427  *  @param[in] stateSetId - state set id
428  *  @param[in] localOrRemote - true for checking local repo and false for remote
429  *                             repo
430  *
431  *  @return uint16_t - the effecter id
432  */
433 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType,
434                              uint16_t entityInstance, uint16_t containerId,
435                              uint16_t stateSetId, bool localOrRemote);
436 
437 /** @brief Emit the sensor event signal
438  *
439  *	@param[in] tid - the terminus id
440  *  @param[in] sensorId - sensorID value of the sensor
441  *  @param[in] sensorOffset - Identifies which state sensor within a
442  * composite state sensor the event is being returned for
443  *  @param[in] eventState - The event state value from the state change that
444  * triggered the event message
445  *  @param[in] previousEventState - The event state value for the state from
446  * which the present event state was entered.
447  *  @return PLDM completion code
448  */
449 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId,
450                                uint8_t sensorOffset, uint8_t eventState,
451                                uint8_t previousEventState);
452 
453 /** @brief Print the buffer
454  *
455  *  @param[in]  isTx - True if the buffer is an outgoing PLDM message, false if
456                        the buffer is an incoming PLDM message
457  *  @param[in]  buffer - Buffer to print
458  *
459  *  @return - None
460  */
461 void printBuffer(bool isTx, const std::vector<uint8_t>& buffer);
462 
463 /** @brief Convert the buffer to std::string
464  *
465  *  If there are characters that are not printable characters, it is replaced
466  *  with space(0x20).
467  *
468  *  @param[in] var - pointer to data and length of the data
469  *
470  *  @return std::string equivalent of variable field
471  */
472 std::string toString(const struct variable_field& var);
473 
474 /** @brief Split strings according to special identifiers
475  *
476  *  We can split the string according to the custom identifier(';', ',', '&' or
477  *  others) and store it to vector.
478  *
479  *  @param[in] srcStr       - The string to be split
480  *  @param[in] delim        - The custom identifier
481  *  @param[in] trimStr      - The first and last string to be trimmed
482  *
483  *  @return std::vector<std::string> Vectors are used to store strings
484  */
485 std::vector<std::string> split(std::string_view srcStr, std::string_view delim,
486                                std::string_view trimStr = "");
487 /** @brief Get the current system time in readable format
488  *
489  *  @return - std::string equivalent of the system time
490  */
491 std::string getCurrentSystemTime();
492 
493 /** @brief checks if the FRU is actually present.
494  *  @param[in] objPath - FRU object path.
495  *
496  *  @return bool to indicate presence or absence of FRU.
497  */
498 bool checkForFruPresence(const std::string& objPath);
499 
500 /** @brief Method to check if the logical bit is set
501  *
502  *  @param[containerId] - container id of the entity
503  *
504  *  @return true or false based on the logic bit set
505  */
506 bool checkIfLogicalBitSet(const uint16_t& containerId);
507 
508 /** @brief setting the present property
509  *
510  *  @param[in] objPath - the object path of the fru
511  *  @param[in] present - status to set either true/false
512  */
513 void setFruPresence(const std::string& fruObjPath, bool present);
514 } // namespace utils
515 } // namespace pldm
516