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