1 #pragma once
2 
3 #include "libpldm/platform.h"
4 
5 #include "pdr.hpp"
6 #include "pdr_utils.hpp"
7 
8 namespace pldm
9 {
10 
11 namespace responder
12 {
13 
14 namespace pdr_state_effecter
15 {
16 
17 using Json = nlohmann::json;
18 
19 static const Json empty{};
20 
21 /** @brief Parse PDR JSON file and generate state effecter PDR structure
22  *
23  *  @param[in] json - the JSON Object with the state effecter PDR
24  *  @param[out] handler - the Parser of PLDM command handler
25  *  @param[out] repo - pdr::RepoInterface
26  *
27  */
28 template <class DBusInterface, class Handler>
29 void generateStateEffecterPDR(const DBusInterface& dBusIntf, const Json& json,
30                               Handler& handler, pdr_utils::RepoInterface& repo)
31 {
32     static const std::vector<Json> emptyList{};
33     auto entries = json.value("entries", emptyList);
34     for (const auto& e : entries)
35     {
36         size_t pdrSize = 0;
37         auto effecters = e.value("effecters", emptyList);
38         for (const auto& effecter : effecters)
39         {
40             auto set = effecter.value("set", empty);
41             auto statesSize = set.value("size", 0);
42             if (!statesSize)
43             {
44                 std::cerr << "Malformed PDR JSON return "
45                              "pdrEntry;- no state set "
46                              "info, TYPE="
47                           << PLDM_STATE_EFFECTER_PDR << "\n";
48                 throw InternalFailure();
49             }
50             pdrSize += sizeof(state_effecter_possible_states) -
51                        sizeof(bitfield8_t) + (sizeof(bitfield8_t) * statesSize);
52         }
53         pdrSize += sizeof(pldm_state_effecter_pdr) - sizeof(uint8_t);
54 
55         std::vector<uint8_t> entry{};
56         entry.resize(pdrSize);
57 
58         pldm_state_effecter_pdr* pdr =
59             reinterpret_cast<pldm_state_effecter_pdr*>(entry.data());
60         if (!pdr)
61         {
62             std::cerr << "Failed to get state effecter PDR.\n";
63             continue;
64         }
65         pdr->hdr.record_handle = 0;
66         pdr->hdr.version = 1;
67         pdr->hdr.type = PLDM_STATE_EFFECTER_PDR;
68         pdr->hdr.record_change_num = 0;
69         pdr->hdr.length = pdrSize - sizeof(pldm_pdr_hdr);
70 
71         pdr->terminus_handle = pdr::BmcPldmTerminusHandle;
72         pdr->effecter_id = handler.getNextEffecterId();
73 
74         try
75         {
76             std::string entity_path = e.value("entity_path", "");
77             auto& associatedEntityMap = handler.getAssociateEntityMap();
78             if (entity_path != "" && associatedEntityMap.find(entity_path) !=
79                                          associatedEntityMap.end())
80             {
81                 pdr->entity_type =
82                     associatedEntityMap.at(entity_path).entity_type;
83                 pdr->entity_instance =
84                     associatedEntityMap.at(entity_path).entity_instance_num;
85                 pdr->container_id =
86                     associatedEntityMap.at(entity_path).entity_container_id;
87             }
88             else
89             {
90                 pdr->entity_type = e.value("type", 0);
91                 pdr->entity_instance = e.value("instance", 0);
92                 pdr->container_id = e.value("container", 0);
93             }
94         }
95         catch (const std::exception& ex)
96         {
97             pdr->entity_type = e.value("type", 0);
98             pdr->entity_instance = e.value("instance", 0);
99             pdr->container_id = e.value("container", 0);
100         }
101 
102         pdr->effecter_semantic_id = 0;
103         pdr->effecter_init = PLDM_NO_INIT;
104         pdr->has_description_pdr = false;
105         pdr->composite_effecter_count = effecters.size();
106 
107         pldm::responder::pdr_utils::DbusMappings dbusMappings{};
108         pldm::responder::pdr_utils::DbusValMaps dbusValMaps{};
109         uint8_t* start =
110             entry.data() + sizeof(pldm_state_effecter_pdr) - sizeof(uint8_t);
111         for (const auto& effecter : effecters)
112         {
113             auto set = effecter.value("set", empty);
114             state_effecter_possible_states* possibleStates =
115                 reinterpret_cast<state_effecter_possible_states*>(start);
116             possibleStates->state_set_id = set.value("id", 0);
117             possibleStates->possible_states_size = set.value("size", 0);
118 
119             start += sizeof(possibleStates->state_set_id) +
120                      sizeof(possibleStates->possible_states_size);
121             static const std::vector<uint8_t> emptyStates{};
122             pldm::responder::pdr_utils::PossibleValues stateValues;
123             auto states = set.value("states", emptyStates);
124             for (const auto& state : states)
125             {
126                 auto index = state / 8;
127                 auto bit = state - (index * 8);
128                 bitfield8_t* bf = reinterpret_cast<bitfield8_t*>(start + index);
129                 bf->byte |= 1 << bit;
130                 stateValues.emplace_back(state);
131             }
132             start += possibleStates->possible_states_size;
133 
134             auto dbusEntry = effecter.value("dbus", empty);
135             auto objectPath = dbusEntry.value("path", "");
136             auto interface = dbusEntry.value("interface", "");
137             auto propertyName = dbusEntry.value("property_name", "");
138             auto propertyType = dbusEntry.value("property_type", "");
139 
140             pldm::responder::pdr_utils::StatestoDbusVal dbusIdToValMap{};
141             pldm::utils::DBusMapping dbusMapping{};
142             try
143             {
144                 auto service =
145                     dBusIntf.getService(objectPath.c_str(), interface.c_str());
146 
147                 dbusMapping = pldm::utils::DBusMapping{
148                     objectPath, interface, propertyName, propertyType};
149                 dbusIdToValMap = pldm::responder::pdr_utils::populateMapping(
150                     propertyType, dbusEntry["property_values"], stateValues);
151             }
152             catch (const std::exception& e)
153             {
154                 std::cerr << "D-Bus object path does not exist, effecter ID: "
155                           << pdr->effecter_id << "\n";
156             }
157 
158             dbusMappings.emplace_back(std::move(dbusMapping));
159             dbusValMaps.emplace_back(std::move(dbusIdToValMap));
160         }
161         handler.addDbusObjMaps(
162             pdr->effecter_id,
163             std::make_tuple(std::move(dbusMappings), std::move(dbusValMaps)));
164         pldm::responder::pdr_utils::PdrEntry pdrEntry{};
165         pdrEntry.data = entry.data();
166         pdrEntry.size = pdrSize;
167         repo.addRecord(pdrEntry);
168     }
169 }
170 
171 } // namespace pdr_state_effecter
172 } // namespace responder
173 } // namespace pldm
174