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 at least one state fails to be set
36 */
37 template <class DBusInterface, class Handler>
setStateEffecterStatesHandler(const DBusInterface & dBusIntf,Handler & handler,uint16_t effecterId,const std::vector<set_effecter_state_field> & stateField)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 StateEffecterPDR record");
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 '{COMPOSITE_EFFECTER_COUNT}' for the effecter ID '{EFFECTERID}'",
85 "EFFECTERID", effecterId, "COMPOSITE_EFFECTER_COUNT",
86 compEffecterCnt);
87 return PLDM_ERROR_INVALID_DATA;
88 }
89 break;
90 }
91
92 if (!pdr)
93 {
94 return PLDM_PLATFORM_INVALID_EFFECTER_ID;
95 }
96
97 int rc = PLDM_SUCCESS;
98 try
99 {
100 const auto& [dbusMappings, dbusValMaps] =
101 handler.getDbusObjMaps(effecterId);
102 if (dbusMappings.empty() || dbusValMaps.empty())
103 {
104 error("DbusMappings for effecter ID '{EFFECTER_ID}' is missing",
105 "EFFECTER_ID", effecterId);
106 return PLDM_ERROR;
107 }
108
109 for (uint8_t currState = 0;
110 currState < compEffecterCnt && currState < dbusMappings.size() &&
111 currState < dbusValMaps.size();
112 ++currState)
113 {
114 std::vector<StateSetNum> allowed{};
115 // computation is based on table 79 from DSP0248 v1.1.1
116 uint8_t bitfieldIndex = stateField[currState].effecter_state / 8;
117 uint8_t bit = stateField[currState].effecter_state -
118 (8 * bitfieldIndex);
119 if (states->possible_states_size < bitfieldIndex ||
120 !(states->states[bitfieldIndex].byte & (1 << bit)))
121 {
122 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
123 error(
124 "Invalid state set value for effecter ID '{EFFECTER_ID}', effecter state '{EFFECTER_STATE}', composite effecter ID '{COMPOSITE_EFFECTER_ID}' and path '{PATH}', response code '{RC}'",
125 "EFFECTER_ID", effecterId, "EFFECTER_STATE",
126 stateField[currState].effecter_state,
127 "COMPOSITE_EFFECTER_ID", currState, "PATH",
128 dbusMappings[currState].objectPath, "RC", rc);
129 break;
130 }
131 const DBusMapping& dbusMapping = dbusMappings[currState];
132 const pldm::responder::pdr_utils::StatestoDbusVal& dbusValToMap =
133 dbusValMaps[currState];
134
135 if (stateField[currState].set_request == PLDM_REQUEST_SET)
136 {
137 try
138 {
139 dBusIntf.setDbusProperty(
140 dbusMapping,
141 dbusValToMap.at(stateField[currState].effecter_state));
142 }
143 catch (const std::exception& e)
144 {
145 error(
146 "Failed to set property '{PROPERTY}', interface '{INTERFACE}' and path '{PATH}', error - '{ERROR}'",
147 "PROPERTY", dbusMapping.propertyName, "INTERFACE",
148 dbusMapping.interface, "PATH", dbusMapping.objectPath,
149 "ERROR", e);
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 '{EFFECTERID}', error - {ERROR}",
165 "EFFECTERID", effecterId, "ERROR", e);
166 return PLDM_ERROR;
167 }
168
169 return rc;
170 }
171
172 } // namespace platform_state_effecter
173 } // namespace responder
174 } // namespace pldm
175