xref: /openbmc/libpldm/src/transport/test.c (revision f56e4dcd)
1 #include "container-of.h"
2 #include "transport.h"
3 #include "test.h"
4 
5 #include <errno.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 
10 struct pldm_transport_test {
11 	struct pldm_transport transport;
12 	const struct pldm_transport_test_descriptor *seq;
13 	size_t count;
14 	size_t cursor;
15 	int timerfd;
16 };
17 
18 #define transport_to_test(ptr)                                                 \
19 	container_of(ptr, struct pldm_transport_test, transport)
20 
21 LIBPLDM_ABI_TESTING
22 struct pldm_transport *pldm_transport_test_core(struct pldm_transport_test *ctx)
23 {
24 	return &ctx->transport;
25 }
26 
27 #ifdef PLDM_HAS_POLL
28 #include <poll.h>
29 LIBPLDM_ABI_TESTING
30 int pldm_transport_test_init_pollfd(struct pldm_transport *ctx,
31 				    struct pollfd *pollfd)
32 {
33 	static const struct itimerspec disable = {
34 		.it_value = { 0, 0 },
35 		.it_interval = { 0, 0 },
36 	};
37 	struct pldm_transport_test *test = transport_to_test(ctx);
38 	const struct pldm_transport_test_descriptor *desc;
39 	int rc;
40 
41 	rc = timerfd_settime(test->timerfd, 0, &disable, NULL);
42 	if (rc < 0) {
43 		return PLDM_REQUESTER_POLL_FAIL;
44 	}
45 
46 	if (test->cursor >= test->count) {
47 		return PLDM_REQUESTER_POLL_FAIL;
48 	}
49 
50 	desc = &test->seq[test->cursor];
51 
52 	if (desc->type == PLDM_TRANSPORT_TEST_ELEMENT_LATENCY) {
53 		rc = timerfd_settime(test->timerfd, 0, &desc->latency, NULL);
54 		if (rc < 0) {
55 			return PLDM_REQUESTER_POLL_FAIL;
56 		}
57 
58 		/* This was an explicit latency element, so now move beyond it for recv */
59 		test->cursor++;
60 	} else if (desc->type == PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV) {
61 		/* Expire the timer immediately so it appears ready */
62 		static const struct itimerspec ready = {
63 			.it_value = { 0, 1 },
64 			.it_interval = { 0, 0 },
65 		};
66 		rc = timerfd_settime(test->timerfd, 0, &ready, NULL);
67 		if (rc < 0) {
68 			return PLDM_REQUESTER_POLL_FAIL;
69 		}
70 
71 		/* Don't increment test->cursor as recv needs to consume the current test element */
72 	} else {
73 		return PLDM_REQUESTER_POLL_FAIL;
74 	}
75 
76 	pollfd->fd = test->timerfd;
77 	pollfd->events = POLLIN;
78 
79 	return 0;
80 }
81 #endif
82 
83 static pldm_requester_rc_t pldm_transport_test_recv(struct pldm_transport *ctx,
84 						    pldm_tid_t tid,
85 						    void **pldm_resp_msg,
86 						    size_t *resp_msg_len)
87 {
88 	struct pldm_transport_test *test = transport_to_test(ctx);
89 	const struct pldm_transport_test_descriptor *desc;
90 	void *msg;
91 
92 	(void)tid;
93 
94 	if (test->cursor >= test->count) {
95 		return PLDM_REQUESTER_RECV_FAIL;
96 	}
97 
98 	desc = &test->seq[test->cursor];
99 
100 	if (desc->type != PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV) {
101 		return PLDM_REQUESTER_RECV_FAIL;
102 	}
103 
104 	msg = malloc(desc->recv_msg.len);
105 	if (!msg) {
106 		return PLDM_REQUESTER_RECV_FAIL;
107 	}
108 
109 	memcpy(msg, desc->recv_msg.msg, desc->recv_msg.len);
110 	*pldm_resp_msg = msg;
111 	*resp_msg_len = desc->recv_msg.len;
112 
113 	test->cursor++;
114 
115 	return PLDM_REQUESTER_SUCCESS;
116 }
117 
118 static pldm_requester_rc_t pldm_transport_test_send(struct pldm_transport *ctx,
119 						    pldm_tid_t tid,
120 						    const void *pldm_req_msg,
121 						    size_t req_msg_len)
122 {
123 	struct pldm_transport_test *test = transport_to_test(ctx);
124 	const struct pldm_transport_test_descriptor *desc;
125 
126 	if (test->cursor > test->count) {
127 		return PLDM_REQUESTER_SEND_FAIL;
128 	}
129 
130 	desc = &test->seq[test->cursor];
131 
132 	if (desc->type != PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND) {
133 		return PLDM_REQUESTER_SEND_FAIL;
134 	}
135 
136 	if (desc->send_msg.dst != tid) {
137 		return PLDM_REQUESTER_SEND_FAIL;
138 	}
139 
140 	if (desc->send_msg.len != req_msg_len) {
141 		return PLDM_REQUESTER_SEND_FAIL;
142 	}
143 
144 	if (memcmp(desc->send_msg.msg, pldm_req_msg, req_msg_len) != 0) {
145 		return PLDM_REQUESTER_SEND_FAIL;
146 	}
147 
148 	test->cursor++;
149 
150 	return PLDM_REQUESTER_SUCCESS;
151 }
152 
153 LIBPLDM_ABI_TESTING
154 int pldm_transport_test_init(struct pldm_transport_test **ctx,
155 			     const struct pldm_transport_test_descriptor *seq,
156 			     size_t count)
157 {
158 	int rc;
159 
160 	if (!ctx || *ctx) {
161 		return -EINVAL;
162 	}
163 
164 	struct pldm_transport_test *test = malloc(sizeof(*test));
165 	if (!test) {
166 		return -ENOMEM;
167 	}
168 
169 	test->transport.name = "TEST";
170 	test->transport.version = 1;
171 	test->transport.recv = pldm_transport_test_recv;
172 	test->transport.send = pldm_transport_test_send;
173 	test->transport.init_pollfd = pldm_transport_test_init_pollfd;
174 	test->seq = seq;
175 	test->count = count;
176 	test->cursor = 0;
177 	test->timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
178 	if (test->timerfd < 0) {
179 		rc = -errno;
180 		goto cleanup_test;
181 	}
182 
183 	*ctx = test;
184 
185 	return 0;
186 
187 cleanup_test:
188 	free(test);
189 	return rc;
190 }
191 
192 LIBPLDM_ABI_TESTING
193 void pldm_transport_test_destroy(struct pldm_transport_test *ctx)
194 {
195 	close(ctx->timerfd);
196 	free(ctx);
197 }
198