blob: dd9a4bd910e1d4fbc7601da9cf875df6116e8188 [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
Rashmica Guptac1b66f42022-12-09 16:24:45 +110033pldm_requester_rc_t pldm_transport_poll(struct pldm_transport *transport,
34 int timeout)
35{
36 struct pollfd pollfd;
37 int rc = 0;
38 if (!transport) {
39 return PLDM_REQUESTER_INVALID_SETUP;
40 }
41 if (!transport->init_pollfd) {
42 return PLDM_REQUESTER_SUCCESS;
43 }
44
Andrew Jeffery98085fa2023-07-19 00:35:42 +093045 rc = transport->init_pollfd(transport, &pollfd);
46 if (rc < 0) {
47 return PLDM_REQUESTER_POLL_FAIL;
48 }
49
Rashmica Guptac1b66f42022-12-09 16:24:45 +110050 rc = poll(&pollfd, 1, timeout);
51 if (rc < 0) {
52 return PLDM_REQUESTER_POLL_FAIL;
53 }
54
55 return PLDM_REQUESTER_SUCCESS;
56}
57
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093058LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110059pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport,
60 pldm_tid_t tid,
61 const void *pldm_req_msg,
62 size_t req_msg_len)
63{
64 if (!transport || !pldm_req_msg) {
65 return PLDM_REQUESTER_INVALID_SETUP;
66 }
67
68 if (req_msg_len < sizeof(struct pldm_msg_hdr)) {
69 return PLDM_REQUESTER_NOT_REQ_MSG;
70 }
71
Rashmica Guptac1b66f42022-12-09 16:24:45 +110072 return transport->send(transport, tid, pldm_req_msg, req_msg_len);
73}
74
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093075LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110076pldm_requester_rc_t pldm_transport_recv_msg(struct pldm_transport *transport,
77 pldm_tid_t tid,
78 void **pldm_resp_msg,
79 size_t *resp_msg_len)
80{
81 if (!transport || !resp_msg_len) {
82 return PLDM_REQUESTER_INVALID_SETUP;
83 }
84
85 pldm_requester_rc_t rc =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093086 transport->recv(transport, tid, pldm_resp_msg, resp_msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +110087 if (rc != PLDM_REQUESTER_SUCCESS) {
88 return rc;
89 }
90
Rashmica Gupta0411b712023-05-30 16:43:08 +100091 if (*resp_msg_len < sizeof(struct pldm_msg_hdr)) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +110092 free(*pldm_resp_msg);
93 *pldm_resp_msg = NULL;
Rashmica Gupta0411b712023-05-30 16:43:08 +100094 return PLDM_REQUESTER_INVALID_RECV_LEN;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110095 }
Rashmica Guptac1b66f42022-12-09 16:24:45 +110096 return PLDM_REQUESTER_SUCCESS;
97}
98
Dung Caoabaf61f2022-11-15 20:48:50 +070099static void timespec_to_timeval(const struct timespec *ts, struct timeval *tv)
100{
101 tv->tv_sec = ts->tv_sec;
102 tv->tv_usec = ts->tv_nsec / 1000;
103}
104
105/* Overflow safety must be upheld before call */
106static long timeval_to_msec(const struct timeval *tv)
107{
108 return tv->tv_sec * 1000 + tv->tv_usec / 1000;
109}
110
111/* If calculations on `tv` don't overflow then operations on derived
112 * intervals can't either.
113 */
114static bool timeval_is_valid(const struct timeval *tv)
115{
116 if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
117 return false;
118 }
119
120 if (tv->tv_sec > (LONG_MAX - tv->tv_usec / 1000) / 1000) {
121 return false;
122 }
123
124 return true;
125}
126
127static int clock_gettimeval(clockid_t clockid, struct timeval *tv)
128{
129 struct timespec now;
130 int rc;
131
132 rc = clock_gettime(clockid, &now);
133 if (rc < 0) {
134 return rc;
135 }
136
137 timespec_to_timeval(&now, tv);
138
139 return 0;
140}
141
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930142LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100143pldm_requester_rc_t
144pldm_transport_send_recv_msg(struct pldm_transport *transport, pldm_tid_t tid,
145 const void *pldm_req_msg, size_t req_msg_len,
146 void **pldm_resp_msg, size_t *resp_msg_len)
147
148{
Dung Caoabaf61f2022-11-15 20:48:50 +0700149 /**
150 * Section "Requirements for requesters" in DSP0240, define the Time-out
151 * waiting for a response of the requester.
152 * PT2max = PT3min - 2*PT4max = 4800ms
153 */
154 static const struct timeval max_response_interval = {
155 .tv_sec = 4, .tv_usec = 800000
156 };
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700157 const struct pldm_msg_hdr *req_hdr;
Dung Caoabaf61f2022-11-15 20:48:50 +0700158 struct timeval remaining;
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700159 pldm_requester_rc_t rc;
Dung Caoabaf61f2022-11-15 20:48:50 +0700160 struct timeval now;
161 struct timeval end;
Dung Caoabaf61f2022-11-15 20:48:50 +0700162 int ret;
163
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700164 if (req_msg_len < sizeof(*req_hdr) || !resp_msg_len) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100165 return PLDM_REQUESTER_INVALID_SETUP;
166 }
167
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700168 req_hdr = pldm_req_msg;
169
Dung Caoabaf61f2022-11-15 20:48:50 +0700170 rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100171 if (rc != PLDM_REQUESTER_SUCCESS) {
172 return rc;
173 }
174
Dung Caoabaf61f2022-11-15 20:48:50 +0700175 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
176 if (ret < 0) {
177 return PLDM_REQUESTER_POLL_FAIL;
178 }
179
180 timeradd(&now, &max_response_interval, &end);
181 if (!timeval_is_valid(&end)) {
182 return PLDM_REQUESTER_POLL_FAIL;
183 }
184
185 do {
186 timersub(&end, &now, &remaining);
187 /* 0 <= `timeval_to_msec()` <= 4800, and 4800 < INT_MAX */
188 rc = pldm_transport_poll(transport,
189 (int)(timeval_to_msec(&remaining)));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100190 if (rc != PLDM_REQUESTER_SUCCESS) {
Dung Caoabaf61f2022-11-15 20:48:50 +0700191 return rc;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100192 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700193
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100194 rc = pldm_transport_recv_msg(transport, tid, pldm_resp_msg,
195 resp_msg_len);
196 if (rc == PLDM_REQUESTER_SUCCESS) {
Thu Nguyenb01fb1c2023-05-28 09:16:46 +0700197 const struct pldm_msg_hdr *resp_hdr = *pldm_resp_msg;
198 if (req_hdr->instance_id == resp_hdr->instance_id) {
199 return rc;
200 }
201
202 /* This isn't the message we wanted */
203 free(*pldm_resp_msg);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100204 }
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100205
Dung Caoabaf61f2022-11-15 20:48:50 +0700206 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
207 if (ret < 0) {
208 return PLDM_REQUESTER_POLL_FAIL;
209 }
210 } while (!timercmp(&now, &end, <));
211
212 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100213}