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