blob: 2a929cc17c4814a18d536bd7b6a82ad404553394 [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jefferydc1edac2023-08-07 21:15:07 +09302/* NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */
3#define _GNU_SOURCE
4#include "array.h"
Andrew Jeffery9a6ba892023-07-18 22:22:14 +09305#include "container-of.h"
6#include "transport.h"
7#include "test.h"
8
9#include <errno.h>
Andrew Jefferydc1edac2023-08-07 21:15:07 +093010#include <poll.h>
Andrew Jeffery9a6ba892023-07-18 22:22:14 +093011#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14
15struct pldm_transport_test {
16 struct pldm_transport transport;
17 const struct pldm_transport_test_descriptor *seq;
18 size_t count;
19 size_t cursor;
20 int timerfd;
21};
22
23#define transport_to_test(ptr) \
24 container_of(ptr, struct pldm_transport_test, transport)
25
26LIBPLDM_ABI_TESTING
27struct pldm_transport *pldm_transport_test_core(struct pldm_transport_test *ctx)
28{
29 return &ctx->transport;
30}
31
32#ifdef PLDM_HAS_POLL
33#include <poll.h>
34LIBPLDM_ABI_TESTING
35int pldm_transport_test_init_pollfd(struct pldm_transport *ctx,
36 struct pollfd *pollfd)
37{
38 static const struct itimerspec disable = {
39 .it_value = { 0, 0 },
40 .it_interval = { 0, 0 },
41 };
42 struct pldm_transport_test *test = transport_to_test(ctx);
43 const struct pldm_transport_test_descriptor *desc;
44 int rc;
45
46 rc = timerfd_settime(test->timerfd, 0, &disable, NULL);
47 if (rc < 0) {
48 return PLDM_REQUESTER_POLL_FAIL;
49 }
50
51 if (test->cursor >= test->count) {
52 return PLDM_REQUESTER_POLL_FAIL;
53 }
54
55 desc = &test->seq[test->cursor];
56
Thu Nguyenf56e4dc2023-07-24 10:39:47 +070057 if (desc->type == PLDM_TRANSPORT_TEST_ELEMENT_LATENCY) {
58 rc = timerfd_settime(test->timerfd, 0, &desc->latency, NULL);
59 if (rc < 0) {
60 return PLDM_REQUESTER_POLL_FAIL;
61 }
Andrew Jeffery9a6ba892023-07-18 22:22:14 +093062
Thu Nguyenf56e4dc2023-07-24 10:39:47 +070063 /* This was an explicit latency element, so now move beyond it for recv */
64 test->cursor++;
65 } else if (desc->type == PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV) {
66 /* Expire the timer immediately so it appears ready */
Andrew Jefferydc1edac2023-08-07 21:15:07 +093067 static const struct timespec ensure_ready = {
68 .tv_sec = 0,
69 .tv_nsec = 2,
70 };
Thu Nguyenf56e4dc2023-07-24 10:39:47 +070071 static const struct itimerspec ready = {
72 .it_value = { 0, 1 },
73 .it_interval = { 0, 0 },
74 };
Andrew Jefferydc1edac2023-08-07 21:15:07 +093075 struct pollfd pfds[] = {
76 { .fd = test->timerfd, .events = POLLIN },
77 };
78
Thu Nguyenf56e4dc2023-07-24 10:39:47 +070079 rc = timerfd_settime(test->timerfd, 0, &ready, NULL);
80 if (rc < 0) {
81 return PLDM_REQUESTER_POLL_FAIL;
82 }
83
Andrew Jefferydc1edac2023-08-07 21:15:07 +093084 rc = ppoll(pfds, ARRAY_SIZE(pfds), &ensure_ready, NULL);
85 if (rc < 1) {
86 return PLDM_REQUESTER_POLL_FAIL;
87 }
88
Thu Nguyenf56e4dc2023-07-24 10:39:47 +070089 /* Don't increment test->cursor as recv needs to consume the current test element */
90 } else {
Andrew Jeffery9a6ba892023-07-18 22:22:14 +093091 return PLDM_REQUESTER_POLL_FAIL;
92 }
93
94 pollfd->fd = test->timerfd;
95 pollfd->events = POLLIN;
96
Andrew Jeffery9a6ba892023-07-18 22:22:14 +093097 return 0;
98}
99#endif
100
101static pldm_requester_rc_t pldm_transport_test_recv(struct pldm_transport *ctx,
Rashmica Gupta24576292023-07-31 14:02:41 +1000102 pldm_tid_t *tid,
Andrew Jeffery9a6ba892023-07-18 22:22:14 +0930103 void **pldm_resp_msg,
104 size_t *resp_msg_len)
105{
106 struct pldm_transport_test *test = transport_to_test(ctx);
107 const struct pldm_transport_test_descriptor *desc;
108 void *msg;
109
Andrew Jeffery9a6ba892023-07-18 22:22:14 +0930110 if (test->cursor >= test->count) {
111 return PLDM_REQUESTER_RECV_FAIL;
112 }
113
114 desc = &test->seq[test->cursor];
115
116 if (desc->type != PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV) {
117 return PLDM_REQUESTER_RECV_FAIL;
118 }
119
120 msg = malloc(desc->recv_msg.len);
121 if (!msg) {
122 return PLDM_REQUESTER_RECV_FAIL;
123 }
124
125 memcpy(msg, desc->recv_msg.msg, desc->recv_msg.len);
126 *pldm_resp_msg = msg;
127 *resp_msg_len = desc->recv_msg.len;
Rashmica Gupta24576292023-07-31 14:02:41 +1000128 *tid = desc->recv_msg.src;
Andrew Jeffery9a6ba892023-07-18 22:22:14 +0930129
130 test->cursor++;
131
132 return PLDM_REQUESTER_SUCCESS;
133}
134
135static pldm_requester_rc_t pldm_transport_test_send(struct pldm_transport *ctx,
136 pldm_tid_t tid,
137 const void *pldm_req_msg,
138 size_t req_msg_len)
139{
140 struct pldm_transport_test *test = transport_to_test(ctx);
141 const struct pldm_transport_test_descriptor *desc;
142
143 if (test->cursor > test->count) {
144 return PLDM_REQUESTER_SEND_FAIL;
145 }
146
147 desc = &test->seq[test->cursor];
148
149 if (desc->type != PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND) {
150 return PLDM_REQUESTER_SEND_FAIL;
151 }
152
153 if (desc->send_msg.dst != tid) {
154 return PLDM_REQUESTER_SEND_FAIL;
155 }
156
157 if (desc->send_msg.len != req_msg_len) {
158 return PLDM_REQUESTER_SEND_FAIL;
159 }
160
161 if (memcmp(desc->send_msg.msg, pldm_req_msg, req_msg_len) != 0) {
162 return PLDM_REQUESTER_SEND_FAIL;
163 }
164
165 test->cursor++;
166
167 return PLDM_REQUESTER_SUCCESS;
168}
169
170LIBPLDM_ABI_TESTING
171int pldm_transport_test_init(struct pldm_transport_test **ctx,
172 const struct pldm_transport_test_descriptor *seq,
173 size_t count)
174{
175 int rc;
176
177 if (!ctx || *ctx) {
178 return -EINVAL;
179 }
180
181 struct pldm_transport_test *test = malloc(sizeof(*test));
182 if (!test) {
183 return -ENOMEM;
184 }
185
186 test->transport.name = "TEST";
187 test->transport.version = 1;
188 test->transport.recv = pldm_transport_test_recv;
189 test->transport.send = pldm_transport_test_send;
190 test->transport.init_pollfd = pldm_transport_test_init_pollfd;
191 test->seq = seq;
192 test->count = count;
193 test->cursor = 0;
194 test->timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
195 if (test->timerfd < 0) {
196 rc = -errno;
197 goto cleanup_test;
198 }
199
200 *ctx = test;
201
202 return 0;
203
204cleanup_test:
205 free(test);
206 return rc;
207}
208
209LIBPLDM_ABI_TESTING
210void pldm_transport_test_destroy(struct pldm_transport_test *ctx)
211{
212 close(ctx->timerfd);
213 free(ctx);
214}