blob: 427c52aff3c170d87321b1caa26c4df5f8716a11 [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"
Rashmica Gupta04273e92023-06-16 16:03:37 +10006#include "socket.h"
Rashmica Guptac1b66f42022-12-09 16:24:45 +11007#include "transport.h"
8
9#include <errno.h>
Rashmica Gupta04273e92023-06-16 16:03:37 +100010#include <limits.h>
Rashmica Guptac1b66f42022-12-09 16:24:45 +110011#include <poll.h>
12#include <stdlib.h>
13#include <string.h>
14#include <sys/socket.h>
15#include <sys/types.h>
16#include <sys/un.h>
17#include <unistd.h>
18
19#define MCTP_DEMUX_NAME "libmctp-demux-daemon"
20const uint8_t mctp_msg_type = MCTP_MSG_TYPE_PLDM;
21
22struct pldm_transport_mctp_demux {
23 struct pldm_transport transport;
24 int socket;
25 /* In the future this probably needs to move to a tid-eid-uuid/network
26 * id mapping for multi mctp networks */
27 pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID];
Rashmica Gupta04273e92023-06-16 16:03:37 +100028 struct pldm_socket_sndbuf socket_send_buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +110029};
30
31#define transport_to_demux(ptr) \
32 container_of(ptr, struct pldm_transport_mctp_demux, transport)
33
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093034LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110035struct pldm_transport *
36pldm_transport_mctp_demux_core(struct pldm_transport_mctp_demux *ctx)
37{
38 return &ctx->transport;
39}
40
41static pldm_requester_rc_t pldm_transport_mctp_demux_open(void)
42{
43 int fd = -1;
44 ssize_t rc = -1;
45
46 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
47 if (fd == -1) {
48 return fd;
49 }
50
51 const char path[] = "\0mctp-mux";
52 struct sockaddr_un addr;
53 addr.sun_family = AF_UNIX;
54 memcpy(addr.sun_path, path, sizeof(path) - 1);
55 rc = connect(fd, (struct sockaddr *)&addr,
56 sizeof(path) + sizeof(addr.sun_family) - 1);
57 if (rc == -1) {
58 return PLDM_REQUESTER_OPEN_FAIL;
59 }
60 rc = write(fd, &mctp_msg_type, sizeof(mctp_msg_type));
61 if (rc == -1) {
62 return PLDM_REQUESTER_OPEN_FAIL;
63 }
64
65 return fd;
66}
67
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093068LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110069int pldm_transport_mctp_demux_init_pollfd(struct pldm_transport *t,
70 struct pollfd *pollfd)
71{
72 struct pldm_transport_mctp_demux *ctx = transport_to_demux(t);
73 pollfd->fd = ctx->socket;
74 pollfd->events = POLLIN;
75 return 0;
76}
77
78static int
79pldm_transport_mctp_demux_get_eid(struct pldm_transport_mctp_demux *ctx,
80 pldm_tid_t tid, mctp_eid_t *eid)
81{
82 int i;
83 for (i = 0; i < MCTP_MAX_NUM_EID; i++) {
84 if (ctx->tid_eid_map[i] == tid) {
85 *eid = i;
86 return 0;
87 }
88 }
89 *eid = -1;
90 return -1;
91}
92
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093093LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110094int pldm_transport_mctp_demux_map_tid(struct pldm_transport_mctp_demux *ctx,
95 pldm_tid_t tid, mctp_eid_t eid)
96{
97 ctx->tid_eid_map[eid] = tid;
98
99 return 0;
100}
101
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930102LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100103int pldm_transport_mctp_demux_unmap_tid(struct pldm_transport_mctp_demux *ctx,
104 __attribute__((unused)) pldm_tid_t tid,
105 mctp_eid_t eid)
106{
107 ctx->tid_eid_map[eid] = 0;
108
109 return 0;
110}
111
112static pldm_requester_rc_t
113pldm_transport_mctp_demux_recv(struct pldm_transport *t, pldm_tid_t tid,
114 void **pldm_resp_msg, size_t *resp_msg_len)
115{
116 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
117 mctp_eid_t eid = 0;
118 int rc = pldm_transport_mctp_demux_get_eid(demux, tid, &eid);
119 if (rc) {
120 return PLDM_REQUESTER_RECV_FAIL;
121 }
122
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930123 ssize_t min_len = sizeof(eid) + sizeof(mctp_msg_type) +
124 sizeof(struct pldm_msg_hdr);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100125 ssize_t length = recv(demux->socket, NULL, 0, MSG_PEEK | MSG_TRUNC);
126 if (length <= 0) {
127 return PLDM_REQUESTER_RECV_FAIL;
128 }
129 uint8_t *buf = malloc(length);
130 if (buf == NULL) {
131 return PLDM_REQUESTER_RECV_FAIL;
132 }
133 if (length < min_len) {
134 /* read and discard */
135 recv(demux->socket, buf, length, 0);
136 free(buf);
137 return PLDM_REQUESTER_INVALID_RECV_LEN;
138 }
139 struct iovec iov[2];
140 uint8_t mctp_prefix[2];
141 size_t mctp_prefix_len = 2;
142 size_t pldm_len = length - mctp_prefix_len;
143 iov[0].iov_len = mctp_prefix_len;
144 iov[0].iov_base = mctp_prefix;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100145 iov[1].iov_len = pldm_len;
Andrew Jefferya8532b52023-06-05 11:58:55 +0930146 iov[1].iov_base = buf;
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930147 struct msghdr msg = { 0 };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100148 msg.msg_iov = iov;
149 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
150 ssize_t bytes = recvmsg(demux->socket, &msg, 0);
151 if (length != bytes) {
Andrew Jefferya8532b52023-06-05 11:58:55 +0930152 free(buf);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100153 return PLDM_REQUESTER_INVALID_RECV_LEN;
154 }
155 if ((mctp_prefix[0] != eid) || (mctp_prefix[1] != mctp_msg_type)) {
Andrew Jefferya8532b52023-06-05 11:58:55 +0930156 free(buf);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100157 return PLDM_REQUESTER_NOT_PLDM_MSG;
158 }
Andrew Jefferya8532b52023-06-05 11:58:55 +0930159 *pldm_resp_msg = buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100160 *resp_msg_len = pldm_len;
161 return PLDM_REQUESTER_SUCCESS;
162}
163
164static pldm_requester_rc_t
165pldm_transport_mctp_demux_send(struct pldm_transport *t, pldm_tid_t tid,
166 const void *pldm_req_msg, size_t req_msg_len)
167{
168 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
169 mctp_eid_t eid = 0;
170 if (pldm_transport_mctp_demux_get_eid(demux, tid, &eid)) {
171 return PLDM_REQUESTER_SEND_FAIL;
172 }
173
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930174 uint8_t hdr[2] = { eid, mctp_msg_type };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100175
176 struct iovec iov[2];
177 iov[0].iov_base = hdr;
178 iov[0].iov_len = sizeof(hdr);
179 iov[1].iov_base = (uint8_t *)pldm_req_msg;
180 iov[1].iov_len = req_msg_len;
181
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930182 struct msghdr msg = { 0 };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100183 msg.msg_iov = iov;
184 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
185
Rashmica Gupta04273e92023-06-16 16:03:37 +1000186 if (req_msg_len > INT_MAX ||
187 pldm_socket_sndbuf_accomodate(&(demux->socket_send_buf),
188 (int)req_msg_len)) {
189 return PLDM_REQUESTER_SEND_FAIL;
190 }
191
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100192 ssize_t rc = sendmsg(demux->socket, &msg, 0);
193 if (rc == -1) {
194 return PLDM_REQUESTER_SEND_FAIL;
195 }
196 return PLDM_REQUESTER_SUCCESS;
197}
198
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930199LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100200int pldm_transport_mctp_demux_init(struct pldm_transport_mctp_demux **ctx)
201{
202 if (!ctx || *ctx) {
203 return -EINVAL;
204 }
205
206 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930207 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100208 if (!demux) {
209 return -ENOMEM;
210 }
211
212 demux->transport.name = MCTP_DEMUX_NAME;
213 demux->transport.version = 1;
214 demux->transport.recv = pldm_transport_mctp_demux_recv;
215 demux->transport.send = pldm_transport_mctp_demux_send;
216 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
217 demux->socket = pldm_transport_mctp_demux_open();
218 if (demux->socket == -1) {
219 free(demux);
220 return -1;
221 }
Rashmica Gupta04273e92023-06-16 16:03:37 +1000222
223 if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) {
224 close(demux->socket);
225 free(demux);
226 return -1;
227 }
228
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100229 *ctx = demux;
230 return 0;
231}
232
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930233LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100234void pldm_transport_mctp_demux_destroy(struct pldm_transport_mctp_demux *ctx)
235{
236 if (!ctx) {
237 return;
238 }
239 close(ctx->socket);
240 free(ctx);
241}
242
243/* Temporary for old API */
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930244LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100245struct pldm_transport_mctp_demux *
246pldm_transport_mctp_demux_init_with_fd(int mctp_fd)
247{
248 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930249 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100250 if (!demux) {
251 return NULL;
252 }
253
254 demux->transport.name = MCTP_DEMUX_NAME;
255 demux->transport.version = 1;
256 demux->transport.recv = pldm_transport_mctp_demux_recv;
257 demux->transport.send = pldm_transport_mctp_demux_send;
258 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
259 /* dup is so we can call pldm_transport_mctp_demux_destroy which closes
260 * the socket, without closing the fd that is being used by the consumer
261 */
262 demux->socket = dup(mctp_fd);
263 if (demux->socket == -1) {
264 free(demux);
265 return NULL;
266 }
Rashmica Gupta04273e92023-06-16 16:03:37 +1000267
268 if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) {
269 close(demux->socket);
270 free(demux);
271 return NULL;
272 }
273
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100274 return demux;
275}
276
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930277LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100278int pldm_transport_mctp_demux_get_socket_fd(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930279 struct pldm_transport_mctp_demux *ctx)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100280{
Andrew Jefferya4da6852023-06-29 10:47:24 +0930281 if (ctx) {
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100282 return ctx->socket;
283 }
Andrew Jefferya4da6852023-06-29 10:47:24 +0930284
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100285 return -1;
286}