blob: 12a26aaa283f7a1a65866fd675bce2565bf56d60 [file] [log] [blame]
Rashmica Guptac1b66f42022-12-09 16:24:45 +11001#include "libpldm/transport.h"
Andrew Jeffery4c1ea562023-09-22 18:01:05 +09302#include "libpldm/base.h"
Rashmica Guptac1b66f42022-12-09 16:24:45 +11003#include "libpldm/requester/pldm.h"
4#include "transport.h"
5
Dung Caoabaf61f2022-11-15 20:48:50 +07006#include <errno.h>
7#include <limits.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +11008#ifdef PLDM_HAS_POLL
9#include <poll.h>
10#endif
Dung Caoabaf61f2022-11-15 20:48:50 +070011#include <stdbool.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110012#include <stdlib.h>
Dung Caoabaf61f2022-11-15 20:48:50 +070013#include <sys/time.h>
14#include <time.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110015#include <unistd.h>
16
17#ifndef PLDM_HAS_POLL
18struct pollfd {
19 int fd; /* file descriptor */
20 short events; /* requested events */
21 short revents; /* returned events */
22};
23
24static inline int poll(struct pollfd *fds __attribute__((unused)),
25 int nfds __attribute__((unused)),
26 int timeout __attribute__((unused)))
27{
28 return 0;
29}
30#endif
31
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093032LIBPLDM_ABI_STABLE
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093033int pldm_transport_poll(struct pldm_transport *transport, int timeout)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110034{
35 struct pollfd pollfd;
36 int rc = 0;
37 if (!transport) {
38 return PLDM_REQUESTER_INVALID_SETUP;
39 }
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093040
41 /* If polling isn't supported then always indicate the transport is ready */
Rashmica Guptac1b66f42022-12-09 16:24:45 +110042 if (!transport->init_pollfd) {
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093043 return 1;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110044 }
45
Andrew Jeffery98085fa2023-07-19 00:35:42 +093046 rc = transport->init_pollfd(transport, &pollfd);
47 if (rc < 0) {
48 return PLDM_REQUESTER_POLL_FAIL;
49 }
50
Rashmica Guptac1b66f42022-12-09 16:24:45 +110051 rc = poll(&pollfd, 1, timeout);
52 if (rc < 0) {
53 return PLDM_REQUESTER_POLL_FAIL;
54 }
55
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093056 /* rc is 0 if poll(2) times out, or 1 if pollfd becomes active. */
57 return rc;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110058}
59
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093060LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110061pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport,
62 pldm_tid_t tid,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100063 const void *pldm_msg,
64 size_t msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110065{
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100066 if (!transport || !pldm_msg) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110067 return PLDM_REQUESTER_INVALID_SETUP;
68 }
69
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100070 if (msg_len < sizeof(struct pldm_msg_hdr)) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110071 return PLDM_REQUESTER_NOT_REQ_MSG;
72 }
73
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100074 return transport->send(transport, tid, pldm_msg, msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +110075}
76
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093077LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110078pldm_requester_rc_t pldm_transport_recv_msg(struct pldm_transport *transport,
Rashmica Gupta24576292023-07-31 14:02:41 +100079 pldm_tid_t *tid, void **pldm_msg,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100080 size_t *msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110081{
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100082 if (!transport || !msg_len) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110083 return PLDM_REQUESTER_INVALID_SETUP;
84 }
85
86 pldm_requester_rc_t rc =
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100087 transport->recv(transport, tid, pldm_msg, msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +110088 if (rc != PLDM_REQUESTER_SUCCESS) {
89 return rc;
90 }
91
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100092 if (*msg_len < sizeof(struct pldm_msg_hdr)) {
93 free(*pldm_msg);
94 *pldm_msg = NULL;
Rashmica Gupta0411b712023-05-30 16:43:08 +100095 return PLDM_REQUESTER_INVALID_RECV_LEN;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110096 }
Rashmica Guptac1b66f42022-12-09 16:24:45 +110097 return PLDM_REQUESTER_SUCCESS;
98}
99
Dung Caoabaf61f2022-11-15 20:48:50 +0700100static void timespec_to_timeval(const struct timespec *ts, struct timeval *tv)
101{
102 tv->tv_sec = ts->tv_sec;
103 tv->tv_usec = ts->tv_nsec / 1000;
104}
105
106/* Overflow safety must be upheld before call */
107static long timeval_to_msec(const struct timeval *tv)
108{
109 return tv->tv_sec * 1000 + tv->tv_usec / 1000;
110}
111
112/* If calculations on `tv` don't overflow then operations on derived
113 * intervals can't either.
114 */
115static bool timeval_is_valid(const struct timeval *tv)
116{
117 if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
118 return false;
119 }
120
121 if (tv->tv_sec > (LONG_MAX - tv->tv_usec / 1000) / 1000) {
122 return false;
123 }
124
125 return true;
126}
127
128static int clock_gettimeval(clockid_t clockid, struct timeval *tv)
129{
130 struct timespec now;
131 int rc;
132
133 rc = clock_gettime(clockid, &now);
134 if (rc < 0) {
135 return rc;
136 }
137
138 timespec_to_timeval(&now, tv);
139
140 return 0;
141}
142
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930143LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100144pldm_requester_rc_t
145pldm_transport_send_recv_msg(struct pldm_transport *transport, pldm_tid_t tid,
146 const void *pldm_req_msg, size_t req_msg_len,
147 void **pldm_resp_msg, size_t *resp_msg_len)
148
149{
Dung Caoabaf61f2022-11-15 20:48:50 +0700150 /**
151 * Section "Requirements for requesters" in DSP0240, define the Time-out
152 * waiting for a response of the requester.
153 * PT2max = PT3min - 2*PT4max = 4800ms
154 */
155 static const struct timeval max_response_interval = {
156 .tv_sec = 4, .tv_usec = 800000
157 };
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700158 const struct pldm_msg_hdr *req_hdr;
Dung Caoabaf61f2022-11-15 20:48:50 +0700159 struct timeval remaining;
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700160 pldm_requester_rc_t rc;
Dung Caoabaf61f2022-11-15 20:48:50 +0700161 struct timeval now;
162 struct timeval end;
Dung Caoabaf61f2022-11-15 20:48:50 +0700163 int ret;
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700164 int cnt;
Dung Caoabaf61f2022-11-15 20:48:50 +0700165
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700166 if (req_msg_len < sizeof(*req_hdr) || !resp_msg_len) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100167 return PLDM_REQUESTER_INVALID_SETUP;
168 }
169
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700170 req_hdr = pldm_req_msg;
171
Andrew Jeffery486d85d2023-08-31 11:12:08 +0930172 if (!req_hdr->request) {
173 return PLDM_REQUESTER_NOT_REQ_MSG;
174 }
175
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700176 for (cnt = 0; cnt <= (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS &&
177 pldm_transport_poll(transport, 0) == 1;
178 cnt++) {
Rashmica Gupta24576292023-07-31 14:02:41 +1000179 pldm_tid_t l_tid;
180 rc = pldm_transport_recv_msg(transport, &l_tid, pldm_resp_msg,
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700181 resp_msg_len);
182 if (rc == PLDM_REQUESTER_SUCCESS) {
183 /* This isn't the message we wanted */
184 free(*pldm_resp_msg);
185 }
186 }
187 if (cnt == (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS) {
188 return PLDM_REQUESTER_TRANSPORT_BUSY;
189 }
190
Dung Caoabaf61f2022-11-15 20:48:50 +0700191 rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100192 if (rc != PLDM_REQUESTER_SUCCESS) {
193 return rc;
194 }
195
Dung Caoabaf61f2022-11-15 20:48:50 +0700196 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
197 if (ret < 0) {
198 return PLDM_REQUESTER_POLL_FAIL;
199 }
200
201 timeradd(&now, &max_response_interval, &end);
202 if (!timeval_is_valid(&end)) {
203 return PLDM_REQUESTER_POLL_FAIL;
204 }
205
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930206 while (timercmp(&now, &end, <)) {
207 pldm_tid_t src_tid;
208
Dung Caoabaf61f2022-11-15 20:48:50 +0700209 timersub(&end, &now, &remaining);
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930210
Dung Caoabaf61f2022-11-15 20:48:50 +0700211 /* 0 <= `timeval_to_msec()` <= 4800, and 4800 < INT_MAX */
Andrew Jeffery3380a6c2023-07-12 13:57:33 +0930212 ret = pldm_transport_poll(transport,
213 (int)(timeval_to_msec(&remaining)));
214 if (ret <= 0) {
Andrew Jeffery1184f092023-09-22 17:44:46 +0930215 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100216 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700217
Andrew Jeffery50382682023-09-22 17:46:54 +0930218 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
219 if (ret < 0) {
220 return PLDM_REQUESTER_POLL_FAIL;
221 }
222
Rashmica Gupta24576292023-07-31 14:02:41 +1000223 rc = pldm_transport_recv_msg(transport, &src_tid, pldm_resp_msg,
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100224 resp_msg_len);
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930225 if (rc != PLDM_REQUESTER_SUCCESS) {
226 continue;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100227 }
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930228
229 if (src_tid != tid || !pldm_msg_hdr_correlate_response(
230 pldm_req_msg, *pldm_resp_msg)) {
231 free(*pldm_resp_msg);
232 continue;
233 }
234
235 return PLDM_REQUESTER_SUCCESS;
236 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700237
238 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100239}