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