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 = requester.getInstanceId(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             requester.markFree(eid, instanceId);
31             error(
32                 "encode_query_device_identifiers_req failed, EID={EID}, RC = {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 QueryDeviceIdentifiers request, EID={EID}, RC = {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("No response received for QueryDeviceIdentifiers, EID={EID}",
58               "EID", unsigned(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             "Decoding QueryDeviceIdentifiers response failed, EID={EID}, RC = {RC}",
74             "EID", unsigned(eid), "RC", rc);
75         return;
76     }
77 
78     if (completionCode)
79     {
80         error(
81             "QueryDeviceIdentifiers response failed with error completion code, EID={EID}, CC = {CC}",
82             "EID", unsigned(eid), "CC", unsigned(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                 "Decoding descriptor type, length and value failed, EID={EID}, RC = {RC}",
99                 "EID", unsigned(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                     "Decoding Vendor-defined descriptor value failed, EID={EID}, RC = {RC}",
123                     "EID", unsigned(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 = requester.getInstanceId(eid);
154     Request requestMsg(sizeof(pldm_msg_hdr) +
155                        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         requester.markFree(eid, instanceId);
162         error("encode_get_firmware_parameters_req failed, EID={EID}, RC = {RC}",
163               "EID", unsigned(eid), "RC", rc);
164         return;
165     }
166 
167     rc = handler.registerRequest(
168         eid, instanceId, PLDM_FWUP, PLDM_GET_FIRMWARE_PARAMETERS,
169         std::move(requestMsg),
170         std::move(
171             std::bind_front(&InventoryManager::getFirmwareParameters, this)));
172     if (rc)
173     {
174         error(
175             "Failed to send GetFirmwareParameters request, EID={EID}, RC = {RC}",
176             "EID", unsigned(eid), "RC", rc);
177     }
178 }
179 
180 void InventoryManager::getFirmwareParameters(mctp_eid_t eid,
181                                              const pldm_msg* response,
182                                              size_t respMsgLen)
183 {
184     if (response == nullptr || !respMsgLen)
185     {
186         error("No response received for GetFirmwareParameters, EID={EID}",
187               "EID", unsigned(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             "Decoding GetFirmwareParameters response failed, EID={EID}, RC = {RC}",
204             "EID", unsigned(eid), "RC", rc);
205         return;
206     }
207 
208     if (fwParams.completion_code)
209     {
210         error(
211             "GetFirmwareParameters response failed with error completion code, EID={EID}, CC = {CC}",
212             "EID", unsigned(eid), "CC", unsigned(fwParams.completion_code));
213         return;
214     }
215 
216     auto compParamPtr = compParamTable.ptr;
217     auto compParamTableLen = compParamTable.length;
218     pldm_component_parameter_entry compEntry{};
219     variable_field activeCompVerStr{};
220     variable_field pendingCompVerStr{};
221 
222     ComponentInfo componentInfo{};
223     while (fwParams.comp_count-- && (compParamTableLen > 0))
224     {
225         auto rc = decode_get_firmware_parameters_resp_comp_entry(
226             compParamPtr, compParamTableLen, &compEntry, &activeCompVerStr,
227             &pendingCompVerStr);
228         if (rc)
229         {
230             error(
231                 "Decoding component parameter table entry failed, EID={EID}, RC = {RC}",
232                 "EID", unsigned(eid), "RC", rc);
233             return;
234         }
235 
236         auto compClassification = compEntry.comp_classification;
237         auto compIdentifier = compEntry.comp_identifier;
238         componentInfo.emplace(
239             std::make_pair(compClassification, compIdentifier),
240             compEntry.comp_classification_index);
241         compParamPtr += sizeof(pldm_component_parameter_entry) +
242                         activeCompVerStr.length + pendingCompVerStr.length;
243         compParamTableLen -= sizeof(pldm_component_parameter_entry) +
244                              activeCompVerStr.length + pendingCompVerStr.length;
245     }
246     componentInfoMap.emplace(eid, std::move(componentInfo));
247 }
248 
249 } // namespace fw_update
250 
251 } // namespace pldm
252