blob: 919cc61380f630d792402da37a93482bf73d8718 [file] [log] [blame]
Rashmica Guptac1b66f42022-12-09 16:24:45 +11001#include "libpldm/transport.h"
2#include "base.h"
3#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 Jeffery9d2a1c62023-06-05 13:02:16 +093032LIBPLDM_ABI_TESTING
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 Jeffery9d2a1c62023-06-05 13:02:16 +093060LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110061pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport,
62 pldm_tid_t tid,
63 const void *pldm_req_msg,
64 size_t req_msg_len)
65{
66 if (!transport || !pldm_req_msg) {
67 return PLDM_REQUESTER_INVALID_SETUP;
68 }
69
70 if (req_msg_len < sizeof(struct pldm_msg_hdr)) {
71 return PLDM_REQUESTER_NOT_REQ_MSG;
72 }
73
Rashmica Guptac1b66f42022-12-09 16:24:45 +110074 return transport->send(transport, tid, pldm_req_msg, req_msg_len);
75}
76
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093077LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110078pldm_requester_rc_t pldm_transport_recv_msg(struct pldm_transport *transport,
79 pldm_tid_t tid,
80 void **pldm_resp_msg,
81 size_t *resp_msg_len)
82{
83 if (!transport || !resp_msg_len) {
84 return PLDM_REQUESTER_INVALID_SETUP;
85 }
86
87 pldm_requester_rc_t rc =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093088 transport->recv(transport, tid, pldm_resp_msg, resp_msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +110089 if (rc != PLDM_REQUESTER_SUCCESS) {
90 return rc;
91 }
92
Rashmica Gupta0411b712023-05-30 16:43:08 +100093 if (*resp_msg_len < sizeof(struct pldm_msg_hdr)) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110094 free(*pldm_resp_msg);
95 *pldm_resp_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 Jeffery9d2a1c62023-06-05 13:02:16 +0930144LIBPLDM_ABI_TESTING
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;
165
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
Dung Caoabaf61f2022-11-15 20:48:50 +0700172 rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100173 if (rc != PLDM_REQUESTER_SUCCESS) {
174 return rc;
175 }
176
Dung Caoabaf61f2022-11-15 20:48:50 +0700177 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
178 if (ret < 0) {
179 return PLDM_REQUESTER_POLL_FAIL;
180 }
181
182 timeradd(&now, &max_response_interval, &end);
183 if (!timeval_is_valid(&end)) {
184 return PLDM_REQUESTER_POLL_FAIL;
185 }
186
187 do {
188 timersub(&end, &now, &remaining);
189 /* 0 <= `timeval_to_msec()` <= 4800, and 4800 < INT_MAX */
Andrew Jeffery3380a6c2023-07-12 13:57:33 +0930190 ret = pldm_transport_poll(transport,
191 (int)(timeval_to_msec(&remaining)));
192 if (ret <= 0) {
193 break;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100194 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700195
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100196 rc = pldm_transport_recv_msg(transport, tid, pldm_resp_msg,
197 resp_msg_len);
198 if (rc == PLDM_REQUESTER_SUCCESS) {
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700199 const struct pldm_msg_hdr *resp_hdr = *pldm_resp_msg;
200 if (req_hdr->instance_id == resp_hdr->instance_id) {
201 return rc;
202 }
203
204 /* This isn't the message we wanted */
205 free(*pldm_resp_msg);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100206 }
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100207
Dung Caoabaf61f2022-11-15 20:48:50 +0700208 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
209 if (ret < 0) {
210 return PLDM_REQUESTER_POLL_FAIL;
211 }
212 } while (!timercmp(&now, &end, <));
213
214 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100215}