blob: 24c264ade158410d56e6c7ea43e2711465dbafad [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jeffery860a43d2024-08-23 01:21:58 +00002#include "compiler.h"
Rashmica Guptac1b66f42022-12-09 16:24:45 +11003#include "transport.h"
4
Andrew Jefferyefb40062023-11-10 13:48:39 +10305#include <libpldm/transport.h>
6#include <libpldm/base.h>
7#include <libpldm/pldm.h>
8
Dung Caoabaf61f2022-11-15 20:48:50 +07009#include <errno.h>
10#include <limits.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110011#ifdef PLDM_HAS_POLL
12#include <poll.h>
13#endif
Dung Caoabaf61f2022-11-15 20:48:50 +070014#include <stdbool.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110015#include <stdlib.h>
Dung Caoabaf61f2022-11-15 20:48:50 +070016#include <sys/time.h>
17#include <time.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110018#include <unistd.h>
19
20#ifndef PLDM_HAS_POLL
21struct pollfd {
22 int fd; /* file descriptor */
23 short events; /* requested events */
24 short revents; /* returned events */
25};
26
Andrew Jeffery860a43d2024-08-23 01:21:58 +000027static inline int poll(struct pollfd *fds LIBPLDM_CC_UNUSED,
28 int nfds LIBPLDM_CC_UNUSED,
29 int timeout LIBPLDM_CC_UNUSED)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110030{
31 return 0;
32}
33#endif
34
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093035LIBPLDM_ABI_STABLE
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093036int pldm_transport_poll(struct pldm_transport *transport, int timeout)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110037{
38 struct pollfd pollfd;
39 int rc = 0;
40 if (!transport) {
41 return PLDM_REQUESTER_INVALID_SETUP;
42 }
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093043
44 /* If polling isn't supported then always indicate the transport is ready */
Rashmica Guptac1b66f42022-12-09 16:24:45 +110045 if (!transport->init_pollfd) {
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093046 return 1;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110047 }
48
Andrew Jeffery98085fa2023-07-19 00:35:42 +093049 rc = transport->init_pollfd(transport, &pollfd);
50 if (rc < 0) {
51 return PLDM_REQUESTER_POLL_FAIL;
52 }
53
Rashmica Guptac1b66f42022-12-09 16:24:45 +110054 rc = poll(&pollfd, 1, timeout);
55 if (rc < 0) {
56 return PLDM_REQUESTER_POLL_FAIL;
57 }
58
Andrew Jeffery3380a6c2023-07-12 13:57:33 +093059 /* rc is 0 if poll(2) times out, or 1 if pollfd becomes active. */
60 return rc;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110061}
62
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093063LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110064pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport,
65 pldm_tid_t tid,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100066 const void *pldm_msg,
67 size_t msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110068{
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100069 if (!transport || !pldm_msg) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110070 return PLDM_REQUESTER_INVALID_SETUP;
71 }
72
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100073 if (msg_len < sizeof(struct pldm_msg_hdr)) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110074 return PLDM_REQUESTER_NOT_REQ_MSG;
75 }
76
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100077 return transport->send(transport, tid, pldm_msg, msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +110078}
79
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093080LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110081pldm_requester_rc_t pldm_transport_recv_msg(struct pldm_transport *transport,
Rashmica Gupta24576292023-07-31 14:02:41 +100082 pldm_tid_t *tid, void **pldm_msg,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100083 size_t *msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +110084{
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100085 if (!transport || !msg_len) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110086 return PLDM_REQUESTER_INVALID_SETUP;
87 }
88
89 pldm_requester_rc_t rc =
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100090 transport->recv(transport, tid, pldm_msg, msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +110091 if (rc != PLDM_REQUESTER_SUCCESS) {
92 return rc;
93 }
94
Rashmica Guptaf1ebde42023-07-31 14:17:57 +100095 if (*msg_len < sizeof(struct pldm_msg_hdr)) {
96 free(*pldm_msg);
97 *pldm_msg = NULL;
Rashmica Gupta0411b712023-05-30 16:43:08 +100098 return PLDM_REQUESTER_INVALID_RECV_LEN;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110099 }
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100100 return PLDM_REQUESTER_SUCCESS;
101}
102
Dung Caoabaf61f2022-11-15 20:48:50 +0700103static void timespec_to_timeval(const struct timespec *ts, struct timeval *tv)
104{
105 tv->tv_sec = ts->tv_sec;
106 tv->tv_usec = ts->tv_nsec / 1000;
107}
108
109/* Overflow safety must be upheld before call */
110static long timeval_to_msec(const struct timeval *tv)
111{
112 return tv->tv_sec * 1000 + tv->tv_usec / 1000;
113}
114
115/* If calculations on `tv` don't overflow then operations on derived
116 * intervals can't either.
117 */
118static bool timeval_is_valid(const struct timeval *tv)
119{
120 if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
121 return false;
122 }
123
124 if (tv->tv_sec > (LONG_MAX - tv->tv_usec / 1000) / 1000) {
125 return false;
126 }
127
128 return true;
129}
130
131static int clock_gettimeval(clockid_t clockid, struct timeval *tv)
132{
133 struct timespec now;
134 int rc;
135
136 rc = clock_gettime(clockid, &now);
137 if (rc < 0) {
138 return rc;
139 }
140
141 timespec_to_timeval(&now, tv);
142
143 return 0;
144}
145
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930146LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100147pldm_requester_rc_t
148pldm_transport_send_recv_msg(struct pldm_transport *transport, pldm_tid_t tid,
149 const void *pldm_req_msg, size_t req_msg_len,
150 void **pldm_resp_msg, size_t *resp_msg_len)
151
152{
Dung Caoabaf61f2022-11-15 20:48:50 +0700153 /**
154 * Section "Requirements for requesters" in DSP0240, define the Time-out
155 * waiting for a response of the requester.
156 * PT2max = PT3min - 2*PT4max = 4800ms
157 */
158 static const struct timeval max_response_interval = {
159 .tv_sec = 4, .tv_usec = 800000
160 };
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700161 const struct pldm_msg_hdr *req_hdr;
Dung Caoabaf61f2022-11-15 20:48:50 +0700162 struct timeval remaining;
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700163 pldm_requester_rc_t rc;
Dung Caoabaf61f2022-11-15 20:48:50 +0700164 struct timeval now;
165 struct timeval end;
Dung Caoabaf61f2022-11-15 20:48:50 +0700166 int ret;
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700167 int cnt;
Dung Caoabaf61f2022-11-15 20:48:50 +0700168
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700169 if (req_msg_len < sizeof(*req_hdr) || !resp_msg_len) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100170 return PLDM_REQUESTER_INVALID_SETUP;
171 }
172
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700173 req_hdr = pldm_req_msg;
174
Andrew Jeffery486d85d2023-08-31 11:12:08 +0930175 if (!req_hdr->request) {
176 return PLDM_REQUESTER_NOT_REQ_MSG;
177 }
178
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700179 for (cnt = 0; cnt <= (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS &&
180 pldm_transport_poll(transport, 0) == 1;
181 cnt++) {
Rashmica Gupta24576292023-07-31 14:02:41 +1000182 pldm_tid_t l_tid;
183 rc = pldm_transport_recv_msg(transport, &l_tid, pldm_resp_msg,
Thu Nguyenf56e4dc2023-07-24 10:39:47 +0700184 resp_msg_len);
185 if (rc == PLDM_REQUESTER_SUCCESS) {
186 /* This isn't the message we wanted */
187 free(*pldm_resp_msg);
188 }
189 }
190 if (cnt == (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS) {
191 return PLDM_REQUESTER_TRANSPORT_BUSY;
192 }
193
Dung Caoabaf61f2022-11-15 20:48:50 +0700194 rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100195 if (rc != PLDM_REQUESTER_SUCCESS) {
196 return rc;
197 }
198
Dung Caoabaf61f2022-11-15 20:48:50 +0700199 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
200 if (ret < 0) {
201 return PLDM_REQUESTER_POLL_FAIL;
202 }
203
204 timeradd(&now, &max_response_interval, &end);
205 if (!timeval_is_valid(&end)) {
206 return PLDM_REQUESTER_POLL_FAIL;
207 }
208
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930209 while (timercmp(&now, &end, <)) {
210 pldm_tid_t src_tid;
211
Dung Caoabaf61f2022-11-15 20:48:50 +0700212 timersub(&end, &now, &remaining);
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930213
Dung Caoabaf61f2022-11-15 20:48:50 +0700214 /* 0 <= `timeval_to_msec()` <= 4800, and 4800 < INT_MAX */
Andrew Jeffery3380a6c2023-07-12 13:57:33 +0930215 ret = pldm_transport_poll(transport,
216 (int)(timeval_to_msec(&remaining)));
217 if (ret <= 0) {
Andrew Jeffery1184f092023-09-22 17:44:46 +0930218 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100219 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700220
Andrew Jeffery50382682023-09-22 17:46:54 +0930221 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
222 if (ret < 0) {
223 return PLDM_REQUESTER_POLL_FAIL;
224 }
225
Rashmica Gupta24576292023-07-31 14:02:41 +1000226 rc = pldm_transport_recv_msg(transport, &src_tid, pldm_resp_msg,
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100227 resp_msg_len);
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930228 if (rc != PLDM_REQUESTER_SUCCESS) {
229 continue;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100230 }
Andrew Jeffery1d0e2d42023-09-22 18:02:44 +0930231
232 if (src_tid != tid || !pldm_msg_hdr_correlate_response(
233 pldm_req_msg, *pldm_resp_msg)) {
234 free(*pldm_resp_msg);
235 continue;
236 }
237
238 return PLDM_REQUESTER_SUCCESS;
239 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700240
241 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100242}