blob: 58826bc6e0d2f83ff83ff6631215bfaa5c48640f [file] [log] [blame]
Jeremy Kerr3d36ee22019-05-30 11:15:37 +08001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Jeremy Kerr4cdc2002019-02-07 16:49:12 +08002
3#include <assert.h>
Andrew Jeffery3e8a12a2020-06-05 16:08:30 +09304#include <errno.h>
Jeremy Kerr4cdc2002019-02-07 16:49:12 +08005#include <stdarg.h>
6#include <stddef.h>
7#include <stdint.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#undef pr_fmt
13#define pr_fmt(fmt) "core: " fmt
14
15#include "libmctp.h"
16#include "libmctp-alloc.h"
17#include "libmctp-log.h"
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +010018#include "libmctp-cmds.h"
Andrew Jefferyc2b833e2020-10-28 14:28:37 +103019#include "range.h"
Matt Johnston4a09e1d2024-09-13 14:55:58 +080020#include "compiler.h"
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080021
Matt Johnston722d0db2024-09-13 15:51:30 +080022/* 64kb should be sufficient for a single message. Applications
23 * requiring higher sizes can override by setting max_message_size.*/
24#ifndef MCTP_MAX_MESSAGE_SIZE
25#define MCTP_MAX_MESSAGE_SIZE 65536
26#endif
27
28/* Must be >= 2 for bridge busses */
29#ifndef MCTP_MAX_BUSSES
30#define MCTP_MAX_BUSSES 2
31#endif
32
Matt Johnston61c95992024-09-16 16:50:35 +080033/* Concurrent reassembly contexts. */
34#ifndef MCTP_REASSEMBLY_CTXS
35#define MCTP_REASSEMBLY_CTXS 16
36#endif
37
38/* Outbound request tags */
39#ifndef MCTP_REQ_TAGS
40#define MCTP_REQ_TAGS MCTP_REASSEMBLY_CTXS
41#endif
42
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080043/* Internal data structures */
44
Andrew Jefferyc61501c2021-01-27 23:24:18 +103045enum mctp_bus_state {
46 mctp_bus_state_constructed = 0,
47 mctp_bus_state_tx_enabled,
48 mctp_bus_state_tx_disabled,
49};
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080050
Andrew Jefferyc61501c2021-01-27 23:24:18 +103051struct mctp_bus {
52 mctp_eid_t eid;
53 struct mctp_binding *binding;
54 enum mctp_bus_state state;
Matt Johnston4a09e1d2024-09-13 14:55:58 +080055 struct mctp *mctp;
Andrew Jefferyc61501c2021-01-27 23:24:18 +103056
Matt Johnston4a09e1d2024-09-13 14:55:58 +080057 /* Current message to transmit */
58 void *tx_msg;
59 /* Position in tx_msg */
60 size_t tx_msgpos;
61 /* Length of tx_msg */
62 size_t tx_msglen;
63 /* Length of current packet payload */
64 size_t tx_pktlen;
65 uint8_t tx_seq;
66 uint8_t tx_src;
67 uint8_t tx_dest;
68 bool tx_to;
69 uint8_t tx_tag;
Jeremy Kerrcc2458d2019-03-01 08:23:33 +080070
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080071 /* todo: routing */
72};
73
Jeremy Kerr24db71f2019-02-07 21:37:35 +080074struct mctp_msg_ctx {
Matt Johnston4a09e1d2024-09-13 14:55:58 +080075 /* NULL buf indicates an unused mctp_msg_ctx */
76 void *buf;
77
Patrick Williamsa721c2d2022-12-04 14:30:26 -060078 uint8_t src;
79 uint8_t dest;
80 uint8_t tag;
81 uint8_t last_seq;
Patrick Williamsa721c2d2022-12-04 14:30:26 -060082 size_t buf_size;
83 size_t buf_alloc_size;
84 size_t fragment_size;
Jeremy Kerr24db71f2019-02-07 21:37:35 +080085};
86
Matt Johnston61c95992024-09-16 16:50:35 +080087struct mctp_req_tag {
88 /* 0 is an unused entry */
89 mctp_eid_t local;
90 mctp_eid_t remote;
91 uint8_t tag;
92};
93
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080094struct mctp {
Patrick Williamsa721c2d2022-12-04 14:30:26 -060095 int n_busses;
Matt Johnston722d0db2024-09-13 15:51:30 +080096 struct mctp_bus busses[MCTP_MAX_BUSSES];
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080097
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080098 /* Message RX callback */
Patrick Williamsa721c2d2022-12-04 14:30:26 -060099 mctp_rx_fn message_rx;
100 void *message_rx_data;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800101
Andrew Jeffery5d3d4e62021-08-20 16:44:40 +0930102 /* Packet capture callback */
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600103 mctp_capture_fn capture;
104 void *capture_data;
Andrew Jeffery5d3d4e62021-08-20 16:44:40 +0930105
Matt Johnston61c95992024-09-16 16:50:35 +0800106 /* Message reassembly. */
107 struct mctp_msg_ctx msg_ctxs[MCTP_REASSEMBLY_CTXS];
108
109 /* Allocated outbound TO tags */
110 struct mctp_req_tag req_tags[MCTP_REQ_TAGS];
111 /* used to avoid always allocating tag 0 */
112 uint8_t tag_round_robin;
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800113
114 enum {
115 ROUTE_ENDPOINT,
116 ROUTE_BRIDGE,
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600117 } route_policy;
Sumanth Bhat2c820c52020-07-02 00:26:25 +0530118 size_t max_message_size;
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800119
120 void *alloc_ctx;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800121};
122
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800123#ifndef ARRAY_SIZE
124#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
125#endif
126
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930127static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src,
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530128 mctp_eid_t dest, bool tag_owner,
129 uint8_t msg_tag, void *msg, size_t msg_len);
Matt Johnston61c95992024-09-16 16:50:35 +0800130static void mctp_dealloc_tag(struct mctp_bus *bus, mctp_eid_t local,
131 mctp_eid_t remote, uint8_t tag);
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800132
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800133struct mctp_pktbuf *mctp_pktbuf_alloc(struct mctp_binding *binding, size_t len)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800134{
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800135 size_t size =
136 binding->pkt_size + binding->pkt_header + binding->pkt_trailer;
Rashmica Gupta487b31e2022-09-14 18:49:45 +1000137 if (len > size) {
138 return NULL;
139 }
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800140
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800141 void *storage = __mctp_alloc(size + sizeof(struct mctp_pktbuf));
142 if (!storage) {
Pedro Martelletto2608b292023-03-30 13:28:28 +0000143 return NULL;
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800144 }
145 struct mctp_pktbuf *pkt = mctp_pktbuf_init(binding, storage);
146 pkt->alloc = true;
147 pkt->end = pkt->start + len;
148 return pkt;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800149}
150
151void mctp_pktbuf_free(struct mctp_pktbuf *pkt)
152{
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800153 if (pkt->alloc) {
154 __mctp_free(pkt);
155 } else {
156 mctp_prdebug("pktbuf_free called for non-alloced");
157 }
158}
159
160struct mctp_pktbuf *mctp_pktbuf_init(struct mctp_binding *binding,
161 void *storage)
162{
163 size_t size =
164 binding->pkt_size + binding->pkt_header + binding->pkt_trailer;
165 struct mctp_pktbuf *buf = (struct mctp_pktbuf *)storage;
166 buf->size = size;
167 buf->start = binding->pkt_header;
168 buf->end = buf->start;
169 buf->mctp_hdr_off = buf->start;
170 buf->alloc = false;
171
172 return buf;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800173}
174
175struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt)
176{
Moritz Fischer7aaccb52022-06-28 20:04:04 -0700177 return (struct mctp_hdr *)(pkt->data + pkt->mctp_hdr_off);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800178}
179
180void *mctp_pktbuf_data(struct mctp_pktbuf *pkt)
181{
Moritz Fischer7aaccb52022-06-28 20:04:04 -0700182 return pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800183}
184
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800185size_t mctp_pktbuf_size(const struct mctp_pktbuf *pkt)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800186{
187 return pkt->end - pkt->start;
188}
189
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800190void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, size_t size)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800191{
192 assert(size <= pkt->start);
193 pkt->start -= size;
194 return pkt->data + pkt->start;
195}
196
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800197void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, size_t size)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800198{
199 void *buf;
200
Andrew Jeffery3ac70d62020-07-01 00:50:44 +0930201 assert(size <= (pkt->size - pkt->end));
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800202 buf = pkt->data + pkt->end;
203 pkt->end += size;
204 return buf;
205}
206
Matt Johnstondfbf0fd2024-10-28 14:40:29 +0800207int mctp_pktbuf_push(struct mctp_pktbuf *pkt, const void *data, size_t len)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800208{
209 void *p;
210
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800211 if (pkt->end + len > pkt->size)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800212 return -1;
213
214 p = pkt->data + pkt->end;
215
216 pkt->end += len;
217 memcpy(p, data, len);
218
219 return 0;
220}
221
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030222void *mctp_pktbuf_pop(struct mctp_pktbuf *pkt, size_t len)
223{
224 if (len > mctp_pktbuf_size(pkt))
225 return NULL;
226
227 pkt->end -= len;
228 return pkt->data + pkt->end;
229}
230
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800231/* Allocate a duplicate of the message and copy it */
232static void *mctp_msg_dup(const void *msg, size_t msg_len, struct mctp *mctp)
233{
234 void *copy = __mctp_msg_alloc(msg_len, mctp);
235 if (!copy) {
236 mctp_prdebug("msg dup len %zu failed", msg_len);
237 return NULL;
238 }
239
240 memcpy(copy, msg, msg_len);
241 return copy;
242}
243
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800244/* Message reassembly */
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600245static struct mctp_msg_ctx *mctp_msg_ctx_lookup(struct mctp *mctp, uint8_t src,
246 uint8_t dest, uint8_t tag)
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800247{
248 unsigned int i;
249
250 /* @todo: better lookup, if we add support for more outstanding
251 * message contexts */
252 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
253 struct mctp_msg_ctx *ctx = &mctp->msg_ctxs[i];
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800254 if (ctx->buf && ctx->src == src && ctx->dest == dest &&
255 ctx->tag == tag)
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800256 return ctx;
257 }
258
259 return NULL;
260}
261
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600262static struct mctp_msg_ctx *mctp_msg_ctx_create(struct mctp *mctp, uint8_t src,
263 uint8_t dest, uint8_t tag)
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800264{
Jeremy Kerr11a234e2019-02-27 17:59:53 +0800265 struct mctp_msg_ctx *ctx = NULL;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800266 unsigned int i;
267
268 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
269 struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i];
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800270 if (!tmp->buf) {
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800271 ctx = tmp;
272 break;
273 }
274 }
275
276 if (!ctx)
277 return NULL;
278
279 ctx->src = src;
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800280 ctx->dest = dest;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800281 ctx->tag = tag;
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800282
Jeremy Kerr9a3da812019-08-02 15:57:53 +0800283 ctx->buf_size = 0;
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800284 ctx->buf_alloc_size = mctp->max_message_size;
285 ctx->buf = __mctp_msg_alloc(ctx->buf_alloc_size, mctp);
286 if (!ctx->buf) {
287 return NULL;
288 }
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800289
290 return ctx;
291}
292
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800293static void mctp_msg_ctx_drop(struct mctp_bus *bus, struct mctp_msg_ctx *ctx)
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800294{
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800295 /* Free and mark as unused */
296 __mctp_msg_free(ctx->buf, bus->mctp);
297 ctx->buf = NULL;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800298}
299
300static void mctp_msg_ctx_reset(struct mctp_msg_ctx *ctx)
301{
302 ctx->buf_size = 0;
Sumanth Bhat69f545f2021-05-18 09:16:43 +0000303 ctx->fragment_size = 0;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800304}
305
306static int mctp_msg_ctx_add_pkt(struct mctp_msg_ctx *ctx,
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800307 struct mctp_pktbuf *pkt)
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800308{
309 size_t len;
310
311 len = mctp_pktbuf_size(pkt) - sizeof(struct mctp_hdr);
312
Sumanth Bhatbc79c242021-06-16 12:36:56 +0530313 if (len + ctx->buf_size < ctx->buf_size) {
314 return -1;
315 }
316
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800317 if (ctx->buf_size + len > ctx->buf_alloc_size) {
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800318 return -1;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800319 }
320
Moritz Fischer7aaccb52022-06-28 20:04:04 -0700321 memcpy((uint8_t *)ctx->buf + ctx->buf_size, mctp_pktbuf_data(pkt), len);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800322 ctx->buf_size += len;
323
324 return 0;
325}
326
327/* Core API functions */
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800328struct mctp *mctp_init(void)
329{
330 struct mctp *mctp;
331
332 mctp = __mctp_alloc(sizeof(*mctp));
Sumanth Bhat96d54492020-07-14 17:10:04 +0530333
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600334 if (!mctp)
Sumanth Bhat96d54492020-07-14 17:10:04 +0530335 return NULL;
336
Matt Johnston722d0db2024-09-13 15:51:30 +0800337 mctp_setup(mctp);
338 return mctp;
339}
340
341void mctp_setup(struct mctp *mctp)
342{
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800343 memset(mctp, 0, sizeof(*mctp));
Sumanth Bhat2c820c52020-07-02 00:26:25 +0530344 mctp->max_message_size = MCTP_MAX_MESSAGE_SIZE;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800345}
346
Sumanth Bhat2c820c52020-07-02 00:26:25 +0530347void mctp_set_max_message_size(struct mctp *mctp, size_t message_size)
348{
349 mctp->max_message_size = message_size;
350}
351
Andrew Jeffery5d3d4e62021-08-20 16:44:40 +0930352void mctp_set_capture_handler(struct mctp *mctp, mctp_capture_fn fn, void *user)
353{
354 mctp->capture = fn;
355 mctp->capture_data = user;
356}
357
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800358static void mctp_bus_destroy(struct mctp_bus *bus, struct mctp *mctp)
Andrew Jeffery3ae89dc2021-01-28 15:24:36 +1030359{
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800360 if (bus->tx_msg) {
361 __mctp_msg_free(bus->tx_msg, mctp);
362 bus->tx_msg = NULL;
Andrew Jeffery3ae89dc2021-01-28 15:24:36 +1030363 }
364}
365
Matt Johnston722d0db2024-09-13 15:51:30 +0800366void mctp_cleanup(struct mctp *mctp)
Andrew Jefferyfa56ca52020-03-10 23:18:22 +1030367{
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930368 size_t i;
Andrew Jefferyfa56ca52020-03-10 23:18:22 +1030369
370 /* Cleanup message assembly contexts */
Matt Johnston3ef47782024-12-11 15:19:06 +0800371 static_assert(ARRAY_SIZE(mctp->msg_ctxs) < SIZE_MAX, "size");
Andrew Jefferyfa56ca52020-03-10 23:18:22 +1030372 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
373 struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i];
374 if (tmp->buf)
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800375 __mctp_msg_free(tmp->buf, mctp);
Andrew Jefferyfa56ca52020-03-10 23:18:22 +1030376 }
377
Andrew Jeffery3ae89dc2021-01-28 15:24:36 +1030378 while (mctp->n_busses--)
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800379 mctp_bus_destroy(&mctp->busses[mctp->n_busses], mctp);
Matt Johnston722d0db2024-09-13 15:51:30 +0800380}
Andrew Jeffery3ae89dc2021-01-28 15:24:36 +1030381
Matt Johnston722d0db2024-09-13 15:51:30 +0800382void mctp_destroy(struct mctp *mctp)
383{
384 mctp_cleanup(mctp);
Andrew Jefferyfa56ca52020-03-10 23:18:22 +1030385 __mctp_free(mctp);
386}
387
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800388int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data)
389{
390 mctp->message_rx = fn;
391 mctp->message_rx_data = data;
392 return 0;
393}
394
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600395static struct mctp_bus *find_bus_for_eid(struct mctp *mctp, mctp_eid_t dest
396 __attribute__((unused)))
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800397{
Brad Bishop663ec392021-10-07 21:16:48 -0400398 if (mctp->n_busses == 0)
399 return NULL;
400
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800401 /* for now, just use the first bus. For full routing support,
402 * we will need a table of neighbours */
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800403 return &mctp->busses[0];
404}
405
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600406int mctp_register_bus(struct mctp *mctp, struct mctp_binding *binding,
407 mctp_eid_t eid)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800408{
Andrew Jeffery3e8a12a2020-06-05 16:08:30 +0930409 int rc = 0;
410
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800411 /* todo: multiple busses */
Matt Johnston722d0db2024-09-13 15:51:30 +0800412 static_assert(MCTP_MAX_BUSSES >= 1, "need a bus");
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800413 assert(mctp->n_busses == 0);
414 mctp->n_busses = 1;
Andrew Jeffery3e8a12a2020-06-05 16:08:30 +0930415
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800416 assert(binding->tx_storage);
417
James Feist62d72362019-12-13 13:43:32 -0800418 memset(mctp->busses, 0, sizeof(struct mctp_bus));
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800419 mctp->busses[0].mctp = mctp;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800420 mctp->busses[0].binding = binding;
421 mctp->busses[0].eid = eid;
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800422 binding->bus = &mctp->busses[0];
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800423 binding->mctp = mctp;
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800424 mctp->route_policy = ROUTE_ENDPOINT;
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800425
Andrew Jeffery3e8a12a2020-06-05 16:08:30 +0930426 if (binding->start) {
427 rc = binding->start(binding);
428 if (rc < 0) {
429 mctp_prerr("Failed to start binding: %d", rc);
Andrew Jeffery19275232021-01-29 14:13:25 +1030430 binding->bus = NULL;
Andrew Jeffery2304c832021-01-29 11:52:49 +1030431 mctp->n_busses = 0;
Andrew Jeffery3e8a12a2020-06-05 16:08:30 +0930432 }
433 }
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800434
Andrew Jeffery3e8a12a2020-06-05 16:08:30 +0930435 return rc;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800436}
437
Andrew Jeffery2094c3c2021-08-26 12:32:46 +0930438void mctp_unregister_bus(struct mctp *mctp, struct mctp_binding *binding)
439{
440 /*
441 * We only support one bus right now; once the call completes we will
442 * have no more busses
443 */
444 mctp->n_busses = 0;
445 binding->mctp = NULL;
446 binding->bus = NULL;
Andrew Jeffery2094c3c2021-08-26 12:32:46 +0930447}
448
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600449int mctp_bridge_busses(struct mctp *mctp, struct mctp_binding *b1,
450 struct mctp_binding *b2)
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800451{
Andrew Jeffery19275232021-01-29 14:13:25 +1030452 int rc = 0;
453
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800454 assert(b1->tx_storage);
455 assert(b2->tx_storage);
456
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800457 assert(mctp->n_busses == 0);
Matt Johnston722d0db2024-09-13 15:51:30 +0800458 assert(MCTP_MAX_BUSSES >= 2);
James Feist62d72362019-12-13 13:43:32 -0800459 memset(mctp->busses, 0, 2 * sizeof(struct mctp_bus));
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800460 mctp->n_busses = 2;
461 mctp->busses[0].binding = b1;
462 b1->bus = &mctp->busses[0];
463 b1->mctp = mctp;
464 mctp->busses[1].binding = b2;
465 b2->bus = &mctp->busses[1];
466 b2->mctp = mctp;
467
468 mctp->route_policy = ROUTE_BRIDGE;
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800469
Andrew Jeffery19275232021-01-29 14:13:25 +1030470 if (b1->start) {
471 rc = b1->start(b1);
472 if (rc < 0) {
473 mctp_prerr("Failed to start bridged bus %s: %d",
474 b1->name, rc);
475 goto done;
476 }
477 }
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800478
Andrew Jeffery19275232021-01-29 14:13:25 +1030479 if (b2->start) {
480 rc = b2->start(b2);
481 if (rc < 0) {
482 mctp_prerr("Failed to start bridged bus %s: %d",
483 b2->name, rc);
484 goto done;
485 }
486 }
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800487
Andrew Jeffery19275232021-01-29 14:13:25 +1030488done:
489 return rc;
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800490}
491
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100492static inline bool mctp_ctrl_cmd_is_transport(struct mctp_ctrl_msg_hdr *hdr)
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800493{
Matt Johnston3ef47782024-12-11 15:19:06 +0800494#pragma GCC diagnostic push
495#pragma GCC diagnostic ignored "-Wtype-limits"
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100496 return ((hdr->command_code >= MCTP_CTRL_CMD_FIRST_TRANSPORT) &&
497 (hdr->command_code <= MCTP_CTRL_CMD_LAST_TRANSPORT));
Matt Johnston3ef47782024-12-11 15:19:06 +0800498#pragma GCC diagnostic pop
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100499}
500
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930501static bool mctp_ctrl_handle_msg(struct mctp_bus *bus, mctp_eid_t src,
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530502 uint8_t msg_tag, bool tag_owner, void *buffer,
503 size_t length)
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100504{
505 struct mctp_ctrl_msg_hdr *msg_hdr = buffer;
506
507 /*
508 * Control message is received. If a transport control message handler
509 * is provided, it will called. If there is no dedicated handler, this
510 * function returns false and data can be handled by the generic
511 * message handler. The transport control message handler will be
512 * provided with messages in the command range 0xF0 - 0xFF.
513 */
514 if (mctp_ctrl_cmd_is_transport(msg_hdr)) {
515 if (bus->binding->control_rx != NULL) {
516 /* MCTP bus binding handler */
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530517 bus->binding->control_rx(src, msg_tag, tag_owner,
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100518 bus->binding->control_rx_data,
519 buffer, length);
520 return true;
521 }
522 }
523
524 /*
525 * Command was not handled, due to lack of specific callback.
526 * It will be passed to regular message_rx handler.
527 */
528 return false;
529}
530
531static inline bool mctp_rx_dest_is_local(struct mctp_bus *bus, mctp_eid_t dest)
532{
533 return dest == bus->eid || dest == MCTP_EID_NULL ||
534 dest == MCTP_EID_BROADCAST;
535}
536
537static inline bool mctp_ctrl_cmd_is_request(struct mctp_ctrl_msg_hdr *hdr)
538{
539 return hdr->ic_msg_type == MCTP_CTRL_HDR_MSG_TYPE &&
540 hdr->rq_dgram_inst & MCTP_CTRL_HDR_FLAG_REQUEST;
541}
542
543/*
544 * Receive the complete MCTP message and route it.
545 * Asserts:
546 * 'buf' is not NULL.
547 */
548static void mctp_rx(struct mctp *mctp, struct mctp_bus *bus, mctp_eid_t src,
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530549 mctp_eid_t dest, bool tag_owner, uint8_t msg_tag, void *buf,
550 size_t len)
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100551{
552 assert(buf != NULL);
553
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800554 if (mctp->route_policy == ROUTE_ENDPOINT &&
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100555 mctp_rx_dest_is_local(bus, dest)) {
Matt Johnston61c95992024-09-16 16:50:35 +0800556 /* Note responses to allocated tags */
557 if (!tag_owner) {
558 mctp_dealloc_tag(bus, dest, src, msg_tag);
559 }
560
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100561 /* Handle MCTP Control Messages: */
562 if (len >= sizeof(struct mctp_ctrl_msg_hdr)) {
563 struct mctp_ctrl_msg_hdr *msg_hdr = buf;
564
565 /*
566 * Identify if this is a control request message.
567 * See DSP0236 v1.3.0 sec. 11.5.
568 */
569 if (mctp_ctrl_cmd_is_request(msg_hdr)) {
570 bool handled;
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530571 handled = mctp_ctrl_handle_msg(
572 bus, src, msg_tag, tag_owner, buf, len);
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100573 if (handled)
574 return;
575 }
576 }
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530577
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100578 if (mctp->message_rx)
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530579 mctp->message_rx(src, tag_owner, msg_tag,
580 mctp->message_rx_data, buf, len);
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100581 }
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800582
583 if (mctp->route_policy == ROUTE_BRIDGE) {
584 int i;
585
586 for (i = 0; i < mctp->n_busses; i++) {
587 struct mctp_bus *dest_bus = &mctp->busses[i];
588 if (dest_bus == bus)
589 continue;
590
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800591 void *copy = mctp_msg_dup(buf, len, mctp);
592 if (!copy) {
593 return;
594 }
595
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530596 mctp_message_tx_on_bus(dest_bus, src, dest, tag_owner,
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800597 msg_tag, copy, len);
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800598 }
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800599 }
600}
601
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800602void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800603{
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800604 struct mctp_bus *bus = binding->bus;
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800605 struct mctp *mctp = binding->mctp;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800606 uint8_t flags, exp_seq, seq, tag;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800607 struct mctp_msg_ctx *ctx;
608 struct mctp_hdr *hdr;
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530609 bool tag_owner;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800610 size_t len;
611 void *p;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800612 int rc;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800613
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800614 assert(bus);
615
Sumanth Bhatd97869d2020-07-02 00:46:13 +0530616 /* Drop packet if it was smaller than mctp hdr size */
Matt Johnston86e9a972024-10-28 15:06:33 +0800617 if (mctp_pktbuf_size(pkt) < sizeof(struct mctp_hdr))
Sumanth Bhatd97869d2020-07-02 00:46:13 +0530618 goto out;
619
Andrew Jeffery5d3d4e62021-08-20 16:44:40 +0930620 if (mctp->capture)
Rashmica Guptaf2988972022-11-09 12:26:44 +1100621 mctp->capture(pkt, MCTP_MESSAGE_CAPTURE_INCOMING,
622 mctp->capture_data);
Andrew Jeffery5d3d4e62021-08-20 16:44:40 +0930623
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800624 hdr = mctp_pktbuf_hdr(pkt);
625
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800626 /* small optimisation: don't bother reassembly if we're going to
627 * drop the packet in mctp_rx anyway */
John Chung133df7a2024-05-14 16:19:56 +0800628 if (mctp->route_policy == ROUTE_ENDPOINT &&
629 !mctp_rx_dest_is_local(bus, hdr->dest))
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800630 goto out;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800631
632 flags = hdr->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
633 tag = (hdr->flags_seq_tag >> MCTP_HDR_TAG_SHIFT) & MCTP_HDR_TAG_MASK;
634 seq = (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & MCTP_HDR_SEQ_MASK;
Andrew Jeffery7f7fdc12023-05-12 15:56:47 +0930635 tag_owner = (hdr->flags_seq_tag >> MCTP_HDR_TO_SHIFT) &
636 MCTP_HDR_TO_MASK;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800637
638 switch (flags) {
639 case MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM:
640 /* single-packet message - send straight up to rx function,
641 * no need to create a message context */
642 len = pkt->end - pkt->mctp_hdr_off - sizeof(struct mctp_hdr);
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800643 p = mctp_msg_dup(pkt->data + pkt->mctp_hdr_off +
644 sizeof(struct mctp_hdr),
645 len, mctp);
646 if (p) {
647 mctp_rx(mctp, bus, hdr->src, hdr->dest, tag_owner, tag,
648 p, len);
649 __mctp_msg_free(p, mctp);
650 }
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800651 break;
652
653 case MCTP_HDR_FLAG_SOM:
654 /* start of a new message - start the new context for
655 * future message reception. If an existing context is
656 * already present, drop it. */
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800657 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800658 if (ctx) {
659 mctp_msg_ctx_reset(ctx);
660 } else {
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600661 ctx = mctp_msg_ctx_create(mctp, hdr->src, hdr->dest,
662 tag);
Sumanth Bhat34d4c962021-06-16 12:50:48 +0530663 /* If context creation fails due to exhaution of contexts we
664 * can support, drop the packet */
665 if (!ctx) {
666 mctp_prdebug("Context buffers exhausted.");
667 goto out;
668 }
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800669 }
670
Sumanth Bhat69f545f2021-05-18 09:16:43 +0000671 /* Save the fragment size, subsequent middle fragments
672 * should of the same size */
673 ctx->fragment_size = mctp_pktbuf_size(pkt);
674
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800675 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800676 if (rc) {
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800677 mctp_msg_ctx_drop(bus, ctx);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800678 } else {
679 ctx->last_seq = seq;
680 }
681
682 break;
683
684 case MCTP_HDR_FLAG_EOM:
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800685 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800686 if (!ctx)
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800687 goto out;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800688
Ed Tanousc2def9f2019-02-21 08:33:08 -0800689 exp_seq = (ctx->last_seq + 1) % 4;
690
691 if (exp_seq != seq) {
692 mctp_prdebug(
693 "Sequence number %d does not match expected %d",
694 seq, exp_seq);
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800695 mctp_msg_ctx_drop(bus, ctx);
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800696 goto out;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800697 }
698
Sumanth Bhat69f545f2021-05-18 09:16:43 +0000699 len = mctp_pktbuf_size(pkt);
700
701 if (len > ctx->fragment_size) {
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600702 mctp_prdebug("Unexpected fragment size. Expected"
703 " less than %zu, received = %zu",
704 ctx->fragment_size, len);
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800705 mctp_msg_ctx_drop(bus, ctx);
Sumanth Bhat69f545f2021-05-18 09:16:43 +0000706 goto out;
707 }
708
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800709 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800710 if (!rc)
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530711 mctp_rx(mctp, bus, ctx->src, ctx->dest, tag_owner, tag,
712 ctx->buf, ctx->buf_size);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800713
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800714 mctp_msg_ctx_drop(bus, ctx);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800715 break;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800716
717 case 0:
718 /* Neither SOM nor EOM */
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600719 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
Ed Tanousc2def9f2019-02-21 08:33:08 -0800720 if (!ctx)
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800721 goto out;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800722
723 exp_seq = (ctx->last_seq + 1) % 4;
724 if (exp_seq != seq) {
725 mctp_prdebug(
726 "Sequence number %d does not match expected %d",
727 seq, exp_seq);
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800728 mctp_msg_ctx_drop(bus, ctx);
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800729 goto out;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800730 }
731
Sumanth Bhat69f545f2021-05-18 09:16:43 +0000732 len = mctp_pktbuf_size(pkt);
733
734 if (len != ctx->fragment_size) {
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600735 mctp_prdebug("Unexpected fragment size. Expected = %zu "
736 "received = %zu",
737 ctx->fragment_size, len);
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800738 mctp_msg_ctx_drop(bus, ctx);
Sumanth Bhat69f545f2021-05-18 09:16:43 +0000739 goto out;
740 }
741
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800742 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
Ed Tanousc2def9f2019-02-21 08:33:08 -0800743 if (rc) {
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800744 mctp_msg_ctx_drop(bus, ctx);
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800745 goto out;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800746 }
747 ctx->last_seq = seq;
748
749 break;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800750 }
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800751out:
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800752 return;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800753}
754
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600755static int mctp_packet_tx(struct mctp_bus *bus, struct mctp_pktbuf *pkt)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800756{
Andrew Jeffery5d3d4e62021-08-20 16:44:40 +0930757 struct mctp *mctp = bus->binding->mctp;
758
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800759 if (bus->state != mctp_bus_state_tx_enabled) {
760 mctp_prdebug("tx with bus disabled");
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800761 return -1;
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800762 }
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800763
Andrew Jeffery5d3d4e62021-08-20 16:44:40 +0930764 if (mctp->capture)
Rashmica Guptaf2988972022-11-09 12:26:44 +1100765 mctp->capture(pkt, MCTP_MESSAGE_CAPTURE_OUTGOING,
766 mctp->capture_data);
Andrew Jeffery5d3d4e62021-08-20 16:44:40 +0930767
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800768 return bus->binding->tx(bus->binding, pkt);
769}
770
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800771/* Returns a pointer to the binding's tx_storage */
772static struct mctp_pktbuf *mctp_next_tx_pkt(struct mctp_bus *bus)
773{
774 if (!bus->tx_msg) {
775 return NULL;
776 }
777
778 size_t p = bus->tx_msgpos;
779 size_t msg_len = bus->tx_msglen;
780 size_t payload_len = msg_len - p;
781 size_t max_payload_len = MCTP_BODY_SIZE(bus->binding->pkt_size);
782 if (payload_len > max_payload_len)
783 payload_len = max_payload_len;
784
785 struct mctp_pktbuf *pkt =
786 mctp_pktbuf_init(bus->binding, bus->binding->tx_storage);
787 struct mctp_hdr *hdr = mctp_pktbuf_hdr(pkt);
788
789 hdr->ver = bus->binding->version & 0xf;
790 hdr->dest = bus->tx_dest;
791 hdr->src = bus->tx_src;
792 hdr->flags_seq_tag = (bus->tx_to << MCTP_HDR_TO_SHIFT) |
793 (bus->tx_tag << MCTP_HDR_TAG_SHIFT);
794
795 if (p == 0)
796 hdr->flags_seq_tag |= MCTP_HDR_FLAG_SOM;
797 if (p + payload_len >= msg_len)
798 hdr->flags_seq_tag |= MCTP_HDR_FLAG_EOM;
799 hdr->flags_seq_tag |= bus->tx_seq << MCTP_HDR_SEQ_SHIFT;
800
801 memcpy(mctp_pktbuf_data(pkt), (uint8_t *)bus->tx_msg + p, payload_len);
802 pkt->end = pkt->start + sizeof(*hdr) + payload_len;
803 bus->tx_pktlen = payload_len;
804
805 mctp_prdebug(
806 "tx dst %d tag %d payload len %zu seq %d. msg pos %zu len %zu",
807 hdr->dest, bus->tx_tag, payload_len, bus->tx_seq, p, msg_len);
808
809 return pkt;
810}
811
812/* Called when a packet has successfully been sent */
813static void mctp_tx_complete(struct mctp_bus *bus)
814{
815 if (!bus->tx_msg) {
816 mctp_prdebug("tx complete no message");
817 return;
818 }
819
820 bus->tx_seq = (bus->tx_seq + 1) & MCTP_HDR_SEQ_MASK;
821 bus->tx_msgpos += bus->tx_pktlen;
822
823 if (bus->tx_msgpos >= bus->tx_msglen) {
824 __mctp_msg_free(bus->tx_msg, bus->binding->mctp);
825 bus->tx_msg = NULL;
826 }
827}
828
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800829static void mctp_send_tx_queue(struct mctp_bus *bus)
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800830{
831 struct mctp_pktbuf *pkt;
832
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800833 while (bus->tx_msg && bus->state == mctp_bus_state_tx_enabled) {
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800834 int rc;
835
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800836 pkt = mctp_next_tx_pkt(bus);
837
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800838 rc = mctp_packet_tx(bus, pkt);
Andrew Jeffery0721f582022-09-29 12:12:39 +0930839 switch (rc) {
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800840 /* If transmission succeded */
Andrew Jeffery0721f582022-09-29 12:12:39 +0930841 case 0:
Andrew Jeffery0721f582022-09-29 12:12:39 +0930842 /* Drop the packet */
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800843 mctp_tx_complete(bus);
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800844 break;
845
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800846 /* If the binding was busy */
Andrew Jeffery0721f582022-09-29 12:12:39 +0930847 case -EBUSY:
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800848 /* Keep the packet for next try */
849 mctp_prdebug("tx EBUSY");
850 return;
851
Andrew Jeffery0721f582022-09-29 12:12:39 +0930852 /* Some other unknown error occurred */
853 default:
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800854 /* Drop the packet */
855 mctp_prdebug("tx drop %d", rc);
856 mctp_tx_complete(bus);
857 return;
Andrew Jeffery0721f582022-09-29 12:12:39 +0930858 };
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800859 }
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800860}
861
862void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable)
863{
864 struct mctp_bus *bus = binding->bus;
Andrew Jefferyc61501c2021-01-27 23:24:18 +1030865
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600866 switch (bus->state) {
Andrew Jefferyc61501c2021-01-27 23:24:18 +1030867 case mctp_bus_state_constructed:
868 if (!enable)
869 return;
870
Andrew Jeffery1fa707e2021-01-28 15:22:11 +1030871 if (binding->pkt_size < MCTP_PACKET_SIZE(MCTP_BTU)) {
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600872 mctp_prerr(
873 "Cannot start %s binding with invalid MTU: %zu",
874 binding->name,
875 MCTP_BODY_SIZE(binding->pkt_size));
Andrew Jeffery1fa707e2021-01-28 15:22:11 +1030876 return;
877 }
878
Andrew Jefferyc61501c2021-01-27 23:24:18 +1030879 bus->state = mctp_bus_state_tx_enabled;
880 mctp_prinfo("%s binding started", binding->name);
881 return;
882 case mctp_bus_state_tx_enabled:
883 if (enable)
884 return;
885
886 bus->state = mctp_bus_state_tx_disabled;
887 mctp_prdebug("%s binding Tx disabled", binding->name);
888 return;
889 case mctp_bus_state_tx_disabled:
890 if (!enable)
891 return;
892
893 bus->state = mctp_bus_state_tx_enabled;
894 mctp_prdebug("%s binding Tx enabled", binding->name);
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800895 mctp_send_tx_queue(bus);
Andrew Jefferyc61501c2021-01-27 23:24:18 +1030896 return;
897 }
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800898}
899
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930900static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src,
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530901 mctp_eid_t dest, bool tag_owner,
902 uint8_t msg_tag, void *msg, size_t msg_len)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800903{
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800904 size_t max_payload_len;
905 int rc;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800906
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800907 if (bus->state == mctp_bus_state_constructed) {
908 rc = -ENXIO;
909 goto err;
910 }
Andrew Jefferyc61501c2021-01-27 23:24:18 +1030911
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800912 if ((msg_tag & MCTP_HDR_TAG_MASK) != msg_tag) {
913 rc = -EINVAL;
914 goto err;
915 }
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530916
Andrew Jeffery1fa707e2021-01-28 15:22:11 +1030917 max_payload_len = MCTP_BODY_SIZE(bus->binding->pkt_size);
918
919 {
920 const bool valid_mtu = max_payload_len >= MCTP_BTU;
921 assert(valid_mtu);
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800922 if (!valid_mtu) {
923 rc = -EINVAL;
924 goto err;
925 }
Andrew Jeffery1fa707e2021-01-28 15:22:11 +1030926 }
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800927
Patrick Williamsa721c2d2022-12-04 14:30:26 -0600928 mctp_prdebug(
929 "%s: Generating packets for transmission of %zu byte message from %hhu to %hhu",
930 __func__, msg_len, src, dest);
Andrew Jeffery298865f2020-02-06 11:51:29 +1030931
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800932 if (bus->tx_msg) {
933 mctp_prdebug("Bus busy");
934 rc = -EBUSY;
935 goto err;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800936 }
937
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800938 /* Take the message to send */
939 bus->tx_msg = msg;
940 bus->tx_msglen = msg_len;
941 bus->tx_msgpos = 0;
942 /* bus->tx_seq is allowed to continue from previous message */
943 bus->tx_src = src;
944 bus->tx_dest = dest;
945 bus->tx_to = tag_owner;
946 bus->tx_tag = msg_tag;
Andrew Jeffery298865f2020-02-06 11:51:29 +1030947
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800948 mctp_send_tx_queue(bus);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800949 return 0;
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800950
951err:
952 __mctp_msg_free(msg, bus->binding->mctp);
953 return rc;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800954}
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800955
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800956int mctp_message_tx_alloced(struct mctp *mctp, mctp_eid_t eid, bool tag_owner,
957 uint8_t msg_tag, void *msg, size_t msg_len)
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800958{
959 struct mctp_bus *bus;
960
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530961 /* TODO: Protect against same tag being used across
962 * different callers */
963 if ((msg_tag & MCTP_HDR_TAG_MASK) != msg_tag) {
964 mctp_prerr("Incorrect message tag %u passed.", msg_tag);
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800965 __mctp_msg_free(msg, mctp);
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530966 return -EINVAL;
967 }
968
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800969 bus = find_bus_for_eid(mctp, eid);
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800970 if (!bus) {
971 __mctp_msg_free(msg, mctp);
Brad Bishop663ec392021-10-07 21:16:48 -0400972 return 0;
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800973 }
Brad Bishop663ec392021-10-07 21:16:48 -0400974
Sumanth Bhatf39c3852022-01-10 17:04:10 +0530975 return mctp_message_tx_on_bus(bus, bus->eid, eid, tag_owner, msg_tag,
976 msg, msg_len);
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800977}
Matt Johnston4a09e1d2024-09-13 14:55:58 +0800978
979int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid, bool tag_owner,
980 uint8_t msg_tag, const void *msg, size_t msg_len)
981{
982 void *copy = mctp_msg_dup(msg, msg_len, mctp);
983 if (!copy) {
984 return -ENOMEM;
985 }
986
987 return mctp_message_tx_alloced(mctp, eid, tag_owner, msg_tag, copy,
988 msg_len);
989}
990
Matt Johnston61c95992024-09-16 16:50:35 +0800991static void mctp_dealloc_tag(struct mctp_bus *bus, mctp_eid_t local,
992 mctp_eid_t remote, uint8_t tag)
993{
994 struct mctp *mctp = bus->binding->mctp;
995 if (local == 0 || remote == 0) {
996 return;
997 }
998
999 for (size_t i = 0; i < ARRAY_SIZE(mctp->req_tags); i++) {
1000 struct mctp_req_tag *r = &mctp->req_tags[i];
1001 if (r->local == local && r->remote == remote && r->tag == tag) {
1002 r->local = 0;
1003 r->remote = 0;
1004 r->tag = 0;
1005 return;
1006 }
1007 }
1008}
1009
1010static int mctp_alloc_tag(struct mctp *mctp, mctp_eid_t local,
1011 mctp_eid_t remote, uint8_t *ret_tag)
1012{
1013 assert(local != 0);
1014 assert(remote != 0);
1015
1016 uint8_t used = 0;
1017 struct mctp_req_tag *spare = NULL;
1018 /* Find which tags and slots are used/spare */
1019 for (size_t i = 0; i < ARRAY_SIZE(mctp->req_tags); i++) {
1020 struct mctp_req_tag *r = &mctp->req_tags[i];
1021 if (r->local == 0) {
1022 spare = r;
1023 } else {
1024 // TODO: check timeouts
1025 if (r->local == local && r->remote == remote) {
1026 used |= 1 << r->tag;
1027 }
1028 }
1029 }
1030
1031 if (spare == NULL) {
1032 // All req_tag slots are in-use
1033 return -EBUSY;
1034 }
1035
1036 for (uint8_t t = 0; t < 8; t++) {
1037 uint8_t tag = (t + mctp->tag_round_robin) % 8;
1038 if ((used & 1 << tag) == 0) {
1039 spare->local = local;
1040 spare->remote = remote;
1041 spare->tag = tag;
1042 *ret_tag = tag;
1043 mctp->tag_round_robin = (tag + 1) % 8;
1044 return 0;
1045 }
1046 }
1047
1048 // All 8 tags are used for this src/dest pair
1049 return -EBUSY;
1050}
1051
1052int mctp_message_tx_request(struct mctp *mctp, mctp_eid_t eid, void *msg,
1053 size_t msg_len, uint8_t *ret_alloc_msg_tag)
1054{
1055 int rc;
1056 struct mctp_bus *bus;
1057
1058 bus = find_bus_for_eid(mctp, eid);
1059 if (!bus) {
1060 __mctp_msg_free(msg, mctp);
1061 return 0;
1062 }
1063
1064 uint8_t alloc_tag;
1065 rc = mctp_alloc_tag(mctp, bus->eid, eid, &alloc_tag);
1066 if (rc) {
1067 mctp_prdebug("Failed allocating tag");
1068 __mctp_msg_free(msg, mctp);
1069 return rc;
1070 }
1071
1072 if (ret_alloc_msg_tag) {
1073 *ret_alloc_msg_tag = alloc_tag;
1074 }
1075
1076 return mctp_message_tx_alloced(mctp, eid, true, alloc_tag, msg,
1077 msg_len);
1078}
1079
Matt Johnston4a09e1d2024-09-13 14:55:58 +08001080bool mctp_is_tx_ready(struct mctp *mctp, mctp_eid_t eid)
1081{
1082 struct mctp_bus *bus;
1083
1084 bus = find_bus_for_eid(mctp, eid);
1085 if (!bus) {
1086 return true;
1087 }
1088 return bus->tx_msg == NULL;
1089}
1090
1091void *mctp_get_alloc_ctx(struct mctp *mctp)
1092{
1093 return mctp->alloc_ctx;
1094}
1095
1096void mctp_set_alloc_ctx(struct mctp *mctp, void *ctx)
1097{
1098 mctp->alloc_ctx = ctx;
1099}