blob: 466d33cf0457719c30c0a4aa3e96d495b52f387c [file] [log] [blame]
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301#include "config.h"
2#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"
7#include "transport.h"
8
9#include <errno.h>
10#include <poll.h>
11#include <stdlib.h>
12#include <string.h>
13#include <sys/socket.h>
14#include <sys/types.h>
15#include <sys/un.h>
16#include <unistd.h>
17
18#define MCTP_DEMUX_NAME "libmctp-demux-daemon"
19const uint8_t mctp_msg_type = MCTP_MSG_TYPE_PLDM;
20
21struct pldm_transport_mctp_demux {
22 struct pldm_transport transport;
23 int socket;
24 /* In the future this probably needs to move to a tid-eid-uuid/network
25 * id mapping for multi mctp networks */
26 pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID];
27};
28
29#define transport_to_demux(ptr) \
30 container_of(ptr, struct pldm_transport_mctp_demux, transport)
31
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093032LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110033struct pldm_transport *
34pldm_transport_mctp_demux_core(struct pldm_transport_mctp_demux *ctx)
35{
36 return &ctx->transport;
37}
38
39static pldm_requester_rc_t pldm_transport_mctp_demux_open(void)
40{
41 int fd = -1;
42 ssize_t rc = -1;
43
44 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
45 if (fd == -1) {
46 return fd;
47 }
48
49 const char path[] = "\0mctp-mux";
50 struct sockaddr_un addr;
51 addr.sun_family = AF_UNIX;
52 memcpy(addr.sun_path, path, sizeof(path) - 1);
53 rc = connect(fd, (struct sockaddr *)&addr,
54 sizeof(path) + sizeof(addr.sun_family) - 1);
55 if (rc == -1) {
56 return PLDM_REQUESTER_OPEN_FAIL;
57 }
58 rc = write(fd, &mctp_msg_type, sizeof(mctp_msg_type));
59 if (rc == -1) {
60 return PLDM_REQUESTER_OPEN_FAIL;
61 }
62
63 return fd;
64}
65
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093066LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110067int pldm_transport_mctp_demux_init_pollfd(struct pldm_transport *t,
68 struct pollfd *pollfd)
69{
70 struct pldm_transport_mctp_demux *ctx = transport_to_demux(t);
71 pollfd->fd = ctx->socket;
72 pollfd->events = POLLIN;
73 return 0;
74}
75
76static int
77pldm_transport_mctp_demux_get_eid(struct pldm_transport_mctp_demux *ctx,
78 pldm_tid_t tid, mctp_eid_t *eid)
79{
80 int i;
81 for (i = 0; i < MCTP_MAX_NUM_EID; i++) {
82 if (ctx->tid_eid_map[i] == tid) {
83 *eid = i;
84 return 0;
85 }
86 }
87 *eid = -1;
88 return -1;
89}
90
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093091LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110092int pldm_transport_mctp_demux_map_tid(struct pldm_transport_mctp_demux *ctx,
93 pldm_tid_t tid, mctp_eid_t eid)
94{
95 ctx->tid_eid_map[eid] = tid;
96
97 return 0;
98}
99
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930100LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100101int pldm_transport_mctp_demux_unmap_tid(struct pldm_transport_mctp_demux *ctx,
102 __attribute__((unused)) pldm_tid_t tid,
103 mctp_eid_t eid)
104{
105 ctx->tid_eid_map[eid] = 0;
106
107 return 0;
108}
109
110static pldm_requester_rc_t
111pldm_transport_mctp_demux_recv(struct pldm_transport *t, pldm_tid_t tid,
112 void **pldm_resp_msg, size_t *resp_msg_len)
113{
114 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
115 mctp_eid_t eid = 0;
116 int rc = pldm_transport_mctp_demux_get_eid(demux, tid, &eid);
117 if (rc) {
118 return PLDM_REQUESTER_RECV_FAIL;
119 }
120
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930121 ssize_t min_len = sizeof(eid) + sizeof(mctp_msg_type) +
122 sizeof(struct pldm_msg_hdr);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100123 ssize_t length = recv(demux->socket, NULL, 0, MSG_PEEK | MSG_TRUNC);
124 if (length <= 0) {
125 return PLDM_REQUESTER_RECV_FAIL;
126 }
127 uint8_t *buf = malloc(length);
128 if (buf == NULL) {
129 return PLDM_REQUESTER_RECV_FAIL;
130 }
131 if (length < min_len) {
132 /* read and discard */
133 recv(demux->socket, buf, length, 0);
134 free(buf);
135 return PLDM_REQUESTER_INVALID_RECV_LEN;
136 }
137 struct iovec iov[2];
138 uint8_t mctp_prefix[2];
139 size_t mctp_prefix_len = 2;
140 size_t pldm_len = length - mctp_prefix_len;
141 iov[0].iov_len = mctp_prefix_len;
142 iov[0].iov_base = mctp_prefix;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100143 iov[1].iov_len = pldm_len;
Andrew Jefferya8532b52023-06-05 11:58:55 +0930144 iov[1].iov_base = buf;
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930145 struct msghdr msg = { 0 };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100146 msg.msg_iov = iov;
147 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
148 ssize_t bytes = recvmsg(demux->socket, &msg, 0);
149 if (length != bytes) {
Andrew Jefferya8532b52023-06-05 11:58:55 +0930150 free(buf);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100151 return PLDM_REQUESTER_INVALID_RECV_LEN;
152 }
153 if ((mctp_prefix[0] != eid) || (mctp_prefix[1] != mctp_msg_type)) {
Andrew Jefferya8532b52023-06-05 11:58:55 +0930154 free(buf);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100155 return PLDM_REQUESTER_NOT_PLDM_MSG;
156 }
Andrew Jefferya8532b52023-06-05 11:58:55 +0930157 *pldm_resp_msg = buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100158 *resp_msg_len = pldm_len;
159 return PLDM_REQUESTER_SUCCESS;
160}
161
162static pldm_requester_rc_t
163pldm_transport_mctp_demux_send(struct pldm_transport *t, pldm_tid_t tid,
164 const void *pldm_req_msg, size_t req_msg_len)
165{
166 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
167 mctp_eid_t eid = 0;
168 if (pldm_transport_mctp_demux_get_eid(demux, tid, &eid)) {
169 return PLDM_REQUESTER_SEND_FAIL;
170 }
171
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930172 uint8_t hdr[2] = { eid, mctp_msg_type };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100173
174 struct iovec iov[2];
175 iov[0].iov_base = hdr;
176 iov[0].iov_len = sizeof(hdr);
177 iov[1].iov_base = (uint8_t *)pldm_req_msg;
178 iov[1].iov_len = req_msg_len;
179
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930180 struct msghdr msg = { 0 };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100181 msg.msg_iov = iov;
182 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
183
184 ssize_t rc = sendmsg(demux->socket, &msg, 0);
185 if (rc == -1) {
186 return PLDM_REQUESTER_SEND_FAIL;
187 }
188 return PLDM_REQUESTER_SUCCESS;
189}
190
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930191LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100192int pldm_transport_mctp_demux_init(struct pldm_transport_mctp_demux **ctx)
193{
194 if (!ctx || *ctx) {
195 return -EINVAL;
196 }
197
198 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930199 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100200 if (!demux) {
201 return -ENOMEM;
202 }
203
204 demux->transport.name = MCTP_DEMUX_NAME;
205 demux->transport.version = 1;
206 demux->transport.recv = pldm_transport_mctp_demux_recv;
207 demux->transport.send = pldm_transport_mctp_demux_send;
208 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
209 demux->socket = pldm_transport_mctp_demux_open();
210 if (demux->socket == -1) {
211 free(demux);
212 return -1;
213 }
214 *ctx = demux;
215 return 0;
216}
217
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930218LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100219void pldm_transport_mctp_demux_destroy(struct pldm_transport_mctp_demux *ctx)
220{
221 if (!ctx) {
222 return;
223 }
224 close(ctx->socket);
225 free(ctx);
226}
227
228/* Temporary for old API */
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930229LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100230struct pldm_transport_mctp_demux *
231pldm_transport_mctp_demux_init_with_fd(int mctp_fd)
232{
233 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930234 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100235 if (!demux) {
236 return NULL;
237 }
238
239 demux->transport.name = MCTP_DEMUX_NAME;
240 demux->transport.version = 1;
241 demux->transport.recv = pldm_transport_mctp_demux_recv;
242 demux->transport.send = pldm_transport_mctp_demux_send;
243 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
244 /* dup is so we can call pldm_transport_mctp_demux_destroy which closes
245 * the socket, without closing the fd that is being used by the consumer
246 */
247 demux->socket = dup(mctp_fd);
248 if (demux->socket == -1) {
249 free(demux);
250 return NULL;
251 }
252 return demux;
253}
254
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930255LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100256int pldm_transport_mctp_demux_get_socket_fd(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930257 struct pldm_transport_mctp_demux *ctx)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100258{
259 if (ctx && ctx->socket) {
260 return ctx->socket;
261 }
262 return -1;
263}