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