blob: 91946d28e478721ee61251eee00c07b22b20fe94 [file] [log] [blame]
Rashmica Guptac1b66f42022-12-09 16:24:45 +11001#include "../mctp-defines.h"
2#include "base.h"
3#include "container-of.h"
4#include "libpldm/pldm.h"
5#include "libpldm/transport.h"
6#include "transport.h"
7
8#include <errno.h>
9#include <poll.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/socket.h>
13#include <sys/types.h>
14#include <sys/un.h>
15#include <unistd.h>
16
17#define MCTP_DEMUX_NAME "libmctp-demux-daemon"
18const uint8_t mctp_msg_type = MCTP_MSG_TYPE_PLDM;
19
20struct pldm_transport_mctp_demux {
21 struct pldm_transport transport;
22 int socket;
23 /* In the future this probably needs to move to a tid-eid-uuid/network
24 * id mapping for multi mctp networks */
25 pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID];
26};
27
28#define transport_to_demux(ptr) \
29 container_of(ptr, struct pldm_transport_mctp_demux, transport)
30
31struct pldm_transport *
32pldm_transport_mctp_demux_core(struct pldm_transport_mctp_demux *ctx)
33{
34 return &ctx->transport;
35}
36
37static pldm_requester_rc_t pldm_transport_mctp_demux_open(void)
38{
39 int fd = -1;
40 ssize_t rc = -1;
41
42 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
43 if (fd == -1) {
44 return fd;
45 }
46
47 const char path[] = "\0mctp-mux";
48 struct sockaddr_un addr;
49 addr.sun_family = AF_UNIX;
50 memcpy(addr.sun_path, path, sizeof(path) - 1);
51 rc = connect(fd, (struct sockaddr *)&addr,
52 sizeof(path) + sizeof(addr.sun_family) - 1);
53 if (rc == -1) {
54 return PLDM_REQUESTER_OPEN_FAIL;
55 }
56 rc = write(fd, &mctp_msg_type, sizeof(mctp_msg_type));
57 if (rc == -1) {
58 return PLDM_REQUESTER_OPEN_FAIL;
59 }
60
61 return fd;
62}
63
64int pldm_transport_mctp_demux_init_pollfd(struct pldm_transport *t,
65 struct pollfd *pollfd)
66{
67 struct pldm_transport_mctp_demux *ctx = transport_to_demux(t);
68 pollfd->fd = ctx->socket;
69 pollfd->events = POLLIN;
70 return 0;
71}
72
73static int
74pldm_transport_mctp_demux_get_eid(struct pldm_transport_mctp_demux *ctx,
75 pldm_tid_t tid, mctp_eid_t *eid)
76{
77 int i;
78 for (i = 0; i < MCTP_MAX_NUM_EID; i++) {
79 if (ctx->tid_eid_map[i] == tid) {
80 *eid = i;
81 return 0;
82 }
83 }
84 *eid = -1;
85 return -1;
86}
87
88int pldm_transport_mctp_demux_map_tid(struct pldm_transport_mctp_demux *ctx,
89 pldm_tid_t tid, mctp_eid_t eid)
90{
91 ctx->tid_eid_map[eid] = tid;
92
93 return 0;
94}
95
96int pldm_transport_mctp_demux_unmap_tid(struct pldm_transport_mctp_demux *ctx,
97 __attribute__((unused)) pldm_tid_t tid,
98 mctp_eid_t eid)
99{
100 ctx->tid_eid_map[eid] = 0;
101
102 return 0;
103}
104
105static pldm_requester_rc_t
106pldm_transport_mctp_demux_recv(struct pldm_transport *t, pldm_tid_t tid,
107 void **pldm_resp_msg, size_t *resp_msg_len)
108{
109 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
110 mctp_eid_t eid = 0;
111 int rc = pldm_transport_mctp_demux_get_eid(demux, tid, &eid);
112 if (rc) {
113 return PLDM_REQUESTER_RECV_FAIL;
114 }
115
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930116 ssize_t min_len = sizeof(eid) + sizeof(mctp_msg_type) +
117 sizeof(struct pldm_msg_hdr);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100118 ssize_t length = recv(demux->socket, NULL, 0, MSG_PEEK | MSG_TRUNC);
119 if (length <= 0) {
120 return PLDM_REQUESTER_RECV_FAIL;
121 }
122 uint8_t *buf = malloc(length);
123 if (buf == NULL) {
124 return PLDM_REQUESTER_RECV_FAIL;
125 }
126 if (length < min_len) {
127 /* read and discard */
128 recv(demux->socket, buf, length, 0);
129 free(buf);
130 return PLDM_REQUESTER_INVALID_RECV_LEN;
131 }
132 struct iovec iov[2];
133 uint8_t mctp_prefix[2];
134 size_t mctp_prefix_len = 2;
135 size_t pldm_len = length - mctp_prefix_len;
136 iov[0].iov_len = mctp_prefix_len;
137 iov[0].iov_base = mctp_prefix;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100138 iov[1].iov_len = pldm_len;
Andrew Jefferya8532b52023-06-05 11:58:55 +0930139 iov[1].iov_base = buf;
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930140 struct msghdr msg = { 0 };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100141 msg.msg_iov = iov;
142 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
143 ssize_t bytes = recvmsg(demux->socket, &msg, 0);
144 if (length != bytes) {
Andrew Jefferya8532b52023-06-05 11:58:55 +0930145 free(buf);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100146 return PLDM_REQUESTER_INVALID_RECV_LEN;
147 }
148 if ((mctp_prefix[0] != eid) || (mctp_prefix[1] != mctp_msg_type)) {
Andrew Jefferya8532b52023-06-05 11:58:55 +0930149 free(buf);
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100150 return PLDM_REQUESTER_NOT_PLDM_MSG;
151 }
Andrew Jefferya8532b52023-06-05 11:58:55 +0930152 *pldm_resp_msg = buf;
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100153 *resp_msg_len = pldm_len;
154 return PLDM_REQUESTER_SUCCESS;
155}
156
157static pldm_requester_rc_t
158pldm_transport_mctp_demux_send(struct pldm_transport *t, pldm_tid_t tid,
159 const void *pldm_req_msg, size_t req_msg_len)
160{
161 struct pldm_transport_mctp_demux *demux = transport_to_demux(t);
162 mctp_eid_t eid = 0;
163 if (pldm_transport_mctp_demux_get_eid(demux, tid, &eid)) {
164 return PLDM_REQUESTER_SEND_FAIL;
165 }
166
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930167 uint8_t hdr[2] = { eid, mctp_msg_type };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100168
169 struct iovec iov[2];
170 iov[0].iov_base = hdr;
171 iov[0].iov_len = sizeof(hdr);
172 iov[1].iov_base = (uint8_t *)pldm_req_msg;
173 iov[1].iov_len = req_msg_len;
174
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930175 struct msghdr msg = { 0 };
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100176 msg.msg_iov = iov;
177 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
178
179 ssize_t rc = sendmsg(demux->socket, &msg, 0);
180 if (rc == -1) {
181 return PLDM_REQUESTER_SEND_FAIL;
182 }
183 return PLDM_REQUESTER_SUCCESS;
184}
185
186int pldm_transport_mctp_demux_init(struct pldm_transport_mctp_demux **ctx)
187{
188 if (!ctx || *ctx) {
189 return -EINVAL;
190 }
191
192 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930193 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100194 if (!demux) {
195 return -ENOMEM;
196 }
197
198 demux->transport.name = MCTP_DEMUX_NAME;
199 demux->transport.version = 1;
200 demux->transport.recv = pldm_transport_mctp_demux_recv;
201 demux->transport.send = pldm_transport_mctp_demux_send;
202 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
203 demux->socket = pldm_transport_mctp_demux_open();
204 if (demux->socket == -1) {
205 free(demux);
206 return -1;
207 }
208 *ctx = demux;
209 return 0;
210}
211
212void pldm_transport_mctp_demux_destroy(struct pldm_transport_mctp_demux *ctx)
213{
214 if (!ctx) {
215 return;
216 }
217 close(ctx->socket);
218 free(ctx);
219}
220
221/* Temporary for old API */
222struct pldm_transport_mctp_demux *
223pldm_transport_mctp_demux_init_with_fd(int mctp_fd)
224{
225 struct pldm_transport_mctp_demux *demux =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930226 calloc(1, sizeof(struct pldm_transport_mctp_demux));
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100227 if (!demux) {
228 return NULL;
229 }
230
231 demux->transport.name = MCTP_DEMUX_NAME;
232 demux->transport.version = 1;
233 demux->transport.recv = pldm_transport_mctp_demux_recv;
234 demux->transport.send = pldm_transport_mctp_demux_send;
235 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
236 /* dup is so we can call pldm_transport_mctp_demux_destroy which closes
237 * the socket, without closing the fd that is being used by the consumer
238 */
239 demux->socket = dup(mctp_fd);
240 if (demux->socket == -1) {
241 free(demux);
242 return NULL;
243 }
244 return demux;
245}
246
247int pldm_transport_mctp_demux_get_socket_fd(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930248 struct pldm_transport_mctp_demux *ctx)
Rashmica Guptac1b66f42022-12-09 16:24:45 +1100249{
250 if (ctx && ctx->socket) {
251 return ctx->socket;
252 }
253 return -1;
254}