blob: a874cef48b5bd609c1c6c81419f5342c67e8a549 [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302#include "mctp-defines.h"
Rashmica Guptac1b66f42022-12-09 16:24:45 +11003#include "base.h"
4#include "container-of.h"
5#include "libpldm/pldm.h"
6#include "libpldm/transport.h"
BonnieLo-wiwynn36402ff2023-08-16 15:38:51 +08007#include "libpldm/transport/mctp-demux.h"
Rashmica Gupta04273e92023-06-16 16:03:37 +10008#include "socket.h"
Rashmica Guptac1b66f42022-12-09 16:24:45 +11009#include "transport.h"
10
11#include <errno.h>
Rashmica Gupta04273e92023-06-16 16:03:37 +100012#include <limits.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110013#include <poll.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/socket.h>
17#include <sys/types.h>
18#include <sys/un.h>
19#include <unistd.h>
20
21#define MCTP_DEMUX_NAME "libmctp-demux-daemon"
22const uint8_t mctp_msg_type = MCTP_MSG_TYPE_PLDM;
23
24struct pldm_transport_mctp_demux {
25 struct pldm_transport transport;
26 int socket;
27 /* In the future this probably needs to move to a tid-eid-uuid/network
28 * id mapping for multi mctp networks */
29 pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID];
Rashmica Gupta04273e92023-06-16 16:03:37 +100030 struct pldm_socket_sndbuf socket_send_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110031};
32
33#define transport_to_demux(ptr) \
34 container_of(ptr, struct pldm_transport_mctp_demux, transport)
35
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093036LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110037struct pldm_transport *
38pldm_transport_mctp_demux_core(struct pldm_transport_mctp_demux *ctx)
39{
40 return &ctx->transport;
41}
42
43static pldm_requester_rc_t pldm_transport_mctp_demux_open(void)
44{
45 int fd = -1;
46 ssize_t rc = -1;
47
48 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
49 if (fd == -1) {
50 return fd;
51 }
52
53 const char path[] = "\0mctp-mux";
54 struct sockaddr_un addr;
55 addr.sun_family = AF_UNIX;
56 memcpy(addr.sun_path, path, sizeof(path) - 1);
57 rc = connect(fd, (struct sockaddr *)&addr,
58 sizeof(path) + sizeof(addr.sun_family) - 1);
59 if (rc == -1) {
60 return PLDM_REQUESTER_OPEN_FAIL;
61 }
62 rc = write(fd, &mctp_msg_type, sizeof(mctp_msg_type));
63 if (rc == -1) {
64 return PLDM_REQUESTER_OPEN_FAIL;
65 }
66
67 return fd;
68}
69
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093070LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110071int pldm_transport_mctp_demux_init_pollfd(struct pldm_transport *t,
72 struct pollfd *pollfd)
73{
74 struct pldm_transport_mctp_demux *ctx = transport_to_demux(t);
75 pollfd->fd = ctx->socket;
76 pollfd->events = POLLIN;
77 return 0;
78}
79
80static int
81pldm_transport_mctp_demux_get_eid(struct pldm_transport_mctp_demux *ctx,
82 pldm_tid_t tid, mctp_eid_t *eid)
83{
84 int i;
85 for (i = 0; i < MCTP_MAX_NUM_EID; i++) {
86 if (ctx->tid_eid_map[i] == tid) {
87 *eid = i;
88 return 0;
89 }
90 }
91 *eid = -1;
92 return -1;
93}
94
Rashmica Gupta24576292023-07-31 14:02:41 +100095static int
96pldm_transport_mctp_demux_get_tid(struct pldm_transport_mctp_demux *ctx,
97 mctp_eid_t eid, pldm_tid_t *tid)
98{
99 /* mapping exists */
100 if (ctx->tid_eid_map[eid] != 0) {
101 *tid = ctx->tid_eid_map[eid];
102 return 0;
103 }
104 return -1;
105}
106
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930107LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100108int pldm_transport_mctp_demux_map_tid(struct pldm_transport_mctp_demux *ctx,
109 pldm_tid_t tid, mctp_eid_t eid)
110{
111 ctx->tid_eid_map[eid] = tid;
112
113 return 0;
114}
115
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930116LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100117int pldm_transport_mctp_demux_unmap_tid(struct pldm_transport_mctp_demux *ctx,
118 __attribute__((unused)) pldm_tid_t tid,
119 mctp_eid_t eid)
120{
121 ctx->tid_eid_map[eid] = 0;
122
123 return 0;
124}
125
126static pldm_requester_rc_t
Rashmica Gupta24576292023-07-31 14:02:41 +1000127pldm_transport_mctp_demux_recv(struct pldm_transport *t, pldm_tid_t *tid,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000128 void **pldm_msg, size_t *msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100129{
130 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930131 size_t mctp_prefix_len = 2;
132 struct msghdr msg = { 0 };
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930133 pldm_requester_rc_t res;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930134 uint8_t mctp_prefix[2];
135 struct iovec iov[2];
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100136 mctp_eid_t eid = 0;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930137 ssize_t min_len;
138 size_t pldm_len;
139 ssize_t length;
140 ssize_t bytes;
141 uint8_t *buf;
142 int rc;
143
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930144 min_len = sizeof(eid) + sizeof(mctp_msg_type) +
145 sizeof(struct pldm_msg_hdr);
146 length = recv(demux->socket, NULL, 0, MSG_PEEK | MSG_TRUNC);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100147 if (length <= 0) {
148 return PLDM_REQUESTER_RECV_FAIL;
149 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930150
151 buf = malloc(length);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100152 if (buf == NULL) {
153 return PLDM_REQUESTER_RECV_FAIL;
154 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930155
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100156 if (length < min_len) {
157 /* read and discard */
158 recv(demux->socket, buf, length, 0);
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930159 res = PLDM_REQUESTER_INVALID_RECV_LEN;
160 goto cleanup_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100161 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930162
163 pldm_len = length - mctp_prefix_len;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100164 iov[0].iov_len = mctp_prefix_len;
165 iov[0].iov_base = mctp_prefix;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100166 iov[1].iov_len = pldm_len;
Andrew Jefferya8532b52023-06-05 11:58:55 +0930167 iov[1].iov_base = buf;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930168
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100169 msg.msg_iov = iov;
170 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930171
172 bytes = recvmsg(demux->socket, &msg, 0);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100173 if (length != bytes) {
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930174 res = PLDM_REQUESTER_INVALID_RECV_LEN;
175 goto cleanup_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100176 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930177
Rashmica Gupta24576292023-07-31 14:02:41 +1000178 if (mctp_prefix[1] != mctp_msg_type) {
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930179 res = PLDM_REQUESTER_NOT_PLDM_MSG;
180 goto cleanup_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100181 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930182
Rashmica Gupta24576292023-07-31 14:02:41 +1000183 eid = mctp_prefix[0];
184 rc = pldm_transport_mctp_demux_get_tid(demux, eid, tid);
185 if (rc) {
186 res = PLDM_REQUESTER_RECV_FAIL;
187 goto cleanup_buf;
188 }
189
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000190 *pldm_msg = buf;
191 *msg_len = pldm_len;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930192
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100193 return PLDM_REQUESTER_SUCCESS;
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930194
195cleanup_buf:
196 free(buf);
197
198 return res;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100199}
200
201static pldm_requester_rc_t
202pldm_transport_mctp_demux_send(struct pldm_transport *t, pldm_tid_t tid,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000203 const void *pldm_msg, size_t msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100204{
205 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
206 mctp_eid_t eid = 0;
207 if (pldm_transport_mctp_demux_get_eid(demux, tid, &eid)) {
208 return PLDM_REQUESTER_SEND_FAIL;
209 }
210
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930211 uint8_t hdr[2] = { eid, mctp_msg_type };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100212
213 struct iovec iov[2];
214 iov[0].iov_base = hdr;
215 iov[0].iov_len = sizeof(hdr);
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000216 iov[1].iov_base = (uint8_t *)pldm_msg;
217 iov[1].iov_len = msg_len;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100218
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930219 struct msghdr msg = { 0 };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100220 msg.msg_iov = iov;
221 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
222
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000223 if (msg_len > INT_MAX ||
Rashmica Gupta04273e92023-06-16 16:03:37 +1000224 pldm_socket_sndbuf_accomodate(&(demux->socket_send_buf),
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000225 (int)msg_len)) {
Rashmica Gupta04273e92023-06-16 16:03:37 +1000226 return PLDM_REQUESTER_SEND_FAIL;
227 }
228
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100229 ssize_t rc = sendmsg(demux->socket, &msg, 0);
230 if (rc == -1) {
231 return PLDM_REQUESTER_SEND_FAIL;
232 }
233 return PLDM_REQUESTER_SUCCESS;
234}
235
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930236LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100237int pldm_transport_mctp_demux_init(struct pldm_transport_mctp_demux **ctx)
238{
239 if (!ctx || *ctx) {
240 return -EINVAL;
241 }
242
243 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930244 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100245 if (!demux) {
246 return -ENOMEM;
247 }
248
249 demux->transport.name = MCTP_DEMUX_NAME;
250 demux->transport.version = 1;
251 demux->transport.recv = pldm_transport_mctp_demux_recv;
252 demux->transport.send = pldm_transport_mctp_demux_send;
253 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
254 demux->socket = pldm_transport_mctp_demux_open();
255 if (demux->socket == -1) {
256 free(demux);
257 return -1;
258 }
Rashmica Gupta04273e92023-06-16 16:03:37 +1000259
260 if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) {
261 close(demux->socket);
262 free(demux);
263 return -1;
264 }
265
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100266 *ctx = demux;
267 return 0;
268}
269
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930270LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100271void pldm_transport_mctp_demux_destroy(struct pldm_transport_mctp_demux *ctx)
272{
273 if (!ctx) {
274 return;
275 }
276 close(ctx->socket);
277 free(ctx);
278}
279
280/* Temporary for old API */
281struct pldm_transport_mctp_demux *
282pldm_transport_mctp_demux_init_with_fd(int mctp_fd)
283{
284 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930285 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100286 if (!demux) {
287 return NULL;
288 }
289
290 demux->transport.name = MCTP_DEMUX_NAME;
291 demux->transport.version = 1;
292 demux->transport.recv = pldm_transport_mctp_demux_recv;
293 demux->transport.send = pldm_transport_mctp_demux_send;
294 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
295 /* dup is so we can call pldm_transport_mctp_demux_destroy which closes
296 * the socket, without closing the fd that is being used by the consumer
297 */
298 demux->socket = dup(mctp_fd);
299 if (demux->socket == -1) {
300 free(demux);
301 return NULL;
302 }
Rashmica Gupta04273e92023-06-16 16:03:37 +1000303
304 if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) {
305 close(demux->socket);
306 free(demux);
307 return NULL;
308 }
309
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100310 return demux;
311}
312
313int pldm_transport_mctp_demux_get_socket_fd(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930314 struct pldm_transport_mctp_demux *ctx)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100315{
Andrew Jefferya4da6852023-06-29 10:47:24 +0930316 if (ctx) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100317 return ctx->socket;
318 }
Andrew Jefferya4da6852023-06-29 10:47:24 +0930319
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100320 return -1;
321}