blob: 23dd9fa79adac50f6baec12a096fc9d4814240f1 [file] [log] [blame]
Deepak Kodihalli70e8db02019-10-21 00:59:46 -05001#include "fru.hpp"
2
3#include "utils.hpp"
4
5#include <systemd/sd-journal.h>
6
7#include <boost/crc.hpp>
8#include <iostream>
9#include <sdbusplus/bus.hpp>
10#include <set>
11
12namespace pldm
13{
14
15namespace responder
16{
17
18FruImpl::FruImpl(const std::string& configPath)
19{
20 fru_parser::FruParser handle(configPath);
21
Tom Josephf0076332020-02-06 10:18:50 +053022 fru_parser::DBusLookupInfo dbusInfo;
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050023 // Read the all the inventory D-Bus objects
24 auto& bus = pldm::utils::DBusHandler::getBus();
25 dbus::ObjectValueTree objects;
26
27 try
28 {
Tom Josephf0076332020-02-06 10:18:50 +053029 dbusInfo = handle.inventoryLookup();
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050030 auto method = bus.new_method_call(
31 std::get<0>(dbusInfo).c_str(), std::get<1>(dbusInfo).c_str(),
32 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
33 auto reply = bus.call(method);
34 reply.read(objects);
35 }
36 catch (const std::exception& e)
37 {
38 std::cerr << "Look up of inventory objects failed and PLDM FRU table "
39 "creation failed";
40 return;
41 }
42
43 // Populate all the interested Item types to a map for easy lookup
44 std::set<dbus::Interface> itemIntfsLookup;
45 auto itemIntfs = std::get<2>(dbusInfo);
46 std::transform(std::begin(itemIntfs), std::end(itemIntfs),
47 std::inserter(itemIntfsLookup, itemIntfsLookup.end()),
48 [](dbus::Interface intf) { return intf; });
49
50 for (const auto& object : objects)
51 {
52 const auto& interfaces = object.second;
53
54 for (const auto& interface : interfaces)
55 {
56 if (itemIntfsLookup.find(interface.first) != itemIntfsLookup.end())
57 {
58 // An exception will be thrown by getRecordInfo, if the item
59 // D-Bus interface name specified in FRU_Master.json does
60 // not have corresponding config jsons
61 try
62 {
63 auto recordInfos = handle.getRecordInfo(interface.first);
64 populateRecords(interfaces, recordInfos);
65 }
66 catch (const std::exception& e)
67 {
68 std::cout << "Config JSONs missing for the item "
69 "interface type, interface = "
70 << interface.first << "\n";
71 break;
72 }
73 }
74 }
75 }
76
77 if (table.size())
78 {
79 padBytes = utils::getNumPadBytes(table.size());
80 table.resize(table.size() + padBytes, 0);
81
82 // Calculate the checksum
83 boost::crc_32_type result;
84 result.process_bytes(table.data(), table.size());
85 checksum = result.checksum();
86 }
87}
88
89void FruImpl::populateRecords(
90 const pldm::responder::dbus::InterfaceMap& interfaces,
91 const fru_parser::FruRecordInfos& recordInfos)
92{
93 // recordSetIdentifier for the FRU will be set when the first record gets
94 // added for the FRU
95 uint16_t recordSetIdentifier = 0;
96 auto numRecsCount = numRecs;
97
98 for (auto const& [recType, encType, fieldInfos] : recordInfos)
99 {
100 std::vector<uint8_t> tlvs;
101 uint8_t numFRUFields = 0;
102 for (auto const& [intf, prop, propType, fieldTypeNum] : fieldInfos)
103 {
104 try
105 {
106 auto propValue = interfaces.at(intf).at(prop);
107 if (propType == "bytearray")
108 {
109 auto byteArray = std::get<std::vector<uint8_t>>(propValue);
110 if (!byteArray.size())
111 {
112 continue;
113 }
114
115 numFRUFields++;
116 tlvs.emplace_back(fieldTypeNum);
117 tlvs.emplace_back(byteArray.size());
118 std::move(std::begin(byteArray), std::end(byteArray),
119 std::back_inserter(tlvs));
120 }
121 else if (propType == "string")
122 {
123 auto str = std::get<std::string>(propValue);
124 if (!str.size())
125 {
126 continue;
127 }
128
129 numFRUFields++;
130 tlvs.emplace_back(fieldTypeNum);
131 tlvs.emplace_back(str.size());
132 std::move(std::begin(str), std::end(str),
133 std::back_inserter(tlvs));
134 }
135 }
136 catch (const std::out_of_range& e)
137 {
138 std::cout << "Interface = " << intf
139 << " , and Property = " << prop
140 << " , in config json not present in D-Bus"
141 << "\n";
142 continue;
143 }
144 }
145
146 if (tlvs.size())
147 {
148 if (numRecs == numRecsCount)
149 {
150 recordSetIdentifier = nextRSI();
151 }
152 auto curSize = table.size();
153 table.resize(curSize + recHeaderSize + tlvs.size());
154 encode_fru_record(table.data(), table.size(), &curSize,
155 recordSetIdentifier, recType, numFRUFields,
156 encType, tlvs.data(), tlvs.size());
157 numRecs++;
158 }
159 }
160}
161
162void FruImpl::getFRUTable(Response& response)
163{
164 auto hdrSize = response.size();
165
166 response.resize(hdrSize + table.size() + sizeof(checksum), 0);
167 std::copy(table.begin(), table.end(), response.begin() + hdrSize);
168
169 // Copy the checksum to response data
170 auto iter = response.begin() + hdrSize + table.size();
171 std::copy_n(reinterpret_cast<const uint8_t*>(&checksum), sizeof(checksum),
172 iter);
173}
174
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500175namespace fru
176{
177
178Response Handler::getFRURecordTableMetadata(const pldm_msg* request,
179 size_t /*payloadLength*/)
180{
181 constexpr uint8_t major = 0x01;
182 constexpr uint8_t minor = 0x00;
183 constexpr uint32_t maxSize = 0xFFFFFFFF;
184
185 Response response(sizeof(pldm_msg_hdr) +
186 PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES,
187 0);
188 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
189
190 auto rc = encode_get_fru_record_table_metadata_resp(
191 request->hdr.instance_id, PLDM_SUCCESS, major, minor, maxSize,
192 impl.size(), impl.numRSI(), impl.numRecords(), impl.checkSum(),
193 responsePtr);
194 if (rc != PLDM_SUCCESS)
195 {
196 return ccOnlyResponse(request, rc);
197 }
198
199 return response;
200}
201
202Response Handler::getFRURecordTable(const pldm_msg* request,
203 size_t payloadLength)
204{
205 if (payloadLength != PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES)
206 {
207 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
208 }
209
210 Response response(
211 sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES, 0);
212 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
213
214 auto rc =
215 encode_get_fru_record_table_resp(request->hdr.instance_id, PLDM_SUCCESS,
216 0, PLDM_START_AND_END, responsePtr);
217 if (rc != PLDM_SUCCESS)
218 {
219 return ccOnlyResponse(request, rc);
220 }
221
222 impl.getFRUTable(response);
223
224 return response;
225}
226
227} // namespace fru
228
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500229} // namespace responder
230
231} // namespace pldm