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