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 {
discoverFDs(const std::vector<mctp_eid_t> & eids)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", 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", eid, "RC", rc);
47         }
48     }
49 }
50 
queryDeviceIdentifiers(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)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", 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", eid, "DESCRIPTOR_COUNT", descriptorCount, "RC", rc);
76         return;
77     }
78 
79     if (completionCode)
80     {
81         error(
82             "Failed to query device identifiers response for endpoint ID '{EID}', completion code '{CC}'",
83             "EID", eid, "CC", completionCode);
84         return;
85     }
86 
87     Descriptors descriptors{};
88     while (descriptorCount-- && (deviceIdentifiersLen > 0))
89     {
90         uint16_t descriptorType = 0;
91         variable_field descriptorData{};
92 
93         rc = decode_descriptor_type_length_value(
94             descriptorPtr, deviceIdentifiersLen, &descriptorType,
95             &descriptorData);
96         if (rc)
97         {
98             error(
99                 "Failed to decode descriptor type {TYPE}, length {LENGTH} and value for endpoint ID '{EID}', response code '{RC}'",
100                 "TYPE", descriptorType, "LENGTH", deviceIdentifiersLen, "EID",
101                 eid, "RC", rc);
102             return;
103         }
104 
105         if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
106         {
107             std::vector<uint8_t> descData(
108                 descriptorData.ptr, descriptorData.ptr + descriptorData.length);
109             descriptors.emplace(descriptorType, std::move(descData));
110         }
111         else
112         {
113             uint8_t descriptorTitleStrType = 0;
114             variable_field descriptorTitleStr{};
115             variable_field vendorDefinedDescriptorData{};
116 
117             rc = decode_vendor_defined_descriptor_value(
118                 descriptorData.ptr, descriptorData.length,
119                 &descriptorTitleStrType, &descriptorTitleStr,
120                 &vendorDefinedDescriptorData);
121             if (rc)
122             {
123                 error(
124                     "Failed to decode vendor-defined descriptor value for endpoint ID '{EID}', response code '{RC}'",
125                     "EID", eid, "RC", rc);
126                 return;
127             }
128 
129             auto vendorDefinedDescriptorTitleStr =
130                 utils::toString(descriptorTitleStr);
131             std::vector<uint8_t> vendorDescData(
132                 vendorDefinedDescriptorData.ptr,
133                 vendorDefinedDescriptorData.ptr +
134                     vendorDefinedDescriptorData.length);
135             descriptors.emplace(descriptorType,
136                                 std::make_tuple(vendorDefinedDescriptorTitleStr,
137                                                 vendorDescData));
138         }
139         auto nextDescriptorOffset =
140             sizeof(pldm_descriptor_tlv().descriptor_type) +
141             sizeof(pldm_descriptor_tlv().descriptor_length) +
142             descriptorData.length;
143         descriptorPtr += nextDescriptorOffset;
144         deviceIdentifiersLen -= nextDescriptorOffset;
145     }
146 
147     descriptorMap.emplace(eid, std::move(descriptors));
148 
149     // Send GetFirmwareParameters request
150     sendGetFirmwareParametersRequest(eid);
151 }
152 
sendGetFirmwareParametersRequest(mctp_eid_t eid)153 void InventoryManager::sendGetFirmwareParametersRequest(mctp_eid_t eid)
154 {
155     auto instanceId = instanceIdDb.next(eid);
156     Request requestMsg(sizeof(pldm_msg_hdr) +
157                        PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
158     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
159     auto rc = encode_get_firmware_parameters_req(
160         instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
161     if (rc)
162     {
163         instanceIdDb.free(eid, instanceId);
164         error(
165             "Failed to encode get firmware parameters req for endpoint ID '{EID}', response code '{RC}'",
166             "EID", eid, "RC", rc);
167         return;
168     }
169 
170     rc = handler.registerRequest(
171         eid, instanceId, PLDM_FWUP, PLDM_GET_FIRMWARE_PARAMETERS,
172         std::move(requestMsg),
173         std::move(
174             std::bind_front(&InventoryManager::getFirmwareParameters, this)));
175     if (rc)
176     {
177         error(
178             "Failed to send get firmware parameters request for endpoint ID '{EID}', response code '{RC}'",
179             "EID", eid, "RC", rc);
180     }
181 }
182 
getFirmwareParameters(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)183 void InventoryManager::getFirmwareParameters(mctp_eid_t eid,
184                                              const pldm_msg* response,
185                                              size_t respMsgLen)
186 {
187     if (response == nullptr || !respMsgLen)
188     {
189         error(
190             "No response received for get firmware parameters for endpoint ID '{EID}'",
191             "EID", eid);
192         descriptorMap.erase(eid);
193         return;
194     }
195 
196     pldm_get_firmware_parameters_resp fwParams{};
197     variable_field activeCompImageSetVerStr{};
198     variable_field pendingCompImageSetVerStr{};
199     variable_field compParamTable{};
200 
201     auto rc = decode_get_firmware_parameters_resp(
202         response, respMsgLen, &fwParams, &activeCompImageSetVerStr,
203         &pendingCompImageSetVerStr, &compParamTable);
204     if (rc)
205     {
206         error(
207             "Failed to decode get firmware parameters response for endpoint ID '{EID}', response code '{RC}'",
208             "EID", eid, "RC", rc);
209         return;
210     }
211 
212     if (fwParams.completion_code)
213     {
214         auto fw_param_cc = fwParams.completion_code;
215         error(
216             "Failed to get firmware parameters response for endpoint ID '{EID}', completion code '{CC}'",
217             "EID", eid, "CC", fw_param_cc);
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", 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