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