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 using namespace pldm::responder::pdr;
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     Repo stateEffecterPDRs(stateEffecterPdrRepo.get());
53     getRepoByType(handler.getRepo(), stateEffecterPDRs,
54                   PLDM_STATE_EFFECTER_PDR);
55     if (stateEffecterPDRs.empty())
56     {
57         std::cerr << "Failed to get record by PDR type\n";
58         return PLDM_PLATFORM_INVALID_EFFECTER_ID;
59     }
60 
61     PdrEntry pdrEntry{};
62     auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry);
63     while (pdrRecord)
64     {
65         pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data);
66         if (pdr->effecter_id != effecterId)
67         {
68             pdr = nullptr;
69             pdrRecord = stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry);
70             continue;
71         }
72 
73         states = reinterpret_cast<state_effecter_possible_states*>(
74             pdr->possible_states);
75         if (compEffecterCnt > pdr->composite_effecter_count)
76         {
77             std::cerr << "The requester sent wrong composite effecter"
78                       << " count for the effecter, EFFECTER_ID=" << effecterId
79                       << "COMP_EFF_CNT=" << compEffecterCnt << "\n";
80             return PLDM_ERROR_INVALID_DATA;
81         }
82         break;
83     }
84 
85     if (!pdr)
86     {
87         return PLDM_PLATFORM_INVALID_EFFECTER_ID;
88     }
89 
90     int rc = PLDM_SUCCESS;
91     try
92     {
93         const auto& [dbusMappings, dbusValMaps] =
94             handler.getDbusObjMaps(effecterId);
95         for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
96         {
97             std::vector<StateSetNum> allowed{};
98             // computation is based on table 79 from DSP0248 v1.1.1
99             uint8_t bitfieldIndex = stateField[currState].effecter_state / 8;
100             uint8_t bit =
101                 stateField[currState].effecter_state - (8 * bitfieldIndex);
102             if (states->possible_states_size < bitfieldIndex ||
103                 !(states->states[bitfieldIndex].byte & (1 << bit)))
104             {
105                 std::cerr << "Invalid state set value, EFFECTER_ID="
106                           << effecterId
107                           << " VALUE=" << stateField[currState].effecter_state
108                           << " COMPOSITE_EFFECTER_ID=" << currState
109                           << " DBUS_PATH=" << dbusMappings[currState].objectPath
110                           << "\n";
111                 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
112                 break;
113             }
114             const DBusMapping& dbusMapping = dbusMappings[currState];
115             const StatestoDbusVal& dbusValToMap = 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