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