1 #include "libpldm/requester/pldm.h" 2 #include "base.h" 3 #include "libpldm/transport.h" 4 5 #include <bits/types/struct_iovec.h> 6 #include <fcntl.h> 7 #include <stdbool.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <sys/socket.h> 11 #include <sys/un.h> 12 #include <unistd.h> 13 14 /* Temporary for old api */ 15 #include "libpldm/transport/mctp-demux.h" 16 extern int 17 pldm_transport_mctp_demux_get_socket_fd(struct pldm_transport_mctp_demux *ctx); 18 extern struct pldm_transport_mctp_demux * 19 pldm_transport_mctp_demux_init_with_fd(int mctp_fd); 20 21 /* --- old APIS written in terms of the new API -- */ 22 /* 23 * pldm_open returns the file descriptor to the MCTP socket, which needs to 24 * persist over api calls (so a consumer can poll it for incoming messages). 25 * So we need a global variable to store the transport struct 26 */ 27 static struct pldm_transport_mctp_demux *open_transport; 28 29 LIBPLDM_ABI_DEPRECATED 30 pldm_requester_rc_t pldm_open(void) 31 { 32 int fd = PLDM_REQUESTER_OPEN_FAIL; 33 34 if (open_transport) { 35 fd = pldm_transport_mctp_demux_get_socket_fd(open_transport); 36 37 /* If someone has externally issued close() on fd then we need to start again. Use 38 * `fcntl(..., F_GETFD)` to test whether fd is valid. */ 39 if (fd < 0 || fcntl(fd, F_GETFD) < 0) { 40 pldm_close(); 41 } 42 } 43 44 /* We retest open_transport as it may have been set to NULL by pldm_close() above. */ 45 if (!open_transport) { 46 struct pldm_transport_mctp_demux *demux = NULL; 47 48 if (pldm_transport_mctp_demux_init(&demux) < 0) { 49 return PLDM_REQUESTER_OPEN_FAIL; 50 } 51 52 open_transport = demux; 53 54 fd = pldm_transport_mctp_demux_get_socket_fd(open_transport); 55 } 56 57 return fd; 58 } 59 60 /* This macro does the setup and teardown required for the old API to use the 61 * new API. Since the setup/teardown logic is the same for all four send/recv 62 * functions, it makes sense to only define it once. */ 63 #define PLDM_REQ_FN(eid, fd, fn, rc, ...) \ 64 do { \ 65 struct pldm_transport_mctp_demux *demux; \ 66 bool using_open_transport = false; \ 67 pldm_tid_t tid = eid; \ 68 struct pldm_transport *ctx; \ 69 /* The fd can be for a socket we opened or one the consumer \ 70 * opened. */ \ 71 if (open_transport && \ 72 mctp_fd == pldm_transport_mctp_demux_get_socket_fd( \ 73 open_transport)) { \ 74 using_open_transport = true; \ 75 demux = open_transport; \ 76 } else { \ 77 demux = pldm_transport_mctp_demux_init_with_fd(fd); \ 78 if (!demux) { \ 79 rc = PLDM_REQUESTER_OPEN_FAIL; \ 80 goto transport_out; \ 81 } \ 82 } \ 83 ctx = pldm_transport_mctp_demux_core(demux); \ 84 rc = pldm_transport_mctp_demux_map_tid(demux, tid, eid); \ 85 if (rc) { \ 86 rc = PLDM_REQUESTER_OPEN_FAIL; \ 87 goto transport_out; \ 88 } \ 89 rc = fn(ctx, tid, __VA_ARGS__); \ 90 transport_out: \ 91 if (!using_open_transport) { \ 92 pldm_transport_mctp_demux_destroy(demux); \ 93 } \ 94 break; \ 95 } while (0) 96 97 LIBPLDM_ABI_DEPRECATED 98 pldm_requester_rc_t pldm_recv_any(mctp_eid_t eid, int mctp_fd, 99 uint8_t **pldm_resp_msg, size_t *resp_msg_len) 100 { 101 pldm_requester_rc_t rc = 0; 102 103 struct pldm_transport_mctp_demux *demux; 104 bool using_open_transport = false; 105 pldm_tid_t tid = eid; 106 struct pldm_transport *ctx; 107 /* The fd can be for a socket we opened or one the consumer 108 * opened. */ 109 if (open_transport && 110 mctp_fd == 111 pldm_transport_mctp_demux_get_socket_fd(open_transport)) { 112 using_open_transport = true; 113 demux = open_transport; 114 } else { 115 demux = pldm_transport_mctp_demux_init_with_fd(mctp_fd); 116 if (!demux) { 117 rc = PLDM_REQUESTER_OPEN_FAIL; 118 goto transport_out; 119 } 120 } 121 ctx = pldm_transport_mctp_demux_core(demux); 122 rc = pldm_transport_mctp_demux_map_tid(demux, tid, eid); 123 if (rc) { 124 rc = PLDM_REQUESTER_OPEN_FAIL; 125 goto transport_out; 126 } 127 /* TODO this is the only change, can we work this into the macro? */ 128 rc = pldm_transport_recv_msg(ctx, &tid, (void **)pldm_resp_msg, 129 resp_msg_len); 130 131 struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg); 132 if (rc != PLDM_REQUESTER_SUCCESS) { 133 return rc; 134 } 135 if (hdr && (hdr->request || hdr->datagram)) { 136 free(*pldm_resp_msg); 137 *pldm_resp_msg = NULL; 138 return PLDM_REQUESTER_NOT_RESP_MSG; 139 } 140 uint8_t pldm_cc = 0; 141 if (*resp_msg_len < (sizeof(struct pldm_msg_hdr) + sizeof(pldm_cc))) { 142 free(*pldm_resp_msg); 143 *pldm_resp_msg = NULL; 144 return PLDM_REQUESTER_RESP_MSG_TOO_SMALL; 145 } 146 147 transport_out: 148 if (!using_open_transport) { 149 pldm_transport_mctp_demux_destroy(demux); 150 } 151 152 return rc; 153 } 154 155 LIBPLDM_ABI_DEPRECATED 156 pldm_requester_rc_t pldm_recv(mctp_eid_t eid, int mctp_fd, 157 __attribute__((unused)) uint8_t instance_id, 158 uint8_t **pldm_resp_msg, size_t *resp_msg_len) 159 { 160 pldm_requester_rc_t rc = 161 pldm_recv_any(eid, mctp_fd, pldm_resp_msg, resp_msg_len); 162 struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg); 163 if (rc == PLDM_REQUESTER_SUCCESS && hdr && 164 hdr->instance_id != instance_id) { 165 free(*pldm_resp_msg); 166 *pldm_resp_msg = NULL; 167 return PLDM_REQUESTER_INSTANCE_ID_MISMATCH; 168 } 169 return rc; 170 } 171 172 LIBPLDM_ABI_DEPRECATED 173 pldm_requester_rc_t pldm_send_recv(mctp_eid_t eid, int mctp_fd, 174 const uint8_t *pldm_req_msg, 175 size_t req_msg_len, uint8_t **pldm_resp_msg, 176 size_t *resp_msg_len) 177 { 178 pldm_requester_rc_t rc = 0; 179 struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)pldm_req_msg; 180 if (hdr && !hdr->request) { 181 return PLDM_REQUESTER_NOT_REQ_MSG; 182 } 183 PLDM_REQ_FN(eid, mctp_fd, pldm_transport_send_recv_msg, rc, 184 pldm_req_msg, req_msg_len, (void **)pldm_resp_msg, 185 resp_msg_len); 186 if (rc != PLDM_REQUESTER_SUCCESS) { 187 return rc; 188 } 189 hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg); 190 if (hdr && (hdr->request || hdr->datagram)) { 191 free(*pldm_resp_msg); 192 *pldm_resp_msg = NULL; 193 return PLDM_REQUESTER_NOT_RESP_MSG; 194 } 195 return rc; 196 } 197 198 LIBPLDM_ABI_DEPRECATED 199 pldm_requester_rc_t pldm_send(mctp_eid_t eid, int mctp_fd, 200 const uint8_t *pldm_req_msg, size_t req_msg_len) 201 { 202 pldm_requester_rc_t rc = 0; 203 struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)pldm_req_msg; 204 if (!hdr->request) { 205 return PLDM_REQUESTER_NOT_REQ_MSG; 206 } 207 PLDM_REQ_FN(eid, mctp_fd, pldm_transport_send_msg, rc, 208 (void *)pldm_req_msg, req_msg_len); 209 return rc; 210 } 211 212 /* Adding this here for completeness in the case we can't smoothly 213 * transition apps over to the new api */ 214 LIBPLDM_ABI_DEPRECATED 215 void pldm_close(void) 216 { 217 if (open_transport) { 218 pldm_transport_mctp_demux_destroy(open_transport); 219 } 220 open_transport = NULL; 221 } 222