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
pldm_open(void)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
pldm_recv_any(mctp_eid_t eid,int mctp_fd,uint8_t ** pldm_resp_msg,size_t * resp_msg_len)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
pldm_recv(mctp_eid_t eid,int mctp_fd,uint8_t instance_id,uint8_t ** pldm_resp_msg,size_t * resp_msg_len)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
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)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
pldm_send(mctp_eid_t eid,int mctp_fd,const uint8_t * pldm_req_msg,size_t req_msg_len)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
pldm_close(void)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