blob: b726139cd0117167f8f4e326ed5e48c2515bce97 [file] [log] [blame]
John Wang9fa87cf2020-06-10 17:53:40 +08001#include <assert.h>
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +05302#include <endian.h>
John Wang9fa87cf2020-06-10 17:53:40 +08003#include <stdbool.h>
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +05304#include <string.h>
5
6#include "fru.h"
7
8int encode_get_fru_record_table_metadata_req(uint8_t instance_id,
Christian Geddes3bdb3c22020-05-01 14:55:39 -05009 struct pldm_msg *msg,
10 size_t payload_length)
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +053011{
12 if (msg == NULL) {
13 return PLDM_ERROR_INVALID_DATA;
14 }
15
Christian Geddes3bdb3c22020-05-01 14:55:39 -050016 if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES) {
17 return PLDM_ERROR_INVALID_LENGTH;
18 }
19
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +053020 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;
Christian Geddes3bdb3c22020-05-01 14:55:39 -050025
George Liub7095ff2021-06-14 16:01:57 +080026 return pack_pldm_header(&header, &(msg->hdr));
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +053027}
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
George Liu684a7162019-12-06 15:10:52 +080044 *completion_code = msg->payload[0];
45 if (PLDM_SUCCESS != *completion_code) {
46 return PLDM_SUCCESS;
47 }
48
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +053049 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;
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +053055
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{
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +053075 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;
George Liub7095ff2021-06-14 16:01:57 +080084
85 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +053086 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}
PriyangaRamasamy497665a2019-07-30 12:48:25 +0530107
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{
George Liub7095ff2021-06-14 16:01:57 +0800137 if (msg == NULL) {
138 return PLDM_ERROR_INVALID_DATA;
139 }
PriyangaRamasamy497665a2019-07-30 12:48:25 +0530140
George Liub7095ff2021-06-14 16:01:57 +0800141 struct pldm_header_info header = {0};
PriyangaRamasamy497665a2019-07-30 12:48:25 +0530142 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
George Liub7095ff2021-06-14 16:01:57 +0800147 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
148 if (rc > PLDM_SUCCESS) {
PriyangaRamasamy497665a2019-07-30 12:48:25 +0530149 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}
Tom Joseph93d68712020-01-07 10:24:41 +0530166
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
Tom Joseph93d68712020-01-07 10:24:41 +0530175 if (fru_table == NULL || curr_size == NULL || !tlvs_size) {
176 return PLDM_ERROR_INVALID_DATA;
177 }
Manojkiran Edabcf91ac2021-03-14 13:50:48 +0530178 if ((*curr_size + record_hdr_size + tlvs_size) != total_size) {
179 return PLDM_ERROR_INVALID_LENGTH;
180 }
Tom Joseph93d68712020-01-07 10:24:41 +0530181
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}
PriyangaRamasamyf3295be2019-07-23 12:18:40 +0530197
John Wang9e82ad12020-06-12 10:53:32 +0800198static 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
John Wang9fa87cf2020-06-10 17:53:40 +0800265int 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;
George Liub7095ff2021-06-14 16:01:57 +0800286 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
John Wang9fa87cf2020-06-10 17:53:40 +0800287 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
George Liub7095ff2021-06-14 16:01:57 +0800346 if (payload_length !=
347 PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES + data_size) {
John Wang9fa87cf2020-06-10 17:53:40 +0800348 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;
George Liub7095ff2021-06-14 16:01:57 +0800356 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
John Wang9fa87cf2020-06-10 17:53:40 +0800357 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
George Liub7095ff2021-06-14 16:01:57 +0800368 if (completion_code == PLDM_SUCCESS) {
369 memcpy(resp->fru_structure_data, fru_structure_data, data_size);
John Wang9fa87cf2020-06-10 17:53:40 +0800370 }
371
John Wang9fa87cf2020-06-10 17:53:40 +0800372 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
PriyangaRamasamyf3295be2019-07-23 12:18:40 +0530407int 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{
George Liub7095ff2021-06-14 16:01:57 +0800413 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 }
PriyangaRamasamyf3295be2019-07-23 12:18:40 +0530419
George Liub7095ff2021-06-14 16:01:57 +0800420 struct pldm_header_info header = {0};
PriyangaRamasamyf3295be2019-07-23 12:18:40 +0530421 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
George Liub7095ff2021-06-14 16:01:57 +0800426 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
427 if (rc != PLDM_SUCCESS) {
PriyangaRamasamyf3295be2019-07-23 12:18:40 +0530428 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(
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{
444 if (msg == NULL || completion_code == NULL ||
445 next_data_transfer_handle == NULL || transfer_flag == NULL ||
446 fru_record_table_data == NULL || fru_record_table_length == NULL) {
447 return PLDM_ERROR_INVALID_DATA;
448 }
449
450 *completion_code = msg->payload[0];
451 if (PLDM_SUCCESS != *completion_code) {
452 return PLDM_SUCCESS;
453 }
454 if (payload_length <= PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES) {
455 return PLDM_ERROR_INVALID_LENGTH;
456 }
457
458 struct pldm_get_fru_record_table_resp *resp =
459 (struct pldm_get_fru_record_table_resp *)msg->payload;
460
461 *next_data_transfer_handle = le32toh(resp->next_data_transfer_handle);
462 *transfer_flag = resp->transfer_flag;
463 memcpy(fru_record_table_data, resp->fru_record_table_data,
464 payload_length - PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES);
465 *fru_record_table_length =
466 payload_length - PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES;
467
468 return PLDM_SUCCESS;
469}