blob: acb95fd8c022f9d72381772a4639c8d9136ec4dd [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
74int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
75 uint16_t *descriptor_type,
76 struct variable_field *descriptor_data)
77{
78 uint16_t descriptor_length = 0;
79
80 if (data == NULL || descriptor_type == NULL ||
81 descriptor_data == NULL) {
82 return PLDM_ERROR_INVALID_DATA;
83 }
84
85 if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
86 return PLDM_ERROR_INVALID_LENGTH;
87 }
88
89 struct pldm_descriptor_tlv *entry =
90 (struct pldm_descriptor_tlv *)(data);
91
92 *descriptor_type = le16toh(entry->descriptor_type);
93 descriptor_length = le16toh(entry->descriptor_length);
94 if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
95 if (descriptor_length !=
96 get_descriptor_type_length(*descriptor_type)) {
97 return PLDM_ERROR_INVALID_LENGTH;
98 }
99 }
100
101 if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
102 descriptor_length)) {
103 return PLDM_ERROR_INVALID_LENGTH;
104 }
105
106 descriptor_data->ptr = entry->descriptor_data;
107 descriptor_data->length = descriptor_length;
108
109 return PLDM_SUCCESS;
110}
111
112int decode_vendor_defined_descriptor_value(
113 const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
114 struct variable_field *descriptor_title_str,
115 struct variable_field *descriptor_data)
116{
117 if (data == NULL || descriptor_title_str_type == NULL ||
118 descriptor_title_str == NULL || descriptor_data == NULL) {
119 return PLDM_ERROR_INVALID_DATA;
120 }
121
122 if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
123 return PLDM_ERROR_INVALID_LENGTH;
124 }
125
126 struct pldm_vendor_defined_descriptor_title_data *entry =
127 (struct pldm_vendor_defined_descriptor_title_data *)(data);
128 if (!is_string_type_valid(
129 entry->vendor_defined_descriptor_title_str_type) ||
130 (entry->vendor_defined_descriptor_title_str_len == 0)) {
131 return PLDM_ERROR_INVALID_DATA;
132 }
133
134 // Assuming atleast 1 byte of VendorDefinedDescriptorData
135 if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
136 entry->vendor_defined_descriptor_title_str_len)) {
137 return PLDM_ERROR_INVALID_LENGTH;
138 }
139
140 *descriptor_title_str_type =
141 entry->vendor_defined_descriptor_title_str_type;
142 descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
143 descriptor_title_str->length =
144 entry->vendor_defined_descriptor_title_str_len;
145
146 descriptor_data->ptr =
147 descriptor_title_str->ptr + descriptor_title_str->length;
148 descriptor_data->length =
149 length - sizeof(entry->vendor_defined_descriptor_title_str_type) -
150 sizeof(entry->vendor_defined_descriptor_title_str_len) -
151 descriptor_title_str->length;
152
153 return PLDM_SUCCESS;
154}
155
gokulsanker138ceba2021-04-05 13:25:25 +0530156int encode_query_device_identifiers_req(uint8_t instance_id,
157 size_t payload_length,
158 struct pldm_msg *msg)
159{
160 if (msg == NULL) {
161 return PLDM_ERROR_INVALID_DATA;
162 }
163
164 if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
165 return PLDM_ERROR_INVALID_LENGTH;
166 }
167
168 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
169 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
170}
gokulsankereca3e192021-04-05 14:57:41 +0530171
172int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
173 size_t payload_length,
174 uint8_t *completion_code,
175 uint32_t *device_identifiers_len,
176 uint8_t *descriptor_count,
177 uint8_t **descriptor_data)
178{
179 if (msg == NULL || completion_code == NULL ||
180 device_identifiers_len == NULL || descriptor_count == NULL ||
181 descriptor_data == NULL) {
182 return PLDM_ERROR_INVALID_DATA;
183 }
184
185 *completion_code = msg->payload[0];
186 if (PLDM_SUCCESS != *completion_code) {
187 return PLDM_SUCCESS;
188 }
189
190 if (payload_length <
191 sizeof(struct pldm_query_device_identifiers_resp)) {
192 return PLDM_ERROR_INVALID_LENGTH;
193 }
194
195 struct pldm_query_device_identifiers_resp *response =
196 (struct pldm_query_device_identifiers_resp *)msg->payload;
197 *device_identifiers_len = le32toh(response->device_identifiers_len);
198
199 if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
200 return PLDM_ERROR_INVALID_LENGTH;
201 }
202
203 if (payload_length !=
204 sizeof(struct pldm_query_device_identifiers_resp) +
205 *device_identifiers_len) {
206 return PLDM_ERROR_INVALID_LENGTH;
207 }
208 *descriptor_count = response->descriptor_count;
209
210 if (*descriptor_count == 0) {
211 return PLDM_ERROR_INVALID_DATA;
212 }
gokulsankereca3e192021-04-05 14:57:41 +0530213 *descriptor_data =
214 (uint8_t *)(msg->payload +
215 sizeof(struct pldm_query_device_identifiers_resp));
216 return PLDM_SUCCESS;
217}
gokulsanker981fbfb2021-04-05 15:17:25 +0530218
219int encode_get_firmware_parameters_req(uint8_t instance_id,
220 size_t payload_length,
221 struct pldm_msg *msg)
222{
223 if (msg == NULL) {
224 return PLDM_ERROR_INVALID_DATA;
225 }
226
227 if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
228 return PLDM_ERROR_INVALID_LENGTH;
229 }
230
231 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
232 PLDM_GET_FIRMWARE_PARAMETERS, msg);
233}
gokulsanker22fbb342021-04-05 15:55:06 +0530234
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700235int decode_get_firmware_parameters_resp(
gokulsanker22fbb342021-04-05 15:55:06 +0530236 const struct pldm_msg *msg, size_t payload_length,
237 struct pldm_get_firmware_parameters_resp *resp_data,
238 struct variable_field *active_comp_image_set_ver_str,
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700239 struct variable_field *pending_comp_image_set_ver_str,
240 struct variable_field *comp_parameter_table)
gokulsanker22fbb342021-04-05 15:55:06 +0530241{
242 if (msg == NULL || resp_data == NULL ||
243 active_comp_image_set_ver_str == NULL ||
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700244 pending_comp_image_set_ver_str == NULL ||
245 comp_parameter_table == NULL) {
gokulsanker22fbb342021-04-05 15:55:06 +0530246 return PLDM_ERROR_INVALID_DATA;
247 }
248
249 if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
250 return PLDM_ERROR_INVALID_LENGTH;
251 }
252
253 struct pldm_get_firmware_parameters_resp *response =
254 (struct pldm_get_firmware_parameters_resp *)msg->payload;
255
256 resp_data->completion_code = response->completion_code;
257
258 if (PLDM_SUCCESS != resp_data->completion_code) {
259 return PLDM_SUCCESS;
260 }
261
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700262 if (!is_string_type_valid(
263 response->active_comp_image_set_ver_str_type) ||
264 (response->active_comp_image_set_ver_str_len == 0)) {
gokulsanker22fbb342021-04-05 15:55:06 +0530265 return PLDM_ERROR_INVALID_DATA;
266 }
267
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700268 if (response->pending_comp_image_set_ver_str_len == 0) {
269 if (response->pending_comp_image_set_ver_str_type !=
270 PLDM_STR_TYPE_UNKNOWN) {
271 return PLDM_ERROR_INVALID_DATA;
272 }
273 } else {
274 if (!is_string_type_valid(
275 response->pending_comp_image_set_ver_str_type)) {
276 return PLDM_ERROR_INVALID_DATA;
277 }
278 }
gokulsanker22fbb342021-04-05 15:55:06 +0530279
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700280 size_t partial_response_length =
281 sizeof(struct pldm_get_firmware_parameters_resp) +
282 response->active_comp_image_set_ver_str_len +
283 response->pending_comp_image_set_ver_str_len;
284
285 if (payload_length < partial_response_length) {
gokulsanker22fbb342021-04-05 15:55:06 +0530286 return PLDM_ERROR_INVALID_LENGTH;
287 }
288
289 resp_data->capabilities_during_update.value =
290 le32toh(response->capabilities_during_update.value);
gokulsanker22fbb342021-04-05 15:55:06 +0530291 resp_data->comp_count = le16toh(response->comp_count);
gokulsanker22fbb342021-04-05 15:55:06 +0530292 resp_data->active_comp_image_set_ver_str_type =
293 response->active_comp_image_set_ver_str_type;
294 resp_data->active_comp_image_set_ver_str_len =
295 response->active_comp_image_set_ver_str_len;
296 resp_data->pending_comp_image_set_ver_str_type =
297 response->pending_comp_image_set_ver_str_type;
298 resp_data->pending_comp_image_set_ver_str_len =
299 response->pending_comp_image_set_ver_str_len;
300
301 active_comp_image_set_ver_str->ptr =
302 msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
303 active_comp_image_set_ver_str->length =
304 resp_data->active_comp_image_set_ver_str_len;
305
306 if (resp_data->pending_comp_image_set_ver_str_len != 0) {
307 pending_comp_image_set_ver_str->ptr =
308 msg->payload +
309 sizeof(struct pldm_get_firmware_parameters_resp) +
310 resp_data->active_comp_image_set_ver_str_len;
311 pending_comp_image_set_ver_str->length =
312 resp_data->pending_comp_image_set_ver_str_len;
313 } else {
314 pending_comp_image_set_ver_str->ptr = NULL;
315 pending_comp_image_set_ver_str->length = 0;
316 }
317
Tom Joseph3fd3eb82021-06-18 04:13:29 -0700318 if (payload_length > partial_response_length && resp_data->comp_count) {
319 comp_parameter_table->ptr =
320 msg->payload +
321 sizeof(struct pldm_get_firmware_parameters_resp) +
322 resp_data->active_comp_image_set_ver_str_len +
323 resp_data->pending_comp_image_set_ver_str_len;
324 comp_parameter_table->length =
325 payload_length - partial_response_length;
326 } else {
327 comp_parameter_table->ptr = NULL;
328 comp_parameter_table->length = 0;
329 }
330
gokulsanker22fbb342021-04-05 15:55:06 +0530331 return PLDM_SUCCESS;
332}
gokulsankere1fb7a82021-04-05 16:09:29 +0530333
334int decode_get_firmware_parameters_resp_comp_entry(
335 const uint8_t *data, size_t length,
336 struct pldm_component_parameter_entry *component_data,
337 struct variable_field *active_comp_ver_str,
338 struct variable_field *pending_comp_ver_str)
339{
340 if (data == NULL || component_data == NULL ||
341 active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
342 return PLDM_ERROR_INVALID_DATA;
343 }
344
345 if (length < sizeof(struct pldm_component_parameter_entry)) {
346 return PLDM_ERROR_INVALID_LENGTH;
347 }
348
349 struct pldm_component_parameter_entry *entry =
350 (struct pldm_component_parameter_entry *)(data);
351 if (entry->active_comp_ver_str_len == 0) {
352 return PLDM_ERROR_INVALID_LENGTH;
353 }
354
355 size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
356 entry->active_comp_ver_str_len +
357 entry->pending_comp_ver_str_len;
358
359 if (length != entry_length) {
360 return PLDM_ERROR_INVALID_LENGTH;
361 }
362
363 component_data->comp_classification =
364 le16toh(entry->comp_classification);
365 component_data->comp_identifier = le16toh(entry->comp_identifier);
366 component_data->comp_classification_index =
367 entry->comp_classification_index;
368 component_data->active_comp_comparison_stamp =
369 le32toh(entry->active_comp_comparison_stamp);
370 component_data->active_comp_ver_str_type =
371 entry->active_comp_ver_str_type;
372 component_data->active_comp_ver_str_len =
373 entry->active_comp_ver_str_len;
374 memcpy(component_data->active_comp_release_date,
375 entry->active_comp_release_date,
376 sizeof(entry->active_comp_release_date));
377 component_data->pending_comp_comparison_stamp =
378 le32toh(entry->pending_comp_comparison_stamp);
379 component_data->pending_comp_ver_str_type =
380 entry->pending_comp_ver_str_type;
381 component_data->pending_comp_ver_str_len =
382 entry->pending_comp_ver_str_len;
383 memcpy(component_data->pending_comp_release_date,
384 entry->pending_comp_release_date,
385 sizeof(entry->pending_comp_release_date));
386 component_data->comp_activation_methods.value =
387 le16toh(entry->comp_activation_methods.value);
388 component_data->capabilities_during_update.value =
389 le32toh(entry->capabilities_during_update.value);
390
391 active_comp_ver_str->ptr =
392 data + sizeof(struct pldm_component_parameter_entry);
393 active_comp_ver_str->length = entry->active_comp_ver_str_len;
394
395 if (entry->pending_comp_ver_str_len != 0) {
396
397 pending_comp_ver_str->ptr =
398 data + sizeof(struct pldm_component_parameter_entry) +
399 entry->active_comp_ver_str_len;
400 pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
401 } else {
402 pending_comp_ver_str->ptr = NULL;
403 pending_comp_ver_str->length = 0;
404 }
405 return PLDM_SUCCESS;
406}