xref: /openbmc/libpldm/src/requester/pldm.c (revision 0411b712)
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