blob: 207d4dee28f3fd87f030de694d60d5e7fff712d1 [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
180 if ((*curr_size + record_hdr_size + tlvs_size) != total_size) {
181 return PLDM_ERROR_INVALID_LENGTH;
182 }
183
184 if (fru_table == NULL || curr_size == NULL || !tlvs_size) {
185 return PLDM_ERROR_INVALID_DATA;
186 }
187
188 struct pldm_fru_record_data_format *record =
189 (struct pldm_fru_record_data_format *)(fru_table + *curr_size);
190 record->record_set_id = htole16(record_set_id);
191 record->record_type = record_type;
192 record->num_fru_fields = num_frus;
193 record->encoding_type = encoding;
194 *curr_size += record_hdr_size;
195
196 if (tlvs) {
197 memcpy(fru_table + *curr_size, tlvs, tlvs_size);
198 *curr_size += tlvs_size;
199 }
200
201 return PLDM_SUCCESS;
202}
PriyangaRamasamyf3295be2019-07-23 12:18:40 +0530203
John Wang9e82ad12020-06-12 10:53:32 +0800204static bool is_table_end(const struct pldm_fru_record_data_format *p,
205 const void *table, size_t table_size)
206{
207 return p ==
208 (const struct pldm_fru_record_data_format *)((uint8_t *)table +
209 table_size);
210}
211
212void get_fru_record_by_option(const uint8_t *table, size_t table_size,
213 uint8_t *record_table, size_t *record_size,
214 uint16_t rsi, uint8_t rt, uint8_t ft)
215{
216 const struct pldm_fru_record_data_format *record_data_src =
217 (const struct pldm_fru_record_data_format *)table;
218 struct pldm_fru_record_data_format *record_data_dest;
219 int count = 0;
220
221 const struct pldm_fru_record_tlv *tlv;
222 size_t len;
223 uint8_t *pos = record_table;
224
225 while (!is_table_end(record_data_src, table, table_size)) {
226 if ((record_data_src->record_set_id != htole16(rsi) &&
227 rsi != 0) ||
228 (record_data_src->record_type != rt && rt != 0)) {
229 tlv = record_data_src->tlvs;
230 for (int i = 0; i < record_data_src->num_fru_fields;
231 i++) {
232 len = sizeof(*tlv) - 1 + tlv->length;
233 tlv = (const struct pldm_fru_record_tlv
234 *)((char *)tlv + len);
235 }
236 record_data_src =
237 (const struct pldm_fru_record_data_format *)(tlv);
238 continue;
239 }
240
241 len = sizeof(struct pldm_fru_record_data_format) -
242 sizeof(struct pldm_fru_record_tlv);
243
244 assert(pos - record_table + len < *record_size);
245 memcpy(pos, record_data_src, len);
246
247 record_data_dest = (struct pldm_fru_record_data_format *)pos;
248 pos += len;
249
250 tlv = record_data_src->tlvs;
251 count = 0;
252 for (int i = 0; i < record_data_src->num_fru_fields; i++) {
253 len = sizeof(*tlv) - 1 + tlv->length;
254 if (tlv->type == ft || ft == 0) {
255 assert(pos - record_table + len < *record_size);
256 memcpy(pos, tlv, len);
257 pos += len;
258 count++;
259 }
260 tlv = (const struct pldm_fru_record_tlv *)((char *)tlv +
261 len);
262 }
263 record_data_dest->num_fru_fields = count;
264 record_data_src =
265 (const struct pldm_fru_record_data_format *)(tlv);
266 }
267
268 *record_size = pos - record_table;
269}
270
John Wang9fa87cf2020-06-10 17:53:40 +0800271int encode_get_fru_record_by_option_req(
272 uint8_t instance_id, uint32_t data_transfer_handle,
273 uint16_t fru_table_handle, uint16_t record_set_identifier,
274 uint8_t record_type, uint8_t field_type, uint8_t transfer_op_flag,
275 struct pldm_msg *msg, size_t payload_length)
276{
277
278 if (msg == NULL) {
279 return PLDM_ERROR_INVALID_DATA;
280 }
281
282 if (payload_length !=
283 sizeof(struct pldm_get_fru_record_by_option_req)) {
284 return PLDM_ERROR_INVALID_LENGTH;
285 }
286
287 struct pldm_header_info header = {0};
288 header.instance = instance_id;
289 header.msg_type = PLDM_REQUEST;
290 header.pldm_type = PLDM_FRU;
291 header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
292 int rc = pack_pldm_header(&header, &(msg->hdr));
293 if (rc != PLDM_SUCCESS) {
294 return rc;
295 }
296
297 struct pldm_get_fru_record_by_option_req *req =
298 (struct pldm_get_fru_record_by_option_req *)msg->payload;
299
300 req->data_transfer_handle = htole32(data_transfer_handle);
301 req->fru_table_handle = htole16(fru_table_handle);
302 req->record_set_identifier = htole16(record_set_identifier);
303 req->record_type = record_type;
304 req->field_type = field_type;
305 req->transfer_op_flag = transfer_op_flag;
306
307 return PLDM_SUCCESS;
308}
309
310int decode_get_fru_record_by_option_req(
311 const struct pldm_msg *msg, size_t payload_length,
312 uint32_t *data_transfer_handle, uint16_t *fru_table_handle,
313 uint16_t *record_set_identifier, uint8_t *record_type, uint8_t *field_type,
314 uint8_t *transfer_op_flag)
315{
316 if (msg == NULL || data_transfer_handle == NULL ||
317 fru_table_handle == NULL || record_set_identifier == NULL ||
318 record_type == NULL || field_type == NULL ||
319 transfer_op_flag == NULL) {
320 return PLDM_ERROR_INVALID_DATA;
321 }
322
323 if (payload_length !=
324 sizeof(struct pldm_get_fru_record_by_option_req)) {
325 return PLDM_ERROR_INVALID_LENGTH;
326 }
327
328 struct pldm_get_fru_record_by_option_req *req =
329 (struct pldm_get_fru_record_by_option_req *)msg->payload;
330
331 *data_transfer_handle = le32toh(req->data_transfer_handle);
332 *fru_table_handle = le16toh(req->fru_table_handle);
333 *record_set_identifier = le16toh(req->record_set_identifier);
334 *record_type = req->record_type;
335 *field_type = req->field_type;
336 *transfer_op_flag = req->transfer_op_flag;
337 return PLDM_SUCCESS;
338}
339
340int encode_get_fru_record_by_option_resp(uint8_t instance_id,
341 uint8_t completion_code,
342 uint32_t next_data_transfer_handle,
343 uint8_t transfer_flag,
344 const void *fru_structure_data,
345 size_t data_size, struct pldm_msg *msg,
346 size_t payload_length)
347{
348 if (msg == NULL || fru_structure_data == NULL) {
349 return PLDM_ERROR_INVALID_DATA;
350 }
351
352 if (payload_length < PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES) {
353 return PLDM_ERROR_INVALID_LENGTH;
354 }
355
356 struct pldm_header_info header = {0};
357 header.instance = instance_id;
358 header.msg_type = PLDM_RESPONSE;
359 header.pldm_type = PLDM_FRU;
360 header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
361 int rc = pack_pldm_header(&header, &(msg->hdr));
362 if (rc != PLDM_SUCCESS) {
363 return rc;
364 }
365
366 struct pldm_get_fru_record_by_option_resp *resp =
367 (struct pldm_get_fru_record_by_option_resp *)msg->payload;
368
369 resp->completion_code = completion_code;
370 resp->next_data_transfer_handle = htole32(next_data_transfer_handle);
371 resp->transfer_flag = transfer_flag;
372
373 if (completion_code != PLDM_SUCCESS) {
374 return PLDM_SUCCESS;
375 }
376
377 if (payload_length !=
378 PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES + data_size) {
379 return PLDM_ERROR_INVALID_LENGTH;
380 }
381
382 memcpy(resp->fru_structure_data, fru_structure_data, data_size);
383
384 return PLDM_SUCCESS;
385}
386
387int decode_get_fru_record_by_option_resp(
388 const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
389 uint32_t *next_transfer_handle, uint8_t *transfer_flag,
390 struct variable_field *fru_structure_data)
391{
392 if (msg == NULL || completion_code == NULL ||
393 next_transfer_handle == NULL || transfer_flag == NULL ||
394 fru_structure_data == NULL) {
395 return PLDM_ERROR_INVALID_DATA;
396 }
397
398 *completion_code = msg->payload[0];
399 if (PLDM_SUCCESS != *completion_code) {
400 return PLDM_SUCCESS;
401 }
402
403 if (payload_length < PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES) {
404 return PLDM_ERROR_INVALID_LENGTH;
405 }
406
407 struct pldm_get_fru_record_by_option_resp *resp =
408 (struct pldm_get_fru_record_by_option_resp *)msg->payload;
409
410 *next_transfer_handle = le32toh(resp->next_data_transfer_handle);
411 *transfer_flag = resp->transfer_flag;
412 fru_structure_data->ptr = resp->fru_structure_data;
413 fru_structure_data->length =
414 payload_length - PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES;
415
416 return PLDM_SUCCESS;
417}
418
PriyangaRamasamyf3295be2019-07-23 12:18:40 +0530419int encode_get_fru_record_table_req(uint8_t instance_id,
420 uint32_t data_transfer_handle,
421 uint8_t transfer_operation_flag,
422 struct pldm_msg *msg, size_t payload_length)
423
424{
425 struct pldm_header_info header = {0};
426 int rc = PLDM_ERROR_INVALID_DATA;
427
428 header.msg_type = PLDM_REQUEST;
429 header.instance = instance_id;
430 header.pldm_type = PLDM_FRU;
431 header.command = PLDM_GET_FRU_RECORD_TABLE;
432
433 if (msg == NULL) {
434 return rc;
435 }
436 if (payload_length != sizeof(struct pldm_get_fru_record_table_req)) {
437 return PLDM_ERROR_INVALID_LENGTH;
438 }
439 if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
440 return rc;
441 }
442
443 struct pldm_get_fru_record_table_req *req =
444 (struct pldm_get_fru_record_table_req *)msg->payload;
445 req->data_transfer_handle = htole32(data_transfer_handle);
446 req->transfer_operation_flag = transfer_operation_flag;
447
448 return PLDM_SUCCESS;
449}
450
451int decode_get_fru_record_table_resp(
452 const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
453 uint32_t *next_data_transfer_handle, uint8_t *transfer_flag,
454 uint8_t *fru_record_table_data, size_t *fru_record_table_length)
455{
456 if (msg == NULL || completion_code == NULL ||
457 next_data_transfer_handle == NULL || transfer_flag == NULL ||
458 fru_record_table_data == NULL || fru_record_table_length == NULL) {
459 return PLDM_ERROR_INVALID_DATA;
460 }
461
462 *completion_code = msg->payload[0];
463 if (PLDM_SUCCESS != *completion_code) {
464 return PLDM_SUCCESS;
465 }
466 if (payload_length <= PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES) {
467 return PLDM_ERROR_INVALID_LENGTH;
468 }
469
470 struct pldm_get_fru_record_table_resp *resp =
471 (struct pldm_get_fru_record_table_resp *)msg->payload;
472
473 *next_data_transfer_handle = le32toh(resp->next_data_transfer_handle);
474 *transfer_flag = resp->transfer_flag;
475 memcpy(fru_record_table_data, resp->fru_record_table_data,
476 payload_length - PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES);
477 *fru_record_table_length =
478 payload_length - PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES;
479
480 return PLDM_SUCCESS;
481}