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