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