1 #include "config.h" 2 #include "libpldm/transport.h" 3 #include "base.h" 4 #include "libpldm/requester/pldm.h" 5 #include "transport.h" 6 7 #include <errno.h> 8 #include <limits.h> 9 #ifdef PLDM_HAS_POLL 10 #include <poll.h> 11 #endif 12 #include <stdbool.h> 13 #include <stdlib.h> 14 #include <sys/time.h> 15 #include <time.h> 16 #include <unistd.h> 17 18 #ifndef PLDM_HAS_POLL 19 struct pollfd { 20 int fd; /* file descriptor */ 21 short events; /* requested events */ 22 short revents; /* returned events */ 23 }; 24 25 static 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 33 LIBPLDM_ABI_TESTING 34 pldm_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 55 LIBPLDM_ABI_TESTING 56 pldm_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 77 LIBPLDM_ABI_TESTING 78 pldm_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 = 88 transport->recv(transport, tid, pldm_resp_msg, resp_msg_len); 89 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 110 static 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 */ 117 static 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 */ 125 static 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 138 static 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 153 LIBPLDM_ABI_TESTING 154 pldm_requester_rc_t 155 pldm_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 { 160 /** 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 }; 168 const struct pldm_msg_hdr *req_hdr; 169 struct timeval remaining; 170 pldm_requester_rc_t rc; 171 struct timeval now; 172 struct timeval end; 173 int ret; 174 175 if (req_msg_len < sizeof(*req_hdr) || !resp_msg_len) { 176 return PLDM_REQUESTER_INVALID_SETUP; 177 } 178 179 req_hdr = pldm_req_msg; 180 181 rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len); 182 if (rc != PLDM_REQUESTER_SUCCESS) { 183 return rc; 184 } 185 186 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))); 201 if (rc != PLDM_REQUESTER_SUCCESS) { 202 return rc; 203 } 204 205 rc = pldm_transport_recv_msg(transport, tid, pldm_resp_msg, 206 resp_msg_len); 207 if (rc == PLDM_REQUESTER_SUCCESS) { 208 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); 215 } 216 217 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; 224 } 225