blob: d4608a758136af901311bb60f9854c3b66b1f530 [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
32pldm_requester_rc_t pldm_transport_poll(struct pldm_transport *transport,
33 int timeout)
34{
35 struct pollfd pollfd;
36 int rc = 0;
37 if (!transport) {
38 return PLDM_REQUESTER_INVALID_SETUP;
39 }
40 if (!transport->init_pollfd) {
41 return PLDM_REQUESTER_SUCCESS;
42 }
43
44 transport->init_pollfd(transport, &pollfd);
45 rc = poll(&pollfd, 1, timeout);
46 if (rc < 0) {
47 return PLDM_REQUESTER_POLL_FAIL;
48 }
49
50 return PLDM_REQUESTER_SUCCESS;
51}
52
53pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport,
54 pldm_tid_t tid,
55 const void *pldm_req_msg,
56 size_t req_msg_len)
57{
58 if (!transport || !pldm_req_msg) {
59 return PLDM_REQUESTER_INVALID_SETUP;
60 }
61
62 if (req_msg_len < sizeof(struct pldm_msg_hdr)) {
63 return PLDM_REQUESTER_NOT_REQ_MSG;
64 }
65
66 const struct pldm_msg_hdr *hdr = pldm_req_msg;
67 if (!hdr->request) {
68 return PLDM_REQUESTER_NOT_REQ_MSG;
69 }
70
71 return transport->send(transport, tid, pldm_req_msg, req_msg_len);
72}
73
74pldm_requester_rc_t pldm_transport_recv_msg(struct pldm_transport *transport,
75 pldm_tid_t tid,
76 void **pldm_resp_msg,
77 size_t *resp_msg_len)
78{
79 if (!transport || !resp_msg_len) {
80 return PLDM_REQUESTER_INVALID_SETUP;
81 }
82
83 pldm_requester_rc_t rc =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093084 transport->recv(transport, tid, pldm_resp_msg, resp_msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +110085 if (rc != PLDM_REQUESTER_SUCCESS) {
86 return rc;
87 }
88
89 struct pldm_msg_hdr *hdr = *pldm_resp_msg;
90 if (hdr->request || hdr->datagram) {
91 free(*pldm_resp_msg);
92 *pldm_resp_msg = NULL;
93 return PLDM_REQUESTER_NOT_RESP_MSG;
94 }
95
96 uint8_t pldm_rc = 0;
97 if (*resp_msg_len < (sizeof(struct pldm_msg_hdr) + sizeof(pldm_rc))) {
98 free(*pldm_resp_msg);
99 *pldm_resp_msg = NULL;
100 return PLDM_REQUESTER_RESP_MSG_TOO_SMALL;
101 }
102
103 return PLDM_REQUESTER_SUCCESS;
104}
105
Dung Caoabaf61f2022-11-15 20:48:50 +0700106static void timespec_to_timeval(const struct timespec *ts, struct timeval *tv)
107{
108 tv->tv_sec = ts->tv_sec;
109 tv->tv_usec = ts->tv_nsec / 1000;
110}
111
112/* Overflow safety must be upheld before call */
113static long timeval_to_msec(const struct timeval *tv)
114{
115 return tv->tv_sec * 1000 + tv->tv_usec / 1000;
116}
117
118/* If calculations on `tv` don't overflow then operations on derived
119 * intervals can't either.
120 */
121static bool timeval_is_valid(const struct timeval *tv)
122{
123 if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
124 return false;
125 }
126
127 if (tv->tv_sec > (LONG_MAX - tv->tv_usec / 1000) / 1000) {
128 return false;
129 }
130
131 return true;
132}
133
134static int clock_gettimeval(clockid_t clockid, struct timeval *tv)
135{
136 struct timespec now;
137 int rc;
138
139 rc = clock_gettime(clockid, &now);
140 if (rc < 0) {
141 return rc;
142 }
143
144 timespec_to_timeval(&now, tv);
145
146 return 0;
147}
148
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100149pldm_requester_rc_t
150pldm_transport_send_recv_msg(struct pldm_transport *transport, pldm_tid_t tid,
151 const void *pldm_req_msg, size_t req_msg_len,
152 void **pldm_resp_msg, size_t *resp_msg_len)
153
154{
Dung Caoabaf61f2022-11-15 20:48:50 +0700155 /**
156 * Section "Requirements for requesters" in DSP0240, define the Time-out
157 * waiting for a response of the requester.
158 * PT2max = PT3min - 2*PT4max = 4800ms
159 */
160 static const struct timeval max_response_interval = {
161 .tv_sec = 4, .tv_usec = 800000
162 };
163 struct timeval remaining;
164 struct timeval now;
165 struct timeval end;
166 pldm_requester_rc_t rc;
167 int ret;
168
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100169 if (!resp_msg_len) {
170 return PLDM_REQUESTER_INVALID_SETUP;
171 }
172
Dung Caoabaf61f2022-11-15 20:48:50 +0700173 rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100174 if (rc != PLDM_REQUESTER_SUCCESS) {
175 return rc;
176 }
177
Dung Caoabaf61f2022-11-15 20:48:50 +0700178 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
179 if (ret < 0) {
180 return PLDM_REQUESTER_POLL_FAIL;
181 }
182
183 timeradd(&now, &max_response_interval, &end);
184 if (!timeval_is_valid(&end)) {
185 return PLDM_REQUESTER_POLL_FAIL;
186 }
187
188 do {
189 timersub(&end, &now, &remaining);
190 /* 0 <= `timeval_to_msec()` <= 4800, and 4800 < INT_MAX */
191 rc = pldm_transport_poll(transport,
192 (int)(timeval_to_msec(&remaining)));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100193 if (rc != PLDM_REQUESTER_SUCCESS) {
Dung Caoabaf61f2022-11-15 20:48:50 +0700194 return rc;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100195 }
Dung Caoabaf61f2022-11-15 20:48:50 +0700196
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100197 rc = pldm_transport_recv_msg(transport, tid, pldm_resp_msg,
198 resp_msg_len);
199 if (rc == PLDM_REQUESTER_SUCCESS) {
Dung Caoabaf61f2022-11-15 20:48:50 +0700200 return rc;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100201 }
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100202
Dung Caoabaf61f2022-11-15 20:48:50 +0700203 ret = clock_gettimeval(CLOCK_MONOTONIC, &now);
204 if (ret < 0) {
205 return PLDM_REQUESTER_POLL_FAIL;
206 }
207 } while (!timercmp(&now, &end, <));
208
209 return PLDM_REQUESTER_RECV_FAIL;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100210}