blob: 2518d93f81e9afad22870ae84be3bd56544fbb0d [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"
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 Jeffery9d2a1c62023-06-05 13:02:16 +093035LIBPLDM_ABI_TESTING
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 Jeffery9d2a1c62023-06-05 13:02:16 +093069LIBPLDM_ABI_TESTING
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
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093094LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +110095int pldm_transport_mctp_demux_map_tid(struct pldm_transport_mctp_demux *ctx,
96 pldm_tid_t tid, mctp_eid_t eid)
97{
98 ctx->tid_eid_map[eid] = tid;
99
100 return 0;
101}
102
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930103LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100104int pldm_transport_mctp_demux_unmap_tid(struct pldm_transport_mctp_demux *ctx,
105 __attribute__((unused)) pldm_tid_t tid,
106 mctp_eid_t eid)
107{
108 ctx->tid_eid_map[eid] = 0;
109
110 return 0;
111}
112
113static pldm_requester_rc_t
114pldm_transport_mctp_demux_recv(struct pldm_transport *t, pldm_tid_t tid,
115 void **pldm_resp_msg, size_t *resp_msg_len)
116{
117 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
118 mctp_eid_t eid = 0;
119 int rc = pldm_transport_mctp_demux_get_eid(demux, tid, &eid);
120 if (rc) {
121 return PLDM_REQUESTER_RECV_FAIL;
122 }
123
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930124 ssize_t min_len = sizeof(eid) + sizeof(mctp_msg_type) +
125 sizeof(struct pldm_msg_hdr);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100126 ssize_t length = recv(demux->socket, NULL, 0, MSG_PEEK | MSG_TRUNC);
127 if (length <= 0) {
128 return PLDM_REQUESTER_RECV_FAIL;
129 }
130 uint8_t *buf = malloc(length);
131 if (buf == NULL) {
132 return PLDM_REQUESTER_RECV_FAIL;
133 }
134 if (length < min_len) {
135 /* read and discard */
136 recv(demux->socket, buf, length, 0);
137 free(buf);
138 return PLDM_REQUESTER_INVALID_RECV_LEN;
139 }
140 struct iovec iov[2];
141 uint8_t mctp_prefix[2];
142 size_t mctp_prefix_len = 2;
143 size_t pldm_len = length - mctp_prefix_len;
144 iov[0].iov_len = mctp_prefix_len;
145 iov[0].iov_base = mctp_prefix;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100146 iov[1].iov_len = pldm_len;
Andrew Jefferya8532b52023-06-05 11:58:55 +0930147 iov[1].iov_base = buf;
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930148 struct msghdr msg = { 0 };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100149 msg.msg_iov = iov;
150 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
151 ssize_t bytes = recvmsg(demux->socket, &msg, 0);
152 if (length != bytes) {
Andrew Jefferya8532b52023-06-05 11:58:55 +0930153 free(buf);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100154 return PLDM_REQUESTER_INVALID_RECV_LEN;
155 }
156 if ((mctp_prefix[0] != eid) || (mctp_prefix[1] != mctp_msg_type)) {
Andrew Jefferya8532b52023-06-05 11:58:55 +0930157 free(buf);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100158 return PLDM_REQUESTER_NOT_PLDM_MSG;
159 }
Andrew Jefferya8532b52023-06-05 11:58:55 +0930160 *pldm_resp_msg = buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100161 *resp_msg_len = pldm_len;
162 return PLDM_REQUESTER_SUCCESS;
163}
164
165static pldm_requester_rc_t
166pldm_transport_mctp_demux_send(struct pldm_transport *t, pldm_tid_t tid,
167 const void *pldm_req_msg, size_t req_msg_len)
168{
169 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
170 mctp_eid_t eid = 0;
171 if (pldm_transport_mctp_demux_get_eid(demux, tid, &eid)) {
172 return PLDM_REQUESTER_SEND_FAIL;
173 }
174
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930175 uint8_t hdr[2] = { eid, mctp_msg_type };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100176
177 struct iovec iov[2];
178 iov[0].iov_base = hdr;
179 iov[0].iov_len = sizeof(hdr);
180 iov[1].iov_base = (uint8_t *)pldm_req_msg;
181 iov[1].iov_len = req_msg_len;
182
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930183 struct msghdr msg = { 0 };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100184 msg.msg_iov = iov;
185 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
186
Rashmica Gupta04273e92023-06-16 16:03:37 +1000187 if (req_msg_len > INT_MAX ||
188 pldm_socket_sndbuf_accomodate(&(demux->socket_send_buf),
189 (int)req_msg_len)) {
190 return PLDM_REQUESTER_SEND_FAIL;
191 }
192
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100193 ssize_t rc = sendmsg(demux->socket, &msg, 0);
194 if (rc == -1) {
195 return PLDM_REQUESTER_SEND_FAIL;
196 }
197 return PLDM_REQUESTER_SUCCESS;
198}
199
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930200LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100201int pldm_transport_mctp_demux_init(struct pldm_transport_mctp_demux **ctx)
202{
203 if (!ctx || *ctx) {
204 return -EINVAL;
205 }
206
207 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930208 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100209 if (!demux) {
210 return -ENOMEM;
211 }
212
213 demux->transport.name = MCTP_DEMUX_NAME;
214 demux->transport.version = 1;
215 demux->transport.recv = pldm_transport_mctp_demux_recv;
216 demux->transport.send = pldm_transport_mctp_demux_send;
217 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
218 demux->socket = pldm_transport_mctp_demux_open();
219 if (demux->socket == -1) {
220 free(demux);
221 return -1;
222 }
Rashmica Gupta04273e92023-06-16 16:03:37 +1000223
224 if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) {
225 close(demux->socket);
226 free(demux);
227 return -1;
228 }
229
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100230 *ctx = demux;
231 return 0;
232}
233
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930234LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100235void pldm_transport_mctp_demux_destroy(struct pldm_transport_mctp_demux *ctx)
236{
237 if (!ctx) {
238 return;
239 }
240 close(ctx->socket);
241 free(ctx);
242}
243
244/* Temporary for old API */
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930245LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100246struct pldm_transport_mctp_demux *
247pldm_transport_mctp_demux_init_with_fd(int mctp_fd)
248{
249 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930250 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100251 if (!demux) {
252 return NULL;
253 }
254
255 demux->transport.name = MCTP_DEMUX_NAME;
256 demux->transport.version = 1;
257 demux->transport.recv = pldm_transport_mctp_demux_recv;
258 demux->transport.send = pldm_transport_mctp_demux_send;
259 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
260 /* dup is so we can call pldm_transport_mctp_demux_destroy which closes
261 * the socket, without closing the fd that is being used by the consumer
262 */
263 demux->socket = dup(mctp_fd);
264 if (demux->socket == -1) {
265 free(demux);
266 return NULL;
267 }
Rashmica Gupta04273e92023-06-16 16:03:37 +1000268
269 if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) {
270 close(demux->socket);
271 free(demux);
272 return NULL;
273 }
274
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100275 return demux;
276}
277
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930278LIBPLDM_ABI_TESTING
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100279int pldm_transport_mctp_demux_get_socket_fd(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930280 struct pldm_transport_mctp_demux *ctx)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100281{
282 if (ctx && ctx->socket) {
283 return ctx->socket;
284 }
285 return -1;
286}