blob: 8b35c0a7310ce29ce3413b761f0242417bbde4dc [file] [log] [blame]
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301#include "mctp-defines.h"
Rashmica Guptac1b66f42022-12-09 16:24:45 +11002#include "base.h"
3#include "container-of.h"
4#include "libpldm/pldm.h"
5#include "libpldm/transport.h"
BonnieLo-wiwynn36402ff2023-08-16 15:38:51 +08006#include "libpldm/transport/mctp-demux.h"
Rashmica Gupta04273e92023-06-16 16:03:37 +10007#include "socket.h"
Rashmica Guptac1b66f42022-12-09 16:24:45 +11008#include "transport.h"
9
10#include <errno.h>
Rashmica Gupta04273e92023-06-16 16:03:37 +100011#include <limits.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110012#include <poll.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/socket.h>
16#include <sys/types.h>
17#include <sys/un.h>
18#include <unistd.h>
19
20#define MCTP_DEMUX_NAME "libmctp-demux-daemon"
21const uint8_t mctp_msg_type = MCTP_MSG_TYPE_PLDM;
22
23struct pldm_transport_mctp_demux {
24 struct pldm_transport transport;
25 int socket;
26 /* In the future this probably needs to move to a tid-eid-uuid/network
27 * id mapping for multi mctp networks */
28 pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID];
Rashmica Gupta04273e92023-06-16 16:03:37 +100029 struct pldm_socket_sndbuf socket_send_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110030};
31
32#define transport_to_demux(ptr) \
33 container_of(ptr, struct pldm_transport_mctp_demux, transport)
34
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093035LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110036struct pldm_transport *
37pldm_transport_mctp_demux_core(struct pldm_transport_mctp_demux *ctx)
38{
39 return &ctx->transport;
40}
41
42static pldm_requester_rc_t pldm_transport_mctp_demux_open(void)
43{
44 int fd = -1;
45 ssize_t rc = -1;
46
47 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
48 if (fd == -1) {
49 return fd;
50 }
51
52 const char path[] = "\0mctp-mux";
53 struct sockaddr_un addr;
54 addr.sun_family = AF_UNIX;
55 memcpy(addr.sun_path, path, sizeof(path) - 1);
56 rc = connect(fd, (struct sockaddr *)&addr,
57 sizeof(path) + sizeof(addr.sun_family) - 1);
58 if (rc == -1) {
59 return PLDM_REQUESTER_OPEN_FAIL;
60 }
61 rc = write(fd, &mctp_msg_type, sizeof(mctp_msg_type));
62 if (rc == -1) {
63 return PLDM_REQUESTER_OPEN_FAIL;
64 }
65
66 return fd;
67}
68
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093069LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110070int pldm_transport_mctp_demux_init_pollfd(struct pldm_transport *t,
71 struct pollfd *pollfd)
72{
73 struct pldm_transport_mctp_demux *ctx = transport_to_demux(t);
74 pollfd->fd = ctx->socket;
75 pollfd->events = POLLIN;
76 return 0;
77}
78
79static int
80pldm_transport_mctp_demux_get_eid(struct pldm_transport_mctp_demux *ctx,
81 pldm_tid_t tid, mctp_eid_t *eid)
82{
83 int i;
84 for (i = 0; i < MCTP_MAX_NUM_EID; i++) {
85 if (ctx->tid_eid_map[i] == tid) {
86 *eid = i;
87 return 0;
88 }
89 }
90 *eid = -1;
91 return -1;
92}
93
Rashmica Gupta24576292023-07-31 14:02:41 +100094static int
95pldm_transport_mctp_demux_get_tid(struct pldm_transport_mctp_demux *ctx,
96 mctp_eid_t eid, pldm_tid_t *tid)
97{
98 /* mapping exists */
99 if (ctx->tid_eid_map[eid] != 0) {
100 *tid = ctx->tid_eid_map[eid];
101 return 0;
102 }
103 return -1;
104}
105
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930106LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100107int pldm_transport_mctp_demux_map_tid(struct pldm_transport_mctp_demux *ctx,
108 pldm_tid_t tid, mctp_eid_t eid)
109{
110 ctx->tid_eid_map[eid] = tid;
111
112 return 0;
113}
114
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930115LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100116int pldm_transport_mctp_demux_unmap_tid(struct pldm_transport_mctp_demux *ctx,
117 __attribute__((unused)) pldm_tid_t tid,
118 mctp_eid_t eid)
119{
120 ctx->tid_eid_map[eid] = 0;
121
122 return 0;
123}
124
125static pldm_requester_rc_t
Rashmica Gupta24576292023-07-31 14:02:41 +1000126pldm_transport_mctp_demux_recv(struct pldm_transport *t, pldm_tid_t *tid,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000127 void **pldm_msg, size_t *msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100128{
129 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930130 size_t mctp_prefix_len = 2;
131 struct msghdr msg = { 0 };
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930132 pldm_requester_rc_t res;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930133 uint8_t mctp_prefix[2];
134 struct iovec iov[2];
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100135 mctp_eid_t eid = 0;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930136 ssize_t min_len;
137 size_t pldm_len;
138 ssize_t length;
139 ssize_t bytes;
140 uint8_t *buf;
141 int rc;
142
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930143 min_len = sizeof(eid) + sizeof(mctp_msg_type) +
144 sizeof(struct pldm_msg_hdr);
145 length = recv(demux->socket, NULL, 0, MSG_PEEK | MSG_TRUNC);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100146 if (length <= 0) {
147 return PLDM_REQUESTER_RECV_FAIL;
148 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930149
150 buf = malloc(length);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100151 if (buf == NULL) {
152 return PLDM_REQUESTER_RECV_FAIL;
153 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930154
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100155 if (length < min_len) {
156 /* read and discard */
157 recv(demux->socket, buf, length, 0);
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930158 res = PLDM_REQUESTER_INVALID_RECV_LEN;
159 goto cleanup_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100160 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930161
162 pldm_len = length - mctp_prefix_len;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100163 iov[0].iov_len = mctp_prefix_len;
164 iov[0].iov_base = mctp_prefix;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100165 iov[1].iov_len = pldm_len;
Andrew Jefferya8532b52023-06-05 11:58:55 +0930166 iov[1].iov_base = buf;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930167
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100168 msg.msg_iov = iov;
169 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930170
171 bytes = recvmsg(demux->socket, &msg, 0);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100172 if (length != bytes) {
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930173 res = PLDM_REQUESTER_INVALID_RECV_LEN;
174 goto cleanup_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100175 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930176
Rashmica Gupta24576292023-07-31 14:02:41 +1000177 if (mctp_prefix[1] != mctp_msg_type) {
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930178 res = PLDM_REQUESTER_NOT_PLDM_MSG;
179 goto cleanup_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100180 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930181
Rashmica Gupta24576292023-07-31 14:02:41 +1000182 eid = mctp_prefix[0];
183 rc = pldm_transport_mctp_demux_get_tid(demux, eid, tid);
184 if (rc) {
185 res = PLDM_REQUESTER_RECV_FAIL;
186 goto cleanup_buf;
187 }
188
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000189 *pldm_msg = buf;
190 *msg_len = pldm_len;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930191
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100192 return PLDM_REQUESTER_SUCCESS;
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930193
194cleanup_buf:
195 free(buf);
196
197 return res;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100198}
199
200static pldm_requester_rc_t
201pldm_transport_mctp_demux_send(struct pldm_transport *t, pldm_tid_t tid,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000202 const void *pldm_msg, size_t msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100203{
204 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
205 mctp_eid_t eid = 0;
206 if (pldm_transport_mctp_demux_get_eid(demux, tid, &eid)) {
207 return PLDM_REQUESTER_SEND_FAIL;
208 }
209
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930210 uint8_t hdr[2] = { eid, mctp_msg_type };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100211
212 struct iovec iov[2];
213 iov[0].iov_base = hdr;
214 iov[0].iov_len = sizeof(hdr);
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000215 iov[1].iov_base = (uint8_t *)pldm_msg;
216 iov[1].iov_len = msg_len;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100217
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930218 struct msghdr msg = { 0 };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100219 msg.msg_iov = iov;
220 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
221
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000222 if (msg_len > INT_MAX ||
Rashmica Gupta04273e92023-06-16 16:03:37 +1000223 pldm_socket_sndbuf_accomodate(&(demux->socket_send_buf),
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000224 (int)msg_len)) {
Rashmica Gupta04273e92023-06-16 16:03:37 +1000225 return PLDM_REQUESTER_SEND_FAIL;
226 }
227
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100228 ssize_t rc = sendmsg(demux->socket, &msg, 0);
229 if (rc == -1) {
230 return PLDM_REQUESTER_SEND_FAIL;
231 }
232 return PLDM_REQUESTER_SUCCESS;
233}
234
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930235LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100236int pldm_transport_mctp_demux_init(struct pldm_transport_mctp_demux **ctx)
237{
238 if (!ctx || *ctx) {
239 return -EINVAL;
240 }
241
242 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930243 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100244 if (!demux) {
245 return -ENOMEM;
246 }
247
248 demux->transport.name = MCTP_DEMUX_NAME;
249 demux->transport.version = 1;
250 demux->transport.recv = pldm_transport_mctp_demux_recv;
251 demux->transport.send = pldm_transport_mctp_demux_send;
252 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
253 demux->socket = pldm_transport_mctp_demux_open();
254 if (demux->socket == -1) {
255 free(demux);
256 return -1;
257 }
Rashmica Gupta04273e92023-06-16 16:03:37 +1000258
259 if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) {
260 close(demux->socket);
261 free(demux);
262 return -1;
263 }
264
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100265 *ctx = demux;
266 return 0;
267}
268
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930269LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100270void pldm_transport_mctp_demux_destroy(struct pldm_transport_mctp_demux *ctx)
271{
272 if (!ctx) {
273 return;
274 }
275 close(ctx->socket);
276 free(ctx);
277}
278
279/* Temporary for old API */
280struct pldm_transport_mctp_demux *
281pldm_transport_mctp_demux_init_with_fd(int mctp_fd)
282{
283 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930284 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100285 if (!demux) {
286 return NULL;
287 }
288
289 demux->transport.name = MCTP_DEMUX_NAME;
290 demux->transport.version = 1;
291 demux->transport.recv = pldm_transport_mctp_demux_recv;
292 demux->transport.send = pldm_transport_mctp_demux_send;
293 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
294 /* dup is so we can call pldm_transport_mctp_demux_destroy which closes
295 * the socket, without closing the fd that is being used by the consumer
296 */
297 demux->socket = dup(mctp_fd);
298 if (demux->socket == -1) {
299 free(demux);
300 return NULL;
301 }
Rashmica Gupta04273e92023-06-16 16:03:37 +1000302
303 if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) {
304 close(demux->socket);
305 free(demux);
306 return NULL;
307 }
308
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100309 return demux;
310}
311
312int pldm_transport_mctp_demux_get_socket_fd(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930313 struct pldm_transport_mctp_demux *ctx)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100314{
Andrew Jefferya4da6852023-06-29 10:47:24 +0930315 if (ctx) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100316 return ctx->socket;
317 }
Andrew Jefferya4da6852023-06-29 10:47:24 +0930318
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100319 return -1;
320}