blob: be9d4114bd53316d1bf0bd8dceb906315efc90d2 [file] [log] [blame]
Andrew Jeffery9c766792022-08-10 23:12:49 +09301#include <assert.h>
2#include <endian.h>
3#include <stdbool.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05304#include <stdint.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09305#include <string.h>
6
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05307#include "base.h"
Andrew Jeffery9c766792022-08-10 23:12:49 +09308#include "fru.h"
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05309#include "utils.h"
Andrew Jeffery9c766792022-08-10 23:12:49 +093010
11int encode_get_fru_record_table_metadata_req(uint8_t instance_id,
12 struct pldm_msg *msg,
13 size_t payload_length)
14{
15 if (msg == NULL) {
16 return PLDM_ERROR_INVALID_DATA;
17 }
18
19 if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES) {
20 return PLDM_ERROR_INVALID_LENGTH;
21 }
22
23 struct pldm_header_info header = {0};
24 header.instance = instance_id;
25 header.msg_type = PLDM_REQUEST;
26 header.pldm_type = PLDM_FRU;
27 header.command = PLDM_GET_FRU_RECORD_TABLE_METADATA;
28
29 return pack_pldm_header(&header, &(msg->hdr));
30}
31
32int decode_get_fru_record_table_metadata_resp(
33 const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
34 uint8_t *fru_data_major_version, uint8_t *fru_data_minor_version,
35 uint32_t *fru_table_maximum_size, uint32_t *fru_table_length,
36 uint16_t *total_record_set_identifiers, uint16_t *total_table_records,
37 uint32_t *checksum)
38{
39 if (msg == NULL || completion_code == NULL ||
40 fru_data_major_version == NULL || fru_data_minor_version == NULL ||
41 fru_table_maximum_size == NULL || fru_table_length == NULL ||
42 total_record_set_identifiers == NULL ||
43 total_table_records == NULL || checksum == NULL) {
44 return PLDM_ERROR_INVALID_DATA;
45 }
46
47 *completion_code = msg->payload[0];
48 if (PLDM_SUCCESS != *completion_code) {
49 return PLDM_SUCCESS;
50 }
51
52 if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES) {
53 return PLDM_ERROR_INVALID_LENGTH;
54 }
55
56 struct pldm_get_fru_record_table_metadata_resp *response =
57 (struct pldm_get_fru_record_table_metadata_resp *)msg->payload;
58
59 *fru_data_major_version = response->fru_data_major_version;
60 *fru_data_minor_version = response->fru_data_minor_version;
61 *fru_table_maximum_size = le32toh(response->fru_table_maximum_size);
62 *fru_table_length = le32toh(response->fru_table_length);
63 *total_record_set_identifiers =
64 le16toh(response->total_record_set_identifiers);
65 *total_table_records = le16toh(response->total_table_records);
66 *checksum = le32toh(response->checksum);
67
68 return PLDM_SUCCESS;
69}
70
71int encode_get_fru_record_table_metadata_resp(
72 uint8_t instance_id, uint8_t completion_code,
73 uint8_t fru_data_major_version, uint8_t fru_data_minor_version,
74 uint32_t fru_table_maximum_size, uint32_t fru_table_length,
75 uint16_t total_record_set_identifiers, uint16_t total_table_records,
76 uint32_t checksum, struct pldm_msg *msg)
77{
78 if (msg == NULL) {
79 return PLDM_ERROR_INVALID_DATA;
80 }
81
82 struct pldm_header_info header = {0};
83 header.msg_type = PLDM_RESPONSE;
84 header.instance = instance_id;
85 header.pldm_type = PLDM_FRU;
86 header.command = PLDM_GET_FRU_RECORD_TABLE_METADATA;
87
88 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
89 if (PLDM_SUCCESS != rc) {
90 return rc;
91 }
92
93 struct pldm_get_fru_record_table_metadata_resp *response =
94 (struct pldm_get_fru_record_table_metadata_resp *)msg->payload;
95 response->completion_code = completion_code;
96 if (response->completion_code == PLDM_SUCCESS) {
97 response->fru_data_major_version = fru_data_major_version;
98 response->fru_data_minor_version = fru_data_minor_version;
99 response->fru_table_maximum_size =
100 htole32(fru_table_maximum_size);
101 response->fru_table_length = htole32(fru_table_length);
102 response->total_record_set_identifiers =
103 htole16(total_record_set_identifiers);
104 response->total_table_records = htole16(total_table_records);
105 response->checksum = htole32(checksum);
106 }
107
108 return PLDM_SUCCESS;
109}
110
111int decode_get_fru_record_table_req(const struct pldm_msg *msg,
112 size_t payload_length,
113 uint32_t *data_transfer_handle,
114 uint8_t *transfer_operation_flag)
115{
116 if (msg == NULL || data_transfer_handle == NULL ||
117 transfer_operation_flag == NULL) {
118 return PLDM_ERROR_INVALID_DATA;
119 }
120
121 if (payload_length != PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES) {
122 return PLDM_ERROR_INVALID_LENGTH;
123 }
124
125 struct pldm_get_fru_record_table_req *req =
126 (struct pldm_get_fru_record_table_req *)msg->payload;
127
128 *data_transfer_handle = le32toh(req->data_transfer_handle);
129 *transfer_operation_flag = req->transfer_operation_flag;
130
131 return PLDM_SUCCESS;
132}
133
134int encode_get_fru_record_table_resp(uint8_t instance_id,
135 uint8_t completion_code,
136 uint32_t next_data_transfer_handle,
137 uint8_t transfer_flag,
138 struct pldm_msg *msg)
139{
140 if (msg == NULL) {
141 return PLDM_ERROR_INVALID_DATA;
142 }
143
144 struct pldm_header_info header = {0};
145 header.msg_type = PLDM_RESPONSE;
146 header.instance = instance_id;
147 header.pldm_type = PLDM_FRU;
148 header.command = PLDM_GET_FRU_RECORD_TABLE;
149
150 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
151 if (rc > PLDM_SUCCESS) {
152 return rc;
153 }
154
155 struct pldm_get_fru_record_table_resp *resp =
156 (struct pldm_get_fru_record_table_resp *)msg->payload;
157
158 resp->completion_code = completion_code;
159
160 if (resp->completion_code == PLDM_SUCCESS) {
161
162 resp->next_data_transfer_handle =
163 htole32(next_data_transfer_handle);
164 resp->transfer_flag = transfer_flag;
165 }
166
167 return PLDM_SUCCESS;
168}
169
170int encode_fru_record(uint8_t *fru_table, size_t total_size, size_t *curr_size,
171 uint16_t record_set_id, uint8_t record_type,
172 uint8_t num_frus, uint8_t encoding, uint8_t *tlvs,
173 size_t tlvs_size)
174{
175 size_t record_hdr_size = sizeof(struct pldm_fru_record_data_format) -
176 sizeof(struct pldm_fru_record_tlv);
177
178 if (fru_table == NULL || curr_size == NULL || !tlvs_size) {
179 return PLDM_ERROR_INVALID_DATA;
180 }
181 if ((*curr_size + record_hdr_size + tlvs_size) != total_size) {
182 return PLDM_ERROR_INVALID_LENGTH;
183 }
184
185 struct pldm_fru_record_data_format *record =
186 (struct pldm_fru_record_data_format *)(fru_table + *curr_size);
187 record->record_set_id = htole16(record_set_id);
188 record->record_type = record_type;
189 record->num_fru_fields = num_frus;
190 record->encoding_type = encoding;
191 *curr_size += record_hdr_size;
192
193 if (tlvs) {
194 memcpy(fru_table + *curr_size, tlvs, tlvs_size);
195 *curr_size += tlvs_size;
196 }
197
198 return PLDM_SUCCESS;
199}
200
201static bool is_table_end(const struct pldm_fru_record_data_format *p,
202 const void *table, size_t table_size)
203{
204 return p ==
205 (const struct pldm_fru_record_data_format *)((uint8_t *)table +
206 table_size);
207}
208
209void get_fru_record_by_option(const uint8_t *table, size_t table_size,
210 uint8_t *record_table, size_t *record_size,
211 uint16_t rsi, uint8_t rt, uint8_t ft)
212{
213 const struct pldm_fru_record_data_format *record_data_src =
214 (const struct pldm_fru_record_data_format *)table;
215 struct pldm_fru_record_data_format *record_data_dest;
216 int count = 0;
217
218 const struct pldm_fru_record_tlv *tlv;
219 size_t len;
220 uint8_t *pos = record_table;
221
222 while (!is_table_end(record_data_src, table, table_size)) {
223 if ((record_data_src->record_set_id != htole16(rsi) &&
224 rsi != 0) ||
225 (record_data_src->record_type != rt && rt != 0)) {
226 tlv = record_data_src->tlvs;
227 for (int i = 0; i < record_data_src->num_fru_fields;
228 i++) {
229 len = sizeof(*tlv) - 1 + tlv->length;
230 tlv = (const struct pldm_fru_record_tlv
231 *)((char *)tlv + len);
232 }
233 record_data_src =
234 (const struct pldm_fru_record_data_format *)(tlv);
235 continue;
236 }
237
238 len = sizeof(struct pldm_fru_record_data_format) -
239 sizeof(struct pldm_fru_record_tlv);
240
241 assert(pos - record_table + len < *record_size);
242 memcpy(pos, record_data_src, len);
243
244 record_data_dest = (struct pldm_fru_record_data_format *)pos;
245 pos += len;
246
247 tlv = record_data_src->tlvs;
248 count = 0;
249 for (int i = 0; i < record_data_src->num_fru_fields; i++) {
250 len = sizeof(*tlv) - 1 + tlv->length;
251 if (tlv->type == ft || ft == 0) {
252 assert(pos - record_table + len < *record_size);
253 memcpy(pos, tlv, len);
254 pos += len;
255 count++;
256 }
257 tlv = (const struct pldm_fru_record_tlv *)((char *)tlv +
258 len);
259 }
260 record_data_dest->num_fru_fields = count;
261 record_data_src =
262 (const struct pldm_fru_record_data_format *)(tlv);
263 }
264
265 *record_size = pos - record_table;
266}
267
268int encode_get_fru_record_by_option_req(
269 uint8_t instance_id, uint32_t data_transfer_handle,
270 uint16_t fru_table_handle, uint16_t record_set_identifier,
271 uint8_t record_type, uint8_t field_type, uint8_t transfer_op_flag,
272 struct pldm_msg *msg, size_t payload_length)
273{
274
275 if (msg == NULL) {
276 return PLDM_ERROR_INVALID_DATA;
277 }
278
279 if (payload_length !=
280 sizeof(struct pldm_get_fru_record_by_option_req)) {
281 return PLDM_ERROR_INVALID_LENGTH;
282 }
283
284 struct pldm_header_info header = {0};
285 header.instance = instance_id;
286 header.msg_type = PLDM_REQUEST;
287 header.pldm_type = PLDM_FRU;
288 header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
289 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
290 if (rc != PLDM_SUCCESS) {
291 return rc;
292 }
293
294 struct pldm_get_fru_record_by_option_req *req =
295 (struct pldm_get_fru_record_by_option_req *)msg->payload;
296
297 req->data_transfer_handle = htole32(data_transfer_handle);
298 req->fru_table_handle = htole16(fru_table_handle);
299 req->record_set_identifier = htole16(record_set_identifier);
300 req->record_type = record_type;
301 req->field_type = field_type;
302 req->transfer_op_flag = transfer_op_flag;
303
304 return PLDM_SUCCESS;
305}
306
307int decode_get_fru_record_by_option_req(
308 const struct pldm_msg *msg, size_t payload_length,
309 uint32_t *data_transfer_handle, uint16_t *fru_table_handle,
310 uint16_t *record_set_identifier, uint8_t *record_type, uint8_t *field_type,
311 uint8_t *transfer_op_flag)
312{
313 if (msg == NULL || data_transfer_handle == NULL ||
314 fru_table_handle == NULL || record_set_identifier == NULL ||
315 record_type == NULL || field_type == NULL ||
316 transfer_op_flag == NULL) {
317 return PLDM_ERROR_INVALID_DATA;
318 }
319
320 if (payload_length !=
321 sizeof(struct pldm_get_fru_record_by_option_req)) {
322 return PLDM_ERROR_INVALID_LENGTH;
323 }
324
325 struct pldm_get_fru_record_by_option_req *req =
326 (struct pldm_get_fru_record_by_option_req *)msg->payload;
327
328 *data_transfer_handle = le32toh(req->data_transfer_handle);
329 *fru_table_handle = le16toh(req->fru_table_handle);
330 *record_set_identifier = le16toh(req->record_set_identifier);
331 *record_type = req->record_type;
332 *field_type = req->field_type;
333 *transfer_op_flag = req->transfer_op_flag;
334 return PLDM_SUCCESS;
335}
336
337int encode_get_fru_record_by_option_resp(uint8_t instance_id,
338 uint8_t completion_code,
339 uint32_t next_data_transfer_handle,
340 uint8_t transfer_flag,
341 const void *fru_structure_data,
342 size_t data_size, struct pldm_msg *msg,
343 size_t payload_length)
344{
345 if (msg == NULL || fru_structure_data == NULL) {
346 return PLDM_ERROR_INVALID_DATA;
347 }
348
349 if (payload_length !=
350 PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES + data_size) {
351 return PLDM_ERROR_INVALID_LENGTH;
352 }
353
354 struct pldm_header_info header = {0};
355 header.instance = instance_id;
356 header.msg_type = PLDM_RESPONSE;
357 header.pldm_type = PLDM_FRU;
358 header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
359 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
360 if (rc != PLDM_SUCCESS) {
361 return rc;
362 }
363
364 struct pldm_get_fru_record_by_option_resp *resp =
365 (struct pldm_get_fru_record_by_option_resp *)msg->payload;
366
367 resp->completion_code = completion_code;
368 resp->next_data_transfer_handle = htole32(next_data_transfer_handle);
369 resp->transfer_flag = transfer_flag;
370
371 if (completion_code == PLDM_SUCCESS) {
372 memcpy(resp->fru_structure_data, fru_structure_data, data_size);
373 }
374
375 return PLDM_SUCCESS;
376}
377
378int decode_get_fru_record_by_option_resp(
379 const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
380 uint32_t *next_transfer_handle, uint8_t *transfer_flag,
381 struct variable_field *fru_structure_data)
382{
383 if (msg == NULL || completion_code == NULL ||
384 next_transfer_handle == NULL || transfer_flag == NULL ||
385 fru_structure_data == NULL) {
386 return PLDM_ERROR_INVALID_DATA;
387 }
388
389 *completion_code = msg->payload[0];
390 if (PLDM_SUCCESS != *completion_code) {
391 return PLDM_SUCCESS;
392 }
393
394 if (payload_length < PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES) {
395 return PLDM_ERROR_INVALID_LENGTH;
396 }
397
398 struct pldm_get_fru_record_by_option_resp *resp =
399 (struct pldm_get_fru_record_by_option_resp *)msg->payload;
400
401 *next_transfer_handle = le32toh(resp->next_data_transfer_handle);
402 *transfer_flag = resp->transfer_flag;
403 fru_structure_data->ptr = resp->fru_structure_data;
404 fru_structure_data->length =
405 payload_length - PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES;
406
407 return PLDM_SUCCESS;
408}
409
410int encode_get_fru_record_table_req(uint8_t instance_id,
411 uint32_t data_transfer_handle,
412 uint8_t transfer_operation_flag,
413 struct pldm_msg *msg, size_t payload_length)
414
415{
416 if (msg == NULL) {
417 return PLDM_ERROR_INVALID_DATA;
418 }
419 if (payload_length != sizeof(struct pldm_get_fru_record_table_req)) {
420 return PLDM_ERROR_INVALID_LENGTH;
421 }
422
423 struct pldm_header_info header = {0};
424 header.msg_type = PLDM_REQUEST;
425 header.instance = instance_id;
426 header.pldm_type = PLDM_FRU;
427 header.command = PLDM_GET_FRU_RECORD_TABLE;
428
429 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
430 if (rc != PLDM_SUCCESS) {
431 return rc;
432 }
433
434 struct pldm_get_fru_record_table_req *req =
435 (struct pldm_get_fru_record_table_req *)msg->payload;
436 req->data_transfer_handle = htole32(data_transfer_handle);
437 req->transfer_operation_flag = transfer_operation_flag;
438
439 return PLDM_SUCCESS;
440}
441
442int decode_get_fru_record_table_resp_safe(
443 const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
444 uint32_t *next_data_transfer_handle, uint8_t *transfer_flag,
445 uint8_t *fru_record_table_data, size_t *fru_record_table_length,
446 size_t max_fru_record_table_length)
447{
448 if (msg == NULL || completion_code == NULL ||
449 next_data_transfer_handle == NULL || transfer_flag == NULL ||
450 fru_record_table_data == NULL || fru_record_table_length == NULL) {
451 return PLDM_ERROR_INVALID_DATA;
452 }
453
454 *completion_code = msg->payload[0];
455 if (PLDM_SUCCESS != *completion_code) {
456 return PLDM_SUCCESS;
457 }
458 if (payload_length <= PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES) {
459 return PLDM_ERROR_INVALID_LENGTH;
460 }
461
462 struct pldm_get_fru_record_table_resp *resp =
463 (struct pldm_get_fru_record_table_resp *)msg->payload;
464
465 *next_data_transfer_handle = le32toh(resp->next_data_transfer_handle);
466 *transfer_flag = resp->transfer_flag;
467
468 *fru_record_table_length =
469 payload_length - PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES;
470
471 if (*fru_record_table_length > max_fru_record_table_length) {
472 return PLDM_ERROR_INVALID_LENGTH;
473 }
474
475 memcpy(fru_record_table_data, resp->fru_record_table_data,
476 *fru_record_table_length);
477
478 return PLDM_SUCCESS;
479}
480
481int decode_get_fru_record_table_resp(
482 const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
483 uint32_t *next_data_transfer_handle, uint8_t *transfer_flag,
484 uint8_t *fru_record_table_data, size_t *fru_record_table_length)
485{
486 return decode_get_fru_record_table_resp_safe(
487 msg, payload_length, completion_code, next_data_transfer_handle,
488 transfer_flag, fru_record_table_data, fru_record_table_length,
489 (size_t)-1);
490}
491
492int decode_set_fru_record_table_req(const struct pldm_msg *msg,
493 size_t payload_length,
494 uint32_t *data_transfer_handle,
495 uint8_t *transfer_flag,
496 struct variable_field *fru_table_data)
497
498{
499 if (msg == NULL || data_transfer_handle == NULL ||
500 transfer_flag == NULL || fru_table_data == NULL) {
501 return PLDM_ERROR_INVALID_DATA;
502 }
503
504 if (payload_length <= PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES) {
505 return PLDM_ERROR_INVALID_LENGTH;
506 }
507
508 struct pldm_set_fru_record_table_req *req =
509 (struct pldm_set_fru_record_table_req *)msg->payload;
510
511 *data_transfer_handle = le32toh(req->data_transfer_handle);
512 *transfer_flag = req->transfer_flag;
513 fru_table_data->length =
514 payload_length - PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES;
515 fru_table_data->ptr = req->fru_record_table_data;
516
517 return PLDM_SUCCESS;
518}
519
520int encode_set_fru_record_table_resp(uint8_t instance_id,
521 uint8_t completion_code,
522 uint32_t next_data_transfer_handle,
523 size_t payload_length,
524 struct pldm_msg *msg)
525{
526 if (msg == NULL) {
527 return PLDM_ERROR_INVALID_DATA;
528 }
529 if (payload_length != PLDM_SET_FRU_RECORD_TABLE_RESP_BYTES) {
530 return PLDM_ERROR_INVALID_LENGTH;
531 }
532
533 struct pldm_header_info header = {0};
534 header.instance = instance_id;
535 header.msg_type = PLDM_RESPONSE;
536 header.pldm_type = PLDM_FRU;
537 header.command = PLDM_SET_FRU_RECORD_TABLE;
538
539 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
540 if (PLDM_SUCCESS != rc) {
541 return rc;
542 }
543
544 struct pldm_set_fru_record_table_resp *response =
545 (struct pldm_set_fru_record_table_resp *)msg->payload;
546 response->completion_code = completion_code;
547 response->next_data_transfer_handle =
548 htole32(next_data_transfer_handle);
549
550 return PLDM_SUCCESS;
551}