xref: /openbmc/libpldm/src/transport/test.c (revision 2b440d4cd04a5b0a47d91e00fa0db85930bedbfc)
1*691668feSPatrick Williams /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2dc1edacfSAndrew Jeffery /* NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */
3dc1edacfSAndrew Jeffery #include "array.h"
49a6ba89cSAndrew Jeffery #include "container-of.h"
59a6ba89cSAndrew Jeffery #include "transport.h"
69a6ba89cSAndrew Jeffery #include "test.h"
79a6ba89cSAndrew Jeffery 
89a6ba89cSAndrew Jeffery #include <errno.h>
9dc1edacfSAndrew Jeffery #include <poll.h>
109a6ba89cSAndrew Jeffery #include <stdlib.h>
119a6ba89cSAndrew Jeffery #include <string.h>
129a6ba89cSAndrew Jeffery #include <unistd.h>
139a6ba89cSAndrew Jeffery 
149a6ba89cSAndrew Jeffery struct pldm_transport_test {
159a6ba89cSAndrew Jeffery 	struct pldm_transport transport;
169a6ba89cSAndrew Jeffery 	const struct pldm_transport_test_descriptor *seq;
179a6ba89cSAndrew Jeffery 	size_t count;
189a6ba89cSAndrew Jeffery 	size_t cursor;
199a6ba89cSAndrew Jeffery 	int timerfd;
209a6ba89cSAndrew Jeffery };
219a6ba89cSAndrew Jeffery 
229a6ba89cSAndrew Jeffery #define transport_to_test(ptr)                                                 \
239a6ba89cSAndrew Jeffery 	container_of(ptr, struct pldm_transport_test, transport)
249a6ba89cSAndrew Jeffery 
259a6ba89cSAndrew Jeffery LIBPLDM_ABI_TESTING
pldm_transport_test_core(struct pldm_transport_test * ctx)269a6ba89cSAndrew Jeffery struct pldm_transport *pldm_transport_test_core(struct pldm_transport_test *ctx)
279a6ba89cSAndrew Jeffery {
289a6ba89cSAndrew Jeffery 	return &ctx->transport;
299a6ba89cSAndrew Jeffery }
309a6ba89cSAndrew Jeffery 
319a6ba89cSAndrew Jeffery #ifdef PLDM_HAS_POLL
329a6ba89cSAndrew Jeffery #include <poll.h>
339a6ba89cSAndrew Jeffery LIBPLDM_ABI_TESTING
pldm_transport_test_init_pollfd(struct pldm_transport * ctx,struct pollfd * pollfd)349a6ba89cSAndrew Jeffery int pldm_transport_test_init_pollfd(struct pldm_transport *ctx,
359a6ba89cSAndrew Jeffery 				    struct pollfd *pollfd)
369a6ba89cSAndrew Jeffery {
379a6ba89cSAndrew Jeffery 	static const struct itimerspec disable = {
389a6ba89cSAndrew Jeffery 		.it_value = { 0, 0 },
399a6ba89cSAndrew Jeffery 		.it_interval = { 0, 0 },
409a6ba89cSAndrew Jeffery 	};
419a6ba89cSAndrew Jeffery 	struct pldm_transport_test *test = transport_to_test(ctx);
429a6ba89cSAndrew Jeffery 	const struct pldm_transport_test_descriptor *desc;
439a6ba89cSAndrew Jeffery 	int rc;
449a6ba89cSAndrew Jeffery 
459a6ba89cSAndrew Jeffery 	rc = timerfd_settime(test->timerfd, 0, &disable, NULL);
469a6ba89cSAndrew Jeffery 	if (rc < 0) {
479a6ba89cSAndrew Jeffery 		return PLDM_REQUESTER_POLL_FAIL;
489a6ba89cSAndrew Jeffery 	}
499a6ba89cSAndrew Jeffery 
509a6ba89cSAndrew Jeffery 	if (test->cursor >= test->count) {
519a6ba89cSAndrew Jeffery 		return PLDM_REQUESTER_POLL_FAIL;
529a6ba89cSAndrew Jeffery 	}
539a6ba89cSAndrew Jeffery 
549a6ba89cSAndrew Jeffery 	desc = &test->seq[test->cursor];
559a6ba89cSAndrew Jeffery 
56f56e4dcdSThu Nguyen 	if (desc->type == PLDM_TRANSPORT_TEST_ELEMENT_LATENCY) {
579a6ba89cSAndrew Jeffery 		rc = timerfd_settime(test->timerfd, 0, &desc->latency, NULL);
589a6ba89cSAndrew Jeffery 		if (rc < 0) {
599a6ba89cSAndrew Jeffery 			return PLDM_REQUESTER_POLL_FAIL;
609a6ba89cSAndrew Jeffery 		}
619a6ba89cSAndrew Jeffery 
62f56e4dcdSThu Nguyen 		/* This was an explicit latency element, so now move beyond it for recv */
63f56e4dcdSThu Nguyen 		test->cursor++;
64f56e4dcdSThu Nguyen 	} else if (desc->type == PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV) {
65f56e4dcdSThu Nguyen 		/* Expire the timer immediately so it appears ready */
66dc1edacfSAndrew Jeffery 		static const struct timespec ensure_ready = {
67dc1edacfSAndrew Jeffery 			.tv_sec = 0,
68dc1edacfSAndrew Jeffery 			.tv_nsec = 2,
69dc1edacfSAndrew Jeffery 		};
70f56e4dcdSThu Nguyen 		static const struct itimerspec ready = {
71f56e4dcdSThu Nguyen 			.it_value = { 0, 1 },
72f56e4dcdSThu Nguyen 			.it_interval = { 0, 0 },
73f56e4dcdSThu Nguyen 		};
74dc1edacfSAndrew Jeffery 		struct pollfd pfds[] = {
75dc1edacfSAndrew Jeffery 			{ .fd = test->timerfd, .events = POLLIN },
76dc1edacfSAndrew Jeffery 		};
77dc1edacfSAndrew Jeffery 
78f56e4dcdSThu Nguyen 		rc = timerfd_settime(test->timerfd, 0, &ready, NULL);
79f56e4dcdSThu Nguyen 		if (rc < 0) {
80f56e4dcdSThu Nguyen 			return PLDM_REQUESTER_POLL_FAIL;
81f56e4dcdSThu Nguyen 		}
82f56e4dcdSThu Nguyen 
83dc1edacfSAndrew Jeffery 		rc = ppoll(pfds, ARRAY_SIZE(pfds), &ensure_ready, NULL);
84dc1edacfSAndrew Jeffery 		if (rc < 1) {
85dc1edacfSAndrew Jeffery 			return PLDM_REQUESTER_POLL_FAIL;
86dc1edacfSAndrew Jeffery 		}
87dc1edacfSAndrew Jeffery 
88f56e4dcdSThu Nguyen 		/* Don't increment test->cursor as recv needs to consume the current test element */
89f56e4dcdSThu Nguyen 	} else {
90f56e4dcdSThu Nguyen 		return PLDM_REQUESTER_POLL_FAIL;
91f56e4dcdSThu Nguyen 	}
92f56e4dcdSThu Nguyen 
939a6ba89cSAndrew Jeffery 	pollfd->fd = test->timerfd;
949a6ba89cSAndrew Jeffery 	pollfd->events = POLLIN;
959a6ba89cSAndrew Jeffery 
969a6ba89cSAndrew Jeffery 	return 0;
979a6ba89cSAndrew Jeffery }
989a6ba89cSAndrew Jeffery #endif
999a6ba89cSAndrew Jeffery 
pldm_transport_test_recv(struct pldm_transport * ctx,pldm_tid_t * tid,void ** pldm_resp_msg,size_t * resp_msg_len)1009a6ba89cSAndrew Jeffery static pldm_requester_rc_t pldm_transport_test_recv(struct pldm_transport *ctx,
10124576290SRashmica Gupta 						    pldm_tid_t *tid,
1029a6ba89cSAndrew Jeffery 						    void **pldm_resp_msg,
1039a6ba89cSAndrew Jeffery 						    size_t *resp_msg_len)
1049a6ba89cSAndrew Jeffery {
1059a6ba89cSAndrew Jeffery 	struct pldm_transport_test *test = transport_to_test(ctx);
1069a6ba89cSAndrew Jeffery 	const struct pldm_transport_test_descriptor *desc;
1079a6ba89cSAndrew Jeffery 	void *msg;
1089a6ba89cSAndrew Jeffery 
1099a6ba89cSAndrew Jeffery 	if (test->cursor >= test->count) {
1109a6ba89cSAndrew Jeffery 		return PLDM_REQUESTER_RECV_FAIL;
1119a6ba89cSAndrew Jeffery 	}
1129a6ba89cSAndrew Jeffery 
1139a6ba89cSAndrew Jeffery 	desc = &test->seq[test->cursor];
1149a6ba89cSAndrew Jeffery 
1159a6ba89cSAndrew Jeffery 	if (desc->type != PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV) {
1169a6ba89cSAndrew Jeffery 		return PLDM_REQUESTER_RECV_FAIL;
1179a6ba89cSAndrew Jeffery 	}
1189a6ba89cSAndrew Jeffery 
1199a6ba89cSAndrew Jeffery 	msg = malloc(desc->recv_msg.len);
1209a6ba89cSAndrew Jeffery 	if (!msg) {
1219a6ba89cSAndrew Jeffery 		return PLDM_REQUESTER_RECV_FAIL;
1229a6ba89cSAndrew Jeffery 	}
1239a6ba89cSAndrew Jeffery 
1249a6ba89cSAndrew Jeffery 	memcpy(msg, desc->recv_msg.msg, desc->recv_msg.len);
1259a6ba89cSAndrew Jeffery 	*pldm_resp_msg = msg;
1269a6ba89cSAndrew Jeffery 	*resp_msg_len = desc->recv_msg.len;
12724576290SRashmica Gupta 	*tid = desc->recv_msg.src;
1289a6ba89cSAndrew Jeffery 
1299a6ba89cSAndrew Jeffery 	test->cursor++;
1309a6ba89cSAndrew Jeffery 
1319a6ba89cSAndrew Jeffery 	return PLDM_REQUESTER_SUCCESS;
1329a6ba89cSAndrew Jeffery }
1339a6ba89cSAndrew Jeffery 
pldm_transport_test_send(struct pldm_transport * ctx,pldm_tid_t tid,const void * pldm_req_msg,size_t req_msg_len)1349a6ba89cSAndrew Jeffery static pldm_requester_rc_t pldm_transport_test_send(struct pldm_transport *ctx,
1359a6ba89cSAndrew Jeffery 						    pldm_tid_t tid,
1369a6ba89cSAndrew Jeffery 						    const void *pldm_req_msg,
1379a6ba89cSAndrew Jeffery 						    size_t req_msg_len)
1389a6ba89cSAndrew Jeffery {
1399a6ba89cSAndrew Jeffery 	struct pldm_transport_test *test = transport_to_test(ctx);
1409a6ba89cSAndrew Jeffery 	const struct pldm_transport_test_descriptor *desc;
1419a6ba89cSAndrew Jeffery 
1429a6ba89cSAndrew Jeffery 	if (test->cursor > test->count) {
1439a6ba89cSAndrew Jeffery 		return PLDM_REQUESTER_SEND_FAIL;
1449a6ba89cSAndrew Jeffery 	}
1459a6ba89cSAndrew Jeffery 
1469a6ba89cSAndrew Jeffery 	desc = &test->seq[test->cursor];
1479a6ba89cSAndrew Jeffery 
1489a6ba89cSAndrew Jeffery 	if (desc->type != PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND) {
1499a6ba89cSAndrew Jeffery 		return PLDM_REQUESTER_SEND_FAIL;
1509a6ba89cSAndrew Jeffery 	}
1519a6ba89cSAndrew Jeffery 
1529a6ba89cSAndrew Jeffery 	if (desc->send_msg.dst != tid) {
1539a6ba89cSAndrew Jeffery 		return PLDM_REQUESTER_SEND_FAIL;
1549a6ba89cSAndrew Jeffery 	}
1559a6ba89cSAndrew Jeffery 
1569a6ba89cSAndrew Jeffery 	if (desc->send_msg.len != req_msg_len) {
1579a6ba89cSAndrew Jeffery 		return PLDM_REQUESTER_SEND_FAIL;
1589a6ba89cSAndrew Jeffery 	}
1599a6ba89cSAndrew Jeffery 
1609a6ba89cSAndrew Jeffery 	if (memcmp(desc->send_msg.msg, pldm_req_msg, req_msg_len) != 0) {
1619a6ba89cSAndrew Jeffery 		return PLDM_REQUESTER_SEND_FAIL;
1629a6ba89cSAndrew Jeffery 	}
1639a6ba89cSAndrew Jeffery 
1649a6ba89cSAndrew Jeffery 	test->cursor++;
1659a6ba89cSAndrew Jeffery 
1669a6ba89cSAndrew Jeffery 	return PLDM_REQUESTER_SUCCESS;
1679a6ba89cSAndrew Jeffery }
1689a6ba89cSAndrew Jeffery 
1699a6ba89cSAndrew Jeffery LIBPLDM_ABI_TESTING
pldm_transport_test_init(struct pldm_transport_test ** ctx,const struct pldm_transport_test_descriptor * seq,size_t count)1709a6ba89cSAndrew Jeffery int pldm_transport_test_init(struct pldm_transport_test **ctx,
1719a6ba89cSAndrew Jeffery 			     const struct pldm_transport_test_descriptor *seq,
1729a6ba89cSAndrew Jeffery 			     size_t count)
1739a6ba89cSAndrew Jeffery {
1749a6ba89cSAndrew Jeffery 	int rc;
1759a6ba89cSAndrew Jeffery 
1769a6ba89cSAndrew Jeffery 	if (!ctx || *ctx) {
1779a6ba89cSAndrew Jeffery 		return -EINVAL;
1789a6ba89cSAndrew Jeffery 	}
1799a6ba89cSAndrew Jeffery 
1809a6ba89cSAndrew Jeffery 	struct pldm_transport_test *test = malloc(sizeof(*test));
1819a6ba89cSAndrew Jeffery 	if (!test) {
1829a6ba89cSAndrew Jeffery 		return -ENOMEM;
1839a6ba89cSAndrew Jeffery 	}
1849a6ba89cSAndrew Jeffery 
1859a6ba89cSAndrew Jeffery 	test->transport.name = "TEST";
1869a6ba89cSAndrew Jeffery 	test->transport.version = 1;
1879a6ba89cSAndrew Jeffery 	test->transport.recv = pldm_transport_test_recv;
1889a6ba89cSAndrew Jeffery 	test->transport.send = pldm_transport_test_send;
1899a6ba89cSAndrew Jeffery 	test->transport.init_pollfd = pldm_transport_test_init_pollfd;
1909a6ba89cSAndrew Jeffery 	test->seq = seq;
1919a6ba89cSAndrew Jeffery 	test->count = count;
1929a6ba89cSAndrew Jeffery 	test->cursor = 0;
1939a6ba89cSAndrew Jeffery 	test->timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
1949a6ba89cSAndrew Jeffery 	if (test->timerfd < 0) {
1959a6ba89cSAndrew Jeffery 		rc = -errno;
1969a6ba89cSAndrew Jeffery 		goto cleanup_test;
1979a6ba89cSAndrew Jeffery 	}
1989a6ba89cSAndrew Jeffery 
1999a6ba89cSAndrew Jeffery 	*ctx = test;
2009a6ba89cSAndrew Jeffery 
2019a6ba89cSAndrew Jeffery 	return 0;
2029a6ba89cSAndrew Jeffery 
2039a6ba89cSAndrew Jeffery cleanup_test:
2049a6ba89cSAndrew Jeffery 	free(test);
2059a6ba89cSAndrew Jeffery 	return rc;
2069a6ba89cSAndrew Jeffery }
2079a6ba89cSAndrew Jeffery 
2089a6ba89cSAndrew Jeffery LIBPLDM_ABI_TESTING
pldm_transport_test_destroy(struct pldm_transport_test * ctx)2099a6ba89cSAndrew Jeffery void pldm_transport_test_destroy(struct pldm_transport_test *ctx)
2109a6ba89cSAndrew Jeffery {
2119a6ba89cSAndrew Jeffery 	close(ctx->timerfd);
2129a6ba89cSAndrew Jeffery 	free(ctx);
2139a6ba89cSAndrew Jeffery }
214