blob: 0ea1cf615c74077b8fffcfee94e58bdffc6985f3 [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Rashmica Guptac1b66f42022-12-09 16:24:45 +11002#include "container-of.h"
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10303#include "mctp-defines.h"
Rashmica Gupta04273e92023-06-16 16:03:37 +10004#include "socket.h"
Rashmica Guptac1b66f42022-12-09 16:24:45 +11005#include "transport.h"
6
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10307#include <libpldm/base.h>
8#include <libpldm/pldm.h>
9#include <libpldm/transport.h>
10#include <libpldm/transport/mctp-demux.h>
11
Rashmica Guptac1b66f42022-12-09 16:24:45 +110012#include <errno.h>
Rashmica Gupta04273e92023-06-16 16:03:37 +100013#include <limits.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110014#include <poll.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/socket.h>
18#include <sys/types.h>
19#include <sys/un.h>
20#include <unistd.h>
21
22#define MCTP_DEMUX_NAME "libmctp-demux-daemon"
23const uint8_t mctp_msg_type = MCTP_MSG_TYPE_PLDM;
24
25struct pldm_transport_mctp_demux {
26 struct pldm_transport transport;
27 int socket;
28 /* In the future this probably needs to move to a tid-eid-uuid/network
29 * id mapping for multi mctp networks */
30 pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID];
Rashmica Gupta04273e92023-06-16 16:03:37 +100031 struct pldm_socket_sndbuf socket_send_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110032};
33
34#define transport_to_demux(ptr) \
35 container_of(ptr, struct pldm_transport_mctp_demux, transport)
36
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093037LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110038struct pldm_transport *
39pldm_transport_mctp_demux_core(struct pldm_transport_mctp_demux *ctx)
40{
41 return &ctx->transport;
42}
43
44static pldm_requester_rc_t pldm_transport_mctp_demux_open(void)
45{
46 int fd = -1;
47 ssize_t rc = -1;
48
49 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
50 if (fd == -1) {
51 return fd;
52 }
53
54 const char path[] = "\0mctp-mux";
55 struct sockaddr_un addr;
56 addr.sun_family = AF_UNIX;
57 memcpy(addr.sun_path, path, sizeof(path) - 1);
58 rc = connect(fd, (struct sockaddr *)&addr,
59 sizeof(path) + sizeof(addr.sun_family) - 1);
60 if (rc == -1) {
61 return PLDM_REQUESTER_OPEN_FAIL;
62 }
63 rc = write(fd, &mctp_msg_type, sizeof(mctp_msg_type));
64 if (rc == -1) {
65 return PLDM_REQUESTER_OPEN_FAIL;
66 }
67
68 return fd;
69}
70
Andrew Jeffery0a6d6822023-08-22 21:40:32 +093071LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +110072int pldm_transport_mctp_demux_init_pollfd(struct pldm_transport *t,
73 struct pollfd *pollfd)
74{
75 struct pldm_transport_mctp_demux *ctx = transport_to_demux(t);
76 pollfd->fd = ctx->socket;
77 pollfd->events = POLLIN;
78 return 0;
79}
80
81static int
82pldm_transport_mctp_demux_get_eid(struct pldm_transport_mctp_demux *ctx,
83 pldm_tid_t tid, mctp_eid_t *eid)
84{
85 int i;
86 for (i = 0; i < MCTP_MAX_NUM_EID; i++) {
87 if (ctx->tid_eid_map[i] == tid) {
88 *eid = i;
89 return 0;
90 }
91 }
92 *eid = -1;
93 return -1;
94}
95
Rashmica Gupta24576292023-07-31 14:02:41 +100096static int
97pldm_transport_mctp_demux_get_tid(struct pldm_transport_mctp_demux *ctx,
98 mctp_eid_t eid, pldm_tid_t *tid)
99{
100 /* mapping exists */
101 if (ctx->tid_eid_map[eid] != 0) {
102 *tid = ctx->tid_eid_map[eid];
103 return 0;
104 }
105 return -1;
106}
107
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930108LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100109int pldm_transport_mctp_demux_map_tid(struct pldm_transport_mctp_demux *ctx,
110 pldm_tid_t tid, mctp_eid_t eid)
111{
112 ctx->tid_eid_map[eid] = tid;
113
114 return 0;
115}
116
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930117LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100118int pldm_transport_mctp_demux_unmap_tid(struct pldm_transport_mctp_demux *ctx,
119 __attribute__((unused)) pldm_tid_t tid,
120 mctp_eid_t eid)
121{
122 ctx->tid_eid_map[eid] = 0;
123
124 return 0;
125}
126
127static pldm_requester_rc_t
Rashmica Gupta24576292023-07-31 14:02:41 +1000128pldm_transport_mctp_demux_recv(struct pldm_transport *t, pldm_tid_t *tid,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000129 void **pldm_msg, size_t *msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100130{
131 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930132 size_t mctp_prefix_len = 2;
133 struct msghdr msg = { 0 };
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930134 pldm_requester_rc_t res;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930135 uint8_t mctp_prefix[2];
136 struct iovec iov[2];
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100137 mctp_eid_t eid = 0;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930138 ssize_t min_len;
139 size_t pldm_len;
140 ssize_t length;
141 ssize_t bytes;
142 uint8_t *buf;
143 int rc;
144
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930145 min_len = sizeof(eid) + sizeof(mctp_msg_type) +
146 sizeof(struct pldm_msg_hdr);
147 length = recv(demux->socket, NULL, 0, MSG_PEEK | MSG_TRUNC);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100148 if (length <= 0) {
149 return PLDM_REQUESTER_RECV_FAIL;
150 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930151
152 buf = malloc(length);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100153 if (buf == NULL) {
154 return PLDM_REQUESTER_RECV_FAIL;
155 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930156
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100157 if (length < min_len) {
158 /* read and discard */
159 recv(demux->socket, buf, length, 0);
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930160 res = PLDM_REQUESTER_INVALID_RECV_LEN;
161 goto cleanup_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100162 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930163
164 pldm_len = length - mctp_prefix_len;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100165 iov[0].iov_len = mctp_prefix_len;
166 iov[0].iov_base = mctp_prefix;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100167 iov[1].iov_len = pldm_len;
Andrew Jefferya8532b52023-06-05 11:58:55 +0930168 iov[1].iov_base = buf;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930169
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100170 msg.msg_iov = iov;
171 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930172
173 bytes = recvmsg(demux->socket, &msg, 0);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100174 if (length != bytes) {
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930175 res = PLDM_REQUESTER_INVALID_RECV_LEN;
176 goto cleanup_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100177 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930178
Rashmica Gupta24576292023-07-31 14:02:41 +1000179 if (mctp_prefix[1] != mctp_msg_type) {
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930180 res = PLDM_REQUESTER_NOT_PLDM_MSG;
181 goto cleanup_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100182 }
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930183
Rashmica Gupta24576292023-07-31 14:02:41 +1000184 eid = mctp_prefix[0];
185 rc = pldm_transport_mctp_demux_get_tid(demux, eid, tid);
186 if (rc) {
187 res = PLDM_REQUESTER_RECV_FAIL;
188 goto cleanup_buf;
189 }
190
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000191 *pldm_msg = buf;
192 *msg_len = pldm_len;
Andrew Jefferyef293fc2023-08-18 12:14:23 +0930193
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100194 return PLDM_REQUESTER_SUCCESS;
Andrew Jeffery27f041c2023-08-18 12:19:15 +0930195
196cleanup_buf:
197 free(buf);
198
199 return res;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100200}
201
202static pldm_requester_rc_t
203pldm_transport_mctp_demux_send(struct pldm_transport *t, pldm_tid_t tid,
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000204 const void *pldm_msg, size_t msg_len)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100205{
206 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
207 mctp_eid_t eid = 0;
208 if (pldm_transport_mctp_demux_get_eid(demux, tid, &eid)) {
209 return PLDM_REQUESTER_SEND_FAIL;
210 }
211
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930212 uint8_t hdr[2] = { eid, mctp_msg_type };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100213
214 struct iovec iov[2];
215 iov[0].iov_base = hdr;
216 iov[0].iov_len = sizeof(hdr);
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000217 iov[1].iov_base = (uint8_t *)pldm_msg;
218 iov[1].iov_len = msg_len;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100219
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930220 struct msghdr msg = { 0 };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100221 msg.msg_iov = iov;
222 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
223
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000224 if (msg_len > INT_MAX ||
Rashmica Gupta04273e92023-06-16 16:03:37 +1000225 pldm_socket_sndbuf_accomodate(&(demux->socket_send_buf),
Rashmica Guptaf1ebde42023-07-31 14:17:57 +1000226 (int)msg_len)) {
Rashmica Gupta04273e92023-06-16 16:03:37 +1000227 return PLDM_REQUESTER_SEND_FAIL;
228 }
229
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100230 ssize_t rc = sendmsg(demux->socket, &msg, 0);
231 if (rc == -1) {
232 return PLDM_REQUESTER_SEND_FAIL;
233 }
234 return PLDM_REQUESTER_SUCCESS;
235}
236
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930237LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100238int pldm_transport_mctp_demux_init(struct pldm_transport_mctp_demux **ctx)
239{
240 if (!ctx || *ctx) {
241 return -EINVAL;
242 }
243
244 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930245 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100246 if (!demux) {
247 return -ENOMEM;
248 }
249
250 demux->transport.name = MCTP_DEMUX_NAME;
251 demux->transport.version = 1;
252 demux->transport.recv = pldm_transport_mctp_demux_recv;
253 demux->transport.send = pldm_transport_mctp_demux_send;
254 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
255 demux->socket = pldm_transport_mctp_demux_open();
256 if (demux->socket == -1) {
257 free(demux);
258 return -1;
259 }
Rashmica Gupta04273e92023-06-16 16:03:37 +1000260
261 if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) {
262 close(demux->socket);
263 free(demux);
264 return -1;
265 }
266
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100267 *ctx = demux;
268 return 0;
269}
270
Andrew Jeffery0a6d6822023-08-22 21:40:32 +0930271LIBPLDM_ABI_STABLE
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100272void pldm_transport_mctp_demux_destroy(struct pldm_transport_mctp_demux *ctx)
273{
274 if (!ctx) {
275 return;
276 }
277 close(ctx->socket);
278 free(ctx);
279}
280
281/* Temporary for old API */
282struct pldm_transport_mctp_demux *
283pldm_transport_mctp_demux_init_with_fd(int mctp_fd)
284{
285 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930286 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100287 if (!demux) {
288 return NULL;
289 }
290
291 demux->transport.name = MCTP_DEMUX_NAME;
292 demux->transport.version = 1;
293 demux->transport.recv = pldm_transport_mctp_demux_recv;
294 demux->transport.send = pldm_transport_mctp_demux_send;
295 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
296 /* dup is so we can call pldm_transport_mctp_demux_destroy which closes
297 * the socket, without closing the fd that is being used by the consumer
298 */
299 demux->socket = dup(mctp_fd);
300 if (demux->socket == -1) {
301 free(demux);
302 return NULL;
303 }
Rashmica Gupta04273e92023-06-16 16:03:37 +1000304
305 if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) {
306 close(demux->socket);
307 free(demux);
308 return NULL;
309 }
310
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100311 return demux;
312}
313
314int pldm_transport_mctp_demux_get_socket_fd(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930315 struct pldm_transport_mctp_demux *ctx)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100316{
Andrew Jefferya4da6852023-06-29 10:47:24 +0930317 if (ctx) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100318 return ctx->socket;
319 }
Andrew Jefferya4da6852023-06-29 10:47:24 +0930320
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100321 return -1;
322}