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