blob: 33197ab69019eb55c3e2d8c00f5d8d7129808e13 [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Rashmica Guptac1b66f42022-12-09 16:24:45 +11002#include "transport.h"
3
Andrew Jefferyefb40062023-11-10 13:48:39 +10304#include <libpldm/transport.h>
5#include <libpldm/base.h>
6#include <libpldm/pldm.h>
7
Dung Caoabaf61f2022-11-15 20:48:50 +07008#include <errno.h>
9#include <limits.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110010#ifdef PLDM_HAS_POLL
11#include <poll.h>
12#endif
Dung Caoabaf61f2022-11-15 20:48:50 +070013#include <stdbool.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110014#include <stdlib.h>
Dung Caoabaf61f2022-11-15 20:48:50 +070015#include <sys/time.h>
16#include <time.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110017#include <unistd.h>
18
19#ifndef PLDM_HAS_POLL
20struct pollfd {
21 int fd; /* file descriptor */
22 short events; /* requested events */
23 short revents; /* returned events */
24};
25
26static inline int poll(struct pollfd *fds __attribute__((unused)),
27 int nfds __attribute__((unused)),
28 int timeout __attribute__((unused)))
29{
30 return 0;
31}
32#endif
33
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093034LIBPLDM_ABI_STABLE
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093035int pldm_transport_poll(struct pldm_transport *transport, int timeout)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110036{
37 struct pollfd pollfd;
38 int rc = 0;
39 if (!transport) {
40 return PLDM_REQUESTER_INVALID_SETUP;
41 }
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093042
43 /* If polling isn't supported then always indicate the transport is ready */
Rashmica Guptac1b66f42022-12-09 16:24:45 +110044 if (!transport->init_pollfd) {
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093045 return 1;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110046 }
47
Andrew Jeffery98085fa2023-07-19 00:35:42 +093048 rc = transport->init_pollfd(transport, &pollfd);
49 if (rc < 0) {
50 return PLDM_REQUESTER_POLL_FAIL;
51 }
52
Rashmica Guptac1b66f42022-12-09 16:24:45 +110053 rc = poll(&pollfd, 1, timeout);
54 if (rc < 0) {
55 return PLDM_REQUESTER_POLL_FAIL;
56 }
57
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093058 /* rc is 0 if poll(2) times out, or 1 if pollfd becomes active. */
59 return rc;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110060}
61
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093062LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110063pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport,
64 pldm_tid_t tid,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100065 const void *pldm_msg,
66 size_t msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110067{
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100068 if (!transport || !pldm_msg) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110069 return PLDM_REQUESTER_INVALID_SETUP;
70 }
71
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100072 if (msg_len < sizeof(struct pldm_msg_hdr)) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110073 return PLDM_REQUESTER_NOT_REQ_MSG;
74 }
75
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100076 return transport->send(transport, tid, pldm_msg, msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +110077}
78
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093079LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110080pldm_requester_rc_t pldm_transport_recv_msg(struct pldm_transport *transport,
Rashmica Gupta24576292023-07-31 14:02:41 +100081 pldm_tid_t *tid, void **pldm_msg,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100082 size_t *msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110083{
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100084 if (!transport || !msg_len) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110085 return PLDM_REQUESTER_INVALID_SETUP;
86 }
87
88 pldm_requester_rc_t rc =
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100089 transport->recv(transport, tid, pldm_msg, msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +110090 if (rc != PLDM_REQUESTER_SUCCESS) {
91 return rc;
92 }
93
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100094 if (*msg_len < sizeof(struct pldm_msg_hdr)) {
95 free(*pldm_msg);
96 *pldm_msg = NULL;
Rashmica Gupta0411b712023-05-30 16:43:08 +100097 return PLDM_REQUESTER_INVALID_RECV_LEN;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110098 }
Rashmica Guptac1b66f42022-12-09 16:24:45 +110099 return PLDM_REQUESTER_SUCCESS;
100}
101
Dung Caoabaf61f2022-11-15 20:48:50 +0700102static void timespec_to_timeval(const struct timespec *ts, struct timeval *tv)
103{
104 tv->tv_sec = ts->tv_sec;
105 tv->tv_usec = ts->tv_nsec / 1000;
106}
107
108/* Overflow safety must be upheld before call */
109static long timeval_to_msec(const struct timeval *tv)
110{
111 return tv->tv_sec * 1000 + tv->tv_usec / 1000;
112}
113
114/* If calculations on `tv` don't overflow then operations on derived
115 * intervals can't either.
116 */
117static bool timeval_is_valid(const struct timeval *tv)
118{
119 if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
120 return false;
121 }
122
123 if (tv->tv_sec > (LONG_MAX - tv->tv_usec / 1000) / 1000) {
124 return false;
125 }
126
127 return true;
128}
129
130static int clock_gettimeval(clockid_t clockid, struct timeval *tv)
131{
132 struct timespec now;
133 int rc;
134
135 rc = clock_gettime(clockid, &now);
136 if (rc < 0) {
137 return rc;
138 }
139
140 timespec_to_timeval(&now, tv);
141
142 return 0;
143}
144
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930145LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100146pldm_requester_rc_t
147pldm_transport_send_recv_msg(struct pldm_transport *transport, pldm_tid_t tid,
148 const void *pldm_req_msg, size_t req_msg_len,
149 void **pldm_resp_msg, size_t *resp_msg_len)
150
151{
Dung Caoabaf61f2022-11-15 20:48:50 +0700152 /**
153 * Section "Requirements for requesters" in DSP0240, define the Time-out
154 * waiting for a response of the requester.
155 * PT2max = PT3min - 2*PT4max = 4800ms
156 */
157 static const struct timeval max_response_interval = {
158 .tv_sec = 4, .tv_usec = 800000
159 };
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700160 const struct pldm_msg_hdr *req_hdr;
Dung Caoabaf61f2022-11-15 20:48:50 +0700161 struct timeval remaining;
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700162 pldm_requester_rc_t rc;
Dung Caoabaf61f2022-11-15 20:48:50 +0700163 struct timeval now;
164 struct timeval end;
Dung Caoabaf61f2022-11-15 20:48:50 +0700165 int ret;
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700166 int cnt;
Dung Caoabaf61f2022-11-15 20:48:50 +0700167
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700168 if (req_msg_len < sizeof(*req_hdr) || !resp_msg_len) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100169 return PLDM_REQUESTER_INVALID_SETUP;
170 }
171
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700172 req_hdr = pldm_req_msg;
173
Andrew Jeffery486d85d2023-08-31 11:12:08 +0930174 if (!req_hdr->request) {
175 return PLDM_REQUESTER_NOT_REQ_MSG;
176 }
177
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700178 for (cnt = 0; cnt <= (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS &&
179 pldm_transport_poll(transport, 0) == 1;
180 cnt++) {
Rashmica Gupta24576292023-07-31 14:02:41 +1000181 pldm_tid_t l_tid;
182 rc = pldm_transport_recv_msg(transport, &l_tid, pldm_resp_msg,
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700183 resp_msg_len);
184 if (rc == PLDM_REQUESTER_SUCCESS) {
185 /* This isn't the message we wanted */
186 free(*pldm_resp_msg);
187 }
188 }
189 if (cnt == (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS) {
190 return PLDM_REQUESTER_TRANSPORT_BUSY;
191 }
192
Dung Caoabaf61f2022-11-15 20:48:50 +0700193 rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100194 if (rc != PLDM_REQUESTER_SUCCESS) {
195 return rc;
196 }
197
Dung Caoabaf61f2022-11-15 20:48:50 +0700198 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
199 if (ret < 0) {
200 return PLDM_REQUESTER_POLL_FAIL;
201 }
202
203 timeradd(&now, &max_response_interval, &end);
204 if (!timeval_is_valid(&end)) {
205 return PLDM_REQUESTER_POLL_FAIL;
206 }
207
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930208 while (timercmp(&now, &end, <)) {
209 pldm_tid_t src_tid;
210
Dung Caoabaf61f2022-11-15 20:48:50 +0700211 timersub(&end, &now, &remaining);
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930212
Dung Caoabaf61f2022-11-15 20:48:50 +0700213 /* 0 <= `timeval_to_msec()` <= 4800, and 4800 < INT_MAX */
Andrew Jeffery3380a6c2023-07-12 13:57:33 +0930214 ret = pldm_transport_poll(transport,
215 (int)(timeval_to_msec(&remaining)));
216 if (ret <= 0) {
Andrew Jeffery1184f092023-09-22 17:44:46 +0930217 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100218 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700219
Andrew Jeffery50382682023-09-22 17:46:54 +0930220 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
221 if (ret < 0) {
222 return PLDM_REQUESTER_POLL_FAIL;
223 }
224
Rashmica Gupta24576292023-07-31 14:02:41 +1000225 rc = pldm_transport_recv_msg(transport, &src_tid, pldm_resp_msg,
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100226 resp_msg_len);
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930227 if (rc != PLDM_REQUESTER_SUCCESS) {
228 continue;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100229 }
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930230
231 if (src_tid != tid || !pldm_msg_hdr_correlate_response(
232 pldm_req_msg, *pldm_resp_msg)) {
233 free(*pldm_resp_msg);
234 continue;
235 }
236
237 return PLDM_REQUESTER_SUCCESS;
238 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700239
240 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100241}