1 #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 12 namespace pldm 13 { 14 15 namespace responder 16 { 17 18 FruImpl::FruImpl(const std::string& configPath) 19 { 20 fru_parser::FruParser handle(configPath); 21 22 fru_parser::DBusLookupInfo dbusInfo; 23 // Read the all the inventory D-Bus objects 24 auto& bus = pldm::utils::DBusHandler::getBus(); 25 dbus::ObjectValueTree objects; 26 27 try 28 { 29 dbusInfo = handle.inventoryLookup(); 30 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 89 void 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 162 void 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 175 namespace fru 176 { 177 178 Response 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 202 Response 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 229 } // namespace responder 230 231 } // namespace pldm 232