/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ #include #include #include #include #include #include #include #include #include #include #include /* Temporary for old api */ #include "libpldm/transport/mctp-demux.h" extern int pldm_transport_mctp_demux_get_socket_fd(struct pldm_transport_mctp_demux *ctx); extern struct pldm_transport_mctp_demux * pldm_transport_mctp_demux_init_with_fd(int mctp_fd); /* --- old APIS written in terms of the new API -- */ /* * pldm_open returns the file descriptor to the MCTP socket, which needs to * persist over api calls (so a consumer can poll it for incoming messages). * So we need a global variable to store the transport struct */ static struct pldm_transport_mctp_demux *open_transport; LIBPLDM_ABI_DEPRECATED pldm_requester_rc_t pldm_open(void) { int fd = PLDM_REQUESTER_OPEN_FAIL; if (open_transport) { fd = pldm_transport_mctp_demux_get_socket_fd(open_transport); /* If someone has externally issued close() on fd then we need to start again. Use * `fcntl(..., F_GETFD)` to test whether fd is valid. */ if (fd < 0 || fcntl(fd, F_GETFD) < 0) { pldm_close(); } } /* We retest open_transport as it may have been set to NULL by pldm_close() above. */ if (!open_transport) { struct pldm_transport_mctp_demux *demux = NULL; if (pldm_transport_mctp_demux_init(&demux) < 0) { return PLDM_REQUESTER_OPEN_FAIL; } open_transport = demux; fd = pldm_transport_mctp_demux_get_socket_fd(open_transport); } return fd; } /* This macro does the setup and teardown required for the old API to use the * new API. Since the setup/teardown logic is the same for all four send/recv * functions, it makes sense to only define it once. */ #define PLDM_REQ_FN(eid, fd, fn, rc, ...) \ do { \ struct pldm_transport_mctp_demux *demux; \ bool using_open_transport = false; \ pldm_tid_t tid = eid; \ struct pldm_transport *ctx; \ /* The fd can be for a socket we opened or one the consumer \ * opened. */ \ if (open_transport && \ mctp_fd == pldm_transport_mctp_demux_get_socket_fd( \ open_transport)) { \ using_open_transport = true; \ demux = open_transport; \ } else { \ demux = pldm_transport_mctp_demux_init_with_fd(fd); \ if (!demux) { \ rc = PLDM_REQUESTER_OPEN_FAIL; \ goto transport_out; \ } \ } \ ctx = pldm_transport_mctp_demux_core(demux); \ rc = pldm_transport_mctp_demux_map_tid(demux, tid, eid); \ if (rc) { \ rc = PLDM_REQUESTER_OPEN_FAIL; \ goto transport_out; \ } \ rc = fn(ctx, tid, __VA_ARGS__); \ transport_out: \ if (!using_open_transport) { \ pldm_transport_mctp_demux_destroy(demux); \ } \ break; \ } while (0) LIBPLDM_ABI_DEPRECATED pldm_requester_rc_t pldm_recv_any(mctp_eid_t eid, int mctp_fd, uint8_t **pldm_resp_msg, size_t *resp_msg_len) { pldm_requester_rc_t rc = 0; struct pldm_transport_mctp_demux *demux; bool using_open_transport = false; pldm_tid_t tid = eid; struct pldm_transport *ctx; /* The fd can be for a socket we opened or one the consumer * opened. */ if (open_transport && mctp_fd == pldm_transport_mctp_demux_get_socket_fd(open_transport)) { using_open_transport = true; demux = open_transport; } else { demux = pldm_transport_mctp_demux_init_with_fd(mctp_fd); if (!demux) { rc = PLDM_REQUESTER_OPEN_FAIL; goto transport_out; } } ctx = pldm_transport_mctp_demux_core(demux); rc = pldm_transport_mctp_demux_map_tid(demux, tid, eid); if (rc) { rc = PLDM_REQUESTER_OPEN_FAIL; goto transport_out; } /* TODO this is the only change, can we work this into the macro? */ rc = pldm_transport_recv_msg(ctx, &tid, (void **)pldm_resp_msg, resp_msg_len); struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg); if (rc != PLDM_REQUESTER_SUCCESS) { return rc; } if (hdr && (hdr->request || hdr->datagram)) { free(*pldm_resp_msg); *pldm_resp_msg = NULL; return PLDM_REQUESTER_NOT_RESP_MSG; } uint8_t pldm_cc = 0; if (*resp_msg_len < (sizeof(struct pldm_msg_hdr) + sizeof(pldm_cc))) { free(*pldm_resp_msg); *pldm_resp_msg = NULL; return PLDM_REQUESTER_RESP_MSG_TOO_SMALL; } transport_out: if (!using_open_transport) { pldm_transport_mctp_demux_destroy(demux); } return rc; } LIBPLDM_ABI_DEPRECATED pldm_requester_rc_t pldm_recv(mctp_eid_t eid, int mctp_fd, __attribute__((unused)) uint8_t instance_id, uint8_t **pldm_resp_msg, size_t *resp_msg_len) { pldm_requester_rc_t rc = pldm_recv_any(eid, mctp_fd, pldm_resp_msg, resp_msg_len); struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg); if (rc == PLDM_REQUESTER_SUCCESS && hdr && hdr->instance_id != instance_id) { free(*pldm_resp_msg); *pldm_resp_msg = NULL; return PLDM_REQUESTER_INSTANCE_ID_MISMATCH; } return rc; } LIBPLDM_ABI_DEPRECATED pldm_requester_rc_t pldm_send_recv(mctp_eid_t eid, int mctp_fd, const uint8_t *pldm_req_msg, size_t req_msg_len, uint8_t **pldm_resp_msg, size_t *resp_msg_len) { pldm_requester_rc_t rc = 0; struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)pldm_req_msg; if (hdr && !hdr->request) { return PLDM_REQUESTER_NOT_REQ_MSG; } PLDM_REQ_FN(eid, mctp_fd, pldm_transport_send_recv_msg, rc, pldm_req_msg, req_msg_len, (void **)pldm_resp_msg, resp_msg_len); if (rc != PLDM_REQUESTER_SUCCESS) { return rc; } hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg); if (hdr && (hdr->request || hdr->datagram)) { free(*pldm_resp_msg); *pldm_resp_msg = NULL; return PLDM_REQUESTER_NOT_RESP_MSG; } return rc; } LIBPLDM_ABI_DEPRECATED pldm_requester_rc_t pldm_send(mctp_eid_t eid, int mctp_fd, const uint8_t *pldm_req_msg, size_t req_msg_len) { pldm_requester_rc_t rc = 0; struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)pldm_req_msg; if (!hdr->request) { return PLDM_REQUESTER_NOT_REQ_MSG; } PLDM_REQ_FN(eid, mctp_fd, pldm_transport_send_msg, rc, (void *)pldm_req_msg, req_msg_len); return rc; } /* Adding this here for completeness in the case we can't smoothly * transition apps over to the new api */ LIBPLDM_ABI_DEPRECATED void pldm_close(void) { if (open_transport) { pldm_transport_mctp_demux_destroy(open_transport); } open_transport = NULL; }