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