1 #include "libpldm/transport.h" 2 #include "base.h" 3 #include "libpldm/requester/pldm.h" 4 #include "transport.h" 5 6 #include <errno.h> 7 #include <limits.h> 8 #ifdef PLDM_HAS_POLL 9 #include <poll.h> 10 #endif 11 #include <stdbool.h> 12 #include <stdlib.h> 13 #include <sys/time.h> 14 #include <time.h> 15 #include <unistd.h> 16 17 #ifndef PLDM_HAS_POLL 18 struct pollfd { 19 int fd; /* file descriptor */ 20 short events; /* requested events */ 21 short revents; /* returned events */ 22 }; 23 24 static 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 32 LIBPLDM_ABI_TESTING 33 int pldm_transport_poll(struct pldm_transport *transport, int timeout) 34 { 35 struct pollfd pollfd; 36 int rc = 0; 37 if (!transport) { 38 return PLDM_REQUESTER_INVALID_SETUP; 39 } 40 41 /* If polling isn't supported then always indicate the transport is ready */ 42 if (!transport->init_pollfd) { 43 return 1; 44 } 45 46 rc = transport->init_pollfd(transport, &pollfd); 47 if (rc < 0) { 48 return PLDM_REQUESTER_POLL_FAIL; 49 } 50 51 rc = poll(&pollfd, 1, timeout); 52 if (rc < 0) { 53 return PLDM_REQUESTER_POLL_FAIL; 54 } 55 56 /* rc is 0 if poll(2) times out, or 1 if pollfd becomes active. */ 57 return rc; 58 } 59 60 LIBPLDM_ABI_TESTING 61 pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport, 62 pldm_tid_t tid, 63 const void *pldm_msg, 64 size_t msg_len) 65 { 66 if (!transport || !pldm_msg) { 67 return PLDM_REQUESTER_INVALID_SETUP; 68 } 69 70 if (msg_len < sizeof(struct pldm_msg_hdr)) { 71 return PLDM_REQUESTER_NOT_REQ_MSG; 72 } 73 74 return transport->send(transport, tid, pldm_msg, msg_len); 75 } 76 77 LIBPLDM_ABI_TESTING 78 pldm_requester_rc_t pldm_transport_recv_msg(struct pldm_transport *transport, 79 pldm_tid_t *tid, void **pldm_msg, 80 size_t *msg_len) 81 { 82 if (!transport || !msg_len) { 83 return PLDM_REQUESTER_INVALID_SETUP; 84 } 85 86 pldm_requester_rc_t rc = 87 transport->recv(transport, tid, pldm_msg, msg_len); 88 if (rc != PLDM_REQUESTER_SUCCESS) { 89 return rc; 90 } 91 92 if (*msg_len < sizeof(struct pldm_msg_hdr)) { 93 free(*pldm_msg); 94 *pldm_msg = NULL; 95 return PLDM_REQUESTER_INVALID_RECV_LEN; 96 } 97 return PLDM_REQUESTER_SUCCESS; 98 } 99 100 static void timespec_to_timeval(const struct timespec *ts, struct timeval *tv) 101 { 102 tv->tv_sec = ts->tv_sec; 103 tv->tv_usec = ts->tv_nsec / 1000; 104 } 105 106 /* Overflow safety must be upheld before call */ 107 static long timeval_to_msec(const struct timeval *tv) 108 { 109 return tv->tv_sec * 1000 + tv->tv_usec / 1000; 110 } 111 112 /* If calculations on `tv` don't overflow then operations on derived 113 * intervals can't either. 114 */ 115 static bool timeval_is_valid(const struct timeval *tv) 116 { 117 if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) { 118 return false; 119 } 120 121 if (tv->tv_sec > (LONG_MAX - tv->tv_usec / 1000) / 1000) { 122 return false; 123 } 124 125 return true; 126 } 127 128 static int clock_gettimeval(clockid_t clockid, struct timeval *tv) 129 { 130 struct timespec now; 131 int rc; 132 133 rc = clock_gettime(clockid, &now); 134 if (rc < 0) { 135 return rc; 136 } 137 138 timespec_to_timeval(&now, tv); 139 140 return 0; 141 } 142 143 LIBPLDM_ABI_TESTING 144 pldm_requester_rc_t 145 pldm_transport_send_recv_msg(struct pldm_transport *transport, pldm_tid_t tid, 146 const void *pldm_req_msg, size_t req_msg_len, 147 void **pldm_resp_msg, size_t *resp_msg_len) 148 149 { 150 /** 151 * Section "Requirements for requesters" in DSP0240, define the Time-out 152 * waiting for a response of the requester. 153 * PT2max = PT3min - 2*PT4max = 4800ms 154 */ 155 static const struct timeval max_response_interval = { 156 .tv_sec = 4, .tv_usec = 800000 157 }; 158 const struct pldm_msg_hdr *req_hdr; 159 struct timeval remaining; 160 pldm_requester_rc_t rc; 161 struct timeval now; 162 struct timeval end; 163 int ret; 164 int cnt; 165 166 if (req_msg_len < sizeof(*req_hdr) || !resp_msg_len) { 167 return PLDM_REQUESTER_INVALID_SETUP; 168 } 169 170 req_hdr = pldm_req_msg; 171 172 for (cnt = 0; cnt <= (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS && 173 pldm_transport_poll(transport, 0) == 1; 174 cnt++) { 175 pldm_tid_t l_tid; 176 rc = pldm_transport_recv_msg(transport, &l_tid, pldm_resp_msg, 177 resp_msg_len); 178 if (rc == PLDM_REQUESTER_SUCCESS) { 179 /* This isn't the message we wanted */ 180 free(*pldm_resp_msg); 181 } 182 } 183 if (cnt == (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS) { 184 return PLDM_REQUESTER_TRANSPORT_BUSY; 185 } 186 187 rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len); 188 if (rc != PLDM_REQUESTER_SUCCESS) { 189 return rc; 190 } 191 192 ret = clock_gettimeval(CLOCK_MONOTONIC, &now); 193 if (ret < 0) { 194 return PLDM_REQUESTER_POLL_FAIL; 195 } 196 197 timeradd(&now, &max_response_interval, &end); 198 if (!timeval_is_valid(&end)) { 199 return PLDM_REQUESTER_POLL_FAIL; 200 } 201 202 do { 203 timersub(&end, &now, &remaining); 204 /* 0 <= `timeval_to_msec()` <= 4800, and 4800 < INT_MAX */ 205 ret = pldm_transport_poll(transport, 206 (int)(timeval_to_msec(&remaining))); 207 if (ret <= 0) { 208 break; 209 } 210 211 pldm_tid_t src_tid; 212 rc = pldm_transport_recv_msg(transport, &src_tid, pldm_resp_msg, 213 resp_msg_len); 214 if (rc == PLDM_REQUESTER_SUCCESS) { 215 const struct pldm_msg_hdr *resp_hdr = *pldm_resp_msg; 216 if ((src_tid == tid) && 217 (req_hdr->instance_id == resp_hdr->instance_id)) { 218 return rc; 219 } 220 221 /* This isn't the message we wanted */ 222 free(*pldm_resp_msg); 223 } 224 225 ret = clock_gettimeval(CLOCK_MONOTONIC, &now); 226 if (ret < 0) { 227 return PLDM_REQUESTER_POLL_FAIL; 228 } 229 } while (timercmp(&now, &end, <)); 230 231 return PLDM_REQUESTER_RECV_FAIL; 232 } 233