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