blob: 3e0887d09e42633412f1d9046e2cbf0bb3d729f0 [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;
25 int rc = pack_pldm_header(&header, &(msg->hdr));
26 if (PLDM_SUCCESS != rc) {
27 return rc;
28 }
Christian Geddes3bdb3c22020-05-01 14:55:39 -050029
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +053030 return PLDM_SUCCESS;
31}
32
33int decode_get_fru_record_table_metadata_resp(
34 const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
35 uint8_t *fru_data_major_version, uint8_t *fru_data_minor_version,
36 uint32_t *fru_table_maximum_size, uint32_t *fru_table_length,
37 uint16_t *total_record_set_identifiers, uint16_t *total_table_records,
38 uint32_t *checksum)
39{
40 if (msg == NULL || completion_code == NULL ||
41 fru_data_major_version == NULL || fru_data_minor_version == NULL ||
42 fru_table_maximum_size == NULL || fru_table_length == NULL ||
43 total_record_set_identifiers == NULL ||
44 total_table_records == NULL || checksum == NULL) {
45 return PLDM_ERROR_INVALID_DATA;
46 }
47
George Liu684a7162019-12-06 15:10:52 +080048 *completion_code = msg->payload[0];
49 if (PLDM_SUCCESS != *completion_code) {
50 return PLDM_SUCCESS;
51 }
52
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +053053 if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES) {
54 return PLDM_ERROR_INVALID_LENGTH;
55 }
56
57 struct pldm_get_fru_record_table_metadata_resp *response =
58 (struct pldm_get_fru_record_table_metadata_resp *)msg->payload;
Jinu Joy Thomas8e92c6c2019-08-06 12:22:34 +053059
60 *fru_data_major_version = response->fru_data_major_version;
61 *fru_data_minor_version = response->fru_data_minor_version;
62 *fru_table_maximum_size = le32toh(response->fru_table_maximum_size);
63 *fru_table_length = le32toh(response->fru_table_length);
64 *total_record_set_identifiers =
65 le16toh(response->total_record_set_identifiers);
66 *total_table_records = le16toh(response->total_table_records);
67 *checksum = le32toh(response->checksum);
68
69 return PLDM_SUCCESS;
70}
71
72int encode_get_fru_record_table_metadata_resp(
73 uint8_t instance_id, uint8_t completion_code,
74 uint8_t fru_data_major_version, uint8_t fru_data_minor_version,
75 uint32_t fru_table_maximum_size, uint32_t fru_table_length,
76 uint16_t total_record_set_identifiers, uint16_t total_table_records,
77 uint32_t checksum, struct pldm_msg *msg)
78{
79
80 if (msg == NULL) {
81 return PLDM_ERROR_INVALID_DATA;
82 }
83
84 struct pldm_header_info header = {0};
85 header.msg_type = PLDM_RESPONSE;
86 header.instance = instance_id;
87 header.pldm_type = PLDM_FRU;
88 header.command = PLDM_GET_FRU_RECORD_TABLE_METADATA;
89 int rc = pack_pldm_header(&header, &(msg->hdr));
90 if (PLDM_SUCCESS != rc) {
91 return rc;
92 }
93
94 struct pldm_get_fru_record_table_metadata_resp *response =
95 (struct pldm_get_fru_record_table_metadata_resp *)msg->payload;
96 response->completion_code = completion_code;
97 if (response->completion_code == PLDM_SUCCESS) {
98 response->fru_data_major_version = fru_data_major_version;
99 response->fru_data_minor_version = fru_data_minor_version;
100 response->fru_table_maximum_size =
101 htole32(fru_table_maximum_size);
102 response->fru_table_length = htole32(fru_table_length);
103 response->total_record_set_identifiers =
104 htole16(total_record_set_identifiers);
105 response->total_table_records = htole16(total_table_records);
106 response->checksum = htole32(checksum);
107 }
108
109 return PLDM_SUCCESS;
110}
PriyangaRamasamy497665a2019-07-30 12:48:25 +0530111
112int decode_get_fru_record_table_req(const struct pldm_msg *msg,
113 size_t payload_length,
114 uint32_t *data_transfer_handle,
115 uint8_t *transfer_operation_flag)
116{
117 if (msg == NULL || data_transfer_handle == NULL ||
118 transfer_operation_flag == NULL) {
119 return PLDM_ERROR_INVALID_DATA;
120 }
121
122 if (payload_length != PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES) {
123 return PLDM_ERROR_INVALID_LENGTH;
124 }
125
126 struct pldm_get_fru_record_table_req *req =
127 (struct pldm_get_fru_record_table_req *)msg->payload;
128
129 *data_transfer_handle = le32toh(req->data_transfer_handle);
130 *transfer_operation_flag = req->transfer_operation_flag;
131
132 return PLDM_SUCCESS;
133}
134
135int encode_get_fru_record_table_resp(uint8_t instance_id,
136 uint8_t completion_code,
137 uint32_t next_data_transfer_handle,
138 uint8_t transfer_flag,
139 struct pldm_msg *msg)
140{
141 struct pldm_header_info header = {0};
142 int rc = PLDM_ERROR_INVALID_DATA;
143
144 header.msg_type = PLDM_RESPONSE;
145 header.instance = instance_id;
146 header.pldm_type = PLDM_FRU;
147 header.command = PLDM_GET_FRU_RECORD_TABLE;
148
149 if (msg == NULL) {
150 return rc;
151 }
152
153 if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
154 return rc;
155 }
156
157 struct pldm_get_fru_record_table_resp *resp =
158 (struct pldm_get_fru_record_table_resp *)msg->payload;
159
160 resp->completion_code = completion_code;
161
162 if (resp->completion_code == PLDM_SUCCESS) {
163
164 resp->next_data_transfer_handle =
165 htole32(next_data_transfer_handle);
166 resp->transfer_flag = transfer_flag;
167 }
168
169 return PLDM_SUCCESS;
170}
Tom Joseph93d68712020-01-07 10:24:41 +0530171
172int encode_fru_record(uint8_t *fru_table, size_t total_size, size_t *curr_size,
173 uint16_t record_set_id, uint8_t record_type,
174 uint8_t num_frus, uint8_t encoding, uint8_t *tlvs,
175 size_t tlvs_size)
176{
177 size_t record_hdr_size = sizeof(struct pldm_fru_record_data_format) -
178 sizeof(struct pldm_fru_record_tlv);
179
Tom Joseph93d68712020-01-07 10:24:41 +0530180 if (fru_table == NULL || curr_size == NULL || !tlvs_size) {
181 return PLDM_ERROR_INVALID_DATA;
182 }
Manojkiran Edabcf91ac2021-03-14 13:50:48 +0530183 if ((*curr_size + record_hdr_size + tlvs_size) != total_size) {
184 return PLDM_ERROR_INVALID_LENGTH;
185 }
Tom Joseph93d68712020-01-07 10:24:41 +0530186
187 struct pldm_fru_record_data_format *record =
188 (struct pldm_fru_record_data_format *)(fru_table + *curr_size);
189 record->record_set_id = htole16(record_set_id);
190 record->record_type = record_type;
191 record->num_fru_fields = num_frus;
192 record->encoding_type = encoding;
193 *curr_size += record_hdr_size;
194
195 if (tlvs) {
196 memcpy(fru_table + *curr_size, tlvs, tlvs_size);
197 *curr_size += tlvs_size;
198 }
199
200 return PLDM_SUCCESS;
201}
PriyangaRamasamyf3295be2019-07-23 12:18:40 +0530202
John Wang9e82ad12020-06-12 10:53:32 +0800203static bool is_table_end(const struct pldm_fru_record_data_format *p,
204 const void *table, size_t table_size)
205{
206 return p ==
207 (const struct pldm_fru_record_data_format *)((uint8_t *)table +
208 table_size);
209}
210
211void get_fru_record_by_option(const uint8_t *table, size_t table_size,
212 uint8_t *record_table, size_t *record_size,
213 uint16_t rsi, uint8_t rt, uint8_t ft)
214{
215 const struct pldm_fru_record_data_format *record_data_src =
216 (const struct pldm_fru_record_data_format *)table;
217 struct pldm_fru_record_data_format *record_data_dest;
218 int count = 0;
219
220 const struct pldm_fru_record_tlv *tlv;
221 size_t len;
222 uint8_t *pos = record_table;
223
224 while (!is_table_end(record_data_src, table, table_size)) {
225 if ((record_data_src->record_set_id != htole16(rsi) &&
226 rsi != 0) ||
227 (record_data_src->record_type != rt && rt != 0)) {
228 tlv = record_data_src->tlvs;
229 for (int i = 0; i < record_data_src->num_fru_fields;
230 i++) {
231 len = sizeof(*tlv) - 1 + tlv->length;
232 tlv = (const struct pldm_fru_record_tlv
233 *)((char *)tlv + len);
234 }
235 record_data_src =
236 (const struct pldm_fru_record_data_format *)(tlv);
237 continue;
238 }
239
240 len = sizeof(struct pldm_fru_record_data_format) -
241 sizeof(struct pldm_fru_record_tlv);
242
243 assert(pos - record_table + len < *record_size);
244 memcpy(pos, record_data_src, len);
245
246 record_data_dest = (struct pldm_fru_record_data_format *)pos;
247 pos += len;
248
249 tlv = record_data_src->tlvs;
250 count = 0;
251 for (int i = 0; i < record_data_src->num_fru_fields; i++) {
252 len = sizeof(*tlv) - 1 + tlv->length;
253 if (tlv->type == ft || ft == 0) {
254 assert(pos - record_table + len < *record_size);
255 memcpy(pos, tlv, len);
256 pos += len;
257 count++;
258 }
259 tlv = (const struct pldm_fru_record_tlv *)((char *)tlv +
260 len);
261 }
262 record_data_dest->num_fru_fields = count;
263 record_data_src =
264 (const struct pldm_fru_record_data_format *)(tlv);
265 }
266
267 *record_size = pos - record_table;
268}
269
John Wang9fa87cf2020-06-10 17:53:40 +0800270int encode_get_fru_record_by_option_req(
271 uint8_t instance_id, uint32_t data_transfer_handle,
272 uint16_t fru_table_handle, uint16_t record_set_identifier,
273 uint8_t record_type, uint8_t field_type, uint8_t transfer_op_flag,
274 struct pldm_msg *msg, size_t payload_length)
275{
276
277 if (msg == NULL) {
278 return PLDM_ERROR_INVALID_DATA;
279 }
280
281 if (payload_length !=
282 sizeof(struct pldm_get_fru_record_by_option_req)) {
283 return PLDM_ERROR_INVALID_LENGTH;
284 }
285
286 struct pldm_header_info header = {0};
287 header.instance = instance_id;
288 header.msg_type = PLDM_REQUEST;
289 header.pldm_type = PLDM_FRU;
290 header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
291 int rc = pack_pldm_header(&header, &(msg->hdr));
292 if (rc != PLDM_SUCCESS) {
293 return rc;
294 }
295
296 struct pldm_get_fru_record_by_option_req *req =
297 (struct pldm_get_fru_record_by_option_req *)msg->payload;
298
299 req->data_transfer_handle = htole32(data_transfer_handle);
300 req->fru_table_handle = htole16(fru_table_handle);
301 req->record_set_identifier = htole16(record_set_identifier);
302 req->record_type = record_type;
303 req->field_type = field_type;
304 req->transfer_op_flag = transfer_op_flag;
305
306 return PLDM_SUCCESS;
307}
308
309int decode_get_fru_record_by_option_req(
310 const struct pldm_msg *msg, size_t payload_length,
311 uint32_t *data_transfer_handle, uint16_t *fru_table_handle,
312 uint16_t *record_set_identifier, uint8_t *record_type, uint8_t *field_type,
313 uint8_t *transfer_op_flag)
314{
315 if (msg == NULL || data_transfer_handle == NULL ||
316 fru_table_handle == NULL || record_set_identifier == NULL ||
317 record_type == NULL || field_type == NULL ||
318 transfer_op_flag == NULL) {
319 return PLDM_ERROR_INVALID_DATA;
320 }
321
322 if (payload_length !=
323 sizeof(struct pldm_get_fru_record_by_option_req)) {
324 return PLDM_ERROR_INVALID_LENGTH;
325 }
326
327 struct pldm_get_fru_record_by_option_req *req =
328 (struct pldm_get_fru_record_by_option_req *)msg->payload;
329
330 *data_transfer_handle = le32toh(req->data_transfer_handle);
331 *fru_table_handle = le16toh(req->fru_table_handle);
332 *record_set_identifier = le16toh(req->record_set_identifier);
333 *record_type = req->record_type;
334 *field_type = req->field_type;
335 *transfer_op_flag = req->transfer_op_flag;
336 return PLDM_SUCCESS;
337}
338
339int encode_get_fru_record_by_option_resp(uint8_t instance_id,
340 uint8_t completion_code,
341 uint32_t next_data_transfer_handle,
342 uint8_t transfer_flag,
343 const void *fru_structure_data,
344 size_t data_size, struct pldm_msg *msg,
345 size_t payload_length)
346{
347 if (msg == NULL || fru_structure_data == NULL) {
348 return PLDM_ERROR_INVALID_DATA;
349 }
350
351 if (payload_length < PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES) {
352 return PLDM_ERROR_INVALID_LENGTH;
353 }
354
355 struct pldm_header_info header = {0};
356 header.instance = instance_id;
357 header.msg_type = PLDM_RESPONSE;
358 header.pldm_type = PLDM_FRU;
359 header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
360 int rc = pack_pldm_header(&header, &(msg->hdr));
361 if (rc != PLDM_SUCCESS) {
362 return rc;
363 }
364
365 struct pldm_get_fru_record_by_option_resp *resp =
366 (struct pldm_get_fru_record_by_option_resp *)msg->payload;
367
368 resp->completion_code = completion_code;
369 resp->next_data_transfer_handle = htole32(next_data_transfer_handle);
370 resp->transfer_flag = transfer_flag;
371
372 if (completion_code != PLDM_SUCCESS) {
373 return PLDM_SUCCESS;
374 }
375
376 if (payload_length !=
377 PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES + data_size) {
378 return PLDM_ERROR_INVALID_LENGTH;
379 }
380
381 memcpy(resp->fru_structure_data, fru_structure_data, data_size);
382
383 return PLDM_SUCCESS;
384}
385
386int decode_get_fru_record_by_option_resp(
387 const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
388 uint32_t *next_transfer_handle, uint8_t *transfer_flag,
389 struct variable_field *fru_structure_data)
390{
391 if (msg == NULL || completion_code == NULL ||
392 next_transfer_handle == NULL || transfer_flag == NULL ||
393 fru_structure_data == NULL) {
394 return PLDM_ERROR_INVALID_DATA;
395 }
396
397 *completion_code = msg->payload[0];
398 if (PLDM_SUCCESS != *completion_code) {
399 return PLDM_SUCCESS;
400 }
401
402 if (payload_length < PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES) {
403 return PLDM_ERROR_INVALID_LENGTH;
404 }
405
406 struct pldm_get_fru_record_by_option_resp *resp =
407 (struct pldm_get_fru_record_by_option_resp *)msg->payload;
408
409 *next_transfer_handle = le32toh(resp->next_data_transfer_handle);
410 *transfer_flag = resp->transfer_flag;
411 fru_structure_data->ptr = resp->fru_structure_data;
412 fru_structure_data->length =
413 payload_length - PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES;
414
415 return PLDM_SUCCESS;
416}
417
PriyangaRamasamyf3295be2019-07-23 12:18:40 +0530418int encode_get_fru_record_table_req(uint8_t instance_id,
419 uint32_t data_transfer_handle,
420 uint8_t transfer_operation_flag,
421 struct pldm_msg *msg, size_t payload_length)
422
423{
424 struct pldm_header_info header = {0};
425 int rc = PLDM_ERROR_INVALID_DATA;
426
427 header.msg_type = PLDM_REQUEST;
428 header.instance = instance_id;
429 header.pldm_type = PLDM_FRU;
430 header.command = PLDM_GET_FRU_RECORD_TABLE;
431
432 if (msg == NULL) {
433 return rc;
434 }
435 if (payload_length != sizeof(struct pldm_get_fru_record_table_req)) {
436 return PLDM_ERROR_INVALID_LENGTH;
437 }
438 if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
439 return rc;
440 }
441
442 struct pldm_get_fru_record_table_req *req =
443 (struct pldm_get_fru_record_table_req *)msg->payload;
444 req->data_transfer_handle = htole32(data_transfer_handle);
445 req->transfer_operation_flag = transfer_operation_flag;
446
447 return PLDM_SUCCESS;
448}
449
450int decode_get_fru_record_table_resp(
451 const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
452 uint32_t *next_data_transfer_handle, uint8_t *transfer_flag,
453 uint8_t *fru_record_table_data, size_t *fru_record_table_length)
454{
455 if (msg == NULL || completion_code == NULL ||
456 next_data_transfer_handle == NULL || transfer_flag == NULL ||
457 fru_record_table_data == NULL || fru_record_table_length == NULL) {
458 return PLDM_ERROR_INVALID_DATA;
459 }
460
461 *completion_code = msg->payload[0];
462 if (PLDM_SUCCESS != *completion_code) {
463 return PLDM_SUCCESS;
464 }
465 if (payload_length <= PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES) {
466 return PLDM_ERROR_INVALID_LENGTH;
467 }
468
469 struct pldm_get_fru_record_table_resp *resp =
470 (struct pldm_get_fru_record_table_resp *)msg->payload;
471
472 *next_data_transfer_handle = le32toh(resp->next_data_transfer_handle);
473 *transfer_flag = resp->transfer_flag;
474 memcpy(fru_record_table_data, resp->fru_record_table_data,
475 payload_length - PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES);
476 *fru_record_table_length =
477 payload_length - PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES;
478
479 return PLDM_SUCCESS;
480}