1 #include "config.h" 2 #include "libpldm/requester/pldm.h" 3 #include "base.h" 4 #include "libpldm/transport.h" 5 6 #include <bits/types/struct_iovec.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_STABLE 30 pldm_requester_rc_t pldm_open(void) 31 { 32 int fd; 33 int rc; 34 35 if (open_transport) { 36 fd = pldm_transport_mctp_demux_get_socket_fd(open_transport); 37 return fd; 38 } 39 40 struct pldm_transport_mctp_demux *demux = NULL; 41 rc = pldm_transport_mctp_demux_init(&demux); 42 if (rc) { 43 return rc; 44 } 45 46 fd = pldm_transport_mctp_demux_get_socket_fd(demux); 47 48 open_transport = demux; 49 50 return fd; 51 } 52 53 /* This macro does the setup and teardown required for the old API to use the 54 * new API. Since the setup/teardown logic is the same for all four send/recv 55 * functions, it makes sense to only define it once. */ 56 #define PLDM_REQ_FN(eid, fd, fn, rc, ...) \ 57 do { \ 58 struct pldm_transport_mctp_demux *demux; \ 59 bool using_open_transport = false; \ 60 pldm_tid_t tid = 1; \ 61 struct pldm_transport *ctx; \ 62 /* The fd can be for a socket we opened or one the consumer \ 63 * opened. */ \ 64 if (open_transport && \ 65 mctp_fd == pldm_transport_mctp_demux_get_socket_fd( \ 66 open_transport)) { \ 67 using_open_transport = true; \ 68 demux = open_transport; \ 69 } else { \ 70 demux = pldm_transport_mctp_demux_init_with_fd(fd); \ 71 if (!demux) { \ 72 rc = PLDM_REQUESTER_OPEN_FAIL; \ 73 goto transport_out; \ 74 } \ 75 } \ 76 ctx = pldm_transport_mctp_demux_core(demux); \ 77 rc = pldm_transport_mctp_demux_map_tid(demux, tid, eid); \ 78 if (rc) { \ 79 rc = PLDM_REQUESTER_OPEN_FAIL; \ 80 goto transport_out; \ 81 } \ 82 rc = fn(ctx, tid, __VA_ARGS__); \ 83 transport_out: \ 84 if (!using_open_transport) { \ 85 pldm_transport_mctp_demux_destroy(demux); \ 86 } \ 87 break; \ 88 } while (0) 89 90 LIBPLDM_ABI_STABLE 91 pldm_requester_rc_t pldm_recv_any(mctp_eid_t eid, int mctp_fd, 92 uint8_t **pldm_resp_msg, size_t *resp_msg_len) 93 { 94 pldm_requester_rc_t rc = 0; 95 PLDM_REQ_FN(eid, mctp_fd, pldm_transport_recv_msg, rc, 96 (void **)pldm_resp_msg, resp_msg_len); 97 struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg); 98 if (rc != PLDM_REQUESTER_SUCCESS) { 99 return rc; 100 } 101 if (hdr && (hdr->request || hdr->datagram)) { 102 free(*pldm_resp_msg); 103 *pldm_resp_msg = NULL; 104 return PLDM_REQUESTER_NOT_RESP_MSG; 105 } 106 uint8_t pldm_cc = 0; 107 if (*resp_msg_len < (sizeof(struct pldm_msg_hdr) + sizeof(pldm_cc))) { 108 free(*pldm_resp_msg); 109 *pldm_resp_msg = NULL; 110 return PLDM_REQUESTER_RESP_MSG_TOO_SMALL; 111 } 112 return rc; 113 } 114 115 LIBPLDM_ABI_STABLE 116 pldm_requester_rc_t pldm_recv(mctp_eid_t eid, int mctp_fd, 117 __attribute__((unused)) uint8_t instance_id, 118 uint8_t **pldm_resp_msg, size_t *resp_msg_len) 119 { 120 pldm_requester_rc_t rc = 121 pldm_recv_any(eid, mctp_fd, pldm_resp_msg, resp_msg_len); 122 struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg); 123 if (rc == PLDM_REQUESTER_SUCCESS && hdr && 124 hdr->instance_id != instance_id) { 125 free(*pldm_resp_msg); 126 *pldm_resp_msg = NULL; 127 return PLDM_REQUESTER_INSTANCE_ID_MISMATCH; 128 } 129 return rc; 130 } 131 132 LIBPLDM_ABI_STABLE 133 pldm_requester_rc_t pldm_send_recv(mctp_eid_t eid, int mctp_fd, 134 const uint8_t *pldm_req_msg, 135 size_t req_msg_len, uint8_t **pldm_resp_msg, 136 size_t *resp_msg_len) 137 { 138 pldm_requester_rc_t rc = 0; 139 struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)pldm_req_msg; 140 if (hdr && !hdr->request) { 141 return PLDM_REQUESTER_NOT_REQ_MSG; 142 } 143 PLDM_REQ_FN(eid, mctp_fd, pldm_transport_send_recv_msg, rc, 144 pldm_req_msg, req_msg_len, (void **)pldm_resp_msg, 145 resp_msg_len); 146 if (rc != PLDM_REQUESTER_SUCCESS) { 147 return rc; 148 } 149 hdr = (struct pldm_msg_hdr *)pldm_resp_msg; 150 if (hdr && (hdr->request || hdr->datagram)) { 151 free(*pldm_resp_msg); 152 *pldm_resp_msg = NULL; 153 return PLDM_REQUESTER_NOT_RESP_MSG; 154 } 155 return rc; 156 } 157 158 LIBPLDM_ABI_STABLE 159 pldm_requester_rc_t pldm_send(mctp_eid_t eid, int mctp_fd, 160 const uint8_t *pldm_req_msg, size_t req_msg_len) 161 { 162 pldm_requester_rc_t rc = 0; 163 struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)pldm_req_msg; 164 if (!hdr->request) { 165 return PLDM_REQUESTER_NOT_REQ_MSG; 166 } 167 PLDM_REQ_FN(eid, mctp_fd, pldm_transport_send_msg, rc, 168 (void *)pldm_req_msg, req_msg_len); 169 return rc; 170 } 171 172 /* Adding this here for completeness in the case we can't smoothly 173 * transition apps over to the new api */ 174 LIBPLDM_ABI_STABLE 175 void pldm_close(void) 176 { 177 if (open_transport) { 178 pldm_transport_mctp_demux_destroy(open_transport); 179 } 180 open_transport = NULL; 181 } 182