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