blob: bc01000c9d5c50b80c943c33fecfc3b85b74e30f [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 "libpldm/transport.h"
Andrew Jeffery4c1ea562023-09-22 18:01:05 +09303#include "libpldm/base.h"
Rashmica Guptac1b66f42022-12-09 16:24:45 +11004#include "libpldm/requester/pldm.h"
5#include "transport.h"
6
Dung Caoabaf61f2022-11-15 20:48:50 +07007#include <errno.h>
8#include <limits.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +11009#ifdef PLDM_HAS_POLL
10#include <poll.h>
11#endif
Dung Caoabaf61f2022-11-15 20:48:50 +070012#include <stdbool.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110013#include <stdlib.h>
Dung Caoabaf61f2022-11-15 20:48:50 +070014#include <sys/time.h>
15#include <time.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110016#include <unistd.h>
17
18#ifndef PLDM_HAS_POLL
19struct pollfd {
20 int fd; /* file descriptor */
21 short events; /* requested events */
22 short revents; /* returned events */
23};
24
25static inline int poll(struct pollfd *fds __attribute__((unused)),
26 int nfds __attribute__((unused)),
27 int timeout __attribute__((unused)))
28{
29 return 0;
30}
31#endif
32
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093033LIBPLDM_ABI_STABLE
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093034int pldm_transport_poll(struct pldm_transport *transport, int timeout)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110035{
36 struct pollfd pollfd;
37 int rc = 0;
38 if (!transport) {
39 return PLDM_REQUESTER_INVALID_SETUP;
40 }
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093041
42 /* If polling isn't supported then always indicate the transport is ready */
Rashmica Guptac1b66f42022-12-09 16:24:45 +110043 if (!transport->init_pollfd) {
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093044 return 1;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110045 }
46
Andrew Jeffery98085fa2023-07-19 00:35:42 +093047 rc = transport->init_pollfd(transport, &pollfd);
48 if (rc < 0) {
49 return PLDM_REQUESTER_POLL_FAIL;
50 }
51
Rashmica Guptac1b66f42022-12-09 16:24:45 +110052 rc = poll(&pollfd, 1, timeout);
53 if (rc < 0) {
54 return PLDM_REQUESTER_POLL_FAIL;
55 }
56
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093057 /* rc is 0 if poll(2) times out, or 1 if pollfd becomes active. */
58 return rc;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110059}
60
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093061LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110062pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport,
63 pldm_tid_t tid,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100064 const void *pldm_msg,
65 size_t msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110066{
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100067 if (!transport || !pldm_msg) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110068 return PLDM_REQUESTER_INVALID_SETUP;
69 }
70
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100071 if (msg_len < sizeof(struct pldm_msg_hdr)) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110072 return PLDM_REQUESTER_NOT_REQ_MSG;
73 }
74
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100075 return transport->send(transport, tid, pldm_msg, msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +110076}
77
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093078LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110079pldm_requester_rc_t pldm_transport_recv_msg(struct pldm_transport *transport,
Rashmica Gupta24576292023-07-31 14:02:41 +100080 pldm_tid_t *tid, void **pldm_msg,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100081 size_t *msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110082{
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100083 if (!transport || !msg_len) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110084 return PLDM_REQUESTER_INVALID_SETUP;
85 }
86
87 pldm_requester_rc_t rc =
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100088 transport->recv(transport, tid, pldm_msg, msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +110089 if (rc != PLDM_REQUESTER_SUCCESS) {
90 return rc;
91 }
92
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100093 if (*msg_len < sizeof(struct pldm_msg_hdr)) {
94 free(*pldm_msg);
95 *pldm_msg = NULL;
Rashmica Gupta0411b712023-05-30 16:43:08 +100096 return PLDM_REQUESTER_INVALID_RECV_LEN;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110097 }
Rashmica Guptac1b66f42022-12-09 16:24:45 +110098 return PLDM_REQUESTER_SUCCESS;
99}
100
Dung Caoabaf61f2022-11-15 20:48:50 +0700101static void timespec_to_timeval(const struct timespec *ts, struct timeval *tv)
102{
103 tv->tv_sec = ts->tv_sec;
104 tv->tv_usec = ts->tv_nsec / 1000;
105}
106
107/* Overflow safety must be upheld before call */
108static long timeval_to_msec(const struct timeval *tv)
109{
110 return tv->tv_sec * 1000 + tv->tv_usec / 1000;
111}
112
113/* If calculations on `tv` don't overflow then operations on derived
114 * intervals can't either.
115 */
116static bool timeval_is_valid(const struct timeval *tv)
117{
118 if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
119 return false;
120 }
121
122 if (tv->tv_sec > (LONG_MAX - tv->tv_usec / 1000) / 1000) {
123 return false;
124 }
125
126 return true;
127}
128
129static int clock_gettimeval(clockid_t clockid, struct timeval *tv)
130{
131 struct timespec now;
132 int rc;
133
134 rc = clock_gettime(clockid, &now);
135 if (rc < 0) {
136 return rc;
137 }
138
139 timespec_to_timeval(&now, tv);
140
141 return 0;
142}
143
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930144LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100145pldm_requester_rc_t
146pldm_transport_send_recv_msg(struct pldm_transport *transport, pldm_tid_t tid,
147 const void *pldm_req_msg, size_t req_msg_len,
148 void **pldm_resp_msg, size_t *resp_msg_len)
149
150{
Dung Caoabaf61f2022-11-15 20:48:50 +0700151 /**
152 * Section "Requirements for requesters" in DSP0240, define the Time-out
153 * waiting for a response of the requester.
154 * PT2max = PT3min - 2*PT4max = 4800ms
155 */
156 static const struct timeval max_response_interval = {
157 .tv_sec = 4, .tv_usec = 800000
158 };
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700159 const struct pldm_msg_hdr *req_hdr;
Dung Caoabaf61f2022-11-15 20:48:50 +0700160 struct timeval remaining;
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700161 pldm_requester_rc_t rc;
Dung Caoabaf61f2022-11-15 20:48:50 +0700162 struct timeval now;
163 struct timeval end;
Dung Caoabaf61f2022-11-15 20:48:50 +0700164 int ret;
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700165 int cnt;
Dung Caoabaf61f2022-11-15 20:48:50 +0700166
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700167 if (req_msg_len < sizeof(*req_hdr) || !resp_msg_len) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100168 return PLDM_REQUESTER_INVALID_SETUP;
169 }
170
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700171 req_hdr = pldm_req_msg;
172
Andrew Jeffery486d85d2023-08-31 11:12:08 +0930173 if (!req_hdr->request) {
174 return PLDM_REQUESTER_NOT_REQ_MSG;
175 }
176
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700177 for (cnt = 0; cnt <= (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS &&
178 pldm_transport_poll(transport, 0) == 1;
179 cnt++) {
Rashmica Gupta24576292023-07-31 14:02:41 +1000180 pldm_tid_t l_tid;
181 rc = pldm_transport_recv_msg(transport, &l_tid, pldm_resp_msg,
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700182 resp_msg_len);
183 if (rc == PLDM_REQUESTER_SUCCESS) {
184 /* This isn't the message we wanted */
185 free(*pldm_resp_msg);
186 }
187 }
188 if (cnt == (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS) {
189 return PLDM_REQUESTER_TRANSPORT_BUSY;
190 }
191
Dung Caoabaf61f2022-11-15 20:48:50 +0700192 rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100193 if (rc != PLDM_REQUESTER_SUCCESS) {
194 return rc;
195 }
196
Dung Caoabaf61f2022-11-15 20:48:50 +0700197 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
198 if (ret < 0) {
199 return PLDM_REQUESTER_POLL_FAIL;
200 }
201
202 timeradd(&now, &max_response_interval, &end);
203 if (!timeval_is_valid(&end)) {
204 return PLDM_REQUESTER_POLL_FAIL;
205 }
206
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930207 while (timercmp(&now, &end, <)) {
208 pldm_tid_t src_tid;
209
Dung Caoabaf61f2022-11-15 20:48:50 +0700210 timersub(&end, &now, &remaining);
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930211
Dung Caoabaf61f2022-11-15 20:48:50 +0700212 /* 0 <= `timeval_to_msec()` <= 4800, and 4800 < INT_MAX */
Andrew Jeffery3380a6c2023-07-12 13:57:33 +0930213 ret = pldm_transport_poll(transport,
214 (int)(timeval_to_msec(&remaining)));
215 if (ret <= 0) {
Andrew Jeffery1184f092023-09-22 17:44:46 +0930216 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100217 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700218
Andrew Jeffery50382682023-09-22 17:46:54 +0930219 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
220 if (ret < 0) {
221 return PLDM_REQUESTER_POLL_FAIL;
222 }
223
Rashmica Gupta24576292023-07-31 14:02:41 +1000224 rc = pldm_transport_recv_msg(transport, &src_tid, pldm_resp_msg,
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100225 resp_msg_len);
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930226 if (rc != PLDM_REQUESTER_SUCCESS) {
227 continue;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100228 }
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930229
230 if (src_tid != tid || !pldm_msg_hdr_correlate_response(
231 pldm_req_msg, *pldm_resp_msg)) {
232 free(*pldm_resp_msg);
233 continue;
234 }
235
236 return PLDM_REQUESTER_SUCCESS;
237 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700238
239 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100240}