blob: 9a5ae09d1138c2c59d021c752092708524e61275 [file] [log] [blame]
Andrew Jeffery9c766792022-08-10 23:12:49 +09301#include <endian.h>
2#include <string.h>
3
4#include "base.h"
5
6uint8_t pack_pldm_header(const struct pldm_header_info *hdr,
7 struct pldm_msg_hdr *msg)
8{
9 if (msg == NULL || hdr == NULL) {
10 return PLDM_ERROR_INVALID_DATA;
11 }
12
13 if (hdr->msg_type != PLDM_RESPONSE && hdr->msg_type != PLDM_REQUEST &&
14 hdr->msg_type != PLDM_ASYNC_REQUEST_NOTIFY) {
15 return PLDM_ERROR_INVALID_DATA;
16 }
17
18 if (hdr->instance > PLDM_INSTANCE_MAX) {
19 return PLDM_ERROR_INVALID_DATA;
20 }
21
22 if (hdr->pldm_type > (PLDM_MAX_TYPES - 1)) {
23 return PLDM_ERROR_INVALID_PLDM_TYPE;
24 }
25
26 uint8_t datagram = (hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) ? 1 : 0;
27
28 if (hdr->msg_type == PLDM_RESPONSE) {
29 msg->request = PLDM_RESPONSE;
30 } else if (hdr->msg_type == PLDM_REQUEST ||
31 hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) {
32 msg->request = PLDM_REQUEST;
33 }
34 msg->datagram = datagram;
35 msg->reserved = 0;
36 msg->instance_id = hdr->instance;
37 msg->header_ver = PLDM_CURRENT_VERSION;
38 msg->type = hdr->pldm_type;
39 msg->command = hdr->command;
40
41 return PLDM_SUCCESS;
42}
43
44uint8_t unpack_pldm_header(const struct pldm_msg_hdr *msg,
45 struct pldm_header_info *hdr)
46{
47 if (msg == NULL) {
48 return PLDM_ERROR_INVALID_DATA;
49 }
50
51 if (msg->request == PLDM_RESPONSE) {
52 hdr->msg_type = PLDM_RESPONSE;
53 } else {
54 hdr->msg_type =
55 msg->datagram ? PLDM_ASYNC_REQUEST_NOTIFY : PLDM_REQUEST;
56 }
57
58 hdr->instance = msg->instance_id;
59 hdr->pldm_type = msg->type;
60 hdr->command = msg->command;
61
62 return PLDM_SUCCESS;
63}
64
65int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg)
66{
67 if (msg == NULL) {
68 return PLDM_ERROR_INVALID_DATA;
69 }
70
71 struct pldm_header_info header = {0};
72 header.instance = instance_id;
73 header.msg_type = PLDM_REQUEST;
74 header.command = PLDM_GET_PLDM_TYPES;
75
76 return pack_pldm_header(&header, &(msg->hdr));
77}
78
79int encode_get_commands_req(uint8_t instance_id, uint8_t type, ver32_t version,
80 struct pldm_msg *msg)
81{
82 if (msg == NULL) {
83 return PLDM_ERROR_INVALID_DATA;
84 }
85
86 struct pldm_header_info header = {0};
87 header.instance = instance_id;
88 header.msg_type = PLDM_REQUEST;
89 header.command = PLDM_GET_PLDM_COMMANDS;
90
91 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
92 if (rc != PLDM_SUCCESS) {
93 return rc;
94 }
95
96 struct pldm_get_commands_req *request =
97 (struct pldm_get_commands_req *)msg->payload;
98
99 request->type = type;
100 request->version = version;
101
102 return PLDM_SUCCESS;
103}
104
105int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code,
106 const bitfield8_t *types, struct pldm_msg *msg)
107{
108 if (msg == NULL) {
109 return PLDM_ERROR_INVALID_DATA;
110 }
111
112 struct pldm_header_info header = {0};
113 header.instance = instance_id;
114 header.msg_type = PLDM_RESPONSE;
115 header.command = PLDM_GET_PLDM_TYPES;
116
117 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
118 if (rc != PLDM_SUCCESS) {
119 return rc;
120 }
121
122 struct pldm_get_types_resp *response =
123 (struct pldm_get_types_resp *)msg->payload;
124 response->completion_code = completion_code;
125 if (response->completion_code == PLDM_SUCCESS) {
126 if (types == NULL) {
127 return PLDM_ERROR_INVALID_DATA;
128 }
129 memcpy(response->types, &(types->byte), PLDM_MAX_TYPES / 8);
130 }
131
132 return PLDM_SUCCESS;
133}
134
135int decode_get_commands_req(const struct pldm_msg *msg, size_t payload_length,
136 uint8_t *type, ver32_t *version)
137{
138 if (msg == NULL || type == NULL || version == NULL) {
139 return PLDM_ERROR_INVALID_DATA;
140 }
141
142 if (payload_length != PLDM_GET_COMMANDS_REQ_BYTES) {
143 return PLDM_ERROR_INVALID_LENGTH;
144 }
145
146 struct pldm_get_commands_req *request =
147 (struct pldm_get_commands_req *)msg->payload;
148 *type = request->type;
149 *version = request->version;
150 return PLDM_SUCCESS;
151}
152
153int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code,
154 const bitfield8_t *commands, struct pldm_msg *msg)
155{
156 if (msg == NULL) {
157 return PLDM_ERROR_INVALID_DATA;
158 }
159
160 struct pldm_header_info header = {0};
161 header.instance = instance_id;
162 header.msg_type = PLDM_RESPONSE;
163 header.command = PLDM_GET_PLDM_COMMANDS;
164 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
165 if (rc != PLDM_SUCCESS) {
166 return rc;
167 }
168
169 struct pldm_get_commands_resp *response =
170 (struct pldm_get_commands_resp *)msg->payload;
171 response->completion_code = completion_code;
172 if (response->completion_code == PLDM_SUCCESS) {
173 if (commands == NULL) {
174 return PLDM_ERROR_INVALID_DATA;
175 }
176 memcpy(response->commands, &(commands->byte),
177 PLDM_MAX_CMDS_PER_TYPE / 8);
178 }
179
180 return PLDM_SUCCESS;
181}
182
183int decode_get_types_resp(const struct pldm_msg *msg, size_t payload_length,
184 uint8_t *completion_code, bitfield8_t *types)
185{
186 if (msg == NULL || types == NULL || completion_code == NULL) {
187 return PLDM_ERROR_INVALID_DATA;
188 }
189
190 *completion_code = msg->payload[0];
191 if (PLDM_SUCCESS != *completion_code) {
192 return PLDM_SUCCESS;
193 }
194
195 if (payload_length != PLDM_GET_TYPES_RESP_BYTES) {
196 return PLDM_ERROR_INVALID_LENGTH;
197 }
198
199 struct pldm_get_types_resp *response =
200 (struct pldm_get_types_resp *)msg->payload;
201
202 memcpy(&(types->byte), response->types, PLDM_MAX_TYPES / 8);
203
204 return PLDM_SUCCESS;
205}
206
207int decode_get_commands_resp(const struct pldm_msg *msg, size_t payload_length,
208 uint8_t *completion_code, bitfield8_t *commands)
209{
210 if (msg == NULL || commands == NULL || completion_code == NULL) {
211 return PLDM_ERROR_INVALID_DATA;
212 }
213
214 *completion_code = msg->payload[0];
215 if (PLDM_SUCCESS != *completion_code) {
216 return PLDM_SUCCESS;
217 }
218
219 if (payload_length != PLDM_GET_COMMANDS_RESP_BYTES) {
220 return PLDM_ERROR_INVALID_LENGTH;
221 }
222
223 struct pldm_get_commands_resp *response =
224 (struct pldm_get_commands_resp *)msg->payload;
225
226 memcpy(&(commands->byte), response->commands,
227 PLDM_MAX_CMDS_PER_TYPE / 8);
228
229 return PLDM_SUCCESS;
230}
231
232int encode_get_version_req(uint8_t instance_id, uint32_t transfer_handle,
233 uint8_t transfer_opflag, uint8_t type,
234 struct pldm_msg *msg)
235{
236 if (NULL == msg) {
237 return PLDM_ERROR_INVALID_DATA;
238 }
239
240 struct pldm_header_info header = {0};
241 header.msg_type = PLDM_REQUEST;
242 header.instance = instance_id;
243 header.pldm_type = PLDM_BASE;
244 header.command = PLDM_GET_PLDM_VERSION;
245
246 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
247 if (rc != PLDM_SUCCESS) {
248 return rc;
249 }
250
251 struct pldm_get_version_req *request =
252 (struct pldm_get_version_req *)msg->payload;
253 transfer_handle = htole32(transfer_handle);
254 request->transfer_handle = transfer_handle;
255 request->transfer_opflag = transfer_opflag;
256 request->type = type;
257
258 return PLDM_SUCCESS;
259}
260
261int encode_get_version_resp(uint8_t instance_id, uint8_t completion_code,
262 uint32_t next_transfer_handle,
263 uint8_t transfer_flag, const ver32_t *version_data,
264 size_t version_size, struct pldm_msg *msg)
265{
266 if (NULL == msg) {
267 return PLDM_ERROR_INVALID_DATA;
268 }
269
270 struct pldm_header_info header = {0};
271 header.msg_type = PLDM_RESPONSE;
272 header.instance = instance_id;
273 header.pldm_type = PLDM_BASE;
274 header.command = PLDM_GET_PLDM_VERSION;
275
276 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
277 if (rc != PLDM_SUCCESS) {
278 return rc;
279 }
280
281 struct pldm_get_version_resp *response =
282 (struct pldm_get_version_resp *)msg->payload;
283 response->completion_code = completion_code;
284 if (response->completion_code == PLDM_SUCCESS) {
285 response->next_transfer_handle = htole32(next_transfer_handle);
286 response->transfer_flag = transfer_flag;
287 memcpy(response->version_data, (uint8_t *)version_data,
288 version_size);
289 }
290 return PLDM_SUCCESS;
291}
292
293int decode_get_version_req(const struct pldm_msg *msg, size_t payload_length,
294 uint32_t *transfer_handle, uint8_t *transfer_opflag,
295 uint8_t *type)
296{
297
298 if (payload_length != PLDM_GET_VERSION_REQ_BYTES) {
299 return PLDM_ERROR_INVALID_LENGTH;
300 }
301
302 struct pldm_get_version_req *request =
303 (struct pldm_get_version_req *)msg->payload;
304 *transfer_handle = le32toh(request->transfer_handle);
305 *transfer_opflag = request->transfer_opflag;
306 *type = request->type;
307 return PLDM_SUCCESS;
308}
309
310int decode_get_version_resp(const struct pldm_msg *msg, size_t payload_length,
311 uint8_t *completion_code,
312 uint32_t *next_transfer_handle,
313 uint8_t *transfer_flag, ver32_t *version)
314{
315 if (msg == NULL || next_transfer_handle == NULL ||
316 transfer_flag == NULL || completion_code == NULL) {
317 return PLDM_ERROR_INVALID_DATA;
318 }
319
320 *completion_code = msg->payload[0];
321 if (PLDM_SUCCESS != *completion_code) {
322 return PLDM_SUCCESS;
323 }
324
325 if (payload_length < PLDM_GET_VERSION_RESP_BYTES) {
326 return PLDM_ERROR_INVALID_LENGTH;
327 }
328
329 struct pldm_get_version_resp *response =
330 (struct pldm_get_version_resp *)msg->payload;
331
332 *next_transfer_handle = le32toh(response->next_transfer_handle);
333 *transfer_flag = response->transfer_flag;
334 memcpy(version, (uint8_t *)response->version_data, sizeof(ver32_t));
335
336 return PLDM_SUCCESS;
337}
338
339int encode_get_tid_req(uint8_t instance_id, struct pldm_msg *msg)
340{
341 if (msg == NULL) {
342 return PLDM_ERROR_INVALID_DATA;
343 }
344
345 struct pldm_header_info header = {0};
346 header.instance = instance_id;
347 header.msg_type = PLDM_REQUEST;
348 header.command = PLDM_GET_TID;
349
350 return pack_pldm_header(&header, &(msg->hdr));
351}
352int encode_get_tid_resp(uint8_t instance_id, uint8_t completion_code,
353 uint8_t tid, struct pldm_msg *msg)
354{
355 if (msg == NULL) {
356 return PLDM_ERROR_INVALID_DATA;
357 }
358
359 struct pldm_header_info header = {0};
360 header.instance = instance_id;
361 header.msg_type = PLDM_RESPONSE;
362 header.command = PLDM_GET_TID;
363
364 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
365 if (rc != PLDM_SUCCESS) {
366 return rc;
367 }
368
369 struct pldm_get_tid_resp *response =
370 (struct pldm_get_tid_resp *)msg->payload;
371 response->completion_code = completion_code;
372 response->tid = tid;
373
374 return PLDM_SUCCESS;
375}
376
377int decode_get_tid_resp(const struct pldm_msg *msg, size_t payload_length,
378 uint8_t *completion_code, uint8_t *tid)
379{
380 if (msg == NULL || tid == NULL || completion_code == NULL) {
381 return PLDM_ERROR_INVALID_DATA;
382 }
383
384 *completion_code = msg->payload[0];
385 if (PLDM_SUCCESS != *completion_code) {
386 return PLDM_SUCCESS;
387 }
388
389 if (payload_length != PLDM_GET_TID_RESP_BYTES) {
390 return PLDM_ERROR_INVALID_LENGTH;
391 }
392
393 struct pldm_get_tid_resp *response =
394 (struct pldm_get_tid_resp *)msg->payload;
395
396 *tid = response->tid;
397
398 return PLDM_SUCCESS;
399}
400
401int decode_multipart_receive_req(
402 const struct pldm_msg *msg, size_t payload_length, uint8_t *pldm_type,
403 uint8_t *transfer_opflag, uint32_t *transfer_ctx, uint32_t *transfer_handle,
404 uint32_t *section_offset, uint32_t *section_length)
405{
406 if (msg == NULL || pldm_type == NULL || transfer_opflag == NULL ||
407 transfer_ctx == NULL || transfer_handle == NULL ||
408 section_offset == NULL || section_length == NULL) {
409 return PLDM_ERROR_INVALID_DATA;
410 }
411
412 if (payload_length != PLDM_MULTIPART_RECEIVE_REQ_BYTES) {
413 return PLDM_ERROR_INVALID_LENGTH;
414 }
415
416 struct pldm_multipart_receive_req *request =
417 (struct pldm_multipart_receive_req *)msg->payload;
418
419 if (request->pldm_type != PLDM_BASE) {
420 return PLDM_ERROR_INVALID_PLDM_TYPE;
421 }
422
423 // Any enum value above PLDM_XFER_CURRENT_PART is invalid.
424 if (request->transfer_opflag > PLDM_XFER_CURRENT_PART) {
425 return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
426 }
427
428 // A section offset of 0 is only valid on FIRST_PART or COMPLETE Xfers.
429 uint32_t sec_offset = le32toh(request->section_offset);
430 if (sec_offset == 0 &&
431 (request->transfer_opflag != PLDM_XFER_FIRST_PART &&
432 request->transfer_opflag != PLDM_XFER_COMPLETE)) {
433 return PLDM_ERROR_INVALID_DATA;
434 }
435
436 uint32_t handle = le32toh(request->transfer_handle);
437 if (handle == 0 && request->transfer_opflag != PLDM_XFER_COMPLETE) {
438 return PLDM_ERROR_INVALID_DATA;
439 }
440
441 *pldm_type = request->pldm_type;
442 *transfer_opflag = request->transfer_opflag;
443 *transfer_ctx = request->transfer_ctx;
444 *transfer_handle = handle;
445 *section_offset = sec_offset;
446 *section_length = le32toh(request->section_length);
447
448 return PLDM_SUCCESS;
449}
450
451int encode_cc_only_resp(uint8_t instance_id, uint8_t type, uint8_t command,
452 uint8_t cc, struct pldm_msg *msg)
453{
454 if (msg == NULL) {
455 return PLDM_ERROR_INVALID_DATA;
456 }
457
458 struct pldm_header_info header = {0};
459 header.instance = instance_id;
460 header.msg_type = PLDM_RESPONSE;
461 header.pldm_type = type;
462 header.command = command;
463
464 uint8_t rc = pack_pldm_header(&header, &msg->hdr);
465 if (rc != PLDM_SUCCESS) {
466 return rc;
467 }
468
469 msg->payload[0] = cc;
470
471 return PLDM_SUCCESS;
472}
473
474int encode_pldm_header_only(uint8_t msg_type, uint8_t instance_id,
475 uint8_t pldm_type, uint8_t command,
476 struct pldm_msg *msg)
477{
478 if (msg == NULL) {
479 return PLDM_ERROR_INVALID_DATA;
480 }
481
482 struct pldm_header_info header = {0};
483 header.msg_type = msg_type;
484 header.instance = instance_id;
485 header.pldm_type = pldm_type;
486 header.command = command;
487 return pack_pldm_header(&header, &(msg->hdr));
488}