blob: 4b56f2f945b94a5f6bba6c54020c3c6ddb810753 [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
116 ssize_t min_len =
117 sizeof(eid) + sizeof(mctp_msg_type) + sizeof(struct pldm_msg_hdr);
118 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;
138 *pldm_resp_msg = buf;
139 if (*pldm_resp_msg == NULL) {
140 return PLDM_REQUESTER_RECV_FAIL;
141 }
142 iov[1].iov_len = pldm_len;
143 iov[1].iov_base = *pldm_resp_msg;
144 struct msghdr msg = {0};
145 msg.msg_iov = iov;
146 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
147 ssize_t bytes = recvmsg(demux->socket, &msg, 0);
148 if (length != bytes) {
149 free(*pldm_resp_msg);
150 *pldm_resp_msg = NULL;
151 return PLDM_REQUESTER_INVALID_RECV_LEN;
152 }
153 if ((mctp_prefix[0] != eid) || (mctp_prefix[1] != mctp_msg_type)) {
154 free(*pldm_resp_msg);
155 *pldm_resp_msg = NULL;
156 return PLDM_REQUESTER_NOT_PLDM_MSG;
157 }
158 *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
172 uint8_t hdr[2] = {eid, mctp_msg_type};
173
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
180 struct msghdr msg = {0};
181 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
191int pldm_transport_mctp_demux_init(struct pldm_transport_mctp_demux **ctx)
192{
193 if (!ctx || *ctx) {
194 return -EINVAL;
195 }
196
197 struct pldm_transport_mctp_demux *demux =
198 calloc(1, sizeof(struct pldm_transport_mctp_demux));
199 if (!demux) {
200 return -ENOMEM;
201 }
202
203 demux->transport.name = MCTP_DEMUX_NAME;
204 demux->transport.version = 1;
205 demux->transport.recv = pldm_transport_mctp_demux_recv;
206 demux->transport.send = pldm_transport_mctp_demux_send;
207 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
208 demux->socket = pldm_transport_mctp_demux_open();
209 if (demux->socket == -1) {
210 free(demux);
211 return -1;
212 }
213 *ctx = demux;
214 return 0;
215}
216
217void pldm_transport_mctp_demux_destroy(struct pldm_transport_mctp_demux *ctx)
218{
219 if (!ctx) {
220 return;
221 }
222 close(ctx->socket);
223 free(ctx);
224}
225
226/* Temporary for old API */
227struct pldm_transport_mctp_demux *
228pldm_transport_mctp_demux_init_with_fd(int mctp_fd)
229{
230 struct pldm_transport_mctp_demux *demux =
231 calloc(1, sizeof(struct pldm_transport_mctp_demux));
232 if (!demux) {
233 return NULL;
234 }
235
236 demux->transport.name = MCTP_DEMUX_NAME;
237 demux->transport.version = 1;
238 demux->transport.recv = pldm_transport_mctp_demux_recv;
239 demux->transport.send = pldm_transport_mctp_demux_send;
240 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd;
241 /* dup is so we can call pldm_transport_mctp_demux_destroy which closes
242 * the socket, without closing the fd that is being used by the consumer
243 */
244 demux->socket = dup(mctp_fd);
245 if (demux->socket == -1) {
246 free(demux);
247 return NULL;
248 }
249 return demux;
250}
251
252int pldm_transport_mctp_demux_get_socket_fd(
253 struct pldm_transport_mctp_demux *ctx)
254{
255 if (ctx && ctx->socket) {
256 return ctx->socket;
257 }
258 return -1;
259}