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 pldm_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 45 transport->init_pollfd(transport, &pollfd); 46 rc = poll(&pollfd, 1, timeout); 47 if (rc < 0) { 48 return PLDM_REQUESTER_POLL_FAIL; 49 } 50 51 return PLDM_REQUESTER_SUCCESS; 52 } 53 54 LIBPLDM_ABI_TESTING 55 pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport, 56 pldm_tid_t tid, 57 const void *pldm_req_msg, 58 size_t req_msg_len) 59 { 60 if (!transport || !pldm_req_msg) { 61 return PLDM_REQUESTER_INVALID_SETUP; 62 } 63 64 if (req_msg_len < sizeof(struct pldm_msg_hdr)) { 65 return PLDM_REQUESTER_NOT_REQ_MSG; 66 } 67 68 return transport->send(transport, tid, pldm_req_msg, req_msg_len); 69 } 70 71 LIBPLDM_ABI_TESTING 72 pldm_requester_rc_t pldm_transport_recv_msg(struct pldm_transport *transport, 73 pldm_tid_t tid, 74 void **pldm_resp_msg, 75 size_t *resp_msg_len) 76 { 77 if (!transport || !resp_msg_len) { 78 return PLDM_REQUESTER_INVALID_SETUP; 79 } 80 81 pldm_requester_rc_t rc = 82 transport->recv(transport, tid, pldm_resp_msg, resp_msg_len); 83 if (rc != PLDM_REQUESTER_SUCCESS) { 84 return rc; 85 } 86 87 if (*resp_msg_len < sizeof(struct pldm_msg_hdr)) { 88 free(*pldm_resp_msg); 89 *pldm_resp_msg = NULL; 90 return PLDM_REQUESTER_INVALID_RECV_LEN; 91 } 92 return PLDM_REQUESTER_SUCCESS; 93 } 94 95 static void timespec_to_timeval(const struct timespec *ts, struct timeval *tv) 96 { 97 tv->tv_sec = ts->tv_sec; 98 tv->tv_usec = ts->tv_nsec / 1000; 99 } 100 101 /* Overflow safety must be upheld before call */ 102 static long timeval_to_msec(const struct timeval *tv) 103 { 104 return tv->tv_sec * 1000 + tv->tv_usec / 1000; 105 } 106 107 /* If calculations on `tv` don't overflow then operations on derived 108 * intervals can't either. 109 */ 110 static bool timeval_is_valid(const struct timeval *tv) 111 { 112 if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) { 113 return false; 114 } 115 116 if (tv->tv_sec > (LONG_MAX - tv->tv_usec / 1000) / 1000) { 117 return false; 118 } 119 120 return true; 121 } 122 123 static int clock_gettimeval(clockid_t clockid, struct timeval *tv) 124 { 125 struct timespec now; 126 int rc; 127 128 rc = clock_gettime(clockid, &now); 129 if (rc < 0) { 130 return rc; 131 } 132 133 timespec_to_timeval(&now, tv); 134 135 return 0; 136 } 137 138 LIBPLDM_ABI_TESTING 139 pldm_requester_rc_t 140 pldm_transport_send_recv_msg(struct pldm_transport *transport, pldm_tid_t tid, 141 const void *pldm_req_msg, size_t req_msg_len, 142 void **pldm_resp_msg, size_t *resp_msg_len) 143 144 { 145 /** 146 * Section "Requirements for requesters" in DSP0240, define the Time-out 147 * waiting for a response of the requester. 148 * PT2max = PT3min - 2*PT4max = 4800ms 149 */ 150 static const struct timeval max_response_interval = { 151 .tv_sec = 4, .tv_usec = 800000 152 }; 153 const struct pldm_msg_hdr *req_hdr; 154 struct timeval remaining; 155 pldm_requester_rc_t rc; 156 struct timeval now; 157 struct timeval end; 158 int ret; 159 160 if (req_msg_len < sizeof(*req_hdr) || !resp_msg_len) { 161 return PLDM_REQUESTER_INVALID_SETUP; 162 } 163 164 req_hdr = pldm_req_msg; 165 166 rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len); 167 if (rc != PLDM_REQUESTER_SUCCESS) { 168 return rc; 169 } 170 171 ret = clock_gettimeval(CLOCK_MONOTONIC, &now); 172 if (ret < 0) { 173 return PLDM_REQUESTER_POLL_FAIL; 174 } 175 176 timeradd(&now, &max_response_interval, &end); 177 if (!timeval_is_valid(&end)) { 178 return PLDM_REQUESTER_POLL_FAIL; 179 } 180 181 do { 182 timersub(&end, &now, &remaining); 183 /* 0 <= `timeval_to_msec()` <= 4800, and 4800 < INT_MAX */ 184 rc = pldm_transport_poll(transport, 185 (int)(timeval_to_msec(&remaining))); 186 if (rc != PLDM_REQUESTER_SUCCESS) { 187 return rc; 188 } 189 190 rc = pldm_transport_recv_msg(transport, tid, pldm_resp_msg, 191 resp_msg_len); 192 if (rc == PLDM_REQUESTER_SUCCESS) { 193 const struct pldm_msg_hdr *resp_hdr = *pldm_resp_msg; 194 if (req_hdr->instance_id == resp_hdr->instance_id) { 195 return rc; 196 } 197 198 /* This isn't the message we wanted */ 199 free(*pldm_resp_msg); 200 } 201 202 ret = clock_gettimeval(CLOCK_MONOTONIC, &now); 203 if (ret < 0) { 204 return PLDM_REQUESTER_POLL_FAIL; 205 } 206 } while (!timercmp(&now, &end, <)); 207 208 return PLDM_REQUESTER_RECV_FAIL; 209 } 210