blob: 1260031be1f2aa1e6c2d0f28b660eb3b278c88dc [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) */
Andrew Jefferydc1edac2023-08-07 21:15:07 +09303#include "array.h"
Andrew Jeffery9a6ba892023-07-18 22:22:14 +09304#include "container-of.h"
5#include "transport.h"
6#include "test.h"
7
8#include <errno.h>
Andrew Jefferydc1edac2023-08-07 21:15:07 +09309#include <poll.h>
Andrew Jeffery9a6ba892023-07-18 22:22:14 +093010#include <stdlib.h>
11#include <string.h>
12#include <unistd.h>
13
14struct pldm_transport_test {
15 struct pldm_transport transport;
16 const struct pldm_transport_test_descriptor *seq;
17 size_t count;
18 size_t cursor;
19 int timerfd;
20};
21
22#define transport_to_test(ptr) \
23 container_of(ptr, struct pldm_transport_test, transport)
24
25LIBPLDM_ABI_TESTING
26struct pldm_transport *pldm_transport_test_core(struct pldm_transport_test *ctx)
27{
28 return &ctx->transport;
29}
30
31#ifdef PLDM_HAS_POLL
32#include <poll.h>
33LIBPLDM_ABI_TESTING
34int pldm_transport_test_init_pollfd(struct pldm_transport *ctx,
35 struct pollfd *pollfd)
36{
37 static const struct itimerspec disable = {
38 .it_value = { 0, 0 },
39 .it_interval = { 0, 0 },
40 };
41 struct pldm_transport_test *test = transport_to_test(ctx);
42 const struct pldm_transport_test_descriptor *desc;
43 int rc;
44
45 rc = timerfd_settime(test->timerfd, 0, &disable, NULL);
46 if (rc < 0) {
47 return PLDM_REQUESTER_POLL_FAIL;
48 }
49
50 if (test->cursor >= test->count) {
51 return PLDM_REQUESTER_POLL_FAIL;
52 }
53
54 desc = &test->seq[test->cursor];
55
Thu Nguyenf56e4dc2023-07-24 10:39:47 +070056 if (desc->type == PLDM_TRANSPORT_TEST_ELEMENT_LATENCY) {
57 rc = timerfd_settime(test->timerfd, 0, &desc->latency, NULL);
58 if (rc < 0) {
59 return PLDM_REQUESTER_POLL_FAIL;
60 }
Andrew Jeffery9a6ba892023-07-18 22:22:14 +093061
Thu Nguyenf56e4dc2023-07-24 10:39:47 +070062 /* This was an explicit latency element, so now move beyond it for recv */
63 test->cursor++;
64 } else if (desc->type == PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV) {
65 /* Expire the timer immediately so it appears ready */
Andrew Jefferydc1edac2023-08-07 21:15:07 +093066 static const struct timespec ensure_ready = {
67 .tv_sec = 0,
68 .tv_nsec = 2,
69 };
Thu Nguyenf56e4dc2023-07-24 10:39:47 +070070 static const struct itimerspec ready = {
71 .it_value = { 0, 1 },
72 .it_interval = { 0, 0 },
73 };
Andrew Jefferydc1edac2023-08-07 21:15:07 +093074 struct pollfd pfds[] = {
75 { .fd = test->timerfd, .events = POLLIN },
76 };
77
Thu Nguyenf56e4dc2023-07-24 10:39:47 +070078 rc = timerfd_settime(test->timerfd, 0, &ready, NULL);
79 if (rc < 0) {
80 return PLDM_REQUESTER_POLL_FAIL;
81 }
82
Andrew Jefferydc1edac2023-08-07 21:15:07 +093083 rc = ppoll(pfds, ARRAY_SIZE(pfds), &ensure_ready, NULL);
84 if (rc < 1) {
85 return PLDM_REQUESTER_POLL_FAIL;
86 }
87
Thu Nguyenf56e4dc2023-07-24 10:39:47 +070088 /* Don't increment test->cursor as recv needs to consume the current test element */
89 } else {
Andrew Jeffery9a6ba892023-07-18 22:22:14 +093090 return PLDM_REQUESTER_POLL_FAIL;
91 }
92
93 pollfd->fd = test->timerfd;
94 pollfd->events = POLLIN;
95
Andrew Jeffery9a6ba892023-07-18 22:22:14 +093096 return 0;
97}
98#endif
99
100static pldm_requester_rc_t pldm_transport_test_recv(struct pldm_transport *ctx,
Rashmica Gupta24576292023-07-31 14:02:41 +1000101 pldm_tid_t *tid,
Andrew Jeffery9a6ba892023-07-18 22:22:14 +0930102 void **pldm_resp_msg,
103 size_t *resp_msg_len)
104{
105 struct pldm_transport_test *test = transport_to_test(ctx);
106 const struct pldm_transport_test_descriptor *desc;
107 void *msg;
108
Andrew Jeffery9a6ba892023-07-18 22:22:14 +0930109 if (test->cursor >= test->count) {
110 return PLDM_REQUESTER_RECV_FAIL;
111 }
112
113 desc = &test->seq[test->cursor];
114
115 if (desc->type != PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV) {
116 return PLDM_REQUESTER_RECV_FAIL;
117 }
118
119 msg = malloc(desc->recv_msg.len);
120 if (!msg) {
121 return PLDM_REQUESTER_RECV_FAIL;
122 }
123
124 memcpy(msg, desc->recv_msg.msg, desc->recv_msg.len);
125 *pldm_resp_msg = msg;
126 *resp_msg_len = desc->recv_msg.len;
Rashmica Gupta24576292023-07-31 14:02:41 +1000127 *tid = desc->recv_msg.src;
Andrew Jeffery9a6ba892023-07-18 22:22:14 +0930128
129 test->cursor++;
130
131 return PLDM_REQUESTER_SUCCESS;
132}
133
134static pldm_requester_rc_t pldm_transport_test_send(struct pldm_transport *ctx,
135 pldm_tid_t tid,
136 const void *pldm_req_msg,
137 size_t req_msg_len)
138{
139 struct pldm_transport_test *test = transport_to_test(ctx);
140 const struct pldm_transport_test_descriptor *desc;
141
142 if (test->cursor > test->count) {
143 return PLDM_REQUESTER_SEND_FAIL;
144 }
145
146 desc = &test->seq[test->cursor];
147
148 if (desc->type != PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND) {
149 return PLDM_REQUESTER_SEND_FAIL;
150 }
151
152 if (desc->send_msg.dst != tid) {
153 return PLDM_REQUESTER_SEND_FAIL;
154 }
155
156 if (desc->send_msg.len != req_msg_len) {
157 return PLDM_REQUESTER_SEND_FAIL;
158 }
159
160 if (memcmp(desc->send_msg.msg, pldm_req_msg, req_msg_len) != 0) {
161 return PLDM_REQUESTER_SEND_FAIL;
162 }
163
164 test->cursor++;
165
166 return PLDM_REQUESTER_SUCCESS;
167}
168
169LIBPLDM_ABI_TESTING
170int pldm_transport_test_init(struct pldm_transport_test **ctx,
171 const struct pldm_transport_test_descriptor *seq,
172 size_t count)
173{
174 int rc;
175
176 if (!ctx || *ctx) {
177 return -EINVAL;
178 }
179
180 struct pldm_transport_test *test = malloc(sizeof(*test));
181 if (!test) {
182 return -ENOMEM;
183 }
184
185 test->transport.name = "TEST";
186 test->transport.version = 1;
187 test->transport.recv = pldm_transport_test_recv;
188 test->transport.send = pldm_transport_test_send;
189 test->transport.init_pollfd = pldm_transport_test_init_pollfd;
190 test->seq = seq;
191 test->count = count;
192 test->cursor = 0;
193 test->timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
194 if (test->timerfd < 0) {
195 rc = -errno;
196 goto cleanup_test;
197 }
198
199 *ctx = test;
200
201 return 0;
202
203cleanup_test:
204 free(test);
205 return rc;
206}
207
208LIBPLDM_ABI_TESTING
209void pldm_transport_test_destroy(struct pldm_transport_test *ctx)
210{
211 close(ctx->timerfd);
212 free(ctx);
213}