blob: 0cbef299a2cefeab1c215172eb2e80916af7c0d6 [file] [log] [blame]
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301#include "config.h"
Rashmica Guptac1b66f42022-12-09 16:24:45 +11002#include "libpldm/transport.h"
3#include "base.h"
4#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 Jeffery9d2a1c62023-06-05 13:02:16 +093033LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110034pldm_requester_rc_t pldm_transport_poll(struct pldm_transport *transport,
35 int timeout)
36{
37 struct pollfd pollfd;
38 int rc = 0;
39 if (!transport) {
40 return PLDM_REQUESTER_INVALID_SETUP;
41 }
42 if (!transport->init_pollfd) {
43 return PLDM_REQUESTER_SUCCESS;
44 }
45
46 transport->init_pollfd(transport, &pollfd);
47 rc = poll(&pollfd, 1, timeout);
48 if (rc < 0) {
49 return PLDM_REQUESTER_POLL_FAIL;
50 }
51
52 return PLDM_REQUESTER_SUCCESS;
53}
54
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093055LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110056pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport,
57 pldm_tid_t tid,
58 const void *pldm_req_msg,
59 size_t req_msg_len)
60{
61 if (!transport || !pldm_req_msg) {
62 return PLDM_REQUESTER_INVALID_SETUP;
63 }
64
65 if (req_msg_len < sizeof(struct pldm_msg_hdr)) {
66 return PLDM_REQUESTER_NOT_REQ_MSG;
67 }
68
69 const struct pldm_msg_hdr *hdr = pldm_req_msg;
70 if (!hdr->request) {
71 return PLDM_REQUESTER_NOT_REQ_MSG;
72 }
73
74 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
93 struct pldm_msg_hdr *hdr = *pldm_resp_msg;
94 if (hdr->request || hdr->datagram) {
95 free(*pldm_resp_msg);
96 *pldm_resp_msg = NULL;
97 return PLDM_REQUESTER_NOT_RESP_MSG;
98 }
99
100 uint8_t pldm_rc = 0;
101 if (*resp_msg_len < (sizeof(struct pldm_msg_hdr) + sizeof(pldm_rc))) {
102 free(*pldm_resp_msg);
103 *pldm_resp_msg = NULL;
104 return PLDM_REQUESTER_RESP_MSG_TOO_SMALL;
105 }
106
107 return PLDM_REQUESTER_SUCCESS;
108}
109
Dung Caoabaf61f2022-11-15 20:48:50 +0700110static void timespec_to_timeval(const struct timespec *ts, struct timeval *tv)
111{
112 tv->tv_sec = ts->tv_sec;
113 tv->tv_usec = ts->tv_nsec / 1000;
114}
115
116/* Overflow safety must be upheld before call */
117static long timeval_to_msec(const struct timeval *tv)
118{
119 return tv->tv_sec * 1000 + tv->tv_usec / 1000;
120}
121
122/* If calculations on `tv` don't overflow then operations on derived
123 * intervals can't either.
124 */
125static bool timeval_is_valid(const struct timeval *tv)
126{
127 if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
128 return false;
129 }
130
131 if (tv->tv_sec > (LONG_MAX - tv->tv_usec / 1000) / 1000) {
132 return false;
133 }
134
135 return true;
136}
137
138static int clock_gettimeval(clockid_t clockid, struct timeval *tv)
139{
140 struct timespec now;
141 int rc;
142
143 rc = clock_gettime(clockid, &now);
144 if (rc < 0) {
145 return rc;
146 }
147
148 timespec_to_timeval(&now, tv);
149
150 return 0;
151}
152
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930153LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100154pldm_requester_rc_t
155pldm_transport_send_recv_msg(struct pldm_transport *transport, pldm_tid_t tid,
156 const void *pldm_req_msg, size_t req_msg_len,
157 void **pldm_resp_msg, size_t *resp_msg_len)
158
159{
Dung Caoabaf61f2022-11-15 20:48:50 +0700160 /**
161 * Section "Requirements for requesters" in DSP0240, define the Time-out
162 * waiting for a response of the requester.
163 * PT2max = PT3min - 2*PT4max = 4800ms
164 */
165 static const struct timeval max_response_interval = {
166 .tv_sec = 4, .tv_usec = 800000
167 };
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700168 const struct pldm_msg_hdr *req_hdr;
Dung Caoabaf61f2022-11-15 20:48:50 +0700169 struct timeval remaining;
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700170 pldm_requester_rc_t rc;
Dung Caoabaf61f2022-11-15 20:48:50 +0700171 struct timeval now;
172 struct timeval end;
Dung Caoabaf61f2022-11-15 20:48:50 +0700173 int ret;
174
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700175 if (req_msg_len < sizeof(*req_hdr) || !resp_msg_len) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100176 return PLDM_REQUESTER_INVALID_SETUP;
177 }
178
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700179 req_hdr = pldm_req_msg;
180
Dung Caoabaf61f2022-11-15 20:48:50 +0700181 rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100182 if (rc != PLDM_REQUESTER_SUCCESS) {
183 return rc;
184 }
185
Dung Caoabaf61f2022-11-15 20:48:50 +0700186 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
187 if (ret < 0) {
188 return PLDM_REQUESTER_POLL_FAIL;
189 }
190
191 timeradd(&now, &max_response_interval, &end);
192 if (!timeval_is_valid(&end)) {
193 return PLDM_REQUESTER_POLL_FAIL;
194 }
195
196 do {
197 timersub(&end, &now, &remaining);
198 /* 0 <= `timeval_to_msec()` <= 4800, and 4800 < INT_MAX */
199 rc = pldm_transport_poll(transport,
200 (int)(timeval_to_msec(&remaining)));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100201 if (rc != PLDM_REQUESTER_SUCCESS) {
Dung Caoabaf61f2022-11-15 20:48:50 +0700202 return rc;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100203 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700204
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100205 rc = pldm_transport_recv_msg(transport, tid, pldm_resp_msg,
206 resp_msg_len);
207 if (rc == PLDM_REQUESTER_SUCCESS) {
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700208 const struct pldm_msg_hdr *resp_hdr = *pldm_resp_msg;
209 if (req_hdr->instance_id == resp_hdr->instance_id) {
210 return rc;
211 }
212
213 /* This isn't the message we wanted */
214 free(*pldm_resp_msg);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100215 }
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100216
Dung Caoabaf61f2022-11-15 20:48:50 +0700217 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
218 if (ret < 0) {
219 return PLDM_REQUESTER_POLL_FAIL;
220 }
221 } while (!timercmp(&now, &end, <));
222
223 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100224}