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