1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #include "container-of.h"
3 #include "mctp-defines.h"
4 #include "responder.h"
5 #include "socket.h"
6 #include "transport.h"
7
8 #include <libpldm/base.h>
9 #include <libpldm/pldm.h>
10 #include <libpldm/transport.h>
11 #include <libpldm/transport/af-mctp.h>
12
13 #include <errno.h>
14 #include <limits.h>
15 #include <linux/mctp.h>
16 #include <poll.h>
17 #include <stdbool.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/socket.h>
21 #include <sys/types.h>
22 #include <sys/un.h>
23 #include <unistd.h>
24
25 struct pldm_responder_cookie_af_mctp {
26 struct pldm_responder_cookie req;
27 struct sockaddr_mctp smctp;
28 };
29
30 #define cookie_to_af_mctp(c) \
31 container_of((c), struct pldm_responder_cookie_af_mctp, req)
32
33 #define AF_MCTP_NAME "AF_MCTP"
34 struct pldm_transport_af_mctp {
35 struct pldm_transport transport;
36 int socket;
37 pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID];
38 struct pldm_socket_sndbuf socket_send_buf;
39 bool bound;
40 struct pldm_responder_cookie cookie_jar;
41 };
42
43 #define transport_to_af_mctp(ptr) \
44 container_of(ptr, struct pldm_transport_af_mctp, transport)
45
46 LIBPLDM_ABI_STABLE
47 struct pldm_transport *
pldm_transport_af_mctp_core(struct pldm_transport_af_mctp * ctx)48 pldm_transport_af_mctp_core(struct pldm_transport_af_mctp *ctx)
49 {
50 return &ctx->transport;
51 }
52
53 LIBPLDM_ABI_STABLE
pldm_transport_af_mctp_init_pollfd(struct pldm_transport * t,struct pollfd * pollfd)54 int pldm_transport_af_mctp_init_pollfd(struct pldm_transport *t,
55 struct pollfd *pollfd)
56 {
57 struct pldm_transport_af_mctp *ctx = transport_to_af_mctp(t);
58 pollfd->fd = ctx->socket;
59 pollfd->events = POLLIN;
60 return 0;
61 }
62
pldm_transport_af_mctp_get_eid(struct pldm_transport_af_mctp * ctx,pldm_tid_t tid,mctp_eid_t * eid)63 static int pldm_transport_af_mctp_get_eid(struct pldm_transport_af_mctp *ctx,
64 pldm_tid_t tid, mctp_eid_t *eid)
65 {
66 int i;
67 for (i = 0; i < MCTP_MAX_NUM_EID; i++) {
68 if (ctx->tid_eid_map[i] == tid) {
69 *eid = i;
70 return 0;
71 }
72 }
73 *eid = -1;
74 return -1;
75 }
76
pldm_transport_af_mctp_get_tid(struct pldm_transport_af_mctp * ctx,mctp_eid_t eid,pldm_tid_t * tid)77 static int pldm_transport_af_mctp_get_tid(struct pldm_transport_af_mctp *ctx,
78 mctp_eid_t eid, pldm_tid_t *tid)
79 {
80 if (ctx->tid_eid_map[eid] != 0) {
81 *tid = ctx->tid_eid_map[eid];
82 return 0;
83 }
84 return -1;
85 }
86
87 LIBPLDM_ABI_STABLE
pldm_transport_af_mctp_map_tid(struct pldm_transport_af_mctp * ctx,pldm_tid_t tid,mctp_eid_t eid)88 int pldm_transport_af_mctp_map_tid(struct pldm_transport_af_mctp *ctx,
89 pldm_tid_t tid, mctp_eid_t eid)
90 {
91 ctx->tid_eid_map[eid] = tid;
92
93 return 0;
94 }
95
96 LIBPLDM_ABI_STABLE
pldm_transport_af_mctp_unmap_tid(struct pldm_transport_af_mctp * ctx,pldm_tid_t tid,mctp_eid_t eid)97 int pldm_transport_af_mctp_unmap_tid(struct pldm_transport_af_mctp *ctx,
98 __attribute__((unused)) pldm_tid_t tid,
99 mctp_eid_t eid)
100 {
101 ctx->tid_eid_map[eid] = 0;
102
103 return 0;
104 }
105
pldm_transport_af_mctp_recv(struct pldm_transport * t,pldm_tid_t * tid,void ** pldm_msg,size_t * msg_len)106 static pldm_requester_rc_t pldm_transport_af_mctp_recv(struct pldm_transport *t,
107 pldm_tid_t *tid,
108 void **pldm_msg,
109 size_t *msg_len)
110 {
111 struct pldm_transport_af_mctp *af_mctp = transport_to_af_mctp(t);
112 struct sockaddr_mctp addr = { 0 };
113 socklen_t addrlen = sizeof(addr);
114 struct pldm_msg_hdr *hdr;
115 pldm_requester_rc_t res;
116 mctp_eid_t eid = 0;
117 ssize_t length;
118 void *msg;
119 int rc;
120
121 length = recv(af_mctp->socket, NULL, 0, MSG_PEEK | MSG_TRUNC);
122 if (length <= 0) {
123 return PLDM_REQUESTER_RECV_FAIL;
124 }
125
126 msg = malloc(length);
127 if (!msg) {
128 return PLDM_REQUESTER_RECV_FAIL;
129 }
130
131 length = recvfrom(af_mctp->socket, msg, length, MSG_TRUNC,
132 (struct sockaddr *)&addr, &addrlen);
133 if (length < (ssize_t)sizeof(struct pldm_msg_hdr)) {
134 res = PLDM_REQUESTER_INVALID_RECV_LEN;
135 goto cleanup_msg;
136 }
137
138 eid = addr.smctp_addr.s_addr;
139 rc = pldm_transport_af_mctp_get_tid(af_mctp, eid, tid);
140 if (rc) {
141 res = PLDM_REQUESTER_RECV_FAIL;
142 goto cleanup_msg;
143 }
144
145 hdr = msg;
146
147 if (af_mctp->bound && hdr->request) {
148 struct pldm_responder_cookie_af_mctp *cookie;
149
150 cookie = malloc(sizeof(*cookie));
151 if (!cookie) {
152 res = PLDM_REQUESTER_RECV_FAIL;
153 goto cleanup_msg;
154 }
155
156 cookie->req.tid = *tid,
157 cookie->req.instance_id = hdr->instance_id,
158 cookie->req.type = hdr->type,
159 cookie->req.command = hdr->command;
160 cookie->smctp = addr;
161
162 rc = pldm_responder_cookie_track(&af_mctp->cookie_jar,
163 &cookie->req);
164 if (rc) {
165 res = PLDM_REQUESTER_RECV_FAIL;
166 goto cleanup_msg;
167 }
168 }
169
170 *pldm_msg = msg;
171 *msg_len = length;
172
173 return PLDM_REQUESTER_SUCCESS;
174
175 cleanup_msg:
176 free(msg);
177
178 return res;
179 }
180
pldm_transport_af_mctp_send(struct pldm_transport * t,pldm_tid_t tid,const void * pldm_msg,size_t msg_len)181 static pldm_requester_rc_t pldm_transport_af_mctp_send(struct pldm_transport *t,
182 pldm_tid_t tid,
183 const void *pldm_msg,
184 size_t msg_len)
185 {
186 struct pldm_transport_af_mctp *af_mctp = transport_to_af_mctp(t);
187 const struct pldm_msg_hdr *hdr;
188 struct sockaddr_mctp addr = { 0 };
189
190 if (msg_len < (ssize_t)sizeof(struct pldm_msg_hdr)) {
191 return PLDM_REQUESTER_SEND_FAIL;
192 }
193
194 hdr = pldm_msg;
195 if (af_mctp->bound && !hdr->request) {
196 struct pldm_responder_cookie_af_mctp *cookie;
197 struct pldm_responder_cookie *req;
198
199 req = pldm_responder_cookie_untrack(&af_mctp->cookie_jar, tid,
200 hdr->instance_id, hdr->type,
201 hdr->command);
202 if (!req) {
203 return PLDM_REQUESTER_SEND_FAIL;
204 }
205
206 cookie = cookie_to_af_mctp(req);
207 addr = cookie->smctp;
208 /* Clear the TO to indicate a response */
209 addr.smctp_tag &= ~MCTP_TAG_OWNER;
210 free(cookie);
211 } else {
212 mctp_eid_t eid = 0;
213 if (pldm_transport_af_mctp_get_eid(af_mctp, tid, &eid)) {
214 return PLDM_REQUESTER_SEND_FAIL;
215 }
216
217 addr.smctp_family = AF_MCTP;
218 addr.smctp_addr.s_addr = eid;
219 addr.smctp_type = MCTP_MSG_TYPE_PLDM;
220 addr.smctp_tag = MCTP_TAG_OWNER;
221 }
222
223 if (msg_len > INT_MAX ||
224 pldm_socket_sndbuf_accomodate(&(af_mctp->socket_send_buf),
225 (int)msg_len)) {
226 return PLDM_REQUESTER_SEND_FAIL;
227 }
228
229 ssize_t rc = sendto(af_mctp->socket, pldm_msg, msg_len, 0,
230 (struct sockaddr *)&addr, sizeof(addr));
231 if (rc == -1) {
232 return PLDM_REQUESTER_SEND_FAIL;
233 }
234
235 return PLDM_REQUESTER_SUCCESS;
236 }
237
238 LIBPLDM_ABI_STABLE
pldm_transport_af_mctp_init(struct pldm_transport_af_mctp ** ctx)239 int pldm_transport_af_mctp_init(struct pldm_transport_af_mctp **ctx)
240 {
241 if (!ctx || *ctx) {
242 return -EINVAL;
243 }
244
245 struct pldm_transport_af_mctp *af_mctp =
246 calloc(1, sizeof(struct pldm_transport_af_mctp));
247 if (!af_mctp) {
248 return -ENOMEM;
249 }
250
251 af_mctp->transport.name = AF_MCTP_NAME;
252 af_mctp->transport.version = 1;
253 af_mctp->transport.recv = pldm_transport_af_mctp_recv;
254 af_mctp->transport.send = pldm_transport_af_mctp_send;
255 af_mctp->transport.init_pollfd = pldm_transport_af_mctp_init_pollfd;
256 af_mctp->bound = false;
257 af_mctp->cookie_jar.next = NULL;
258 af_mctp->socket = socket(AF_MCTP, SOCK_DGRAM, 0);
259 if (af_mctp->socket == -1) {
260 free(af_mctp);
261 return -1;
262 }
263
264 if (pldm_socket_sndbuf_init(&af_mctp->socket_send_buf,
265 af_mctp->socket)) {
266 close(af_mctp->socket);
267 free(af_mctp);
268 return -1;
269 }
270
271 *ctx = af_mctp;
272 return 0;
273 }
274
275 LIBPLDM_ABI_STABLE
pldm_transport_af_mctp_destroy(struct pldm_transport_af_mctp * ctx)276 void pldm_transport_af_mctp_destroy(struct pldm_transport_af_mctp *ctx)
277 {
278 if (!ctx) {
279 return;
280 }
281 close(ctx->socket);
282 free(ctx);
283 }
284
285 LIBPLDM_ABI_STABLE
pldm_transport_af_mctp_bind(struct pldm_transport_af_mctp * transport,const struct sockaddr_mctp * smctp,size_t len)286 int pldm_transport_af_mctp_bind(struct pldm_transport_af_mctp *transport,
287 const struct sockaddr_mctp *smctp, size_t len)
288 {
289 struct sockaddr_mctp lsmctp = { 0 };
290 int rc;
291
292 if (!transport) {
293 return PLDM_REQUESTER_INVALID_SETUP;
294 }
295
296 if (!smctp && len) {
297 return PLDM_REQUESTER_INVALID_SETUP;
298 }
299
300 if (!smctp) {
301 lsmctp.smctp_family = AF_MCTP;
302 lsmctp.smctp_network = MCTP_NET_ANY;
303 lsmctp.smctp_addr.s_addr = MCTP_ADDR_ANY;
304 lsmctp.smctp_type = MCTP_MSG_TYPE_PLDM;
305 lsmctp.smctp_tag = MCTP_TAG_OWNER;
306 smctp = &lsmctp;
307 len = sizeof(lsmctp);
308 }
309
310 if (smctp->smctp_family != AF_MCTP ||
311 smctp->smctp_type != MCTP_MSG_TYPE_PLDM ||
312 smctp->smctp_tag != MCTP_TAG_OWNER) {
313 return PLDM_REQUESTER_INVALID_SETUP;
314 }
315
316 if (len != sizeof(*smctp)) {
317 return PLDM_REQUESTER_INVALID_SETUP;
318 }
319
320 rc = bind(transport->socket, (const struct sockaddr *)smctp,
321 sizeof(*smctp));
322 if (rc) {
323 return PLDM_REQUESTER_SETUP_FAIL;
324 }
325
326 transport->bound = true;
327
328 return PLDM_REQUESTER_SUCCESS;
329 }
330