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