blob: 7b73a819f80ebdd72f609ba83447fb14da4e0f78 [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 {
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500138 continue;
139 }
140 }
141
142 if (tlvs.size())
143 {
144 if (numRecs == numRecsCount)
145 {
146 recordSetIdentifier = nextRSI();
147 }
148 auto curSize = table.size();
149 table.resize(curSize + recHeaderSize + tlvs.size());
150 encode_fru_record(table.data(), table.size(), &curSize,
151 recordSetIdentifier, recType, numFRUFields,
152 encType, tlvs.data(), tlvs.size());
153 numRecs++;
154 }
155 }
156}
157
158void FruImpl::getFRUTable(Response& response)
159{
160 auto hdrSize = response.size();
161
162 response.resize(hdrSize + table.size() + sizeof(checksum), 0);
163 std::copy(table.begin(), table.end(), response.begin() + hdrSize);
164
165 // Copy the checksum to response data
166 auto iter = response.begin() + hdrSize + table.size();
167 std::copy_n(reinterpret_cast<const uint8_t*>(&checksum), sizeof(checksum),
168 iter);
169}
170
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500171namespace fru
172{
173
174Response Handler::getFRURecordTableMetadata(const pldm_msg* request,
175 size_t /*payloadLength*/)
176{
177 constexpr uint8_t major = 0x01;
178 constexpr uint8_t minor = 0x00;
179 constexpr uint32_t maxSize = 0xFFFFFFFF;
180
181 Response response(sizeof(pldm_msg_hdr) +
182 PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES,
183 0);
184 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
185
186 auto rc = encode_get_fru_record_table_metadata_resp(
187 request->hdr.instance_id, PLDM_SUCCESS, major, minor, maxSize,
188 impl.size(), impl.numRSI(), impl.numRecords(), impl.checkSum(),
189 responsePtr);
190 if (rc != PLDM_SUCCESS)
191 {
192 return ccOnlyResponse(request, rc);
193 }
194
195 return response;
196}
197
198Response Handler::getFRURecordTable(const pldm_msg* request,
199 size_t payloadLength)
200{
201 if (payloadLength != PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES)
202 {
203 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
204 }
205
206 Response response(
207 sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES, 0);
208 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
209
210 auto rc =
211 encode_get_fru_record_table_resp(request->hdr.instance_id, PLDM_SUCCESS,
212 0, PLDM_START_AND_END, responsePtr);
213 if (rc != PLDM_SUCCESS)
214 {
215 return ccOnlyResponse(request, rc);
216 }
217
218 impl.getFRUTable(response);
219
220 return response;
221}
222
223} // namespace fru
224
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500225} // namespace responder
226
227} // namespace pldm