1 #pragma once
2 
3 #include "config.h"
4 
5 #include "common/utils.hpp"
6 #include "libpldmresponder/pdr.hpp"
7 #include "pdr_utils.hpp"
8 #include "pldmd/handler.hpp"
9 
10 #include <libpldm/platform.h>
11 #include <libpldm/states.h>
12 
13 #include <phosphor-logging/lg2.hpp>
14 
15 #include <cstdint>
16 #include <map>
17 
18 PHOSPHOR_LOG2_USING;
19 
20 namespace pldm
21 {
22 namespace responder
23 {
24 namespace platform_state_effecter
25 {
26 /** @brief Function to set the effecter requested by pldm requester
27  *
28  *  @tparam[in] DBusInterface - DBus interface type
29  *  @tparam[in] Handler - pldm::responder::platform::Handler
30  *  @param[in] dBusIntf - The interface object of DBusInterface
31  *  @param[in] handler - The interface object of
32  *             pldm::responder::platform::Handler
33  *  @param[in] effecterId - Effecter ID sent by the requester to act on
34  *  @param[in] stateField - The state field data for each of the states,
35  * equal to composite effecter count in number
36  *  @return - Success or failure in setting the states. Returns failure in
37  * terms of PLDM completion codes if atleast one state fails to be set
38  */
39 template <class DBusInterface, class Handler>
40 int setStateEffecterStatesHandler(
41     const DBusInterface& dBusIntf, Handler& handler, uint16_t effecterId,
42     const std::vector<set_effecter_state_field>& stateField)
43 {
44     using namespace pldm::responder::pdr;
45     using namespace pldm::utils;
46     using StateSetNum = uint8_t;
47 
48     state_effecter_possible_states* states = nullptr;
49     pldm_state_effecter_pdr* pdr = nullptr;
50     uint8_t compEffecterCnt = stateField.size();
51 
52     std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateEffecterPdrRepo(
53         pldm_pdr_init(), pldm_pdr_destroy);
54     pldm::responder::pdr_utils::Repo stateEffecterPDRs(
55         stateEffecterPdrRepo.get());
56     getRepoByType(handler.getRepo(), stateEffecterPDRs,
57                   PLDM_STATE_EFFECTER_PDR);
58     if (stateEffecterPDRs.empty())
59     {
60         error("Failed to get record by PDR type");
61         return PLDM_PLATFORM_INVALID_EFFECTER_ID;
62     }
63 
64     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
65     auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry);
66     while (pdrRecord)
67     {
68         pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data);
69         if (pdr->effecter_id != effecterId)
70         {
71             pdr = nullptr;
72             pdrRecord = stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry);
73             continue;
74         }
75 
76         states = reinterpret_cast<state_effecter_possible_states*>(
77             pdr->possible_states);
78         if (compEffecterCnt > pdr->composite_effecter_count)
79         {
80             error(
81                 "The requester sent wrong composite effecter count for the effecter, EFFECTER_ID={EFFECTER_ID} COMP_EFF_CNT={COMP_EFF_CNT}",
82                 "EFFECTER_ID", effecterId, "COMP_EFF_CNT", compEffecterCnt);
83             return PLDM_ERROR_INVALID_DATA;
84         }
85         break;
86     }
87 
88     if (!pdr)
89     {
90         return PLDM_PLATFORM_INVALID_EFFECTER_ID;
91     }
92 
93     int rc = PLDM_SUCCESS;
94     try
95     {
96         const auto& [dbusMappings,
97                      dbusValMaps] = handler.getDbusObjMaps(effecterId);
98         for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
99         {
100             std::vector<StateSetNum> allowed{};
101             // computation is based on table 79 from DSP0248 v1.1.1
102             uint8_t bitfieldIndex = stateField[currState].effecter_state / 8;
103             uint8_t bit = stateField[currState].effecter_state -
104                           (8 * bitfieldIndex);
105             if (states->possible_states_size < bitfieldIndex ||
106                 !(states->states[bitfieldIndex].byte & (1 << bit)))
107             {
108                 error(
109                     "Invalid state set value, EFFECTER_ID={EFFECTER_ID} VALUE={EFFECTER_STATE} COMPOSITE_EFFECTER_ID={CURR_STATE} DBUS_PATH={DBUS_OBJ_PATH}",
110                     "EFFECTER_ID", effecterId, "EFFECTER_STATE",
111                     stateField[currState].effecter_state, "CURR_STATE",
112                     currState, "DBUS_OBJ_PATH",
113                     dbusMappings[currState].objectPath.c_str());
114                 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
115                 break;
116             }
117             const DBusMapping& dbusMapping = dbusMappings[currState];
118             const pldm::responder::pdr_utils::StatestoDbusVal& dbusValToMap =
119                 dbusValMaps[currState];
120 
121             if (stateField[currState].set_request == PLDM_REQUEST_SET)
122             {
123                 try
124                 {
125                     dBusIntf.setDbusProperty(
126                         dbusMapping,
127                         dbusValToMap.at(stateField[currState].effecter_state));
128                 }
129                 catch (const std::exception& e)
130                 {
131                     error(
132                         "Error setting property, ERROR={ERR_EXCEP} PROPERTY={DBUS_PROP} INTERFACE={DBUS_INTF} PATH={DBUS_OBJ_PATH}",
133                         "ERR_EXCEP", e.what(), "DBUS_PROP",
134                         dbusMapping.propertyName, "DBUS_INTF",
135                         dbusMapping.interface, "DBUS_OBJ_PATH",
136                         dbusMapping.objectPath.c_str());
137                     return PLDM_ERROR;
138                 }
139             }
140             uint8_t* nextState =
141                 reinterpret_cast<uint8_t*>(states) +
142                 sizeof(state_effecter_possible_states) -
143                 sizeof(states->states) +
144                 (states->possible_states_size * sizeof(states->states));
145             states =
146                 reinterpret_cast<state_effecter_possible_states*>(nextState);
147         }
148     }
149     catch (const std::out_of_range& e)
150     {
151         error("Unknown effecter ID : {EFFECTER_ID} {ERR_EXCEP}", "EFFECTER_ID",
152               effecterId, "ERR_EXCEP", e.what());
153         return PLDM_ERROR;
154     }
155 
156     return rc;
157 }
158 
159 } // namespace platform_state_effecter
160 } // namespace responder
161 } // namespace pldm
162