1 #include "inventory_manager.hpp"
2 
3 #include "libpldm/firmware_update.h"
4 
5 #include "common/utils.hpp"
6 #include "xyz/openbmc_project/Software/Version/server.hpp"
7 
8 #include <functional>
9 
10 namespace pldm
11 {
12 
13 namespace fw_update
14 {
15 
16 void InventoryManager::discoverFDs(const std::vector<mctp_eid_t>& eids)
17 {
18     for (const auto& eid : eids)
19     {
20         auto instanceId = requester.getInstanceId(eid);
21         Request requestMsg(sizeof(pldm_msg_hdr) +
22                            PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES);
23         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
24         auto rc = encode_query_device_identifiers_req(
25             instanceId, PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES, request);
26         if (rc)
27         {
28             requester.markFree(eid, instanceId);
29             std::cerr << "encode_query_device_identifiers_req failed, EID="
30                       << unsigned(eid) << ", RC=" << rc << "\n";
31             continue;
32         }
33 
34         rc = handler.registerRequest(
35             eid, instanceId, PLDM_FWUP, PLDM_QUERY_DEVICE_IDENTIFIERS,
36             std::move(requestMsg),
37             std::move(std::bind_front(&InventoryManager::queryDeviceIdentifiers,
38                                       this)));
39         if (rc)
40         {
41             std::cerr << "Failed to send QueryDeviceIdentifiers request, EID="
42                       << unsigned(eid) << ", RC=" << rc << "\n ";
43         }
44     }
45 }
46 
47 void InventoryManager::queryDeviceIdentifiers(mctp_eid_t eid,
48                                               const pldm_msg* response,
49                                               size_t respMsgLen)
50 {
51     if (response == nullptr || !respMsgLen)
52     {
53         std::cerr << "No response received for QueryDeviceIdentifiers, EID="
54                   << unsigned(eid) << "\n";
55         return;
56     }
57 
58     uint8_t completionCode = PLDM_SUCCESS;
59     uint32_t deviceIdentifiersLen = 0;
60     uint8_t descriptorCount = 0;
61     uint8_t* descriptorPtr = nullptr;
62 
63     auto rc = decode_query_device_identifiers_resp(
64         response, respMsgLen, &completionCode, &deviceIdentifiersLen,
65         &descriptorCount, &descriptorPtr);
66     if (rc)
67     {
68         std::cerr << "Decoding QueryDeviceIdentifiers response failed, EID="
69                   << unsigned(eid) << ", RC=" << rc << "\n";
70         return;
71     }
72 
73     if (completionCode)
74     {
75         std::cerr << "QueryDeviceIdentifiers response failed with error "
76                      "completion code, EID="
77                   << unsigned(eid) << ", CC=" << unsigned(completionCode)
78                   << "\n";
79         return;
80     }
81 
82     Descriptors descriptors{};
83     while (descriptorCount-- && (deviceIdentifiersLen > 0))
84     {
85         uint16_t descriptorType = 0;
86         variable_field descriptorData{};
87 
88         rc = decode_descriptor_type_length_value(
89             descriptorPtr, deviceIdentifiersLen, &descriptorType,
90             &descriptorData);
91         if (rc)
92         {
93             std::cerr
94                 << "Decoding descriptor type, length and value failed, EID="
95                 << unsigned(eid) << ", RC=" << rc << "\n ";
96             return;
97         }
98 
99         if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
100         {
101             std::vector<uint8_t> descData(
102                 descriptorData.ptr, descriptorData.ptr + descriptorData.length);
103             descriptors.emplace(descriptorType, std::move(descData));
104         }
105         else
106         {
107             uint8_t descriptorTitleStrType = 0;
108             variable_field descriptorTitleStr{};
109             variable_field vendorDefinedDescriptorData{};
110 
111             rc = decode_vendor_defined_descriptor_value(
112                 descriptorData.ptr, descriptorData.length,
113                 &descriptorTitleStrType, &descriptorTitleStr,
114                 &vendorDefinedDescriptorData);
115             if (rc)
116             {
117                 std::cerr
118                     << "Decoding Vendor-defined descriptor value failed, EID="
119                     << unsigned(eid) << ", RC=" << rc << "\n ";
120                 return;
121             }
122 
123             auto vendorDefinedDescriptorTitleStr =
124                 utils::toString(descriptorTitleStr);
125             std::vector<uint8_t> vendorDescData(
126                 vendorDefinedDescriptorData.ptr,
127                 vendorDefinedDescriptorData.ptr +
128                     vendorDefinedDescriptorData.length);
129             descriptors.emplace(descriptorType,
130                                 std::make_tuple(vendorDefinedDescriptorTitleStr,
131                                                 vendorDescData));
132         }
133         auto nextDescriptorOffset =
134             sizeof(pldm_descriptor_tlv().descriptor_type) +
135             sizeof(pldm_descriptor_tlv().descriptor_length) +
136             descriptorData.length;
137         descriptorPtr += nextDescriptorOffset;
138         deviceIdentifiersLen -= nextDescriptorOffset;
139     }
140 
141     descriptorMap.emplace(eid, std::move(descriptors));
142 
143     // Send GetFirmwareParameters request
144     sendGetFirmwareParametersRequest(eid);
145 }
146 
147 void InventoryManager::sendGetFirmwareParametersRequest(mctp_eid_t eid)
148 {
149     auto instanceId = requester.getInstanceId(eid);
150     Request requestMsg(sizeof(pldm_msg_hdr) +
151                        PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
152     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
153     auto rc = encode_get_firmware_parameters_req(
154         instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
155     if (rc)
156     {
157         requester.markFree(eid, instanceId);
158         std::cerr << "encode_get_firmware_parameters_req failed, EID="
159                   << unsigned(eid) << ", RC=" << rc << "\n";
160         return;
161     }
162 
163     rc = handler.registerRequest(
164         eid, instanceId, PLDM_FWUP, PLDM_GET_FIRMWARE_PARAMETERS,
165         std::move(requestMsg),
166         std::move(
167             std::bind_front(&InventoryManager::getFirmwareParameters, this)));
168     if (rc)
169     {
170         std::cerr << "Failed to send GetFirmwareParameters request, EID="
171                   << unsigned(eid) << ", RC=" << rc << "\n ";
172     }
173 }
174 
175 void InventoryManager::getFirmwareParameters(mctp_eid_t eid,
176                                              const pldm_msg* response,
177                                              size_t respMsgLen)
178 {
179     if (response == nullptr || !respMsgLen)
180     {
181         std::cerr << "No response received for GetFirmwareParameters, EID="
182                   << unsigned(eid) << "\n";
183         descriptorMap.erase(eid);
184         return;
185     }
186 
187     pldm_get_firmware_parameters_resp fwParams{};
188     variable_field activeCompImageSetVerStr{};
189     variable_field pendingCompImageSetVerStr{};
190     variable_field compParamTable{};
191 
192     auto rc = decode_get_firmware_parameters_resp(
193         response, respMsgLen, &fwParams, &activeCompImageSetVerStr,
194         &pendingCompImageSetVerStr, &compParamTable);
195     if (rc)
196     {
197         std::cerr << "Decoding GetFirmwareParameters response failed, EID="
198                   << unsigned(eid) << ", RC=" << rc << "\n";
199         return;
200     }
201 
202     if (fwParams.completion_code)
203     {
204         std::cerr << "GetFirmwareParameters response failed with error "
205                      "completion code, EID="
206                   << unsigned(eid)
207                   << ", CC=" << unsigned(fwParams.completion_code) << "\n";
208         return;
209     }
210 
211     auto compParamPtr = compParamTable.ptr;
212     auto compParamTableLen = compParamTable.length;
213     pldm_component_parameter_entry compEntry{};
214     variable_field activeCompVerStr{};
215     variable_field pendingCompVerStr{};
216 
217     ComponentInfo componentInfo{};
218     while (fwParams.comp_count-- && (compParamTableLen > 0))
219     {
220         auto rc = decode_get_firmware_parameters_resp_comp_entry(
221             compParamPtr, compParamTableLen, &compEntry, &activeCompVerStr,
222             &pendingCompVerStr);
223         if (rc)
224         {
225             std::cerr << "Decoding component parameter table entry failed, EID="
226                       << unsigned(eid) << ", RC=" << rc << "\n";
227             return;
228         }
229 
230         auto compClassification = compEntry.comp_classification;
231         auto compIdentifier = compEntry.comp_identifier;
232         componentInfo.emplace(
233             std::make_pair(compClassification, compIdentifier),
234             compEntry.comp_classification_index);
235         compParamPtr += sizeof(pldm_component_parameter_entry) +
236                         activeCompVerStr.length + pendingCompVerStr.length;
237         compParamTableLen -= sizeof(pldm_component_parameter_entry) +
238                              activeCompVerStr.length + pendingCompVerStr.length;
239     }
240     componentInfoMap.emplace(eid, std::move(componentInfo));
241 }
242 
243 } // namespace fw_update
244 
245 } // namespace pldm