blob: d31ec4ab66a253c3c426c26273723fbd939256e1 [file] [log] [blame]
gokulsanker138ceba2021-04-05 13:25:25 +05301#include "firmware_update.h"
gokulsankereca3e192021-04-05 14:57:41 +05302#include <endian.h>
gokulsankere1fb7a82021-04-05 16:09:29 +05303#include <string.h>
gokulsanker138ceba2021-04-05 13:25:25 +05304
Tom Joseph763b51e2021-06-05 04:50:47 -07005/** @brief Check whether string type value is valid
6 *
7 * @return true if string type value is valid, false if not
8 */
9static bool is_string_type_valid(uint8_t string_type)
10{
11 switch (string_type) {
12 case PLDM_STR_TYPE_UNKNOWN:
Tom Josephbc44b7b2021-06-19 01:13:52 -070013 return false;
Tom Joseph763b51e2021-06-05 04:50:47 -070014 case PLDM_STR_TYPE_ASCII:
15 case PLDM_STR_TYPE_UTF_8:
16 case PLDM_STR_TYPE_UTF_16:
17 case PLDM_STR_TYPE_UTF_16LE:
18 case PLDM_STR_TYPE_UTF_16BE:
19 return true;
20 default:
21 return false;
22 }
23}
24
25/** @brief Return the length of the descriptor type described in firmware update
26 * specification
27 *
28 * @return length of the descriptor type if descriptor type is valid else
29 * return 0
30 */
31static uint16_t get_descriptor_type_length(uint16_t descriptor_type)
32{
33 switch (descriptor_type) {
34
35 case PLDM_FWUP_PCI_VENDOR_ID:
36 return PLDM_FWUP_PCI_VENDOR_ID_LENGTH;
37 case PLDM_FWUP_IANA_ENTERPRISE_ID:
38 return PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH;
39 case PLDM_FWUP_UUID:
40 return PLDM_FWUP_UUID_LENGTH;
41 case PLDM_FWUP_PNP_VENDOR_ID:
42 return PLDM_FWUP_PNP_VENDOR_ID_LENGTH;
43 case PLDM_FWUP_ACPI_VENDOR_ID:
44 return PLDM_FWUP_ACPI_VENDOR_ID_LENGTH;
45 case PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID:
46 return PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH;
47 case PLDM_FWUP_SCSI_VENDOR_ID:
48 return PLDM_FWUP_SCSI_VENDOR_ID_LENGTH;
49 case PLDM_FWUP_PCI_DEVICE_ID:
50 return PLDM_FWUP_PCI_DEVICE_ID_LENGTH;
51 case PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID:
52 return PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH;
53 case PLDM_FWUP_PCI_SUBSYSTEM_ID:
54 return PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH;
55 case PLDM_FWUP_PCI_REVISION_ID:
56 return PLDM_FWUP_PCI_REVISION_ID_LENGTH;
57 case PLDM_FWUP_PNP_PRODUCT_IDENTIFIER:
58 return PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH;
59 case PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER:
60 return PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH;
61 case PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING:
62 return PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH;
63 case PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING:
64 return PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH;
65 case PLDM_FWUP_SCSI_PRODUCT_ID:
66 return PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH;
67 case PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE:
68 return PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH;
69 default:
70 return 0;
71 }
72}
73
Tom Joseph568e4702021-06-07 22:15:49 -070074int decode_pldm_package_header_info(
75 const uint8_t *data, size_t length,
76 struct pldm_package_header_information *package_header_info,
77 struct variable_field *package_version_str)
78{
79 if (data == NULL || package_header_info == NULL ||
80 package_version_str == NULL) {
81 return PLDM_ERROR_INVALID_DATA;
82 }
83
84 if (length < sizeof(struct pldm_package_header_information)) {
85 return PLDM_ERROR_INVALID_LENGTH;
86 }
87
88 struct pldm_package_header_information *data_header =
89 (struct pldm_package_header_information *)(data);
90
91 if (!is_string_type_valid(data_header->package_version_string_type) ||
92 (data_header->package_version_string_length == 0)) {
93 return PLDM_ERROR_INVALID_DATA;
94 }
95
96 if (length < sizeof(struct pldm_package_header_information) +
97 data_header->package_version_string_length) {
98 return PLDM_ERROR_INVALID_LENGTH;
99 }
100
101 if ((data_header->component_bitmap_bit_length %
102 PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE) != 0) {
103 return PLDM_ERROR_INVALID_DATA;
104 }
105
106 memcpy(package_header_info->uuid, data_header->uuid,
107 sizeof(data_header->uuid));
108 package_header_info->package_header_format_version =
109 data_header->package_header_format_version;
110 package_header_info->package_header_size =
111 le16toh(data_header->package_header_size);
112 memcpy(package_header_info->timestamp104, data_header->timestamp104,
113 sizeof(data_header->timestamp104));
114 package_header_info->component_bitmap_bit_length =
115 le16toh(data_header->component_bitmap_bit_length);
116 package_header_info->package_version_string_type =
117 data_header->package_version_string_type;
118 package_header_info->package_version_string_length =
119 data_header->package_version_string_length;
120 package_version_str->ptr =
121 data + sizeof(struct pldm_package_header_information);
122 package_version_str->length =
123 package_header_info->package_version_string_length;
124
125 return PLDM_SUCCESS;
126}
127
Tom Joseph763b51e2021-06-05 04:50:47 -0700128int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
129 uint16_t *descriptor_type,
130 struct variable_field *descriptor_data)
131{
132 uint16_t descriptor_length = 0;
133
134 if (data == NULL || descriptor_type == NULL ||
135 descriptor_data == NULL) {
136 return PLDM_ERROR_INVALID_DATA;
137 }
138
139 if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
140 return PLDM_ERROR_INVALID_LENGTH;
141 }
142
143 struct pldm_descriptor_tlv *entry =
144 (struct pldm_descriptor_tlv *)(data);
145
146 *descriptor_type = le16toh(entry->descriptor_type);
147 descriptor_length = le16toh(entry->descriptor_length);
148 if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
149 if (descriptor_length !=
150 get_descriptor_type_length(*descriptor_type)) {
151 return PLDM_ERROR_INVALID_LENGTH;
152 }
153 }
154
155 if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
156 descriptor_length)) {
157 return PLDM_ERROR_INVALID_LENGTH;
158 }
159
160 descriptor_data->ptr = entry->descriptor_data;
161 descriptor_data->length = descriptor_length;
162
163 return PLDM_SUCCESS;
164}
165
166int decode_vendor_defined_descriptor_value(
167 const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
168 struct variable_field *descriptor_title_str,
169 struct variable_field *descriptor_data)
170{
171 if (data == NULL || descriptor_title_str_type == NULL ||
172 descriptor_title_str == NULL || descriptor_data == NULL) {
173 return PLDM_ERROR_INVALID_DATA;
174 }
175
176 if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
177 return PLDM_ERROR_INVALID_LENGTH;
178 }
179
180 struct pldm_vendor_defined_descriptor_title_data *entry =
181 (struct pldm_vendor_defined_descriptor_title_data *)(data);
182 if (!is_string_type_valid(
183 entry->vendor_defined_descriptor_title_str_type) ||
184 (entry->vendor_defined_descriptor_title_str_len == 0)) {
185 return PLDM_ERROR_INVALID_DATA;
186 }
187
188 // Assuming atleast 1 byte of VendorDefinedDescriptorData
189 if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
190 entry->vendor_defined_descriptor_title_str_len)) {
191 return PLDM_ERROR_INVALID_LENGTH;
192 }
193
194 *descriptor_title_str_type =
195 entry->vendor_defined_descriptor_title_str_type;
196 descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
197 descriptor_title_str->length =
198 entry->vendor_defined_descriptor_title_str_len;
199
200 descriptor_data->ptr =
201 descriptor_title_str->ptr + descriptor_title_str->length;
202 descriptor_data->length =
203 length - sizeof(entry->vendor_defined_descriptor_title_str_type) -
204 sizeof(entry->vendor_defined_descriptor_title_str_len) -
205 descriptor_title_str->length;
206
207 return PLDM_SUCCESS;
208}
209
gokulsanker138ceba2021-04-05 13:25:25 +0530210int encode_query_device_identifiers_req(uint8_t instance_id,
211 size_t payload_length,
212 struct pldm_msg *msg)
213{
214 if (msg == NULL) {
215 return PLDM_ERROR_INVALID_DATA;
216 }
217
218 if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
219 return PLDM_ERROR_INVALID_LENGTH;
220 }
221
222 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
223 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
224}
gokulsankereca3e192021-04-05 14:57:41 +0530225
226int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
227 size_t payload_length,
228 uint8_t *completion_code,
229 uint32_t *device_identifiers_len,
230 uint8_t *descriptor_count,
231 uint8_t **descriptor_data)
232{
233 if (msg == NULL || completion_code == NULL ||
234 device_identifiers_len == NULL || descriptor_count == NULL ||
235 descriptor_data == NULL) {
236 return PLDM_ERROR_INVALID_DATA;
237 }
238
239 *completion_code = msg->payload[0];
240 if (PLDM_SUCCESS != *completion_code) {
241 return PLDM_SUCCESS;
242 }
243
244 if (payload_length <
245 sizeof(struct pldm_query_device_identifiers_resp)) {
246 return PLDM_ERROR_INVALID_LENGTH;
247 }
248
249 struct pldm_query_device_identifiers_resp *response =
250 (struct pldm_query_device_identifiers_resp *)msg->payload;
251 *device_identifiers_len = le32toh(response->device_identifiers_len);
252
253 if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
254 return PLDM_ERROR_INVALID_LENGTH;
255 }
256
257 if (payload_length !=
258 sizeof(struct pldm_query_device_identifiers_resp) +
259 *device_identifiers_len) {
260 return PLDM_ERROR_INVALID_LENGTH;
261 }
262 *descriptor_count = response->descriptor_count;
263
264 if (*descriptor_count == 0) {
265 return PLDM_ERROR_INVALID_DATA;
266 }
gokulsankereca3e192021-04-05 14:57:41 +0530267 *descriptor_data =
268 (uint8_t *)(msg->payload +
269 sizeof(struct pldm_query_device_identifiers_resp));
270 return PLDM_SUCCESS;
271}
gokulsanker981fbfb2021-04-05 15:17:25 +0530272
273int encode_get_firmware_parameters_req(uint8_t instance_id,
274 size_t payload_length,
275 struct pldm_msg *msg)
276{
277 if (msg == NULL) {
278 return PLDM_ERROR_INVALID_DATA;
279 }
280
281 if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
282 return PLDM_ERROR_INVALID_LENGTH;
283 }
284
285 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
286 PLDM_GET_FIRMWARE_PARAMETERS, msg);
287}
gokulsanker22fbb342021-04-05 15:55:06 +0530288
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700289int decode_get_firmware_parameters_resp(
gokulsanker22fbb342021-04-05 15:55:06 +0530290 const struct pldm_msg *msg, size_t payload_length,
291 struct pldm_get_firmware_parameters_resp *resp_data,
292 struct variable_field *active_comp_image_set_ver_str,
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700293 struct variable_field *pending_comp_image_set_ver_str,
294 struct variable_field *comp_parameter_table)
gokulsanker22fbb342021-04-05 15:55:06 +0530295{
296 if (msg == NULL || resp_data == NULL ||
297 active_comp_image_set_ver_str == NULL ||
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700298 pending_comp_image_set_ver_str == NULL ||
299 comp_parameter_table == NULL) {
gokulsanker22fbb342021-04-05 15:55:06 +0530300 return PLDM_ERROR_INVALID_DATA;
301 }
302
303 if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
304 return PLDM_ERROR_INVALID_LENGTH;
305 }
306
307 struct pldm_get_firmware_parameters_resp *response =
308 (struct pldm_get_firmware_parameters_resp *)msg->payload;
309
310 resp_data->completion_code = response->completion_code;
311
312 if (PLDM_SUCCESS != resp_data->completion_code) {
313 return PLDM_SUCCESS;
314 }
315
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700316 if (!is_string_type_valid(
317 response->active_comp_image_set_ver_str_type) ||
318 (response->active_comp_image_set_ver_str_len == 0)) {
gokulsanker22fbb342021-04-05 15:55:06 +0530319 return PLDM_ERROR_INVALID_DATA;
320 }
321
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700322 if (response->pending_comp_image_set_ver_str_len == 0) {
323 if (response->pending_comp_image_set_ver_str_type !=
324 PLDM_STR_TYPE_UNKNOWN) {
325 return PLDM_ERROR_INVALID_DATA;
326 }
327 } else {
328 if (!is_string_type_valid(
329 response->pending_comp_image_set_ver_str_type)) {
330 return PLDM_ERROR_INVALID_DATA;
331 }
332 }
gokulsanker22fbb342021-04-05 15:55:06 +0530333
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700334 size_t partial_response_length =
335 sizeof(struct pldm_get_firmware_parameters_resp) +
336 response->active_comp_image_set_ver_str_len +
337 response->pending_comp_image_set_ver_str_len;
338
339 if (payload_length < partial_response_length) {
gokulsanker22fbb342021-04-05 15:55:06 +0530340 return PLDM_ERROR_INVALID_LENGTH;
341 }
342
343 resp_data->capabilities_during_update.value =
344 le32toh(response->capabilities_during_update.value);
gokulsanker22fbb342021-04-05 15:55:06 +0530345 resp_data->comp_count = le16toh(response->comp_count);
gokulsanker22fbb342021-04-05 15:55:06 +0530346 resp_data->active_comp_image_set_ver_str_type =
347 response->active_comp_image_set_ver_str_type;
348 resp_data->active_comp_image_set_ver_str_len =
349 response->active_comp_image_set_ver_str_len;
350 resp_data->pending_comp_image_set_ver_str_type =
351 response->pending_comp_image_set_ver_str_type;
352 resp_data->pending_comp_image_set_ver_str_len =
353 response->pending_comp_image_set_ver_str_len;
354
355 active_comp_image_set_ver_str->ptr =
356 msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
357 active_comp_image_set_ver_str->length =
358 resp_data->active_comp_image_set_ver_str_len;
359
360 if (resp_data->pending_comp_image_set_ver_str_len != 0) {
361 pending_comp_image_set_ver_str->ptr =
362 msg->payload +
363 sizeof(struct pldm_get_firmware_parameters_resp) +
364 resp_data->active_comp_image_set_ver_str_len;
365 pending_comp_image_set_ver_str->length =
366 resp_data->pending_comp_image_set_ver_str_len;
367 } else {
368 pending_comp_image_set_ver_str->ptr = NULL;
369 pending_comp_image_set_ver_str->length = 0;
370 }
371
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700372 if (payload_length > partial_response_length && resp_data->comp_count) {
373 comp_parameter_table->ptr =
374 msg->payload +
375 sizeof(struct pldm_get_firmware_parameters_resp) +
376 resp_data->active_comp_image_set_ver_str_len +
377 resp_data->pending_comp_image_set_ver_str_len;
378 comp_parameter_table->length =
379 payload_length - partial_response_length;
380 } else {
381 comp_parameter_table->ptr = NULL;
382 comp_parameter_table->length = 0;
383 }
384
gokulsanker22fbb342021-04-05 15:55:06 +0530385 return PLDM_SUCCESS;
386}
gokulsankere1fb7a82021-04-05 16:09:29 +0530387
388int decode_get_firmware_parameters_resp_comp_entry(
389 const uint8_t *data, size_t length,
390 struct pldm_component_parameter_entry *component_data,
391 struct variable_field *active_comp_ver_str,
392 struct variable_field *pending_comp_ver_str)
393{
394 if (data == NULL || component_data == NULL ||
395 active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
396 return PLDM_ERROR_INVALID_DATA;
397 }
398
399 if (length < sizeof(struct pldm_component_parameter_entry)) {
400 return PLDM_ERROR_INVALID_LENGTH;
401 }
402
403 struct pldm_component_parameter_entry *entry =
404 (struct pldm_component_parameter_entry *)(data);
405 if (entry->active_comp_ver_str_len == 0) {
406 return PLDM_ERROR_INVALID_LENGTH;
407 }
408
409 size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
410 entry->active_comp_ver_str_len +
411 entry->pending_comp_ver_str_len;
412
413 if (length != entry_length) {
414 return PLDM_ERROR_INVALID_LENGTH;
415 }
416
417 component_data->comp_classification =
418 le16toh(entry->comp_classification);
419 component_data->comp_identifier = le16toh(entry->comp_identifier);
420 component_data->comp_classification_index =
421 entry->comp_classification_index;
422 component_data->active_comp_comparison_stamp =
423 le32toh(entry->active_comp_comparison_stamp);
424 component_data->active_comp_ver_str_type =
425 entry->active_comp_ver_str_type;
426 component_data->active_comp_ver_str_len =
427 entry->active_comp_ver_str_len;
428 memcpy(component_data->active_comp_release_date,
429 entry->active_comp_release_date,
430 sizeof(entry->active_comp_release_date));
431 component_data->pending_comp_comparison_stamp =
432 le32toh(entry->pending_comp_comparison_stamp);
433 component_data->pending_comp_ver_str_type =
434 entry->pending_comp_ver_str_type;
435 component_data->pending_comp_ver_str_len =
436 entry->pending_comp_ver_str_len;
437 memcpy(component_data->pending_comp_release_date,
438 entry->pending_comp_release_date,
439 sizeof(entry->pending_comp_release_date));
440 component_data->comp_activation_methods.value =
441 le16toh(entry->comp_activation_methods.value);
442 component_data->capabilities_during_update.value =
443 le32toh(entry->capabilities_during_update.value);
444
445 active_comp_ver_str->ptr =
446 data + sizeof(struct pldm_component_parameter_entry);
447 active_comp_ver_str->length = entry->active_comp_ver_str_len;
448
449 if (entry->pending_comp_ver_str_len != 0) {
450
451 pending_comp_ver_str->ptr =
452 data + sizeof(struct pldm_component_parameter_entry) +
453 entry->active_comp_ver_str_len;
454 pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
455 } else {
456 pending_comp_ver_str->ptr = NULL;
457 pending_comp_ver_str->length = 0;
458 }
459 return PLDM_SUCCESS;
460}