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