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