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