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